Flip the GraphicsPath that draws the text/string

时光总嘲笑我的痴心妄想 提交于 2019-11-28 01:33:56

There is a simpler way to flip a Graphics object.
Create a Matrix which is the result of the Matrix multiplication of all the transformations that need to be applied to the specified object.

A Matrix transformation can be applied to either the GraphicsPath object or the Graphics object. Or both, when multiple transformation need to be performed sequentially.

The .Net System.Drawing.Drawing2D Matrix class does not have a pre-built Flip (mirroring) transformation, but this Matrix structure is already well known (I'm not sure this is the reason why there isn't a specific method in the Matrix class):

| 1 | 0 | 0 |       |-1 | 0 | 0 |       | 1 | 0 | 0 |
| 0 | 1 | 0 |       | 0 | 1 | 0 |       | 0 |-1 | 0 |
| 0 | 0 | 1 |       | 0 | 0 | 1 |       | 0 | 0 | 1 |

   Identity         Mirror X-Axis       Mirror Y-Axis
    Matrix              Matrix             Matrix

You can notice (it's also reported in the Docs) that the 3rd column is always the same, therefore, when building a new Matrix, the 3rd column values are implied and are provided by the Matrix class initialization, so we specify just the elements in the first 2 columns.

Important note, straight from the Matrix class Docs:

Caution:
The order of a composite transformation is important. In general, rotate, then scale, then translate is not the same as scale, then rotate, then translate. Similarly, the order of matrix multiplication is important. In general, ABC is not the same as BAC

An example of a string drawn on a Panel using the GraphicsPath.AddString() method.
Two Matrix transformations are added to the GraphicsPath object:
a Flip-X and a Flip-Y, which are combined using the Matrix.Multiply() method:

The Flip-X and Flip-Y Matrices are built including the X and Y translations, applied to the 3rd row of each Matrix. The translation values are determined by the Canvas dimensions.
For example, the Flip-X Matrix:

With a [Canvas].Width = 100 =>:
Rotation Element : Rotate the X-Axis 180° (-1 radians) on the origin Point(0, 0).
Translate Element: Translate the X Position 100 Graphics Units to the right (positive value).

| -1  |  0  |  0  |
|  0  |  1  |  0  |
| 100 |  0  |  1  |

   Mirror X-Axis
  Translate X +100
      Matrix 

A visual representation of the effect.
The Controls referenced in the code are the same you can see here (if you need to reproduce it).

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;

string SampleText = "Sample Text to Flip";
bool FlipX = false;
bool FlipY = false;
bool Outlined = false;

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.CompositingMode = CompositingMode.SourceOver;
    e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
    e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

    using (GraphicsPath path = new GraphicsPath())
    using (StringFormat format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap))
    {
        format.Alignment = StringAlignment.Center;
        format.LineAlignment = StringAlignment.Center;
        path.AddString(SampleText, new FontFamily("Segoe UI"), (int)FontStyle.Regular, 28, panel1.ClientRectangle, format);

        using (Matrix FlipXMatrix = new Matrix(-1, 0, 0, 1, panel1.Width, 0))
        using (Matrix FlipYMatrix = new Matrix(1, 0, 0, -1, 0, panel1.Height))
        using (Matrix TransformMatrix = new Matrix())
        {
            if (FlipX)
            {
                TransformMatrix.Multiply(FlipXMatrix);
            }
            if (FlipY)
            {
                TransformMatrix.Multiply(FlipYMatrix);
            }
            path.Transform(TransformMatrix);
            //Or e.Graphics.Transform = TransformMatrix;

            if (Outlined)
            {
                e.Graphics.DrawPath(Pens.LawnGreen, path);
            }
            else
            {
                e.Graphics.FillPath(Brushes.Orange, path);
            }

        }
    }
}

private void btnFlipX_Click(object sender, EventArgs e)
{
    FlipX = !FlipX;
    panel1.Invalidate();
}

private void btnFlipY_Click(object sender, EventArgs e)
{
    FlipY = !FlipY;
    panel1.Invalidate();
}

private void chkOutlined_CheckedChanged(object sender, EventArgs e)
{
    Outlined = chkOutlined.Checked;
    panel1.Invalidate();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!