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

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

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
【Jw_cad 外部変形】分割点2
各線分・円・円弧・楕円・楕円弧を当分割するような点要素を作図する「分割点」外部変形プログラムについては、既に読み込みデータの生成(5)」にて作成しましたが、連続した線分・円弧・楕円弧を1つの曲線として認識し、曲線に対して、指定距離(長さ)分ずつ分割点を作図するプログラムについて考えていきたいと思います。
 
Jw_cad では、メニュー→その他→測定→[距離測定] にて、線分の端点をスナップ(右クリックで端点取得)していく事によって距離を計測する事が出来ます。円弧・楕円弧の場合は、[( 弧指定]により計測する事が出来ます。しかし線数が多くなると結構手間になってきます。分割コマンドの場合も状況は多少異なりますが、もう少し機能があれば?と思う場合もあるかもしれません。
 
ここでは、まず、検索開始点を指示し、範囲選択を行い、選択された線分・円弧・楕円弧の始点・終点を検索して追い掛けを行い、分割する距離(長さ)を入力して、分割点を作図したいと思います。最後に画面上に全長表示を行います。(「REM #h」による注釈文表示を利用します。先に範囲選択を行うと、この全長表示が「範囲選択して下さい」コメントによって消されてしまいますので、先に検索開始点の指示を行うようにしています)
それではまずバッチファイルから。
p042_分割点2.bat
REM p042−分割点2
@echo off
REM #jww
REM #cd
REM #hf
REM #zs
REM #zc
REM #zz
REM #zw
REM #1 分割開始点を指示して下さい。(L)free (R)Read
REM #h1
REM #hc 範囲選択をして下さい。
REM #g0
REM #hr
start /w p042.exe
実寸で要素データを取得し、距離(長さ)入力も実寸で行います。図寸ではありません。また、現在のレイヤグループ内(書込みレイヤグループ内)を対象に行います。ですので「REM #g0」の指定を入れてあります。全レイヤグループ指定をしても構いませんが、レイヤグループの縮尺設定が異なる場合、距離(長さ)もそれぞれ違ってしまいますので注意が必要です。
 
分割開始点を指定しているのは、範囲選択内の要素データを検索して開始点を見つけだす処理を省略したい、という事。複数の開始点が見つかった場合、どれを選択すべきなのか、或いは、全ての複数の曲線についての処理を行うのか、という事等々について考慮する必要がないためにこのようにしています。
 
 
線分の長さは、既に MyFunc.pas にも登録していますが、2点間の距離 d = Sqrt( (x2-x1)2 + (y2-y1)2 ) を利用します。円弧の長さは、円の円周(全円)= 2πr でも分かる通り、円弧角×半径となります。円弧角=終了角度−開始角度 ですからさほど問題もないでしょう。問題は、楕円弧の円弧長さです。これは算術式で用意に解くという事は出来ません。何らかの近似式で算出する必要があります。角度が絡んできますので、単純に考えると、内接する多角形線分の長さの和として、その多角形の角数をかなり大きくしていけば求められるであろう、という予想は出来ます。楕円弧の式は
 x = cx + r * Cos(α)
 y = cy + r * h * Sin(α)
   中心点(cx,cy)、半径 r、偏平率 h
で、傾き角度による回転写像により x,y を中心点基準にして回転させる事により計算出来ます。
しかし、高い精度の結果を求めていくと、1000分割、10,000分割、100,000分割、・・・と増えていってしまいます。そうなると高速なパソコンでも流石に遅くなってしまいます。
そこで、ここでは、内接する 3600分割の多角形状態の3点ずつをピックアップし、3点を通る円弧を想定して、その2点間の円弧の長さを計算します。これを 3600回行って加算し、楕円弧の近似長さとしています。3600回程度の繰り返しであれば、コンパイラ処理系であるDelphiではそこそこの速度で実行可能です。
 

 
プロジェクト「p042」の準備を行います。「C:\DelphiProgram\jww」フォルダの中に「p042」というフォルダを作成し、Windowsのエクスプローラ等で「p033」内のファイルを「p042」の中へコピーします。また、「p041」内のファイル「JwwGaibu.pas」「MyFunc.pas」を「p042」の中へコピーします。(※移動しないよう注意)
Delphi6を起動します。メニュー「ファイル」→「プロジェクトを開く」を実行し、「C:\DelphiProgram\jww\p042」内の「p033.dpr」を開きます。メニュー「プロジェクト」→「オプション」を実行し、下記の設定を行います。
[アプリケーション]頁
 タイトル
p042−分割点2
[ディレクトリ/条件]頁
 パス及びディレクトリ
C:\DelphiProgram\jww\p042

メニュー「ファイル」→「プロジェクトに名前を付けて保存」
「C:\DelphiProgram\jww\p042」の中に「p042.dpr」として保存
「C:\DelphiProgram\jww\p042」の中に「p033.〜」のファイルが残っていますので、Windowsのエクスプローラ等で削除します。
プロジェクトマネージャを表示しコード画面の左側にドッキングしておきます。
画面レイアウトを下記のようにしてみました。

Label3 には 処理中のメッセージを表示するようにします。範囲選択した要素データがかなりの量になった場合には何らかのメッセージを表示した方が、止まっていないです・動いていますよ、という事を利用者に知らせるのに役立ちます。ここでは行っていませんが、カウンタ表示を行ったり、プログレスバー(0%→100%になるゲージ)を配置したりするのも良いです。アイコンも適当に書き換えました。
 
検索開始点の座標は、変数
  JG_IPoints[1].x ;
  JG_IPoints[1].y ;
に入ります。
範囲選択を行って取得した線分データは
  数:JW_EntLineN
  動的配列:JW_EntLine[〜]
円弧・楕円弧データは
  数:JW_EntArcN
  動的配列:JW_EntArc[〜]
に入ります。但し楕円データも含まれますので、開始角度の座標と終了角度の座標が同じ場合には対象から外すようにします。
 
連続線=曲線をピックアップするため、各線分・円弧・楕円弧の始点座標・終点座標を専用の変数に入れる事にします。座標だけではなく、線分なのか円弧・楕円弧なのかの区別、始点なのか終点なのかの区別、何番目のデータか、も一緒に含めますので、type宣言で record定義を行い、それを動的配列として確保します。
Unit1.pas
(・・・前略・・・)
type
  TPntField = record
   x : double ;
   y : double ;
   t1: integer ;  // 0:Line 1:Arc
   t2: integer ;  // 0:始点 1:終点
   n : integer ;  // No(0-)
   fl: Boolean ;  // フラグ
  end;
 
  TForm1 = class(TForm)
(・・・)
// [OK]
procedure TForm1.Button1Click(Sender: TObject);
var
  d : double ;
  pn : integer ;
  pnt: array of TPntField ;
  i,j: integer ;
  xx1,yy1,xx2,yy2,rx,ry : double ;
begin
  d := SDbl(Edit1.Text) ;
  if (d <= _LIMIT) then exit;
  Label3.Caption := '端点を検索中です';
  Label3.Update ;
  // ----- 点のピックアップ -----
  pn := 0;
  pnt:= nil;
  // 線データ
  for i:=0 to JW_EntLineN-1 do begin
   with JW_EntLine[i] do begin
    pn := pn + 2;
    SetLength(pnt,pn);
    pnt[pn-2].x := x1 ;
    pnt[pn-2].y := y1 ;
    pnt[pn-2].t1:= 0;
    pnt[pn-2].t2:= 0;
    pnt[pn-2].n := i;
    pnt[pn-2].fl:= True;
    //
    pnt[pn-1].x := x2 ;
    pnt[pn-1].y := y2 ;
    pnt[pn-1].t1:= 0;
    pnt[pn-1].t2:= 1;
    pnt[pn-1].n := i;
    pnt[pn-1].fl:= True;
   end;
  end;
  // 弧・楕円データ
  for i:=0 to JW_EntArcN-1 do begin
   with JW_EntArc[i] do begin
    rx := cx + cr *Cos(sa/180.0*Pi);
    ry := cy + cr*he*Sin(sa/180.0*Pi);
    Rev(xx1,yy1,rx,ry,cx,cy,ka);
    rx := cx + cr *Cos(ea/180.0*Pi);
    ry := cy + cr*he*Sin(ea/180.0*Pi);
    Rev(xx2,yy2,rx,ry,cx,cy,ka);
    if (Abs(xx2-xx1) <= _LIMIT)and(Abs(yy2-yy1) <= _LIMIT) then continue ;
    pn := pn + 2;
    SetLength(pnt,pn);
    pnt[pn-2].x := xx1 ;
    pnt[pn-2].y := yy1 ;
    pnt[pn-2].t1:= 1;
    pnt[pn-2].t2:= 0;
    pnt[pn-2].n := i;
    pnt[pn-2].fl:= True;
    //
    pnt[pn-1].x := xx2 ;
    pnt[pn-1].y := yy2 ;
    pnt[pn-1].t1:= 1;
    pnt[pn-1].t2:= 1;
    pnt[pn-1].n := i;
    pnt[pn-1].fl:= True;
   end;
  end;
  if (pn = 0) then begin
   Label3.Caption := '端点が検索出来ませんでした';
   exit ;
  end;
(・・・)
次に、分割開始点が、検索した端点のうちのどれかにあるかどうかを検索します。
Unit1.pas
(・・・)
  // 分割開始点が端点上にあるかどうかをチェック
  Label3.Caption := '分割開始点を検索中です';
  Label3.Update ;
  xx1 := JG_IPoints[1].x ;
  yy1 := JG_IPoints[1].y ;
  j := -1;
  for i:=0 to pn-1 do begin
   if (Abs(pnt[i].x-xx1) <= _LIMIT)and(Abs(pnt[i].y-yy1) <= _LIMIT) then begin
    j := i;
    break ;
   end;
  end;
  if (j = -1) then begin
   Label3.Caption := '分割開始点が検索出来ませんでした';
   exit ;
  end;
(・・・)
見つけた端点が、
線分・円弧・楕円弧の始点である場合は、
 次はその要素データの終点を、
線分・円弧・楕円弧の終点である場合は、
 次はその要素データの始点を、
ピックアップします。それは必ず前か後かにあります。
そして、その始点→終点、或いは、終点→始点 の長さを測定します。分割距離に相当する位置へ点を作図します。この始点・終点は処理済みという事でフラグを False にして、次の検索で拾わないようにします。
そして、終点或いは始点座標から、同じ座標のものを検索します。そしてその始点或いは終点座標をピックアップして長さを測定し、分割点を作図します。
これを繰り返し、同じ座標が見つからなくなったら処理完了です。コメント表示として全長表示をついでに行っておきます。
 

 
と、こうあっさり書いてしまいましたが、実のところ、中身がぐちゃぐちゃになってしまい(これをスパゲッティ化、スパゲッティプログラムと呼ぶ)とてもじゃありませんが、人様に見せる事が出来るようなものでは無くなってしまいました。
ですので今回は、ソースをオープンにはしません。あまりにもみっともないですので。
 
今回のバッチファイルと実行ファイルについては、Pcataサイトに置いておきますので必要な方はそちらからダウンロードして下さい。
 
 
CAD装置(1)
CAD装置(2)
メディア
AutoCADの
DIESELマクロ
CSV
DXF
PCES
IGES
STEP
数学とCAD
CAD作ろ!
M7
Jw_cad
 [BACK]
 [NEXT]
 
お問い合わせ 
本サイトはリンクフリーです
リンクバナー
(C)Copyright 1999-2015 By AFsoft All Rights Reserved.