Le blog de Jean David TECHER, un Réunionnais à Saint-Priest/Lyon

Aller au contenu | Aller au menu | Aller à la recherche


< 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 >

mardi 8 mai 2007

Libpqxx 2.6.9 - une belle interface de programmation en C++ pour PostgreSQL - 1ère partie

RESUME

C'est sûrement l'interface de programmation en C++ de PostgreSQL, la plus innovante. Elle constitue par rapport aux habituelles, l'une de la nouvelle génération. Son intérêt réside surtout avec son adéquation avec la bibliothèque STL (Standard Template Library). Comme le souligne son auteur, elle a été pensée «STL-compatible» . Le site de développement est http://thaiopensource.org/development/libpqxx/.

Autre point à signaler, libpqxx est basée sur le mode transactionnel de PostgreSQL. Elle sort donc du cadre purement basique de la programmation «Requêtes - Réponses» pour l'interfaçage client-serveur. La richesse de ses fonctionnalités est vraiment impressionnante, déroutante parfois au premier abord. Elle permet un code lisible, bien stylé, appréciable.

INSTALLATION SOUS UBUNTU DAPPER

En pré-requis, il faut avoir un serveur PostgreSQL sous la main. Libpqxx est basée sur libpq. Sous Windows, j'ai pu la compilé avec MinGW/Msys sans souci. Je livre ici mes notes pour une compilation sous Ubuntu Dapper (ou Debian). Je ne l'ai pas testé sous Visual C++.

Son installation se fait en faisant
wget http://thaiopensource.org/download/software/libpqxx/libpqxx-2.6.9.tar.gz
tar xvzf libpqxx-2.6.9.tar.gz
cd libpqxx-2.6.9
Chez moi PostgreSQL est installé à /opt/pgsql/, je dois effectuer une modification du fichier libpqxx.pc.in avant de continuer. Je fais celà surtout pour pouvoir compiler mes programmes par la suite. On ouvre donc le fichier et on effectue le remplacement suivant
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: libpqxx
Description: a C++ API to the PostgreSQL database management system.
Version: @VERSION@
Libs: -L${libdir} -L@with_postgres_lib@ -lpq -lpqxx
Cflags: -I${includedir} -I@with_postgres_include@

On peut maintenant compiler.
export PATH=/opt/pgsql/bin/:$PATH
./configure 
make
make install
En essayant d'utiliser pqxx-config, j'ai eu l'erreur suivante
#pqxx-config --libs
pqxx-config is deprecated; please use "/usr/bin/pkg-config --libs libpqxx"

En fait c'est surtout sur la commande pkg-config --libs libpqxx ou pkg-config --cflags libpqxx qu'il faut se baser. Par exemple, pour l'une des deux j'obtiens
# pkg-config --libs libpqxx
-L/usr/local/lib -L/opt/pgsql/lib -lpq -lpqxx
TEST DE REGRESSION
Toujours dans les sources, il faut se rendre dans le sous-répertoire test les sources et faire
cd test
chmod 777 -R .
su postgres
make check
UN PREMIER PROGRAMME
Pour la compilation de mon programme, je vais me doter du Makefile suivant
PKGCONFIG=/usr/bin/pkg-config
CXXFLAGS = -g -Wall $(shell $(PKGCONFIG) --cflags libpqxx)
LDLIBS   = $(shell $(PKGCONFIG) --libs libpqxx)

exes = test1

all:	$(exes)

test1: test1.cc

clean:
	rm -f $(exes)
Si l'utilisation d'un Makefile peut s'avérer déroutant, on pourra essayer
g++ -g -Wall -I/usr/local/include -I/opt/pgsql/include      test1.cc  -L/usr/local/lib -L/opt/pgsql/lib -lpq -lpqxx   -o test1
Mon programme test1.cc sera le suivant, juste un petit programme de connexion
/* test1.cc */

