- 对多边形进行三角剖分。
- 如果您选择的 origin vertex 不是多边形顶点(即它是多边形内的一个点),请将该点作为 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.getB(), 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;
}