【问题标题】:Polyline shifting algorithm折线移位算法
【发布时间】:2017-03-29 05:45:50
【问题描述】:

我有一个包含折线 (PointCollection) 的列表,如图所示。一些片段像“原始”中所示的蓝色和橙色线一样重叠。我已经知道这些是哪些部分。我需要将重叠的部分分开。棘手的是要避免新的与其他行重叠,如“错误”中所示。

我的问题是,我只有节点的坐标,没有关于段的信息。是否有可能确定我是否在另一条线的一段上移动节点?有人知道我该如何解决这个问题吗?

【问题讨论】:

  • 您的目标是什么:Winforms、WPF、ASP..? 总是正确标记您的问题! - 你想怎么换班?手动还是代码?哪个方向?随机?您可以编写一个试错例程,该例程使用相同的测试来检查重叠,因为您必须首先找到重叠。 (提示您可以将折线制作成图形路径,并将它们组合成可以测试是否为空的区域)
  • 我为第三方工具准备数据,我不会在我的应用程序中将其可视化。目标是通过代码移动节点。我的想法是将节点在两个线段之间的角平分线方向上向左或向右移动。在我移动节点之前,我想测试哪个方向是空的。如何将折线转换为图形路径?
  • 您可以使用 GDI+ 图形并且仍然只导出结果而不实际显示任何内容,尽管对于测试例程,一个小型 winforms 项目可能是个好主意...您只需将点数组添加到空图形路径:gp.AddLines(pointlist.ToArray())。要移动 GP,请使用 Matrix 和 gp.transform!从一个 gp 创建一个区域并使用 reg.Intersect(gp2) 和 if (reg.IsEmtpy(graphics object)) 进行测试..
  • 请注意,此解决方案将取决于您创建的 Graphics 对象的像素分辨率。所以也许需要一个分析解决方案;为此,您将在几何上测试线段相交。周围的线交叉点有不少帖子..

标签: c# winforms 2d gdi+ polyline


【解决方案1】:

如 cmets 中所述,您可以选择

  • 通过几何计算分析解决问题或
  • 使用一些 GDI+ 方法

这是后者的一个例子:

首先,您的控制台应用程序需要包含对 System.Drawing 的引用和一些 using 子句:

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;  //optional, used for bitmap saving only

这是一个静态函数,用于测试两个GraphicsPaths 是否相交:

static bool intersect(GraphicsPath gp1, GraphicsPath gp2, Graphics g) 
{
    using (Region reg = new Region(gp1))
    {
        reg.Intersect(gp2);
        return !reg.IsEmpty(g);
    }
}

它需要两个 GraphicsPaths 和一个 Graphics 对象。

这是一个演示如何使用它的测试平台。它创建 2 条随机折线,然后每次将第二条折线向右移动 50 个像素,直到它不再与第一条相交。

所有阶段都被绘制成一个位图,然后被保存..:

static void Main(string[] args)
{
    int w = 1234;
    int h = 1234;

    Random rnd = new Random(0);
    for (int t = 0; t < 33; t++)
    {
        List<Point> l1 = new List<Point>();
        List<Point> l2 = new List<Point>();
        for (int i = 0; i < 4; i++)
        {
            l1.Add(new Point(rnd.Next(1234), rnd.Next(567)));
            l2.Add(new Point(rnd.Next(567), rnd.Next(1234)));
        }

        using (Matrix m = new Matrix())
        using (Bitmap bmp = new Bitmap(w, h))
        using (Graphics g = Graphics.FromImage(bmp))
        using (GraphicsPath gp1 = new GraphicsPath())
        using (GraphicsPath gp2 = new GraphicsPath())
        {
            gp1.AddLines(l1.ToArray());
            gp2.AddLines(l2.ToArray());
            m.Translate(50, 0);
            bool intersects = intersect(gp1, gp2, g);
            g.Clear(Color.White);
            g.DrawPath(Pens.Blue, gp1);
            g.DrawPath(intersects ? Pens.Red : Pens.Green, gp2);

            while (intersects)
            {
                gp2.Transform(m);
                intersects = intersect(gp1, gp2, g);
                g.DrawPath(intersects ? Pens.Red : Pens.Green, gp2);
                intersects = intersect(gp1, gp2, g);
            }


            bmp.Save(@"D:\scrape\x\__xTest_" + t.ToString("000") + ".png", 
                     ImageFormat.Png);

        }
    }
}

这是其中一个输出文件:

您可以访问移动的路径点

 List<PointF> l3 = gp2.PathPoints.ToList();

请注意,您应该使Bitmap 足够大以容纳您的实际数字,或者缩小它们并使用floats

【讨论】:

  • 好的,我喜欢你使用 GDI+ 的方法。谢谢你的例子。我的想法是首先用没有交叉点的线填充平面。然后我选择重叠对中的第一个(例如蓝色的)并绘制它。接下来我选择第二个(橙色的)并将其向右移动。然后我将它与已经绘制的线进行比较,以检查我是否还有交叉点。如果是这样,我将其向左移动并重复检查。这是一个好方法吗?是否可以将一个 GraphicsPath 与平面中已绘制的 GraphicsPath 进行比较以检查交叉点?
  • 当然,只需将它们放入List&lt;GraphicsPath&gt; 并循环遍历即可。请注意,我只画它们来演示这个想法;你不需要做任何实际的绘图。虽然你需要Graphics对象来调用函数,所以你还需要一个Bitmap;但是所有的绘图本身都不是必需的!
猜你喜欢
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多