楕円の計算と作図

 楕円の作図に関しては、作図の項目にもありますが、ここでは、離心率の観点から、検討します。
楕円の、作図、積分計算や接線等のプログラムを検討してきましたが、基本的な部分について抜けていましたので、改めてプログラムを組んでみました。
計算そのものは、非常に単純な計算です。

 楕円、双曲線の公式は、上記です。
x,yは座標、a,bは、楕円の半径で、離心率 k パラメータ m=k2 です。
楕円の半径aを1とすると、xに対するyの値は、y=√(b2-b2x2)となるのは周知の如くです、b2はmに対して b2=1-m となります。

 

 mが0より小さいと、aの半径よりbの半径が大きい縦長の楕円となります。
mの値がゼロだと円、ゼロより大きく1以下なら、横長の楕円です。
m=1だと、Xの値が-aから+aの直線となり
1より大きくなると、双曲線となるので、双曲線も楕円に含まれることになるようです。
 双曲線となった時の漸近線の角度は、楕円のパラメータmの値の実数積分範囲の角度を α とすると π/2 - α の角度となります。
楕円積分が、y軸から始まるためです。 
ですがが、mが1より大きいときの楕円積分の値の実数となる部分は、双曲線が作図された、線のない部分なので、疑問が残ります。
虚数となるのは、実際に線が描画されている部分です。
 

 入力をmかkを選択して作図する簡単なプログラムです。



プログラム

