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

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

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
CADを考える:楕円
前頁では、幾何要素/表記要素フィーチャの円弧について見ましたので今回は楕円について見てみます。
 
幾何要素/表記要素|楕円
パラメータ説明範囲
LayerIntレイヤコード
ColorInt色コード
TypeInt線種コード
line_widthInt線幅コード
Center_xdouble中心X座標 double(64bits)の
範囲(有効桁15桁)
Center_ydouble中心Y座標 double(64bits)の
範囲(有効桁15桁)
Radius_xdoubleX方向半径0<半径<1.0×1015
Radius_ydoubleY方向半径0<半径<1.0×1015
rotation_angledouble回転角0≦回転角<360
備考
 
SXF Ver.3.1実装規約では線分等同様、楕円について何も無さそうです。
 
それでは楕円のデータ構造を決めます。
UnitData.pas
type
 ・・・
 TDataEllipse = 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)
  Center_x : double ;   // 中心点X座標
  Center_y : double ;   // 中心点Y座標
  Radius_x : double ;   // X方向半径
  Radius_y : double ;   // Y方向半径
  rotation_angle:double ; // 回転角[°]
 end;
 
 TFukugoZukeiDef = record  // 構造化要素|複合図形定義
  exf : Boolean ;     // 存在フラグ(True:有り False:無し)
  name : string ;     // 複合図形名
  Flag : Integer ;     // 種別フラグ
  cnt : Integer ;     // 配置数
  ・・・
  mEll : array of TDataEllipse;   // 幾何要素|楕円
  mEllN : Integer ;         // 数
  mFzk : array of TDataFukugoZukei; // 構造化要素|複合図形配置
  mFzkN : Integer ;         // 数
 end;
 
 TDataClass = class
  public
  { Public 宣言 }
  ・・・
  dEll : array of TDataEllipse;   // 表記要素|楕円
  dEllN: Integer ;         // 数
  ・・・
 
データ追加用の関数は
function AddDataEllipse(s:string;lay,col,ltp,wid:integer;cx,cy,rx,ry,ra:double) : Boolean;
のようにします。線分等と同様、最初に「データ追加先の複合図形名(幾何要素) null:用紙へ追加(表記要素)」を指定するようにしています。
 
