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

Last change on this file since 9 was 9, checked in by djay, 10 years ago

Update of both ZOO Kernel and ZOO Services (ogr base-vect-ops ServicesProvider?).
All the ZCFG files have been corrected to remove all references to wrong metadata (Test = Demo) to avoid validation issues.
Main Memory leaks has been removed from this version.
Addition of the Simplify Service in the C ogr base-vect-ops ServicesProvider? and addition of the Python version (without Simplify).
Update of the configure.ac and Makefile.in to follow dicussions on the mailing list and ensure to use our cgic206 and not another one, path to our cgic library is now directly in the Makefile.in file.
Accept the "-" character to name inputs, to solve issue on GRASS 7 integration.
Addition of the extension keyword for ZCFG file to be able to store resulting outputs in a file name using the extension suffix.
This version after a testing period shall be considerate as 1.0.1 version of the ZOO Project.

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