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

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

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
CADを考える:図形描画(3)
前頁の続きで図形を画面に描画する手法について考えてみます。
 
前頁で GDI、GDI+、Direct2Dで線を描画する簡単なサンプルプログラムを作成しましたが、メインプログラム Unit1.pas 内に直接記述していましたので、専用の別ユニットとして UnitGraph.pas を作成する事にします。クラス化しておきます。
type
 TGraphClass = class
  public
  { Public 宣言 }
  DisplayMode : integer ; // 描画モード 0:GDI 1:GDI+ 2:Direct2D
  constructor Create;
  destructor Free;
  procedure DataInit;
  ・・・
  private
  { Private 宣言 }
  Ca: TCanvas ;
  gra : TGPGraphics;
  pen : TGPPen;
  D2DCanvas : TDirect2DCanvas ;
 end;
 
まずは、描画モードを設定する手続きを作成します。
// 描画モードを設定
//  m : 0:GDI 1:GDI+ 2:Direct2D
//  Direct2Dが使えるかどうかを判定してDisplayModeに入れる
procedure TGraphClass.SetDisplayMode(m:integer);
begin
 if (m < 0)or(m > 2) then m:=0;
 if (m = 2) then
  if not(TDirect2DCanvas.Supported) then m:=0;
 DisplayMode := m ;
end;
Direct2Dを指定した場合、Direct2Dが使えない環境の場合には、GDIで描画するようにします。後に画像を描画する場合には GDIの場合、GDI+を利用する事になろうと思いますし、塗り潰しの場合も GDI+を利用する事になるかもしれません。その際には手直しを加える可能性もあります。印刷の場合も基本的に GDIとGDI+の組み合わせで処理する事になると思われます。
 
メインプログラム Unit1.pas で「gp : TGraphClass ;」の定義をしておき、起動時に「gp := TGraphClass.Create ;」と行ってオブジェクト作成を行い、終了時に「gp.Free;」としてオブジェクト解放を行っています。
 
描画は、GDI+、Direct2Dの都合上、
gp.G_Start(PaintBox1.Canvas);
 ・・・各描画処理・・・
gp.G_End;
のように、開始・描画処理・終了の形を取るようにして、
// 描画開始
//  C : 描画先
//  描画を行う最初に必ず行う事
procedure TGraphClass.G_Start(C:TCanvas);
begin
 Ca := C ;
 case(DisplayMode)of
 0:begin  // GDI
   with Ca do begin
    Pen.Color := clBlack;
    Pen.Width := 1;
    Pen.Style := psSolid;
   end;
  end;
 1:begin  // GDI+
   gra := TGPGraphics.Create(Ca.Handle);
   gra.SetSmoothingMode(SmoothingModeHighSpeed);
   pen := TGPPen.Create(MakeColor(255, 0, 0, 0));
   pen.SetWidth(1.0);
  end;
 2:begin  // Direct2D
   D2DCanvas := TDirect2DCanvas.Create(Ca, Ca.ClipRect);
   with D2DCanvas do begin
    BeginDraw;
    RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); // アンチエイリアス無し
    Pen.Color := clBlack;
    Pen.Width := 1;
    Pen.Style := psSolid ;
   end;
  end;
 end;
end;
// 描画終了
//  描画を終わる時に必ず行う事
procedure TGraphClass.G_End ;
begin
 if (Ca = nil) then exit ;
 case(DisplayMode)of
 1:begin  // GDI+
   pen.Free;  pen := nil;
   gra.Free;  gra := nil;
  end;
 2:begin  // Direct2D
   with D2DCanvas do begin
    EndDraw;
    Free;
   end;
   D2DCanvas := nil;
  end;
 end;
end;
としています。
GDI+、Direct2Dでは、アンチエイリアスをオフ状態にしていますが、これは、処理速度を速くするためです。Direct2Dでは特に、アンチエイリアスをオンにしていると結構遅くなってしまいます。
 
取り合えず、画面クリア、ペン設定、ペン幅設定、線分描画の機能をつけています。GDI+、Diirect2Dでは、透過色等も使えますが現状は簡単な状態にしておきます。線幅に「0」を指定した場合、Direct2Dでは線分が描画されませんので、最低でも「1」に指定して下さい。
// 線分描画
//  x1,y1 : 始点
//  x2,y2 : 終点
procedure TGraphClass.G_Line(x1,y1,x2,y2:integer) ;
begin
 case(DisplayMode)of
 0:begin  // GDI
   with Ca do begin
    MoveTo(x1,y1);
    LineTo(x2,y2);
   end;
  end;
 1:begin  // GDI+
   gra.DrawLine(pen, x1,y1, x2,y2);
  end;
 2:begin  // Direct2D
   with D2DCanvas do begin
    DrawLine(D2D1PointF(x1,y1),D2D1PointF(x2,y2));
   end;
  end;
 end;