UnitData.pas
// 楕円 データ項目の追加登録
function TDataClass.AddDataEllipse(s:string;lay,col,ltp,wid:integer;cx,cy,rx,ry,ra: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 (rx < LIMIT10)or(ry < LIMIT10) then exit ; // 半径が <= 0
 ra := SetAngle(ra);
 
 if (s = '') then begin
  // 用紙へ追加
  if (AddDataOrder(-1,6,dEllN)) then begin
   try
    Inc(dEllN);
    if ((dEllN mod 200) = 1) then SetLength(dEll, dEllN+199);
    with dEll[dEllN-1] do begin
     exf := True ;
     Layer := lay ;
     Color := col ;
     Ltype := ltp ;
     line_width := wid ;
     Center_x := cx ;
     Center_y := cy ;
     Radius_x := rx ;
     Radius_y := ry ;
     rotation_angle := ra ;
    end;
    Result := True ;
    AddLayerCnt(lay,col,ltp,wid,-1);
   except
    Dec(dEllN);
    Dec(dOrdN);
   end;
  end;
 end
 else begin
  m := FZukeiNameCheck(0,s);
  if (m = 0) then exit ; // 追加先の複合図形名は無いのでエラー
  with fDef[m-1] do begin
   if (AddDataOrder(m,6,mEllN)) then begin
    try
     Inc(mEllN);
     if ((mEllN mod 200) = 1) then SetLength(mEll, mEllN+199);
     with mEll[mEllN-1] do begin
      exf := True ;
      Layer := lay ;
      Color := col ;
      Ltype := ltp ;
      line_width := wid ;
      Center_x := cx ;
      Center_y := cy ;
      Radius_x := rx ;
      Radius_y := ry ;
      rotation_angle := ra ;
     end;
     Result := True ;
     AddLayerFCnt(lay,col,ltp,wid,-1);
    except
     Dec(mEllN);
     Dec(mOrdN);
    end;
   end;
  end;
 end;
end;
 
さて、これで楕円データの登録は出来るようになりました。
 
次は、楕円の描画についてです。
円の方程式は、
  (x-cx)2+(y-cy)2=r2
ですが、プログラムで記述するには非常にやりにくいです。そのため通常は
  x=cx+r*Cosθ
  y=cy+r*Sinθ (θ:0〜2π)
の式を利用します。
 
同様に、楕円の方程式は
  (x-cx)2/rx2+(y-cy)2/ry2=1
となりますが、これも同様に
  x=cx+rx*Cosθ
  y=cy+ry*Sinθ (θ:0〜2π)
という形で利用します。但しこれには回転角が掛かっていませんので、回転を掛けるようにします。
 
円の描画を利用して楕円の描画を作ってみます。
UnitDataGraph.pas
// 楕円の表示
procedure DisplayEllipse(lay,col,ltp,wid:integer;px,py,rx,ry,ra:double;t:TMatrix);
const
 ARC_LENGTH = 15.0 ; // 補間線分長さ[dot相当値]
 ARC_MIN = 8 ;
 ARC_MAX = 360 ;
var
 c,cc,l,w, i,j : integer ;
 ww, d1, a,aa,n, x1,y1,x2,y2,x3,y3,x4,y4 : double ;
 fl : Boolean ;
 tr,tr1 : TMatrix ;
begin
 // 楕円・クリッピングチェック
 MtxMove(tr, -px,-py);
 MtxRotD(tr1,ra);
 tr := MtxMult(tr,tr1) ;
 MtxMove(tr1, px,py);
 tr := MtxMult(tr,tr1) ;
 t := MtxMult(tr,t) ;
 x1 := px-rx; y1 := py-ry; MtxXY(x1,y1, x1,y1, t);
 x2 := px+rx; y2 := py-ry; MtxXY(x2,y2, x2,y2, t);
 x3 := px+rx; y3 := py+ry; MtxXY(x3,y3, x3,y3, t);
 x4 := px-rx; y4 := py+ry; MtxXY(x4,y4, x4,y4, t);
 if (Clip4Point(x1,y1,x2,y2,x3,y3,x4,y4, WndX1,WndY1,WndX2,WndY2) = 2) then exit;
 
 x1 := 0.0 ;
 y1 := 0.0 ;
 x2 := rx*Cos(0.25*Pi) ;
 y2 := ry*Sin(0.25*Pi) ;
 MtxXY(x1,y1, x1,y1, t);
 MtxXY(x2,y2, x2,y2, t);
 d1 := Dist(x1,y1,x2,y2);
 a := ARC_LENGTH / (d1 * mm_dot) ;
 n := Int(2.0*Pi/a) ;
 if (n < ARC_MIN) then n := ARC_MIN ;
 if (n > ARC_MAX) then n := ARC_MAX ;
 a := 2.0*Pi / n ;
 
 DisplayLayCol2(lay,col,ltp,wid, c,cc,l,w,ww); // 色・線種・線幅
 //
 fl := False ;
 if (CData.zLtp[l-1].Segment = 0)
  or(CData.zLtp[l-1].SpaceMax * mm_dot < 2.0)
  or(CData.zLtp[l-1].SpaceMax * mm_dot < ww ) then
  fl := True ;
 
 i := 0 ;
 d1 := 0.0 ;
 aa := 0.0 ;
 x1 := px + rx*Cos(aa);
 y1 := py + ry*Sin(aa);
 MtxXY(x1,y1, x1,y1, t);
 for j:=1 to Round(n) do begin
  aa := aa + a;
  x2 := px + rx*Cos(aa);
  y2 := py + ry*Sin(aa);
  MtxXY(x2,y2, x2,y2, t);
  if (fl) then
   DisplayLineSub1(x1,y1,x2,y2)
  else
   DisplayLineSub2(l,i,d1, x1,y1,x2,y2) ;
  x1 := x2 ;
  y1 := y2 ;
 end;
end;
半径 pr だった箇所を、X方向半径 rx、Y方向半径 ry に変更し、楕円の回転角については、この手続きでは元々円を変換行列で変形して楕円状態にするようになっているので、その変換行列に対して、楕円の回転を前から掛けるようにしています。楕円の回転は楕円の中心点を基準に回転しますので、中心点の分をマイナス→回転→中心点の分をプラス、しています。 その後に部分図以下の変換行列を掛けます。そうすれば、クリッピングチェック、および、各点の座標を算出する際に、回転処理(UnitFunc.pas のRev・dRev等)を行ってから変換行列を掛ける、という事をせずに済みます。
 
これをしない場合は
 x:=px-rx; y:=py-ry; dRev(x1,y1,x,y,px,py,ra); MtxXY(x1,y1, x1,y1, t);
 x:=px+rx; y:=py-ry; dRev(x2,y2,x,y,px,py,ra); MtxXY(x2,y2, x2,y2, t);
 x:=px+rx; y:=py+ry; dRev(x3,y3,x,y,px,py,ra); MtxXY(x3,y3, x3,y3, t);
 x:=px-rx; y:=py+ry; dRev(x4,y4,x,y,px,py,ra); MtxXY(x4,y4, x4,y4, t);
 if (Clip4Point(x1,y1,x2,y2,x3,y3,x4,y4, WndX1,WndY1,WndX2,WndY2) = 2) then exit;
 aa := 0.0 ;
 x1 := px + rx*Cos(aa);
 y1 := py + ry*Sin(aa);
 dRev(x3,y3,x1,y1,px,py,ra);
 MtxXY(x1,y1, x3,y3, t);
 for j:=1 to Round(n) do begin
  aa := aa + a;
  x2 := px + rx*Cos(aa);
  y2 := py + ry*Sin(aa);
  dRev(x3,y3,x2,y2,px,py,ra);
  MtxXY(x2,y2, x3,y3, t);
  if (fl) then
   DisplayLineSub1(x1,y1,x2,y2)
  else
   DisplayLineSub2(l,i,d1, x1,y1,x2,y2) ;
  x1 := x2 ;
  y1 := y2 ;
 end;
end;
のような感じで、回転処理を行う dRev手続きを行うという形になります。それであれば事前に変換行列にその回転処理の計算も含んでおけば、dRev手続きを実行する手間や処理時間を軽減することが出来るという訳です。
 
では簡単な楕円描画のテストをしてみます。
Unit1.pas
・・・
// 楕円データ登録テスト
col := 1 ;
ltp := 1 ;
wid := 1 ;
for i:=1 to 10 do begin
 lx1 := i*10 ;
 ly1 := i*5 ;
 CData.AddDataEllipse('', 1,col,ltp,wid, 150.0,50.0,lx1,ly1,30.0);
 CData.AddDataEllipse('部分図A', 1,col,ltp,wid, 150.0,50.0,lx1,ly1,30.0);
 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;
・・・
これを実行すると下図のようになります。

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