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

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

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
DelphiXE3 [FMX] 変換マトリックス 2014/06/03
 
前回は、文字描画(FillText)について記述しました。今回は、変換マトリックス(Matrix)について見ていきます。
 
キャンバス(TCanvas)には、Matrix プロパティというものがあります。
これを実行時に操作する事により、それ以降に描画する図形の各種変形を行う事が出来るようになります。
 
以下、ヘルプより
TCanvas.
Matrix
property Matrix: TMatrix read FMatrix;
変換マトリックスを示します。
 
Matrix は読み取り専用プロパティで、TCanvas に対して適用される 2 次元変換を参照することができます。
 
TCanvas.
SetMatrix
procedure SetMatrix(const M: TMatrix);
Matrix プロパティを設定します。
 
TCanvas の下位クラスではこれをオーバーライドすることにより、matrix を設定し、使用されるプラットフォームに応じて変換することができます。
 
TCanvas.
MultiplyMatrix
procedure MultiplyMatrix(const M: TMatrix);
Matrix プロパティを拡大させます。
 
TCanvas での実装のように、なにも行いませんが、TCanvas の下位クラスではこれをオーバーライドして、キャンバスに対して、M マトリックスを使用した乗算変換を適用することができます。
 
今現在のキャンバスの変換マトリックス内容を参照する場合には、Matrix プロパティの内容を見れば良いです。キャンバスの変換マトリックス内容を即値で指定したい場合には、SetMatrix メソッドを利用します。また、キャンバスの現在の変換マトリックスに対してアフィン変換をしたい場合には、MultiplyMatrix メソッドを利用します。これを利用しなくても、Matrix プロパティ内容参照と SetMatrix メソッド利用で同じ事が出来ますけれども。
 
 
[Shapes]内のペイントボックス(PaintBox)を配置し、ClipChildernプロパティを True にしておきます。uses節に「UIConsts」を追記します。

OnPaintイベントハンドラを下記のようにしてみます。
まずは Matrixプロパティ内容の確認です。
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
 with Canvas do begin
  ShowMessage(FloatToStr(Matrix.m11)+' '
       + FloatToStr(Matrix.m12)+' '
       + FloatToStr(Matrix.m13)+#13+#10
       + FloatToStr(Matrix.m21)+' '
       + FloatToStr(Matrix.m22)+' '
       + FloatToStr(Matrix.m23)+#13+#10
       + FloatToStr(Matrix.m31)+' '
       + FloatToStr(Matrix.m32)+' '
       + FloatToStr(Matrix.m33) );
 end;
end;
保存・ビルド(コンパイル)・実行をすると下図の画面が表示されます。

 
見て分かる通り、単位行列に、X=24、Y=24、の移動指定が入っている状態になっていますが、これは、PaintBox1 をオブジェクトインスペクタで見ると分かる通り、PaintBox1.Position.X・Y の値そのままです。この状態では、Scaleプロパティはデフォルトの(1,1)状態、RotationAngleプロパティも同じくデフォルトの 0 状態、となっていますが、オブジェクトインスペクタでこれらを設定すると、キャンバスの Matrix プロパティには、それらが反映された内容となります。
 
ですので、OnPaintイベントハンドラ以外での PaintBox1.Canvas 内容の参照時には、PaintBox1の位置状態とは無関係に、フォーム内のクライアント領域の左上が(0,0)となりますから、上記とは異なる状態になると想定されます。
 
 
さて、それでは、下記のようにしてみて、変換マトリックスが有効になるかどうかを確認してみます。
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
 m : TMatrix ;
begin
 with Canvas do begin
  Clear(claWhite);
  m.m11 := 1.0 ;
  m.m12 := 0.0 ;
  m.m13 := 0.0 ;
  m.m21 := 0.0 ;
  m.m22 := 1.0 ;
  m.m23 := 0.0 ;
  m.m31 := 4.0 ;
  m.m32 := 4.0 ;
  m.m33 := 1.0 ;
  SetMatrix(m);
  Stroke.Kind := TBrushKind.bkSolid ;
  Stroke.Color := claBlue ;
  DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
 end;
end;
保存・ビルド(コンパイル)・実行をすると下図のようになります。

