source: branches/branch-1.2/zoo-services/ogr/ogr2ogr/service.c @ 718

Last change on this file since 718 was 268, checked in by djay, 13 years ago

Merge branch-1.2 to current rev. 267. Tag release-1.2.0-rc2.

File size: 41.7 KB
Line 
1/******************************************************************************
2 * $Id: ogr2ogr.cpp 15473 2008-10-07 20:59:24Z warmerdam $
3 *
4 * Project:  OpenGIS Simple Features Reference Implementation
5 * Purpose:  Simple client for translating between formats.
6 * Author:   Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 1999, Frank Warmerdam
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30#include "ogrsf_frmts.h"
31#include "ogr_p.h"
32#include "cpl_conv.h"
33#include "cpl_string.h"
34#include "ogr_api.h"
35#ifdef ZOO_SERVICE
36#include "service.h"
37#endif
38
39CPL_CVSID("$Id: ogr2ogr.cpp 15473 2008-10-07 20:59:24Z warmerdam $");
40
41#ifdef ZOO_SERVICE
42extern "C" {
43#endif
44
45static void Usage();
46
47static int TranslateLayer( OGRDataSource *poSrcDS, 
48                           OGRLayer * poSrcLayer,
49                           OGRDataSource *poDstDS,
50                           char ** papszLSCO,
51                           const char *pszNewLayerName,
52                           int bTransform, 
53                           OGRSpatialReference *poOutputSRS,
54                           OGRSpatialReference *poSourceSRS,
55                           char **papszSelFields,
56                           int bAppend, int eGType,
57                           int bOverwrite,
58                           double dfMaxSegmentLength);
59
60static int bSkipFailures = FALSE;
61static int nGroupTransactions = 200;
62static int bPreserveFID = FALSE;
63static int nFIDToFetch = OGRNullFID;
64
65/************************************************************************/
66/*                                main()                                */
67/************************************************************************/
68
69#ifdef ZOO_SERVICE
70#ifdef WIN32
71__declspec(dllexport)
72#endif
73int Ogr2Ogr(maps*& conf,maps*& inputs,maps*& outputs)
74#else
75int main( int nArgc, char ** papszArgv )
76#endif
77{
78    const char  *pszFormat = "ESRI Shapefile";
79    const char  *pszDataSource = NULL;
80    const char  *pszDestDataSource = NULL;
81    const char  *pszwebDestData = NULL;
82    char        **papszLayers = NULL;
83    char        **papszDSCO = NULL, **papszLCO = NULL;
84    int         bTransform = FALSE;
85    int         bAppend = FALSE, bUpdate = FALSE, bOverwrite = FALSE;
86    const char  *pszOutputSRSDef = NULL;
87    const char  *pszSourceSRSDef = NULL;
88    OGRSpatialReference *poOutputSRS = NULL;
89    OGRSpatialReference *poSourceSRS = NULL;
90    const char  *pszNewLayerName = NULL;
91    const char  *pszWHERE = NULL;
92    OGRGeometry *poSpatialFilter = NULL;
93    const char  *pszSelect;
94    char        **papszSelFields = NULL;
95    const char  *pszSQLStatement = NULL;
96    int         eGType = -2;
97    double      dfMaxSegmentLength = 0;
98
99    /* Check strict compilation and runtime library version as we use C++ API */
100    if (! GDAL_CHECK_VERSION("ogr2ogr"))
101#ifdef ZOO_SERVICE
102        {
103                fprintf(stderr,"Not correct version of the gdal library\n");
104                setMapInMaps(conf,"lenv","message","Unable to check gdal version for ogr2ogr_service.zo");
105                return SERVICE_FAILED;
106        }
107#else
108        exit(1);
109#endif
110/* -------------------------------------------------------------------- */
111/*      Register format(s).                                             */
112/* -------------------------------------------------------------------- */
113    OGRRegisterAll();
114
115#ifdef ZOO_SERVICE
116    map *tmpMap=NULL;
117    char dataPath[1024];
118    tmpMap=getMapFromMaps(conf,"main","dataPath");
119    if(tmpMap!=NULL)
120      sprintf(dataPath,"%s",tmpMap->value);
121    tmpMap=NULL;
122    char tempPath[1024];
123    tmpMap=getMapFromMaps(conf,"main","tmpPath");
124    if(tmpMap!=NULL){
125      sprintf(tempPath,"%s",tmpMap->value);
126    }
127   
128    tmpMap=NULL;
129    char serverAddress[1024];
130    tmpMap=getMapFromMaps(conf,"main","serverAddress");
131    if(tmpMap!=NULL){
132      sprintf(serverAddress,"%s",tmpMap->value);
133    }
134   
135    tmpMap=NULL;
136    char tmpurl[1024];
137    tmpMap=getMapFromMaps(conf,"main","tmpurl");
138    if(tmpMap!=NULL){
139      sprintf(tmpurl,"%s",tmpMap->value);
140    }
141
142    tmpMap=NULL;
143    tmpMap=getMapFromMaps(inputs,"F","value");
144    if(tmpMap!=NULL){
145      pszFormat=tmpMap->value;
146    }
147
148    tmpMap=NULL;
149    tmpMap=getMapFromMaps(inputs,"DSCO","value");
150    if(tmpMap!=NULL){
151          papszDSCO = CSLAddString(papszDSCO, tmpMap->value );
152    }
153
154    tmpMap=NULL;
155    tmpMap=getMapFromMaps(inputs,"LCO","value");
156    if(tmpMap!=NULL){
157          papszLCO = CSLAddString(papszLCO, tmpMap->value );
158    }
159
160    tmpMap=NULL;
161    tmpMap=getMapFromMaps(inputs,"preserve_fid","value");
162    if(tmpMap!=NULL){
163          bPreserveFID = TRUE;
164    }
165
166    tmpMap=NULL;
167    tmpMap=getMapFromMaps(inputs,"skipfailure","value");
168    if(tmpMap!=NULL){
169          bPreserveFID = TRUE;
170          bSkipFailures = TRUE;
171          nGroupTransactions = 1; /* #2409 */
172    }
173
174    tmpMap=NULL;
175    tmpMap=getMapFromMaps(inputs,"append","value");
176    if(tmpMap!=NULL){
177          bAppend = TRUE;
178    }
179
180    /* if exist, overwrite the data with the same name */
181    bOverwrite = TRUE;
182   
183    tmpMap=NULL;
184    tmpMap=getMapFromMaps(inputs,"update","value");
185    if(tmpMap!=NULL){
186          bUpdate = TRUE;
187    }
188
189    tmpMap=NULL;
190    tmpMap=getMapFromMaps(inputs,"fid","value");
191    if(tmpMap!=NULL){
192          nFIDToFetch = atoi(tmpMap->value);
193    }
194
195    tmpMap=NULL;
196    tmpMap=getMapFromMaps(inputs,"sql","value");
197    if(tmpMap!=NULL){
198          pszSQLStatement = tmpMap->value;
199    }
200
201    tmpMap=NULL;
202    tmpMap=getMapFromMaps(inputs,"nln","value");
203    if(tmpMap!=NULL){
204          pszNewLayerName = tmpMap->value;
205    }
206
207    tmpMap=NULL;
208    tmpMap=getMapFromMaps(inputs,"nlt","value");
209    if(tmpMap!=NULL){
210          pszNewLayerName = tmpMap->value;
211          if( EQUAL(tmpMap->value,"NONE") )
212                  eGType = wkbNone;
213          else if( EQUAL(tmpMap->value,"GEOMETRY") )
214                  eGType = wkbUnknown;
215          else if( EQUAL(tmpMap->value,"POINT") )
216                  eGType = wkbPoint;
217          else if( EQUAL(tmpMap->value,"LINESTRING") )
218                  eGType = wkbLineString;
219          else if( EQUAL(tmpMap->value,"POLYGON") )
220                  eGType = wkbPolygon;
221          else if( EQUAL(tmpMap->value,"GEOMETRYCOLLECTION") )
222                  eGType = wkbGeometryCollection;
223          else if( EQUAL(tmpMap->value,"MULTIPOINT") )
224                  eGType = wkbMultiPoint;
225          else if( EQUAL(tmpMap->value,"MULTILINESTRING") )
226                  eGType = wkbMultiLineString;
227          else if( EQUAL(tmpMap->value,"MULTIPOLYGON") )
228                  eGType = wkbMultiPolygon;
229          else if( EQUAL(tmpMap->value,"GEOMETRY25D") )
230                  eGType = wkbUnknown | wkb25DBit;
231          else if( EQUAL(tmpMap->value,"POINT25D") )
232                  eGType = wkbPoint25D;
233          else if( EQUAL(tmpMap->value,"LINESTRING25D") )
234                  eGType = wkbLineString25D;
235          else if( EQUAL(tmpMap->value,"POLYGON25D") )
236                  eGType = wkbPolygon25D;
237          else if( EQUAL(tmpMap->value,"GEOMETRYCOLLECTION25D") )
238                  eGType = wkbGeometryCollection25D;
239          else if( EQUAL(tmpMap->value,"MULTIPOINT25D") )
240                  eGType = wkbMultiPoint25D;
241          else if( EQUAL(tmpMap->value,"MULTILINESTRING25D") )
242                  eGType = wkbMultiLineString25D;
243          else if( EQUAL(tmpMap->value,"MULTIPOLYGON25D") )
244                  eGType = wkbMultiPolygon25D;
245          else   
246          {
247                  fprintf( stderr, "-nlt %s: type not recognised.\n", 
248                          tmpMap->value );
249                  exit( 1 );
250          }
251    }
252
253    tmpMap=NULL;
254    tmpMap=getMapFromMaps(inputs,"tg","value");
255    if(tmpMap!=NULL){
256          nGroupTransactions = atoi(tmpMap->value);
257    }
258
259    tmpMap=NULL;
260    tmpMap=getMapFromMaps(inputs,"s_srs","value");
261    if(tmpMap!=NULL){
262          pszSourceSRSDef = tmpMap->value;
263    }
264
265    tmpMap=NULL;
266    tmpMap=getMapFromMaps(inputs,"a_srs","value");
267    if(tmpMap!=NULL){
268          pszOutputSRSDef = tmpMap->value;
269    }
270
271    tmpMap=NULL;
272    tmpMap=getMapFromMaps(inputs,"t_srs","value");
273    if(tmpMap!=NULL){
274          pszOutputSRSDef = tmpMap->value;
275          bTransform = TRUE;
276    }
277
278    tmpMap=NULL;
279    tmpMap=getMapFromMaps(inputs,"SPAT","value");
280    if(tmpMap!=NULL){
281      char *tmp=tmpMap->value;
282      char *t=strtok(tmp,",");
283      int cnt=0;
284      double dfULX, dfULY, dfLRX, dfLRY;
285      while(t!=NULL){
286        switch(cnt){
287        case 0:
288          dfULX = atof(t);
289          break;
290        case 1:
291          dfULY = atof(t);
292          break;
293        case 2:
294          dfLRX = atof(t);
295          break;
296        case 3:
297          dfLRY = atof(t);
298          break;
299        }
300        fprintf(stderr,"%s\n\n",t);
301        fprintf(stderr,"%f - %f - %f - %f\n\n",dfULX,dfULY,dfLRX,dfLRY);
302        t=strtok(NULL,",");
303        cnt++;
304      }
305
306      OGRLinearRing  oRing;
307     
308      oRing.addPoint( dfULX, dfULY );
309      oRing.addPoint( dfULX, dfLRY );
310      oRing.addPoint( dfLRX, dfLRY );
311      oRing.addPoint( dfLRX, dfULY );
312      oRing.addPoint( dfULX, dfULY );
313      poSpatialFilter = new OGRPolygon();
314      ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
315    }
316
317    tmpMap=NULL;
318    tmpMap=getMapFromMaps(inputs,"where","value");
319    if(tmpMap!=NULL){
320          pszWHERE = tmpMap->value;
321    }
322
323    tmpMap=NULL;
324    tmpMap=getMapFromMaps(inputs,"select","value");
325    if(tmpMap!=NULL){
326          pszSelect = tmpMap->value;
327          papszSelFields = CSLTokenizeStringComplex(pszSelect, " ,", 
328                  FALSE, FALSE );
329    }
330
331    tmpMap=NULL;
332    tmpMap=getMapFromMaps(inputs,"segmentize","value");
333    if(tmpMap!=NULL){
334          dfMaxSegmentLength = atof(tmpMap->value);
335    }
336
337    tmpMap=NULL;
338    tmpMap=getMapFromMaps(inputs,"segmentize","value");
339    if(tmpMap!=NULL){
340          dfMaxSegmentLength = atof(tmpMap->value);
341    }
342
343    tmpMap=NULL;
344    tmpMap=getMapFromMaps(inputs,"InputDSN","value");
345    if(tmpMap!=NULL){
346      pszDataSource=(char*)malloc(sizeof(char)*(strlen(dataPath)+strlen(tmpMap->value)+1));
347      sprintf((char*)pszDataSource,"%s/%s",dataPath,tmpMap->value);
348    }
349
350    tmpMap=NULL;
351    tmpMap=getMapFromMaps(inputs,"OutputDSN","value");
352    if(tmpMap!=NULL){
353      pszDestDataSource=(char*)malloc(sizeof(char)*(strlen(tempPath)+strlen(tmpMap->value)+4));
354      sprintf((char*)pszDestDataSource,"%s/%s",tempPath,tmpMap->value/*,ext*/);
355      pszwebDestData=(char*)malloc(sizeof(char)*(strlen(serverAddress)+strlen(tmpurl)+strlen(tmpMap->value)+4));
356      sprintf((char*)pszwebDestData,"%s%s/%s",serverAddress,tmpurl,tmpMap->value/*,ext*/);
357    }
358
359#else
360/* -------------------------------------------------------------------- */
361/*      Processing command line arguments.                              */
362/* -------------------------------------------------------------------- */
363    nArgc = OGRGeneralCmdLineProcessor( nArgc, &papszArgv, 0 );
364   
365    if( nArgc < 1 )
366        exit( -nArgc );
367
368    for( int iArg = 1; iArg < nArgc; iArg++ )
369    {
370        if( EQUAL(papszArgv[iArg], "--utility_version") )
371        {
372                                printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
373                   papszArgv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
374            return 0;
375        }
376        else if( EQUAL(papszArgv[iArg],"-f") && iArg < nArgc-1 )
377        {
378            pszFormat = papszArgv[++iArg];
379        }
380        else if( EQUAL(papszArgv[iArg],"-dsco") && iArg < nArgc-1 )
381        {
382            papszDSCO = CSLAddString(papszDSCO, papszArgv[++iArg] );
383        }
384        else if( EQUAL(papszArgv[iArg],"-lco") && iArg < nArgc-1 )
385        {
386            papszLCO = CSLAddString(papszLCO, papszArgv[++iArg] );
387        }
388        else if( EQUAL(papszArgv[iArg],"-preserve_fid") )
389        {
390            bPreserveFID = TRUE;
391        }
392        else if( EQUALN(papszArgv[iArg],"-skip",5) )
393        {
394            bSkipFailures = TRUE;
395            nGroupTransactions = 1; /* #2409 */
396        }
397        else if( EQUAL(papszArgv[iArg],"-append") )
398        {
399            bAppend = TRUE;
400        }
401        else if( EQUAL(papszArgv[iArg],"-overwrite") )
402        {
403            bOverwrite = TRUE;
404        }
405        else if( EQUAL(papszArgv[iArg],"-update") )
406        {
407            bUpdate = TRUE;
408        }
409        else if( EQUAL(papszArgv[iArg],"-fid") && papszArgv[iArg+1] != NULL )
410        {
411            nFIDToFetch = atoi(papszArgv[++iArg]);
412        }
413        else if( EQUAL(papszArgv[iArg],"-sql") && papszArgv[iArg+1] != NULL )
414        {
415            pszSQLStatement = papszArgv[++iArg];
416        }
417        else if( EQUAL(papszArgv[iArg],"-nln") && iArg < nArgc-1 )
418        {
419            pszNewLayerName = papszArgv[++iArg];
420        }
421        else if( EQUAL(papszArgv[iArg],"-nlt") && iArg < nArgc-1 )
422        {
423            if( EQUAL(papszArgv[iArg+1],"NONE") )
424                eGType = wkbNone;
425            else if( EQUAL(papszArgv[iArg+1],"GEOMETRY") )
426                eGType = wkbUnknown;
427            else if( EQUAL(papszArgv[iArg+1],"POINT") )
428                eGType = wkbPoint;
429            else if( EQUAL(papszArgv[iArg+1],"LINESTRING") )
430                eGType = wkbLineString;
431            else if( EQUAL(papszArgv[iArg+1],"POLYGON") )
432                eGType = wkbPolygon;
433            else if( EQUAL(papszArgv[iArg+1],"GEOMETRYCOLLECTION") )
434                eGType = wkbGeometryCollection;
435            else if( EQUAL(papszArgv[iArg+1],"MULTIPOINT") )
436                eGType = wkbMultiPoint;
437            else if( EQUAL(papszArgv[iArg+1],"MULTILINESTRING") )
438                eGType = wkbMultiLineString;
439            else if( EQUAL(papszArgv[iArg+1],"MULTIPOLYGON") )
440                eGType = wkbMultiPolygon;
441            else if( EQUAL(papszArgv[iArg+1],"GEOMETRY25D") )
442                eGType = wkbUnknown | wkb25DBit;
443            else if( EQUAL(papszArgv[iArg+1],"POINT25D") )
444                eGType = wkbPoint25D;
445            else if( EQUAL(papszArgv[iArg+1],"LINESTRING25D") )
446                eGType = wkbLineString25D;
447            else if( EQUAL(papszArgv[iArg+1],"POLYGON25D") )
448                eGType = wkbPolygon25D;
449            else if( EQUAL(papszArgv[iArg+1],"GEOMETRYCOLLECTION25D") )
450                eGType = wkbGeometryCollection25D;
451            else if( EQUAL(papszArgv[iArg+1],"MULTIPOINT25D") )
452                eGType = wkbMultiPoint25D;
453            else if( EQUAL(papszArgv[iArg+1],"MULTILINESTRING25D") )
454                eGType = wkbMultiLineString25D;
455            else if( EQUAL(papszArgv[iArg+1],"MULTIPOLYGON25D") )
456                eGType = wkbMultiPolygon25D;
457            else
458            {
459                fprintf( stderr, "-nlt %s: type not recognised.\n", 
460                         papszArgv[iArg+1] );
461                exit( 1 );
462            }
463            iArg++;
464        }
465        else if( (EQUAL(papszArgv[iArg],"-tg") ||
466                  EQUAL(papszArgv[iArg],"-gt")) && iArg < nArgc-1 )
467        {
468            nGroupTransactions = atoi(papszArgv[++iArg]);
469        }
470        else if( EQUAL(papszArgv[iArg],"-s_srs") && iArg < nArgc-1 )
471        {
472            pszSourceSRSDef = papszArgv[++iArg];
473        }
474        else if( EQUAL(papszArgv[iArg],"-a_srs") && iArg < nArgc-1 )
475        {
476            pszOutputSRSDef = papszArgv[++iArg];
477        }
478        else if( EQUAL(papszArgv[iArg],"-t_srs") && iArg < nArgc-1 )
479        {
480            pszOutputSRSDef = papszArgv[++iArg];
481            bTransform = TRUE;
482        }
483        else if( EQUAL(papszArgv[iArg],"-spat") 
484                 && papszArgv[iArg+1] != NULL 
485                 && papszArgv[iArg+2] != NULL 
486                 && papszArgv[iArg+3] != NULL 
487                 && papszArgv[iArg+4] != NULL )
488        {
489            OGRLinearRing  oRing;
490
491            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
492            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
493            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
494            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
495            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
496
497            poSpatialFilter = new OGRPolygon();
498            ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
499            iArg += 4;
500        }
501        else if( EQUAL(papszArgv[iArg],"-where") && papszArgv[iArg+1] != NULL )
502        {
503            pszWHERE = papszArgv[++iArg];
504        }
505        else if( EQUAL(papszArgv[iArg],"-select") && papszArgv[iArg+1] != NULL)
506        {
507            pszSelect = papszArgv[++iArg];
508            papszSelFields = CSLTokenizeStringComplex(pszSelect, " ,", 
509                                                      FALSE, FALSE );
510        }
511        else if( EQUAL(papszArgv[iArg],"-segmentize") && iArg < nArgc-1 )
512        {
513            dfMaxSegmentLength = atof(papszArgv[++iArg]);
514        }
515        else if( papszArgv[iArg][0] == '-' )
516        {
517            Usage();
518        }
519        else if( pszDestDataSource == NULL )
520            pszDestDataSource = papszArgv[iArg];
521        else if( pszDataSource == NULL )
522            pszDataSource = papszArgv[iArg];
523        else
524            papszLayers = CSLAddString( papszLayers, papszArgv[iArg] );
525    }
526#endif
527
528    if( pszDataSource == NULL )
529#ifdef ZOO_SERVICE
530        {
531#endif
532          Usage();
533#ifdef ZOO_SERVICE
534          setMapInMaps(conf,"lenv","message","Wrong parameter");
535          return SERVICE_FAILED;
536        }
537#endif
538
539/* -------------------------------------------------------------------- */
540/*      Open data source.                                               */
541/* -------------------------------------------------------------------- */
542    OGRDataSource       *poDS;
543       
544    poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE );
545
546/* -------------------------------------------------------------------- */
547/*      Report failure                                                  */
548/* -------------------------------------------------------------------- */
549    if( poDS == NULL )
550    {
551        OGRSFDriverRegistrar    *poR = OGRSFDriverRegistrar::GetRegistrar();
552       
553        fprintf( stderr, "FAILURE:\n"
554                "Unable to open datasource `%s' with the following drivers.\n",
555                pszDataSource );
556
557        for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
558        {
559            fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
560        }
561#ifdef ZOO_SERVICE
562        char tmp[1024];
563        sprintf(tmp,"Unable to open datasource `%s' with the following drivers.",pszDataSource);
564        setMapInMaps(conf,"lenv","message",tmp);
565        return SERVICE_FAILED;
566#else
567        exit( 1 );
568#endif
569    }
570
571/* -------------------------------------------------------------------- */
572/*      Try opening the output datasource as an existing, writable      */
573/* -------------------------------------------------------------------- */
574    OGRDataSource       *poODS;
575   
576    if( bUpdate )
577    {
578        poODS = OGRSFDriverRegistrar::Open( pszDestDataSource, TRUE );
579        if( poODS == NULL )
580        {
581            fprintf( stderr, "FAILURE:\n"
582                    "Unable to open existing output datasource `%s'.\n",
583                    pszDestDataSource );
584#ifdef ZOO_SERVICE
585            char tmp[1024];
586            sprintf(tmp,"Unable to open existing output datasource `%s'.",pszDestDataSource);
587            setMapInMaps(conf,"lenv","message",tmp);
588            return SERVICE_FAILED;
589#else
590        exit( 1 );
591#endif
592        }
593
594        if( CSLCount(papszDSCO) > 0 )
595        {
596            fprintf( stderr, "WARNING: Datasource creation options ignored since an existing datasource\n"
597                    "         being updated.\n" );
598        }
599    }
600
601/* -------------------------------------------------------------------- */
602/*      Find the output driver.                                         */
603/* -------------------------------------------------------------------- */
604    else
605    {
606        OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
607        OGRSFDriver          *poDriver = NULL;
608        int                  iDriver;
609
610        for( iDriver = 0;
611             iDriver < poR->GetDriverCount() && poDriver == NULL;
612             iDriver++ )
613        {
614            if( EQUAL(poR->GetDriver(iDriver)->GetName(),pszFormat) )
615            {
616                poDriver = poR->GetDriver(iDriver);
617            }
618        }
619
620        if( poDriver == NULL )
621        {
622            fprintf( stderr, "Unable to find driver `%s'.\n", pszFormat );
623            fprintf( stderr,  "The following drivers are available:\n" );
624       
625            for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
626            {
627                fprintf( stderr,  "  -> `%s'\n", poR->GetDriver(iDriver)->GetName() );
628            }
629#ifdef ZOO_SERVICE
630            char tmp[1024];
631            sprintf(tmp,"Unable to find driver `%s'.",pszFormat);
632            setMapInMaps(conf,"lenv","message",tmp);
633            return SERVICE_FAILED;
634#else
635            exit( 1 );
636#endif
637        }
638
639        if( !poDriver->TestCapability( ODrCCreateDataSource ) )
640        {
641            fprintf( stderr,  "%s driver does not support data source creation.\n",
642                    pszFormat );
643#ifdef ZOO_SERVICE
644            char tmp[1024];
645            sprintf(tmp,"%s driver does not support data source creation.",pszFormat);
646            setMapInMaps(conf,"lenv","message",tmp);
647            return SERVICE_FAILED;
648#else
649            exit( 1 );
650#endif
651        }
652
653/* -------------------------------------------------------------------- */
654/*      Create the output data source.                                  */
655/* -------------------------------------------------------------------- */
656        poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
657        if( poODS == NULL )
658        {
659            fprintf( stderr,  "%s driver failed to create %s\n", 
660                    pszFormat, pszDestDataSource );
661#ifdef ZOO_SERVICE
662            char tmp[1024];
663            sprintf(tmp,"%s driver failed to create %s",pszFormat, pszDestDataSource);
664            setMapInMaps(conf,"lenv","message",tmp);
665            return SERVICE_FAILED;
666#else
667            exit( 1 );
668#endif
669        }
670    }
671
672/* -------------------------------------------------------------------- */
673/*      Parse the output SRS definition if possible.                    */
674/* -------------------------------------------------------------------- */
675    if( pszOutputSRSDef != NULL )
676    {
677        poOutputSRS = new OGRSpatialReference();
678        if( poOutputSRS->SetFromUserInput( pszOutputSRSDef ) != OGRERR_NONE )
679        {
680            fprintf( stderr,  "Failed to process SRS definition: %s\n", 
681                    pszOutputSRSDef );
682#ifdef ZOO_SERVICE
683            char tmp[1024];
684            sprintf(tmp,"Failed to process SRS definition: %s",pszOutputSRSDef);
685            setMapInMaps(conf,"lenv","message",tmp);
686            return SERVICE_FAILED;
687#else
688            exit( 1 );
689#endif
690        }
691    }
692
693/* -------------------------------------------------------------------- */
694/*      Parse the source SRS definition if possible.                    */
695/* -------------------------------------------------------------------- */
696    if( pszSourceSRSDef != NULL )
697    {
698        poSourceSRS = new OGRSpatialReference();
699        if( poSourceSRS->SetFromUserInput( pszSourceSRSDef ) != OGRERR_NONE )
700        {
701            fprintf( stderr,  "Failed to process SRS definition: %s\n", 
702                    pszSourceSRSDef );
703#ifdef ZOO_SERVICE
704            char tmp[1024];
705            sprintf(tmp,"Failed to process SRS definition: %s",pszOutputSRSDef);
706            setMapInMaps(conf,"lenv","message",tmp);
707            return SERVICE_FAILED;
708#else
709            exit( 1 );
710#endif
711        }
712    }
713
714/* -------------------------------------------------------------------- */
715/*      Special case for -sql clause.  No source layers required.       */
716/* -------------------------------------------------------------------- */
717    if( pszSQLStatement != NULL )
718    {
719        OGRLayer *poResultSet;
720
721        if( pszWHERE != NULL )
722            fprintf( stderr,  "-where clause ignored in combination with -sql.\n" );
723        if( CSLCount(papszLayers) > 0 )
724            fprintf( stderr,  "layer names ignored in combination with -sql.\n" );
725       
726        poResultSet = poDS->ExecuteSQL( pszSQLStatement, poSpatialFilter, 
727                                        NULL );
728
729        if( poResultSet != NULL )
730        {
731            if( !TranslateLayer( poDS, poResultSet, poODS, papszLCO, 
732                                 pszNewLayerName, bTransform, poOutputSRS,
733                                 poSourceSRS, papszSelFields, bAppend, eGType,
734                                 bOverwrite, dfMaxSegmentLength ))
735            {
736                CPLError( CE_Failure, CPLE_AppDefined, 
737                          "Terminating translation prematurely after failed\n"
738                          "translation from sql statement." );
739
740                exit( 1 );
741            }
742            poDS->ReleaseResultSet( poResultSet );
743        }
744    }
745
746/* -------------------------------------------------------------------- */
747/*      Process each data source layer.                                 */
748/* -------------------------------------------------------------------- */
749    for( int iLayer = 0; 
750         pszSQLStatement == NULL && iLayer < poDS->GetLayerCount(); 
751         iLayer++ )
752    {
753        OGRLayer        *poLayer = poDS->GetLayer(iLayer);
754
755        if( poLayer == NULL )
756        {
757            fprintf( stderr, "FAILURE: Couldn't fetch advertised layer %d!\n",
758                    iLayer );
759#ifdef ZOO_SERVICE
760            char tmp[1024];
761            sprintf(tmp,"Couldn't fetch advertised layer %d!",iLayer);
762            setMapInMaps(conf,"lenv","message",tmp);
763            return SERVICE_FAILED;
764#else
765            exit( 1 );
766#endif
767        }
768
769        if( CSLCount(papszLayers) == 0
770            || CSLFindString( papszLayers,
771                              poLayer->GetLayerDefn()->GetName() ) != -1 )
772        {
773            if( pszWHERE != NULL )
774                poLayer->SetAttributeFilter( pszWHERE );
775           
776            if( poSpatialFilter != NULL )
777                poLayer->SetSpatialFilter( poSpatialFilter );
778           
779            if( !TranslateLayer( poDS, poLayer, poODS, papszLCO, 
780                                 pszNewLayerName, bTransform, poOutputSRS,
781                                 poSourceSRS, papszSelFields, bAppend, eGType,
782                                 bOverwrite, dfMaxSegmentLength ) 
783                && !bSkipFailures )
784            {
785                CPLError( CE_Failure, CPLE_AppDefined, 
786                          "Terminating translation prematurely after failed\n"
787                          "translation of layer %s (use -skipfailures to skip errors)\n", 
788                          poLayer->GetLayerDefn()->GetName() );
789
790#ifdef ZOO_SERVICE
791                char tmp[1024];
792                sprintf(tmp,"Terminating translation prematurely after failed of layer %s",poLayer->GetLayerDefn()->GetName() );
793                setMapInMaps(conf,"lenv","message",tmp);
794                return SERVICE_FAILED;
795#else
796                exit( 1 );
797#endif
798            }
799        }
800    }
801
802/* -------------------------------------------------------------------- */
803/*      Close down.                                                     */
804/* -------------------------------------------------------------------- */
805    delete poOutputSRS;
806    delete poSourceSRS;
807    delete poODS;
808    delete poDS;
809
810    CSLDestroy(papszSelFields);
811#ifndef ZOO_SERVICE
812        CSLDestroy( papszArgv );
813#endif
814    CSLDestroy( papszLayers );
815    CSLDestroy( papszDSCO );
816    CSLDestroy( papszLCO );
817
818    OGRCleanupAll();
819
820#ifdef DBMALLOC
821    malloc_dump(1);
822#endif
823   
824#ifdef ZOO_SERVICE
825    outputs->content=createMap("value",(char*)pszwebDestData);
826    return SERVICE_SUCCEEDED;
827#else
828        return 0;
829#endif
830}
831
832/************************************************************************/
833/*                               Usage()                                */
834/************************************************************************/
835
836static void Usage()
837
838{
839    OGRSFDriverRegistrar        *poR = OGRSFDriverRegistrar::GetRegistrar();
840
841#ifdef ZOO_SERVICE
842        fprintf(stderr,
843#else
844        printf(
845#endif
846                "Usage: ogr2ogr [--help-general] [-skipfailures] [-append] [-update] [-gt n]\n"
847                "               [-select field_list] [-where restricted_where] \n"
848                "               [-sql <sql statement>] \n" 
849                "               [-spat xmin ymin xmax ymax] [-preserve_fid] [-fid FID]\n"
850                "               [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def]\n"
851                "               [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]\n"
852                "               [-segmentize max_dist]\n"
853                "               dst_datasource_name src_datasource_name\n"
854                "               [-lco NAME=VALUE] [-nln name] [-nlt type] [layer [layer ...]]\n"
855                "\n"
856                " -f format_name: output file format name, possible values are:\n");
857   
858    for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
859    {
860        OGRSFDriver *poDriver = poR->GetDriver(iDriver);
861
862        if( poDriver->TestCapability( ODrCCreateDataSource ) )
863            printf( "     -f \"%s\"\n", poDriver->GetName() );
864    }
865
866#ifdef ZOO_SERVICE
867        fprintf(stderr,
868#else
869        printf(
870#endif
871                " -append: Append to existing layer instead of creating new if it exists\n"
872                " -overwrite: delete the output layer and recreate it empty\n"
873                " -update: Open existing output datasource in update mode\n"
874                " -select field_list: Comma-delimited list of fields from input layer to\n"
875                "                     copy to the new layer (defaults to all)\n" 
876                " -where restricted_where: Attribute query (like SQL WHERE)\n" 
877                " -sql statement: Execute given SQL statement and save result.\n"
878                " -skipfailures: skip features or layers that fail to convert\n"
879                " -gt n: group n features per transaction (default 200)\n"
880                " -spat xmin ymin xmax ymax: spatial query extents\n"
881                " -segmentize max_dist: maximum distance between 2 nodes.\n"
882                "                       Used to create intermediate points\n"
883                " -dsco NAME=VALUE: Dataset creation option (format specific)\n"
884                " -lco  NAME=VALUE: Layer creation option (format specific)\n"
885                " -nln name: Assign an alternate name to the new layer\n"
886                " -nlt type: Force a geometry type for new layer.  One of NONE, GEOMETRY,\n"
887                "      POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, MULTIPOINT,\n"
888                "      MULTIPOLYGON, or MULTILINESTRING.  Add \"25D\" for 3D layers.\n"
889                "      Default is type of source layer.\n" );
890
891#ifdef ZOO_SERVICE
892        fprintf(stderr,
893#else
894        printf(
895#endif
896                " -a_srs srs_def: Assign an output SRS\n"
897                " -t_srs srs_def: Reproject/transform to this SRS on output\n"
898                " -s_srs srs_def: Override source SRS\n"
899                "\n" 
900                " Srs_def can be a full WKT definition (hard to escape properly),\n"
901                " or a well known definition (ie. EPSG:4326) or a file with a WKT\n"
902                " definition.\n" );
903
904
905#ifndef ZOO_SERVICE
906        exit( 1 );
907#endif
908}
909
910/************************************************************************/
911/*                           TranslateLayer()                           */
912/************************************************************************/
913
914static int TranslateLayer( OGRDataSource *poSrcDS, 
915                           OGRLayer * poSrcLayer,
916                           OGRDataSource *poDstDS,
917                           char **papszLCO,
918                           const char *pszNewLayerName,
919                           int bTransform, 
920                           OGRSpatialReference *poOutputSRS,
921                           OGRSpatialReference *poSourceSRS,
922                           char **papszSelFields,
923                           int bAppend, int eGType, int bOverwrite,
924                           double dfMaxSegmentLength)
925               
926{
927    OGRLayer    *poDstLayer;
928    OGRFeatureDefn *poFDefn;
929    OGRErr      eErr;
930    int         bForceToPolygon = FALSE;
931    int         bForceToMultiPolygon = FALSE;
932
933    if( pszNewLayerName == NULL )
934        pszNewLayerName = poSrcLayer->GetLayerDefn()->GetName();
935
936    if( wkbFlatten(eGType) == wkbPolygon )
937        bForceToPolygon = TRUE;
938    else if( wkbFlatten(eGType) == wkbMultiPolygon )
939        bForceToMultiPolygon = TRUE;
940
941/* -------------------------------------------------------------------- */
942/*      Setup coordinate transformation if we need it.                  */
943/* -------------------------------------------------------------------- */
944    OGRCoordinateTransformation *poCT = NULL;
945
946    if( bTransform )
947    {
948        if( poSourceSRS == NULL )
949            poSourceSRS = poSrcLayer->GetSpatialRef();
950
951        if( poSourceSRS == NULL )
952        {
953            fprintf( stderr, "Can't transform coordinates, source layer has no\n"
954                    "coordinate system.  Use -s_srs to set one.\n" );
955#ifdef ZOO_SERVICE
956            return SERVICE_FAILED;
957#else
958            exit( 1 );
959#endif
960        }
961
962        CPLAssert( NULL != poSourceSRS );
963        CPLAssert( NULL != poOutputSRS );
964
965        poCT = OGRCreateCoordinateTransformation( poSourceSRS, poOutputSRS );
966        if( poCT == NULL )
967        {
968            char        *pszWKT = NULL;
969
970            fprintf( stderr, "Failed to create coordinate transformation between the\n"
971                   "following coordinate systems.  This may be because they\n"
972                   "are not transformable, or because projection services\n"
973                   "(PROJ.4 DLL/.so) could not be loaded.\n" );
974           
975            poSourceSRS->exportToPrettyWkt( &pszWKT, FALSE );
976            fprintf( stderr,  "Source:\n%s\n", pszWKT );
977           
978            poOutputSRS->exportToPrettyWkt( &pszWKT, FALSE );
979            fprintf( stderr,  "Target:\n%s\n", pszWKT );
980#ifdef ZOO_SERVICE
981            return SERVICE_FAILED;
982#else
983            exit( 1 );
984#endif
985        }
986    }
987   
988/* -------------------------------------------------------------------- */
989/*      Get other info.                                                 */
990/* -------------------------------------------------------------------- */
991    poFDefn = poSrcLayer->GetLayerDefn();
992   
993    if( poOutputSRS == NULL )
994        poOutputSRS = poSrcLayer->GetSpatialRef();
995
996/* -------------------------------------------------------------------- */
997/*      Find the layer.                                                 */
998/* -------------------------------------------------------------------- */
999    int iLayer = -1;
1000    poDstLayer = NULL;
1001
1002    for( iLayer = 0; iLayer < poDstDS->GetLayerCount(); iLayer++ )
1003    {
1004        OGRLayer        *poLayer = poDstDS->GetLayer(iLayer);
1005
1006        if( poLayer != NULL 
1007            && EQUAL(poLayer->GetLayerDefn()->GetName(),pszNewLayerName) )
1008        {
1009            poDstLayer = poLayer;
1010            break;
1011        }
1012    }
1013   
1014/* -------------------------------------------------------------------- */
1015/*      If the user requested overwrite, and we have the layer in       */
1016/*      question we need to delete it now so it will get recreated      */
1017/*      (overwritten).                                                  */
1018/* -------------------------------------------------------------------- */
1019    if( poDstLayer != NULL && bOverwrite )
1020    {
1021        if( poDstDS->DeleteLayer( iLayer ) != OGRERR_NONE )
1022        {
1023            fprintf( stderr, 
1024                     "DeleteLayer() failed when overwrite requested.\n" );
1025            return FALSE;
1026        }
1027        poDstLayer = NULL;
1028    }
1029
1030/* -------------------------------------------------------------------- */
1031/*      If the layer does not exist, then create it.                    */
1032/* -------------------------------------------------------------------- */
1033    if( poDstLayer == NULL )
1034    {
1035        if( eGType == -2 )
1036            eGType = poFDefn->GetGeomType();
1037
1038        if( !poDstDS->TestCapability( ODsCCreateLayer ) )
1039        {
1040            fprintf( stderr, 
1041              "Layer %s not found, and CreateLayer not supported by driver.", 
1042                     pszNewLayerName );
1043            return FALSE;
1044        }
1045
1046        CPLErrorReset();
1047
1048        poDstLayer = poDstDS->CreateLayer( pszNewLayerName, poOutputSRS,
1049                                           (OGRwkbGeometryType) eGType, 
1050                                           papszLCO );
1051
1052        if( poDstLayer == NULL )
1053            return FALSE;
1054
1055        bAppend = FALSE;
1056    }
1057
1058/* -------------------------------------------------------------------- */
1059/*      Otherwise we will append to it, if append was requested.        */
1060/* -------------------------------------------------------------------- */
1061    else if( !bAppend )
1062    {
1063        fprintf( stderr, "FAILED: Layer %s already exists, and -append not specified.\n"
1064                "        Consider using -append, or -overwrite.\n",
1065                pszNewLayerName );
1066        return FALSE;
1067    }
1068    else
1069    {
1070        if( CSLCount(papszLCO) > 0 )
1071        {
1072            fprintf( stderr, "WARNING: Layer creation options ignored since an existing layer is\n"
1073                    "         being appended to.\n" );
1074        }
1075    }
1076
1077/* -------------------------------------------------------------------- */
1078/*      Add fields.  Default to copy all field.                         */
1079/*      If only a subset of all fields requested, then output only      */
1080/*      the selected fields, and in the order that they were            */
1081/*      selected.                                                       */
1082/* -------------------------------------------------------------------- */
1083    int         iField;
1084
1085    if (papszSelFields && !bAppend )
1086    {
1087        for( iField=0; papszSelFields[iField] != NULL; iField++)
1088        {
1089            int iSrcField = poFDefn->GetFieldIndex(papszSelFields[iField]);
1090            if (iSrcField >= 0)
1091                poDstLayer->CreateField( poFDefn->GetFieldDefn(iSrcField) );
1092            else
1093            {
1094                fprintf( stderr, "Field '%s' not found in source layer.\n", 
1095                        papszSelFields[iField] );
1096                if( !bSkipFailures )
1097                    return FALSE;
1098            }
1099        }
1100    }
1101    else if( !bAppend )
1102    {
1103        for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
1104            poDstLayer->CreateField( poFDefn->GetFieldDefn(iField) );
1105    }
1106
1107/* -------------------------------------------------------------------- */
1108/*      Transfer features.                                              */
1109/* -------------------------------------------------------------------- */
1110    OGRFeature  *poFeature;
1111    int         nFeaturesInTransaction = 0;
1112   
1113    poSrcLayer->ResetReading();
1114
1115    if( nGroupTransactions )
1116        poDstLayer->StartTransaction();
1117
1118    while( TRUE )
1119    {
1120        OGRFeature      *poDstFeature = NULL;
1121
1122        if( nFIDToFetch != OGRNullFID )
1123        {
1124            // Only fetch feature on first pass.
1125            if( nFeaturesInTransaction == 0 )
1126                poFeature = poSrcLayer->GetFeature(nFIDToFetch);
1127            else
1128                poFeature = NULL;
1129        }
1130        else
1131            poFeature = poSrcLayer->GetNextFeature();
1132       
1133        if( poFeature == NULL )
1134            break;
1135
1136        if( ++nFeaturesInTransaction == nGroupTransactions )
1137        {
1138            poDstLayer->CommitTransaction();
1139            poDstLayer->StartTransaction();
1140            nFeaturesInTransaction = 0;
1141        }
1142
1143        CPLErrorReset();
1144        poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
1145
1146        if( poDstFeature->SetFrom( poFeature, TRUE ) != OGRERR_NONE )
1147        {
1148            if( nGroupTransactions )
1149                poDstLayer->CommitTransaction();
1150           
1151            CPLError( CE_Failure, CPLE_AppDefined,
1152                      "Unable to translate feature %ld from layer %s.\n",
1153                      poFeature->GetFID(), poFDefn->GetName() );
1154           
1155            OGRFeature::DestroyFeature( poFeature );
1156            OGRFeature::DestroyFeature( poDstFeature );
1157            return FALSE;
1158        }
1159
1160        if( bPreserveFID )
1161            poDstFeature->SetFID( poFeature->GetFID() );
1162
1163#ifndef GDAL_1_5_0
1164        if (poDstFeature->GetGeometryRef() != NULL && dfMaxSegmentLength > 0)
1165            poDstFeature->GetGeometryRef()->segmentize(dfMaxSegmentLength);
1166#endif
1167
1168        if( poCT && poDstFeature->GetGeometryRef() != NULL )
1169        {
1170            eErr = poDstFeature->GetGeometryRef()->transform( poCT );
1171            if( eErr != OGRERR_NONE )
1172            {
1173                if( nGroupTransactions )
1174                    poDstLayer->CommitTransaction();
1175
1176                fprintf( stderr, "Failed to reproject feature %d (geometry probably out of source or destination SRS).\n", 
1177                        (int) poFeature->GetFID() );
1178                if( !bSkipFailures )
1179                {
1180                    OGRFeature::DestroyFeature( poFeature );
1181                    OGRFeature::DestroyFeature( poDstFeature );
1182                    return FALSE;
1183                }
1184            }
1185        }
1186
1187        if( poDstFeature->GetGeometryRef() != NULL && bForceToPolygon )
1188        {
1189            poDstFeature->SetGeometryDirectly( 
1190                OGRGeometryFactory::forceToPolygon(
1191                    poDstFeature->StealGeometry() ) );
1192        }
1193                   
1194        if( poDstFeature->GetGeometryRef() != NULL && bForceToMultiPolygon )
1195        {
1196            poDstFeature->SetGeometryDirectly( 
1197                OGRGeometryFactory::forceToMultiPolygon(
1198                    poDstFeature->StealGeometry() ) );
1199        }
1200                   
1201        OGRFeature::DestroyFeature( poFeature );
1202
1203        CPLErrorReset();
1204        if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE
1205            && !bSkipFailures )
1206        {
1207            if( nGroupTransactions )
1208                poDstLayer->RollbackTransaction();
1209
1210            OGRFeature::DestroyFeature( poDstFeature );
1211            return FALSE;
1212        }
1213
1214        OGRFeature::DestroyFeature( poDstFeature );
1215    }
1216
1217    if( nGroupTransactions )
1218        poDstLayer->CommitTransaction();
1219
1220/* -------------------------------------------------------------------- */
1221/*      Cleaning                                                        */
1222/* -------------------------------------------------------------------- */
1223    delete poCT;
1224
1225    return TRUE;
1226}
1227
1228#ifdef ZOO_SERVICE
1229}
1230#endif
Note: See TracBrowser for help on using the repository browser.

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png