Chapitre 7. PostGIS et les languages

Table des matières

7.1. avec du C -interface client de PostgreSQL -
7.1.1. Modifications des fichiers
7.1.2. Sortie et exécution
7.2. avec du PHP - un peu de SVG -

Dans ce chapitre, je vais tenter de mettre à profit les divers languages que j'ai peu testé sous Win32 avec PostGIS.

7.1. avec du C -interface client de PostgreSQL -

Les sources de PostGIS sont fournis avec un petit exemple de code en C que vous trouverez dans postgis-1.2.0\extra\wkb_reader. Nous allons ici adapter le code de certains fichiers à Windows pour pouvoir les utiliser pour un petit exemple que nous avons traiter dans le précédent chapitre.

7.1.1. Modifications des fichiers

Sous Win32 pour MinGW, on ne dispose pas du fichier d'en-tête endian.h, ouvrez donc le fichier wkbtest.h et au début du fichier remplacez la ligne

...
#include <endian.h>
...

par

...
#ifndef _ENDIAN_H_
#define _ENDIAN_H_
#include <sys/param.h>
#endif   /* _ENDIAN_H_ */
...

Ouvrez ensuite le fichier readwkb.c et remplacer son contenu par le suivant -que j'ai ici adapté à notre exemple -

#include "wkbtest.h"

/* example set-up

Nous allons ici utiliser le premier exemple de données rencontrées au cours du chapitre précédent

Ne pas oublier de définir convenablement les
variables d'environnement PGDATABASE et PGUSER avant d'utiliser ce programme

Also, change the "declare cursor" command so it returns the columns you want, and converts the geometry
into wkb.

*/


void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

void dump_bytes( char *a, int numb)
{
	int	t;

	for (t=0; t<numb; t++)
	{
		printf("	+ Byte #%i has value %i (%x)\n",t,a[t],a[t]);
	}
}


// need to find the OID coresponding to the GEOMETRY type
//
// select OID from pg_type where typname = 'wkb';

int	find_WKB_typeid(PGconn 	*conn)
{
	PGresult *dbresult;
	char		*num;

	if (PQstatus(conn) == CONNECTION_BAD) 
	{
		fprintf(stderr, "no connection to db\n"); 
		exit_nicely(conn); 
	} 

	dbresult = PQexec(conn, "select OID from pg_type where typname = 'bytea';");

	if (PQresultStatus(dbresult) != PGRES_TUPLES_OK) 
	{
		fprintf(stderr, "couldnt execute query to find oid of geometry type");
		exit_nicely(conn);	//command failed
	}
	
	if( PQntuples(dbresult) != 1)
	{
		fprintf(stderr, "query to find oid of geometry didnt return 1 row!");
		exit_nicely(conn);	
	}
	
	num =  PQgetvalue(dbresult, 0, 0);  // first row, first field

	PQclear(dbresult);

	return ( atoi(num) );
}