変換マトリックスの操作をしない場合には、

となりますから、描画する四角形が変換マトリックスにより移動されたのが分かります。しかし、SetMatrixメソッドで直接指定した場合には、現在の PaintBox1 の位置とは無関係な指定となってしまいますし、これから描画しようとする四角形の位置を相対的にどれくらい移動したいのか、というのが分かりません。
 
ですから、通常、現在の変換マトリックスに、これから相対的にどれくらい移動するのかを示すマトリックスを乗算(アフィン変換)して、指定をするという事になります。
例えば、右に20、下に10、移動したいという事なら、
m.m11 := 1.0 ;
m.m12 := 0.0 ;
m.m13 := 0.0 ;
m.m21 := 0.0 ;
m.m22 := 1.0 ;
m.m23 := 0.0 ;
m.m31 := 20.0 ;
m.m32 := 10.0 ;
m.m33 := 1.0 ;
m := MatrixMultiply(matrix,m);
SetMatrix(m);
Stroke.Kind := TBrushKind.bkSolid ;
Stroke.Color := claBlue ;
DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
という具合にすると、

となりますので、感覚的にも分かりやすいと思います。
 
m := MatrixMultiply(matrix,m);
SetMatrix(m);
の箇所は、
MultiplyMatrix(m);
と記述する事も出来ます。後者の方が簡単ですね。
 
 
次に、四角形の大きさを拡大縮小してみましょう。
横に1.2倍、縦に0.5倍、としてみます。
m.m11 := 1.2 ;
m.m12 := 0.0 ;
m.m13 := 0.0 ;
m.m21 := 0.0 ;
m.m22 := 0.5;
m.m23 := 0.0 ;
m.m31 := 0.0 ;
m.m32 := 0.0 ;
m.m33 := 1.0 ;
MultiplyMatrix(m);
SetMatrix(m);
Stroke.Kind := TBrushKind.bkSolid ;
Stroke.Color := claBlue ;
DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
これを実行すると、下図のようになります。

なお、拡大縮小は、(0,0)点が基準となりますので、例えば、四角形の中心を基準として拡大縮小したい場合には、四角形の中心は(75,75)ですから、X=-75・Y=-75 で移動して、拡大縮小をして、X=75・Y=75 で移動する、というようなプログラミングが必要です。マトリックスに値を入れるルーチンを利用すると簡単です。
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
 m,m1 : TMatrix ;
begin
 m := CreateTranslateMatrix(-75,-75);
 m1:= CreateScaleMatrix(1.2,0.5);
 m := MatrixMultiply(m,m1) ;
 m1:= CreateTranslateMatrix(75,75);
 m := MatrixMultiply(m,m1) ;
 with Canvas do begin
  Clear(claWhite);
  MultiplyMatrix(m);
  Stroke.Kind := TBrushKind.bkSolid ;
  Stroke.Color := claBlue ;
  DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
 end;
end;
これを実行すると、下図のようになります。

 
次に、四角形を45°回転させてみます。同じように、四角形の中心(75,75)を基準とします。
m := CreateTranslateMatrix(-75,-75);
m1:= CreateRotationMatrix(45.0/180.0*Pi);
m := MatrixMultiply(m,m1) ;
m1:= CreateTranslateMatrix(75,75);
m := MatrixMultiply(m,m1) ;
with Canvas do begin
 Clear(claWhite);
 MultiplyMatrix(m);
 Stroke.Kind := TBrushKind.bkSolid ;
 Stroke.Color := claBlue ;
 DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
end;
これを実行すると、下図のようになります。

 
さて、この四角形描画のあとは、普通のように拡大縮小も回転もしていない状態で別の四角形を描画したいとします。その場合は、最初の変換マトリックスを記憶保持しておき、変換処理が終わったら、元に戻して、次の処理を行う、という事になります。
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
 mo,m,m1 : TMatrix ;
