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

C# 如何在图形上创建镜像形状,c#,.net,winforms,gdi+,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)); 为此,我将在链接中得到左边图像的结果 如果我需要创建镜像以获得链接中正确图像的结果 是否有任何方法可以镜像

我有要点清单

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));
为此,我将在链接中得到左边图像的结果

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

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

有没有像复制和翻转图形和复合的东西


谢谢

就API而言,这是一个非常广泛的问题。所有与图形相关的API都有转换。命名空间中的类也是如此,它们主要用于SIMD操作。但从几何角度来看,答案很清楚,您需要对所有点应用正确的变换。在这种特殊情况下,它是

有些API直接支持反射,例如:

打印出反射点会产生:

0, 0
-30, 0
-30, -100
0, -100
在其他情况下,可以计算变换矩阵并将每个点乘以:

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

计算机图形学中的变换应用为3x2矩阵,其中第三列沿每个轴应用换位。在本例中,我们不希望移动结果,因此第三列包含0

这一次使用,而不是
反射

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+中,转换由对象表示。反射不可用,但当我们只想沿X或Y轴反射时,可以替换为。例如:

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

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

使用
图形SPATH
,可以使用以下方法镜像路径:

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
使用路径右侧作为轴

在下图中,红色弧线为原始弧线,绿色为左后视镜,蓝色为右后视镜:

下面是上述输出的代码:

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

您可以简单地翻转图形对象:

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

还请注意,
图形
只能显示正值,除非相应地移动图形对象。因此,如果没有
TranslateTransform
,您的数字将永远无法显示。(我已经为演示更改了它们。)

还请注意,连接的线条应始终使用
图形绘制。绘制线条
或使用较大的笔宽和/或半透明颜色将连接搞糟

正如Jimi所指出的,如果您想继续绘图,您将需要执行
e.Graphics.ResetTransform()翻转后,或者,如果您已经通过将画布转换为正面领域来准备整个图形,则恢复翻转前的状态。对于第一个存储,状态为:

var state = e.Graphics.Save();
然后恢复它:

e.Graphics.Restore(state);

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

我没有得到你想要的。您想镜像右侧视线上的左侧图像还是右侧图像?那太过分了,所以我不知道你的意思。你能给我们一个输入和输出的例子吗?所有与GDI相关的API都有2D转换,System.Drawing命名空间也是如此。可以使用二维变换矩阵检查和本章中的其他文章(包括容器和范围),将一个点阵列变换为另一个点阵列。可以变换特定区域、控件或路径对象。OTOH,为什么不使用WPF,它将所有这些属性表示为组件XAML上的转换?这是一个非常广泛的问题。你想干什么?除了Winforms中的转换API和XAML中对WPF及更高版本的本机支持之外,当您不想在屏幕上显示结果时,在名称空间中也有转换。。在本例中,镜像矩阵应用于GraphicsPath,但不是强制性的。阅读注释。当然这不是你的问题,但OP永远不会使用问题中提供的代码绘制该形状,包括
[Graphics].DrawLine()
、错误的索引和负值(除非原点上有活动的转换)。可以使用
[Graphics]绘制形状。绘制线(画笔、点列表.ToArray())
[GraphicsPath]。添加线(点列表.ToArray())
,而不关闭图形。正在克隆
GraphicsPath
对象。这可能需要
e.Graphics.ResetTransform
after(是的,我知道你知道:)。
var state = e.Graphics.Save();
e.Graphics.Restore(state);