|
前頁の続きで図形を画面に描画する手法について考えてみます。
前頁で 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
|