放物線と焦点
放物線のプログラムに、光線の角度と、焦点の関係を作図するルーチンを追加してみました。
光線の角度のズレに対する焦点の変化が良く理解できます。
放物線二次式と一次式の交点を求めるプログラムに入射光の角度と焦点の関係を作図するルーチンを追加した場合の実行例です。
光線の角度を固定して、放物線を移動するのは大変なので、光線の角度を変更しています。
二次式と直線の値、光の角度を決め計算ボタンをクリックすることで最初の作図がされます。
光線の角度は90度のまゝで変更しなくても、下のスライドバーを動かすことにより、光線の角度と、反射光の長さを変えることが出来ます。
僅かな角度のズレで、一点に焦点が集まらなくなることがわかります。
天体望遠鏡の場合、星はかなり遠く完全に平行光線でありますが、放物面は目的とする星に対して精度よく向ける必要があります。
焦点距離を長くすれば、計算上のズレは小さくなるようですが、放物面の精度を高くする必要があるようです。
プログラム
条件によっては、光線が放物面で実際には複数回反射する場合も場合もありますが、此処の計算では一度の反射しか計算しません。
unit Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, Vcl.StdCtrls, Vcl.ExtCtrls, VCLTee.TeEngine, VCLTee.Series, VCLTee.TeeProcs, VCLTee.Chart, Vcl.ComCtrls; type TForm1 = class(TForm) Chart1: TChart; Series1: TLineSeries; Series2: TLineSeries; Memo1: TMemo; Series3: TLineSeries; Series4: TLineSeries; Series6: TLineSeries; Image1: TImage; Panel1: TPanel; Label1: TLabel; Label3: TLabel; LabeledEdit1: TLabeledEdit; LabeledEdit3: TLabeledEdit; LabeledEdit4: TLabeledEdit; LabeledEdit5: TLabeledEdit; Button1: TButton; LabeledEdit2: TLabeledEdit; Label4: TLabel; Label2: TLabel; LabeledEdit6: TLabeledEdit; Label5: TLabel; Series5: TPointSeries; Label6: TLabel; ScrollBar1: TScrollBar; Label7: TLabel; ScrollBar2: TScrollBar; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); procedure ScrollBar2Scroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); procedure LabeledEdit1Change(Sender: TObject); procedure LabeledEdit4Change(Sender: TObject); private { Private 宣言 } function datainput: boolean; function calc_point_of_intersection: boolean; procedure graphDraw; function calc_arc: boolean; procedure fpoint(x, y, ql, qs, xl : double; var xf, yf: double); procedure division; procedure focusPoint; procedure ImageClear; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses math; var x1, x2 : double; // 放物線と直線の交点 y1, y2 : double; xc0, yc0 : double; // 放物線原点 xcc, ycc : double; // 接線の交点 a1, b1, c1 : double; // 放物線二次式の値 b2, c2 : double; // 直線の値 alpha, beta : double; // 交点の位置面積計算用 alpy, bety : double; CF : boolean; // 交点の有無フラグ Q0 : double; // 入射光線角度仮 focusY : double; // 焦点のY位置 focusL : double; // 焦点の距離 ImgF : boolean; // Imageの作図のみのフラグ sclpos : double; // 反射光線の長さ係数 SCF : Boolean; // 反射光線の長さ調整有無フラグ STF : Boolean; // Button1により計算開始フラグ // 入力値処理 function TForm1.datainput: boolean; var ch: integer; Q, Qmin, Qmax: double; Qstr : string; begin result := false; SCF := False; // 反射光線の長さ調整有無フラグ STF := True; // Button1により計算開始フラグ val(LabeledEdit1.Text, a1, ch); if ch <> 0 then begin application.MessageBox('α1の値に間違いがあります。','',0); exit; end; if a1 = 0 then begin application.MessageBox('α1の値はゼロではいけません。','',0); exit; end; val(LabeledEdit2.Text, b1, ch); if ch <> 0 then begin application.MessageBox('β1の値に間違いがあります。','',0); exit; end; val(LabeledEdit3.Text, c1, ch); if ch <> 0 then begin application.MessageBox('C1の値に間違いがあります。','',0); exit; end; val(LabeledEdit4.Text, b2, ch); if ch <> 0 then begin application.MessageBox('β2の値に間違いがあります。','',0); exit; end; val(LabeledEdit5.Text, c2, ch); if ch <> 0 then begin application.MessageBox('C2の値に間違いがあります。','',0); exit; end; val(LabeledEdit6.Text, Q0, ch); if ch <> 0 then begin application.MessageBox('光線角度の値に間違いがあります。','',0); exit; end; Q := arctan(b2) / pi * 180; Qstr := floatTostrF(Q, ffFixed, 5,3); Qmin := 0; Qmax := 180; // 計算出来る光角度範囲の設定 if a1 > 0 then begin if Q > 0 then begin Qmin := Q; Qmax := 180; end; if Q < 0 then begin Qmin := 0; Qmax := Q + 180 end; end else begin if Q > 0 then begin Qmin := 0; Qmax := 180 - Q; end; if Q < 0 then begin Qmin := - Q; Qmax := 180; end; end; scrollbar2.Max := round(Qmax - 0.5); scrollbar2.Min := round(Qmin + 0.5); scrollbar1.Position := 50; Qstr := FloatTostrF(Qmin, ffFixed, 4, 1) + '°<角度<' + FloatTostrF(Qmax, ffFixed, 4, 1)+ '°'; LabeledEdit6.EditLabel.Caption := Qstr; if Q0 < Qmin then begin application.MessageBox('光線の角度が小さすぎます。','',0); exit; end; if Q0 > Qmax then begin application.MessageBox('光線の角度が大きすぎます。','',0); exit; end; if Q0 = 0 then begin application.MessageBox('光線の角度がゼロでは計算出来ません。','',0); exit; end; if Q0 = 180 then begin application.MessageBox('光線の角度が180°では計算出来ません。','',0); exit; end; scrollbar2.Position := round(Q0); SCF := True; // 反射光線の長さ調整有無フラグ // 条件により入力角度を計算用角度に変更 if a1 < 0 then Q0 := - Q0; if a1 > 0 then begin if Q0 > 90 then Q0 := Q0 - 180; end else begin if Q0 <= -90 then Q0 := 180 + Q0; end; result := true; end; // 面積 弧の長さΔx分割計算 procedure TForm1.division; var i, n : integer; dx, dx2 : double; Xmax, Xmin : double; x0, y0 : double; y3 : double; L, ls : double; x, y : double; begin n := 10000; dx := (x2 - x1) / n; L := 0; x0 := x1; y0 := x0 * x0 * a1 + x0 * b1 + c1; for i := 1 to n do begin x := i * dx + x1; y := x * x * a1 + x * b1 + c1; Xmin := (x - x0); Xmax := (y - y0); ls := sqrt(Xmin * Xmin + Xmax * Xmax); L := L + Ls; x0 := x; y0 := y; end; memo1.Lines.Add('分割積分長さ = ' + floatTostr(L)); dx2 := dx / 2; L := 0; for i := 0 to n - 1 do begin x := i * dx + dx2 + x1; y3 := x * b2 + c2; y := x * x * a1 + x * b1 + c1 - y3; ls := y * dx; L := L + Ls; end; L := abs(L); memo1.Lines.Add('分割積分面積= ' + floatTostr(L)); end; // 弓形部長さ計算 // 右と左に分けて計算 function TForm1.calc_arc: boolean; var L, L1, L2 : double; s1, s2 : double; a3, b3 : double; a4, b4 : double; begin xc0 := -b1 / a1 / 2; // 放物線 変曲点 原点X yc0 := xc0 * xc0 * a1 + xc0 * b1 + c1; // 変曲点 原点y memo1.Lines.Add('O x,y = ' + floatTostr(xc0) + ', ' + floatTostr(yc0)); b3 := abs(x1 - xc0) * 2; a3 := abs(y1 - yc0); // 放物線のx1の高さ if a3 <> 0 then begin s1 := sqrt(b3 * b3 + 16 * a3 * a3); L1 := s1 / 2 + b3 * b3 / 8 / a3 * ln((4 * a3 + s1) / b3); end else L1 := 0; b4 := abs(x2 - xc0) * 2; a4 := abs(y2 - yc0); // 放物線のx2の高さ if a4 <> 0 then begin s2 := sqrt(b4 * b4 + 16 * a4 * a4); L2 := s2 / 2 + b4 * b4 / 8 / a4 * ln((4 * a4 + s2) / b4); end else L2 := 0; if (x1 - xc0) * (x2 - xc0) > 0 then L := abs(L2 - L1) / 2 else L := (L1 + L2) / 2; memo1.Lines.Add(''); memo1.Lines.Add('弓形部弧長さ = ' + floatTostr(L)); result := true; end; // 放物線弓形部の面積 // 1/6公式で計算 function TForm1.calc_point_of_intersection: boolean; var i , n: integer; dx : double; Xmax, Xmin : double; x, y : double; a0, b0, c0 : double; b3, c3, b4, c4 : double; d, e, s : double; ycp : double; begin result := False; a0 := a1; // 放物線と直線の交点計算 b0 := b1 - b2; c0 := c1 - c2; d := b0 * b0 - 4 * a0 * c0; if d < 0 then exit; // ルートの中がマイナスなら交点なし e := sqrt(d); x1 := (-b0 - e) / 2 / a0; // 交点x1座標 x2 := (-b0 + e) / 2 / a0; // 交点x2座標 alpha := x1; beta := x2; y1 := x1 * b2 + c2; // 交点y1座標 y2 := x2 * b2 + c2; // 交点y2座標 alpy := y1; bety := y2; if beta < alpha then begin // 値の大きさで入れ替え β > αにします、面積計算の為 alpha := x2; beta := x1; alpy := y2; bety := y1; end; focusPoint; // 光軸による焦点位置の計算 memo1.Lines.Add('α x,y = ' + floatTostr(alpha) + ', ' + floatTostr(alpy)); memo1.Lines.Add('β x,y = ' + floatTostr(beta) + ', ' + floatTostr(bety)); b3 := 2 * a1 * alpha + b1; // y1=m1x+c1 のm1の値 c3 := - b3 * alpha + alpy; // y1=m1x+c1 のc1の値 b4 := 2 * a1 * beta + b1; // y2=m2x+c2 のm2の値 c4 := - b4 * beta + bety; // y2=m2x+c2 のc2の値 if b3 <> b4 then // 二つの直線の傾きに差があったら交点あり xcc := (c4 - c3) / (b3 - b4) // y1=m1x+c1 と y2=m2x+c2 の交点xの値 else xcc := 0; // 差が無かったら交点無し ycc := b3 * xcc + c3; // y1=m1x+c1 と y2=m2x+c2 の交点yの値 memo1.Lines.Add('C x,y = ' + floatTostr(xcc) + ', ' + floatTostr(ycc)); if not calc_arc then exit; result := true; s := abs(a1) * (beta - alpha) * (beta - alpha) * (beta - alpha) / 6; // 弓形部面積計算 1/6公式 memo1.Lines.Add('弓形部面積 = ' + floatTostr(s)); if (b3 = b4) then exit; division; // 面積 弧の長さΔx分割計算 if a1 > 0 then begin if yc0 > ycc then ycp := ycc - (yc0 - ycc) / 2 // 直線のyの描画範囲 else ycp := yc0 - 0.1 / a1; end else begin if yc0 < ycc then ycp := ycc + (ycc - yc0) / 2 // 放物線a1x^2のa1の符号±で方向変更 else ycp := yc0 - 0.1 / a1; end; n := 1000; Xmin := x1 - (x2 - X1) / 4; Xmax := x2 + (X2 - X1) / 4; dx := (Xmax - Xmin) / n; for i := 0 to n do begin // 接線1の描画 x := i * dx + Xmin; y := b3 * x + c3; if a1 > 0 then if y > ycp then Series3.AddXY(x,y); if a1 < 0 then if y < ycp then Series3.AddXY(x,y); end; for i := 0 to n do begin // 接線2の描画 x := i * dx + Xmin; y := b4 * x + c4; if a1 > 0 then if y > ycp then Series4.AddXY(x,y); if a1 < 0 then if y < ycp then Series4.AddXY(x,y); end; end; // x, y 放物線と光線の交点 // ql 光線の角度 // qs 接線の角度 // xl x1,y1 とx2,y2 の距離 // 光線の終端座標 procedure TForm1.fpoint(x, y, ql, qs, xl : double; var xf, yf: double); var qm, qb : double; // qsをゼロにした場合の反射角qm 戻し角qb x1, y1, l : double; x2, y2 : double; dx, dy : double; begin // memo1.Lines.Add('光角度 ' + floatTostr(ql / pi * 180)); // memo1.Lines.Add('接線角度 ' + floatTostr(qs / pi * 180)); qm := (qs - ql); // 接線に対する光線角度計算 if qm < pi then qm := qm + pi; // memo1.Lines.Add('反射角度 ' + floatTostr(qm / pi * 180)); x1 := cos(qm) * xl; // 光線端点x位置計算 y1 := sin(qm) * xl; // 光線端点y位置計算 l := sqrt(x1 * x1 + y1 * y1); // 座標変換用距離計算 qb := qm + qs; // 接線の角度に戻し // memo1.Lines.Add('回転後角度 ' + floatTostr(qb / pi * 180)); x2 := cos(qb) * l; // 接線の角度に戻し後x座標 y2 := sin(qb) * l; // 接線の角度に戻し後y座標 if ql * a1 > 0 then begin // 光線の角度が+だったら x,y標値加算 xf := x + x2; yf := y + y2; end else begin // 光線の角度が-だったら x,y標値減算 xf := x - x2; yf := y - y2; end; // 光端座標がグラフ外になるのを防止します dy := yf - y; dx := xf - x; if yf > Chart1.LeftAxis.Maximum then begin yf := Chart1.LeftAxis.Maximum; xf := dx * ((Chart1.LeftAxis.Maximum - y) / dy) + x; end; if yf < Chart1.LeftAxis.Minimum then begin yf := Chart1.LeftAxis.Minimum; xf := dx * ((Chart1.LeftAxis.Minimum - y) / dy) + x; end; if xf < Chart1.BottomAxis.Minimum then begin xf := Chart1.BottomAxis.Minimum; yf := dy * ((Chart1.BottomAxis.Minimum - x) / dx) + y; end; if xf > Chart1.BottomAxis.Maximum then begin xf := Chart1.BottomAxis.Maximum; yf := dy * ((Chart1.BottomAxis.Maximum - x) / dx) + y; end; end; // 光軸による焦点位置の計算 procedure TForm1.focusPoint; var x, y, m : double; xo : double; // 放物線原点x // yo : double; // 放物線原点y q, qp, mq : double; mfc : double; begin xo := - b1 / a1 / 2; // yo := xo / 2 * b1; // memo1.Lines.Add('o x,y = ' + floatTostr(xo) + ', ' + floatTostr(yo)); x := xo + 2; y := a1 * x * x + b1 * x + c1; // X=1の放物線のyの値 m := 2 * a1 * x + b1; // 接線y=mx+c のm q := arctan(m); // 接線の角度 qp := 2 * q + pi / 2; // 反射角 mq := tan(qp); // 反射光傾き mfc := -mq * x + y; // 反射光直線式 y := mqx + mfc のmfc focusY := xo * mq + mfc; // 中心位置の 光線通過点 焦点位置 end; // 放物線と直線の描画 // 光線作図 procedure TForm1.graphDraw; label IMG; var i, n : integer; dx, dx2 : double; Xmax, Xmin : double; Ymax, Ymin : double; Hmax, Hmin : double; Vmax, Vmin : double; L, ls : double; x, y : double; x3, y3 : double; x4, y4 : double; x0m, y0m : double; x1m, y1m : double; Vx, Vy : double; ypl, ypm : integer; xpl, xpm : integer; ax, ay : double; ysp, ypp : integer; xsp, xpp : integer; fys : integer; ma, mc : double; b0, c0 : double; d, e : double; b3, c3 : double; Q1, Q4, Q5 : double; Q2 : double; mf, mfc : double; yback : double; xl : double; foc : double; begin if ImgF then goto IMG; focusL := 1 / 4 / a1; // 焦点距離計算 // 放物線と交わる直線の描画 n := 1000; Xmin := x1 - (x2 - x1) / 4; // 描画範囲 Xmax := x2 + (x2 - x1) / 4; if (Xmax - Xmin) = 0 then begin // 接線となるときの描画範囲 Xmin := x1 - abs(1 / a1); Xmax := x1 + abs(1 / a1); CF := False; end; if CF then begin // 交点があったら dx := abs(Xmax - Xmin) / 10; if a1 > 0 then begin if Xmin + dx > xc0 then Xmin := xc0 - dx; if Xmax - dx < xc0 then Xmax := xc0 + dx; end else begin if Xmax + dx > xc0 Then Xmax := xc0 - dx; if Xmin - dx < xc0 then Xmin := xc0 + dx; end; end; dx := abs(Xmax - Xmin) / n; if Xmax < Xmin then Xmin := Xmax; for i := 0 to n do begin x := i * dx + Xmin; y := x * x * a1 + x * b1 + c1; // 放物線 Series1.AddXY(x, y); // 放物線のグラフ y := x * b2 + c2; // 直線 Series2.AddXY(x, y); // 直線のグラフ end; if CF then begin // 交点があったら dx := (x2 - x1) / n; for i := 0 to n do begin x := i * dx + x1; y := x * x * a1 + x * b1 + c1; // 放物線 Series6.AddXY(x, y); // 放物線x1,x2間のグラフ end; end; Chart1.Update; application.ProcessMessages; // 描画待ち // Chartの縦横比を同じに設定します Hmax := Chart1.BottomAxis.Maximum; Hmin := Chart1.BottomAxis.Minimum; Vmax := Chart1.LeftAxis.Maximum; Vmin := Chart1.LeftAxis.Minimum; if (focusy * 0.95) > Chart1.LeftAxis.Maximum then begin Vmax := focusy / 0.95; if (90 > Q0) and (Q0 > 0) then Vmax := Vmax + focusL / 1.5; end; if (focusy * 0.95) < Chart1.LeftAxis.Minimum then begin Vmin := focusy / 0.95; if (0 > Q0) and (Q0 > -90) then Vmin := Vmin + focusL / 1.5; end; if (Hmax - Hmin) > (Vmax - Vmin) then begin dx2 := ((Hmax - Hmin) - (Vmax - Vmin)) / 2; Vmax := Vmax + dx2; Vmin := Vmin - dx2; end else begin dx2 := ((Vmax - Vmin) - (Hmax - Hmin)) / 2; Hmax := Hmax + dx2; Hmin := Hmin - dx2; end; Series5.AddXY(Hmin, Vmax); // Hmax,Hmin,Vmax,Vmin 反映の為の Series Series5.AddXY(Hmin, Vmin); Series5.AddXY(Hmax, Vmin); Chart1.Update; application.ProcessMessages; // 描画待ち if not CF then exit; // 交点がなかったら光線軸計算無し scrollbar2.Enabled := True;; scrollbar1.Enabled := True; IMG: if STF then begin // Button1により計算開始フラグ foc := 0; // 反射角90°時反射光補正長さゼロ sclpos := 1; // 反射光長さ補正スケール1 end else foc := focusL; // 反射角90°時反射光補正長さ焦点距離に設定 STF := False; // Button1により計算開始フラグ ypl := chart1.LeftAxis.IStartPos; // y軸スタート座標 ypm := chart1.LeftAxis.IEndPos; // y軸エンド座標 xpl := chart1.BottomAxis.IStartPos; // x軸スタート座標 xpm := chart1.BottomAxis.IEndPos; // x軸エンド座標 Hmax := chart1.BottomAxis.Maximum; Hmin := chart1.BottomAxis.Minimum; Vmax := chart1.LeftAxis.Maximum; Vmin := chart1.LeftAxis.Minimum; ax := (xpm - xpl) / (Hmax - Hmin); // x方向座標変換係数 ay := (ypm - ypl) / (Vmax - Vmin); // y方向座標変換係数 xsp := round((x2 - Hmin) * ax) + xpl; // 分割数設定の為の計算 ysp := round((x1 - Hmin) * ax) + xpl; n := abs(xsp - ysp) div 21; // 分割数 if n < 5 then n := 5; dx := (x2 - x1) / n; Q5 := Q0 / 180 * pi; // 光線の角度deg yback := 0; // 焦点のy位置クリア for i := 0 to n do begin // 左から右へ計算 x := i * dx + x1; // xの値 x xsp := round((x - Hmin) * ax) + xpl; y := x * b2 + c2; // 直線yの値 y if Q0 <> 90 then begin // 光線90°でない時 ma := tan(Q5); // 直線の傾き mc := y - ma * x; // 傾き maの直線 y = max + mc b0 := b1 - ma; // 放物線と光線の交点計算 c0 := c1 - mc; d := b0 * b0 - 4 * a1 * c0; e := sqrt(d); if Q5 > 0 then x3 := (-b0 - e) / 2 / a1 // 放物線交点xの値 x3 else x3 := (-b0 + e) / 2 / a1; y3 := x3 * x3 * a1 + x3 * b1 + c1; // 放物線交点yの値 y3 // 光線の入射位置をグラフの端点に変更 if a1 > 0 then Vy := Vmax else Vy := Vmin; x0m := (Vy - mc) / ma; y0m := Vy; if ma > 0 then begin if a1 > 0 then Vx := Hmax else Vx := Hmin; end else begin if a1 > 0 then Vx := Hmin else Vx := Hmax; end; y1m := ma * Vx + mc; x1m := Vx; if a1 > 0 then begin if y0m > y1m then begin y0m := y1m; x0m := x1m; end; end else begin if y0m < y1m then begin y0m := y1m; x0m := x1m; end; end; xsp := round((x0m - Hmin) * ax) + xpl; // 入射光直線端点xの座標 ysp := round((Vmax - y0m) * ay) + ypl; // 入射光直線端点yの座標 end else begin // 光線90°の時 X3 := x; // 放物線xの値 y3 := x3 * x3 * a1 + x3 * b1 + c1; // 放物線yの値 y3 ysp := ypl; // 直線yの座標 if a1 < 0 then ysp := round((Vmax - Vmin) * ay) + ypl; end; ypp := round((Vmax - y3) * ay) + ypl; // 放物線yの座標 xpp := round((x3 - Hmin) * ax) + xpl; // 放物線xの座標 Image1.Canvas.Pen.Color := clSkyblue; Image1.Canvas.MoveTo(xsp, ysp); // 直線のx位置から Image1.Canvas.LineTo(xpp, ypp); // 放物線xの位置へ線描画 b3 := 2 * a1 * x3 + b1; // 接線y1=m1x+c1 のm1の値 b3 c3 := - b3 * x3 + y3; // 接線y1=m1x+c1 のc1の値 c3 if Q0 <> 90 then begin // 光線角度90°以外だったら xl := sqrt((x3 - xc0) * (x3 - xc0) + (y3 - focusY) * (y3 - focusY)); // 反射光長 xl := (xl + abs(focusL)) * sclpos; // 反射光長補正 Q1 := arctan(b3); // 反射点の放物線との接線の角度rad fpoint(x3, y3, Q5, Q1, xl, x4, y4); // 反射光線の端点位置を求めるサブルーチン xsp := round((x4 - Hmin) * ax) + xpl; // 光線端点位置xの座標 ysp := round((Vmax - y4) * ay) + ypl; // 光線端点位置yの座標 end else begin // 光線90°の時 Q2 := arctan(b3) / pi * 180; // 反射点の放物線との接線の角度deg // Q2 := 90 + Q1; // Q3 := 90 - Q2; // Q4 := Q2 - Q3; Q4 := 90 + 2 * Q2; // 反射角deg if Q4 <> 90 then begin // 反射角が90°以外だったら mf := tan(Q4 / 180 * pi); // 直線の傾き角rad mfc := -mf * x3 + y3; // 直線 y = mfX + mfc x4 := xc0; // 放物線原点x y4 := X4 * mf + mfc; // 放物線原点xの反射光のy値 yback := y4; // y値のバックアップ Q1 := arctan(b3); // 反射点の放物線との接線の角度rad xl := sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4)); // 反射光長 xl := (xl + abs(foc)) * sclpos; // 反射光長補正 fpoint(x3, y3, Q5, Q1, xl, x4, y4); // 反射光線の端点位置を求めるサブルーチン xsp := round((x4 - Hmin) * ax) + xpl; // 焦点位置xの座標 ysp := round((Vmax - y4) * ay) + ypl; // 焦点位置y座標 end else begin // 反射角90°の時 xsp := round((x - Hmin) * ax) + xpl; // 焦点位置x座標 if yback = 0 then y4 := abs(y3 + focusL + foc) * sclpos // 垂直方向反射光長 else y4 := (yback + foc) * sclpos; if y4 > Vmax then y4 := Vmax; if y4 < Vmin then y4 := Vmin; ysp := round((Vmax - y4) * ay) + ypl; // 反射光端点位置y座標 end; end; Image1.Canvas.Pen.Color := clPurple; // 反射光線 Image1.Canvas.MoveTo(xsp, ysp); // 光線端点xy座標から Image1.Canvas.LineTo(xpp, ypp); // 放物線交点座標 end; if not ImgF then begin memo1.Lines.Add(''); if abs(Q0) = 90 then begin memo1.Lines.Add('焦点x, y座標 = ' + floatTostrF(xc0, ffFixed, 13, 8) + ', ' + floatTostrF(yback, ffFixed, 13, 8)) end else begin memo1.Lines.Add('焦点x, y座標 = ' + floatTostrF(xc0, ffFixed, 13, 8) + ', ' + floatTostrF(focusY, ffFixed, 13, 8)); memo1.Lines.Add('焦点座標 拡散'); end; memo1.Lines.Add('焦点距離 = ' + floatTostrF(focusL, ffFixed, 13, 8)); end; // 文字の描画 α,β,c,o fys := 12; Image1.Canvas.Font.Size := fys; Image1.Canvas.Font.Color := clRed; Image1.Canvas.TextOut(xpl + 10, ypl, '光線角度 = ' + floatTostr(Q0) + '°'); Image1.Canvas.Font.Color := clBlack; Image1.Canvas.Font.Size := fys; xsp := round((beta - Hmin) * ax) + xpl + 10; ysp := round((Vmax - bety) * ay) + ypl - fys; Image1.Canvas.TextOut(xsp,ysp,'β'); // 直線と放物線の座標β xsp := round((alpha - Hmin) * ax) + xpl - 22; ysp := round((Vmax - alpy) * ay) + ypl - fys; Image1.Canvas.TextOut(xsp,ysp,'α'); // 直線と放物線の座標α xsp := round((xcc - Hmin) * ax) + xpl - 22; ysp := round((Vmax - ycc) * ay) + ypl - fys; Image1.Canvas.TextOut(xsp,ysp,'c'); // 二接線の交点座標c xsp := round((xc0 - Hmin) * ax) + xpl - 8; if a1 > 0 then fys := 0; ysp := round((Vmax - yc0) * ay) + ypl - fys * 2; Image1.Canvas.TextOut(xsp,ysp,'o'); // 放物線原点の座標o Image1.Canvas.Font.Size := 9; Image1.Canvas.Font.Color := clBlue; end; // Image画像消去 procedure TForm1.ImageClear; begin Image1.Canvas.Brush.Style := bsSolid; Image1.Canvas.FillRect(rect(0, 0, Image1.Width, Image1.Height)); Image1.Canvas.Brush.Style := bsClear; Chart1.BackImage.Bitmap := Image1.Picture.Bitmap; end; // 計算開始 procedure TForm1.Button1Click(Sender: TObject); begin Button1.Enabled := False; scrollbar1.Enabled := False; scrollbar2.Enabled := False; ImageClear; // Image画像消去 memo1.Clear; Series1.Clear; // 放物線 Series2.Clear; // 放物線に対する直線 Series3.Clear; // 接線α Series4.Clear; // 接線β Series5.Clear; // Xyスケール設定 Series6.Clear; // 放物線反射面 if not datainput then begin Button1.Enabled := True; exit; end; CF := True; // 計算フラグ sclpos := scrollbar1.Position / 50; if not calc_point_of_intersection then begin Memo1.Lines.Add('交点無し'); CF := False; // 交点が無しフラグ 光線計算無し x1 := b1 / 2 - abs(1 / a1); // 交点なし時の作図範囲設定 x2 := b1 / 2 + abs(1 / a1); end; ImgF := False; // Seriesデーター許可フラグ graphDraw; // 作図 Chart1.BackImage.Bitmap := Image1.Picture.Bitmap; Button1.Enabled := True; end; procedure TForm1.FormCreate(Sender: TObject); var bm : Tbitmap; begin SCF := False; // 反射光線の長さ調整有無フラグ scrollbar1.Enabled := False; // 反射光線の長さ調整スクロールバー scrollbar2.Enabled := False;; // 入射光角度調整スクロールバー bm := Tbitmap.Create; bm.Width := Chart1.Width; bm.Height := Chart1.Height; Image1.Width := Chart1.Width; Image1.Height := Chart1.Height; Image1.Picture.Bitmap := bm; Image1.Canvas.Brush.Color := clWhite; Image1.Visible := False; bm.Free; Label5.Caption := '放物面での反射は一度の反射計算です。' + #13#10 + '反射面の角度に近い角度で入光すると複数回反射する事があります。' + #13#10 + '複数回の反射は考慮していません。'; Label6.Caption := '角度は、計算時、計算用の角度に変換されます。'; end; // 反射光長調整 procedure TForm1.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); begin ImageClear; // Image画像消去 ImgF := True; // Image画像のみ作図フラグ sclpos := scrollbar1.Position / 50; // 反射光長さ設定係数 graphDraw; Chart1.BackImage.Bitmap := Image1.Picture.Bitmap; end; // 入射光線角度調整 procedure TForm1.ScrollBar2Scroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); begin if not CF then exit; Q0 := ScrollPos; if Q0 <= 0 then exit; if Q0 >= 180 then exit; if not SCF then exit; // 反射光線の長さ調整有無フラグ if a1 < 0 then Q0 := - Q0; if a1 > 0 then begin if Q0 > 90 then Q0 := Q0 - 180; end else begin if Q0 <= -90 then Q0 := 180 + Q0; end; ImgF := True; // Image画像のみ作図フラグ ImageClear; // Image画像消去 graphDraw; Chart1.BackImage.Bitmap := Image1.Picture.Bitmap; end; procedure TForm1.LabeledEdit1Change(Sender: TObject); begin ScrollBar2.Enabled := False; SCF := False; // 反射光線の長さ調整有無フラグ end; procedure TForm1.LabeledEdit4Change(Sender: TObject); begin ScrollBar2.Enabled := False; SCF := False; // 反射光線の長さ調整有無フラグ end; end.