main()
{
    char       *pghost,
               *pgport,
               *pgoptions,
               *pgtty;
    char       *dbName;
    int         nFields;
    int         row,
                field;
    PGconn     *conn;
    PGresult   *res;
	int	junk,j;
	char	*field_name;
	int	field_type;
int	WKB_OID;
	  char		conn_string[255];

	bool		*bool_val;
	int		*int_val;
	float		*float_val;
	double	*double_val;
	char		*char_val;
	char		*wkb_val;
	char		*table_name = "test";
	char		query_str[1000];

	/* make a connection to the database */
	conn = PQconnectdb("");

	/*
	* check to see that the backend connection was successfully made
	*/
	if (PQstatus(conn) == CONNECTION_BAD)
	{
		fprintf(stderr, "%s", PQerrorMessage(conn));
		exit_nicely(conn);
	}

	//what is the geometry type's OID #?
	WKB_OID = find_WKB_typeid(conn);


	/* start a transaction block */
	res = PQexec(conn, "BEGIN");
	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		fprintf(stderr, "%s", PQerrorMessage(conn));
		PQclear(res);
		exit_nicely(conn);
	}

	/*
	 * should PQclear PGresult whenever it is no longer needed to avoid
	 * memory leaks
	 */
	PQclear(res);

	/*
	 * fetch rows from the pg_database, the system catalog of
	 * databases
	 */
	sprintf(query_str, "DECLARE mycursor BINARY CURSOR FOR select text(genre), astext(geom) as astext,geometrytype(geom) as type_geometrique,srid(geom),assvg(geom) as svg,text(area2d(geom)) as aire from %s", table_name);

	printf(query_str); printf("\n");

	res = PQexec(conn, query_str);

	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		fprintf(stderr, "DECLARE CURSOR command failed\n");
		fprintf(stderr, "%s", PQerrorMessage(conn));
		PQclear(res);
		exit_nicely(conn);
	}
	PQclear(res);

	res = PQexec(conn, "FETCH ALL in mycursor");
	if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		fprintf(stderr, "FETCH ALL command didn't return tuples properly\n");
		fprintf(stderr, "%s", PQerrorMessage(conn));
		PQclear(res);
		exit_nicely(conn);
	}
       j=0;
	for (row=0; row< PQntuples(res); row++)
	{
            j++;
		printf("------------------------------Ligne %i --------------------------\n",j);
		//not so efficient, but...
		for (field =0 ; field< PQnfields(res); field++)
		{
			field_type =PQftype(res,field);
			field_name = PQfname(res, field);

			//we just handle a few of the popular type since this is just an example

			if (field_type ==16)// bool
			{
				bool_val = (bool *) PQgetvalue(res, row, field);	
				if (*bool_val)
					 printf("%s: TRUE\n",field_name);
				else
					printf("%s: FALSE\n",field_name);
			}
			else if (field_type ==23 )//int4 (int)
			{
				int_val = (int *) PQgetvalue(res, row, field);
				printf("%s: %i\n",field_name,*int_val);	
			}
			else if (field_type ==700 )//float4 (float)
			{
				float_val = (float *) PQgetvalue(res, row, field);
				printf("%s: %g\n",field_name,*float_val);	
			}
			else if (field_type ==701 )//float8 (double)
			{
				double_val = (double *) PQgetvalue(res, row, field);
				printf("%s: %g\n",field_name,*double_val);	
			}
			else if ( (field_type ==1043 ) || (field_type==25) )//varchar 
			{
				char_val = (char *) PQgetvalue(res, row, field);
				printf("%s: %s\n",field_name,char_val);	
			}
			else if (field_type == WKB_OID ) //wkb
			{
				char_val = (char *) PQgetvalue(res, row, field);
				printf("%s: ", field_name);
				// skip 4 bytes varlena size 
				decode_wkb(char_val, &junk);
				printf("\n");
			}
			
		}
	}

    PQclear(res);

    /* close the cursor */
    res = PQexec(conn, "CLOSE mycursor");
    PQclear(res);

    /* commit the transaction */
    res = PQexec(conn, "COMMIT");
    PQclear(res);

    /* close the connection to the database and cleanup */
    PQfinish(conn);

    return 0;
}

On va aussi adapter le Makefile de ce répertoire à notre exemple en remplaçant

CFLAGS=-I`pg_config --includedir` -L`pg_config --libdir` -lpq

par

CFLAGS=-I`pg_config --includedir` `pg_config --libdir`/libpq.dll

7.1.2. Sortie et exécution

Depuis MinGW, il ne reste pluq qu'à préciser les variables de PostgreSQL nécessaire à l'utilisation du programme

export PGDATABASE=testgis
export PGUSER=$USERNAME
export PGHOST=localhost

où ici PGUSER correpond à votre utilisateur de MinGW. $USERNAME est une variable interne de MiNGW. Il ne reste plus qu'à faire[7]

make
readwkb.exe

qui nous renverra

