見出し画像

高校数学をプログラミングで解く(数学II編)「2-2 2直線の関係」


はじめに

今回は、数学IIで学ぶ「2直線の関係」について、ある直線に平行な直線、垂直な直線を描くプログラムやある直線に関して対称となる点をプロットするプログラムを作成します。

2直線の関係

まず、2直線の関係について解説しておきます。

2直線の位置関係

2直線$${y=m_1 x + n_1, y=m_2 x + n_2}$$の場合
交わる条件 $${m_1 \neq m_2}$$
平行条件 $${m_1=m_2}$$
垂直条件 $${m_1m_2 = -1}$$

2直線$${a_1x+b_1y+c_1=0, a_2x+b_2y+c_2=0}$$の場合
交わる条件 $${a_1b_2-a_2b_1 \neq 0}$$
平行条件 $${a_1b_2-a_2b_1 = 0}$$
垂直条件 $${a_1a_2+b_1b_2 = 0}$$

直線に関して対称な点

2点A,Bが直線$${l}$$に関して対称
$${ \Leftrightarrow }$$ ① 直線ABは$${l}$$に垂直、② 線分ABの中点は$${l}$$上

点と直線の距離

点$${(x_1, y_1)}$$と直線$${ax+by+c=0}$$の距離$${d}$$は

$$
d = \frac{|ax_1+by_1+c|}{\sqrt{a^2+b^2}}
$$

平行な直線、垂直な直線を描く

基準となる直線に関して平行な直線、垂直な直線を描くプログラムを作成していきます。

問題1
点$${(3,-2)}$$を通り、直線$${y=3x-2}$$に平行な直線(赤色)、垂直な直線(緑色)を描け。

アルゴリズム設計

一般に点$${(x_1,y_1)}$$を通り、直線$${y=mx+n}$$に平行な直線は

$$
y = m(x-x_1)+y_1
$$

となり、点$${(x_1,y_1)}$$を通り、直線$${y=mx+n}$$に垂直な直線は

$$
y = -\frac{1}{m} (x-x_1)+y_2
$$

となります。これらの直線の方程式は、上記で解説した平行条件、垂直条件と記事『高校数学をプログラミングで解く(数学II編)「2-1 直線の方程式」』で解説した直線の方程式②を合わせることで求めることができます。
また、これらの直線を描くために記事『高校数学をプログラミングで解く(数学II編)「2-1 直線の方程式」』で作成した関数「draw_equation_of_line2」などを再利用していきます。

プログラム 

それでは、問題1の平行な直線、垂直な直線を描くプログラムを作成します。記事『高校数学をプログラミングで解く(数学II編)「2-1 直線の方程式」』で作成したスケッチ「drawEquationOfLine2」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「drawTwoLines」と変更し、またスケッチ「drawTwoLines」内の「drawEquationOfLine2.pde」ファイルの名前を「drawTwoLines.pde」に変更します。そして、pdeファイル「drawTwoLines.pde」をダブルクリックしてスケッチ「drawTwoLines」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawTwoLines」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。

float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 10.0; // y軸の表示範囲 -y_rangeからy_rangeまで 

void setup(){
  size(500,500);
  noLoop();

  setAxes(x_range, y_range); // 座標軸の準備
  
  noFill();
  stroke(0,0,0);
  
  // 直線y=3x-2を描画
  float m = 3.0;
  float n = -2.0;
  draw_equation_of_line0(m,n);
 
  // 直線が通る点(x1,y1)
  float x1 = 3.0;
  float y1 = -2.0;
  
  // 点(x1,y1)を通り直線y=3x-2に平行な直線を描画
  stroke(255,0,0);
  draw_equation_of_line2(x1,y1,m);
  
  // 点(x1,y1)を通り直線y=3x-2に垂直な直線を描画
  stroke(0,255,0);
  draw_equation_of_line2(x1,y1,-1.0/m);
 
//  save("equation_of_line.jpg");
}

// 直線の方程式 y=mx+nを描く関数
void draw_equation_of_line0(
  float m, // 傾き
  float n  // 切片
){
  // グラフの定義域
  float x_min = -x_range;
  float x_max = x_range;
  int plot_num = 200; // グラフを描くための頂点の個数  
  
  // グラフを描画
  float x, y; // 関数の座標
  float X, Y; // キャンバス上の座標 
  beginShape();
  for(int i=0; i<=plot_num; i++){
    x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
    y = m * x + n; // 直線上の点のyの値
    // キャンバス上の座標位置に換算
    X = width / 2.0 / x_range * x;
    Y = height / 2.0 / y_range * y;
    vertex(X, Y);
  }
  endShape();

}

