C# 命中测试线段

C# 命中测试线段,c#,winforms,system.drawing,hittest,C#,Winforms,System.drawing,Hittest,1我有一个由两个端点和宽度定义的线段列表。 2这些线段在嵌板中绘制。 3当我的鼠标移动Panel.MouseMove事件时,我在线段列表上循环。 4.每人: gPath.Reset(); Pen Pen = new Pen(Color.White, 20); gPath.AddLine(P1, P2); return gPath.IsOutlineVisible(cursorPos, Pen); 5如果我为真,那么我知道我的光标悬停在当前线段上 这在大约……的时间内效果很好。。

1我有一个由两个端点和宽度定义的线段列表。 2这些线段在嵌板中绘制。 3当我的鼠标移动Panel.MouseMove事件时,我在线段列表上循环。 4.每人:

  gPath.Reset();
  Pen Pen = new Pen(Color.White, 20);
  gPath.AddLine(P1, P2);
  return gPath.IsOutlineVisible(cursorPos, Pen);
5如果我为真,那么我知道我的光标悬停在当前线段上

这在大约……的时间内效果很好。。。300行左右。当我达到1000时,我的程序会慢到停止。分析表明这是由IsOutlineVisible引起的。那么,有什么方法可以提高命中测试算法的性能呢?我不知道IsOutlineVisible的效率有多高,所以我不想实现该方法已经使用的任何优化。有什么想法吗

编辑: 在深入研究我的数据后,我注意到有些线条非常大。例如: 端点1=16000,-16000 端点2=5041448,-32868734

是的,其中一个坐标是负数千万

我验证了只对一个这样的线段进行命中测试就足以使我的程序停止,IsOutlineVisible需要2-3秒来进行测试,并且只要光标移动,测试就会运行

在发布之前,我应该对此进行更彻底的测试。感谢所有的回应,如果我最终处理了数千行,那么2d空间索引是一个很好的建议

p、 如果有人知道为什么大线段对IsOutlineVisible来说是个大问题,那就太好了。

试试这个:

public Line GetHotSpottedLine(Point mousePos){
        var line = lines.Where(line =>
        {
            Point p1 = new Point(Math.Min(line.P1.X, line.P2.X), Math.Min(line.P1.Y, line.P2.Y));
            Point p2 = new Point(Math.Max(line.P1.X, line.P2.X), Math.Max(line.P1.Y, line.P2.Y));
            return mousePos.X >= p1.X && mousePos.X <= p2.X && mousePos.Y >= p1.Y && mousePos.Y <= p2.Y;
        }).FirstOrDefault(line => {
            using (GraphicsPath gp = new GraphicsPath())
            {
                gp.AddLine(line.P1, line.P2);
                //You can declare your pen outside and this pen should be used to draw your lines.
                using (Pen p = new Pen(Color.Red, 20))
                {
                    return gp.IsOutlineVisible(mousePos, p);
                }
            }
        });
        return line;
 }
 public class Line{
        public Point P1 { get; set; }
        public Point P2 { get; set; }
 }
 List<Line> lines = new List<Line>();

这取决于你想如何使用你的线,如果你想画它们,我们必须注意的性能,绘制不检测悬停线,是的,在这种情况下,绘图是你的问题。我想我们可以在这里用一些线。无论如何,我测试了1000条线,它可以在Form Paint中绘制所有线,而不使用任何线程。

IsOutlineVisible调用Gdi+,这可能会让它慢一点

public bool GraphicsPath.IsOutlineVisible(PointF pt, Pen pen, Graphics graphics)
{
  int num;
  if (pen == null)
  {
      throw new ArgumentNullException("pen");
  }
  int status = SafeNativeMethods.Gdip.GdipIsOutlineVisiblePathPoint(new HandleRef(this, this.nativePath), pt.X, pt.Y, new HandleRef(pen, pen.NativePen), new HandleRef(graphics, (graphics != null) ? graphics.NativeGraphics : IntPtr.Zero), out num);
  if (status != 0)
  {
      throw SafeNativeMethods.Gdip.StatusException(status);
  }
  return (num != 0);
}
除此之外,这些命中测试并没有使用优化,比如为所有使用的图形元素建立二维索引。为了提高性能,我会尝试

自己实现命中测试并迭代所有元素 可能使用2D索引,但对于<1000个元素,我几乎不认为这是必要的。
您可能希望使用当前相关的.Net Windows UI技术了解一个非常类似的东西。它包括一些有趣的功能,如行选择和突出显示。谢谢,但我目前正在使用winforms。只是一个评论。我认为这会使测试变成矩形。从数学上讲,这样做可以提高性能,例如,边界框和向量距离应该很快。1000行太多了