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

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

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
CADを考える:ハッチング(5)
前頁の続きで、ハッチングについてです。
前回はハッチング要素データ(既定義(外部定義))の登録・描画について考えましたが、「既定義」の内容についてはテスト状態でしたので、今回はそれについて考えてみます。
 
SXF仕様書では、構造化要素にハッチング(既定義)フィーチャがあり、既定義(外部定義)のハッチング名を指定する事によってハッチングを行う事が出来る、という風に記載されていますが、「SXF Ver.3.1仕様書・同解説フィーチャ仕様編(第2版).pdf」では前回も書きましたが「CROSS_STRIPES」というサンプルで記載されていますが、これはあくまでもサンプルの様子らしく他の文書での記述は見当たりません。
「SXF Ver.3.1実装規約.pdf」によれば、
3 ダウンコンバート規約
3-3 構造化要素
(11)ハッチング(既定義)
線分に変換する。なお、外形および中抜きの図形に関しては、後述の「(15)複合曲線定義」を参照のこと。
既定義(外部定義)に関しては、「SXF Ver.3.1 仕様書・同解説共通既定義要素編」を参照のこと。
とありますので、「SXF Ver.3.1仕様書・同解説共通既定義要素編.pdf」を参照しますと
1 既定義要素の仕様
1-6 既定義ハッチング
要素種別構造化要素フィーチャ要素名既定義ハッチング
ハッチング名値(name)説明
Area_controlArea_controlハッチング形状はなく、空白の領域を定義する。
備考 
・属性付加機構を利用して、特定の領域に名称などの属性を付加したい場合に用いる特殊な既定義ハッチングである。
・ハッチング線、塗り、パターンのいずれも持たない空白の領域である。
とあるだけです。
これはハッチング領域図形を表すだけで、図面の背景色の属性を持たすような場合に利用するものですから、通常のハッチングとは異なります。つまりこれだけでは、ハッチング(既定義)要素データの意味がほとんどありません。ハッチング(ユーザ定義)(※後述)はありますのでそれを利用すればハッチングそのものの作図は可能ですが、どうにも納得出来ませんし、ハッチング(ユーザ定義)要素データを利用するとデータ毎にハッチングパターンを登録する事になるため、データ量が大きくなってしまいますし、そもそもなぜ、このような中身のない「既定義」という仕様が実在するのか?という疑問が沸いてきます。
 
そこで、少し古い仕様を見てみますと、SXF仕様 Ver.2の頃の文書ファイル「sxfv2shiyouR541extra1.pdf」を見ると、そこには、
3. 既定義要素の定義
3.2. 構造化要素
(2) ハッチング(既定義(外部定義))<EXTERNALLY_DEFINED_HATCH>

のように記述されています。この記載が Ver.3.0/3.1にて削除されているという事は、当初は仕様として作成したけれども、諸事情によって廃止された、という可能性はありますし、単なる記載忘れ、という可能性もありますが、この辺りは実際に、JACICのSXFライブラリを入手して、文書の確認や、実際にプログラムを作成し、それをSXFブラウザで表示させる等をして確認してみない事にはよく分かりません(※現在未確認)。
 
という訳で、本プログラムでは、取り合えず上記の6種類のハッチングパターンをハッチング(既定義)として利用出来るようにします。7,8はハッチング(パターン)(※後述)になりますのでロジックが異なりますから現在はパスします。前回では、UnitData.pasでの手続き MakeHatch1 にてハッチング計算を行うと述べましたが、ここで直接、条件判断をしても構わないのですが、柔軟性を高めるために、ハッチング名の定義を行って、それを判別してハッチング計算を行うようにしてみます。
 