#include <stdlib.h>	// Nécessaire pour exit(), EXIT_SUCCESS, et EXIT_FAILURE
#include <iostream> 	// requis pour cerr
#include <pqxx/pqxx>	// définitions pour libpqxx

using namespace pqxx;
using namespace std;

int main( int argc, const char * argv[] )
{

  try 
  {
    connection    myConnection( argc > 1 ? argv[1] : "" );

    myConnection.activate();
    if (myConnection.is_open())
    {
       string host = to_string( myConnection.server_version() );
       host.replace(1,1,"."); host.replace(3,1,".");
       cout<<" INFORMATIONS:"<<endl;
        cout<<" Paramètres de connexion host="<<myConnection.hostname();
       cout<<" dbname="<<myConnection.dbname()<<" user="<<myConnection.username()<<endl;
       cout<<" Serveur - Version "<<host<<endl;
    }
  }	
  catch( runtime_error & e )
  {
    cerr << "Echec à la connexion avec erreur := " << e.what();
    exit( EXIT_FAILURE );
  }
  catch( exception & e )
  {
    cerr << e.what();
    exit( EXIT_FAILURE );
  }
  catch( ... )
  {
    cerr << "Erreur/exception inconnue !" << endl;
    exit( EXIT_FAILURE );
  }

  exit( EXIT_SUCCESS );

}


Ensuite on tape
make
Pour une utilisation standard, je vais passer à test1 les paramètres de connexion
./test1 "host=localhost dbname=testgis user=postgres password=empr888"
qui me renverra
 INFORMATIONS:
 Paramètres de connexion host=localhost dbname=testgis user=postgres
 Serveur - Version 8.2.3
On peut aussi utiliser des variables d'environnement de PostgreSQL, par exemple
# PGHOST=localhost PGUSER=postgres ./test1 "dbname=testgis password=empr888"
 INFORMATIONS:
 Paramètres de connexion host=localhost dbname=testgis user=postgres
 Serveur - Version 8.2.3
Bien sûr, en cas d'échec de connexion, j'aurais par exemple sur un hôte distant
# PGHOST=192.168.0.5 PGUSER=postgres ./test1 "dbname=testgis password=empr888"
Echec à la connexion avec erreur := FATAL:  authentification par mot de passe échouée pour l'utilisateur  «postgres»

Test du module de PgRouting de Ka-Map avec les données NavTeq

Suite à mon précédent billet, je me suis amusé à tester les données NavTeq de ADCI avec le module PgRoutin de KaMap. Un exemple de démo avec les données de Orkney est visible à kappa.gonfi.org/dev/gonfi-ka-map/htdocs/index_routing.html

J'ai réussi à obtenir par exemple la screenshot suivante pour mes propres données

Une démo est disponible chez moi à http://www.davidgis.fr/ka-map/index_routing.html

Pour commencer il faut suivre les indications de http://ka-map.ominiverdi.org/wiki/index.php/KaRouting. Malheureusement il s'avère que les indications fournies sont incomplètes . Reprenons ici les détails de l'installation

On s'assure par exemple d'avoir le jeu de tests de PgRouting provenant de http://www.postlbs.org/postlbs-cms/en/download à savoir «pgRouting Sample Application». Chez moi, j'ai décompressé le répertoire dans mon "/var/www/". J'ai ensuite copié tout ce qui était associé à streets.shp dans /var/www/routingj/data/

cp streets.* /var/www/routingj/data/

J'ai ensuite crée la mapfile suivante /var/www/routingj/maps/kamap-streets.map dont le contenu est

MAP
  IMAGETYPE   PNG
  EXTENT      -77.1166763305664 38.7924194335938 -76.909538269043 38.9952430725098
  #SIZE        500 489.585635359116
  SIZE 200 195.834254143646
  IMAGECOLOR  255 255 255
  SHAPEPATH   "../data"

  FONTSET     "../fonts/fonts.list"
  
