マウスクリックで図形を描く(2)
普段なにげなく使っている直線ツールや四角形ツールをマイツール化してみましょう。クリックインタフェースを学び、ツール化までしてみます。
第2章 二点クリック(直線ラバー)
二点クリックの操作は本体機能の直線ツールと同じです。
手続きGetLine(VAR p1X, p1Y, p2X, p2Y : REAL);
を使います。
この手続きを実行すると、マウスカーソルが十字カーソルになりクリックをするまで待ち続けます。図面の任意の場所でクリック(始点)すると、ラバーバンドが出て、次のクリック(終点)をするまで待ち続けます。その位置座標を引数 p1X, p1Y, p2X, p2Y に実数の値で返します。
クリックされた場所をメッセージウインドウに表示するプログラムをかいて見ましょう。
メッセージウインドウに表示するには、
手続きMessage( z1, z2, ..., zN : ANY );
を使います。
PROCEDURE sample; VAR p1X, p1Y, p2X, p2Y : REAL; BEGIN GetLine( p1X, p1Y, p2X, p2Y ); Message( p1X, ',', p1Y, ',', p2X, ',', p2Y ); END; Run( sample );
残念ながら、このままではラバーバンドは消えてしまいます。
何故なら 手続きGetLineは2点の座標を返すだけの命令だからです。
では次に、直線ツールのように直線を描かせてみましょう。
直線は、
手続き MoveTo( pX, pY : REAL );
手続き LineTo( pX, pY : REAL );
を使います。
直線を描く動作はペンプロッタを思い浮かべていただけると理解しやすいと思います。 手続き MoveToで描き始めの場所までペンを上げた状態で移動します。そして、 手続き LineToによってペンを下げた状態で描き納めの場所まで移動しますので、線が描かれるわけです。
PROCEDURE sample; VAR p1X, p1Y, p2X, p2Y : REAL; BEGIN GetLine( p1X, p1Y, p2X, p2Y ); MoveTo( p1X, p1Y ); LineTo( p2X, p2Y ); END; Run( sample );
手続き GetLine はクリックした座標位置を返しますが、その数値を使って直線しか描けないわけではありませんたとえば、下の図のような図形はどうでしょう?
この図形を描くにあたって必要な情報は、 円の半径と円の中心点を求める必要があります。
団子の数はひとまず3つということで、定数に3としておきます。
円弧の開始位置と円弧角度は0.0、360.0固定なのでこれも定数としておきます。
円の半径は
関数 Distance(x1, y1, x2, y2 : REAL):REAL;
を使うと簡単に求まります。
GetLineから得た始点と終点の座標を引数とすることで、距離が求まります。
その距離を団子の数+1(始点終点の串の部分も計算に入れる)で割ることで直径が求まります。
さらに半分にすることで半径になります。
中心点を求めるために必要な串(直線)の角度は、
関数HAngle(h : HANDLE):REAL;
を使うことで求まります。引数に
関数LNewObj:HANDLE;
を渡すことで、直前に描いた直線のハンドルを渡すことができます。
角度を渡す三角関数は単位が度ではなくラジアンですので、
PI(VSで用意されているπの定数) / 180.0をかけておきます。
最後に円を定数個描画するために繰り返し文FOR文を使います。
始点から直径分シフトした位置からn個円を描くわけですが、円の中心座標は三角関数を使って求めましょう。
一つ描くたびに、直径分づつシフトした位置の中心座標を計算していきます。
PROCEDURE sample; CONST kstartAngl = 0.0; ksweepAngle = 360.0; kNUM = 3; VAR p1X, p1Y, p2X, p2Y : REAL; angle : REAL; dist, radius : REAL; ii : INTEGER; BEGIN GetLine( p1X, p1Y, p2X, p2Y ); MoveTo( p1X, p1Y ); LineTo( p2X, p2Y ); angle := HAngle( LNewObj ); angle := angle * PI / 180.0; dist := Distance( p1X, p1Y, p2X, p2Y ); radius := dist / ( kNUM + 1 ) / 2; dist := radius * 2; FOR ii := 1 TO kNUM DO BEGIN ArcByCenter( p1X + Cos( angle ) * dist, p1Y + Sin( angle ) * dist, radius, kstartAngl, ksweepAngle ); dist := dist + radius * 2; END; END; Run( sample );