それでは、既定義ハッチング名の定義です。
UnitData.pas
type
 ・・・
 THatchNameDef = record     // 既定義ハッチング名定義
  name : string ;       // ハッチング名(最大256バイト)
  hatch1_number : integer ;  // ハッチング線のパターン数(1-4)
  hatch1_color : array[0..3] of integer ;  // ハッチング線色コード
  hatch_type  : array[0..3] of integer ;  // ハッチング線線種コード
  hatch_line_width:array[0..3] of integer ; // ハッチング線線幅コード
  hatch_spacing : array[0..3] of double ;  // ハッチング線の間隔
  hatch_angle  : array[0..3] of double ;  // ハッチング線の角度[°]
 end;
 ・・・
 
 TDataClass = class
 public
  { Public 宣言 }
  ・・・
  hDef : array of THatchNameDef ; // 既定義ハッチング名定義
  hDefN: Integer ;         // 数
  ・・・
各項目データ名は、ハッチング(ユーザ定義)のものと同じにしています。なぜ「hatch1_」と「1」が付いているのかは不明なのですが。ハッチングの通過点は、ハッチング領域図形の外郭線の座標の最小値・最大値をとった中点位置とします。
 
既定義ハッチング名定義のデータ追加は、初期化の際に行います。
UnitData.pas
// 指定した既定義ハッチング名の番号を取得する
// s : ハッチング名
// (ret) 1〜:ハッチング名番号 0:登録無し
function TDataClass.HatchNameCheck(s:string) : Integer;
var
 i : integer;
begin
 Result := 0 ;
 for i:=0 to hDefN-1 do begin
  if (s = hDef[i].name) then begin
   Result := i + 1;
   break ;
  end;
 end;
end;
 
// 既定義ハッチング名定義 データ項目の追加登録
//  s : シンボル名
// (ret) True:登録OK False:NG
function TDataClass.AddHatchNameDef(s:string;num:integer;
 col,ltp,wid:array of integer;sp,an:array of double) : Boolean ;
var
 i : integer ;
begin
 Result := False;
 i := StrBytes(s);
 if (i < 1)or(i > 256) then exit;
 if (HatchNameCheck(s) <> 0) then exit; // 既に定義済
 
 try
  Inc(hDefN);
  SetLength(hDef, hDefN);
  with hDef[hDefN-1] do begin
   name := s ;
   hatch1_number := num ;
   for i:=0 to 3 do begin
    hatch1_color[i] := 0 ;
    hatch_type[i] := 0 ;
    hatch_line_width[i] := 0 ;
    hatch_spacing[i] := 0.0 ;
    hatch_angle[i] := 0.0 ;
   end;
   for i:=0 to num-1 do begin
    hatch1_color[i] := col[i] ;
    hatch_type[i] := ltp[i] ;
    hatch_line_width[i] := wid[i] ;
    hatch_spacing[i] := sp[i] ;
    hatch_angle[i] := an[i] ;
   end;
  end;
  Result := True ;
 except
  Dec(hDefN);
  SetLength(hDef, hDefN);
 end;
end;
 
ここで問題になるのは、色コードが「任意」となっているところです。任意の色コードを指定する場合は、hatch1_color[]値に「-1」を入れる事にします。しかしそうなると、ハッチング線の色を指定するところが無くなってしまいます。ハッチング(既定義)要素データには、色コードの指定がありません。ですので、ハッチング(既定義)要素データに色の指定を追加しておきます。
UnitData.pas
type
 ・・・
 TDataHatch1 = record     // 構造化要素|ハッチング(既定義)
  exf : Boolean ;      // 存在フラグ(True:有り False:無し)
  Layer : Integer ;     // レイヤ(1〜256)
  Color : Integer ;     // ハッチング線の色 (0:レイヤ色 1〜256)
  name : string ;      // ハッチング名(最大256バイト)
  out_id : Integer ;     // 外形の複合曲線のフィーチャコード
  Number : Integer ;     // 中抜の閉領域数(0〜)
  in_id : array of Integer; // 中抜の複合曲線のフィーチャコード
  hln : integer ;      // ハッチング線数
  hl : array of THatchLine; // ハッチング線
 end;
 ・・・