begin
 m := CreateTranslateMatrix(-75,-75);
 m1:= CreateScaleMatrix(1.2,0.5);
 m := MatrixMultiply(m,m1) ;
 m1:= CreateRotationMatrix(45.0/180.0*Pi);
 m := MatrixMultiply(m,m1) ;
 m1:= CreateTranslateMatrix(75,75);
 m := MatrixMultiply(m,m1) ;
 with Canvas do begin
  mo := Matrix ; // 記憶
  Clear(claWhite);
  MultiplyMatrix(m);
  Stroke.Kind := TBrushKind.bkSolid ;
  Stroke.Color := claBlue ;
  DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
  SetMatrix(mo); // 戻す
  Stroke.Color := claRed ;
  DrawRect(RectF(20,20, 130,130),0,0,AllCorners,1.0);
 end;
end;
これを実行すると、下図のようになります。

 
 
次に楕円を回転させてみます。
m := CreateTranslateMatrix(-75,-75);
m1:= CreateRotationMatrix(45.0/180.0*Pi);
m := MatrixMultiply(m,m1) ;
m1:= CreateTranslateMatrix(75,75);
m := MatrixMultiply(m,m1) ;
with Canvas do begin
 mo := Matrix ; // 記憶
 Clear(claWhite);
 MultiplyMatrix(m);
 Fill.Kind := TBrushKind.bkGradient;
 Fill.Gradient.Color := claRed ;
 Fill.Gradient.Color1 := claYellow ;
 FillEllipse(RectF(20,50,130,100),1.0);
 Stroke.Kind := TBrushKind.bkSolid ;
 Stroke.Color := claBlue ;
 Stroke.Thickness := 10 ;
 DrawEllipse(RectF(20,50,130,100),1.0);
 SetMatrix(mo); // 戻す
 Stroke.Color := claRed ;
 Stroke.Thickness := 1 ;
 DrawEllipse(RectF(20,50,130,100),1.0);
end;
これを実行すると、下図のようになります。

 
 
次に、画像を回転させてみます。
var
 bm : TBitmap ;
・・・
bm := TBitmap.CreateFromFile('Hydrangeas.jpg') ;
m := CreateTranslateMatrix(-75,-75);
m1:= CreateRotationMatrix(45.0/180.0*Pi);
m := MatrixMultiply(m,m1) ;
m1:= CreateTranslateMatrix(75,75);
m := MatrixMultiply(m,m1) ;
with Canvas do begin
 Clear(claWhite);
 MultiplyMatrix(m);
 DrawBitmap(bm,RectF(0,0, bm.Width,bm.Height),
  RectF(20,30, 130,120),1.0);
end;
bm.Free ;
保存・ビルド(コンパイル)します。
Windowsサンプルピクチャ内の「アジサイ.jpg」を実行プログラムと同じフォルダにコピーしておきます。実行をすると下図のようになります。

 
 
次に、文字を回転させてみます。
m := CreateTranslateMatrix(-75,-75);
m1:= CreateRotationMatrix(45.0/180.0*Pi);
m := MatrixMultiply(m,m1) ;
m1:= CreateTranslateMatrix(75,75);
m := MatrixMultiply(m,m1) ;
with Canvas do begin
 mo := Matrix ; // 記憶
 Clear(claWhite);
 MultiplyMatrix(m);
 Fill.Kind := TBrushKind.bkSolid ;
 Fill.Color := claBlue ;
 Font.Family := 'MS 明朝';
 Font.Size := 32;
 Font.Style := [TFontStyle.fsItalic,TFontStyle.fsStrikeOut] ;
 FillText(RectF(0,0,150,150),'テストです',False,1.0,
  [], TTextAlign.taCenter);
 SetMatrix(mo); // 戻す
 Fill.Color := claRed ;
 Font.Size := 20;
 FillText(RectF(0,0,150,150),'テストです',False,1.0,
  [], TTextAlign.taCenter);
end;
これを実行すると、下図のようになります。

 
 
バッチファイル
BASIC
C言語のお勉強
拡張子な話
DOSプログラム
Delphi
>Dehi入門編
>Delphi2010
>DelphiXE3
▲2014/06/02
 2014/06/03
▼2014/06/05
 
シェアウェア
Script!World
データベース
 
お問い合わせ 
本サイトはリンクフリーです
リンクバナー
(C)Copyright 1999-2015. By AFsoft All Rights Reserved.