REFERENCE
   IMAGE "/var/www/keymap-streets.png"
  EXTENT -77.1166763305664 38.7924194335938 -76.909538269043 38.9952430725098
  STATUS ON
  COLOR -1 -1 -1
  OUTLINECOLOR 255 0 0
  SIZE 200 164
END

  WEB
    IMAGEPATH "/var/www/tmp/"
    IMAGEURL  "/tmp/"
  END
		
  PROJECTION
   "init=epsg:4326" # JGD2000
  END

  UNITS DD

  SYMBOL
    NAME "hatch"
    TYPE hatch
  END
  
  LAYER 
    NAME "roads"
    DATA streets
    STATUS DEFAULT
    TYPE LINE

    CLASS
      COLOR 155 155 155
    END

  END 

END 

Bien sûr pour calculer l'extent et les dimensions adéquates de l'image pour width=500, je me suis servi des requêtes suivantes

routing=# select extent(the_geom) from streets_edges;
                                  extent
---------------------------------------------------------------------------
 BOX(-77.1166763305664 38.7924194335938,-76.909538269043 38.9952430725098)
(1 ligne)
et de
routing=# SELECT
               500*(abs(Ymax(foo.extent)-Ymin(foo.extent))/abs(Xmax(foo.extent)-Xmin(foo.extent)))
               AS hauteur
         FROM (SELECT Extent(the_geom) FROM streets_edges) AS foo;
     hauteur
------------------
 489.585635359116
(1 ligne)
Générer la keymap pour la légende
Pour connaître les dimensions pour width=200
routing=# SELECT
               200*(abs(Ymax(foo.extent)-Ymin(foo.extent))/abs(Xmax(foo.extent)-Xmin(foo.extent)))
               AS hauteur
         FROM (SELECT Extent(the_geom) FROM streets_edges) AS foo;
     hauteur
------------------
 195.834254143646
(1 ligne)
Le script php suivant a amplement suffit pour générer la keymap /var/www/keymap-streets.png
<html>
<body>
<?php
    $sw_MapFile = "/var/www/routingj/maps/kamap-streets.map";
    
    $map = ms_newMapObj( $sw_MapFile );
    
    $image = $map->draw();
//$image_url = $image->saveWebImage(MS_PNG,1,1,0);
$image->saveImage("/var/www/keymap-streets.png");
echo "<IMG   
BORDER=0 
SRC='".$image_url."'
width='".$map->width."' height='".$map->height."'/>
<BR>"; 
?>
</body>
</html>
Configuration de PgRouting avec Kamap

On peut télécharger la CVS disponible à http://ka-map.ominiverdi.org/CVSimg/ka-map-cvs-image.tar.gz

cd /var/www/
wget http://ka-map.ominiverdi.org/CVSimg/ka-map-cvs-image.tar.gz
tar xvzf ka-map-cvs-image.tar.gz
Ce qui donnera le répertoire ka-map.

Comme précisé dans le wiki

i
cd ka-map
cp include/config.routing.dist.php include/config.php
Par rapport au contenu proposé voici le mien avec les différences notables en gras

 // $aszGMap = array (
 //        'title' => 'GMap 75',
 //        'path' => '/var/www/gmap/htdocs/gmap75.map',
 //        'scales' => array( 40000000, 25000000, 12000000, 7500000, 3000000, 1000000 ),
 //        'format' =>'PNG'
 //        /* Sample authorized_users entry. See auth.php for more details:
 //         * ,'authorized_users' => array('popplace' => array('user1', 'user2'),
 //         *                              'park'     => array('user1')
 //         */
 //);

 $aszKaRoute = array (
         'title' => 'Routing',
         'path' => '/var/www/routingj/maps/kamap-streets.map',
         'scales' => array(100000,50000,10000 ),
         'format' =>'PNG'
         /* Sample authorized_users entry. See auth.php for more details:
          * ,'authorized_users' => array('popplace' => array('user1', 'user2'),
          *                              'park'     => array('user1')
          */
 );
 $aszMapFiles = array( 'routeMap'=>$aszKaRoute);


