AFsoft WebSite(エーエフソフト・ウェブサイト)
 

オペレーティング・システムについて

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
CAD作ろ! 交点を拾う(スナップ)
端点スナップの次は、交点スナップです。本プログラムでは、線・円・円弧・点・文字の5要素をサポートしますので、円と円弧は同じ計算と考えて、線と線、線と円、円と円、の交点を算出する事から考えます。
線と線の交点計算は、2線の連立2元1次方程式を解く、という事になります。高校数学の基礎(4)で既に記述してあります。
線と円、円と円の交点計算は、高校数学の基礎(6)で既にちらっと書きましたが、改めて、線と円の交点計算円と円の交点計算に書いておきます。
 
端点スナップと同様、計算した交点がマウス近傍であるかどうかを判定します。
xx := 交点のX座標;
yy := 交点のY座標;
if (Abs(tx - xx) <= a)and(Abs(ty - yy) <= a) then begin
 (交点を拾いました)
end;
要素数が2個の場合には、交点計算は1回だけです。要素数が3個ある場合、要素1と要素2、要素1と要素3、要素2と要素3、合計3回計算を行います。要素数が4個の場合には、要素1と要素2,3,4、要素2と要素3,4、要素3と要素4、の合計6回、とバブルソートのような感じで計算を繰り返します。要素数が多くなればなるほど、計算数も増えて行きます。
一番最初に検索出来た交点を返す、とした場合でも、要素数が多い場合にはかなりの時間が掛かってしまう場合があります。一番近い交点を返したい、という場合には、全ての計算を行い、算出した距離の比較をせねばなりませんので、どうすれば計算数を減らせるか?を考える必要があります。作図操作するのに特に重要なポイントで、これが遅すぎると、ストレスになり、「このCADは使えない」と判断されてしまう一因となってしまいます。
 
速度をなるべく速くするため、全要素を検索対象にするのではなく、画面で目視出来ている要素だけを対象にする、というのがまず1つ、そして、
 要素ループ→交点計算→マウス近傍かどうか?
というロジックではなく
 要素ループ→マウス近傍の要素をピックアップ
 ピックアップされた要素だけループ→交点計算→判定
という風にしてみる等の工夫が必要になってくるでしょう。
 
 
CADによっては、端点や交点の近くへマウスを移動すると、自動的にマーカーが表示されて、そこでクリックすると、その点にスナップされる、というものがあります。こういうスタイルのCADの場合、右クリックしたら検索計算をする、という形態ではなく、画面を作図する際に、予め検索計算をして、計算結果の座標点を保管するデータ領域に入れておき、その点データを参照する、というような処理を行います。
 
 
まず、スナップした直後に、スナップ前の場所からラバーバンドが表示されてしまうので、これを修正します。が、ラバーバンド関連で指定する座標値はドット値であるため、ラバーバンド表示中に画面移動・拡大縮小を行うと表示に支障を来します。ですので、ラバーバンド関連でmm座標を指定するように修正します。
◇メイン GRBLINE(),GRBBOX(),GRBCIRC(),GRBARC(),GRBERASE
◇UnitGraph GRB_LINE(),GRB_CIRCLE(),GRB_ARC()
◇その他、変数を integerからdoubleにして、入れる値にも注意をして書き換えます。◆拡大縮小時のドラッグ用は、ドット値のままにしておきます。専用にGDRBOX()を用意し、UnitGraphのGRB_BOX()もドラッグ専用とします。線幅を2ドットにして、拡大縮小時は赤色、基準画面・図形範囲表示時は青色にします。◇このため、GRBBOX()は未使用状態となっていますが、将来使うかもしれませんのでそのまま置いておく事にします。(コンパイルすると「ヒント」が出るようになります)
 
微調整しかしていませんが、取りあえず、ここまでのサンプルプログラムです。
サンプルプログラムのソース
次に、ホイールマウスでの拡大・縮小を考えてみましょう。
AutoCAD、M7、Jw_cad4、等、ホイールマウス(スクロールマウス)によって画面の拡大・縮小が出来るソフトが増えており、ボーランド Delphiでも、Delphi4からホイールマウスの感知・イベントの記述が出来るようになっています。Delphi6でも当然、可能ですが、Delphi6を非対応のWindows95で強引に使っている場合、作成したプログラムでホイール操作を確認する事は出来ませんので注意が必要です。(作成したプログラムをWindows98〜で実行すればホイール操作は可能です)
 
まず、ホイールボタンをクリックした時の処理は、通常のマウスイベントの Shift値に、中央ボタンを押したという「ssMiddle」が入る事で感知出来ます。
例:
procedure TFmMain.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
begin
 ・・・
 if (ssMiddle in Shift) then begin
  (中央ボタンをクリックした=マウス・ホイールクリックをした)
 end;
 ・・・
