2

I have the point list

List<Point> pointList = new List<Point>();

pointList.Add(new Point(0,0));
pointList.Add(new Point(30,0));
pointList.Add(new Point(30,-100));
pointList.Add(new Point(0,-100));

Then Draw the line

Pen pen = new Pen(Color.Red,2);

g.Drawline(pen,pointList[0],pointList[1]);

g.Drawline(pen,pointList[3],poin,tList[4]);

for this I will get the result of the left image in the link

mirror image

and If I need to create the mirror to get the result of the right image in the link

is there any method that can mirror the graphic that I draw from pointlist ?

it there something like copy and flip the graphic and compound?

Thank you

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
WhiteCode
  • 43
  • 5
  • I didnt get what you want exactly. you want to mirror the left image on the right sight or the right image on the right side? that would be cutting, so i don't know what you mean. can you give us an example input and output? – slow Jan 07 '19 at 08:33
  • All GDI-related APIs have 2D transformations, and so does the System.Drawing namespace. You can use [Graphics.TransformPoints](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.graphics.transformpoints?view=netframework-4.7.2) to transform one array of points to another using a 2D transformation matrix – Panagiotis Kanavos Jan 07 '19 at 08:53
  • Check [Using Transformations in Managed GDI+](https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/using-transformations-in-managed-gdi) and the other articles in the chapter, including containers and ranges. You can transform specific areas, controls, or Path objects. OTOH, why not use WPF which has all of those attributes expressed as transformations right on a component's XAML? – Panagiotis Kanavos Jan 07 '19 at 08:56
  • This is a *very* broad question. What are you trying to do? Apart from the transformation API in Winforms and the native support in XAML for WPF and later, you also have transformations in the [System.Numeric.Vectors](https://learn.microsoft.com/en-us/dotnet/api/system.numerics?view=netframework-4.7.2) namespace, when you *don't* want to display the results to the screen. – Panagiotis Kanavos Jan 07 '19 at 08:58
  • 1
    [Flip the GraphicsPath](https://stackoverflow.com/a/53182901/7444103). In the example, the Mirror matrix is applied to a GraphicsPath, but it's not mandatory. Read the notes. – Jimi Jan 07 '19 at 13:35
  • Have you resolved your problems? – TaW Feb 07 '19 at 11:54

3 Answers3

3

Having a GraphicsPath, you can use the following methods to mirror the path:

GraphicsPath MirrorLeft(GraphicsPath path)
{
    var r = path.GetBounds();
    var p = (GraphicsPath)path.Clone();
    p.Transform(new Matrix(-1, 0, 0, 1, 2 * r.Left, 0));
    return p;
}
GraphicsPath MirrorRight(GraphicsPath path)
{
    var r = path.GetBounds();
    var p = (GraphicsPath)path.Clone();
    p.Transform(new Matrix(-1, 0, 0, 1, 2 * (r.Left + r.Width), 0));
    return p;
}

MirrorLeft, mirrors the path by using the left side of the path as axis, and MirrorRight uses the right side of the path as axis.

In the following picture, red arc is the original, green is mirror left, and blue is mirror right:

enter image description here

Here the code for above output:

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    using (var path1 = new GraphicsPath())
    {
        path1.AddArc(new Rectangle(100, 100, 200, 200), -90, 90);
        using (var pen1 = new Pen(Color.Red, 3))
            e.Graphics.DrawPath(pen1, path1);

        using (var path2 = MirrorLeft(path1))
        using (var pen2 = new Pen(Color.Green, 3))
            e.Graphics.DrawPath(pen2, path2);
        using (var path3 = MirrorRight(path1))
        using (var pen3 = new Pen(Color.Blue, 3))
            e.Graphics.DrawPath(pen3, path3);
    }
    base.OnPaint(e);
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • 1
    Of course it's not your *problem*, but the OP will never draw that shape using the code presented in the question, with `[Graphics].DrawLine()`, wrong indexing and negative values (unless there's an active transformation on the origin point). The shape can be drawn using `[Graphics].DrawLines(pen, pointList.ToArray())` or `[GraphicsPath].AddLines(pointList.ToArray())`, without closing the figure. – Jimi Jan 07 '19 at 16:01
2

You can simply flip the Graphics object:

e.Graphics.DrawLines(Pens.Black, pointList.ToArray());
e.Graphics.ScaleTransform(-1, 1);
// you need to know at which x value the flipping axis should be!
e.Graphics.TranslateTransform(..., 0);
e.Graphics.DrawLines(Pens.Red, pointList.ToArray());

Note that you need to know where you want to flip (mirror-axis). For the effect you show, you need to move to the right by twice the left edge (minimum) of the figure..:

int xmin = pointList.Min(x => x.X);
int xmax = pointList.Max(x => x.X);

e.Graphics.TranslateTransform(xmin * 2, 0);

enter image description here

Also note that the Graphics can only display positive values unless you move the Graphics object accordingly. So without a TranslateTransform your numbers will never show. (I have changed them for the demo.)

Also note that connected lines should always be drawn with Graphics.DrawLines or else the connections will get botched with larger pen widths and/or semi-transparent colors.

As Jimi notes, if you want to continue drawing, you will want to do either a e.Graphics.ResetTransform(); after the flip, or, if you had already prepared the whole drawing by translating the canvas into the positive realm, restore the state it had before the flip. For this first store the state:

var state = e.Graphics.Save();

and afterwards restore it:

e.Graphics.Restore(state);

Do note that you need to take care that those two commands need to be matched one for one!!

TaW
  • 53,122
  • 8
  • 69
  • 111
  • 1
    [Reza Aghaei](https://stackoverflow.com/a/54077316/7444103) is cloning the `GraphicsPath` object. This will, probably, require `e.Graphics.ResetTransform` after (yes, I know you know it :). – Jimi Jan 07 '19 at 17:47
0

In terms of API, this is a very broad question. All graphics related APIs have transformations. So do the classes in the System.Numerics namespace, which are used mainly in SIMD operations. In geometry terms though, the answer is clear, you need to apply the correct transformation to all points. In this particular case it's reflection.

Some APIs support reflection directly, eg Vector2.Reflect :

var points=new[]{
        new Vector2(0,0),
        new Vector2(30,0),
        new Vector2(30,-100),
        new Vector2(0,-100),                                                            
};

var reflect_y=new Vector2(1,0);
var reflected = points.Select(p=>Vector2.Reflect(p,reflect_y))            
                      .ToArray();

Printing out the reflected points produces :

0, 0
-30, 0
-30, -100
0, -100

In other cases one can calculate the transformation matrix and multiply each point by it with :

Reflection Matrix

This article explains the math and shows the values to use for reflection along the X, Y axes or both. In this case the desired matrix is :

Reflect Y

Transformations in computer graphics are applied as 3x2 matrices where the third column applies a transposition along each axis. In this case we don't want to move the result, so the third column contains 0s.

enter image description here

This time, Vector2.Transform is used instead of Reflect :

var reflect_y=new Matrix3x2(-1,0,0,1,0,0);
var reflected = ( from point in points
                  select Vector2.Transform(point,reflect_y)            
                ).ToArray();

In GDI+, a transformation is represented by a Matrix object. Reflect isn't available but can be replaced with Matrix.Scale when we want to reflect along the X or Y axes only. For example :

var m=new Matrix();
m.Scale(1,-1);
m.TransformVectors(points);

Will reflect an array of points by multiplying all X values by 1 and all Y values by -1.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236