/******************************************************************************
 * figure out which map file to use and set up the necessary variables for
 * the rest of the code to use.  This does need to be done on every page load
 * unfortunately.
 *
 * szMap should be set to the default map file to use but can change if
 * this script is called with map=.
 */
$szMap = 'routeMap';

/******************************************************************************
 * Configure kaRouting settings
 * the array set the second mapfile you need to call and let kaRouting.php 
 * override and the postgres connection string
 */
$kaRoute = Array(
			'routeMap' => '/var/www/routingj/maps/mapfile.map',//the second mapfile -should be changed with an SLD file
			'pgConn' => 'dbname=routing host=localhost port=5432 user=postgres password=empr888',
			'myGraphTable' => 'streets_edges',
			'costColumn' => 'length',
			'reverseCostColumn' => 'reverse_cost',
			'directed' => 'false',//check pgRouting docs for this value
			'has_reverse_cost' => 'true',//check pgRouting docs for this value
			'buffer' => '0.01'//should be related to your map unit
		);

La pour la suite, il faut créer la mapfile /var/www/routingj/maps/mapfile.map dont le contenu sera - conformément au wiki -

MAP
  IMAGETYPE   png
  EXTENT      139.602 35.413 139.678 35.489
  SIZE        550 450 

   IMAGECOLOR  255 255 255
  SHAPEPATH   "data" #there are no shapes ;-)

   FONTSET      "../fonts/fonts.list"
  WEB
    IMAGEPATH "../tmp/"
    IMAGEURL  "/routingj/tmp/" 
  END 

  PROJECTION
   "init=epsg:4612" # JGD2000. the kanagawa one
  END 

  UNITS DD 

  SYMBOL
    NAME "hatch"
    TYPE hatch
  END 

LAYER
      NAME "path"
      CONNECTION "user=postgres password=empr888 dbname=routing host=localhost port=5432"
      CONNECTIONTYPE postgis
      STATUS OFF 
      TYPE LINE 

      CLASS
        NAME "path"
        STYLE
          COLOR 155 0 0
          WIDTH 2
       END
      END
 END


END
Rappel: Création de la table streets_edges

Par la suite, on s'assurera pour la création de la table streets_egdes de suivre les indications de http://www.davidgis.fr/documentation/win32/html/apa.html aux sections «A.8.1. Importation d'un jeu de données NavTeq» et «A.8.2. Noeuds du réseau et direction pour le routage».

Recommencdations supplémentaires du wiki

Pour être conforme au wiki, il faut ensuite modifier son fichier de configuration d'Apache

Alias /ka-map/ "/var/www/ka-map/htdocs/"

       Options Indexes
       AllowOverride None
       Order allow,deny
       Allow from all

Et ensuite de créer la table suivante dont le contenu sera
CREATE TABLE kroute (
    gid serial NOT NULL,
    sessionid text,
    the_geom geometry NOT NULL,
    date timestamp without time zone,
    CONSTRAINT enforce_dims_the_geom CHECK ((ndims(the_geom) = 2)),
    CONSTRAINT enforce_geotype_the_geom CHECK (((geometrytype(the_geom) = 'MULTILINESTRING'::text) OR (the_geom IS NULL))),
    CONSTRAINT enforce_srid_the_geom CHECK ((srid(the_geom) = -1))
);
Pour lancer l'application, il suffira de pointer vers http://localhost/ka-map/index_routing.html

dimanche 6 mai 2007

SpiderMan 3 et les films de cet été.

Hier je suis allé le voir au Gaumont Multiplexe de Montpellier. Pour la séance de 16h30 - première semaine -, y'avait un de ces mondes ! J'suis arrivé, j'ai fait la queue. Les panneaux interactifs qui fournissaient le nombre de places restantes mentionnait 94 places restantes. Même pas deux minutes plus tard, il en restait 84.

