Blog del Máster
en Tecnologías de la Información Geográfica y Ciencia de Datos
Espaciales

analisis_postgis

Análisis espacial con PostGIS

En este post vamos a mostrar cómo utilizar varias funciones espaciales de PostGIS para obtener la línea de costa de una provincia mediterránea.  Los datos de partida constarán de  una única tabla espacial llamada ‘municipios’ . Esta tabla, con todos los municipios de la provincia, contiene los  siguientes atributos: código municipal, nombre del municipio  y geometría de cada municipio.

Datos iniciales

Fig 1. Datos de partida, municipios de Girona.

Para obtener la línea de costa vamos a utilizar, entre otras, dos funciones espaciales de postgis:  ST_Line_Substring y ST_Line_Locate_Point.

ST_Line_Substring devuelve un subconjunto de una linestring previamente conocida. Para ello requiere, además de la geometría inicial (linestring),  de una posición de inicio y de una posición final. Tanto la posición inicial como la posición final representan un valor real comprendido entre 0 y 1. De este modo podemos indicar que el subconjunto deseado va desde el 33% (0.33)  hasta el 66% (0.66) de la geometría inicial.


ST_Line_Locate_Point por su parte devuelve la posición que ocupa un punto concreto dentro de una geometría. El valor devuelto es un valor numérico y está comprendido entre cero (inicio) y uno (final)

Dada la geometría LinestringA, y dado el puntoA=(2,2) obtenemos el siguiente resultado.

Puntos de inicio y final de la línea de costa.

La línea de costa para el municipio de Girona alcanza, de norte a sur, desde el municipio de Portbou (codigo_municipio=17138)  hasta el municipio de Blanes (codigo_municipio=17023).

En la  imagen anterior podemos ver dónde empieza (punto A) y dónde termina (punto B) la línea de costa. Por lo tanto obteniendo esos puntos podremos aplicar la función ST_Line_Locate_Point para determinar en qué posición, respecto a la longitud total de la provincia, empieza y termina la línea de costa. Después solo faltará combinar el resultado de la función ST_Line_Locate_Point con ST_Line_Substring.

El comando SQL final tendrá el siguiente aspecto.

select st_line_substring(
geometria_perimetro_provincia ,
st_line_locate_point ( geometria_perimetro_provincia , puntoA ) ,
st_line_locate_point ( geometria_perimetro_provincia , puntoB )
)
)
from municipios

Obteniendo los puntos A y B.

Punto A.

La intersección del municipio con el perímetro de su bounding box nos devolverá una sola geometría de tipo MULTIPOINT que contendrá los 4 puntos que aparecen en  la siguiente imagen.  Con la función ST_Dump podemos descomponer esa geometría en 4 geometrías de tipo POINT.

El comando SQL quedaría como:

select (ST_Dump(
    ST_Intersection(st_boundary(the_geom), st_boundary(envelope(the_geom)) )
    )).geom as puntoA
from town_geom where code in (17138)

Finalmente podemos utilizar la consulta anterior y ordenarlos descendientemente por la componente ‘X’ y limitando el resultado a un solo punto.

select * from
(
select (ST_Dump(
        ST_Intersection(st_boundary(the_geom), st_boundary(envelope(the_geom)) )
        )).geom as puntoA
    from town_geom where code in (17138)
) as foo
order by x(puntoA) desc
limit 1

Punto B.

Podemos hacer ahora lo mismo para el punto B. La diferencia está tanto en el municipio (Blanes, 17023) como en la ordenación del punto. En este caso debemos ordenar por la componente  ‘Y’ de manera ascendente.

select * from
(
select (ST_Dump(
        ST_Intersection(st_boundary(the_geom), st_boundary(envelope(the_geom)) )
        )).geom as puntoB
    from town_geom where code in (17023)
) as foo
order by y(puntoB) asc
limit 1

Volviendo al comando SQL general…

En primer lugar vamos a recordar el esquema general del comando SQL que hemos visto al principio:

select st_line_substring(
    geometria_perimetro_provincia,
    st_line_locate_point(geometria_perimetro_provincia, puntoA),
    st_line_locate_point(geometria_perimetro_provincia, puntoB)
    )
)
from municipios

Por lo tanto, llegados a este punto, solo nos falta obtener el límite (linestring) de la geometría de la provincia. Para ello debemos unir las geometrías de los municipios con la función ST_Union y aplicar la función ST_Boundary:
st_boundary(st_union(the_geom))

Juntando todas las partes tenemos.

select asbinary( st_line_substring(
     st_boundary(st_union(the_geom))
    ,
    st_line_locate_point(
        st_boundary(st_union(the_geom))
        ,
        (
            select * from
            (
                select (ST_Dump(
                    ST_Intersection(st_boundary(the_geom), st_boundary(envelope(the_geom)) )
                    )).geom as puntoA
                from municipios where codigo_municipio in (17138)
            ) as foo
            order by x(puntoA) desc
            limit 1       
        )
    ),
    st_line_locate_point(
        st_boundary(st_union(the_geom))
        ,
        (
            select * from
            (
                select (ST_Dump(
                    ST_Intersection(st_boundary(the_geom), st_boundary(envelope(the_geom)) )
                    )).geom as puntoB
                from municipios where codigo_municipio in (17023)
            ) as foo
            order by y(puntoB) asc
            limit 1       
        )
    )
     )
)
from municipios

Obteniendo finalmente el siguiente resultado:

Toni Hernández
Ambientólogo y diplomado en informática. Trabajo como desarrollador de aplicaciones web map en el Servicio de SIG y Teledetección (SIGTE) de la Universitat de Girona. Me interesa la capacidad espacial de las bases de datos y el desarrollo de aplicaciones web map tanto del lado del cliente como del servidor.


Suscríbete a nuestra newsletter