end;
 
そして実行をすると、線幅=1の場合には分かりませんけれども、線幅を大きくすると、GDIの場合には先端が丸くなりますが、GDI+、Direct2Dの場合には、先端がフラット(平ら)な状態になってしまいます。先端がフラットになっていると、連続線の場合、下図のようになって綺麗ではありませんから、先端は丸い方が無難です。

逆に、フラットにしたい場合、DelphiのTCanvasでは フラットにする設定がありませんので、WindowsAPIを使う事になってしまい、多少煩雑になります。
丸くしたい場合、GDI+の場合は簡単なのですが、Direct2Dの場合には多少煩雑になってしまうようです。Delphi2010のヘルプには記載が無いので不明ですが、どうやら、D2DFactoryを使用して独自のストロークスタイルを作成し、それを利用して、RenderTarget経由での DrawLine等メソッドを使って画面描画を行う必要があるようです。
type
 TGraphClass = class
  public
  { Public 宣言 }
  DisplayMode : integer ; // 描画モード 0:GDI 1:GDI+ 2:Direct2D
  constructor Create;
  destructor Free;
  procedure DataInit;
  procedure SetDisplayMode(m:integer);
  procedure G_Start(C:TCanvas);
  procedure G_End ;
  procedure G_Cls(col:integer) ;
  procedure G_SetPen(col:integer) ;
  procedure G_SetWidth(wid:integer) ;
  procedure G_Line(x1,y1,x2,y2:integer) ;
  private
  { Private 宣言 }
  Ca: TCanvas ;
  gra : TGPGraphics;
  pen : TGPPen;
  D2DCanvas : TDirect2DCanvas ;
  D2Dfa : ID2D1Factory ;
  D2Dss : ID2D1StrokeStyle ;
  D2Dbr : ID2D1Brush;
 end;
// 描画開始
//  C : 描画先
//  描画を行う最初に必ず行う事
procedure TGraphClass.G_Start(C:TCanvas);
begin
 Ca := C ;
 case(DisplayMode)of
 0:begin  // GDI
   with Ca do begin
    Pen.Color := clBlack;
    Pen.Width := 1;
    Pen.Style := psSolid;
   end;
  end;
 1:begin  // GDI+
   gra := TGPGraphics.Create(Ca.Handle);
   gra.SetSmoothingMode(SmoothingModeHighSpeed);
   pen := TGPPen.Create(MakeColor(255, 0, 0, 0));
   pen.SetWidth(1.0);
   // 先端を丸く設定
   pen.SetDashStyle(DashStyleSolid);
   pen.SetStartCap(LineCapRound);
   pen.SetEndCap(LineCapRound);
   pen.SetLineJoin(LineJoinRound);
  end;
 2:begin  // Direct2D
   D2DCanvas := TDirect2DCanvas.Create(Ca, Ca.ClipRect);
   with D2DCanvas do begin
    BeginDraw;
    RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); // アンチエイリアス無し
    Pen.Color := clBlack;
    Pen.Width := 1;
    Pen.Style := psSolid ;
    // 先端を丸く設定 描画はRenderTargetに対して行う事
    RenderTarget.GetFactory(D2Dfa);
    D2Dfa.CreateStrokeStyle(
      D2D1StrokeStyleProperties(D2D1_CAP_STYLE_ROUND,
       D2D1_CAP_STYLE_ROUND,D2D1_CAP_STYLE_ROUND,
       D2D1_LINE_JOIN_ROUND,10,D2D1_DASH_STYLE_SOLID,0),
      nil,0,D2Dss);
    D2Dbr := CreateBrush(Pen.Color);
   end;
  end;
 end;
end;
// 線分描画
//  x1,y1 : 始点
//  x2,y2 : 終点
procedure TGraphClass.G_Line(x1,y1,x2,y2:integer) ;
begin
 case(DisplayMode)of
 0:begin  // GDI
   with Ca do begin
    MoveTo(x1,y1);
    LineTo(x2,y2);
   end;
  end;
 1:begin  // GDI+
   gra.DrawLine(pen, x1,y1, x2,y2);
  end;
 2:begin  // Direct2D
   with D2DCanvas do begin
    RenderTarget.DrawLine(D2D1PointF(x1,y1),D2D1PointF(x2,y2),D2Dbr,Pen.Width,D2Dss);
   end;
  end;
 end;
end;
 ※取り合えず動作していますが、後に修正するかもしれません
 
 
メインプログラムのほうで、テスト描画として、ランダムで10000本の線を描画させています。GDI、GDI+、Direct2Dのそれぞれの描画速度がどれくらいなのかを確認できると思います。今回は、描画速度を確認できるよう実行プログラムもソースプログラムと一緒に同梱しておきます。そのためファイルサイズは大きくなってしまいますが。
 
 
それではここまでのテストプログラムです。
 
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.