我正在开发一个使用Voronoi创建地图的Java程序。我正在使用一个生成Voronoi的Java库,它非常快(http://sourceforge.net/projects/simplevoronoi/)。
我面临的问题是,我必须扫描每个Voronoi边缘,以了解边缘左侧和右侧的点,以创建包含每个点的多边形。它是包含每个Voronoi边缘的类:
public class GraphEdge
{
public double x1, y1, x2, y2;
public int site1;
public int site2;
}
坐标x1, y1, x2, y2
是边缘起点和终点坐标,site1
和site2
是边缘左侧和右侧点的索引。因此,要创建包含每个点的多边形,我会这样做:
for(int n = 0; n < xValues.length; ++n){
polygonsList.add(new GPolygon());
for(GraphEdge mGraphEdge : edgesList){
if( (xValues[mGraphEdge.site1] == xValues[n] || xValues[mGraphEdge.site2] == xValues[n])
&& (yValues[mGraphEdge.site1] == yValues[n] || yValues[mGraphEdge.site2] == yValues[n]) ){
polygonsList.get(n).addPoint((int)mGraphEdge.x1, (int)mGraphEdge.y1);
polygonsList.get(n).addPoint((int)mGraphEdge.x2, (int)mGraphEdge.y2);
}
}
}
xValues
和yValues
是我生成Voronoi图的点坐标,GPolygon
是我创建的从java.awt.Polygon
延伸的Polygon类。这些是我测量的时间:
正如您所看到的,与其他时间相比,时间真的很重要,我如何才能加快for循环?还有其他选择吗?非常感谢你提前。
答案 0 :(得分:5)
因此,如下简单的事情应该很好地解决它:
Map<Integer, List<GraphEdge>> edgesByPolygon = new HashMap<>();
for (GraphEdge edge : edgesList) {
List<GraphEdge> list = edgesByPolygon.get(edge.site1);
if (list == null) {
list = new ArrayList<>();
edgesByPolygon.put(edge.site1, list);
}
list.add(edge);
list = edgesByPolygon.get(edge.site2);
if (list == null) {
list = new ArrayList<>();
edgesByPolygon.put(edge.site2, list);
}
list.add(edge);
}
for (List<GraphEdge> list : edgesByPolygon.valueSet()) {
// order the edges by adjacency and construct the polygon instance
// (a naive algorithm will do, as the average number of edges is small)
}
这是一个近O(n)算法(而不是你的O(n ^ 2)),我估计这应该快约1000倍。
答案 1 :(得分:1)
实际上,在for循环期间将新GPolygon存储到变量中,而不是直接将其添加到列表中:
for(int n = 0; n < xValues.length; ++n){
GPolygon polygon = new GPolygon();
polygonsList.add(polygon);
for(GraphEdge mGraphEdge : edgesList){
if( (xValues[mGraphEdge.site1] == xValues[n] || xValues[mGraphEdge.site2] == xValues[n])
&& (yValues[mGraphEdge.site1] == yValues[n] || yValues[mGraphEdge.site2] == yValues[n]) ){
polygon.addPoint((int)mGraphEdge.x1, (int)mGraphEdge.y1);
polygon.addPoint((int)mGraphEdge.x2, (int)mGraphEdge.y2);
}
}
}
这样你根本不必打电话给。
答案 2 :(得分:1)
行:
polygonsList.get(n).addPoint((int)mGraphEdge.x1, (int)mGraphEdge.y1);
polygonsList.get(n).addPoint
可以通过只调用一次polygonsList.get(n)来简化。
如果你有很多边缘,你可以加速100到1000倍,
将您的边缘存储在基于quadtree的存储桶中,可以是线四叉树或边界框四叉树,我更喜欢这样。然后对于每个搜索点,四叉树为您提供附近的16条边(假设桶大小= 16)。您不必迭代所有10.0000,仅用于16。