Du coup dans la salle, j'ai été aux premièrs rangs. Mais celà ne m'a pas emêché de matter le film . Que dire si ce n'est que c'était un bon film d'action. Moi qui a baigné dans l'univers de Marvel quand zétais petit: Iron-Man, X-Men. Comme troisième opus, c'était vraiment pas mal. C'est surtout Venom qui m'a fait craqué aussi bien fait que dans la BD avec ses nombreuses dents asserrées. Pour le reste, c'était plutôt pas mal que d'avoir 3 super-vilains que d'un seul pour une fois.

Par contre avant le film, j'ai vu la bande-annonce de Transformers. De la balle, ça promet en juillet cet été. Un de mes dessins animés préférés porté à l'écran. Je ne manquerais pas le RDV. Ce qui est dommage c'est que dans la bande-annonce, on ne devine pas les robots. C'est uniquement à la fin en voyant le symbole suivant

Y'a aussi Pirates des Caraïbes 3 qui devrait bientôt sortir. On aura droit à de bons films cette année. Au moins j'aurais l'occasion de partir plus souvent au cinéma cet été.

Un lien pour tester des données NavTeq

Le lien que j'ai trouvé hier soir sur internet est http://www.adci.com/products/navteq/index.html. C'est surtout le jeu "NAVTEQ Premium - for routing applications" qu'il faut télécharger. Une simple inscription sur le site permet par la suite de pouvoir télécharger les données. Une fois téléchargées et décompressées, ce sera surtout le shapefile streets.shp qui s'avèrera intéressant.

Le petit + c'est aussi la documentation qui accompagne les shapefiles. On y apprend comment NavTeq présente sa topologie, ses spécifités etc...

Pour convertir le fichier en kml, rien de plus simple que

/opt/gdal-1.4.0/bin/ogr2ogr -f KML ~/streets.kml streets.shp
Une petite visualisation dans googleearth nous donne les belles screenshots suivantes


Direction pour le routage
En regardant de près la documentation, on s'aperçoit que tout repose sur la colonne dir_travel:
  • dir_travel='B' c'est une tronçon à double sens;
  • dir_travel='F' c'est une tronçon à sens unique. Le sens de parcours est le sens direct;
  • dir_travel='T' c'est une tronçon à sens unique. Le sens de parcours est le sens opposé;
Ce qui me donnera par exemple pour les noeuds 5274,5488, les images suivantes

Sens aller

Sens retour
Sur les images ci-dessus, les tronçons à sens unique sont en vert. Les tronçons à double sens sont en bleu.
Exemple pour TSP

Je dois commencer par effectuer quelques modifications à ma table streets_edges

alter TABLE streets_edges RENAME id to gid;
alter TABLE streets_edges RENAME cost to length;
alter TABLE streets_edges RENAME edge_id to edge_id_old;
Et pour les noeuds , la fonctionnalité me renverra
 SELECT the_geom FROM tsp_astar_as_geometry_internal_id_directed('streets_edges','5403,5822,338,7106,6043,1952',1952,.03,false,true);
l'image suivante

TSP() sur les noeuds 5403,5822,338,7106,6043,1952 en partant du noeud 1952
La commande
/opt/gdal-1.4.0/bin/ogr2ogr -f KML ~/parcours.kml PG:'host=localhost dbname=routing user=postgres' \
-sql "SELECT (dump).geom FROM (SELECT dump(the_geom) FROM \tsp_astar_as_geometry_internal_id_directed('streets_edges','5403,5822,338,7106,6043,1952',1952,.03,false,true)) AS foo"
me donnera l'affichage suivant sous googleearth

TSP() sur les noeuds 5403,5822,338,7106,6043,1952 en partant du noeud 1952