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)