Estoy usando una PL/R
función y PostGIS
para generar polígonos voronoi alrededor de un conjunto de puntos. La función que estoy usando se define aquí . Cuando uso esta función en un conjunto de datos en particular, aparece el siguiente mensaje de error:
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
Al examinar esta parte del mensaje de error:
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
Así es como se ve el problema mencionado anteriormente:
Inicialmente pensé que este mensaje podría ser causado por la existencia de puntos idénticos, e intenté resolverlo usando la st_translate()
función, que se usa de la siguiente manera:
ST_Translate(geom, random()*20, random()*20) as geom
Esto soluciona el problema, pero mi preocupación es que ahora estoy traduciendo todos los puntos hasta ~ 20m en la dirección x / y. Tampoco puedo decir qué cantidad de traducción se necesita. Por ejemplo, en este conjunto de datos a través de prueba y error a 20m * random number
está bien, pero ¿cómo puedo saber si esto necesita ser más grande?
Basado en la imagen de arriba, creo que el problema es que el punto se cruza con la línea mientras el algoritmo intenta intersecar el punto con un polígono. No estoy seguro de lo que debería hacer para asegurarme de que el punto esté dentro de un polígono, en lugar de cruzarse con una línea. El error está ocurriendo en esta línea:
"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'');"
He leído esta pregunta anterior, ¿Qué es una "intersección sin nudos"? para tratar de comprender mejor este problema, y agradecería cualquier consejo sobre la mejor manera de resolverlo.
WHERE ST_IsValid(p.geom)
para filtrar los puntos inicialmente.Respuestas:
En mi experiencia, este problema casi siempre es causado por:
El enfoque de "empujar" de las
ST_Buffer
soluciones le permite salirse con la # 2, pero cualquier cosa que pueda hacer para resolver estas causas subyacentes, como ajustar su geometría a una cuadrícula 1e-6, le facilitará la vida. Las geometrías amortiguadas generalmente son adecuadas para cálculos intermedios como el área de superposición, pero querrá tener cuidado al retenerlas porque pueden empeorar sus problemas cercanos pero no del todo a largo plazo.La capacidad de manejo de excepciones de PostgreSQL le permite escribir funciones de contenedor para manejar estos casos especiales, almacenando en búfer solo cuando sea necesario. Aquí hay un ejemplo para
ST_Intersection
; Yo uso una función similar paraST_Difference
. Tendrá que decidir si el almacenamiento en búfer y el posible retorno de un polígono vacío son aceptables en su situación.Otro beneficio con este enfoque es que puede identificar las geometrías que realmente están causando sus problemas; simplemente agregue algunas
RAISE NOTICE
declaraciones en elEXCEPTION
bloque para generar WKT o algo más que lo ayudará a rastrear el problema.fuente
A través de muchas pruebas y errores, finalmente me di cuenta de que era el
non-noded intersection
resultado de un problema de auto-intersección. Encontré un hilo que sugirió queST_buffer(geom, 0)
se puede usar para solucionar el problema (aunque en general lo hace mucho más lento). Luego intenté usarST_MakeValid()
y cuando se aplica directamente a la geometría antes que cualquier otra función. Esto parece solucionar el problema de manera robusta.He marcado esto como la respuesta, ya que parece ser el único enfoque que soluciona mi problema.
fuente
Me encontré con este mismo problema (Postgres 9.1.4, PostGIS 2.1.1), y lo único que funcionó para mí fue envolver la geometría con un búfer muy pequeño.
ST_MakeValid
no funcionó para mí, ni la combinación deST_Node
yST_Dump
. El búfer no pareció provocar ninguna degradación en el rendimiento, pero si lo reduje aún recibo un error de intersección sin nudos.Feo, pero funciona.
Actualizar:
La estrategia ST_Buffer parece funcionar bien, pero me encontré con un problema en el que producía errores al transmitir la geometría a la geografía. Por ejemplo, si un punto está originalmente en -90.0, y está protegido por 0.0000001, ahora está en -90.0000001, que es una geografía no válida.
Esto significaba que, a pesar de que
ST_IsValid(geom)
erat
,ST_Area(geom::geography)
regresóNaN
por muchas características.Para evitar el problema de intersección sin nudos, mientras mantenía una geografía válida, terminé usando
ST_SnapToGrid
asífuente
En postgis, ST_Node debería romper una serie de líneas en las intersecciones, lo que debería resolver el problema de intersección sin nudos. Al envolver esto en ST_Dump, se genera la matriz compuesta de las líneas discontinuas .
Ligeramente relacionado, hay una presentación impresionante PostGIS: Consejos para usuarios avanzados que describe claramente este tipo de problemas y soluciones.
fuente
ST_Node
yST_Dump
? Me imagino que necesitaría usarlos cerca de esta parte de la función, pero no estoy seguro:st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'')
enst_node
aquí, ¿puedo usarlo antesst_intersection
?En mi experiencia, resolví mi
non-noded intersection
error usando la función St_SnapToGrid que resolvió el problema de tener una alta precisión en las coordenadas del vértice de los polígonos.fuente