Me enfrento a un desafío con PostGIS que parece que no puedo entender. Sé que puedo resolver esto usando un lenguaje de programación (y ese es mi plan de respaldo), pero realmente me gusta resolver esto en PostGIS. Intenté buscar, pero no pude encontrar ninguna respuesta que coincida con mi problema, esto podría deberse a que no estoy seguro de mis términos de búsqueda, así que discúlpeme y apúnteme en la dirección correcta, de hecho, hay una respuesta.
Mi problema es este:
- Tengo una mesa con polígonos mixtos / polígonos múltiples
- Cada polígono (múltiple) tiene un atributo que lo clasifica (prioridad)
- Cada polígono también tiene un valor que me gustaría saber
- Tengo un área de búsqueda (polígono)
- Para mi área de consulta, quiero encontrar el área cubierta por cada valor de polígono
Ejemplo:
Digamos que tengo los tres polígonos representados en rojo, verde e índigo aquí:
Y que el rectángulo azul más pequeño es mi polígono de consulta
Además, los atributos son
geom | rank | value
-------|------|----
red | 3 | 0.1
green | 1 | 0.2
indigo | 2 | 0.2
Lo que quiero es seleccionar estas geometrías, de modo que el rango más alto (verde) llene todo el área que pueda (es decir, la intersección entre mi consulta geom y esa geom), luego el siguiente más alto (índigo) llena la intersección entre la consulta geom y el geom MENOS el ya cubierto) etc.
He encontrado esta pregunta: ¿ Usando ST_Difference para eliminar características superpuestas? pero no parece hacer lo que quiero.
¡Yo mismo puedo descubrir cómo calcular áreas y cosas así, así que una consulta que me da las tres geometrías como se muestra en la segunda imagen está bien!
Información adicional: - Esta no es una tabla grande (~ 2000 filas) - puede haber cero o múltiples superposiciones (no solo tres) - puede que no haya ningún polígono en mi área de consulta (o solo en partes de ella) - i ' m ejecutando postgis 2.3 en postgres 9.6.6
Mi solución alternativa es hacer una consulta como esta:
SELECT
ST_Intersection(geom, querygeom) as intersection, rank, value
FROM mytable
WHERE ST_Intersects(geom, querygeom)
ORDER by rank asc
Y luego iterativamente "corta" partes de las geometrías en el código. Pero, como dije, realmente me gustaría hacer esto en PostGIS
WITH RECURSIVE ...
Respuestas:
Creo que esto funciona.
Es una función de ventana, obteniendo la diferencia entre la intersección de cada intersección de geometrías con el cuadro de consulta y la unión de las geometrías anteriores.
La fusión es necesaria ya que la unión de las geometrías anteriores para la primera geometría es nula, lo que da un resultado nulo, en lugar de lo que se desea.
Sin embargo, no estoy seguro de cómo funciona. Pero dado que tanto ST_Union como ST_Intersection están marcados como inmutables, puede que no sea tan malo.
fuente
Un enfoque un poco diferente a esto. Hay una advertencia de que no sé cómo escalará el rendimiento, pero en una tabla indexada debería estar bien. Realiza casi lo mismo que la consulta de Nicklas (¿un poco más lenta?), Pero la medición en una muestra tan pequeña está cargada.
Se ve mucho más feo que la consulta de Nicklas, pero evita la recurrencia en la consulta.
fuente
Como balbuceé,
WITH RECURSIVE
agregaré una respuesta rápida y sucia al usarla.Esto funciona tan bien como la solución de @ NicklasAvén en tres polígonos, no se pudo probar cuando se amplió.
Tal como están las dos soluciones, esta tiene un pequeño beneficio sobre la otra: si, por ejemplo, el Polígono con rango = 2 está contenido por el de rango = 1 , los
...WHERE GeometryType = 'POLYGON'
filtros se eliminan mientras que de lo contrario habrá unGEOMETRYCOLLECTION EMPTY
(Cambié la geometría del Polígono respectivo en mi solución en consecuencia para dar un ejemplo; esto también es cierto para otros casos cuando no se encuentra una intersección con la diferencia). Sin embargo, esto se incluye fácilmente en las otras soluciones y puede que ni siquiera sea motivo de preocupación.fuente