ここでの色指定は、既定義ハッチング名での色指定が任意の場合にのみ有効とします。これに従い、関数 AddDataHatch1も変更しておきます。
UnitData.pas
// ハッチング(既定義) データ項目の追加登録
function TDataClass.AddDataHatch1(s,st:string;lay,col,oid,num:integer;
 iid:array of integer) : Boolean ;
 
既定義ハッチング名定義データの初期化は下記のようにします。
UnitData.pas
// 既定義ハッチング名定義データ 初期値セット
procedure TDataClass.DataInitHatchName ;
begin
 hDef := nil;
 hDefN := 0;
 AddHatchNameDef('sxf_hatch_style_1', 1,[-1],[1],[2],[2.0],[45.0]);
  // 右上がり斜線
 AddHatchNameDef('sxf_hatch_style_2', 1,[-1],[2],[2],[2.0],[45.0]);
  // 右上がり斜線(破線)
 AddHatchNameDef('sxf_hatch_style_3', 1,[-1],[1],[2],[2.0],[0.0]);
  // 水平線
 AddHatchNameDef('sxf_hatch_style_4', 1,[-1],[2],[2],[2.0],[0.0]);
  // 水平線(破線)
 AddHatchNameDef('sxf_hatch_style_5', 2,
  [-1,-1],[1,1],[2,2],[2.0,2.0],[45.0,135.0]); // 斜線格子縞
 AddHatchNameDef('sxf_hatch_style_6', 2,
  [-1,-1],[2,2],[2,2],[2.0,2.0],[45.0,135.0]); // 斜線格子縞(破線)
 AddHatchNameDef('Area_control', 0,[],[],[],[],[]);
end;
これで6種類の既定義ハッチング名の定義が出来ました。見て頂ければ分かるように、同様にすれば、垂直線や左上がり斜線なども自由に作成できます。けれども SXF仕様にはありませんし、データの受け渡しがうまく行かないと余り意味が無いかもしれませんし、追加するのはいつでも出来るので、ここでは、ここまでとしてあります。
 
それでは実際のハッチング計算を行うよう修正を行います。
UnitData.pas
// ハッチング(既定義) ハッチング線の算出
// s : ハッチング名
// (ret)
// zHLn, zHLnN
procedure TDataClass.MakeHatch1(s:string) ;
var
 h,i,j,k : integer ;
 wx1,wy1,wx2,wy2 : double ;
 tl,tx,ty,ts,ta : double ;
 col,ltp,wid : integer ;
