見出し画像

高校数学をプログラミングで解く(数学II編)「2-3 円の方程式」

マガジンリスト > 数学Ⅱ編 2.図形と方程式 > 2-3 円の方程式


はじめに

今回は、数学IIで学ぶ「円の方程式」について、Processingの circle 関数を用いていくつかの円を描くプログラムを作成します。

円の方程式

まず、円の方程式について解説しておきます。

円の方程式

中心$${(a,b)}$$、半径$${r}$$ $${(x-a)^2+(y-b)^2=r^2}$$
一般形 $${x^2+y^2+lx+my+n=0}$$(ただし、$${l^2+m^2-4n>0}$$)

円を描く

では、いくつかの円を描くプログラムを作成していきます。

問題
次のような円を描け。
(1) 中心が$${(-3,4)}$$、半径が$${5}$$
(2) 中心が$${(4,2)}$$で点$${(1,3)}$$を通る
(3) 直径の両端が$${(2,5)}$$、$${(4,-7)}$$

アルゴリズム設計

プログラミング言語Processingでは、円を描くための関数 circle が準備されています。(なお、circle 関数については記事『高校数学をプログラミングで解く(準備編)「2-1 Processingで図形を描く」』でも解説しています。)

circle(x, y, d);

各引数は次のようになっています。

x:円の中心のx座標 float型
y:円の中心のy座標 float型
d:円の直径の大きさ float型

今回はこの circle 関数を利用します。
問題1(1)は、中心座標$${(x,y)}$$と半径$${r}$$が与えられているので、直径$${d=2r}$$であることに注意しておけば circle 関数で描くことができます。
問題1(2)は、中心座標$${(x,y)}$$と円が通る点$${(x_1,y_1)}$$が与えられているので、円の半径を$${r=\sqrt{(x_1-x)^2+(y_1-y)^2}}$$で計算しておけば、circle 関数で描くことができます。
問題1(3)は、直径の両端となる2点$${(x_1,y_1), (x_2,y_2)}$$が与えられているので、円の中心座標$${(x,y)}$$を

$$
x=\frac{x_1+x_2}{2}, \ y=\frac{y_1+y_2}{2}
$$

で計算し、円の直径$${d}$$を、

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

で計算しておけば、この円も circle 関数で描くことができます。

プログラム 

それでは、問題1の円を描くプログラムを作成します。
今回、円だけでなく、中心座標の位置や円が通る点などもキャンバス上にプロットできるように記事『高校数学をプログラミングで解く(数学II編)「2-2 2直線の関係」』でのスケッチ「plotSymmetricPoint」内で作成した plot_point 関数を利用したいので、スケッチ「plotSymmetricPoint」を再利用します。以下の zip ファイルをダウンロードして展開または解凍してご利用ください。

そして、スケッチの名前(フォルダ名)を「drawCircles」と変更し、またスケッチ「drawCircles」内の「plotSymmetricPoint.pde」ファイルの名前を「drawCircles.pde」に変更します。そして、pdeファイル「drawCircles.pde」をダブルクリックしてスケッチ「drawCircles」の開発環境ウィンドウを立ち上げます。開発環境ウィンドウのタブ欄で「drawCircles」タブを選択し、そのテキストエリアのソースコードを以下で書き換えます。

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);
  
  // (1) 中心が(-3,4)、半径が5の円
  stroke(255,0,0);
  float x = -3.0;
  float y = 4.0;
  float r = 5.0;
  draw_circle(x, y, r);
  plot_point(x,y);

  // (2) 中心が(4,2)で、点(1,3)を通る円
  stroke(0,255,0);
  x = 4.0;
  y = 2.0;
  float x1 = 1.0;
  float y1 = 3.0;
  r = sqrt((x1-x)*(x1-x)+(y1-y)*(y1-y));
  draw_circle(x, y, r);
  plot_point(x,y);
  plot_point(x1,y1);
  
  // (3) 直径の両端が(2,5)、(4,-7)となる円
  stroke(0,0,255);
  x1 = 2.0;
  y1 = 5.0;
  float x2 = 4.0;
  float y2 = -7.0;
  x = (x1+x2)/2.0;
  y = (y1+y2)/2.0;
  r = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))/2.0;
  draw_circle(x, y, r);
  plot_point(x,y);
  plot_point(x1,y1);
  plot_point(x2,y2);

}

// 中心(x,y)、半径rの円を描く関数
void draw_circle(
  float x, // 円の中心のx座標
  float y, // 円の中心のy座標
  float r  // 円の半径
){
  float X, Y; // キャンバス上の座標
  // キャンバス上の座標位置に換算
  X = width / 2.0 / x_range * x;
  Y = height / 2.0 / y_range * y;
  // 半径をキャンバス上の大きさに換算
  float R = width / 2.0 / x_range * r;
  // 円を描画
  circle(X, Y, 2.0*R);
}

// 座標(x,y)に点をプロットする関数
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);
}

ソースコード1 問題1の各種の円を描くプログラム

今回、円を描くために circle 関数を利用しますが、引数に与える中心座標や直径の長さとして$${xy}$$座標系での値を単純に与えることはできず、キャンバス上の座標に換算してから与える必要があります。その換算を含めて円を描画できるように関数 draw_circle を準備しました。

ソースコード1を、スケッチ「drawCircles」の「drawCircles」タブのテキストエディタ部分に書いて実行すると、図1のように、実行ウィンドウのキャンバス上に問題(1)の円が赤色、問題(2)の円が緑色、問題(3)の円が青色でそれぞれ描かれます。

図1 問題1の3つの円

3点を通る円を描く

次に、異なる3点を通る円を描くプログラムを作成します。

