42 votos

Cómo arreglar un no-noded intersección problema en PostGIS?

Estoy usando un PL/R función y PostGIS para generar polígonos de voronoi en torno a un conjunto de puntos. La función que estoy utilizando es definido aquí. Al utilizar esta función en un determinado conjunto de datos me sale 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

Del examen de esta parte de la 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

Esto es lo que el problema de los enumerados arriba se ve como:

enter image description here

Al principio pensé que este mensaje podría ser causado por la existencia de idénticos puntos, y trató de resolver esta usando el st_translate() función, se utiliza de la siguiente manera:

ST_Translate(geom, random()*20, random()*20) as geom 

Esto no soluciona el problema, pero mi preocupación es que ahora estoy traduciendo todos los puntos hasta ~20m en la dirección x/y. Yo también puedo decir lo que una traducción adecuada cantidad que se necesita. Por ejemplo, en este conjunto de datos a través de ensayo y error 20m * random number está bien, pero ¿cómo puedo saber si esto tiene que ser más grande?

Basado en la imagen de arriba, creo que el problema es que el punto es la intersección con la línea mientras que el algoritmo está tratando de cortarse el punto con un polígono. No estoy seguro de lo que debe hacer para asegurarse de que el punto está dentro de un polígono, en lugar de intersección 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 a través de esta pregunta anterior, ¿Qué es un "no-noded intersección"? para tratar de entender mejor este problema, y agradecería cualquier consejo sobre la mejor manera de resolverlo.

96voto

lewis Puntos 1178

Tal vez un seg error está siendo creado por un muy agudo de ángulo que es ilegible y desde la lógica de no superar el ángulo que nunca lee el siguiente nodo en la secuencia, generando el error. Entiendo que a partir de la gráfica, de todos modos.

39voto

MBCook Puntos 8316

En mi experiencia este problema es casi siempre causada por:

  1. Alta precisión en sus coordenadas (43.231499999999996), combinado con
  2. Líneas que son casi coincidentes, pero no idénticos

El "empujón" enfoque de la ST_Buffer soluciones le permite salirse con la #2, pero cualquier cosa que usted puede hacer para resolver estas causas subyacentes, como el ajuste de su geometría a una 1e-6 cuadrícula, va a hacer su vida más fácil. El búfer de geometrías son por lo general bien por intermedio de los cálculos como área de solapamiento, pero usted querrá tener cuidado acerca de la retención de ellos porque pueden hacer que su cerca-pero-no-muy empeorar los problemas en el largo plazo.

PostgreSQL es la excepción-capacidad de manejo le permite escribir funciones de contenedor para manejar estos casos especiales, el almacenamiento en búfer sólo cuando sea necesario. He aquí un ejemplo para ST_Intersects; puedo utilizar una función similar para ST_Difference. Tendrás que decidir si el almacenamiento en búfer y el posible retorno de vacío de un polígono son aceptables en su situación.

CREATE OR REPLACE FUNCTION safe_isect(geom_a geometry, geom_b geometry)
RETURNS geometry AS
$$
BEGIN
    RETURN ST_Intersection(geom_a, geom_b);
    EXCEPTION
        WHEN OTHERS THEN
            BEGIN
                RETURN ST_Intersection(ST_Buffer(geom_a, 0.0000001), ST_Buffer(geom_b, 0.0000001));
                EXCEPTION
                    WHEN OTHERS THEN
                        RETURN ST_GeomFromText('POLYGON EMPTY');
    END;
END
$$
LANGUAGE 'plpgsql' STABLE STRICT;

Otra ventaja de este enfoque es que usted puede identificar las geometrías que realmente están causando sus problemas; sólo tiene que añadir algunos RAISE NOTICE declaraciones en la EXCEPTION bloque a la salida de WKT o algo que le ayudará a localizar el problema.

17voto

djq Puntos 7670

A través de una gran cantidad de ensayo y error que finalmente me di cuenta de que el non-noded intersection el resultado de una auto-intersección problema. He encontrado un hilo que sugirió el uso de ST_buffer(geom, 0) puede ser utilizado para corregir el problema (aunque lo hace mucho más lento en general). Luego traté de uso ST_MakeValid() , y cuando se aplica directamente a la geometría antes de cualquier otra función. Esto parece solucionar el problema con firmeza.

ipoint <- pg.spi.exec(
        sprintf(
            "SELECT 
                    %3$s AS id, 
                    st_intersection(ST_MakeValid(''SRID=''||st_srid(%2$s)||'';%4$s''::text), ST_MakeValid(''%5$s'', 0)) AS polygon 
            FROM %1$s 
            WHERE 
                ST_Intersects(ST_MakeValid(%2$s::text),ST_MakeValid(''SRID=''||st_srid(%2$s)||'';%4$s''));",
            arg1,
            arg2,
            arg3,
            curpoly,
            buffer_set$ewkb[1]
        )
    )

He marcó esto como la respuesta parece ser que el único enfoque que soluciona mi problema.

16voto

jczaplew Puntos 312

Me encontré con este mismo problema (Postgres 9.1.4, PostGIS 2.1.1), y lo único que trabajó para mí fue envoltura de la geometría con un muy pequeño búfer.

SELECT ST_Intersection(
    (SELECT geom FROM table1), ST_Union(ST_Buffer(geom, 0.0000001))
) FROM table2

ST_MakeValid no trabajo para mí, ni la combinación de ST_Node y ST_Dump. El buffer no parece ser el resultado de cualquier degradación en el rendimiento, pero si lo hacía más pequeña he recibido aún no noded intersección de error.

Feo, pero funciona.

Actualización:

El ST_Buffer estrategia parece funcionar bien, pero me encontré con un problema en el que se dio errores al casting de la geometría a la geografía. Por ejemplo, si un punto se encuentra inicialmente a -90.0, y es amortiguado por el 0.0000001, es ahora en -90.0000001, que no es válida la geografía.

Esto significaba que a pesar de ST_IsValid(geom) fue t, ST_Area(geom::geography) devuelto NaN para muchas de las funciones.

Para evitar la no-noded intersección problema, mientras que el mantenimiento de la validez de la geografía, que terminó con ST_SnapToGrid como

SELECT ST_Union(ST_MakeValid(ST_SnapToGrid(geom, 0.0001))) AS geom, common_id
    FROM table
    GROUP BY common_id;

6voto

DylanJ Puntos 951

En postgis ST_Node debe romper una serie de líneas en las intersecciones, lo que debe resolver la no-noded intersección problema. Envolver esta en ST_Dump genera el compuesto de matriz de las líneas rotas.

Ligeramente relacionadas, hay una impresionante presentación (PostGIS Poder) por ahí que define claramente este tipo de problemas y de soluciones.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X