问题描述
给定一个简单的(非相交的)多边形,例如平面图(房间之间的门缺失,以便给出 1 个简单的不间断边界)。如何找到从 (x,y) 点(多边形的边界内或边界上)可到达的多边形内的所有区域?理想情况下,我希望从中返回一个多边形,然后可以将其覆盖以显示所有可到达的区域。
我已经考虑了 A* 搜索类型的方法,我将搜索最短路径迭代位于多边形周长(作为目标)上的所有点,然后沿着最短路径折线在设置的距离限制处绘制新点以给出新的多边形外壳。
我也考虑过将波传播作为一种方法。
我想知道我是否在这里遗漏了一些明显的库/方法明智的东西,以及是否有人对我如何实现这一目标有任何其他想法。
给定一个这样的多边形:
我正在创建一个多边形,显示内部空间(不包括内门),如下所示:
这是我的问题所指的部分。我想从多边形边界上的给定点找到多边形内所有可到达的点(以红色显示为新多边形),距离该点的设定最大旅行距离(下面用红色方块捐赠)如下:>
解决方法
- 对多边形进行三角剖分。
- 如果您选择的原点不是多边形顶点(即它是多边形内的一个点),请将此点作为steiner点包含在三角剖分中。立>
- 根据三角剖分的顶点和约束边(其中图边权重是三角剖分边的长度)构建一个无向加权图。
- 受约束的边是不位于多边形之外的边。
- 计算从您的原点到图中所有其他顶点的最短路径(使用 Dijkstra 或 Bellman-Ford 算法)。从原点到顶点的路径距离是该顶点的 Z 值。
- 更新/创建另一个三角剖分网格,使用与之前计算的 Z 值相同的顶点。
- 通过在三角形内/三角形之间进行插值计算每个像素的距离值(基于每个三角形顶点的 Z 值进行插值)。这可以通过使用 barycentric coordinates 轻松完成。坐标的插值输出为您提供从原点位置到该坐标的距离。
对于下面的插图,我使用了 TinFour Java 库中的 NaturalNeighborInterpolator。它通过对三角剖分进行运算来简化插值步骤——我只是在每个像素坐标处调用插值器,最后用原始多边形屏蔽输出(因为它有效地计算了多边形的凸包)。
说明性代码
图形和 Dijkstra 实现使用 JGraphT 库。
IncrementalTin tin = new IncrementalTin();
tin.add(listOfPolygonVertices); // triangulates upon insertion
Graph<Vertex,IQuadEdge> graph = new DefaultUndirectedWeightedGraph<>(IQuadEdge.class);
tin.edges().forEach(e -> {
if (e.isConstrainedRegionInterior() || e.isConstrainedRegionBorder()) {
graph.addVertex(e.getA());
graph.addVertex(e.getB());
graph.addEdge(e.getA(),e.getB(),e);
graph.setEdgeWeight(e.getA(),e.getLength());
}
});
DijkstraShortestPath<Vertex,IQuadEdge> shortestPaths = new DijkstraShortestPath<>(graph);
Vertex originVertex = tin.getNavigator().getNearestVertex(originX,originY);
var paths = shortestPaths.getPaths(originVertex);
IncrementalTin distanceMesh = new IncrementalTin();
for (Vertex v : graph.vertexSet()) {
var d = paths.getWeight(v);
distanceMesh.add(new Vertex(v.x,v.y,d)); // add vertices with Z to new tin
}
IInterpolatorOverTin interpolator = new NaturalNeighborInterpolator(distanceMesh);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
double z = interpolator.interpolate(x,y,null);
if (!Double.isNaN(z)) {
pixels[y * width + x] = someColour;
}
}
}
更新:距离边界顶点
如果您只想要距离边界线,则可以放弃第 5 步。而是根据所需距离计算(如果适用)每个三角形的 isoline。如果等值线与三角形相交(如下图所示),它将与三角形的两条边相交——为每个这样的三角形在每对相交点之间绘制一条线段,为您提供距离边界。
为三角剖分中每个受约束三角形的每条边调用一个方法(如下所示)。如果距离等值线与三角形相交,您将得到该三角形的两个交点;否则没有。
/**
* Compute isoline vertex (if applicable) for a triangle side given by two vertices
*/
Vertex isoVertex(Vertex a,Vertex b,double d) {
Vertex min,max;
if (a.getZ() > b.getZ()) {
max = a;
min = b;
} else {
max = b;
min = a;
}
if (d > min.getZ() && d < max.getZ()) {
double diff = max.getZ() - min.getZ();
double numerator = d - min.getZ();
double fract = numerator / diff;
double xDiff = max.getX() - min.getX();
double yDiff = max.getY() - min.getY();
return new Vertex(min.getX() + fract * xDiff,min.getY() + fract * yDiff);
}
return null;
}