以下は2πを40等分して単振動の様子をシミュレーションさせる関数ですが、これだと当然ながら40個の円が一度に単振動して全体としては最初から正弦曲線を描いてしまいます。最初40個の円はY軸上に配置して、一番最初(x = 0)の円が単振動をはじめたら、それにつづいて次の円が位相の分だけ遅れて単振動をするというようにしたいのですが、どうしたらいいでしょうか?
private
FOx, FOy: Integer; //原点
FTm, Fq: Extended; //振動数と時間
//実座標⇒表示座標
function TForm1.RealToDispX(x: Extended): Integer;
begin
Result := Round(FOx + x * PerX);
end;
function TForm1.RealToDispY(y: Extended): Integer;
begin
Result := Round(FOy - y * PerY);
end;
//単振動-横波
procedure TForm1.FDrawShm(TargetCanvas: TCanvas);
var
Ex,Ey,Phi : Extended;
i: Integer;
begin
with TargetCanvas do
begin
Pen.Width := SubWidth;
Pen.Color := clGreen;
Phi := 0; //とりあえず 0≦ x ≦2π
Ex := 0;
for i := 0 to 40 do
begin
Ey := 3*sin(2*Pi*Fq*FTm+Phi);
MoveTo( RealToDispX(Ex),RealToDispY(Ey) );
if i Mod 5 = 0 then Brush.Color := clRed
else Brush.Color := clBlack;
Ellipse( RealToDispX(Ex)-20, RealToDispY(Ey)-20, //位置を示す円
RealToDispX(Ex)+20, RealToDispY(Ey)+20 );
Ex := Ex + 1;
Phi := Phi + Pi/20;
end;
end;
FTm := FTm + 0.002;
end;
基本こんな形でどうですか。使うコンポはForm,PaintBox,Timer,Buttonです。
Buttonを押したら最初にy軸並びの○を描いて、それからタイマースタート。
タイマーが動き出したら、タイマーイベントで○を再描画しています。
画面のちらつきとか、スタート/ストップで一旦画面消去するとか、色々やることは
有りますので、そこは頑張ってみてください。
unit Unit1;
interface
uses
Forms, ExtCtrls, Controls, Classes, StdCtrls, Graphics;
Type
TForm1 = class(TForm)
Button1: TButton;
PaintBox1: TPaintBox;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
FOx, FOy : Integer; //原点
Ex,Ey,Phi : Extended;
PerX, PerY : integer; //表示倍率
iCount : integer;
function RealToDispX(x1: Extended): Integer;
function RealToDispY(y1: Extended): Integer;
procedure FDrawShm(x: integer; Phi: Extended);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TForm1.RealToDispX(x1: Extended): Integer;
begin
Result := Round(FOx + x1 * PerX);
end;
function TForm1.RealToDispY(y1: Extended): Integer;
begin
Result := Round(FOy - y1 * PerY);
end;
procedure TForm1.FDrawShm(x:integer; Phi: Extended);
var y :extended;
begin
y := sin(Phi-Pi/20);
with PaintBox1.Canvas do begin
Brush.Color:=clBtnFace; //背景で上書きして
Pen.Color := clBtnFace; //消去の代わり
MoveTo( RealToDispX(x),RealToDispY(y) );
Ellipse( RealToDispX(x)-10, RealToDispY(y)-10,
RealToDispX(x)+10, RealToDispY(y)+10 );
y := sin(Phi);
Pen.Color := clGreen;
if x Mod 5 = 0 then Brush.Color := clRed
else Brush.Color := clBlack;
MoveTo( RealToDispX(x),RealToDispY(y) );
Ellipse( RealToDispX(x)-10, RealToDispY(y)-10,
RealToDispX(x)+10, RealToDispY(y)+10 );
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
iCount:= 0; //初期値の設定
FOx := 100;
FOy := 200;
PerX := 20;
Pery := 100;
Phi := 0;
Ex := 0;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i: Integer;
begin
Phi := Phi + Pi/20;
for i:=0 to iCount do
FDrawShm(i, Phi-i*(Pi/20));
if iCount<40 then
inc(iCount)
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
with PaintBox1.Canvas do begin
Pen.Color := clGreen;
for i := 0 to 40 do begin
Ey := sin(Phi);
MoveTo( RealToDispX(Ex),RealToDispY(Ey) );
if i Mod 5 = 0 then Brush.Color := clRed
else Brush.Color := clBlack;
Ellipse( RealToDispX(Ex)-10, RealToDispY(Ey)-10,
RealToDispX(Ex)+10, RealToDispY(Ey)+10 );
Ex := Ex + 1;
end;
end;
Phi := 0;
Timer1.Enabled:=true;
end;
end.
あ、貼り付けたタイマーコンポはデフォルトでEnabledがtrueになっているので、
インスペクタで初期値=falseにしておいてください。
すみません。書き方が悪かったみたいです。単振動のシミュ自体は出来ているのです。もちろんチラツキ対策も裏画面を利用する方法で対応しています。
http://ichigo-up.com/cgi/up/qqq/nm31346.zip
上のファイルを見てもらえたらわかるのですが、たとえば横波の場合40個の円が最初から正弦曲線を描いた状態で単振動がスタートします。それを最初は
* * * * * * * * * * * *
のようにに一直線上に並べた状態でスタートさせたいということなのです。
>* * * * * * * * * * * *
>のようにに一直線上に並べた状態でスタートさせたいということなのです。
私が書いたやつはそうなっていますよ。TimerコンポのEnabledがtrueのままになっていませんか?
> 私が書いたやつはそうなっていますよ。TimerコンポのEnabledがtrueのま
> まになっていませんか?
あ、そうですね。ありがとうございます。
ツイート | ![]() |