Побудова полігону над досяжною площею


10

Зараз я працюю в галузі ізохронів та основоположних алгоритмів. Що зараз спричиняє проблеми - це не розрахунок, якщо сам ізохрон, а візуалізація результатів.
Результатом мого ізохронічного алгоритму є точки та ребра. Насправді у мене є робоче рішення, але для 3873 країв і 1529 вузлів, здається, це займе назавжди (приблизно 2,0 секунди на моєму ноутбуці Lenovo T440s, який містить процесор Core i7 2015 i досить швидкий SSD). Замість секунд я хочу щось більше, як msec :-).

Можливо, хтось може допомогти мені скоротити час обчислення, необхідний для побудови полігонів, які візуалізують доступні ділянки.

Але зачекайте ... спочатку все!
Ось візуалізація ребер, що я є результатом обчислення моєї ізохрони: Результат розрахунку ізохрону (існуючий кістяк рядків) Ці краї зберігаються в таблиці бази даних PostGIS і є простими рядками.

Те, що я хочу показати користувачеві, виглядає приблизно так: введіть тут опис зображення відзначте відключені ділянки на самому півдні та на самому сході зображення. Вони повинні бути намальовані як окремі області (тому ніяке об’єднання тут не дозволено :-))

На даний момент я використовую цей запит:

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_MakePolygon(ST_ExteriorRing(ST_GeometryN(segments, generate_series(1, ST_NumGeometries(segments))))) AS polygons FROM (
        SELECT ST_Union(ST_Buffer("GEOMETRY", 20, 'quad_segs=2')) AS segments FROM my_edges AS a
    ) AS b
) AS c

Я вже робив експерименти, а також читав багато документації, але краще рішення не можу знайти.
На мої очі, великою проблемою є використання ST_Union (як зазначено в документах, ця функція може бути повільною). Дуже цікава річ, що заміна його на ST_Collect, здається, уповільнює обчислення ST_Buffer, так що всезагальний наступний запит займе ще довше, хоча він не заповнює області між ребрами (він створює лише буфер навколо рядків ):

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_Buffer(ST_Collect(ST_LineMerge("GEOMETRY")), 20, 'quad_segs=2') AS polygons FROM my_edges AS a
) AS b

Це займає 3,8 секунди в моїй системі (тобто майже вдвічі більше часу). Мій перший висновок з цього маленького орієнтиру полягає в тому, що ST_Buffer стає несподівано повільним, коли мова йде про MultiLineStrings (навіть повільніше, ніж при створенні буферів для кожного рядка та об'єднанні буферів - що в моїх очах просто дивно)

Я також намагався використовувати альфа-форми (використовуючи реалізацію з pgRouting), але оскільки для встановлення не існує альфа-значення (і насправді я б не дійсно зараз, на яке значення встановити таке значення), я просто отримую один великий багатокутник ( тож я б втратив регіони на самому півдні та сході як окремі регіони, що не те, чого я хочу).
Також ST_Polygonize (що перше, що мені прийшло в голову) не дало корисних результатів, але, можливо, я щось тут пропустив ...

Чи є кращий спосіб створити область, показану на PostGIS? Можливо, також використовуючи код java (jts) або код javascript на стороні клієнта (jsts)? Насправді я міг би жити, втрачаючи деякі деталі до тих пір, поки ділянки, показані в моєму результаті, залишаються відокремленими, а обчислення стають (набагато) швидшими.


Чи можете ви не просто використовувати ST_Exteriorring (ST_Dump (ST_Union (ST_Buffer (geom, ....))). Можливо, вам доведеться протестувати рядки рядків, які іноді є результатом ST_Union після буфера, але це легко за допомогою ST_GeometryType (geom). Що стосується використання Java або jsts, ви можете, але це навряд чи буде швидше, враховуючи, що значна частина функцій Postgis (GEOS) - це спочатку C / C ++ порти JTS.
Джон Пауелл,

Ви маєте рацію, це працює, але насправді це не швидше (займає ~ 3,1 сек, тоді як використання GeometryN займає 2 секунди). Ось що я використав: SELECT ST_AsGeoJson (ST_Transform (ST_Exteriorring ((ST_Dump (ST_Union (ST_Buffer ("GEOMETRY", 20)))). Geom), 4326)) FROM my_edges;
Ніколаус Крисмер

@ john-barça: Ой .. Я замикаю quad_segs = 2 частину в ST_Buffer, коли намагаюся підходити ... із цією зміною запити рівні (обидва приблизно в 2 секунди). Однак це все ще дуже повільно (на моїх очах), чи є інший спосіб спробувати?
Ніколаус Крисмер

Цікава проблема .... Ви хочете поділитися деякими тестовими даними?
dbaston

Якщо це допоможе, я радий поділитися деякими даними. Усі речі, які я тут роблю, є відкритим кодом, тому це не повинно бути великою проблемою. Перше, що потрібно помітити: Веб-додаток для тестування розміщено за адресою dbis-isochrone.uibk.ac.at:8080/testing . Більше інформації про речі, над якими я працюю, можна знайти на dbis-isochrone.uibk.ac.at . У розділі "посилання" на веб-сайті є додаткові посилання (включаючи деякі дані тестування)
Nikolaus Krismer

Відповіді:


5

Відклавши серіалізацію GeoJSON, на моєму ноутбуці триває приблизно 6,3 секунди:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(geom, 20, 2)))).geom))
FROM bz_edges

