如何在图形上创建镜像形状

时间:2019-01-07 08:31:07

标签: c# .net winforms gdi+

我有要点列表

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));

然后画线

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

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

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

为此,我将在链接中获得左侧图像的结果

mirror image

如果需要创建镜像以获取链接中正确图像的结果

是否有任何方法可以镜像我从点列表绘制的图形?

是否有类似复制和翻转图形以及复合的内容?

谢谢

3 个答案:

答案 0 :(得分:3)

具有GraphicsPath,您可以使用以下方法来镜像路径:

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,使用路径的左侧作为轴来镜像路径,而MirrorRight使用路径的右侧作为轴。

在下面的图片中,红色的弧是原始的,绿色是左侧的镜像,蓝色是右侧的镜像。

enter image description here

以下是上面输出的代码:

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);
}

答案 1 :(得分:2)

您只需翻转 图形对象:

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());

请注意,您需要要在哪里翻转(镜轴)。为了显示效果,您需要向右移动两倍于图形的左边缘(最小)。.

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

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

enter image description here

还请注意,除非您相应地移动Graphics对象,否则Graphics只能显示正值。因此,如果没有TranslateTransform,您的电话号码将永远无法显示。 (我已为演示更改了它们。)

还请注意,已连接的线应始终使用Graphics.DrawLines绘制,否则连接将被较大的笔宽度和/或半透明的颜色所破坏。

如Jimi所述,如果要继续绘制,则需要在翻转后执行e.Graphics.ResetTransform();,或者,如果您已经通过将画布平移到正向区域而准备了整个图形,请还原翻转之前的状态。对于第一个存储状态:

var state = e.Graphics.Save();

,然后将其还原:

e.Graphics.Restore(state);

请注意,您需要注意,这两个命令必须一对一地匹配

答案 2 :(得分:0)

就API而言,这是一个非常广泛的问题。所有与图形相关的API都有转换。 System.Numerics名称空间中的类也是如此,它们主要用于SIMD操作中。不过,就几何而言,答案很明确,您需要对所有点应用正确的变换。在这种情况下,它是reflection

某些API直接支持反射,例如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();

打印出反射点会产生:

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

在其他情况下,可以计算转换矩阵,并将其乘以每个点:

Reflection Matrix

article解释了数学原理,并显示了用于沿X,Y轴或这两个轴反射的值。在这种情况下,所需的矩阵为:

Reflect Y

计算机图形学中的变换以3x2矩阵的形式应用,其中第三列沿每个轴应用变换。在这种情况下,我们不想移动结果,因此第三列包含0。

enter image description here

这一次,使用Vector2.Transform代替了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();

在GDI +中,转换由Matrix对象表示。反射不可用,但是当我们只想沿X轴或Y轴反射时,可以用Matrix.Scale代替。例如:

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

将所有X值乘以1,将所有Y值乘以-1来反映点数组。