Как исправить geojson, чтобы удовлетворить потребности в 2dsphere-индексе mongodb - PullRequest
0 голосов
/ 27 сентября 2018

У меня ~ 400К документов в коллекции монго, все с геометрией type:Polygon.Невозможно добавить индекс 2dsphere к данным в их текущем состоянии, поскольку геометрия, по-видимому, имеет самопересечения.

В прошлом у нас был хакерский обходной путь, который заключался в вычислении ограничивающей рамкигеометрию на крючке сохранения мангуста, а затем индексируйте ее, а не саму геометрию, но мы хотели бы упростить вещи и просто использовать фактическую геометрию.

До сих пор я пытался использовать 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 здесь, чтобы превратить массив Polygon s в один 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);
    }
  }
}

Однако даже после всего этого монго все еще жалуется.

Вот пример исходного ввода 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, или она не выполняет то, чтоМне нужно здесь с точки зрения поддержания Монго счастливым?Также есть ли документация о том, что именно нужно 2dshpere индексу в терминах «исправления»?Кроме того, есть ли у кого-нибудь предложения относительно того, какие другие инструменты я мог бы использовать для исправления данных, например, mapshaper или PostGIS ST_MakeValid .

Обратите внимание, что как только существующие данныеисправлено Мне также нужно решение для исправления новых данных на лету (в идеале то, что хорошо работает с узлом).

Mongo версия: 3.4.14 (или более поздняя 3.x)

1 Ответ

0 голосов
/ 02 октября 2018

Проблема здесь не в том, что многоугольник пересекает себя, а в том, что у вас есть (крошечная) дыра в многоугольнике, состоящая из 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)
...