2点を通る2次曲線

 今回は2点(x1, y1)(x2, y2)を通る2次曲線y=ax2+bx+cを求めてみます。ただし、2点の座標のみだと曲線を1つに特定できませんので、同時にaの値も指定するようにしましょう。つまり、「指定されたaの値と曲線が通る2点の座標から、2次曲線の式を求める」わけですね。

2次曲線の式

 まず、未知のパラメータb, cを求めて2次曲線の式を確定させるために、2次曲線の式y=ax2+bx+ca, b, cそれぞれについて解いてみましょう。すると

  a=(y-bx-c)/x2 - (1)
  b=(y-ax2-c)/x - (2)
  c=y-ax2-bx    - (3)

 という関係が導かれます。この関係は(x1, y1)(x2, y2)でも成り立っているので、(x1, y1)(x2, y2)とaの値を入れて未知のb, cを求める事にします。式を見ると、(3)に入れるのが楽そうですね。(3)の(x, y)に(x1, y1)(x2, y2)を代入すると、

  c=y1-ax12-bx1=y2-ax22-bx2 -(4)

 となって、この式から

  y1-ax12-bx1=y2-ax22-bx2 -(5)

 という関係が導かれました。(5)式の変数のうち、(x1, y1)(x2, y2)とaは既に与えられているので、未知の変数はbのみ。(5)式をbについて解けばbの値が求まる事になります。

  bx1-bx2=-ax12+ax22+y1-y2
  b=(-ax12+ax22+y1-y2)/(x1-x2) -(6)

 後は、求めたbを(3)式に入れてcを求めるだけですね。

2次曲線の表示

 未知であったb, cを求め2次曲線の式を確定する方法がわかったので、実際に2点とaを指定して2次曲線を描くJavaアプレットを作ってみましょう。今回は、2次曲線を描くグラフとして100×100のImageを用意し、その各座標を(-50,-50)-(49,49)に対応させて使う事にしました。Imageは、4倍に拡大して表示します。

 2点の入力には、マウスを使います。2点の座標を入れるPoint型配列pt[2]を用意して、グラフ上でマウスがクリックされたらその座標を入れていきましょう。現在指定されている点の数は変数npに保持し、2点以上は入力できない、また同じx座標の点も入力できないようにします。

  public void mouseClicked(MouseEvent e) { // マウスクリック

      int x=(int)((e.getX()-4)/4);
      int y=(int)((e.getY()-4)/4);

      if (x<0 || x>99 || y<0 || y>99 || np>1)
          return;

      if (np==1 && pt[0].x==x-50)
          return;

      y=99-y;

      pt[np].x=x-50;
      pt[np].y=y-50;

      // TextFieldに点の座標を表示
      fp[np].setText(String.valueOf(pt[np].x)+","+String.valueOf(pt[np].y));

      np++;

      repaint();

  }

 2点とaの値を指定したら、Drawボタンで2次曲線を描画します。描画は、描画関数paint内で行うようにしました。paintの中でまずb, cを求め、続いてグラフ上の各x座標に対するyを求めて行きます。

  private double func(double x) { // 2次曲線の関数
      return a*x*x+b*x+c;
  }

  public void paint(Graphics g) {

      int x,y,xx,yy;
      double x1=pt[0].x,x2=pt[1].x,y1=pt[0].y,y2=pt[1].y;

      g_img.setColor(Color.white);
      g_img.fillRect(0,0,100,100);

      if (draw) {

          g_img.setColor(Color.red);

          // 入力されたaの値を取得
          a=Double.valueOf(fa.getText()).doubleValue();

          b=(y1-y2-a*x1*x1+a*x2*x2)/(x1-x2);
          c=y1-a*x1*x1-b*x1;

          if (c<0) // TextFiledに2次曲線の式を表示
              fy.setText(String.valueOf(a)+"x2+"+String.valueOf(b)
                         +"x"+String.valueOf(c));
          else
              fy.setText(String.valueOf(a)+"x2+"+String.valueOf(b)
                         +"x"+"+"+String.valueOf(c));

          // 2次曲線を描画
          xx=0;
          yy=99-((int)func(-50)+50);

          for (x=0;x<100;x++) {

              y=99-((int)func(x-50)+50);
              g_img.fillRect(x,y,1,1);

              g_img.drawLine(xx,yy,x,y);

              xx=x;
              yy=y;

          }

      }

      g_img.setColor(Color.blue);

      for (int i=0;i<2;i++) // 指定された点を表示
          if (pt[i].x!=999)
              g_img.fillRect(pt[i].x+50,99-(pt[i].y+50),1,1);

      g.drawImage(img,4,4,400,400,this);
      g.setColor(Color.gray);
      g.drawLine(4,204,404,204);
      g.drawLine(204,4,204,404);
      g.setColor(Color.black);
      g.drawRect(4,4,400,400);

  }

プログラム

 グラフ内の2点をマウスで指定し、aの値を入力したらdraw!ボタンをクリックしてください。2点を繋ぐ2次曲線とその式が表示されます。やり直す時は、Clear!ボタンでクリアできます。

プログラムソース表示

実行すると、数学の授業でもおなじみの「放物線」が描かれますね。


数学アルゴリズム演習室 > プログラミング資料庫