jeudi 17 mai 2007
Connaître les points contenus dans un MULTILINESTRING
Par david techer, jeudi 17 mai 2007 à 04:01 :: PostGIS et PostgreSQL
J'ai posté un message suite à question posée par un utilisateur de postgis dans la mailing-list à http://postgis.refractions.net/pipermail/postgis-users/2007-May/015680.html. Je n'ai pas essayé de la coder en C bien que celà soit possible mais en PL/PGSQL celà reste quand même aussi faisable. La facilité vient surtout du fait du type e géométrie employé : MULTILINESTRING. Pour cette dernière, PostGIS dispose de fonctionnalités intéressantes pour écrire une fonction en PL/PGSQL: pointn(), etc...
LA FONCTION
Il faut commencer par écrire un type en PostgreSQL qui aura la structure suivante
CREATE TYPE PointSetFromLinetype AS (idx_geom int4,idx_point int4,point_x double precision, point_y double precision);avec
- idx_geom: l'indice de la nième LINESTRING;
- idx_point: qui sera le nième point dans la LINESTRING en cours;
- point_x, point_y: les coordonnées X et Y du point.
Quant à la fonction, on peut par exemple imaginer la fonction suivante
CREATE OR REPLACE FUNCTION points_from_linetype(geometry) RETURNS SETOF PointSetFromLinetype AS $$
DECLARE
geom ALIAS FOR $1;
Idx_Geom int4 :=1;
Num_Geom int4 :=0;
Nb_Points_In_Ring int4;
Idx_Point int4 := 1;
j PointSetFromLinetype;
BEGIN
/*
Get the number of points
*/
SELECT INTO Num_Geom NumGeometries(multi(geom))+1 ;
/* Parsing the Geometry */
WHILE Idx_Geom < Num_Geom
LOOP
SELECT INTO Nb_Points_In_Ring npoints(GeometryN(multi(geom),Idx_Geom))+1;
WHILE Idx_Point < Nb_Points_In_Ring
LOOP
SELECT INTO j Idx_Geom,Idx_Point,x(pointn(GeometryN(multi(geom),Idx_Geom),Idx_Point)),y(pointn(GeometryN(multi(geom),Idx_Geom),Idx_Point));
RETURN NEXT j;
Idx_Point := Idx_Point + 1;
END LOOP; -- End - FOR 1
Idx_Point := 1;
Idx_Geom := Idx_Geom + 1;
END LOOP; -- End - while
END;
$$ LANGUAGE plpgsql stable;
EXEMPLES D'UTILISATION
Pour le cas d'une simple LINESTRING, on aura
testgis=# SELECT * FROM points_from_linetype('LINESTRING(2 3,3 2,5 4)'::geometry);
idx_geom | idx_point | point_x | point_y
----------+-----------+---------+---------
1 | 1 | 2 | 3
1 | 2 | 3 | 2
1 | 3 | 5 | 4
(3 lignes)
Dans le cas d'un MULTILINESTRING, ce sera
testgis=# SELECT * FROM points_from_linetype('MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))'::geometry);
idx_geom | idx_point | point_x | point_y
----------+-----------+---------+---------
1 | 1 | 0 | 0
1 | 2 | 1 | 1
1 | 3 | 1 | 2
2 | 1 | 2 | 3
2 | 2 | 3 | 2
2 | 3 | 5 | 4
(6 lignes)