如何在多段线上找到最近点

时间:2016-11-02 09:08:50

标签: c# unity3d

我正在努力寻找最佳性能的解决方案。

我需要在多段线(列表点)上找到给定点的壁橱点。

我的线有数千点,我需要每秒检查几次到这条线的距离。所以解决方案需要非常快。

现在我有类似下面的内容。它可以工作,但当线路有10000+点时它会很慢。

也许有人知道如何让它更快?

public static float GetSqrDistXZ(Vector3 a, Vector3 b)
{
    Vector3 vector = new Vector3(a.x - b.x, 0, a.z - b.z);
    return vector.sqrMagnitude;
}

public static Vector3 NearestPointOnFiniteLine(Vector3 start, Vector3 end, Vector3 pnt)
    {
        Vector3 line = (end - start);
        float len =  Mathf.Sqrt(line.sqrMagnitude);
        line.Normalize();

        Vector3 v = pnt - start;
        float d = (v.x * line.x) + (v.z * line.z); 
        d = Mathf.Clamp(d, 0f, len);
        return start + line * d;
    }


int pointsCount = line.points3.Count - 1;  // line - List<Vector3> points.

float[] distances = new float[pointsCount];

    for (int i = 0; i < pointsCount+1; i++) {
        if (i >= 1) {
            distances [i - 1] = GetSqrDistXZ (point, NearestPointOnFiniteLine (line.points3 [i - 1], line.points3 [i], point));
        }

    }

int minListIndexLeft = System.Array.IndexOf (distances, Mathf.Min (distances));
float minimalDistance = distances[minListIndexLeft];

Vector3 closestPoint = NearestPointOnFiniteLine (line.points3[minListIndexLeft], line.points3[minListIndexLeft+1], point);

1 个答案:

答案 0 :(得分:2)

您想要考虑空间分区。在这个例子中,我将假设一个2D空间,但这也适用于3D。还有更好的解决方案,如BSP树和东西,但我们会在这里保持简单。

想象一下,在2D空间上放置网格。您线条的每个线段(2点之间的距离)与该网格的一个或多个单元格相交。您需要做的是为每个单元格存储相交的段。如果您的线路没有变化,您可以在启动时一次性完成,甚至将该信息静态存储在资产中。

但是一旦获得了这些信息,您所需要做的就是计算您的点所在的单元格,然后只检查与该特定单元格或多个直接邻居相交的线段(见下文)。这样可以比较快速地找到最近点闪电。

如果你在一张纸上玩这个想法,你可能会遇到这种解决方案没有产生最近点的情况,因为它没有考虑包含更近点的相邻单元格。解决这个问题的最简单方法是采用以下方法:

1. Find cell C, which is the cell your point is in
2. Let cellRange = 0
3. Let point B be undefined

4. Find closest point P among all segments that intersect cell C and its neighboring cells of range cellRange*
5. If B is the same as newly found point P then P is the solution. You are done.
6. Increase cellRange by 1
7. Let B = P
8. Repeat from step 4

* "neighboring cells of range cellRange" means:
  cellRange 0: only cell C, no neighbours
  cellRange 1: cell C and direct neighbours
  cellRange 2: cell C, direct neighbours and their direct neighbours
  ...

此解决方案基本上检查增加搜索范围是否改进了解决方案。一旦增加范围没有改善解决方案,你就找到了最接近的点。