Разделить большой многоугольник на меньшие по условию

У меня есть большой полигон. Внутри него совокупность листовидных слоев (точек). Каждая точка имеет некоторое числовое свойство. Я хочу разделить большой многоугольник на более мелкие. Каждый меньший полигон должен содержать точки с ~равной (+-200 ok) суммой свойств точек. В левой части моей страницы примера я добавил изображение желаемого результата. Вот мой упрощенный пример с достаточным количеством кода и комментариев.

  1. Итак, мой первый шаг — найти начальную точку внутри большого полигона. Это должна быть точка рядом с краем полигона, например, самая северная точка.

    var nothernmostPoint= 0;
    var nothernmostLayer= 0;
    L.geoJSON(features, {
        pointToLayer: function (feature) {
            return L.circleMarker(feature.geometry.coordinates.reverse(), defaultPointStyle);
        },
        onEachFeature: function (feature, layer) {
            if (feature.geometry.coordinates[0] > nothernmostPoint) {
                nothernmostPoint = feature.geometry.coordinates[0];
                nothernmostLayer = feature;
            }
        }
    }).addTo(map);
    

  1. Второй шаг - найти следующую ближайшую точку (точки) к моей начальной точке.

     var geoJ = L.GeometryUtil.nClosestLayers(map, features, nothernmostLayer.geometry.coordinates, 5);
    

  1. Затем суммируйте их свойства. Если сумма меньше, чем необходимо, я перехожу к шагу 2 и повторяю, если сумма удовлетворяет условию, я рисую многоугольник с выбранными точками внутри него, нахожу ближайшую точку к моей последней точке и повторяю поиск точек для следующего меньшего многоугольника.

Моя текущая трудность состоит в том, чтобы найти ближайшую точку (точки) к моей начальной точке. Для этого я использую плагин GeometryUtil Leaflet. Красные точки — это точки, которые GeometryUtil нашли как ближайшие к моей начальной точке (зеленой). Это определенно не то, что я ожидал. Что я делаю не так? Может быть, мне следует использовать другой алгоритм и/или инструмент для этой задачи? Любые полезные предложения с благодарностью.

Если это поможет - все эти данные я храню в PostgreSQL с расширением PostGIS. Возможно, это можно сделать на уровне базы данных.


person dabajabaza    schedule 16.11.2017    source источник


Ответы (1)


Если ваш набор данных довольно мал, вы можете использовать метод грубой силы в PostGIS:

  • для каждой точки сгенерируйте N точек, представляющих «вес», используя select geom, generate_series(0, weight);
  • определитесь с количеством кластеров, которые вы хотите получить, примерно sum(weight)/desired_sum;
  • запустить кластеризацию K-средних для набора данных, https://postgis.net/docs/manual-2.3/ST_ClusterKMeans.html
  • нарисуйте многоугольник вокруг каждого кластера, используя ST_ConvexHull(ST_Collect(geom)).
person Darafei Praliaskouski    schedule 24.11.2017