end;
ホイールクリックをしたら、画面移動を行うようにします。
 
次に、ホイール操作についてですが、残念ながら、TPaintBoxに、マウスホイールイベント定義はありません。TPaintBoxは、TPanelの上に載せていますが、TPanelにもマウスホイールイベント定義はありません。という訳で、フォームのマウスホイールイベントを記述する事になります。
 マウスホイールを上方向へ操作
 procedure TFmMain.FormMouseWheelUp(〜);
 マウスホイールを下方向へ操作
 procedure TFmMain.FormMouseWheelDown(〜);
マウスホイールを上方向へ操作したら画面拡大、下方向へ操作したら画面縮小を行うようにします。このイベント内で、Senderを利用しようとしても、FindVCLWindow()を利用しようとしても、TPaintBoxは受け取ってくれません。仕方がないので、マウス位置から判定するようにします。この手続きの引数に「MousePos: TPoint」があります。MousePos.X、MousePos.Y の値には、マウスのスクリーン座標(フォーム内座標ではありません)が入ります。ですので、PaintBox1は Panel2の上に置いていますので、Panel2の左上のスクリーン座標 Panel2.ClientOrigin.X、Panel2.ClientOrigin.Y から、PaintBox1の範囲内に、マウスがあれば、画面の拡大縮小処理を行うようにします。処理を行ったら、「Handled」に「True」を指定するようにします。1.5倍で拡大・縮小を行うようにしています。
 
あと、ユニットのファイル名を変更しています。
(Unit0054b.pas〜Unit54f.pas → UnitFileNew.pas等)
 
なかなか本題に行きませんが、取りあえず、ここまでのサンプルプログラムです。
サンプルプログラムのソース
それでは交点スナップのコーディングについて考えましょう。まずは、UnitFuncに、点から線分へ垂直に下ろした点(垂点)を算出する手続き CrossPointToLine() を追加します。詳細は点と線に記述してあります。点と線分の距離は、点と垂点の距離を出せば可能です。なお、点と円の距離は、点と円の中心点の距離を算出して、円の半径分を引けば可能です。ついでに、点から円へ垂直に下ろした点を算出する関数 CrossPointToCircle()も作っておきます。点が円の中心点と等しい場合には、点は存在しないという意味で、Falseを返します。次に、線分と線分の交点計算を行う関数 CrossLineToLine() を追加します。これも詳細は点と線等に記述してあります。なお、算出した値が0に等しい場合、という条件式を「Abs(a) < _LIMITN」のように書いているのは、計算誤差があるのを前提としているためです(_LIMITNは、非常に小さい値)。コンピュータは、0での割り算等をするとエラーをしてしまい、プログラムが強制的に中断してしまったり、誤動作を起こしてしまったりする事があります。エラーになると予測される場所には、必ず、何らかのかわし技を掛けておく必要があります。同様、線分と円の交点計算を行う関数 CrossLineToCircle() 、円と円の交点計算を行う関数 CrossCircleToCircle() を追加します。そして、マウススナップ処理 TFmMain.MouseSnap() に、要素端点検索の次に、交点検索を行うように追加します。取りあえず、組み込んでしまいます。
ここまでのサンプルプログラムです。
サンプルプログラムのソース
 
実行してみると分かりますが、交点を取ったつもりが中点を拾ってしまったり、円の交点を取りたいがために、円上点→中心点を拾う処理が出来なかったり、します。これは検索の優先順位を変更せねばならないでしょう。また、何故か変な所を拾ったりしてしまう事があります。これは、別の線分の延長線との交点を拾ってしまっているのが原因です。つまり交点検索の際には、見えない延長線の部分は対象外とせねばならない訳です。
また、円の交点部分を拡大していくと、交点と円とが離れてしまいます。これは、円を作図する処理で、実際には、72角形を作図しているため、そう見えてしまうのが原因です。これを防ぐには、円の作図ロジックを変える、つまり、円のクリッピング処理をちゃんとせねばならないという事を意味します。
それでは、交点のスナップでは延長線上の点は取らないようにします。線上か延長線上かを判定する関数 CheckOnLine()CheckOnArc() をUnitFuncに用意して、線上の点のみを拾うようにします。
そして、見えない点だけれどもスナップしたい点(線分の中点、円・円弧の 0°・90°・180°・270°点、中心点、文字)の検索を、交点検索の後に回しましょう。
 
ここまでのサンプルプログラムです。
サンプルプログラムのソース
 
 
CAD装置(1)
CAD装置(2)
メディア
AutoCADの
DIESELマクロ
CSV
DXF
PCES
IGES
STEP
数学とCAD
CAD作ろ!
 ▲PREV
 ▼NEXT
 
お問い合わせ 
本サイトはリンクフリーです
リンクバナー
(C)Copyright 1999-2015 By AFsoft All Rights Reserved.