unit main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    LabeledEdit1: TLabeledEdit;
    Image1: TImage;
    LabeledEdit2: TLabeledEdit;
    RadioButton1: TRadioButton;
    RadioButton2: TRadioButton;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure clear;
    procedure Linetod(x, y: double);
    procedure Movetod(x, y: double);
    procedure anglline(q, r: double);
    procedure mnoe;
    procedure large(m :double);
    procedure normal(m :double);
    procedure minus(m :double);
    function mtobh2(m: double): double;
    procedure ellipse(bh2, dx, one: double; c : integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses system.Math;

var
  yc, xc    : integer;    // 中心座標
  sc : double = 30;        // スケール


procedure TForm1.clear;
var
  rect: Trect;
begin
  Rect.Top  := 0;
  Rect.Left := 0;
  Rect.Right  := Image1.Width;
  Rect.Bottom := Image1.Height;
  Image1.canvas.Brush.Style := bsSolid;
  Image1.canvas.Brush.Color := clBtnface;
  Image1.canvas.FillRect(Rect);
end;

procedure TForm1.Linetod(x, y: double);
var
  xi, yi: integer;
begin
  xi := round(x * sc + xc);
  yi := round(yc - y * sc);
  Image1.canvas.Lineto(xi, yi);
end;

procedure TForm1.Movetod(x, y: double);
var
  xi, yi: integer;
begin
  xi := round(x * sc + xc);
  yi := round(yc - y * sc);
  Image1.canvas.Moveto(xi, yi);
end;

// q 角度deg  r 半径
procedure TForm1.anglline(q, r: double);
var
  x, y  : integer;
begin
  x := round(cos(q) * r * sc);
  y := round(sin(q) * r * sc);
  Image1.canvas.Moveto(xc - x, yc - y);
  Image1.canvas.lineto(xc + x, yc + y);
end;

// パラメータm  m = k^2 から b^2の値計算  k 離心率
// m = (a^2 - b^2) / a^2
// m = 1- b^2           a = 1 として
// b^2 = 1- m
// m > 1 の時 B^2 < 0  となり x^2 / a^2 - y^2 / b^2 = 1   放物線となります
// m = 1 の時  y = 0 x で水平直線
// 0 < m  < 1 の時 横長楕円
// m = 0 円
// m < 0 の時 縦長楕円
function TForm1.mtobh2(m: double): double;
var
  bh: double;                      // b^2
begin
  bh := 1 - m;                     // x^2 / a^2 - y^2 / bh = 1      a = 1
  result := bh;
  if bh >= 0 then begin
    bh := sqrt(bh);
    Image1.Canvas.TextOut(10, Image1.Height - 17, ' a = 1, ' + 'b = ' + floatTostr(bh));
  end
  else begin
    bh := sqrt(-bh);
    Image1.Canvas.TextOut(10, Image1.Height - 17, ' a = 1, ' + 'b = ' + floatTostr(bh) + 'i');
  end;
end;

// m = 1 の時の 作図
// y^2 = 0 +  0 * x^2
// y = 0 * x             水平直線
procedure TForm1.mnoe;
begin
  sc := 10;

  image1.Canvas.Pen.Color := clred;
  Image1.Canvas.Pen.Style := psDashDot;
  movetod(0, 5);
  lineTod(0, -5);

  image1.Canvas.Pen.Color := clblack;
  Image1.Canvas.Pen.Style := psSolid;
  movetod(-15, 0);
  lineTod(15, 0);

  Image1.Canvas.TextOut(10, Image1.Height - 17, ' a = 1, ' + 'b = 0');
end;

// 楕円 双曲線 作図
// bh2   b^2
// dx    Δx
// one   xの最小値 0 or 1
// c     分割数
procedure TForm1.ellipse(bh2, dx, one: double; c : integer);
var
  i : integer;
  x, yh2, y: double;
begin
  x := one;
  yh2 := bh2 - bh2 * x * x;
  y := sqrt(yh2);
  movetod(x, y);
  for i:= 1 to c do begin
    x := i * dx + one;
    yh2 := bh2 - bh2 * x * x;
    y := sqrt(yh2);
    linetod(x, y);
  end;
  x := one;
  yh2 := bh2 - bh2 * x * x;
  y := sqrt(yh2);
  movetod(x, -y);
  for i:= 1 to c do begin
    x := i * dx + one;
    yh2 := bh2 - bh2 * x * x;
    y := sqrt(yh2);
    linetod(x, -y);
  end;
  x := one;
  yh2 := bh2 - bh2 * x * x;
  y := sqrt(yh2);
  movetod(-x, y);
  for i:= 1 to c do begin
    x := i * dx + one;
    yh2 := bh2 - bh2 * x * x;
    y := sqrt(yh2);
    linetod(-x, y);
  end;
  x := one;
  yh2 := bh2 - bh2 * x * x;
  y := sqrt(yh2);
  movetod(-x, -y);
  for i:= 1 to c do begin
    x := i * dx + one;
    yh2 := bh2 - bh2 * x * x;
    y := sqrt(yh2);
    linetod(-x, -y);
  end;
end;

// m > 1
// x^2 / a^2 + y^2 / b^2 = 1    楕円の公式
// y^2 = b^2 - b^2 * x^2        a = 1 として
// y = √y
// xの値は x >= 1  or x <= -1
procedure TForm1.large(m :double);
const
  c = 50;
var
  Q, Qb   : double;
  bh2, k  : double;
  dx      : double;
begin
  Sc := 15;
  k := sqrt(m);
  Qb := arcsin(1 / k);
  Q := pi / 2 - Qb;
  Image1.Canvas.TextOut(10, 0, '漸近線角度 = ' + floatTostr(Q / pi * 180) + '°');
  Image1.Canvas.pen.Color := clred;
  anglline(Q, 12);
  anglline(-Q, 12);

  Image1.Canvas.Pen.Color := clblack;
  Image1.Canvas.Pen.Style := psSolid;
  bh2 := mtobh2(m);
  dx := 12 * cos(Q) / c;
  // 放物線
  ellipse(bh2, dx, 1, c);

  // 内接楕円
//  Image1.Canvas.Pen.Color := clgreen;
//  dx := 1 / c;
//  ellipse(-bh2, dx, 0, c);
end;

// 0 <= m < 1
// m < 1 はすべて同じです計算です 作図上分けています (円と横長楕円)
// x^2 / a^2 + y^2 / b^2 = 1    楕円の公式
// y^2 = b^2 - b^2 * x^2        a = 1 として
// y = √y
// xの値は -1 <= x <= 1
procedure TForm1.normal(m :double);
const
  c = 100;
var
  bh2 : double;
  dx  : double;
begin
  sc := 100;
  image1.Canvas.Pen.Color := clred;
  Image1.Canvas.Pen.Style := psDashDot;
  movetod(0, -1.2);
  linetod(0, 1.2);
  movetod(-1.2, 0);
  linetod(1.2, 0);

  Image1.Canvas.Pen.Color := clblack;
  Image1.Canvas.Pen.Style := psSolid;
  bh2 := mtobh2(m);
  dx := 1 / c;
  // 円、横長楕円
  ellipse(bh2, dx, 0, c);
end;

// m < 0
// m < 1 はすべて同じです計算です 作図上分けています (縦長楕円)
// x^2 / a^2 + y^2 / b^2 = 1    楕円の公式
// y^2 = b^2 - b^2 * x^2        a = 1 として
// y = √y
// xの値は -1 <= x <= 1
procedure TForm1.minus(m :double);
const
  c = 50;
var
  bh2, yh2: double;
  dx, x, y     : double;
begin
  bh2 := mtobh2(m);
  dx := 1 / c;
  x := 0;
  yh2 := bh2 - bh2 * x * x;
  y := sqrt(yh2);
  sc := 100;
  Image1.Canvas.Pen.Color := clred;
  Image1.Canvas.Pen.Style := psDashDot;
  movetod(0, -1.2);
  linetod(0, 1.2);
  movetod(-1.2, 0);
  linetod(1.2, 0);
  if 1 <= y then sc := 100 / y;

  Image1.Canvas.Pen.Color := clblack;
  Image1.Canvas.Pen.Style := psSolid;
  // 縦長楕円
  ellipse(bh2, dx, 0, c);
end;

// 値入力と楕円計算
procedure TForm1.BitBtn1Click(Sender: TObject);
var
  m, k     : double;
  ch, l : integer;
  kstr, kss: string;
  c : char;
  FI : boolean;
begin
  m := 0;
  if radiobutton1.Checked = true then begin
    val(labelededit1.Text, m, ch);
    if ch <> 0 then begin
      application.MessageBox('入力値に誤りがあります。','注意',0);
      exit;
    end;
  end;
  FI := False;
  if radiobutton2.Checked = true then begin
    kstr := LabeledEdit2.Text;
    l       := length(kstr);                     // 文字の長さ取得
    c       := kstr[l];                          // iの文字確認
    if (c = 'i') or (c = 'I') then begin         // i虚数指定だったら
      kss   := copy(kstr, 1, l - 1);             // iの前までコピー
      FI := True;                                // 虚数フラグセット
    end
    else Kss := kstr;
    val(kss, k, ch);
    if ch <> 0 then begin
      application.MessageBox('k(離心率)の値に間違いがあります。','k(離心率)',0);
      exit;
    end;
    m := k * K;
    if FI then m := -m;                          // kが虚数だったらm -> -m
  end;
  clear;                                         // 画面消去
  if m < 0 then begin
    k := sqrt(-m);
    kstr := 'k = ' + floatTostr(k) + 'i';
  end
  else begin
    k := sqrt(m);
    kstr := 'k = ' + floatTostr(k);
  end;
  Image1.Canvas.TextOut(10,15, kstr);
  if m > 1 then large(m);
  if m = 1 then  mnoe;
  if (0 <= m) and (m < 1) then normal(m);
  if m < 0 then minus(m);
end;

// 初期設定
procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Top := 10;
  Image1.Left := 10;
  Image1.height := clientheight - 20;
  Image1.Width :=  clientwidth - 150;
  xc := Image1.Width div 2;           // 中心座標X
  yc := Image1.Height div 2;          // 中心座標Y
  image1.Canvas.Font.Size := 11;
  Image1.Canvas.Pen.Width := 1;
  clear;
  normal(0.64);
end;

end.

download ellipse_k.zip


各種プログラム計算例に戻る