从一个点到一个区域的最小距离

时间:2013-03-21 13:26:50

标签: algorithm graphics computational-geometry

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

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

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

Peroblem

感谢。

4 个答案:

答案 0 :(得分:4)

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

提示:我用来查找区域周长的方法很简单,就像你怎么知道这片土地的海滩?回答:海滩从一侧被海洋覆盖,所以在我的图表矩阵中,NULL参考是Sea,Points是Land!

分类点:

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

答案 1 :(得分:1)

我们必须假设您知道或者可以在区域内轻松找到至少一个像素地址(x0,y0)。最快的解决方案肯定是从这个像素中直线搜索,比如在加号x方向上搜索。或者,因为你有一个边界框,所以选择指向最近边界的罗盘点并朝那个方向前进。

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

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

请注意,如果您真的按性能表示,则可以逐步更新此距离平方以使用加法替换乘法。即如果您知道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当然只是一个左移,所以这很便宜。每个方向的步骤都有类似的非常便宜的更新。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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