問題2
3点$${\mathrm{A}(1,0)}$$、$${\mathrm{B}(2,-1)}$$、$${\mathrm{C}(3,-3)}$$を通る円を描け。

アルゴリズム設計

3点$${\mathrm{A}(x_1,y_1)}$$, $${\mathrm{B}(x_2,y_2)}$$, $${\mathrm{C}(x_3,y_3)}$$を通る円の中心座標と半径を求めることができれば、あとは circle 関数を用いて描くことができます。そのため、円の中心座標と半径を求めておきます。
 円の中心座標$${(x_c, y_c)}$$は、線分$${\mathrm{AB}}$$の垂直二等分線と線分$${\mathrm{BC}}$$の垂直二等分線との交点として求めることができます。

図2 中心座標の算出

線分$${\mathrm{AB}}$$の垂直二等分線は、線分$${\mathrm{AB}}$$の中点$${(x_{m1}, y_{m1})}$$と垂直二等分線の傾きを$${m_1}$$とすると、

$$
y=m_1(x-x_{m1})+y_{m1}
$$

と表すことができます。ここで、

$$
x_{m1} = \frac{x_1+x_2}{2}, \ y_{m1} = \frac{y_1+y_2}{2}, \ m_1 = -\frac{x_2-x_1}{y_2-y_1}
$$

と計算することができます。同様にして、線分$${\mathrm{BC}}$$の垂直二等分線は、線分$${\mathrm{BC}}$$の中点$${(x_{m2}, y_{m2})}$$と垂直二等分線の傾きを$${m_2}$$とすると、

$$
y=m_2(x-x_{m2})+y_{m2}
$$

と表すことができます。ここで、

$$
x_{m2} = \frac{x_2+x_3}{2}, \ y_{m2} = \frac{y_2+y_3}{2}, \ m_2 = -\frac{x_3-x_2}{y_3-y_2}
$$

と計算できます。これらの2つの垂直二等分線の方程式を連立させて解くことで、円の中心座標$${(x_c, y_c)}$$は

$$
x_c = \frac{(m_2 x_{m2} - m_1 x_{m1}) - (y_{m2} - y_{m1})}{m_2 - m_1}, \ y_c = m_1(x_c-x_{m1})+y_{m1}
$$

と求めることができます。
最後に、円の半径$${r}$$は、

$$
r = \sqrt{(x_1-x_c)^2+(y_1-y_c)^2}
$$

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

プログラム

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

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);
  
  // 3点(1,0),(2,-1),(3,-3)を通る円
  stroke(255,0,0);
  float x1 = 1.0;
  float y1 = 0.0;
  float x2 = 2.0;
  float y2 = -1.0;
  float x3 = 3.0;
  float y3 = -3.0;
  draw_circle_3points(x1,y1,x2,y2,x3,y3);
  plot_point(x1, y1);
  plot_point(x2, y2);
  plot_point(x3, y3);
  
}

// 異なる3点を通る円を描く関数
void draw_circle_3points(
  float x1, // 1つ目の点のx座標
  float y1, // 1つ目の点のy座標
  float x2, // 2つ目の点のx座標
  float y2, // 2つ目の点のy座標
  float x3, // 3つ目の点のx座標
  float y3  // 3つ目の点のy座標
){
  // 1つ目と2つ目を結ぶ線分の垂直二等分線
  float xm1 = (x1+x2)/2.0; // 線分の中点のx座標
  float ym1 = (y1+y2)/2.0; // 線分の中点のy座標
  float m1 = -(x2-x1)/(y2-y1); // 垂直二等分線の傾き
  
  // 2つ目と3つ目を結ぶ線分の垂直二等分線
  float xm2 = (x2+x3)/2.0; // 線分の中点のx座標
  float ym2 = (y2+y3)/2.0; // 線分の中点のy座標
  float m2 = -(x3-x2)/(y3-y2); // 垂直二等分線の傾き
  
  // 描きたい円の中心
  float xc = ((m2*xm2 - m1*xm1) - (ym2 - ym1))/(m2 - m1);
  float yc = m1 * (xc - xm1) +ym1;
  // 描きたい円の半径
  float r = sqrt((x1 - xc)*(x1 - xc)+(y1 - yc)*(y1 - yc));
  
  float X, Y; // キャンバス上の座標
  // キャンバス上の座標位置に換算
  X = width / 2.0 / x_range * xc;
  Y = height / 2.0 / y_range * yc;
  // 半径をキャンバス上の大きさに換算
  float R = width / 2.0 / x_range * r;
  // 円を描画
  circle(X, Y, 2.0*R);
}

// 座標(x,y)に点をプロットする関数
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);
}

ソースコード2 異なる3点を通る円を描くプログラム

今回のプログラムでは、異なる3点の座標を与えるとそれら3点を通る円をアルゴリズム設計のところで説明した手順で描く関数「draw_circle_3points」を準備しました。

ソースコード2を、スケッチ「drawCircle_3points」の「drawCircle_3points」タブのテキストエディタ部分に書いて実行すると、図3のように、実行ウィンドウのキャンバス上に問題2の円が赤色で描かれます。

図3 異なる3点を通る円

まとめ

今回は、数学IIで学ぶ「円の方程式」について、Processingの circle 関数を用いていくつかの円を描くプログラムを作成しました。
円を描くこと自体は、記事『高校数学をプログラミングで解く(準備編)「2-1 Processingで図形を描く」』でもすでに描いていましたが、今回は、設定した$${xy}$$座標上にきちんと円が描かれるように、直接 circle 関数を呼び出すのではなく、座標変換を行ってから円を描くように新たに関数を作成しました。このように問題に合うように再度関数化することはよく行いますので、少しずつ慣れていきましょう。

参考文献

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

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