【发布时间】: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