10 votos

Identificación de polígonos "largos y estrechos" con PostGIS

Tengo un conjunto de polígonos que representan grandes áreas, digamos barrios de la ciudad. Quiero identificar las grandes áreas que se superponen entre ellos.

Pero hay un problema: a veces estos polígonos se superponen a lo largo de sus perímetros (porque fueron dibujados con poca precisión). Esto generará solapamientos largos y estrechos que no me importan.

Pero otras veces habrá grandes superposiciones de polígonos robustos, es decir, grandes áreas donde el polígono de un barrio se superpone a otro. Quiero seleccionar sólo estos.

Ver la imagen de abajo de sólo las superposiciones. Imagina que quiero seleccionar sólo el polígono azul de la esquina inferior derecha.

overlap

Podría mirar las áreas, pero a veces los estrechos son tan largos que acaban teniendo áreas tan grandes como el polígono azul. He tratado de hacer una relación de área / perímetro, pero eso también ha dado resultados mixtos.

Incluso he intentado usar ST_MinimumClearance Pero a veces las áreas grandes tendrán una parte estrecha unida a ella, o dos vértices muy cercanos.

¿Alguna idea de otros enfoques?


Al final lo que mejor me funcionó fue usar un buffer negativo, como sugieren @Cyril y @FGreg más abajo.

Usé algo como:

ST_Area(ST_Buffer(geom, -10)) as neg_buffer_area

En mi caso, las unidades eran metros, por lo que 10 m de búfer negativo.

Para los polígonos estrechos, esta área devolvía cero (además, la geometría estaría vacía). Entonces utilicé esta columna para filtrar los polígonos estrechos.

4 votos

Ciertamente, la relación área/perímetro podría utilizarse para ello.

0 votos

Es difícil decir dónde están los polígonos distintos de la imagen, pero haciendo algo como esto gis.stackexchange.com/a/265233/64838 ¿podría funcionar? Calcular el cuadro delimitador mínimo girado y descartar los que tengan una anchura o altura pequeñas.

0 votos

También puedes probar a utilizar un tampón negativo como se describe aquí: ¿Cómo puedo identificar polígonos muy finos en mi archivo shape?

9voto

xenny Puntos 670

En lugar de área/perímetro, es mejor utilizar el área dividida por el cuadrado del perímetro (o su inverso).

También se denomina "índice de forma". El cuadrado del perímetro dividido por el área tiene un valor mínimo de 4*Pi() (en el caso de un disco, que es la geometría 2D más compacta), por lo que se puede normalizar por 4*Pi() para una fácil interpretación (los valores normalizados cercanos a 1 significan entonces que se tienen objetos muy compactos y los cuadrados tienen un valor de aproximadamente 1,27).

EDIT: Un umbral en el área sería útil para eliminar los artefactos muy pequeños, que podrían ser compactos. Entonces el índice de forma mostraría un mejor contraste. EDIT: además de esta respuesta, el uso de ST_Snap podría ayudarle a resolver el problema antes de que se produzca.

0 votos

Gracias. Pero no estoy seguro de cómo podría ayudar ST_Snap en este caso... Si lo he entendido bien, estás sugiriendo algo como (o.overlap_perimeter^2 / o.overlap_area) / (4 * Pi()) as overlap_ratio ? Esto me está dando peores resultados que el área/perímetro.

0 votos

Ahora usando o.overlap_perimeter / (4 * sqrt(o.overlap_area)) as overlap_ratio según este documento, pero aún así los resultados son peores (aunque es difícil cuantificar lo que quiero decir con peor) isprs-ann-photogramm-remote-sens-spatial-inf-sci.net/I-7/135/ , página 183.

2 votos

Gracias por esto, nunca había oído hablar del "índice de forma". Siempre había pensado que el uso de un rectángulo delimitador mínimo era la mejor manera de responder a este tipo de preguntas. He encontrado esto, repository.asu.edu/attachments/111230/content/ Lo cual es interesante.

5voto

Chris Puntos 128

Una opción sería utilizar la relación entre el área del polígono y la línea más larga que se puede trazar utilizando sus extremos. Identificación de polígonos largos y estrechos.

