7 votos

¿Cómo puedo ajustar las líneas en PostGIS?

Tengo unas cuantas líneas que juntas forman una línea larga. Los puntos de inicio y final de las líneas son iguales a su vecino directo, pero cuando se comprueba la distancia ST_Distance entre dos líneas cualquiera es como 1,0x10^-11.

Este parece ser el problema conocido con la codificación de flotantes. Son iguales pero no son lo mismo.

Sin embargo, cuando actualizo 2 líneas vecinas con sus coordenadas Astext existentes, se codifican por el mismo algoritmo y su distancia es 0. Pero entonces tienen una pequeña distancia con sus vecinos exteriores (que no se actualizan de esta manera).

Lo que quiero hacer es ajustar una línea a la izquierda y a la derecha con sus vecinos para que la ST_Distance con ambos vecinos sea 0. Creo que ST_Snap sólo mueve una geometría a otra geometría. Eso no es lo que quiero. Sólo quiero que el punto inicial y final de una línea se ajuste al vecino. El resto de la línea debe permanecer donde está.

¿Cómo lo hago?

Con la respuesta dada he arreglado los dos extremos de la línea conflictiva así:

update network set the_geom = ST_RemovePoint(the_geom, (select st_npoints(the_geom)-1 from network where gid=6909)) where gid=6909;
update network set the_geom = ST_AddPoint(the_geom, (select st_endpoint(the_geom) from network where gid=6123), (select st_npoints(the_geom) from network where gid=6909)) where gid=6909;
update network set the_geom = ST_RemovePoint(the_geom, 0) where gid=6055;
update network set the_geom = ST_AddPoint(the_geom, (select st_startpoint(the_geom) from network where gid=6909), 0) where gid=6055;

0 votos

Podría intentar extraer los puntos de inicio y final, ajustarlos y reemplazar los antiguos puntos de inicio y final con los datos que obtenga de st_snap

1 votos

Hay ST_AddPoint(línea, punto, índice), ST_RemovePoint(línea, índice) pero sólo puedes usar ST_ReplacePoint (línea,índice,punto) entonces necesitas ST_PointN(línea, índice) y ST_NumPoints(línea). Añade St_Snap dos veces y reemplaza tus viejos puntos finales con los nuevos

0 votos

Simplexia - He utilizado St_RemovePoint y ST_AddPoint como forma de reemplazar un vértice (ya que no pude encontrar el ST_ReplacePoint que mencionaste). Funcionó. Si actualizas tu comentario a una respuesta lo aceptaré como la respuesta que estaba buscando.

5voto

Michael Barker Puntos 8234

Puede utilizar ST_RemovePoint(línea, índice) y ST_AddPoint(línea, punto, índice). Primero, obtén el primer y último punto con ST_pointN(line, index) y ST_NumPoints(line), luego usa ST_Snap a esos puntos. A continuación, utilice los puntos devueltos para reemplazar los antiguos.

Estas funciones deberían estar en Postgis < 2.0 ST_ReplacePoint debería estar en Postgis 2.0

0voto

jbalk Puntos 581

Me doy cuenta de que esta es una pregunta antigua, pero acabo de aterrizar aquí y quiero compartir otra opción para limpiar las líneas con pequeños espacios entre ellas. Tuve el mismo problema que la pregunta original - Tuve multilíneas hechas de líneas que tenían espacios minúsculos entre ellos (menos de un cm). Esto me impedía fusionar estas multilíneas en cadenas de líneas para la referenciación lineal. La solución que se presenta a continuación elimina los huecos automáticamente.

Mi respuesta está sacada de este post Limpieza de redes de carreteras con PostGIS Topology

En primer lugar, añada la extensión de topología a su base de datos postgis. Puede crear una nueva base de datos o añadir la extensión a una base de datos existente.

CREATE DATABASE "roadsdb";
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
SET search_path = topology,public;

A continuación, cree la topología para su capa de líneas - roads_topo es el nombre del nuevo esquema de topología que se creará, 2154 es el código epsg para la referencia espacial:

SELECT topology.CreateTopology('roads_topo', 2154);
SELECT topology.AddTopoGeometryColumn('roads_topo', 'public', 'roads', 'topo_geom', 'LINESTRING');

Convierte la tabla de líneas en nodos y aristas, fijando la tolerancia en 1m. Ajuste el valor de 1,0 que aparece a continuación a la tolerancia que le resulte aceptable (los mayores huecos que necesite cerrar). Si no está utilizando un sistema de coordenadas proyectado, tendrá que convertir este valor a grados. En WGS84, 1 grado equivale a unos 100 km:

UPDATE roads SET topo_geom = topology.toTopoGeom(wkb_geometry, 'roads_topo', 1, 1.0);

Sólo si encuentra errores y toTopoGeom falla, puede que tenga que insertar los registros de uno en uno y saltarse los errores.

DO $$DECLARE r record;
BEGIN
  FOR r IN SELECT * FROM roads LOOP
    BEGIN
      UPDATE roads SET topo_geom = topology.toTopoGeom(wkb_geometry, 'roads_topo', 1, 1.0)
      WHERE ogc_fid = r.ogc_fid;
    EXCEPTION
      WHEN OTHERS THEN
        RAISE WARNING 'Loading of record % failed: %', r.ogc_fid, SQLERRM;
    END;
  END LOOP;
END$$;

A continuación, puede exportar una nueva capa "limpia" utilizando la nueva columna topo_geom:

CREATE TABLE roads_clean AS (
    SELECT ogc_fid, topo_geom::geometry
    FROM roads
);

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