【问题标题】:Compute Voronoï diagram on a large dataset of very close points在非常接近点的大型数据集上计算 Voronoï 图
【发布时间】:2016-03-30 14:18:22
【问题描述】:

我有一个大的地理点数据集(大约 22000 个点,但我将来可能会更多),我需要计算他们的 Voronoï 图。我首先将我的点从(lat,lng) 投影到(x,y)(使用 Leaflet 中的 latLngToLayerPoint()),然后根据Javascript implementation of Fortune's algorithm 计算图表。我恢复了图表的每个单元格,或者更准确地说是va 和vb,分别是:

"一个 Voronoi.Vertex 对象,具有定义起点的 x 和 y 属性 这个 Voronoi.Edge 的点(相对于左侧的 Voronoi 站点) 对象。”

和

"一个 Voronoi.Vertex 对象,带有一个定义结束的 x 和一个 y 属性 这个 Voronoi.Edge 的点(相对于左侧的 Voronoi 站点) 对象。”

(参见文档)

最后,我将这些点投影回来以使用传单显示图表。我知道,为了计算图表,每个点都必须是唯一的,所以我在计算图表之前去掉了重复项。但问题是,我最终得到了一个非常糟糕的结果(无节点的交叉点,复杂的多边形):

特写

我的图表上有洞,我不知道为什么。这些点是房屋地址,因此其中一些,即使它们不相等,也确实(真的)很接近。而且我想知道问题是否不是来自投影(如果(lat1,lng1) 和(lat2,lng2) 几乎相等,那么(x1,y1) 和(x2,y2) 是否相等?)。我强烈怀疑这就是问题所在,但我不知道如何解决(建立阈值?)

编辑:我确切地说我在投影后删除了重复项,所以这与投影的精度无关,而是更多关于如果两点相距一像素会发生什么?

【问题讨论】:

  • 您是在对 lat/long 值还是 x/y 值进行重复数据删除?至于基于“足够接近”的重复数据删除,您必须找到适合您的值。您提到您正在使用地址,所以在我看来,如果两个点之间的距离在 10 英尺以内,我会认为它们是重复的。
  • 我正在删除 x/y 值以避免“足够接近”

标签: javascript leaflet gis computational-geometry voronoi


【解决方案1】:

所以我找到了我的问题的解决方案,我发布它以防有人需要使用 Leaflet 和 Turf 在地图上计算 Voronoï 图,并且在实施 Fortune 算法时遇到了麻烦(直到 turf-voronoi 工作)。 Other sources of how to compute a Voronoï diagram on map can be found (but using d3)(我认为d3也使用了Fortune算法的这个Javascript实现)

问题不是由数据集的大小或点的接近程度引起的,而是由我如何恢复单元格引起的。

因此,您首先需要将您的点从(lat,lng) 投影到(x,y)(使用latLngToLayerPoint()),计算图表:voronoi.compute(sites,bbox),其中站点是您的点,看起来像这样[ {x: 200, y: 200}, {x: 50, y: 250}, {x: 400, y: 100} /* , ... */ ](请注意,您的网站需要唯一),如果您希望当前缩放的屏幕框架成为您的 bbox,请使用:

var xl = 0, 
    xr = $(document).width(),
    yt = 0,
    yb = $(document).height();

一旦你计算了图表,只需恢复单元格(小心,如​​果你想要正确的多边形,你需要逆时针排序的边缘(或顺时针排序,但你要排序),谢天谢地算法提供了一半给定Voronoï.Vertex 的边缘逆时针排序)。要恢复每个单元格的顶点,您可以使用getStartpoint() 或getEndpoint() 而不会忘记将它们从(x,y) 投影回(lat,lng)(使用layerPointToLatLng())

diagram.cells.forEach(function (c) {
    var edges=[];

    var size = c.halfedges.length;
    for (var i = 0; i < size; i++) {

        var pt = c.halfedges[i].getEndpoint();
        edges.push(map.layerPointToLatLng(L.point(pt.x,pt.y)));

    };

    voronoi_cells.push(L.polygon(edges));
});

最后,你必须使用FeatureCollection 来显示图表:

【讨论】:

    【解决方案2】:

    我强烈建议您不要自己实现 Voronoi 镶嵌算法,而是使用 https://github.com/Turfjs/turf-voronoi。

    【讨论】:

    • 这是我最初的计划,但它似乎还没有准备好使用(并且构建失败)
    猜你喜欢
    • 2019-03-07
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 2017-02-07
    • 1970-01-01
    • 2020-04-19
    • 2013-07-08
    相关资源
    最近更新 更多