それでは、幾何要素/表記要素フィーチャを見ていく事にします。先の頁で記述したように、幾何要素というのは部分図内以下にある要素のことで、表記要素というのは用紙上にある要素のことで、要素の内容そのものは同じです。
幾何要素/表記要素フィーチャの最初にあるのは、点マーカです。
幾何要素/表記要素|点マーカ |
マーカコード
|
パラメータ | 型 | 説明 | 範囲 |
Layer | Int | レイヤコード |
|
Color | Int | 色コード |
|
start_x | double | 配置点X座標 |
double(64bits)の
範囲(有効桁15桁) |
start_y | double | 配置点Y座標 |
double(64bits)の
範囲(有効桁15桁) |
marker_code | Int | マーカコード |
|
rotate_angle | double | 回転角 | 0≦度<360.0 |
Scale | double | 尺度 | 0<尺度<1.0×1015 |
備考
・点マーカの大きさは用紙座標系で解釈する。 |
SXF Ver.3.1実装規約では、
. 点マーカの一つである“dot”を表示する場合の大きさは、画面の状態に関わらず、常に一定の大きさで表示する。 |
. 点マーカは、大きさ・回転角を以下の通りに扱って表示する。
大きさ:部分図の縮尺や作図部品配置倍率を考慮せず、
用紙(尺度1/1)に表示した際の大きさで表示する。
回転角:部分図の配置角度、作図部品配置角度を考慮し、
用紙に対する角度を算出して表示する。 |
とありますので、画面に描画する際にはこれに注意する必要があります。dotの大きさは常に一定との事なので、どこかで設定を行うようにして、このデータ項目の尺度値(Scale値)は掛けない、とするのが無難だと思われます。
それでは点マーカのデータ構造を決めます。
UnitData.pas |
type
・・・
TDataTenMarker = record // 幾何要素/表記要素|点マーカ
exf : Boolean ; // 存在フラグ(True:有り False:無し)
Layer : Integer ; // レイヤ(1〜256)
Color : Integer ; // 色 (0:レイヤ色 1〜256)
start_x : double ; // 配置点X座標
start_y : double ; // 配置点Y座標
marker_code : Integer ; // マーカコード(1〜7)
rotate_angle : double ; // 回転角[°]
Scale : double ; // 尺度
end;
TFukugoZukeiDef = record // 構造化要素|複合図形定義
exf : Boolean ; // 存在フラグ(True:有り False:無し)
name : string ; // 複合図形名
Flag : Integer ; // 種別フラグ
cnt : Integer ; // 配置数
// ・・・幾何要素等データが入る予定・・・
mTen : array of TDataTenMarker; // 幾何要素|点マーカ
mTenN : Integer ; // 数
mFzk : array of TDataFukugoZukei; // 構造化要素|複合図形配置
mFzkN : Integer ; // 数
end;
TDataClass = class
public
{ Public 宣言 }
・・・
dTen : array of TDataTenMarker; // 表記要素|点マーカ
dTenN : Integer ; // 数
・・・ |
データ追加用の関数は
function AddDataTen(s:string;lay,col,mc:integer;px,py,an,sc:double) : Boolean; |
のようにします。マーカコードを先に書いていますが、整数・実数をまとめる為です。複合図形配置と同様、最初に「データ追加先の複合図形名(幾何要素) null:用紙へ追加(表記要素)」を指定するようにしています。点マーカのデータはこれまで同様、動的配列で格納するようにしています。今後のその他のデータも同様となります。初期化・解放時に点マーカ用の動的配列を解放するようにしています。
UnitData.pas |
// 点マーカ データ項目の追加登録
function TDataClass.AddDataTen(s:string;lay,col,mc:integer;px,py,an,sc: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 (mc < 1) or (mc > 7) then mc := 3 ; // dot
an := SetAngle(an);
if (sc < LIMIT8) then sc := 1.0;
if (s = '') then begin
// 用紙へ追加
try
Inc(dTenN);
if ((dTenN mod 200) = 1) then SetLength(dTen, dTenN+199);
with dTen[dTenN-1] do begin
exf := True ;
Layer := lay ;
Color := col ;
start_x := px ;
start_y := py ;
marker_code := mc ;
rotate_angle:= an ;
Scale := sc ;
end;
Result := True ;
except
Dec(dTenN);
end;
end
else begin
m := FZukeiNameCheck(0,s);
if (m = 0) then exit ; // 追加先の複合図形名は無いのでエラー
with fDef[m-1] do begin
try
Inc(mTenN);
if ((mTenN mod 200) = 1) then SetLength(mTen, mTenN+199);
with mTen[mTenN-1] do begin
exf := True ;
Layer := lay ;
Color := col ;
start_x := px ;
start_y := py ;
marker_code := mc ;
rotate_angle:= an ;
Scale := sc ;
end;
Result := True ;
except
Dec(mTenN);
end;
end;
end;
end; |
一応、データのメモリ確保時に例外処理を入れていますが、これはプログラムが変なところで強制終了されたりすると困るから、という程度の理由です。メモリ確保は、データ200個分ずつ行っていますが、メモリの無駄使いになるかもしれませんが、図面データ読み込み時など、多くのデータをメモリ確保する際、動的配列の SetLengthを何度も連続して行うと処理時間は結構掛かってしまうため、このような処置をしています。
そのような処置は必要無いという事であれば、単純に、
Inc(dTenN);
SetLength(dTen, dTenN); |
のようにされても構いません。
さて、これで点マーカ・データの登録は出来るようになりましたが、画面に描画できないと面白くありません。線分の描画は既に作成しましたが、円の描画と点の描画が必要になります。点の描画は、塗り潰し円の描画という事になります。取り合えず簡単に、UnitGraph.pasに、G_Circle、G_CircleF、という手続きを作ってみます。
// 円描画
// x,y : 中心点
// r : 半径
procedure TGraphClass.G_Circle(x,y,r:integer) ;
begin
if (r < 1) then r := 1 ;
case(DisplayMode)of
0: begin // GDI
with Ca do begin
Brush.Style := bsClear ;
Ellipse(x-r,y-r, x+r,y+r);
end;
end;
1: begin // GDI+
gra.DrawEllipse(pen, x-r,y-r, r+r,r+r);
end;
2: begin // Direct2D
with D2DCanvas do begin
RenderTarget.DrawEllipse(D2D1Ellipse(D2D1PointF(x,y),r,r),D2Dbr,Pen.Width,D2Dss);
end;
end;
end;
end;
// 塗り潰し円描画
// x,y : 中心点
// r : 半径
procedure TGraphClass.G_CircleF(x,y,r:integer) ;
begin
if (r < 1) then r := 1 ;
case(DisplayMode)of
0: begin // GDI
with Ca do begin
Brush.Style := bsSolid ;
Brush.Color := Pen.Color ;
Ellipse(x-r,y-r, x+r,y+r);
Brush.Style := bsClear ;
end;
end;
1: begin // GDI+
gra.FillEllipse(br0, x-r,y-r, r+r,r+r);
end;
2: begin // Direct2D
with D2DCanvas do begin
RenderTarget.FillEllipse(D2D1Ellipse(D2D1PointF(x,y),r,r),D2Dbr);
end;
end;
end;
end; |
これで例えば
// テスト描画 点を描画
gp.G_SetPen(clRed);
for i:=1 to 20 do begin
lx1 := i * 50 ;
ly1 := 100.0 ;
x1 := Trunc(ox + (lx1 - CData.zp.x/2.0)*mm_dot) ;
y1 := Trunc(oy - (ly1 - CData.zp.y/2.0)*mm_dot) ;
x2 := Trunc(i*mm_dot);
gp.G_Circle(x1,y1,x2);
ly1 := 200.0 ;
y1 := Trunc(oy - (ly1 - CData.zp.y/2.0)*mm_dot) ;
gp.G_CircleF(x1,y1,x2);
end; |
のような単純に点を作図するテストプログラムを実行すると
のように表示されるのが確認できます。
それでは、点マーカのデータ登録を行い、[描画]をするとその点を描画するようにすれば良い訳ですが、表記要素=用紙上に直接表示=CData.dTenへの登録をするのか、幾何要素=部分図以下に表示=複合図形定義 CData.fDef[〜].mTenへの登録を行うのか、の区別と、それに応じた表示方法行う事が必要となります。
// 点マーカ・データ登録テスト
// 表記要素/用紙上に直接
col := 1 ;
for i:=1 to 20 do begin
lx1 := i * 50 ;
ly1 := 100.0 ;
CData.AddDataTen('', 1,col,1, lx1,ly1,0.0,1.0);
Inc(col);
if (col > CData.zColN) then col := 1 ;
end;
// 点マーカ・データ表示テスト
// 表記要素/用紙上に直接
for i:=0 to CData.dTenN-1 do begin
with CData.dTen[i] do begin
gp.G_SetPen(RGB(CData.zCol[Color-1].Red,CData.zCol[Color-1].Green,CData.zCol[Color-1].Blue));
x1 := Trunc(ox + (start_x - CData.zp.x/2.0)*mm_dot) ;
y1 := Trunc(oy - (start_y - CData.zp.y/2.0)*mm_dot) ;
gp.G_Circle(x1,y1,10);
end;
end; |
// 点マーカ・データ登録テスト
// 幾何要素/部分図以下に
col := 1 ;
for i:=1 to 20 do begin
lx1 := i * 50 ;
ly1 := 100.0 ;
CData.AddDataTen('部分図A', 1,col,1, lx1,ly1,0.0,1.0);
Inc(col);
if (col > CData.zColN) then col := 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].mTenN-1 do begin
with CData.fDef[j-1].mTen[k] do begin
gp.G_SetPen(RGB(CData.zCol[Color-1].Red,CData.zCol[Color-1].Green,CData.zCol[Color-1].Blue));
MtxXY(lx1,ly1, start_x,start_y, CData.zFzt[i].mtx);
x1 := Trunc(ox + (lx1 - CData.zp.x/2.0)*mm_dot) ;
y1 := Trunc(oy - (ly1 - CData.zp.y/2.0)*mm_dot) ;
gp.G_CircleF(x1,y1,5);
end;
end;
end; |
テストとして、表記要素は半径10ドットの円で、幾何要素は半径5ドットの塗り潰し円で表示させています。幾何要素での座標変換は、前回の複合図形ツリーデータの変換行列を使って換算しています。これを実行すると、
というようになります。四角は前回のテストのものを目安として付けています。四角は(0,0)-(200,150)です。緑色の四角は部分図A=角度30°、X尺度1.5、Y尺度1.2です。そのため、部分図Aに配置した点の位置もそれに応じて変化しています。
それでは次に、点マーカのコードに従ってその形状を表示させるようプログラミングしてみます。点マーカの大きさは、用紙上での大きさ×尺度(Scale値)であり、点マーカの角度は部分図〜作図グループ〜作図部品の影響を受ける回転角となりますので注意します。
// 点マーカ・データ登録テスト
// 表記要素/用紙上に直接
col := 1 ;
mc := 1 ;
for i:=1 to 20 do begin
lx1 := i * 50 ;
ly1 := 100.0 ;
CData.AddDataTen('', 1,col,mc, lx1,ly1,0.0,15.0);
Inc(col);
if (col > CData.zColN) then col := 1 ;
Inc(mc);
if (mc > 7) then mc := 1 ;
end;
// 点マーカ・データ表示テスト
// 表記要素/用紙上に直接
for i:=0 to CData.dTenN-1 do begin
with CData.dTen[i] do begin
an := rotate_angle/180.0*Pi ;
DisplayTenMarker(Layer,Color,marker_code,start_x,start_y,an,Scale);
end;
end;
// 点マーカ・データ登録テスト
// 幾何要素/部分図以下に
col := 1 ;
mc := 1 ;
for i:=1 to 20 do begin
lx1 := i * 50 ;
ly1 := 100.0 ;
CData.AddDataTen('部分図A', 1,col,mc, lx1,ly1,0.0,15.0);
Inc(col);
if (col > CData.zColN) then col := 1 ;
Inc(mc);
if (mc > 7) then mc := 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].mTenN-1 do begin
with CData.fDef[j-1].mTen[k] do begin
MtxXY(lx1,ly1, start_x,start_y, CData.zFzt[i].mtx);
an := rotate_angle/180.0*Pi ;
lx2 := start_x + 10.0*Cos(an);
ly2 := start_y + 10.0*Sin(an);
MtxXY(lx3,ly3, lx2,ly2, CData.zFzt[i].mtx);
an := Angle(lx3-lx1,ly3-ly1);
DisplayTenMarker(Layer,Color,marker_code,lx1,ly1,an,Scale);
end;
end;
end; |
幾何要素での角度取得は、水平線があると想定し、それを座標変換し、得られる換算座標への傾き角度を取得して、それを用紙に対する傾き角度としています。
用紙mm座標から画面ドット座標への変換は何度も書くと手間なので
// 用紙mm座標→画面ドット座標
procedure TForm1.Z2D(var ix,iy:integer;x,y:double);
begin
ix := Trunc(ox + (x - CData.zp.x/2.0)*mm_dot) ;
iy := Trunc(oy - (y - CData.zp.y/2.0)*mm_dot) ;
end; |
という手続きを追加しています。
点マーカの表示は下記のようにしています。
// 点マーカの表示
// an : 回転角[rad]
procedure TForm1.DisplayTenMarker(lay,col,mc:integer;px,py,an,sc:double);
var
c : integer ;
sz : double ;
w1,w2,w3,w4,w5,w6 : double ;
x1,y1,x2,y2,i1 : integer ;
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);
gp.G_SetWidth(1);
//
sz := 2.5/2.0*sc ;
case(mc)of
1: begin
// asterisk
w5 := px ;
w6 := py+sz ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px ;
w6 := py-sz ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px+sz*Cos(30.0/180.0*Pi) ;
w6 := py+sz*Sin(30.0/180.0*Pi) ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz*Cos(210.0/180.0*Pi) ;
w6 := py+sz*Sin(210.0/180.0*Pi) ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px+sz*Cos(150.0/180.0*Pi) ;
w6 := py+sz*Sin(150.0/180.0*Pi) ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz*Cos(330.0/180.0*Pi) ;
w6 := py+sz*Sin(330.0/180.0*Pi) ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
end;
2: begin
// circle
Z2D(x1,y1, px,py);
i1 := Trunc(sz*mm_dot);
gp.G_Circle(x1,y1,i1);
end;
3: begin
// dot
Z2D(x1,y1, px,py);
gp.G_CircleF(x1,y1,5);
end;
4: begin
// plus
w5 := px-sz ;
w6 := py ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz ;
w6 := py ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px ;
w6 := py+sz ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px ;
w6 := py-sz ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
end;
5: begin
// square
w5 := px-sz ;
w6 := py-sz ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz ;
w6 := py-sz ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px+sz ;
w6 := py-sz ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz ;
w6 := py+sz ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px+sz ;
w6 := py+sz ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px-sz ;
w6 := py+sz ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px-sz ;
w6 := py+sz ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px-sz ;
w6 := py-sz ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
end;
6: begin
// triangle
sz := 2.5*2.0/3.0*sc ;
w5 := px+sz*Cos(90.0/180.0*Pi) ;
w6 := py+sz*Sin(90.0/180.0*Pi) ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz*Cos(210.0/180.0*Pi) ;
w6 := py+sz*Sin(210.0/180.0*Pi) ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px+sz*Cos(210.0/180.0*Pi) ;
w6 := py+sz*Sin(210.0/180.0*Pi) ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz*Cos(330.0/180.0*Pi) ;
w6 := py+sz*Sin(330.0/180.0*Pi) ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px+sz*Cos(330.0/180.0*Pi) ;
w6 := py+sz*Sin(330.0/180.0*Pi) ;
Rev(w1,w2, w5,w6, px,py, an);
w5 := px+sz*Cos(90.0/180.0*Pi) ;
w6 := py+sz*Sin(90.0/180.0*Pi) ;
Rev(w3,w4, w5,w6, px,py, an);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
end;
7: begin
// X
w5 := px-sz ;
w6 := py ;
Rev(w1,w2, w5,w6, px,py, an+0.25*Pi);
w5 := px+sz ;
w6 := py ;
Rev(w3,w4, w5,w6, px,py, an+0.25*Pi);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
w5 := px ;
w6 := py+sz ;
Rev(w1,w2, w5,w6, px,py, an+0.25*Pi);
w5 := px ;
w6 := py-sz ;
Rev(w3,w4, w5,w6, px,py, an+0.25*Pi);
Z2D(x1,y1, w1,w2);
Z2D(x2,y2, w3,w4);
gp.G_Line(x1,y1,x2,y2);
end;
end;
end; |
これを実行すると、下図のようになります。
ここまでのテストプログラムです。実行ファイル、gdiplus.dll、gdipフォルダは入っていません。ソースのみです。
|