【问题标题】:Least distance from a point to an area点到区域的最小距离
【发布时间】:2013-03-22 16:18:19
【问题描述】:

我试图在一个封闭区域中找到一个点 (P2),它与点 (P1) 的距离最小。该区域由同质像素构成,形状不完美,也不一定是凸面的。这基本上是从最短路径到达某个区域的问题。

整个空间以位图的形式存储在内存中。找到 P2 的最佳方法是什么?我应该使用随机搜索(优化)方法吗?优化方法没有给出确切的最小值,但它们比强制该区域的每个像素更快。我需要在几秒钟内执行数千个这样的决定。

该区域的MinX,MinY,MaxX,MaxY可用。

谢谢。

【问题讨论】:

  • 形状是凸的吗?否则解决方案可能不是唯一的。你可以在这里找到一些答案:math.stackexchange.com/questions/170731/…
  • 如果你也能解释一下这个逻辑的实现需求,可以想到一个可行的方案。
  • 区域内的点数是如何存储的?我们是否可以快速访问边界点(唯一相关的)?
  • 我们可以假设这个区域是凸的吗?
  • @chepner 我添加了信息。整个空间存储在内存位图中。

标签: algorithm graphics computational-geometry


【解决方案1】:

这是我的代码,它是使用离散坐标的离散版本:

提示:我用来求区域周长的方法很简单,就像你如何从陆地上知道海滩?答:海滩从一侧被海覆盖,所以在我的图形矩阵中,NULL 参考是海,点是土地!

课点:

class Point
{
    public int x;
    public int y;

    public Point (int X, int Y)
    {
        this.x = X;
        this.y = Y;
    }
}

课堂区:

class Area
{
    public ArrayList<Point> points;

    public Area ()
    {
        p = new ArrayList<Point>();
    }
}

离散距离实用程序类:

class DiscreteDistance
{

    public static int distance (Point a, Point b)
    {
        return Math.sqrt(Math.pow(b.x - a.x,2), Math.pow(b.y - a.y,2))
    }

    public static int distance (Point a, Area area)
    {
        ArrayList<Point> cir = circumference(area);
        int d = null;

        for (Point b : cir)
        {
            if (d == null || distance(a,b) < d)
            {
                d = distance(a,b);
            }
        }

        return d;
    }

    ArrayList<Point> circumference (Area area)
    {
        int minX = 0;
        int minY = 0;
        int maxX = 0;
        int maxY = 0;

        for (Point p : area.points)
        {
            if (p.x < minX) minX = p.x;
            if (p.x > maxX) maxX = p.x;
            if (p.y < minY) minY = p.y;
            if (p.y > maxY) maxY = p.y;
        }

        int w = maxX - minX +1;
        int h = maxY - minY +1;

        Point[][] graph = new Point[w][h];

        for (Point p : area.points)
        {
            graph[p.x - minX][p.y - minY] = p;
        }

        ArrayList<Point> cir = new ArrayList<Point>();

        for (int i=0; i<w; i++)
        {
            for (int j=0; j<h; j++)
            {
                if ((i > 0 && graph[i-1][j] == null)
                  || (i < (w-1) && graph[i+1][j] == null)
                  || (j > 0 && graph[i][j-1] == null)
                  || (i < (h-1) && graph[i][j+1] == null))
                {
                    cir.add(graph[i][j]);
                }
            }
        }

        return cir;
    }    
}

【讨论】:

  • 哈立德,谢谢。我想我需要在 Area ArrayList 中有边缘,对吧?该区域应该是一个多边形?
  • 首先,感谢我为我的解决方案投票。基本上,我正在对距离(点,周长)进行线性最小化。如果你想找到两个区域之间的最小距离,你只需要对距离进行线性最小化(circumferenceA,circumB)
  • 那么Area类中的“ArrayList points”包含什么?
  • 这应该很明显,一个区域是由点组成的..查看您在帖子中提供的数字,上面写着“区域(像素集)”,基本上这里我们使用点代替像素
  • 如果您要在该区域中的每个点上循环至少 3 次,为什么不只计算一次到每个点的距离并记录最小值呢?与您正在做的事情相比,取平方根和平方的成本并不高。
【解决方案2】:

我们必须假设您知道或可以轻松找到该区域内的至少一个像素地址 (x0,y0)。最快的解决方案肯定是从该像素沿直线搜索,例如在加 x 方向上。或者,由于您有一个边界框,请选择指向最近边界的指南针点并朝该方向移动。

当你找到区域的边缘时,首先沿着边界搜索深度。 对于具有自相交和/或孔洞的一般多边形,这必须是一个完整且精心实施的 DFS,维护一组已访问的顶点。 只有当多边形很简单时,才足以记住只有最后访问的像素,以避免重复搜索已经搜索的内容。

在 DFS 期间,计算每个边界像素的距离平方 p1 并跟踪最小值。

请注意,如果您真的很想提高性能,这个距离的平方可以逐步更新,以用加法代替乘法。 IE。如果您知道d2=(x2-x1)^2+(y2-y1)^2,然后将x2 增加1 以围绕边界进行下一步,则新的平方距离为

((x2+1) - x1)^2 + (y2-y1)^2 = d2 + 2(x2 - x1) + 1

因此您可以将d2 更新为d2 += 2(x2 - x1) + 1。乘以 2 当然只是左移,所以这很便宜。每个方向的步骤都有类似的非常便宜的更新。

【讨论】:

    【解决方案3】:

    一种方法可能是通过首先计算该区域的三角剖分来设置近似解;之后,只需检查三角形的角。这种方法可能是有益的,特别是如果在您计划的许多评估中,外部点发生变化但形状本身没有变化。

    【讨论】:

      【解决方案4】:

      您可以找到该区域矩形的中心,并使用两点之间的三角形来找到角度,然后使用函数 f(x) = mx + b 进行像素游走,直到找到该区域的像素计算距离,然后旋转角度,直到找到最短路径。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-28
        • 2012-02-01
        • 2013-10-06
        • 1970-01-01
        • 2013-12-12
        • 1970-01-01
        • 2012-01-09
        • 2012-11-02
        相关资源
        最近更新 更多