Graphics.TransformのMatrixの中身を覗いてみる2「TransformPoints」

コンピュータ

Matrix.TransformPoints()でアフィン変換後の座標を計算してくれるようなので、試してみます。

プログラム

using System.Drawing.Drawing2D;

namespace MatrixSample;

public partial class Form1 : Form
{
    Bitmap _bmp = new Bitmap(256, 256);
    PictureBox picbox = new PictureBox
    {
        Dock = DockStyle.Fill,
        SizeMode = PictureBoxSizeMode.AutoSize,
    };

    // Matrixのプロパティを出力
    static void OutputMatrix(Matrix mat)
    {
        Console.WriteLine("{0}", mat);
        Console.Write("Elements:[");
        foreach(var v in mat.Elements) {
            Console.Write("{0:0.0},", v);
        }
        Console.WriteLine("]");
        Console.WriteLine("IsIdentity:{0}",mat.IsIdentity);
        Console.WriteLine("IsInvertible:{0}",mat.IsInvertible);
        Console.WriteLine("OffsetX:{0}",mat.OffsetX);
        Console.WriteLine("OffsetY:{0}",mat.OffsetY);
        Console.WriteLine("");
    }
    public Form1()
    {
        InitializeComponent();

        // 青色の画像
        using (var g = Graphics.FromImage(_bmp))
        {
            g.Clear(Color.Blue);
        }
        // リサイズ
        picbox.Resize += (s, e) =>
        {
            picbox.Image?.Dispose();
            picbox.Image = new Bitmap(picbox.Width, picbox.Height);
        };

        // マウスクリック
        picbox.MouseDown += (s, e) =>
        {
            if (picbox.Image is null) return;

            using var g = Graphics.FromImage(picbox.Image);

            // ピクチャボックスのクリア  
            g.Clear(picbox.BackColor);

            // 領域
            var rect = new RectangleF(-0.5f, -0.5f, _bmp.Width, _bmp.Height);
            var points = new PointF[]
            {
                new PointF(rect.Left, rect.Top),
                new PointF(rect.Right, rect.Top),
                new PointF(rect.Left, rect.Bottom),
            };

            // 縮小、移動
            var mat = new Matrix();
            Console.WriteLine("Before");
            OutputMatrix(mat);
            mat.Scale(0.5f, 0.5f, MatrixOrder.Append);
            mat.Translate(100, 100, MatrixOrder.Append);
            Console.WriteLine("After");
            OutputMatrix(mat);

            mat.TransformPoints(points);
            // 描画
            g.DrawImage(
                _bmp,
                points,
                rect,
                GraphicsUnit.Pixel
            );

            Console.WriteLine("LT{0}, RT{1}, LB{2}", points[0], points[1], points[2]);
            // リフレッシュ
            picbox.Refresh();
        };

        this.Controls.Add(picbox);
    }
}

結果

Before
System.Drawing.Drawing2D.Matrix
Elements:[1.0,0.0,0.0,1.0,0.0,0.0,]
IsIdentity:True
IsInvertible:True
OffsetX:0
OffsetY:0

After
System.Drawing.Drawing2D.Matrix
Elements:[0.5,0.0,0.0,0.5,100.0,100.0,]
IsIdentity:False
IsInvertible:True
OffsetX:100
OffsetY:100

LT{X=99.75, Y=99.75}, RT{X=227.75, Y=99.75}, LB{X=99.75, Y=227.75}
このプログラムでは高さ256幅256の青色の正方形のビットマップ画像を、アフィン変換で0.5倍に縮小し、x座標+100Y座標+100方向へ移動しています。移動後の座標をTransformPoints()で求めたの値は、99.75及び227.75の2種類になりました。
例えば、LT(Left.Top)のXは99.75ですが、こちらは-0.5(x座標)*0.5(拡縮倍率)+100(x移動量)で求められます。
次にRT(Right.Top)のXは227.75ですが、こちらは(-0.5(x座標)+256(幅))*0.5(拡縮倍率)+100(x移動量)だと思われます。
PointFの配列を作る部分は少し面倒ですが、自前で計算することを考えると大変便利な機能だと思います。

コメント