source: trunk/zoo-services/ogr/base-vect-ops/service.c @ 35

Last change on this file since 35 was 35, checked in by djay, 14 years ago

Correct use of translation function in ogr base-vect-ops Services Provider...

File size: 17.8 KB
Line 
1/**
2 * Author : Gérald FENOY
3 *
4 * Copyright 2008-2009 GeoLabs SARL. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include <libintl.h>
26#include <locale.h>
27#define _(String) dgettext ("zoo-services",String)
28
29#include "cpl_conv.h"
30#include "ogr_api.h"
31#include "ogr_geometry.h"
32#include "geos_c.h"
33#include "service.h"
34
35
36extern "C" {
37#include <libxml/tree.h>
38#include <libxml/parser.h>
39#include <libxml/xpath.h>
40#include <libxml/xpathInternals.h>
41
42#include <openssl/sha.h>
43#include <openssl/hmac.h>
44#include <openssl/evp.h>
45#include <openssl/bio.h>
46#include <openssl/buffer.h>
47
48  void printExceptionReportResponse(maps*,map*);
49  char *base64(const unsigned char *input, int length);
50
51  OGRGeometryH createGeometryFromGML(maps* conf,char* inputStr){
52    xmlInitParser();
53    xmlDocPtr doc = xmlParseMemory(inputStr,strlen(inputStr));
54    xmlChar *xmlbuff;
55    int buffersize;
56    xmlXPathContextPtr xpathCtx;
57    xmlXPathObjectPtr xpathObj;
58    char * xpathExpr="/*/*/*/*/*[local-name()='Polygon' or local-name()='MultiPolygon']";
59    xpathCtx = xmlXPathNewContext(doc);
60    xpathObj = xmlXPathEvalExpression(BAD_CAST xpathExpr,xpathCtx);
61    if(!xpathObj->nodesetval){
62      map* tmp=createMap("text","Unable to parse Input Polygon");
63      addToMap(tmp,"code","InvalidParameterValue");
64      printExceptionReportResponse(conf,tmp);
65      exit(0);
66    }
67    int size = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0;
68    /**
69     * Create a temporary XML document
70     */
71    xmlDocPtr ndoc = xmlNewDoc(BAD_CAST "1.0");
72    /**
73     * Only one polygon should be provided so we use it as the root node.
74     */
75    for(int k=size-1;k>=0;k--){ 
76      xmlDocSetRootElement(ndoc, xpathObj->nodesetval->nodeTab[k]);
77    }
78    xmlDocDumpFormatMemory(ndoc, &xmlbuff, &buffersize, 1);
79    char *tmp=(char*)calloc((xmlStrlen(xmlStrstr(xmlbuff,BAD_CAST "?>"))-1),sizeof(char));
80    sprintf(tmp,"%s",xmlStrstr(xmlbuff,BAD_CAST "?>")+2);
81    xmlXPathFreeObject(xpathObj);
82    xmlXPathFreeContext(xpathCtx);
83    xmlFree(xmlbuff);
84    xmlFreeDoc(doc);
85    xmlFreeDoc(ndoc);
86    xmlCleanupParser();
87#ifdef DEBUG
88    fprintf(stderr,"\nService internal print\n Loading the geometry from GML string ...");
89#endif
90    OGRGeometryH res=OGR_G_CreateFromGML(tmp);
91    free(tmp);
92    if(res==NULL){
93      setMapInMaps(conf,"lenv","message",_("Unable to call OGR_G_CreatFromGML"));
94      return NULL;
95    }
96    else
97      return res;
98  }
99
100  int Simplify(maps*& conf,maps*& inputs,maps*& outputs){
101    maps* cursor=inputs;
102    OGRGeometryH geometry,res;
103    double tolerance;
104    map* tmp0=getMapFromMaps(cursor,"Tolerance","value");
105    if(tmp0==NULL){
106      tolerance=atof("2.0");
107    }
108    else
109      tolerance=atof(tmp0->value);
110    fprintf(stderr,"Tolerance for Simplify %f",tolerance);
111    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
112    if(!tmp){
113      setMapInMaps(conf,"lenv","message",_("Unable to parse the input geometry from InputPolygon"));
114      return SERVICE_FAILED;
115    }
116    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
117    if(tmp1!=NULL){
118      if(strncmp(tmp1->value,"text/js",7)==0 ||
119         strncmp(tmp1->value,"application/json",16)==0)
120        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
121      else
122        geometry=createGeometryFromGML(conf,tmp->value);
123    }
124    else{
125      setMapInMaps(conf,"lenv","message",_("Unable to find any geometry for InputPolygon"));
126      return SERVICE_FAILED;
127    }
128    if(geometry==NULL){
129      setMapInMaps(conf,"lenv","message",_("Unable to parse the input geometry from InputPolygon"));
130      return SERVICE_FAILED;
131    }
132    fprintf(stderr,"Create GEOSGeometry object");
133    GEOSGeometry* ggeometry=((OGRGeometry *) geometry)->exportToGEOS();
134    GEOSGeometry* gres=GEOSTopologyPreserveSimplify(ggeometry,tolerance);
135    res=OGRGeometryFactory::createFromGEOS(gres);
136    tmp1=getMapFromMaps(outputs,"Result","mimeType");
137    if(tmp1!=NULL){
138      if(strncmp(tmp1->value,"text/js",7)==0 ||
139         strncmp(tmp1->value,"application/json",16)==0){
140        char *tmpS=OGR_G_ExportToJson(res);
141        setMapInMaps(outputs,"Result","value",tmpS);
142        setMapInMaps(outputs,"Result","mimeType","text/plain");
143        setMapInMaps(outputs,"Result","encoding","UTF-8");
144        free(tmpS);
145      }
146      else{
147        char *tmpS=OGR_G_ExportToGML(res);
148        setMapInMaps(outputs,"Result","value",tmpS);
149        setMapInMaps(outputs,"Result","mimeType","text/xml");
150        setMapInMaps(outputs,"Result","encoding","UTF-8");
151        setMapInMaps(outputs,"Result","schema","http://fooa/gml/3.1.0/polygon.xsd");
152        free(tmpS);
153      }
154    }else{
155      char *tmpS=OGR_G_ExportToJson(tmp->value);
156      setMapInMaps(outputs,"Result","value",tmpS);
157      setMapInMaps(outputs,"Result","mimeType","text/plain");
158      setMapInMaps(outputs,"Result","encoding","UTF-8");
159      free(tmpS);
160    }
161    outputs->next=NULL;
162    //GEOSFree(ggeometry);
163    //GEOSFree(gres);
164    OGR_G_DestroyGeometry(res);
165    OGR_G_DestroyGeometry(geometry);
166    return SERVICE_SUCCEEDED;
167  }
168
169
170  int applyOne(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometryH (*myFunc)(OGRGeometryH)){
171#ifdef DEBUG
172    fprintf(stderr,"\nService internal print\n");
173#endif
174    maps* cursor=inputs;
175    OGRGeometryH geometry,res;
176#ifdef DEBUG
177    dumpMaps(cursor);
178#endif
179    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
180    if(!tmp){
181      setMapInMaps(conf,"lenv","message",_("Unable to parse the input geometry from InputPolygon"));
182      return SERVICE_FAILED;
183    }
184    fprintf(stderr,"Service internal print \n");
185    dumpMaps(inputs);
186    fprintf(stderr,"/Service internal print \n");
187    map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
188    fprintf(stderr,"Service internal print \n");
189    dumpMap(tmp1);
190    fprintf(stderr,"/Service internal print \n");
191    if(tmp1!=NULL){
192      if(strncmp(tmp1->value,"text/js",7)==0 ||
193         strncmp(tmp1->value,"application/json",7)==0)
194        geometry=OGR_G_CreateGeometryFromJson(tmp->value);
195      else
196        geometry=createGeometryFromGML(conf,tmp->value);
197    }
198    else
199      geometry=createGeometryFromGML(conf,tmp->value);
200    if(geometry==NULL){
201      setMapInMaps(conf,"lenv","message",_("Unable to parse the input geometry from InputPolygon"));
202      return SERVICE_FAILED;
203    }
204    res=(*myFunc)(geometry);
205    fprintf(stderr,"Service internal print \n");
206    dumpMaps(outputs);
207    fprintf(stderr,"/Service internal print \n");
208    map *tmp_2=getMapFromMaps(outputs,"Result","mimeType");
209    fprintf(stderr,"Service internal print \n");
210    dumpMap(tmp_2);
211    fprintf(stderr,"/Service internal print \n");
212    if(tmp_2!=NULL){
213      if(strncmp(tmp_2->value,"text/js",7)==0 ||
214         strncmp(tmp_2->value,"application/json",16)==0){
215        char *tmpS=OGR_G_ExportToJson(res);
216        setMapInMaps(outputs,"Result","value",tmpS);
217        setMapInMaps(outputs,"Result","mimeType","text/plain");
218        setMapInMaps(outputs,"Result","encoding","UTF-8");
219        free(tmpS);
220      }
221      else{
222        char *tmpS=OGR_G_ExportToGML(res);
223        setMapInMaps(outputs,"Result","value",tmpS);
224        setMapInMaps(outputs,"Result","mimeType","text/plain");
225        setMapInMaps(outputs,"Result","encoding","UTF-8");
226        free(tmpS);
227
228      }
229    }else{
230      char *tmpS=OGR_G_ExportToJson(res);
231      setMapInMaps(outputs,"Result","value",tmpS);
232      setMapInMaps(outputs,"Result","mimeType","text/plain");
233      setMapInMaps(outputs,"Result","encoding","UTF-8");
234      free(tmpS);
235    }
236    outputs->next=NULL;
237#ifdef DEBUG
238    dumpMaps(outputs);
239    fprintf(stderr,"\nService internal print\n===\n");
240#endif
241    OGR_G_DestroyGeometry(res);
242    OGR_G_DestroyGeometry(geometry);
243    //CPLFree(res);
244    //CPLFree(geometry);
245    fprintf(stderr,"Service internal print \n");
246    dumpMaps(outputs);
247    fprintf(stderr,"/Service internal print \n");
248    return SERVICE_SUCCEEDED;
249  }
250
251#ifdef WIN32
252  __declspec(dllexport)
253#endif
254int Buffer(maps*& conf,maps*& inputs,maps*& outputs){
255   OGRGeometryH geometry,res;
256   map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
257   if(tmp==NULL){
258     setMapInMaps(conf,"lenv","message",_("Unable to fetch input geometry"));
259     return SERVICE_FAILED;
260   }else
261     if(strlen(tmp->value)<=0){
262       setMapInMaps(conf,"lenv","message",_("Unable to fetch input geometry"));
263       return SERVICE_FAILED;
264     }
265   map* tmp1=getMapFromMaps(inputs,"InputPolygon","mimeType");
266   if(strncmp(tmp1->value,"application/json",16)==0)
267     geometry=OGR_G_CreateGeometryFromJson(tmp->value);
268   else
269     geometry=createGeometryFromGML(conf,tmp->value);
270   if(geometry==NULL){
271     setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry"));
272     return SERVICE_FAILED;
273   }
274   double bufferDistance;
275   tmp=getMapFromMaps(inputs,"BufferDistance","value");
276   if(tmp==NULL){
277     bufferDistance=atof("10.0");
278   }
279   else
280     bufferDistance=atof(tmp->value);
281   res=OGR_G_Buffer(geometry,bufferDistance,30);
282   tmp1=getMapFromMaps(outputs,"Result","mimeType");
283   if(strncmp(tmp1->value,"application/json",16)==0){
284     char *tmpS=OGR_G_ExportToJson(res);
285     setMapInMaps(outputs,"Result","value",tmpS);
286     setMapInMaps(outputs,"Result","mimeType","text/plain");
287     setMapInMaps(outputs,"Result","encoding","UTF-8");
288     free(tmpS);
289   }
290   else{
291     char *tmpS=OGR_G_ExportToGML(res);
292     setMapInMaps(outputs,"Result","value",tmpS);
293     free(tmpS);
294     setMapInMaps(outputs,"Result","mimeType","text/xml");
295     setMapInMaps(outputs,"Result","encoding","UTF-8");
296     setMapInMaps(outputs,"Result","schema","http://fooa/gml/3.1.0/polygon.xsd");
297   }
298   outputs->next=NULL;
299   OGR_G_DestroyGeometry(geometry);
300   OGR_G_DestroyGeometry(res);
301   return SERVICE_SUCCEEDED;
302}
303
304#ifdef WIN32
305  __declspec(dllexport)
306#endif
307  int Boundary(maps*& conf,maps*& inputs,maps*& outputs){
308    return applyOne(conf,inputs,outputs,&OGR_G_GetBoundary);
309  }
310
311#ifdef WIN32
312  __declspec(dllexport)
313#endif
314  int ConvexHull(maps*& conf,maps*& inputs,maps*& outputs){
315    return applyOne(conf,inputs,outputs,&OGR_G_ConvexHull);
316  }
317
318
319  OGRGeometryH MY_OGR_G_Centroid(OGRGeometryH hTarget){
320    OGRGeometryH res;
321    res=OGR_G_CreateGeometryFromJson("{\"type\": \"Point\", \"coordinates\": [0,0] }");
322    OGRwkbGeometryType gtype=OGR_G_GetGeometryType(hTarget);
323    if(gtype!=wkbPolygon){
324      hTarget=OGR_G_ConvexHull(hTarget);
325    }
326    int c=OGR_G_Centroid(hTarget,res);
327    return res;
328  }
329
330#ifdef WIN32
331  __declspec(dllexport)
332#endif
333  int Centroid(maps*& conf,maps*& inputs,maps*& outputs){
334    return applyOne(conf,inputs,outputs,&MY_OGR_G_Centroid);
335  }
336
337  int applyTwo(maps*& conf,maps*& inputs,maps*& outputs,OGRGeometryH (*myFunc)(OGRGeometryH,OGRGeometryH)){
338#ifdef DEBUG
339    fprintf(stderr,"\nService internal print1\n");
340    fflush(stderr);
341#endif
342    fprintf(stderr,"\nService internal print1\n");
343    dumpMaps(inputs);
344    fprintf(stderr,"\nService internal print1\n");
345
346    maps* cursor=inputs;
347    OGRGeometryH geometry1,geometry2;
348    OGRGeometryH res;
349    {
350      map* tmp=getMapFromMaps(inputs,"InputEntity1","value");
351      map* tmp1=getMapFromMaps(inputs,"InputEntity1","mimeType");
352      if(tmp1!=NULL){
353        if(strncmp(tmp1->value,"application/json",16)==0)
354          geometry1=OGR_G_CreateGeometryFromJson(tmp->value);
355        else
356          geometry1=createGeometryFromGML(conf,tmp->value);
357      }
358      else
359        geometry1=createGeometryFromGML(conf,tmp->value);
360    }
361    if(geometry1==NULL){
362      setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry for InputEntity1."));
363      fprintf(stderr,"SERVICE FAILED !\n");
364      return SERVICE_FAILED;
365    }
366    fprintf(stderr,"\nService internal print1 InputEntity1\n");
367    {
368      map* tmp=getMapFromMaps(inputs,"InputEntity2","value");
369      map* tmp1=getMapFromMaps(inputs,"InputEntity2","mimeType");
370      //#ifdef DEBUG
371      fprintf(stderr,"MY MAP \n[%s] - %i\n",tmp1->value,strncmp(tmp1->value,"application/json",16));
372      //dumpMap(tmp);
373      fprintf(stderr,"MY MAP\n");
374      ///#endif
375      fprintf(stderr,"\nService internal print1 InputEntity2\n");
376      if(tmp1!=NULL){
377        if(strncmp(tmp1->value,"application/json",16)==0){
378          fprintf(stderr,"\nService internal print1 InputEntity2 as JSON\n");
379          geometry2=OGR_G_CreateGeometryFromJson(tmp->value);
380        }
381        else{
382          fprintf(stderr,"\nService internal print1 InputEntity2 as GML\n");
383          geometry2=createGeometryFromGML(conf,tmp->value);
384        }
385      }
386      else
387        geometry2=createGeometryFromGML(conf,tmp->value);
388      fprintf(stderr,"\nService internal print1 InputEntity2 PreFinal\n");
389    }
390    fprintf(stderr,"\nService internal print1 InputEntity2 Final\n");
391    if(geometry2==NULL){
392      setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry for InputEntity2."));
393      fprintf(stderr,"SERVICE FAILED !\n");
394      return SERVICE_FAILED;
395    }
396    fprintf(stderr,"\nService internal print1\n");
397    res=(*myFunc)(geometry1,geometry2);
398    fprintf(stderr,"\nService internal print1\n");
399    char *tmpS=OGR_G_ExportToJson(res);
400    setMapInMaps(outputs,"Result","value",tmpS);
401    setMapInMaps(outputs,"Result","mimeType","text/plain");
402    setMapInMaps(outputs,"Result","encoding","UTF-8");
403    free(tmpS);
404    OGR_G_DestroyGeometry(geometry1);
405    OGR_G_DestroyGeometry(geometry2);
406    OGR_G_DestroyGeometry(res);
407    return SERVICE_SUCCEEDED;
408  }
409 
410#ifdef WIN32
411  __declspec(dllexport)
412#endif
413  int Difference(maps*& conf,maps*& inputs,maps*& outputs){
414    return applyTwo(conf,inputs,outputs,&OGR_G_Difference);
415  }
416
417#ifdef WIN32
418  __declspec(dllexport)
419#endif
420  int SymDifference(maps*& conf,maps*& inputs,maps*& outputs){
421    return applyTwo(conf,inputs,outputs,&OGR_G_SymmetricDifference);
422  }
423
424#ifdef WIN32
425  __declspec(dllexport)
426#endif
427  int Intersection(maps*& conf,maps*& inputs,maps*& outputs){
428    return applyTwo(conf,inputs,outputs,&OGR_G_Intersection);
429  }
430
431#ifdef WIN32
432  __declspec(dllexport)
433#endif
434  int Union(maps*& conf,maps*& inputs,maps*& outputs){
435    return applyTwo(conf,inputs,outputs,&OGR_G_Union);
436  }
437
438#ifdef WIN32
439  __declspec(dllexport)
440#endif
441  int Distance(maps*& conf,maps*& inputs,maps*& outputs){
442#ifdef DEBUG
443    fprintf(stderr,"\nService internal print1\n");
444#endif
445    fflush(stderr);
446    maps* cursor=inputs;
447    OGRGeometryH geometry1,geometry2;
448    double res;
449    {
450      map* tmp=getMapFromMaps(inputs,"InputEntity1","value");
451      map* tmp1=getMapFromMaps(inputs,"InputEntity1","mimeType");
452#ifdef DEBUG
453      fprintf(stderr,"MY MAP\n");
454      dumpMap(tmp1);
455      dumpMaps(inputs);
456      fprintf(stderr,"MY MAP\n");
457#endif
458      if(tmp1!=NULL){
459        if(strncmp(tmp1->value,"application/json",16)==0)
460          geometry1=OGR_G_CreateGeometryFromJson(tmp->value);
461        else
462          geometry1=createGeometryFromGML(conf,tmp->value);
463      }
464      else
465        geometry1=createGeometryFromGML(conf,tmp->value);
466    }
467    if(geometry1==NULL){
468      setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry for InputEntity1."));
469      fprintf(stderr,"SERVICE FAILED !\n");
470      return SERVICE_FAILED;
471    }
472    {
473      map* tmp=getMapFromMaps(inputs,"InputEntity2","value");
474      map* tmp1=getMapFromMaps(inputs,"InputEntity2","mimeType");
475#ifdef DEBUG
476      fprintf(stderr,"MY MAP\n");
477      dumpMap(tmp1);
478      dumpMaps(inputs);
479      fprintf(stderr,"MY MAP\n");
480#endif
481      if(tmp1!=NULL){
482        if(strncmp(tmp1->value,"application/json",16)==0)
483          geometry2=OGR_G_CreateGeometryFromJson(tmp->value);
484        else
485          geometry2=createGeometryFromGML(conf,tmp->value);
486      }
487      else
488        geometry2=createGeometryFromGML(conf,tmp->value);
489    }
490    if(geometry2==NULL){
491      setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry for InputEntity2."));
492      fprintf(stderr,"SERVICE FAILED !\n");
493      return SERVICE_FAILED;
494    }
495    res=OGR_G_Distance(geometry1,geometry2);   
496    char tmpres[100];
497    sprintf(tmpres,"%d",res);
498    setMapInMaps(outputs,"Distance","value",tmpres);
499    setMapInMaps(outputs,"Distance","dataType","float");
500#ifdef DEBUG
501    dumpMaps(outputs);
502    fprintf(stderr,"\nService internal print\n===\n");
503#endif
504    return SERVICE_SUCCEEDED;
505  }
506
507#ifdef WIN32
508  __declspec(dllexport)
509#endif
510  int GetArea(maps*& conf,maps*& inputs,maps*& outputs){
511    fprintf(stderr,"GETAREA \n");
512    double res;
513    /**
514     * Extract Geometry from the InputPolygon value
515     */
516    OGRGeometryH geometry;
517    map* tmp=getMapFromMaps(inputs,"InputPolygon","value");
518    if(tmp==NULL){
519      setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry from InputPolygon"));
520      return SERVICE_FAILED;
521    }
522    fprintf(stderr,"geometry creation %s \n",tmp->value);
523    geometry=createGeometryFromGML(conf,tmp->value);
524    if(geometry==NULL){
525      setMapInMaps(conf,"lenv","message",_("Unable to parse input geometry from InputPolygon"));
526      return SERVICE_FAILED;
527    }
528    fprintf(stderr,"geometry created %s \n",tmp->value);
529    res=OGR_G_GetArea(geometry);
530    fprintf(stderr,"area %d \n",res);
531    /**
532     * Filling the outputs
533     */
534    char tmp1[100];
535    sprintf(tmp1,"%d",res);
536    setMapInMaps(outputs,"Area","value",tmp1);
537    setMapInMaps(outputs,"Area","dataType","float");
538#ifdef DEBUG
539    dumpMaps(outputs);
540#endif
541    return SERVICE_SUCCEEDED;
542  }
543
544}
Note: See TracBrowser for help on using the repository browser.

Search

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