|
前頁では、幾何要素/表記要素フィーチャの点マーカについて見ましたのでここでは、同じく幾何要素/表記要素フィーチャの線分について見ていく事にします。
幾何要素/表記要素|線分 |
|
パラメータ | 型 | 説明 | 範囲 |
Layer | Int | レイヤコード |
|
Color | Int | 色コード |
|
Type | Int | 線種コード |
|
line_width | Int | 線幅コード |
|
start_x | double | 始点X座標 |
double(64bits)の
範囲(有効桁15桁) |
start_y | double | 始点Y座標 |
double(64bits)の
範囲(有効桁15桁) |
end_x | double | 終点X座標 |
double(64bits)の
範囲(有効桁15桁) |
end_y | double | 終点Y座標 |
double(64bits)の
範囲(有効桁15桁) |
備考
・始終点に同一の点は指定できない。 |
SXF Ver.3.1実装規約では、、、線分については何も無さそうですが、線種でのピッチ長さの指定は用紙座標系で行われる、という事に注意をすればよさそうです。AutoCADにあるような「線種尺度」(線種ピッチ長さに掛かる倍率指定)というのはSXFには無いようですからここでも指定しません。
それでは線分のデータ構造を決めます。
UnitData.pas |
type
・・・
TDataLine = record // 幾何要素/表記要素|線分
exf : Boolean ; // 存在フラグ(True:有り False:無し)
Layer : Integer ; // レイヤ(1〜256)
Color : Integer ; // 色 (0:レイヤ色 1〜256)
Ltype : Integer ; // 線種 (0:レイヤ線種 1〜32)
line_width: Integer ; // 線幅 (0:レイヤ線幅 1〜16)
start_x : double ; // 始点X座標
start_y : double ; // 始点Y座標
end_x : double ; // 終点X座標
end_y : double ; // 終点Y座標
end;
TFukugoZukeiDef = record // 構造化要素|複合図形定義
exf : Boolean ; // 存在フラグ(True:有り False:無し)
name : string ; // 複合図形名
Flag : Integer ; // 種別フラグ
cnt : Integer ; // 配置数
// ・・・幾何要素等データが入る予定・・・
mTen : array of TDataTenMarker; // 幾何要素|点マーカ
mTenN : Integer ; // 数
mLin : array of TDataLine; // 幾何要素|線分
mLinN : Integer ; // 数
mFzk : array of TDataFukugoZukei; // 構造化要素|複合図形配置
mFzkN : Integer ; // 数
end;
TDataClass = class
public
{ Public 宣言 }
・・・
dLin : array of TDataLine; // 表記要素|線分
dLinN: Integer ; // 数
・・・ |
データ追加用の関数は
function AddDataLine(s:string;lay,col,ltp,wid:integer;x1,y1,x2,y2:double) : Boolean; |
のようにします。点マーカ・複合図形配置と同様、最初に「データ追加先の複合図形名(幾何要素) null:用紙へ追加(表記要素)」を指定するようにしています。手法的には、点マーカと全く同じですが、レイヤ内の数等の指定も一応一緒に出来るようにしておきます。同じ事を何度も書くと手間なので手続き化しておきます。また、レイヤデータにレイヤ文字フォントの指定を出来るようにしています。
UnitData.pas |
// レイヤ内等の数を+1する
// ※レイヤ等のコードはチェックしていないので注意
// lay: レイヤ(1-256) -1:+1しない
// col: 色 (0,1-256) -1:+1しない
// ltp: 線種(0,1-32) -1:+1しない
// wid: 線幅(0,1-16) -1:+1しない
// fnt: 文字フォント(0,1-1024) -1:+1しない
procedure TDataClass.AddLayerCnt(lay,col,ltp,wid,fnt:integer);
var
i : integer ;
begin
// レイヤ 数
if (lay > 0) then
zLay[lay-1].cnt := zLay[lay-1].cnt + 1;
// 色 数
if (col > 0) then
zCol[col-1].cnt := zCol[col-1].cnt + 1
else if (col = 0)and(lay > 0) then begin
i := zLay[lay-1].Color;
zCol[i-1].cnt := zCol[i-1].cnt + 1;
end;
// 線種 数
if (ltp > 0) then
zLtp[ltp-1].cnt := zLtp[ltp-1].cnt + 1
else if (ltp = 0)and(lay > 0) then begin
i := zLay[lay-1].Ltype ;
zLtp[i-1].cnt := zLtp[i-1].cnt + 1;
end;
// 線幅 数
if (wid > 0) then
zWid[wid-1].cnt := zWid[wid-1].cnt + 1
else if (wid = 0)and(lay > 0) then begin
i := zLay[lay-1].Width ;
zWid[i-1].cnt := zWid[i-1].cnt + 1;
end;
// 文字フォント 数
if (fnt > 0) then
zFnt[fnt-1].cnt := zFnt[fnt-1].cnt + 1
else if (fnt = 0)and(lay > 0) then begin
i := zLay[lay-1].Mfont ;
zFnt[i-1].cnt := zFnt[i-1].cnt + 1;
end;
end; |
// 線分 データ項目の追加登録
function TDataClass.AddDataLine(s:string;lay,col,ltp,wid:integer;x1,y1,x2,y2:double) : Boolean;
var
m : integer ;
begin
Result := False;
if (lay < 1) or (lay > zLayN) then lay := 1 ;
if (col < 0) or (col > zColN) then col := 0 ;
if (ltp < 0) or (ltp > zLtpN) then ltp := 0 ;
if (wid < 0) or (wid > zWidN) then wid := 0 ;
if (s = '') then begin
// 用紙へ追加
try
Inc(dLinN);
if ((dLinN mod 200) = 1) then SetLength(dLin, dLinN+199);
with dLin[dLinN-1] do begin
exf := True ;
Layer := lay ;
Color := col ;
Ltype := ltp ;
line_width := wid ;
start_x := x1 ;
start_y := y1 ;
end_x := x2 ;
end_y := y2 ;
end;
Result := True ;
AddLayerCnt(lay,col,ltp,wid,-1);
except
Dec(dLinN);
end;
end
else begin
m := FZukeiNameCheck(0,s);
if (m = 0) then exit ; // 追加先の複合図形名は無いのでエラー
with fDef[m-1] do begin
try
Inc(mLinN);
if ((mLinN mod 200) = 1) then SetLength(mLin, mLinN+199);
with mLin[mLinN-1] do begin
exf := True ;
Layer := lay ;
Color := col ;
Ltype := ltp ;
line_width := wid ;
start_x := x1 ;
start_y := y1 ;
end_x := x2 ;
end_y := y2 ;
end;
Result := True ;
AddLayerFCnt(lay,col,ltp,wid,-1);
except
Dec(mLinN);
end;
end;
end;
end; |
さて、これで線分データの登録は出来るようになりました。画面に線分を描画する手続きは UnitGraph.pas にて既に G_Line手続きとして作成していますがこれでは不十分です。線種の表現が出来ていない為です。
GDI/GDI+/Direct2Dでは、線種=線のスタイルとして、Pen.Style 等により破線・点線・一点鎖線・二点鎖線の描画は出来るのですが、ドット的な表現であって mm値での任意指定は出来ません。そのため、実線以外の線分は、線種ピッチ長さの複数の線分に分解して描画を行う必要があります。
斜めに傾いた線分を表現するには、線分の傾き角度を計算し、線種フィーチャで定義した各ピッチ長さ分の短い線の位置を計算しながら作図していく事になります。
連続線を作図する事を考慮すれば、線種も連続になるように注意する必要がありますが少し煩雑になるので次回以降に述べる事にします。まずは簡単に下記のように記述してみます。
UnitData.pas |
// 線分の表示
procedure TForm1.DisplayLine(lay,col,ltp,wid:integer;px1,py1,px2,py2:double);
var
c,w,l,i : integer ;
x1,y1,x2,y2 : integer ;
a,d,d1,p,wx1,wy1,wx2,wy2 : double ;
begin
c := col ;
if (c = 0) then c := CData.zLay[lay-1].Color ;
c := RGB(CData.zCol[c-1].Red,CData.zCol[c-1].Green,CData.zCol[c-1].Blue);
gp.G_SetPen(c);
w := wid ;
if (w = 0) then w := CData.zLay[lay-1].Width ;
w := Round(CData.zWid[w-1].Width * mm_dot) ;
if (w < 1) then w := 1 ;
gp.G_SetWidth(w);
l := ltp ;
if (l = 0) then l := CData.zLay[lay-1].Ltype ;
//
if (CData.zLtp[l-1].Segment = 0) then begin
Z2D(x1,y1, px1,py1);
Z2D(x2,y2, px2,py2);
gp.G_Line(x1,y1,x2,y2);
end
else begin
a := Angle(px2-px1,py2-py1);
d := Dist(px1,py1,px2,py2);
d1:= 0.0 ;
i := 0 ;
while (d1 < d) do begin
wx1:= px1 + d1*Cos(a);
wy1:= py1 + d1*Sin(a);
p := CData.zLtp[l-1].Pitch[i];
d1 := d1 + p ;
if (d1 > d) then d1 := d;
wx2:= px1 + d1*Cos(a);
wy2:= py1 + d1*Sin(a);
Z2D(x1,y1, wx1,wy1);
Z2D(x2,y2, wx2,wy2);
gp.G_Line(x1,y1,x2,y2);
Inc(i);
p := CData.zLtp[l-1].Pitch[i];
d1 := d1 + p ;
Inc(i);
if (i >= CData.zLtp[l-1].Segment) then i:=0;
end;
end;
end; |
線種のセグメント数が「0」の場合には実線であるとして、線分をそのまま描画しています。そうでない場合には破線等であるとし、線分の角度(変数a)・線分の長さ(変数d)を算出し、各ピッチ長さ分ずつの線分を作図していきます。変数d1は途中経過の位置を示します。それが線分長さ内である限り繰り返しを行います。
線分データの登録、表示については下記のようにしています。
// 線分データ登録テスト
// 表記要素/用紙上に直接
col := 1 ;
ltp := 1 ;
wid := 1 ;
for i:=1 to 50 do begin
lx1 := i * 20 ;
ly1 := 100.0 ;
ly2 := 200.0 ;
CData.AddDataLine('', 1,col,ltp,wid, lx1,ly1,lx1,ly2);
Inc(col);
if (col > CData.zColN) then col := 1 ;
Inc(ltp);
if (ltp > CData.zLtpN) then ltp := 1 ;
Inc(wid);
if (wid > CData.zWidN) then wid := 1 ;
end;
// 線分データ表示テスト
// 表記要素/用紙上に直接
for i:=0 to CData.dLinN-1 do begin
with CData.dLin[i] do begin
DisplayLine(Layer,Color,Ltype,line_width,start_x,start_y,end_x,end_y);
end;
end;
// 線分データ登録テスト
// 幾何要素/部分図以下に
col := 1 ;
ltp := 1 ;
wid := 1 ;
for i:=1 to 50 do begin
lx1 := i * 20 ;
ly1 := 100.0 ;
ly2 := 200.0 ;
CData.AddDataLine('部分図A', 1,col,ltp,wid, lx1,ly1,lx1,ly2);
Inc(col);
if (col > CData.zColN) then col := 1 ;
Inc(ltp);
if (ltp > CData.zLtpN) then ltp := 1 ;
Inc(wid);
if (wid > CData.zWidN) then wid := 1 ;
end;
// 線分データ登録テスト
// 幾何要素/部分図以下に
for i:=0 to CData.zFztN-1 do begin
j := CData.FZukeiNameCheck(0,CData.zFzt[i].name) ;
if (j = 0) then continue ;
for k:=0 to CData.fDef[j-1].mLinN-1 do begin
with CData.fDef[j-1].mLin[k] do begin
MtxXY(lx1,ly1, start_x,start_y, CData.zFzt[i].mtx);
MtxXY(lx2,ly2, end_x ,end_y , CData.zFzt[i].mtx);
DisplayLine(Layer,Color,Ltype,line_width,lx1,ly1,lx2,ly2);
end;
end;
end; |
垂直線を用紙上に50本、部分図上に50本、登録&表示をさせているだけです。これをコンパイル(再構築)して実行すると、下図のようになります。
たったこれだけの線数にも関わらず、実行速度は結構掛かってしまいます。それをなるべく避けるため、多少のギミックを用意します。1つは、線種フィーチャの空白部のピッチ長さの最大値をとって、それが2ドット分に満たない場合には実線で表示させるようにします。そのため、線種データにそのデータ項目を追加する事にします。もう1つは、その空白部よりも線幅の方が大きい場合には実線で表示させるようにします。これは下図のように線幅で線種表現が潰れてしまうので実線で表現したほうが良いでしょう、という事です。
UnitData.pas |
TZumenLtype = record // 図面構造|線種
name : string ; // 線種名
Segment : Integer ; // セグメント数
Pitch : array[0..9] of double ; // 各ピッチ長
SpaceMax : double ; // 余白部最大ピッチ長
cnt : Integer ; // 線種内要素数
Fcnt : Integer ; // 複合図形定義内のレイヤ内要素数
end; |
// 線種 データ項目の追加登録
function TDataClass.AddLtype(s:string;seg:integer;pit:array of double) : Boolean;
・・・
with zLtp[zLtpN-1] do begin
name := s ;
Segment := seg ;
for i:=0 to 9 do
Pitch[i] := 0.0 ;
for i:=0 to seg-1 do
Pitch[i] := pit[i] ;
SpaceMax := 0.0 ;
for i:=0 to (seg div 2 - 1) do begin
if (SpaceMax < Pitch[i*2+1]) then
SpaceMax := Pitch[i*2+1] ;
end;
cnt := 0 ;
Fcnt := 0 ;
end;
Result := True ;
end; |
「線種 データ項目の編集登録」のほうも同様にします。
多少、小手先的なテクニック(テクニックといえるものでもない)ですが、下記のように修正してみます。
UnitData.pas |
// 線分の表示
procedure TForm1.DisplayLine(lay,col,ltp,wid:integer;px1,py1,px2,py2:double);
var
c,w,ww,l,i : integer ;
x1,y1,x2,y2 : integer ;
a,sa,ca,d,d1,p,wx1,wy1,wx2,wy2 : double ;
begin
c := col ;
if (c = 0) then c := CData.zLay[lay-1].Color ;
c := RGB(CData.zCol[c-1].Red,CData.zCol[c-1].Green,CData.zCol[c-1].Blue);
gp.G_SetPen(c);
w := wid ;
if (w = 0) then w := CData.zLay[lay-1].Width ;
ww := Round(CData.zWid[w-1].Width * mm_dot) ;
if (ww < 1) then ww := 1 ;
gp.G_SetWidth(ww);
l := ltp ;
if (l = 0) then l := CData.zLay[lay-1].Ltype ;
//
if (CData.zLtp[l-1].Segment = 0)
or(CData.zLtp[l-1].SpaceMax * mm_dot < 2.0)
or(CData.zLtp[l-1].SpaceMax < CData.zWid[w-1].Width) then begin
Z2D(x1,y1, px1,py1);
Z2D(x2,y2, px2,py2);
gp.G_Line(x1,y1,x2,y2);
end
else begin
a := Angle(px2-px1,py2-py1);
d := Dist(px1,py1,px2,py2);
ca:= Cos(a);
sa:= Sin(a);
d1:= 0.0 ;
i := 0 ;
while (d1 < d) do begin
wx1:= px1 + d1*ca;
wy1:= py1 + d1*sa;
p := CData.zLtp[l-1].Pitch[i] ;
d1 := d1 + p ;
if (d1 > d) then d1 := d ;
wx2:= px1 + d1*ca;
wy2:= py1 + d1*sa;
Z2D(x1,y1, wx1,wy1);
Z2D(x2,y2, wx2,wy2);
gp.G_Line(x1,y1,x2,y2);
Inc(i);
p := CData.zLtp[l-1].Pitch[i] ;
d1 := d1 + p ;
Inc(i);
if (i >= CData.zLtp[l-1].Segment) then i:=0;
end;
end;
end; |
保存・コンパイル(再構築)・実行をしてみます。
すると、上記のように破線状態にはならない分、描画速度は速くなります。例えば用紙サイズを「A4」にして画面を少し大きくして描画すると
という風に表示され、線種指定&描画が正常に出来ていることが確認出来ます。将来、拡大表示を行った場合には、クリッピング処理によって画面外の線分等は描画されない事になりますから、画面外の描画速度を気にする必要は無い、かもしれません。
それでは、ここまでのテストプログラムです。実行ファイル、gdiplus.dll、gdipフォルダは入っていません。ソースのみです。
|
|
CAD装置(1)
CAD装置(2)
メディア
AutoCADの
DIESELマクロ
CSV
DXF
PCES
IGES
STEP
数学とCAD
CAD作ろ!
CADを考える
▲PREV
▼NEXT
M7
Jw_cad
|