// 直線の方程式② 点(x1,y1)を通り、傾きmの直線を描く関数
void draw_equation_of_line2(
  float x1, // 直線が通る点のx座標
  float y1, // 直線が通る点のy座標
  float m   // 直線の傾き
){
  // グラフの定義域
  float x_min = -x_range;
  float x_max = x_range;
  int plot_num = 200; // グラフを描くための頂点の個数  
  
  // グラフを描画
  float x, y; // 関数の座標
  float X, Y; // キャンバス上の座標 
  beginShape();
  for(int i=0; i<=plot_num; i++){
    x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
    y = m * (x-x1) + y1; // 直線上の点のyの値
    // キャンバス上の座標位置に換算
    X = width / 2.0 / x_range * x;
    Y = height / 2.0 / y_range * y;
    vertex(X, Y);
  }
  endShape();

}

ソースコード1 平行な直線、垂直な直線を描くプログラム

今回、平行な直線、垂直な直線だけでなく、基準の直線$${y=3x-2}$$も黒色で描くようにしています。その基準となる直線は一般形$${y=mx+n}$$の形をしていますが、この形の直線を描く関数を準備していませんでしたので、今回「draw_equation_of_line0」として作成しました。

ソースコード1を、スケッチ「drawTwoLines」の「drawTwoLines」タブのテキストエディタ部分に書いて実行すると、図1のように、実行ウィンドウのキャンバス上に基準となる直線が黒色、平行な直線が赤色、垂直な直線が緑色でそれぞれ描かれます。

図1 平行な直線(赤色)、垂直な直線(緑色)

直線に関して対称な点を描く

ある直線に関して点Aと対称となる点Bを求めて、座標上にプロットするプログラムを作成します。

問題2
直線$${y=-2x+3}$$に関して、点A$${(2,-3)}$$と対称な点Bを赤色でプロットせよ。また、線分ABの長さを求めて、コンソールに出力せよ。

アルゴリズム設計

点Bの座標を求める手順をまとめておきます。なお、問題2を一般化して、直線$${y=mx+n}$$に関して、点A$${(x_1,y_1)}$$と対称な点B$${(x_2,y_2)}$$の座標を求める手順を示します。
① 点A$${(x_1,y_1)}$$を通り、傾きが$${-1/m}$$の直線(垂直な直線)を求めます。

$$
y = -\frac{1}{m} (x-x_1)+y_1
$$

② ①で求めた直線と直線$${y=mx+n}$$との交点の座標$${(x_m, y_m)}$$を求めます。

$$
x_m = \frac{x_1+my_1-mn}{m^2+1}, \ y_m = mx_m+n
$$

③ 最後に、

$$
x_m = \frac{x_1+x_2}{2}, \ y_m = \frac{y_1+y_2}{2}
$$

となることを考慮すると、点Bの座標は

$$
x_2 = 2x_m-x_1, \ x_y = 2y_m - x_1
$$

で求めることができます。

また、線分ABの長さは、点A$${(x_1, y_1)}$$と直線$${y=mx+n}$$の距離$${d}$$の2倍になるので、

$$
\mathrm{AB} = 2d =2 \frac{|mx_1-y_1+n|}{\sqrt{m^2+1}}
$$

となります。

プログラム

では、問題2の点や直線を描くプログラムを作成します。先ほど作成したスケッチ「drawTwoLines」を再利用します。
スケッチ「drawTwoLines」をフォルダごとコピーして、スケッチの名前(フォルダ名)を「plotSymmetricPoint」と変更し、またスケッチ「plotSymmetricPoint」内の「drawTwoLines.pde」ファイルの名前を「plotSymmetricPoint.pde」に変更します。そして、pdeファイル「plotSymmetricPoint.pde」をダブルクリックしてスケッチ「plotSymmetricPoint」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「plotSymmetricPoint」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。

float x_range = 10.0; // x軸の表示範囲 -x_rangeからx_rangeまで
float y_range = 10.0; // y軸の表示範囲 -y_rangeからy_rangeまで 

