6 votos

Cálculo de la sinuosidad del camino en postgis

Sinuosidad es un concepto bastante sencillo. ¿Cómo puede esto se calcula en postgis dada una serie de linestrings que representan el camino?

13voto

El uso de la postgis documentación como punto de partida, he llegado a la siguiente solución, que es una función que toma un conjunto de linestrings, y un segmento de longitud y devuelve un conjunto de segmentos con asociados sinuosidad.

Soy relativamente nuevo en postgis, por lo que cualquier consejo o crítica de la función o método de bienvenida.

create type SinuosityRecord as (id int, the_geom geometry, actualdistance double precision, lineardistance double precision, sinuositypercentage double precision, sinuosityindex double precision);

/*
    GetSinuosityIndex
      sql: expects an sql statement with a linestring geometry ordered sequentially
        linestringfieldname: the name of the field in the sql statement that represents the linestring geometry
        segmentlength: the length of segments you wish to use to calculate the sinuosity
        returns: 
            id : an id representing each segment
            the_geom: a linestring geometry for each segment
            actualdistance:  the actual length of the segment
            lineardistance: the linear distance between the segment start and end
            sinuositypercentage: the percentage of actual length of the difference in actual length and lineardistance
            sinuosityindex: the ratio of actual length to linear distance
*/
create or replace function GetSinuosityIndex ( sql text, linestringfieldname text, segmentlength numeric ) returns setof sinuosityrecord as
$BODY$
declare
    r sinuosityrecord;                          -- used to return the result set
    totallength double precision;       -- used to store the total length of the path
    serieslength int;                               -- used to store the number of segments that will be needed
begin

    -- calculates the total length of the path
    execute $$
    SELECT
        ST_LENGTH(the_geom) as totallength
    FROM
    (
        SELECT 
            ST_LINEMERGE(s.$$ || linestringfieldname || $$) AS the_geom
        FROM
            (
                $$ || sql || $$
            ) s
    ) x $$
    INTO
        totallength;

    -- determine the total number of segements that will be required
    serieslength := ceiling(totallength / segmentlength) + 1;

    for r in execute $$
    SELECT
        x.n as id,
        x.the_geom, 
        ST_LENGTH(x.the_geom) AS actualdistance, 
        ST_DISTANCE(ST_STARTPOINT(x.the_geom), ST_ENDPOINT(x.the_geom)) AS lineardistance, 
        (ST_LENGTH(x.the_geom) - ST_DISTANCE(ST_STARTPOINT(x.the_geom), ST_ENDPOINT(x.the_geom))) / ST_LENGTH(x.the_geom) * 100::double precision AS sinuositypercentage, 
        ST_LENGTH(x.the_geom) / ST_DISTANCE(ST_STARTPOINT(x.the_geom), ST_ENDPOINT(x.the_geom)) AS sinuosityindex
    FROM 
        (
            SELECT 
                n.n, 
                ST_LINE_SUBSTRING
                (
                    t.the_geom,
                    ($$ || segmentlength || $$ * n.n::numeric)::double precision / t.length, 
                    CASE
                        WHEN ($$ || segmentlength || $$ * (n.n + 1)::numeric)::double precision < t.length THEN ($$ || segmentlength || $$ * (n.n + 1)::numeric)::double precision / t.length
                        ELSE 1::double precision
                    END
                ) AS the_geom
            FROM 
            (
                SELECT 
                    ST_LINEMERGE(s.$$ || linestringfieldname || $$) AS the_geom, 
                    ST_LENGTH(s.$$ || linestringfieldname || $$) AS length
                FROM
                (
                    $$ || sql || $$
                ) s
        ) t
        CROSS JOIN 
        generate_series(0, $$ || serieslength || $$) n(n)
    WHERE
    ((n.n::numeric * $$ || segmentlength || $$)::double precision / t.length) < 1::double precision) x $$

    loop
        return next r;
    end loop;

    return;

end
$BODY$
language plpgsql;

Un ejemplo de cómo esto puede ser denominado:

SELECT
    *
FROM
    GetSinuosityIndex 
    ( 
        'SELECT 
            st_makeline(network_table.point_field) AS the_geom
        FROM
            network_table
            '
        ,'the_geom'
        ,600 
    )

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