Я использую PL/R
функцию и PostGIS
для генерации вороных многоугольников вокруг множества точек. Функция, которую я использую, определяется здесь . Когда я использую эту функцию для определенного набора данных, я получаю следующее сообщение об ошибке:
Error : ERROR: R interpreter expression evaluation error
DETAIL: Error in pg.spi.exec(sprintf("SELECT %3$s AS id,
st_intersection('SRID='||st_srid(%2$s)||';%4$s'::text,'%5$s')
AS polygon FROM %1$s WHERE st_intersects(%2$s::text,'SRID='||st_srid(%2$s)||';%4$s');",
:error in SQL statement : Error performing intersection: TopologyException: found non-noded
intersection between LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465
264611, 594406 286813) at 568465.05533706467 264610.82749605528
CONTEXT: In R support function pg.spi.exec In PL/R function r_voronoi
Из изучения этой части сообщения об ошибке:
Error performing intersection: TopologyException: found non-noded intersection between
LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465 264611, 594406 286813)
at 568465.05533706467 264610.82749605528
Вот как выглядит проблема, перечисленная выше:
Сначала я подумал, что это сообщение может быть вызвано наличием идентичных точек, и попытался решить эту проблему с помощью st_translate()
функции, используемой следующим образом:
ST_Translate(geom, random()*20, random()*20) as geom
Это решает проблему, но я обеспокоен тем, что теперь я перевожу все точки на расстояние до ~ 20 м в направлении x / y. Я также не могу сказать, какая сумма перевода нужна. Например, в этом наборе данных методом проб и ошибок все в 20m * random number
порядке, но как я могу определить, должно ли это быть больше?
Основываясь на изображении выше, я думаю, что проблема в том, что точка пересекается с линией, а алгоритм пытается пересечь точку с многоугольником. Я не уверен, что мне следует делать, чтобы точка находилась внутри многоугольника, а не пересекалась с линией. Ошибка происходит в этой строке:
"SELECT
%3$s AS id,
st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'') AS polygon
FROM
%1$s
WHERE
st_intersects(%2$s::text,''SRID=''||st_srid(%2$s)||'';%4$s'');"
Я прочитал этот предыдущий вопрос, что такое «пересечение без узлов»? чтобы попытаться лучше понять эту проблему, и был бы признателен за любые советы о том, как лучше всего решить ее.
WHERE ST_IsValid(p.geom)
для фильтрации точек изначально.Ответы:
По моему опыту, эта проблема почти всегда вызвана:
Подход «подталкивания»
ST_Buffer
решений позволяет вам избежать проблем с №2, но все, что вы можете сделать для устранения этих основных причин, например привязка вашей геометрии к сетке 1е-6, сделает вашу жизнь проще. Буферизованная геометрия обычно подходит для промежуточных вычислений, таких как область перекрытия, но вы должны быть осторожны с их сохранением, потому что они могут усугубить ваши проблемы, но не совсем, в долгосрочной перспективе.Возможность обработки исключений в PostgreSQL позволяет вам писать функции-оболочки для обработки этих особых случаев, буферизуя только при необходимости. Вот пример для
ST_Intersection
; Я использую аналогичную функцию дляST_Difference
. Вам нужно решить, приемлемы ли буферизация и потенциальный возврат пустого многоугольника в вашей ситуации.Еще одним преимуществом этого подхода является то, что вы можете точно определить геометрию, которая на самом деле вызывает ваши проблемы; просто добавьте несколько
RAISE NOTICE
операторов вEXCEPTION
блок для вывода WKT или что-то еще, что поможет вам отследить проблему.источник
Через много проб и ошибок я в конечном итоге понял, что это
non-noded intersection
стало результатом проблемы самопересечения. Я обнаружил, чтоST_buffer(geom, 0)
для решения проблемы можно использовать ветку, в которой предлагается использовать (хотя в целом это делает ее намного медленнее). Затем я попытался использоватьST_MakeValid()
и при применении непосредственно к геометрии перед любой другой функцией. Это, кажется, решает проблему надежно.Я пометил это как ответ, так как кажется, что это единственный подход, который решает мою проблему.
источник
Я столкнулся с этой же проблемой (Postgres 9.1.4, PostGIS 2.1.1), и единственное, что мне помогло, - это обернуть геометрию очень маленьким буфером.
ST_MakeValid
не работает для меня, а также не комбинацияST_Node
иST_Dump
. Похоже, что буфер не приводит к ухудшению производительности, но если я уменьшу его, я все равно получу ошибку пересечения без узлов.Уродливо, но это работает.
Обновить:
Стратегия ST_Buffer, кажется, работает хорошо, но я столкнулся с проблемой, когда она приводила к ошибкам при приведении геометрии к географии. Например, если точка изначально имеет значение -90,0 и буферизуется значением 0,0000001, теперь она имеет значение -90,0000001, что является недопустимой географией.
Это означало , что даже если
ST_IsValid(geom)
былоt
,ST_Area(geom::geography)
вернулисьNaN
для многих функций.Чтобы избежать проблемы пересечения без узлов, сохраняя правильную географию, я в конечном итоге использовал
ST_SnapToGrid
вот такисточник
В postgis ST_Node должен разбивать ряд линий на пересечениях, что должно решить проблему пересечения без узлов. Обтекание этого в ST_Dump генерирует составной массив из пунктирных линий.
Немного связано, есть отличная презентация PostGIS: Советы для опытных пользователей, в которой четко обозначены проблемы и решения такого рода.
источник
ST_Node
иST_Dump
? Я полагаю, что мне нужно использовать их рядом с этой частью функции, но я не уверен:st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'')
inst_node
здесь - могу ли я использовать его раньшеst_intersection
?Исходя из своего опыта, я решил свою
non-noded intersection
ошибку, используя функцию St_SnapToGrid, которая решила проблему с высокой точностью в координатах вершины многоугольников.источник