我在 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
抱怨它的输入,并且那里是为了将一个scombine
数组变成一个 s 。实际上,仍然对它的输入不满意,所以我不得不编写一个如下的 hacky 函数来抖动重复的顶点,这会修改传递给之前的:Polygon
MultiPolygon
unkink
geom
unkink
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)