DECLARE mycursor BINARY CURSOR FOR select text(genre), astext(geom) as astext,geometrytype(geom) as type_geometrique,srid(geom),assvg(geom) as svg,text(area2d(geom)) as aire from test
------------------------------Ligne 1 --------------------------
text: pieton 1
astext: POINT(10 70)
type_geometrique: POINT
srid: -1
svg: cx="10" cy="-70"
aire: 0
------------------------------Ligne 2 --------------------------
text: pieton 2
astext: POINT(30 30)
type_geometrique: POINT
srid: -1
svg: cx="30" cy="-30"
aire: 0
------------------------------Ligne 3 --------------------------
text: batiment 1
astext: POLYGON((10 10,40 20,35 8,12 4,10 10))
type_geometrique: POLYGON
srid: -1
svg: M 10 -10 40 -20 35 -8 12 -4 10 -10
aire: 228
------------------------------Ligne 4 --------------------------
text: batiment 2
astext: POLYGON((10 40,20 30,30 40,40 35,50 60,35 80,20 60,10 40))
type_geometrique: POLYGON
srid: -1
svg: M 10 -40 20 -30 30 -40 40 -35 50 -60 35 -80 20 -60 10 -40
aire: 1050
------------------------------Ligne 5 --------------------------
text: batiment 3
astext: POLYGON((10 95,20 95,20 135,10 135,10 95))
type_geometrique: POLYGON
srid: -1
svg: M 10 -95 20 -95 20 -135 10 -135 10 -95
aire: 400
------------------------------Ligne 6 --------------------------
text: pieton 3
astext: POINT(35 70)
type_geometrique: POINT
srid: -1
svg: cx="35" cy="-70"
aire: 0
------------------------------Ligne 7 --------------------------
text: pieton 4
astext: POINT(35 60)
type_geometrique: POINT
srid: -1
svg: cx="35" cy="-60"
aire: 0
------------------------------Ligne 8 --------------------------
text: bordure 1 route
astext: LINESTRING(1 85,50 85)
type_geometrique: LINESTRING
srid: -1
svg: M 1 -85 50 -85
aire: 0
------------------------------Ligne 9 --------------------------
text: bordure 2 route
astext: LINESTRING(1 92,50 92)
type_geometrique: LINESTRING
srid: -1
svg: M 1 -92 50 -92
aire: 0

Pour de plus amples informations sur l'interface client libpq en C de PostgreSQL, merci de vous reportez à la documentation de PostgreSQL. Consultez notamment

http://traduc.postgresqlfr.org/pgsql-8.2.1-fr/client-interfaces.html

7.2. avec du PHP - un peu de SVG -

Ici mon exemple est basé sur celui du chapitre 4 "Exemples de requêtes spatiales II"

On va commencer par définir la page index.php qui va contenir une liste déroulante de quelques requêtes spatiales qui seront afficher depuis une liste déroulante

<html>
<body bgcolor='#AAEEFC'>
<!--
      Formulaire générale
-->
<form method='get' action='<?php $PHP_SELF;?>'>

<!--
     Insertion des requetes possibles
-->
<select name='id'>
<option value='0'>Affichage normale</option>
<option value='1'>Afficher les personnes contenus dans le bâtiment 'Résidence des Mousquetaires'</option>
<option value='2'>Afficher les bâtiments qui ne contiennent aucune personne</option>
<option value='3'>Afficher les bâtiments contenus dans les parcs</option>
<option value='4'>Afficher les points d'intersection entre les petites et les grandes routes</option>
<option value='5'>Afficher l'intersection entre la rivière et les parcs</option>
<option value='6'>Afficher les personnes présentes autour de la rivière dans une rayon de 5 mètres</option>
</select>
<input type='submit' value='recharger'>
<br>
<?php
/*
    On commence par récupérer la valeur de id passer au script
*/
   $id = (( isset($_GET["id"]) )? $_GET["id"]: "0");
?>
<!--
   insertion du svg
-->
<embed name='SVG' type='image/svg+xml' src='madatabase.php?id=<?php echo $id;?>' width='600px' height='509.505693569px' />
<!--
   Fin du formulaire
-->
</form>
</body>
</html>

Lors de la soumission du formulaire ce script qui s'appelle lui-même fait appel au script madatabase.php suivant:

<?php
header("Content-type: image/svg+xml");
echo '<?xml version="1.0" encoding="iso-8859-1"?>';
$id = (( isset($_GET["id"]) )? $_GET["id"]: "0");
if ( extension_loaded('pgsql') != 1)
{
    switch (PHP_OS)
    {

  case "WINNT": if (!extension_loaded('pgsql'))  dl("php_pgsql.dll");
                    break;
      default:  if (!extension_loaded('pgsql'))  dl("php_pgsql.so");
               break;
  }
}
?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<?php $pg_hote = "localhost";
    $pg_base_de_donnees = "madatabase";
    $pg_utilisateur = "postgres";
    $pg_mot_de_passe = " ";
    $pg_srid="-1";   