Переглядаючи дані у OpenJUMP, я помітив зовсім небагато деталей у вуличних сегментах відносно бажаного рівня деталізації у висновку. Здається, навіть спрощення цих ліній на ходу може призвести до значного прискорення в PostGIS:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(ST_Simplify(geom, 10), 20, 2)))).geom))
FROM bz_edges

що зводить речі до 2,3 секунди. Я думав, що, можливо, я можу зробити краще, зберігаючи узагальнену геометрію в окремому стовпчику, а не обчислюючи його на льоту, але це фактично не надало додаткової користі.

Залежно від того, скільки коду ви готові написати, ви майже напевно можете зробити краще на Java, якщо нічого іншого, тому що ви можете скористатися декількома ядрами. (Для чого це варто, JTS виконує описану вище операцію за 2,8 секунди). Одним із підходів може бути розширення, CascadedPolygonUnionщоб деякі операції профспілки відбувалися паралельно. (оновлення - ось ParallelCascadedPolygonUnion )

Я помітив у зразках даних, що краї зберігаються із посиланнями на їхні початкові та кінцеві вузли, тобто у вас є попередньо побудований графік. Я підозрюю, що ви можете генерувати ці багатокутники набагато швидше, якщо працюєте з графіком, а не використовуєте генетичні операції з геометрії. Наприклад, я думаю, ви могли б зробити щось подібне:

  1. ідентифікувати пов'язані компоненти графіка
  2. для кожного підключеного компонента знайдіть вузол з мінімальною координатою X (гарантовано знаходиться на зовнішній стороні компонента)
  3. пройдіться по краях компонента, завжди повертаючи вліво (або вправо), коли це можливо. Це дасть вам зовнішнє кільце кожного компонента.
  4. полігонізувати зовнішнє кільце і буфер відповідним чином.

Дякую ... спрощення - це чудове і навіть "просте" вдосконалення. На моєму ноутбуці знадобився час, до 1,5сек. Це не те, де я хочу бути, але трохи краще.
Ніколаус Крисмер

Стосовно запропонованого рішення (пункти 1-4). Звучить також дуже просто і варто спробувати. Я подумав про щось подібне, але я застряг у точці1 (так дуже рано :-)). Як би можна було визначити підключені компоненти (єдине, про що я можу придумати, - це рекурсивний запит, який також може бути дуже повільним).
Ніколаус Крісмер

@NikolausKrismer Я використовую JGraphT і ткацький верстат для подібних завдань. Якщо ви замість цього пишете свої власні графічні методи (непогана ідея для найкращої продуктивності), то за допомогою глибокого пошуку ви знайдете компоненти. (Ви можете їх знайти в майбутньому PostGIS 2.2, ST_ClusterIntersectingале я думаю, ви хочете, щоб будь-яка обробка графіків відбувалася поза базою даних, тому це, мабуть, не корисно).
дбастон

це кілька чудових натяків. Я подивився на JGraphT, і це, безумовно, може допомогти вирішити мою проблему. Однак я також переглянув Postgis 2.2 та функцію ST_ClusterIntersecting -> для ідентифікації різних кластерів у вищенаведеному випадку потрібно приблизно 200-250 мсек. Це добре для мене (JGraphT, безумовно, може зробити краще). Тепер мені доводиться мати справу із створенням зовнішнього кільця (ST_ExteriorRing не вдається, оскільки ST_MakePolygon каже, що мої посилання не мають оболонки)
Nikolaus Krismer

Я бачу два ускладнення: (а) вам потрібно не тільки зовнішнє кільце, але і будь-які сегменти, що простягаються назовні від цього кільця, і (б) схоже, що ваші лінії насправді не перетинаються на деяких перехрестях. Вам потрібно буде виправити (б), якщо ви збираєтеся спробувати побудувати геометрію за результатами прогулянки по графіку.
dbaston
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.