void setup(){
  size(500,500);
  noLoop();

  setAxes(x_range, y_range); // 座標軸の準備
  
  noFill();
  stroke(0,0,0);
  
  // 直線y=-2x+3を描画
  float m = -2.0;
  float n = 3.0;
  draw_equation_of_line0(m,n);
 
  // 点A(x1,y1)
  float x1 = 2.0;
  float y1 = -3.0;
  plot_point(x1, y1);
  
  // 線分ABの中点(xm, ym)
  float xm = (x1 + m*y1 - m*n)/(m*m + 1.0);
  float ym = m*xm + n;
  
  // 点B(x2,y2)
  float x2 = 2.0*xm - x1;
  float y2 = 2.0*ym - y1;
  stroke(255,0,0);
  plot_point(x2, y2);
  
  // 線分ABの長さ
  float AB = 2.0 * abs(m*x1 - y1 + n)/sqrt(m*m + 1.0);
  println("線分ABの長さ:", AB);

}

// 点をプロットする関数
void plot_point(
  float x, // 点の位置のx座標
  float y  // 点の位置のy座標
){
  float X, Y; // キャンバス上の座標
  // キャンバス上の座標位置に換算
  X = width / 2.0 / x_range * x;
  Y = height / 2.0 / y_range * y;
  strokeWeight(5);
  point(X,Y);
  strokeWeight(1);
}

// 直線の方程式 y=mx+nを描く関数
void draw_equation_of_line0(
  float m, // 傾き
  float n  // 切片
){
  // グラフの定義域
  float x_min = -x_range;
  float x_max = x_range;
  int plot_num = 200; // グラフを描くための頂点の個数  
  
  // グラフを描画
  float x, y; // 関数の座標
  float X, Y; // キャンバス上の座標 
  beginShape();
  for(int i=0; i<=plot_num; i++){
    x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
    y = m * x + n; // 直線上の点のyの値
    // キャンバス上の座標位置に換算
    X = width / 2.0 / x_range * x;
    Y = height / 2.0 / y_range * y;
    vertex(X, Y);
  }
  endShape();

}

// 直線の方程式② 点(x1,y1)を通り、傾きmの直線を描く関数
void draw_equation_of_line2(
  float x1, // 直線が通る点のx座標
  float y1, // 直線が通る点のy座標
  float m   // 直線の傾き
){
  // グラフの定義域
  float x_min = -x_range;
  float x_max = x_range;
  int plot_num = 200; // グラフを描くための頂点の個数  
  
  // グラフを描画
  float x, y; // 関数の座標
  float X, Y; // キャンバス上の座標 
  beginShape();
  for(int i=0; i<=plot_num; i++){
    x = x_min + (x_max - x_min) / plot_num * i; // 直線上の点のx座標
    y = m * (x-x1) + y1; // 直線上の点のyの値
    // キャンバス上の座標位置に換算
    X = width / 2.0 / x_range * x;
    Y = height / 2.0 / y_range * y;
    vertex(X, Y);
  }
  endShape();

}

ソースコード2 直線に関して対称な点をプロットするプログラム

今回のプログラムでは、点を求めてプロットするので、点を描くための関数「plot_point」を準備しました。なお、点の大きさはstrokeWeight関数を利用して直径 5 pixelsになるように調整しました。直線を描く関数は「draw_equation_of_line0」を再利用しています。

ソースコード2を、スケッチ「plotSymmetricPoint」の「plotSymmetricPoint」タブのテキストエディタ部分に書いて実行すると、図2のように、実行ウィンドウのキャンバス上に問題2の基準となる直線や点Aが黒色で、対称な点Bが赤色で描かれます。

図2 直線に関して点A(黒色)と対称な点B(赤色)

また、図3のように開発環境ウィンドウのコンソール部分に、

線分ABの長さ: 1.7888544

と出力されます。

図3 スケッチ「plotSymmetricPoint」の実行結果

まとめ

今回は、数学IIで学ぶ「2直線の関係」について、ある直線に平行な直線、垂直な直線を描くプログラムやある直線に関して対称となる点をプロットするプログラムを作成しました。
プログラム自体は、記事『高校数学をプログラミングで解く(数学II編)「2-1 直線の方程式」』で作成した直線を描くための関数やソースコードを再利用して作成することができました。比較的簡単にプログラミングできたのでないでしょうか。
問題2では、線分ABの長さを最後に求めましたが、この結果が正しいかどうかは検算しておいた方がよいでしょう。例えば、点Aの座標$${(x_1, y_1)}$$と点Bの座標$${(x_2, y_2)}$$がわかっているので、

$$
\sqrt{ (x_2-x_1)^2+(y_2-y_1)^2 }
$$

を計算してみて、同じ値が出るかどうかを確認しておくとよいでしょう。

参考文献

改訂版 教科書傍用 スタンダード 数学II(数研出版、ISBN9784410209369)

この記事が気に入ったらサポートをしてみませんか?