select * from polygons where ST_Length(ST_LongestLine(geom, geom)) < ST_Area(geom) * 4

Esto funciona bastante bien para los polígonos de la astilla. Puedes ajustar el ratio (con el que multiplicas el área) para adaptarlo a tus necesidades y a la proyección.

5voto

Cyril Puntos 141

Yo intentaría crear un buffer negativo, si se come los polígonos finos, entonces es bueno, si no se come el polígono, entonces es mío... :-)

ejecutar este script, habiendo fijado previamente 2/3 de la anchura de los polígonos lineales ...

create table name_table as
SELECT ST_Buffer(
(ST_Dump(
(ST_Union(
ST_Buffer(
(geom),-0.0001))))).geom,
0.0001)) as geom from source_table

OS :-)...

0 votos

Al final tu sugerencia es lo que mejor me ha funcionado. Terminé usando algo como ST_Area(ST_Buffer(geom, -10)) El -10 es -10 metros en mi caso. Si algo devolviera 0 de esa expresión entonces podría filtrarlo.

1voto

aalaap Puntos 145

Esto me parece un caso de uso perfecto para Extensión de la topología PostGIS . El parámetro de tolerancia de la topología determinará hasta qué punto permite que los vértices se ajusten a otros polígonos existentes, para hacer frente a la baja precisión de los datos de origen y limpiarlos.

En resumen, la estrategia es:

1. Habilitar la extensión de la topología

CREATE EXTENSION postgis_topology;

2. Cree una nueva topología vacía

SELECT topology.CreateTopology('neighborhoods_topo', 4326, 1e-7);

El tercer parámetro es la tolerancia, en las unidades del SRI; elíjalo sabiamente. Lo ideal es un SIR cuya unidad sea el metro. Si la unidad del CRS no es el metro, como en el caso de WGS 84 aka 4326, utilice ST_Transform para reproyectar sus polígonos.

3. Añadir una columna TopoGeometry a la tabla de polígonos

SELECT topology.AddTopoGeometryColumn('neighborhoods_topo', 'public', 'neighborhoods', 'topogeom', 'POLYGON');

Esto devuelve un nuevo layer_id . Guárdalo, lo necesitarás más adelante. Será la capa 1 si se parte de cero, y se incrementa en cada nueva llamada.

4. Añadir todos los polígonos a la topología

UPDATE public.neighborhoods
SET topogeom = topology.toTopoGeom(geom, 'neighborhoods_topo', 1, 1e-7);

Esto puede llevar varias horas para un conjunto de datos grande, sea paciente. 1 es el layer_id devuelto anteriormente.

5. Encontrar rostros que aparezcan en varios barrios

Encuentra todas las caras de la topología que están presentes en 2 o más topogeometrías. Dejaré la consulta como ejercicio. Lo más fácil es probablemente con el GetTopoGeomElements y, a continuación, agrupar por ID de cara, y mirar las que tienen un recuento de 2 o más. Alternativamente, usted podría crear una nueva tabla con la geometría limpiada de la columna topogeom, sólo cast a la geometría estándar topogeom::geometry y repite lo que ya tienes ahora, pero ahora con un conjunto de datos limpio sin las superposiciones de astillas.

0voto

Doug Lerner Puntos 106

Parece que esto podría coincidir con su caso de uso: Eliminar los polígonos seleccionados

Combina los polígonos seleccionados de la capa de entrada con ciertos polígonos adyacentes borrando su límite común. El polígono adyacente puede ser el de mayor o menor área o el que comparta el mayor límite común con el polígono a eliminar.

Eliminar se utiliza normalmente para deshacerse de los polígonos astillados, es decir, los polígonos diminutos que son el resultado de procesos de intersección de polígonos en los que los límites de las entradas son similares pero no idénticos.

Parece que quieres probar la opción "Límite común más grande".

0 votos

Ahora me doy cuenta de que estabas preguntando por soluciones postgis y no por soluciones qgis. Mis disculpas, no creo que postgis tenga una función equivalente pero lo dejaré para la posteridad.

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