begin
 zHLn := nil ;
 zHLnN:= 0 ;
 h := HatchNameCheck(s);
 if (h = 0) then exit ;
 // min,maxを取得
 with zHAr[0] do begin
  wx1 := a[0].x ;
  wy1 := a[0].y ;
  wx2 := wx1;
  wy2 := wy1;
  for i:=1 to an-1 do begin
   if (wx1 > a[i].x) then wx1 := a[i].x ;
   if (wy1 > a[i].y) then wy1 := a[i].y ;
   if (wx2 < a[i].x) then wx2 := a[i].x ;
   if (wy2 < a[i].y) then wy2 := a[i].y ;
  end;
 end;
 tl := Dist(wx1,wy1,wx2,wy2); // 対角長さ
 tx := (wx1+wx2)/2.0; // 通過点
 ty := (wy1+wy2)/2.0;
 //
 for k:=0 to (hDef[h-1].hatch1_number-1) do begin
  ts := hDef[h-1].hatch_spacing[k] ; // ハッチング間隔
  ta := hDef[h-1].hatch_angle[k] ;  // ハッチング角度
  col:= hDef[h-1].hatch1_color[k] ;
  ltp:= hDef[h-1].hatch_type[k] ;
  wid:= hDef[h-1].hatch_line_width[k] ;
  // 通過点 及び 上方向へ走査
  j := 1 ;
  wx1:= tx ;
  wy1:= ty ;
  while (j > 0) do begin
   j := CalcHatch1Point(wx1,wy1,tl,ta); // 1ライン交点計算
   for i:=0 to (j div 2)-1 do begin
    try
     Inc(zHLnN);
     if ((zHLnN mod 100) = 1) then SetLength(zHLn, zHLnN+99);
     with zHLn[zHLnN-1] do begin
      Color := col ;
      Ltype := ltp ;
      line_width := wid ;
      x1 := zHCp[i*2 ].x ;
      y1 := zHCp[i*2 ].y ;
      x2 := zHCp[i*2+1].x ;
      y2 := zHCp[i*2+1].y ;
     end;
    except
     Dec(zHLnN);
     break ;
    end;
   end;
   wx1 := wx1 + ts*Cos((ta+90.0)/180.0*Pi);
   wy1 := wy1 + ts*Sin((ta+90.0)/180.0*Pi);
  end;
  // 下方向へ走査
  wx1:= tx ;
  wy1:= ty ;
  j := 1 ;
  while (j > 0) do begin
   wx1 := wx1 + ts*Cos((ta-90.0)/180.0*Pi);
   wy1 := wy1 + ts*Sin((ta-90.0)/180.0*Pi);
   j := CalcHatch1Point(wx1,wy1,tl,ta); // 1ライン交点計算
   for i:=0 to (j div 2)-1 do begin
    try
     Inc(zHLnN);
     if ((zHLnN mod 100) = 1) then SetLength(zHLn, zHLnN+99);
     with zHLn[zHLnN-1] do begin
      Color := col ;
      Ltype := ltp ;
      line_width := wid ;
      x1 := zHCp[i*2 ].x ;
      y1 := zHCp[i*2 ].y ;
      x2 := zHCp[i*2+1].x ;
      y2 := zHCp[i*2+1].y ;
     end;
    except
     Dec(zHLnN);
     break ;
    end;
   end;
  end;
 end;
 SetLength(zHLn, zHLnN);
 zHCp := nil;
 zHCpN:= 0;
end;
 
それでは、ハッチング(既定義)の登録・描画のテストです。
Unit1.pas
・・・
SetLength(lx,5);
SetLength(ly,5);
CData.AddCCurveDef(1,1,1,1,1);   // 複合曲線定義 #1
lx[0] := 40; ly[0] := 40 ;
lx[1] := 140; ly[1] := 40 ;
lx[2] := 140; ly[2] := 140 ;
lx[3] := 40; ly[3] := 140 ;
lx[4] := 40; ly[4] := 40 ;
CData.AddCCrvDataLines(1,5,lx,ly); // 折線
 
CData.AddCCurveDef(2,2,2,1,1);   // 複合曲線定義 #2
CData.AddCCrvDataArc(2,36,0, 90,130,8,0,180); // 円は円弧2つで形成
CData.AddCCrvDataArc(2,36,0, 90,130,8,180,0);
 
CData.AddCCurveDef(3,4,4,1,1);   // 複合曲線定義 #3
lx[0] := 60; ly[0] := 60 ;
lx[1] := 90; ly[1] := 90 ;
lx[2] := 60; ly[2] := 120 ;
lx[3] := 60; ly[3] := 60 ;
CData.AddCCrvDataSpline(3,3,10,4,0,lx,ly); // スプライン曲線
 
CData.AddCCurveDef(4,5,5,1,1);   // 複合曲線定義 #4
lx[0] := 120; ly[0] := 60 ;
lx[1] := 90; ly[1] := 90 ;
lx[2] := 120; ly[2] := 120 ;
lx[3] := 120; ly[3] := 60 ;
CData.AddCCrvDataSpline(4,3,10,4,0,lx,ly); // スプライン曲線
 
lx := nil;
ly := nil;
 
// ----- ハッチングテスト -----
// 右上がり斜線
CData.AddDataHatch1(''    ,'sxf_hatch_style_1',1,2,1,3,[2,3,4]);
CData.AddDataHatch1('部分図A','sxf_hatch_style_1',1,2,1,3,[2,3,4]);
 
DisplayAllData ; // 全データ表示
・・・
というような感じでハッチングデータの登録をして描画をすると下記のような感じになります。

少し拡大します

 
 
それでは、ここまでのテストプログラムです。実行ファイル、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.