Estou usando uma PL/R
função e PostGIS
para gerar polígonos voronoi em torno de um conjunto de pontos. A função que estou usando é definida aqui . Quando uso essa função em um conjunto de dados específico, recebo a seguinte mensagem de erro:
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
Ao examinar esta parte da mensagem de erro:
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
É assim que o problema listado acima se parece:
Inicialmente, pensei que essa mensagem pudesse ser causada pela existência de pontos idênticos e tentei resolver isso usando a st_translate()
função, usada da seguinte maneira:
ST_Translate(geom, random()*20, random()*20) as geom
Isso resolve o problema, mas minha preocupação é que agora estou traduzindo todos os pontos até ~ 20m na direção x / y. Também não sei dizer qual é a quantidade necessária de tradução. Por exemplo, neste conjunto de dados por tentativa e erro a 20m * random number
está ok, mas como posso saber se isso precisa ser maior?
Com base na imagem acima, acho que o problema é que o ponto está cruzando com a linha enquanto o algoritmo está tentando cruzar o ponto com um polígono. Não tenho certeza do que devo fazer para garantir que o ponto esteja dentro de um polígono, em vez de cruzar com uma linha. O erro está ocorrendo nesta linha:
"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'');"
Eu li essa pergunta anterior: o que é um "cruzamento sem aceno"? para tentar entender melhor esse problema e gostaria de receber conselhos sobre a melhor maneira de resolvê-lo.
WHERE ST_IsValid(p.geom)
para filtrar os pontos inicialmente.Respostas:
Na minha experiência, esse problema quase sempre é causado por:
A abordagem "cutucada" das
ST_Buffer
soluções permite que você se safe da segunda posição, mas tudo o que você pode fazer para resolver essas causas subjacentes, como encaixar sua geometria em uma grade 1e-6, facilitará sua vida. As geometrias com buffer geralmente são boas para cálculos intermediários, como a área de sobreposição, mas você deve ter cuidado ao retê-las, pois elas podem piorar seus problemas próximos, mas não muito, a longo prazo.O recurso de tratamento de exceções do PostgreSQL permite escrever funções de invólucro para lidar com esses casos especiais, armazenando em buffer somente quando necessário. Aqui está um exemplo para
ST_Intersection
; Eu uso uma função semelhante paraST_Difference
. Você precisará decidir se o buffer e o retorno potencial de um polígono vazio são aceitáveis em sua situação.Outro benefício dessa abordagem é que você pode identificar as geometrias que realmente estão causando seus problemas; basta adicionar algumas
RAISE NOTICE
instruções noEXCEPTION
bloco para gerar o WKT ou outra coisa que o ajudará a rastrear o problema.fonte
Através de muitas tentativas e erros, finalmente percebi que o
non-noded intersection
resultado era de um problema de auto-interseção. Eu encontrei um tópico que sugeria o usoST_buffer(geom, 0)
pode ser usado para corrigir o problema (embora o torne muito mais lento no geral). Eu tentei usarST_MakeValid()
e, quando aplicado diretamente à geometria, antes de qualquer outra função. Isso parece resolver o problema de maneira robusta.Marquei isso como a resposta, pois parece ser a única abordagem que resolve meu problema.
fonte
Corri para o mesmo problema (Postgres 9.1.4, PostGIS 2.1.1), e a única coisa que funcionou para mim foi envolver a geometria com um buffer muito pequeno.
ST_MakeValid
não funcionou para mim, nem a combinação deST_Node
eST_Dump
. O buffer parece não resultar em nenhuma degradação no desempenho, mas se eu o diminuísse ainda recebia um erro de interseção sem aceno.Feio, mas funciona.
Atualizar:
A estratégia ST_Buffer parece funcionar bem, mas encontrei um problema em que ela produzia erros ao converter a geometria para a geografia. Por exemplo, se um ponto está originalmente em -90.0 e é armazenado em buffer por 0.0000001, agora está em -90.0000001, que é uma geografia inválida.
Isso significava que, embora tenha
ST_IsValid(geom)
sidot
,ST_Area(geom::geography)
retornouNaN
para muitos recursos.Para evitar o problema de interseção sem aceno, mantendo a geografia válida, acabei usando
ST_SnapToGrid
assimfonte
No postgis, o ST_Node deve quebrar uma série de linhas nos cruzamentos, o que deve resolver o problema de cruzamento sem aceno. Quebrar isso em ST_Dump gera a matriz composta das linhas quebradas.
Ligeiramente relacionado, há uma apresentação impressionante PostGIS: Dicas para Usuários Avançados, que descreve claramente esse tipo de problemas e soluções.
fonte
ST_Node
eST_Dump
? Imagino que seria necessário para usá-los perto esta parte da função, mas não estou certo:st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'')
emst_node
aqui - posso usá-lo antesst_intersection
?Na minha experiência, resolvi meu
non-noded intersection
erro usando a função St_SnapToGrid , que resolveu o problema de ter uma alta precisão nas coordenadas do vértice dos polígonos.fonte