$db_handle = pg_connect("host=".$pg_hote." 
                        dbname=".$pg_base_de_donnees." 
                        user=".$pg_utilisateur." 
                        password=".$pg_mot_de_passe.""); 
                
$widthsvg = 600;                               
$Requete_MS_Tables =  "SELECT * from mapserver_desc";

$Resultat_MS_Tables = pg_exec( $db_handle, $Requete_MS_Tables );
   // tableaux nécessaire pour calculer l'extent
   $Xmin = array(); $Xmax = array();
   $Ymin = array(); $Ymax = array();
   while( $MS_Ligne = pg_fetch_object( $Resultat_MS_Tables) )
   {
        /*
              calcul de l'Extent pour chaque table
        */
        
        $colonne_geometrique = "the_geom";
        $Requete_Extent = "select
                                 xmin(extent(".$colonne_geometrique.")),
                                 ymin(extent(".$colonne_geometrique.")),
                                 xmax(extent(".$colonne_geometrique.")),
                                 ymax(extent(".$colonne_geometrique.")) from
                                ".$MS_Ligne->ms_table;
                                
        $Resultat_Extent = pg_exec( $db_handle, $Requete_Extent );
         
         while ( $Row_Extent = pg_fetch_object( $Resultat_Extent ))
         {
              $Xmin[] = $Row_Extent->xmin;
              $Ymin[] = $Row_Extent->ymin;
              $Xmax[] = $Row_Extent->xmax;
              $Ymax[] = $Row_Extent->ymax;
         }
   
   
   
   
   }
   /* 
   
       Calcul de l'Extent générale et des dimensions de l'image
      
   */
   $xmin = min($Xmin);
   $xmax = max( $Xmax );
   $ymin = min($Ymin );
   $ymax = max ($Ymax);
   $width= abs($xmax-$xmin);
   $height= abs($ymax-$ymin);
   $rapport= $width / $height;   
    
echo "<svg id='racine' width='".$widthsvg."px'
                    height='".$widthsvg/$rapport."px' 
                    viewBox='".$xmin." ".-1*$ymax." ".$width." ".$height."'>";
echo "                    
<style type='text/css'><![CDATA[
.StyleFondsmallroadsOn { fill:none; stroke:rgb(80,80,80); stroke-width:2} 
.StyleFondsmallroadsOff { fill:none; stroke:rgb(80,80,80); stroke-width:2} 
.StyleFondgreatroadsOn { fill:none; stroke:rgb(125,125,125); stroke-width:3} 
.StyleFondgreatroadsOff { fill:none; stroke:rgb(80,80,80); stroke-width:3}
.StyleFondparcsOn { fill:rgb(0,123,0); stroke:rgb(255,255,255); stroke-width:0.1} 
.StyleFondparcsOff { fill:none; stroke:rgb(255,255,255); stroke-width:0.1}
.StyleFondriversOn { fill:rgb(0,12,189); stroke:rgb(0,12,189); stroke-width:1} 
.StyleFondriversOff { fill:none; stroke:rgb(80,80,80); stroke-width:11}  
.StyleFondbuildingsOn { fill:rgb(234,156,78); stroke:black; stroke-width:0.4 } 
.StyleFondbuildingsOff { fill:rgb(0,30,0); stroke:black; stroke-width:0.4 }
.StyleFondpersonnesOn { fill:rgb(255,0,0); stroke:black; stroke-width:0.1 } 
.StyleFondpersonnesOff { fill:rgb(255,0,0); stroke:black; stroke-width:0.1 }
]]>
</style>";
/*
    On liste les tables à afficher ici

*/                             
   $Table_Geom = array();
   $Table_Geom[] = "small_roads"; 
   $Table_Geom[] = "great_roads";
   $Table_Geom[] = "parcs";
   $Table_Geom[] = "rivers";
   $Table_Geom[] = "buildings";
   $Table_Geom[] = "personnes";
/*
    On ferme le fichier SVG
*/  
  for($Iter_Geom = 0;$Iter_Geom< count($Table_Geom);$Iter_Geom++)
  {// Début de la boucle sur les tables
    
      $table = $Table_Geom[$Iter_Geom];
    
     $Requete_SVG = "select AsSVG(the_geom,0) from ".$table;
     $Requete_Geom_Type = "select type from geometry_columns where 
                             f_table_name like '".$table."'";
                             
      $Resultat_SVG = pg_exec($db_handle, $Requete_SVG);                       
                
       $Resultat_Geom_Type =    pg_result(pg_exec($db_handle, $Requete_Geom_Type),
                                      0,
                                      0);      
                             
      $Nb_ligne_table_SVG = pg_numrows( $Resultat_SVG );                       
                             
       for($It_SVG=0;$It_SVG< $Nb_ligne_table_SVG;$It_SVG++)                      
       {   
       
                           
        echo "<g id='id_".$table."_".$It_SVG."' 
                           class='StyleFond".str_replace("_","",$table)."On'>";
      
      

         switch   ($Resultat_Geom_Type)
         {
         
    case "POINT": echo "<circle ".pg_result($Resultat_SVG,$It_SVG,0)." r='1'/>";
                    break;
           
    default:
        echo "<path id='id_path_".$table."_".$It_SVG."' d='".pg_result($Resultat_SVG,$It_SVG,0)."'/>";
         break;
            }
        echo "</g>";

      
        
      }
  }// Fin de la boucle sur les tables
  /*
   $Table_Geom = array();
   $Table_Geom[] = "small_roads"; 
   $Table_Geom[] = "great_roads";
   $Table_Geom[] = "parcs";
   $Table_Geom[] = "rivers";
   $Table_Geom[] = "buildings";
   $Table_Geom[] = "personnes";
 for($Iter_Geom = 0;$Iter_Geom< count($Table_Geom);$Iter_Geom++)
  {// Début de la boucle sur les tables
     $table = $Table_Geom[$Iter_Geom];
     
     $Requete_Gid = "select gid from ".$table;
     
                             
      $Resultat_Gid = pg_exec($db_handle, $Requete_Gid);                       
                
       
      $Nb_ligne_table_Gid = pg_numrows( $Resultat_Gid );                       
                             
       for($It_SVG=0;$It_SVG< $Nb_ligne_table_Gid;$It_SVG++)                      
       { 
             if (($table=="great_roads")||($table=="small_roads"))
         {
             $Requete_Affichage_buildings = "select assvg(translate(pointonsurface(the_geom),-12,0),1),data from ".$table." where gid=".intval($It_SVG+1);
             $Resultat_Affichage_buildings = pg_exec($db_handle, $Requete_Affichage_buildings);
             
             $my_SVG->ecrire("<text ".pg_result($Resultat_Affichage_buildings,0,0)." fill='black' 
             font-size='3' font-color='black' 
             >".pg_result($Resultat_Affichage_buildings,0,1)."
             </text>");

         
         }
        }
  }
  */
/*
         Traitement des cas

*/           
switch ($id)  
{  

     case 1: $Requete_Affichage = "select AsSvg(personnes.the_geom,0),
                              AsSvg(PointOnSurface(personnes.the_geom),1),
        personnes.data from personnes,buildings 
     where within(personnes.the_geom,buildings.the_geom) 
          and buildings.data like 'Résidence des Mousquetaires'";
             $Resultat_Affichage = pg_exec($db_handle, $Requete_Affichage);
            for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage);$It_SVG++)                      
            {    
             echo "<circle fill='blue' ".pg_result($Resultat_Affichage,$It_SVG,0)." r='2'>
             <animate attributeName='fill' values='blue;lightskyblue' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete' />
              </circle>";
             echo "<text ".pg_result($Resultat_Affichage,$It_SVG,1)." fill='black' 
             font-size='3' font-color='white' 
             >".pg_result($Resultat_Affichage,$It_SVG,2)."
             </text>";
          }
            break;
    case 2: $Requete_Affichage = "select AsSvg(the_geom,0),
                              AsSvg(PointOnSurface(the_geom),1),
                          b.data from buildings b,
                  (select geomunion(the_geom) from personnes) gp 
                where 
                    not intersects(gp.geomunion,b.the_geom)";
             $Resultat_Affichage = pg_exec($db_handle, $Requete_Affichage);
              for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage);$It_SVG++)                      
                {    
             echo "<path fill='rgb(234,156,78)' d='".pg_result($Resultat_Affichage,$It_SVG,0)."'>
                  <animate attributeName='stroke' values='white;lightskyblue' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete'/>
                  </path>";
             echo "<text ".pg_result($Resultat_Affichage,$It_SVG,1)." fill='black' 
             font-size='3' font-color='white' 
             >".pg_result($Resultat_Affichage,$It_SVG,2)."
             </text>";
             }             
             
             
             break;
    case 3: $Requete_Affichage = "select AsSvg(the_geom,0),
                              AsSvg(PointOnSurface(the_geom),1),
                          b.data from buildings b where
                            Contains(parcs.the_geom,b.the_geom)";
             $Resultat_Affichage = pg_exec($db_handle, $Requete_Affichage);
              for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage);$It_SVG++)                      
                {    
             echo "<path fill='rgb(234,156,78)' d='".pg_result($Resultat_Affichage,$It_SVG,0)."'>
                  <animate attributeName='stroke' values='white;lightskyblue' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete'/>
                  </path>";
             echo "<text ".pg_result($Resultat_Affichage,$It_SVG,1)." fill='black' 
             font-size='3' font-color='white' 
             >".pg_result($Resultat_Affichage,$It_SVG,2)."
             </text>";
             }             
             
             
             break;

    case 4:         $Requete_Affichage = "select 
             assvg(intersection(g.the_geom,s.the_geom),1),
             astext(intersection(g.the_geom,s.the_geom)),
             assvg(intersection(g.the_geom,s.the_geom),0)
             from great_roads g, small_roads s
                     where intersects(g.the_geom,s.the_geom)";
             $Resultat_Affichage = pg_exec($db_handle, $Requete_Affichage);
          for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage);$It_SVG++)                      
            {    
             echo "<circle fill='blue' ".pg_result($Resultat_Affichage,$It_SVG,2)." r='2'>
             <animate attributeName='fill' values='blue;lightskyblue' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete' />
              </circle>";
             echo "<text ".pg_result($Resultat_Affichage,$It_SVG,0)." fill='black' 
             font-size='3' font-color='black' 
             >".pg_result($Resultat_Affichage,$It_SVG,1)."
             </text>";
          }
          break;
    case 5: $Requete_Affichage = "select
          AsSvg(Intersection(r.the_geom,p.the_geom),0)
          from rivers r, parcs p
          where intersects(r.the_geom,p.the_geom)";
          $Resultat_Affichage = pg_exec($db_handle, $Requete_Affichage);
                for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage);$It_SVG++)                      
                {    
             echo "<path d='".pg_result($Resultat_Affichage,$It_SVG,0)."'>
                  <animate attributeName='fill' values='blue;lightskyblue' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete'/>
                  </path>";
                  }
              break;
     case 6:    $Requete_Affichage = "select AsSvg(p.the_geom,0),
                              AsSvg(PointOnSurface(p.the_geom),1),
                              p.data from personnes p
                     where contains(buffer(rivers.the_geom,5),p.the_geom)";
                      $Resultat_Affichage = pg_exec($db_handle, $Requete_Affichage);
              for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage);$It_SVG++)                      
                {    
             echo "<circle fill='blue' ".pg_result($Resultat_Affichage,$It_SVG,0)." r='2'>
             <animate attributeName='fill' values='blue;lightskyblue' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete' />
              </circle>";
             echo "<text ".pg_result($Resultat_Affichage,$It_SVG,1)." fill='black' 
             font-size='3' font-color='white' 
             >".pg_result($Resultat_Affichage,$It_SVG,2)."
             </text>";
             }  
             $Requete_Affichage_Buffer = "select AsSvg(buffer(the_geom,5),0) from rivers";
                             $Resultat_Affichage_Buffer = pg_exec($db_handle, $Requete_Affichage_Buffer);
              for($It_SVG=0;$It_SVG< pg_numrows($Resultat_Affichage_Buffer);$It_SVG++)                      
                {    
             echo "<path fill='none' d='".pg_result($Resultat_Affichage_Buffer,$It_SVG,0)."'>
                  <animate attributeName='stroke' values='red;lightskyred' dur='1.5s' repeatCount='indefinite' begin='0s' calcMode='discrete'/>
                  </path>";
             }  
             break;
             
      default: break;
      
}// Fin des test pour id
/*
    Connexion à PostgreSQL => Fermeture
*/         
pg_close($db_handle);
?>
</svg>

On aura par exemple l'image suivante

Figure 7.1. Sortie en SVG sur quelques requêtes de la section "Exemples de requêtes spatiales II" du chapitre 4

Sortie en SVG sur quelques requêtes de la section "Exemples de requêtes spatiales II" du chapitre 4


[7] On se sera assurer ici que l'utilisateur sous MinGW soit un super-utilisateur dans PostgreSQL. Pour celà, consultez le chapitre 3: "Devenir soi-même super-utilisateur de PostgreSQL (pour l'utilisateur de MinGW)"