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

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

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
CADを考える:点マーカ
それでは、幾何要素/表記要素フィーチャを見ていく事にします。先の頁で記述したように、幾何要素というのは部分図内以下にある要素のことで、表記要素というのは用紙上にある要素のことで、要素の内容そのものは同じです。
 
幾何要素/表記要素フィーチャの最初にあるのは、点マーカです。
幾何要素/表記要素|点マーカ
マーカコード
パラメータ説明範囲
LayerIntレイヤコード
ColorInt色コード
start_xdouble配置点X座標 double(64bits)の
範囲(有効桁15桁)
start_ydouble配置点Y座標 double(64bits)の
範囲(有効桁15桁)
marker_codeIntマーカコード
rotate_angledouble回転角0≦度<360.0
Scaledouble尺度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フォルダは入っていません。ソースのみです。
 
CAD装置(1)
CAD装置(2)
メディア
AutoCADの
DIESELマクロ
CSV
DXF
PCES
IGES
STEP
数学とCAD
CAD作ろ!
CADを考える
 ▲PREV
 ▼NEXT
M7
Jw_cad
 
お問い合わせ 
本サイトはリンクフリーです
リンクバナー
(C)Copyright 1999-2015 By AFsoft All Rights Reserved.