【问题标题】:How to fix geojson to satisfy the needs of a mongodb 2dsphere index如何修复geojson以满足mongodb 2dsphere索引的需求
【发布时间】:2018-09-27 14:17:08
【问题描述】:

我在 mongo 集合中有大约 400K 文档,所有文档的几何形状均为 type:Polygon。由于几何显然具有自相交,因此无法将2dsphere 索引添加到当前的数据中。

过去我们有一个 hacky 解决方法,即在 mongoose 保存钩子上计算几何的边界框,然后索引它而不是几何本身,但我们希望简化事情并只使用实际的几何。

到目前为止,我已经尝试使用 turf 如下(这是一个名为 fix 的函数的主体):

let geom = turf.polygon(geometry.coordinates);
geom = turf.simplify(geom, { tolerance: 1e-7 }); 
geom = turf.cleanCoords(geom); 
geom = turf.unkinkPolygon(geom);
geom = turf.combine(geom);
return geom.features[0].geometry;

最重要的功能是unkinkPolygons,我希望它完全符合我的要求,即使几何图形足够好以便被索引。 simplify 可能没有帮助,但我添加它是为了更好的衡量标准。 clean 在那里是因为 unkink 抱怨它的输入,combine 在那里将 Polygons 的数组转换为单个 MultiPolygon。实际上,unkink 仍然对它的输入不满意,所以我不得不编写一个如下的 hacky 函数来抖动重复的顶点,这会在传递给 unkink 之前修改 geom

function jitterDups(geom) {
  let coords = geom.geometry.coordinates;
  let points = new Set();
  for (let ii = 0; ii < coords.length; ii++) {
    // last coords is allowed to match first, not sure if it must match.
    let endsMatch = coords[ii][0].join(",") === coords[ii][coords[ii].length - 1].join(",");

    for (let jj = 0; jj < coords[ii].length - (endsMatch ? 1 : 0); jj++) {
      let str = coords[ii][jj].join(",");

      while (points.has(str)) {
        coords[ii][jj][0] += 1e-8; // if you make this too small it doesn't do the job
        if (jj === 0 && endsMatch) {
          coords[ii][coords[ii].length - 1][0] = coords[ii][jj][0];
        }
        str = coords[ii][jj].join(",");
      }
      points.add(str);
    }
  }
}

但是,即使所有的 mongo 仍然抱怨。

这里是一些示例原始Polygon 输入:

{ type: "Polygon", coordinates: [ [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027535925691804, 51.5122814221859 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027638484531731, 51.5122996934574 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027672409315982, 51.5123868001613 ], [ -0.027667905522642, 51.5123866344944 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.02764931654289, 51.512375566682 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.027542009179339, 51.5122867222457 ] ], [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ], [ -0.027542009179339, 51.5122867222457 ] ] ] }

通过上述修复管道后的相同数据:

{ type: "MultiPolygon", coordinates: [ [ [ [ -0.027560309178214, 51.5123001412876 ], [ -0.02754202882236209, 51.51228674396312 ], [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.02754202884162257, 51.51228674398443 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ] ] ], [ [ [ -0.02754202884162257, 51.51228674398443 ], [ -0.02754202882236209, 51.51228674396312 ], [ -0.027541999179339, 51.5122867222457 ], [ -0.02754202884162257, 51.51228674398443 ] ] ] ] }

这里是索引创建时抛出的相关错误:

Edges 0 and 9 cross.
Edge locations in degrees: [-0.0275603, 51.5123001]-[-0.0275420, 51.5122867] and [-0.0275420, 51.5122867]-[-0.0275579, 51.5122984]
"code" : 16755,
"codeName" : "Location16755"

我的问题是:turf 中是否存在错误,或者它在保持 mongo 快乐方面没有做我需要的事情?还有关于“修复”方面2dshpere 索引需要什么的文档吗?另外,是否有人对我可以使用哪些其他工具来修复数据有建议,例如mapshaper 或 PostGIS 的 ST_MakeValid

请注意,一旦现有数据得到修复,我还需要一个动态修复新数据的解决方案(理想情况下与节点配合得很好)。

Mongo 版本:3.4.14(或任何更高版本的 3.x)

【问题讨论】:

  • MongoDB 非常严格地遵循 GeoJSON RFC (tools.ietf.org/html/rfc7946),因此如果您的形状符合 RFC,它们应该被 MongoDB 接受。您的收藏中的多边形是否有可能出现不同的变形,并且该工具仅修复了部分而非全部变形?您是否看到该工具的任何输出未被 MongoDB 接受但随后被接受?
  • @KevinAdistambha - 是的,我想我正在解决一些问题,但我正在寻找一个可以解决所有问题的工具。
  • @dan-man 你找到解决这个问题的方法了吗?

标签: mongodb postgis geojson turfjs mapshaper


【解决方案1】:

这里的问题不是多边形与自身相交,而是多边形中有一个(小)洞,由 4 个点组成,与外部共享一个点。所以这个洞“接触”了外部,而不是与之相交,但这是不允许的。 您可以使用具有微小值的 Shapely 缓冲区来修复此类情况,例如:

shp = shapely.geometry.shape({ "type": "Polygon", "coordinates": [ [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027535925691804, 51.5122814221859 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027638484531731, 51.5122996934574 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027672409315982, 51.5123868001613 ], [ -0.027667905522642, 51.5123866344944 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.02764931654289, 51.512375566682 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.027542009179339, 51.5122867222457 ] ], [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ], [ -0.027542009179339, 51.5122867222457 ] ] ] })
shp = shp.buffer(1e-12, resolution=0)
geojson = shapely.geometry.mapping(shp)

【讨论】:

  • 谢谢你的建议,今天晚些时候我会试试这个
  • 发布后我才注意到您不在 Python 域中,所以我希望这会有所帮助...
猜你喜欢
  • 2013-06-09
  • 1970-01-01
  • 2021-07-24
  • 2013-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-06
  • 1970-01-01
相关资源
最近更新 更多