source: trunk/zoo-project/zoo-kernel/service_internal_saga.c @ 938

Last change on this file since 938 was 917, checked in by djay, 6 years ago

Merge prototype-v0 branch in trunk

  • Property svn:keywords set to Id
File size: 35.8 KB
RevLine 
[634]1/*
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2015 GeoLabs SARL
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 <stdlib.h>
26#include <limits.h>
[637]27#include <locale.h>
28#include <wx/string.h>
29#include <wx/app.h>
30#include <api_core.h>
31#include <data_manager.h>
[917]32#include <saga_api.h>
[637]33#define _ZOO_SAGA
[634]34#include "service_internal_saga.h"
[640]35#include "server_internal.h"
[634]36#include "mimetypes.h"
37
38/**
[637]39 * Global SAGA-GIS output counter
40 */
41int sagaOutputCounter=0;
42
43/**
[634]44 * Observer used to access the ongoing status of a running OTB Application
45 */
46class SagaWatcher
47{
48 public:
49  static int Callback(TSG_UI_Callback_ID ID, CSG_UI_Parameter &Param_1, CSG_UI_Parameter &Param_2);
50  /**
51   * Define the message value
52   *
53   * @param conf the maps pointer to copy
54   */
55  static void SetMessage(const char *mess)
56  {
57    FreeMessage();
58    message=zStrdup(mess);
59  }
60  /**
61   * Free the message value
62   *
63   */
64  static void FreeMessage()
65  {
66    if(message!=NULL)
67      free(message);
68    message=NULL;
69  }
70  /**
71   * Copy the original conf in the m_conf property
72   *
73   * @param conf the maps pointer to copy
74   */
75  void SetConf(maps **conf)
76  {
77    m_conf=dupMaps(conf);
78  }
79  /** 
80   * Get Configuration maps (m_conf)
81   * @return the m_conf property
82   */
83  const maps& GetConf()
84  {
85    return *m_conf;
86  }
87  /** 
88   * Free Configuration maps (m_Conf)
89   */
90  void FreeConf(){
91    freeMaps(&m_conf);
92    free(m_conf);
93  }
94 private:
95  /** Main conf maps */
96  static maps* m_conf;
97  /** Status */
98  static int status;
99  /** Message */
100  static char* message;
101};
102
103maps* SagaWatcher::m_conf;
[652]104char* SagaWatcher::message=zStrdup("No message left");
[634]105int SagaWatcher::status=1;
106
107/**
108 * The callback function called at any SAGA-GIS module step
109 *
110 * @param id a TSG_UI_Callback_ID as defined in api_core.h (line 1290)
111 * @param param1
112 * @param param2
113 */
114int
115SagaWatcher::
116Callback(TSG_UI_Callback_ID id, CSG_UI_Parameter &param1, CSG_UI_Parameter &param2)
117{
118
119  int res = 1;
120  switch( id )
121    {
122    default:
[652]123      return 0;
[634]124      break;
125
[652]126    case CALLBACK_DLG_ERROR:
127      return 1;
[634]128      break;
129
[652]130    case CALLBACK_DLG_PARAMETERS:
[634]131    case CALLBACK_PROCESS_SET_OKAY:
[652]132    case CALLBACK_DATAOBJECT_COLORS_GET:
133    case CALLBACK_DATAOBJECT_COLORS_SET:
134    case CALLBACK_DATAOBJECT_PARAMS_GET:
135    case CALLBACK_DATAOBJECT_PARAMS_SET:
136    case CALLBACK_DATAOBJECT_UPDATE:
137    case CALLBACK_DATAOBJECT_SHOW:
138    case CALLBACK_DLG_CONTINUE:
139    case CALLBACK_PROCESS_SET_READY:
[653]140    case CALLBACK_PROCESS_GET_OKAY:
141      return res;
[634]142      break;
143
144    case CALLBACK_PROCESS_SET_PROGRESS:
145      {
146        int cPercent= param2.Number != 0.0 ? 1 + (int)(100.0 * param1.Number / param2.Number) : 100 ;
147        if( cPercent != status ){
148          status=cPercent;
[653]149        }else
150          return res;
[634]151      }
152      break;
153
154    case CALLBACK_PROCESS_SET_TEXT:
155      SetMessage(param1.String.b_str());
156      break;
157
158    case CALLBACK_MESSAGE_ADD:
159      SetMessage(param1.String.b_str());
160      break;
161
162    case CALLBACK_MESSAGE_ADD_ERROR:
163      SetMessage(param1.String.b_str());
164      break;
165
166    case CALLBACK_MESSAGE_ADD_EXECUTION:
167      SetMessage(param1.String.b_str());
168      break;
169
170    case CALLBACK_DLG_MESSAGE:
171      SetMessage((param2.String + ": " + param1.String).b_str());
172      break;
173
174    case CALLBACK_DATAOBJECT_ADD:
175      if(SG_Get_Data_Manager().Add((CSG_Data_Object *)param1.Pointer))
176        res = 1 ;
177      else
178        res = 0;
[653]179      return res;
[634]180      break;
181
182    }
183  updateStatus(m_conf,status,message);
184  return( res );
185}
186
[636]187TSG_PFNC_UI_Callback Get_Callback (SagaWatcher watcher){
[634]188  return( &(watcher.Callback) );
189}
190
191
192/**
193 * Get the default file extension for SAGA-GIS parameter type.
194 * Extensions are the following:
195 *  - sgrd for grid and data_object
196 *  - shp for shapes and tin
197 *  - csv for tables
198 *  - spc for points
199 *
200 * @param param a SAGA-GIS Parameter
201 */ 
202const char* sagaGetDefaultExt(CSG_Parameter* param){
203  if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid"))
204     || CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("data_object"))){
205    return "sgrd";
206  }
207  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes")) ||
208          CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
209    return "shp";
210  }
211  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
212    return "csv";
213  }
214  else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("points"))){
215    return "spc";
216  }
217  return "unknown";
218}
219
220/**
221 * Load a datasource in the SAGA-GIS Data Manager.
222 *
223 * @param param a SAGA-GIS Parameter
224 * @param arg the arguments map passed to a SAGA-GIS module
225 * @return false on failure, true in case of success
226 */
227bool sagaLoadInput(CSG_Parameter* param,map* arg){
228  if(!param->is_Input() || !param->is_Enabled()){
229    return true;
230  }
231  map* carg=getMap(arg,CSG_String(param->Get_Identifier()).b_str());
232  if(carg!=NULL){
233    wxString fileName(carg->value);
234    if(param->is_DataObject()){
235      // In case it there is a single datasource
236      if(!SG_Get_Data_Manager().Find(&fileName) && !SG_Get_Data_Manager().Add(&fileName) && !param->is_Optional() ){
237        return false;
238      }
[917]239      fprintf(stderr,"%s %s\n",carg->name,carg->value);
240      fflush(stderr);
241      return( param->Set_Value(SG_Get_Data_Manager().Find(&fileName,false)) );
[634]242    }
243    else
244      if(param->is_DataObject_List()){
245        // In case there are multiple datasources
246        param->asList()->Del_Items();
247        wxString fileNames(fileName);
248        while( fileNames.Length() > 0 ){
249          fileName = fileNames.BeforeFirst(';').Trim(false);
250          fileNames = fileNames.AfterFirst (';');           
251          if( !SG_Get_Data_Manager().Find(&fileName) ){
252            SG_Get_Data_Manager().Add(&fileName);
253          }
[917]254          param->asList()->Add_Item(SG_Get_Data_Manager().Find(&fileName,false));
[634]255        }
256      }
257  }
258  return true;
259}
260
261/**
262 * Extract all SAGA-GIS parameters from a parameters list and set its values to
263 * the one defined in the map.
264 *
265 * @parap params the parameters list
266 * @parap argument the argument map containing the value to use
267 * @return true in success, false in other case
268 */
269bool sagaSetParameters(CSG_Parameters *params,map* argument){
270
271  int pc=params->Get_Count();
272  params->Restore_Defaults();
273
274  for(int k=0;k<pc;k++){
275    CSG_Parameter * param=params->Get_Parameter(k);
276    if( param->is_Output() ){
277      map* omap=getMap(argument,CSG_String(param->Get_Identifier()).b_str());
278      if( param->is_DataObject() && param->is_Optional() && !param->asDataObject() && omap!=NULL){
279        param->Set_Value(DATAOBJECT_CREATE);
280      }
281    }
282    else
283      if( param->is_Option() && !param->is_Information() ){
284        map* inmap=getMap(argument,CSG_String(param->Get_Identifier()).b_str());
285        if(inmap!=NULL){
286            switch( param->Get_Type() ){
287            case PARAMETER_TYPE_Bool:
288              if(strncasecmp(inmap->value,"true",4)==0 || strncasecmp(inmap->value,"1",1)==0){
289                param->Set_Value(1);
290              }else
291                param->Set_Value(0);
292              break;
293            case PARAMETER_TYPE_Parameters:
294              // TODO: nested inputs gesture
295              break;
296            case PARAMETER_TYPE_Int:
297              param->Set_Value((int)strtol(inmap->value,NULL,10));
298              break;
299            case PARAMETER_TYPE_Double:
300            case PARAMETER_TYPE_Degree:
301              param->Set_Value((double)strtod(inmap->value,NULL));
302              break;
303            case PARAMETER_TYPE_String:
304              param->Set_Value(CSG_String(inmap->value));
305              break;
306            case PARAMETER_TYPE_FilePath:
307              param->Set_Value(CSG_String(inmap->value));
308              break;
309            case PARAMETER_TYPE_FixedTable:
310              {
311                CSG_Table Table(inmap->value);
312                param->asTable()->Assign_Values(&Table);
313              }
314              break;
315            case PARAMETER_TYPE_Choice:
316              {
317                int val=(int)strtol(inmap->value,(char**)NULL,10);
318                if(val==0 && strncasecmp(inmap->value,"0",1)!=0)
319                  param->Set_Value(CSG_String(inmap->value));
320                else
321                  param->Set_Value(val);
322              }
323              break;
324            default:
325              break;
326            }
327        }else{
328          if(param->Get_Type()==PARAMETER_TYPE_Range){
329            inmap=getMap(argument,(CSG_String(param->Get_Identifier())+"_MIN").b_str());
330            if(inmap!=NULL)
[917]331#if SAGA_MAJOR_VERSION == 2           
[634]332              param->asRange()->Set_LoVal(strtod(inmap->value,NULL));
[917]333#else
334              param->asRange()->Set_Min(strtod(inmap->value,NULL));
335#endif     
[634]336            inmap=getMap(argument,(CSG_String(param->Get_Identifier())+"_MAX").b_str());
337            if(inmap!=NULL)
[917]338#if SAGA_MAJOR_VERSION == 2           
[634]339              param->asRange()->Set_HiVal(strtod(inmap->value,NULL));       
[917]340#else
341              param->asRange()->Set_Max(strtod(inmap->value,NULL));
342#endif     
[634]343          }
344          if(inmap==NULL){
345            param->Restore_Default();
346          }
347        }
348      }
349  }
350
351  for(int k=0;k<pc;k++){
352    CSG_Parameter * param=params->Get_Parameter(k);
353    if( param->is_Input() )
354      if(!sagaLoadInput(param,argument)){
355        fprintf(stderr,"%s %d \n",__FILE__,__LINE__);
356        return false;
357      }
358  }
359  return true;
360}
361
362/**
363 * Save all values outputed by a SAGA-GIS module invocation to files
364 *
365 * @param params the parameters list
366 * @param main_conf the conf maps containing the main.cfg settings
367 * @param outputs the maps to set the generated_file for each output
368 */
369bool sagaSaveOutputs(CSG_Parameters *params,maps* main_conf,maps** outputs)
370{
371  for(int j=0; j<params->Get_Count(); j++)
372    {
373      CSG_Parameter *param = params->Get_Parameter(j);
374      maps* cMaps=getMaps(*outputs,CSG_String(param->Get_Identifier()).b_str());
375      // Specific TIN case
376      if(cMaps==NULL && CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin")))
377        cMaps=getMaps(*outputs,(CSG_String(param->Get_Identifier())+"_POINTS").b_str());
378      if(cMaps!=NULL){
379        map* tmpPath=getMapFromMaps(main_conf,"main","tmpPath");
380        map* sid=getMapFromMaps(main_conf,"lenv","usid");
381        const char *file_ext=sagaGetDefaultExt(param);
382
383        if( param->is_Input() )
384          {
385            if( param->is_DataObject() )
386              {
387                CSG_Data_Object *pObject = param->asDataObject();
388               
389                if( pObject && pObject->is_Modified() && SG_File_Exists(pObject->Get_File_Name()) )
390                  {
391                    pObject->Save(pObject->Get_File_Name());
392                    addToMap(cMaps->content,"generated_file",CSG_String(pObject->Get_File_Name()).b_str());
393                  }
394              }
395           
396            else if( param->is_DataObject_List() )
397              {
[917]398                for(int i=0; i<
399#if SAGA_MAJOR_VERSION == 2
400                      param->asList()->Get_Count()
401#else
402                      param->asList()->Get_Data_Count()
403#endif               
404                      ; i++)
[634]405                  {
[917]406                    CSG_Data_Object *pObject =
407#if SAGA_MAJOR_VERSION == 2                   
408                      param->asList()->asDataObject(i)
409#else
410                      param->asList()->Get_Data(i)
411#endif               
412                      ;
[634]413                   
414                    if( pObject->is_Modified() && SG_File_Exists(pObject->Get_File_Name()) )
415                      {
416                        pObject->Save(pObject->Get_File_Name());
417                        setMapArray(cMaps->content,"generated_file",i,CSG_String(pObject->Get_File_Name()).b_str());
418                      }
419                  }
420              }
421          }
422        else
423          if( param->is_Output() )
424            {
425              char *realFileName=(char*)malloc((strlen(file_ext)+strlen(sid->value)+strlen(cMaps->name)+14)*sizeof(char));
426              char *fullFileName=(char*)malloc((strlen(file_ext)+strlen(sid->value)+strlen(cMaps->name)+strlen(tmpPath->value)+16)*sizeof(char));
[639]427              sprintf(realFileName,"Output_%s_%s_%d",cMaps->name,sid->value,sagaOutputCounter);
428              sprintf(fullFileName,"%s/Output_%s_%s_%d.%s",tmpPath->value,cMaps->name,sid->value,sagaOutputCounter,file_ext);
[634]429              sagaOutputCounter+=1;
430              wxString fileName(fullFileName);
431              addToMap(cMaps->content,"generated_name",realFileName);
432              free(realFileName);
433              free(fullFileName);
434
435              if( param->is_DataObject() )
436                {
437                  if( param->asDataObject() )
438                    {
439                      param->asDataObject()->Save(&fileName);
440                      addToMap(cMaps->content,"generated_file",CSG_String(param->asDataObject()->Get_File_Name()).b_str());
441                    }
442                }
443           
444              else if( param->is_DataObject_List() )
445                {
446                  CSG_Strings   fileNames;
447               
448                  while( fileName.Length() > 0 )
449                    {
[636]450                      CSG_String current_file(&fileName);
451                      current_file = current_file.BeforeFirst(';');
452                      if( current_file.Length() > 0 )
[634]453                        {
[636]454                          fileNames += current_file;
455                          fileName = fileName.AfterFirst(';');
[634]456                        }
457                      else
458                        {
[636]459                          fileNames += &fileName;
460                          fileName.Clear();
[634]461                        }
462                    }
[917]463#if SAGA_MAJOR_VERSION == 2               
[634]464                  int nFileNames = param->asList()->Get_Count() <= fileNames.Get_Count() ? fileNames.Get_Count() : fileNames.Get_Count() - 1;
465                  for(int i=0; i<param->asList()->Get_Count(); i++)
466                    {
467                      if( i < nFileNames )
468                        {
469                          param->asList()->asDataObject(i)->Save(fileNames[i]);
470                        }
471                      else
472                        {
473                          param->asList()->asDataObject(i)->Save(CSG_String::Format(SG_T("%s_%0*d"),
474                                                                                    fileNames[fileNames.Get_Count() - 1].c_str(),
475                                                                                    SG_Get_Digit_Count(param->asList()->Get_Count()),
476                                                                                    1 + i - nFileNames
477                                                                                    ));
478                        }
479                      setMapArray(cMaps->content,"generated_file",i,
480                                  CSG_String(param->asList()->asDataObject(i)->Get_File_Name()).b_str());
481                    }
[917]482#else
483                  int nFileNames = param->asList()->Get_Data_Count() <= fileNames.Get_Count() ? fileNames.Get_Count() : fileNames.Get_Count() - 1;
484                  for(int i=0; i<param->asList()->Get_Data_Count(); i++)
485                    {
486                      if( i < nFileNames )
487                        {
488                          param->asList()->Get_Data(i)->Save(fileNames[i]);
489                        }
490                      else
491                        {
492                          param->asList()->Get_Data(i)->Save(CSG_String::Format(SG_T("%s_%0*d"),
493                                                                                    fileNames[fileNames.Get_Count() - 1].c_str(),
494                                                                                    SG_Get_Digit_Count(param->asList()->Get_Data_Count()),
495                                                                                    1 + i - nFileNames
496                                                                                    ));
497                        }
498                      setMapArray(cMaps->content,"generated_file",i,
499                                  CSG_String(param->asList()->Get_Data(i)->Get_File_Name()).b_str());
500                    }
501                 
502#endif           
[634]503                }
504            }
505      }
[636]506    }
[634]507  return( true );
508}
509
510/**
511 * Invoke the execution of a SAGA-GIS module.
512 *
513 * @param main_conf the conf maps containing the main.cfg settings
514 * @param lib_name the SAGA-GIS library name
515 * @param module_name the SAGA-GIS module name
516 * @param arguments the map containing the arguments to pass to the module
517 * @param outputs default to NULL, contains the maps to fill with the result
518 */
519int sagaExecuteCmd(maps** main_conf,const char* lib_name,const char* module_name,map* arguments,maps** outputs=NULL){
520  int res=SERVICE_FAILED;
521
[917]522#if SAGA_MAJOR_VERSION == 2 
[634]523  CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(CSG_String(lib_name),true);
[917]524#else
525  CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(CSG_String(lib_name),true);
526#endif 
[634]527  if( library == NULL){
528    char tmp[255];
529    sprintf(tmp,"Counld not load the %s SAGA library",lib_name);
530    setMapInMaps(*main_conf,"lenv","message",tmp);
531    res=SERVICE_FAILED;
532    return res;
533  }
534
[917]535#if SAGA_MAJOR_VERSION == 2 
[634]536  CSG_Module * module=library->Get_Module(atoi(module_name));
[917]537#else
538  CSG_Tool * module=library->Get_Tool(atoi(module_name));
539#endif 
[634]540  if(module == NULL){
541    char tmp[255];
542    sprintf(tmp,"Counld not load the %s module from the %s SAGA library",module_name,lib_name);
543    setMapInMaps(*main_conf,"lenv","message",tmp);
544    res=SERVICE_FAILED;
545    return res;
546  }
547
548  CSG_Parameters * params=module->Get_Parameters();
549  if(!params){
550    char tmp[255];
551    sprintf(tmp,"Counld not find any param for the %s module from the %s SAGA library",module_name,lib_name);
552    setMapInMaps(*main_conf,"lenv","message",tmp);
553    res=SERVICE_FAILED;
554    return res;
555  }
556 
557  sagaSetParameters(params,arguments);
558
559  module->Update_Parameter_States();
560
561  bool retval=false;
562  if(module->On_Before_Execution()){
563    retval=module->Execute();
564    module->On_After_Execution();
565  }
566 
567  if(retval && outputs!=NULL){
568    sagaSaveOutputs(module->Get_Parameters(),*main_conf,outputs);
569    SG_Get_Data_Manager().Delete_Unsaved();
570    return SERVICE_SUCCEEDED;
571  }
572
573  return SERVICE_FAILED;
574
575}
576
577/**
578 * Export a SAGA-GIS Shapes to a file in a specific format (GML,KML,GeoJSON).
579 * saga_cmd io_gdal 4 -FILE my.format -SHAPES my.shp -FORMAT XXX
580 *
581 * @param main_conf the conf maps containing the main.cfg settings
582 * @param in the output maps to fill with the resulting file
583 */
584int sagaExportOGR(maps** conf, maps** in){
585  map* mtype=getMap((*in)->content,"mimeType");
586  map* gfile=getMap((*in)->content,"generated_file");
587  char* fext=NULL;
588  map* arg=NULL;
589  if(strncasecmp(mtype->value,"text/xml",8)==0){
590    fext=zStrdup("xml");
591  }
592  else if(strncasecmp(mtype->value,"application/json",16)==0){
593    fext=zStrdup("json");
594  }
595  else{
596    fext=zStrdup("kml");
597  }
598  char* tmpName=(char*)malloc((strlen(gfile->value)+2)*sizeof(char));
599  strncpy(tmpName,gfile->value,(strlen(gfile->value)-3)*sizeof(char));
600  strncpy(&tmpName[0]+(strlen(gfile->value)-3),fext,(strlen(fext))*sizeof(char));
601  tmpName[strlen(fext)+(strlen(gfile->value)-3)]=0;
602  arg=createMap("SHAPES",gfile->value);
603  addToMap(arg,"FILE",tmpName);
604  if(strncasecmp(mtype->value,"text/xml",8)==0){
605    addToMap(arg,"FORMAT","GML");
606  }
607  else if(strncasecmp(mtype->value,"application/json",16)==0){
608    addToMap(arg,"FORMAT","GeoJSON");
609  }
610  else{
[752]611#ifdef HAVE_LIBKML
[634]612    addToMap(arg,"FORMAT","LIBKML");
[752]613#else
614    addToMap(arg,"FORMAT","KML");
615#endif
[634]616  }
617  free(fext);
618  free(gfile->value);
619  gfile->value=zStrdup(tmpName);
620  free(tmpName);
621 
622  sagaExecuteCmd(conf,"io_gdal","4",arg);
623  freeMap(&arg);
624  free(arg);
625}
626
627/**
628 * Export a SAGA-GIS pointcloud to a las file.
629 * saga_cmd io_shapes_las 0 -POINTS my.spc -FILE my.las
630 *
631 * @param main_conf the conf maps containing the main.cfg settings
632 * @param in the output maps to fill with the resulting file
633 */
634void sagaExportPC(maps** conf, maps** in){
635  map* mtype=getMap((*in)->content,"mimeType");
636  map* gfile=getMap((*in)->content,"generated_file");
637  char* fext="las";
638  map* arg=NULL;
639  char* tmpName=(char*)malloc((strlen(gfile->value)+2)*sizeof(char));
640  strncpy(tmpName,gfile->value,(strlen(gfile->value)-3)*sizeof(char));
641  strncpy(&tmpName[0]+(strlen(gfile->value)-3),fext,(strlen(fext))*sizeof(char));
642  tmpName[strlen(fext)+(strlen(gfile->value)-3)]=0;
643  arg=createMap("POINTS",gfile->value);
644  addToMap(arg,"FILE",tmpName);
645  free(gfile->value);
646  gfile->value=zStrdup(tmpName);
647  sagaExecuteCmd(conf,"io_shapes_las","0",arg);
648  freeMap(&arg);
649  free(arg);
650  free(tmpName);
651}
652
653/**
654 * Export a SAGA-GIS Grid to a file in a specific format (tiff,hdr,aa).
655 * saga_cmd io_gdal 1 -FILE my.format -GRIDS my.sgrd -FORMAT XXX
656 *
657 * @param main_conf the conf maps containing the main.cfg settings
658 * @param in the output maps to fill with the resulting file
659 */
660int sagaExportGDAL(maps** conf, maps** in/*,CSG_Parameter* param*/){
661  map* mtype=getMap((*in)->content,"extension");
662  map* gfile=getMap((*in)->content,"generated_file");
663  char* fext=NULL;
664  map* arg;
665
666  if(mtype!=NULL)
667    fext=zStrdup(mtype->value);
668  else{
669    fext=zStrdup("tiff");
670  }
671
672  mtype=getMap((*in)->content,"mimeType");
673  if(strncasecmp(mtype->value,"image/tiff",10)==0){
674    arg=createMap("FORMAT","1");
675  }
676  else if(strncasecmp(mtype->value,"application/x-ogc-envi",22)==0){
677    arg=createMap("FORMAT","ENVI .hdr Labelled");
678  }
679  else{
680    arg=createMap("FORMAT","ARC Digitized Raster Graphics");
681  }
682
683  if(gfile!=NULL){
684    char* tmpName=(char*)malloc((strlen(gfile->value)+1)*sizeof(char));
685    strncpy(tmpName,gfile->value,(strlen(gfile->value)-4)*sizeof(char));
686    strncpy(&tmpName[0]+(strlen(gfile->value)-4),fext,(strlen(fext))*sizeof(char));
687    tmpName[strlen(fext)+(strlen(gfile->value)-4)]=0;
688    addToMap(arg,"FILE",tmpName);
689    addToMap(arg,"GRIDS",gfile->value);
690    free(tmpName);
691    free(fext);
692    free(gfile->value);
693    map* tmp=getMap(arg,"FILE");
694    gfile->value=zStrdup(tmp->value);
695    sagaExecuteCmd(conf,"io_gdal","1",arg);
696  }
697  else{
698    // Empty result
699    return true;
700  }
701  freeMap(&arg);
702  free(arg);
703}
704
705/**
706 * Export a SAGA-GIS TIN to a file in a specific format (GML,KML,GeoJSON).
707 * Exporting TIN produce 5 separated files (POINTS, CENTER, EDGES, TRIANGLES
708 * and POLYGONS). Even if a client can choose which result it want to have,
709 * SAGA-GIS module will be invoked in a way that it will produce in any case
710 * each possible outputs. The selection of a specific output is made in the
711 * ZOO-Kernel itself and not specifically at this level.
712 * saga_cmd tin_tools 3 -TIN my.shp -POINTS p.shp ...
713 *
714 * @param conf the conf maps containing the main.cfg settings
715 * @param in the output maps to fill with the resulting file
716 * @see sagaExportOGR
717 */
718int sagaExportTIN(maps** conf, maps** in,const char* tname/*,CSG_Parameter* param*/){
719  map* mtype=getMap((*in)->content,"mimeType");
720  map* gfile=getMap((*in)->content,"generated_file");
721  char* fext="shp";
722  map* arg=createMap("TIN",gfile->value);
723
724  char* tinOut[5]={
725    "POINTS",
726    "CENTER",
727    "EDGES",
728    "TRIANGLES",
729    "POLYGONS"
730  };
731  maps* resouts=NULL;
732
733  int i=0;
734  for(i=0;i<5;i++){
735    char* tmpName=(char*)malloc((strlen(gfile->value)+strlen(tinOut[i])+4)*sizeof(char));
736    strncpy(tmpName,gfile->value,(strlen(gfile->value)-3)*sizeof(char));
737    char *tmpSubName=(char*) malloc((strlen(tinOut[i])+3)*sizeof(char));
738    sprintf(tmpSubName,"_%s.",tinOut[i]);
739    strncpy(&tmpName[0]+(strlen(gfile->value)-4),tmpSubName,(strlen(tmpSubName))*sizeof(char));
740    strncpy(&tmpName[0]+(strlen(gfile->value)+strlen(tmpSubName)-4),fext,(strlen(fext))*sizeof(char));
741    tmpName[strlen(fext)+(strlen(gfile->value)+strlen(tmpSubName)-4)]=0;
742
[790]743    maps* louts=createMaps(tinOut[i]);
[634]744    louts->content=createMap("mimeType","UNKOWN");
745   
746    addToMap(arg,tinOut[i],tmpName);
747   
748    free(tmpName);
749    if(resouts==NULL)
750      resouts=dupMaps(&louts);
751    else
752      addMapsToMaps(&resouts,louts);
753    freeMaps(&louts);
754    free(louts);
755  }
756 
757  sagaExecuteCmd(conf,"tin_tools","3",arg,&resouts);
758
759  for(i=0;i<5;i++){
760    map* generatedFile=getMapFromMaps(resouts,tinOut[i],"generated_file");
761    setMapInMaps(*in,(CSG_String(tname)+"_"+tinOut[i]).b_str(),"generated_file",generatedFile->value);
762    maps* cout=getMaps(*in,(CSG_String(tname)+"_"+tinOut[i]).b_str());
763    sagaExportOGR(conf,&cout);
764  }
765  return true;
766}
767
768/**
769 * Import GDAL Datasource into SAGA-GIS.
770 * saga_cmd io_gdal 0 -TRANSFORM 0 -FILES my.format -GRIDS /tmpPath/MyGridXXX.sgrd
771 *
772 * @param conf the conf maps containing the main.cfg settings
773 * @param in in the inputs maps
774 */
775int sagaImportGDAL(maps** conf, maps** in){
776  map* l=getMap((*in)->content,"length");
777  bool shouldClean=false;
778  if(l==NULL){
779    l=createMap("length","1");
780    shouldClean=true;
781  }
782  int len=strtol(l->value,NULL,10);
783  int i=0;
784  for(i=0;i<len;i++){
785    map* arg=createMap("TRANSFORM","0");
786    addToMap(arg,"INTERPOL","4");
787    map* v=getMapArray((*in)->content,"cache_file",i);
788    if(v!=NULL)
789      addToMap(arg,"FILES",v->value);
790    addToMap(arg,"GRIDS","");
791
[790]792    maps* louts=createMaps("GRIDS");
[634]793    louts->content=createMap("mimeType","UNKOWN");
794
795    sagaExecuteCmd(conf,"io_gdal","0",arg,&louts);
796
797    map* tmp=getMapFromMaps(louts,"GRIDS","generated_file");
798    setMapArray((*in)->content,"saga_value",i,tmp->value);
799
800    freeMaps(&louts);
801    free(louts);
802    freeMap(&arg);
803    free(arg);
804  }
805  if(shouldClean){
806    freeMap(&l);
807    free(l);
808  }
809}
810
811/**
812 * Import OGR Datasource into SAGA-GIS.
813 * saga_cmd io_gdal 3 -SHAPES my.shp -FILES my.format
814 *
815 * @param conf the conf maps containing the main.cfg settings
816 * @param in in the inputs maps
817 */
818int sagaImportOGR(maps** conf, maps** in){
819  char *ext;
820  map* arg;
821  map* l=getMap((*in)->content,"length");
822  bool shouldClean=false;
823  if(l==NULL){
824    l=createMap("length","1");
825    shouldClean=true;
826  }
827  int len=strtol(l->value,NULL,10);
828  int i=0;
829  for(i=0;i<len;i++){
830    map* v=getMapArray((*in)->content,"cache_file",i);
831    arg=createMap("SHAPES","");
832    if(v!=NULL)
833      addToMap(arg,"FILES",v->value);
834
[790]835    maps* louts=createMaps("SHAPES");
[634]836    louts->content=createMap("mimeType","UNKOWN");
837
838    sagaExecuteCmd(conf,"io_gdal","3",arg,&louts);
839
840    map* tmp=getMapFromMaps(louts,"SHAPES","generated_file");
841    setMapArray((*in)->content,"saga_value",i,tmp->value);
842
843    freeMaps(&louts);
844    free(louts);
845    freeMap(&arg);
846    free(arg);
847  }
848  if(shouldClean){
849    freeMap(&l);
850    free(l);
851  }
852}
853
854/**
855 * Import TIN into SAGA-GIS. Calling this function suppose that sagaImportOGR
856 * was called first.
857 * saga_cmd tin_tools 2 -SHAPES myShapes.shp -TIN myTin.shp
858 *
859 * @param conf the conf maps containing the main.cfg settings
860 * @param in in the inputs maps
861 * @see sagaImportOGR
862 */
863bool sagaImportTIN(maps** conf, maps** in){
864  char *ext;
865  map* arg;
866  map* l=getMap((*in)->content,"length");
867  bool shouldClean=false;
868  if(l==NULL){
869    l=createMap("length","1");
870    shouldClean=true;
871  }
872  int len=strtol(l->value,NULL,10);
873  int i=0;
874  for(i=0;i<len;i++){
875    map* v=getMapArray((*in)->content,"saga_value",i);
876    arg=createMap("TIN","");
877    if(v!=NULL)
878      addToMap(arg,"SHAPES",v->value);
[790]879    maps* louts=createMaps("TIN");
[634]880    louts->content=createMap("mimeType","UNKOWN");
881    sagaExecuteCmd(conf,"tin_tools","2",arg,&louts);
882    map* tmp=getMapFromMaps(louts,"TIN","generated_file");
883    v=getMapArray((*in)->content,"saga_value",i);
884    if(tmp!=NULL){
885      if(v!=NULL){
886        free(v->value);
887        v->value=zStrdup(tmp->value);
888      }
889      else
890        setMapArray((*in)->content,"saga_value",i,tmp->value);
891    }
892    freeMaps(&louts);
893    free(louts);
894    freeMap(&arg);
895    free(arg);
896  }
897  if(shouldClean){
898    freeMap(&l);
899    free(l);
900  }
901  return true;
902}
903
904/**
905 * Import table into SAGA-GIS.
906 * saga_cmd io_table 1 -TABLE myTable -FILENAME myFile -SEPARATOR 2
907 *
908 * @param conf the conf maps containing the main.cfg settings
909 * @param in in the inputs maps
910 */
911int sagaImportTable(maps** conf, maps** in){
912  char *ext;
913  map* arg;
914  map* l=getMap((*in)->content,"length");
915  bool shouldClean=false;
916  if(l==NULL){
917    l=createMap("length","1");
918    shouldClean=true;
919  }
920  int len=strtol(l->value,NULL,10);
921  int i=0;
922  for(i=0;i<len;i++){
923
924    // Create and fill arg map
925    arg=createMap("SEPARATOR","2");
926    addToMap(arg,"TABLE","");
927    map* v=getMapArray((*in)->content,"cache_file",i);
928    if(v!=NULL)
929      addToMap(arg,"FILENAME",v->value);
930
931    // Create the output maps
[790]932    maps* louts=createMaps("TABLE");
[634]933    louts->content=createMap("mimeType","UNKOWN");
934
935    // Execute the saga command
936    sagaExecuteCmd(conf,"io_table","1",arg,&louts);
937
938    // Fetch result and add it to the original map as saga_value
939    map* tmp=getMapFromMaps(louts,"TABLE","generated_file");
940    setMapArray((*in)->content,"saga_value",i,tmp->value);
941
942    // Cleanup
943    freeMaps(&louts);
944    free(louts);
945    freeMap(&arg);
946    free(arg);
947
948  }
949  // Cleanup if required
950  if(shouldClean){
951    freeMap(&l);
952    free(l);
953  }
954}
955
956/**
957 * Import las file as pointcloud into SAGA-GIS.
958 * saga_cmd io_shapes_las 1 -POINTS my.spc -FILENAME my.las
959 *
960 * @param conf the conf maps containing the main.cfg settings
961 * @param in in the inputs maps
962 */
963int sagaImportPC(maps** conf, maps** in){
964  char *ext;
965  map* arg;
966  map* l=getMap((*in)->content,"length");
967  bool shouldClean=false;
968  if(l==NULL){
969    l=createMap("length","1");
970    shouldClean=true;
971  }
972  int len=strtol(l->value,NULL,10);
973  int i=0;
974  for(i=0;i<len;i++){
975
976    // Create and fill arg map
977    arg=createMap("POINTS","");
978    map* v=getMapArray((*in)->content,"cache_file",i);
979    if(v!=NULL)
980      addToMap(arg,"FILES",v->value);
981
982    // Create the output maps
[790]983    maps* louts=createMaps("POINTS");
[634]984    louts->content=createMap("mimeType","UNKOWN");
985
986    // Execute the saga command
987    sagaExecuteCmd(conf,"io_shapes_las","1",arg,&louts);
988
989    // Fetch result and add it to the original map as saga_value
990    map* tmp=getMapFromMaps(louts,"POINTS","generated_file");
991    setMapArray((*in)->content,"saga_value",i,tmp->value);
992
993    // Cleanup
994    freeMaps(&louts);
995    free(louts);
996    freeMap(&arg);
997    free(arg);
998
999  }
1000  // Cleanup if required
1001  if(shouldClean){
1002    freeMap(&l);
1003    free(l);
1004  }
1005}
1006
1007/**
1008 * Load and invoke a SAGA-GIS module defined in a service metadata definitions.
1009 * Load all the input data into SAGA-GIS using io_gdal, io_tables and
1010 * io_shapes_las for SAGA grids/shapes, tables and pointcloud respectively.
1011 * Load and run the module from its library and invoke it using the data
1012 * imported in SAGA-GIS at first stage. After the execution, export the outputs
1013 * to files using io_gdal and io_shapes_las for grids/shapes and pointcloud
1014 * respectively.
1015 *
1016 * @param main_conf the conf maps containing the main.cfg settings
1017 * @param request the map containing the HTTP request
1018 * @param s the service structure
1019 * @param inputs the maps containing the inputs
1020 * @param outputs the maps containing the outputs
1021 */
1022int zoo_saga_support(maps** main_conf,map* request,service* s,maps** inputs,maps** outputs){
1023  int res=SERVICE_FAILED;
1024  if( !wxInitialize() ){
1025    fprintf(stderr,"initialisation failed");
1026    return SERVICE_FAILED;
1027  }
1028  setlocale(LC_NUMERIC, "C");
1029  static bool g_bShow_Messages = false;
1030
1031  dumpMapsValuesToFiles(main_conf,inputs);
1032
1033  SagaWatcher watcher=SagaWatcher();
1034  watcher.SetConf(main_conf);
1035
1036  SG_Set_UI_Callback(Get_Callback(watcher));
1037
[917]1038#if SAGA_MAJOR_VERSION == 2 
[634]1039  int n = SG_Get_Module_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
[917]1040  if( SG_Get_Module_Library_Manager().Get_Count() <= 0 )
1041#else
1042  int n = SG_Get_Tool_Library_Manager().Add_Directory(wxT(MODULE_LIBRARY_PATH),false);
1043  if( SG_Get_Tool_Library_Manager().Get_Count() <= 0 )
1044#endif
1045  {
[634]1046    setMapInMaps(*main_conf,"lenv","message","Could not load any SAGA tool library");
1047    res=SERVICE_FAILED;
1048    return res;
1049  }
1050
1051  map* serviceProvider=getMap(s->content,"serviceProvider");
1052
1053  // Load the SAGA-GIS library corresponding to the serviceProvider
[917]1054#if SAGA_MAJOR_VERSION == 2 
[634]1055  CSG_Module_Library * library=SG_Get_Module_Library_Manager().Get_Library(CSG_String(serviceProvider->value),true);
[917]1056#else
1057  CSG_Tool_Library * library=SG_Get_Tool_Library_Manager().Get_Library(CSG_String(serviceProvider->value),true);
1058#endif
[634]1059  if( library == NULL){
1060    char tmp[255];
1061    sprintf(tmp,"Counld not load the %s SAGA library",serviceProvider->value);
1062    setMapInMaps(*main_conf,"lenv","message",tmp);
1063    res=SERVICE_FAILED;
1064    return res;
1065  }
1066 
1067  // Load the SAGA-GIS module corresponding to the service name from the library
[917]1068#if SAGA_MAJOR_VERSION == 2 
[634]1069  CSG_Module * module=library->Get_Module(atoi(s->name));
[917]1070#else
1071  CSG_Tool * module=library->Get_Tool(atoi(s->name));
1072#endif
[634]1073  if(module == NULL){
1074    char tmp[255];
1075    sprintf(tmp,"Counld not load the %s module from the %s SAGA library",
1076            s->name,serviceProvider->value);
1077    setMapInMaps(*main_conf,"lenv","message",tmp);
1078    res=SERVICE_FAILED;
1079    return res;
1080  }
1081
1082  // Load all the parameters defined for the module
1083  CSG_Parameters * params=module->Get_Parameters();
1084  if(!params){
1085    char tmp[255];
1086    sprintf(tmp,"Counld not find any param for the %s module from the %s SAGA library",
1087            s->name,serviceProvider->value);
1088    setMapInMaps(*main_conf,"lenv","message",tmp);
1089    res=SERVICE_FAILED;
1090    return res;
1091  }
[917]1092  int pc=params->Get_Count();
[634]1093
1094  // Loop over each inputs to transform raster files to grid when needed,
1095  // import tables, shapes or point clouds
1096  for(int k=0;k<pc;k++){
1097    CSG_Parameter * param=params->Get_Parameter(k);
1098    if(param!=NULL && !param->is_Output()){
1099      maps* inmap=getMaps(*inputs,CSG_String(param->Get_Identifier()).b_str());
1100      if(inmap!=NULL){
1101        map* tmp=getMap(inmap->content,"value");
1102        if(tmp==NULL || strncasecmp(tmp->value,"NULL",4)!=0){
1103          if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid"))){
1104            sagaImportGDAL(main_conf,&inmap);
1105          }
1106          else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
1107            sagaImportOGR(main_conf,&inmap);
1108            sagaImportTIN(main_conf,&inmap);
1109          }
1110          else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes"))){
1111            sagaImportOGR(main_conf,&inmap);
1112          }
1113          else{
1114            if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
1115              sagaImportTable(main_conf,&inmap);
1116            }
1117            else
1118              if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("points"))){
1119                sagaImportPC(main_conf,&inmap);
1120              }
1121          }
1122        }
1123      }
1124    }
1125  }
1126
1127  // Create a map conraining arguments to pass to the SAGA-GIS module
1128  // Fetch all input value (specifically for data imported into SAGA-GIS)
1129  maps* inp=*inputs;
1130  int k=0;
1131  map* cParams=NULL;
1132  while(inp!=NULL){
1133    map* len=getMap(inp->content,"length");
1134    bool shouldClean=false;
1135    if(len==NULL){
1136      len=createMap("length","1");
1137      shouldClean=true;
1138    }
1139    int len0=strtol(len->value,NULL,10);
1140    int i=0;
1141    char *cinput=NULL;
1142    int clen=0;
1143    for(i=0;i<len0;i++){
1144      map* val=getMapArray(inp->content,"saga_value",i);
1145      if(val==NULL)
1146        val=getMapArray(inp->content,"value",i);
1147      if(val!=NULL && strncasecmp(val->value,"NULL",4)!=0){
1148        if(cinput==NULL){
1149          cinput=zStrdup(val->value);
1150        }
1151        else{
1152          cinput=(char*)realloc(cinput,(clen+strlen(val->value)+1)*sizeof(char));
1153          strncpy(&cinput[0]+clen,";",1);
1154          strncpy(&cinput[0]+(clen+1),val->value,strlen(val->value));
1155          clen+=1;
1156        }
1157        clen+=strlen(val->value);
1158        cinput[clen]=0;
1159      }
1160    }
1161    if(cinput!=NULL && strncasecmp(cinput,"NULL",4)!=0){
1162      if(cParams==NULL)
1163        cParams=createMap(inp->name,cinput);
1164      else
1165        addToMap(cParams,inp->name,cinput);
1166      free(cinput);
1167    }
1168    inp=inp->next;
1169  }
1170
1171  // Fetch all output and define a resulting filename
1172  inp=*outputs;
1173  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
1174  map* sid=getMapFromMaps(*main_conf,"lenv","usid");
1175  while(inp!=NULL){
1176    for(int k=0;k<pc;k++){
1177      CSG_Parameter * param=params->Get_Parameter(k);
1178      if(CSG_String(param->Get_Identifier()).Cmp(inp->name)==0){
1179        const char *file_ext=sagaGetDefaultExt(param);
1180        char *fileName=(char*)malloc((strlen(file_ext)+strlen(sid->value)+strlen(inp->name)+strlen(tmpPath->value)+11)*sizeof(char));
1181        sprintf(fileName,"%s/Output_%s_%s.%s",tmpPath->value,inp->name,sid->value,file_ext);
1182        if(cParams==NULL)
1183          cParams=createMap(inp->name,fileName);
1184        else
1185          addToMap(cParams,inp->name,fileName);
1186      }
1187    }
1188    inp=inp->next;
1189  }
1190
1191  sagaSetParameters(params,cParams);
1192
1193  module->Update_Parameter_States();
1194 
1195  bool retval=false;
1196  if(module->On_Before_Execution()){
1197    retval=module->Execute();
1198    module->On_After_Execution();
1199  }
1200
1201  sagaSaveOutputs(params,*main_conf,outputs);
1202
1203  // Loop over each outputs to transform grid to raster file when needed,
1204  // export tables, shapes or point clouds
1205  for(int k=0;k<pc;k++){
1206    CSG_Parameter * param=params->Get_Parameter(k);
1207    if(param!=NULL && param->is_Output()){
1208      maps* inmap=getMaps(*outputs,CSG_String(param->Get_Identifier()).b_str());
1209      if(inmap!=NULL){
1210        if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("grid"))
1211           || CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("data_object"))){
1212          sagaExportGDAL(main_conf,&inmap);
1213        }else{
1214          if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("shapes"))){
1215            sagaExportOGR(main_conf,&inmap);
1216          }
1217          else{
1218            if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("table"))){
1219            }
1220            else{
1221              if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
1222                sagaExportTIN(main_conf,&inmap,"TIN");
1223              }
1224              else
1225                if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("points"))){
1226                  sagaExportPC(main_conf,&inmap);
1227              }
1228            }
1229          }
1230        }
1231      }
1232      else if(CSG_String(param->Get_Type_Identifier()).Contains(CSG_String("tin"))){
1233        sagaExportTIN(main_conf,outputs,CSG_String(param->Get_Identifier()).b_str());
1234      }
1235             
1236    }
1237  }
1238
1239  wxUninitialize();
1240
1241  return SERVICE_SUCCEEDED;
1242}
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