1 /******************************************************************************
2  * Project:  Geography Network utility
3  * Purpose:  To manage GNM networks
4  * Authors:  Mikhail Gusev, gusevmihs at gmail dot com
5  *           Dmitry Baryshnikov, polimax@mail.ru
6  *
7  ******************************************************************************
8  * Copyright (c) 2014, Mikhail Gusev
9  * Copyright (c) 2014-2015, NextGIS <info@nextgis.com>
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 "commonutils.h"
31 #include "cpl_string.h"
32 #include "gdal_version.h"
33 #include "gdal.h"
34 #include "gnm.h"
35 #include "gnm_priv.h"
36 
37 //#include "ogr_p.h"
38 //#include "gnm.h"
39 //#include "gnm_api.h"
40 
41 CPL_CVSID("$Id: gnmmanage.cpp 8c3e4ef55212f20eec95aa7e12ba5d48dacfdc47 2020-10-01 21:20:51 +0200 Even Rouault $")
42 
43 enum operation
44 {
45     op_unknown = 0, /** no operation */
46     op_info,        /** print information about network */
47     op_create,      /** create a new network */
48     op_import,      /** add a OGR layer to the network */
49     op_connect,     /** connect features from layers added to the network */
50     op_disconnect,  /** disconnect features from layers added to the network */
51     op_rule,        /** add connect rule */
52     op_autoconnect, /** try to connect features base on their tolerance */
53     op_delete,      /** delete network */
54     op_change_st    /** change vertex or edge blocking state */
55 };
56 
57 /************************************************************************/
58 /*                               Usage()                                */
59 /************************************************************************/
60 
61 static void Usage(const char* pszAdditionalMsg, int bShort = TRUE) CPL_NO_RETURN;
62 
Usage(const char * pszAdditionalMsg,int bShort)63 static void Usage(const char* pszAdditionalMsg, int bShort)
64 {
65     printf("Usage: gnmmanage [--help][-q][-quiet][--long-usage]\n"
66            "                 [info]\n"
67            "                 [create [-f format_name] [-t_srs srs_name] [-dsco NAME=VALUE]... ]\n"
68            "                 [import src_dataset_name] [-l layer_name]\n"
69            "                 [connect gfid_src gfid_tgt gfid_con [-c cost] [-ic inv_cost] [-dir dir]]\n"
70            "                 [disconnect gfid_src gfid_tgt gfid_con]\n"
71            "                 [rule rule_str]\n"
72            "                 [autoconnect tolerance]\n"
73            "                 [delete]\n"
74            "                 [change [-bl gfid][-unbl gfid][-unblall]]\n"
75            "                 gnm_name [layer [layer ...]]\n");
76 
77     if (bShort)
78     {
79         printf("\nNote: gnmmanage --long-usage for full help.\n");
80         if (pszAdditionalMsg)
81             fprintf(stderr, "\nFAILURE: %s\n", pszAdditionalMsg);
82         exit(1);
83     }
84 
85     printf("\n   info: different information about network: system and class "
86            "layers, network metadata, network spatial reference\n"
87            "   create: create network\n"
88            "      -f format_name: output file format name, possible values are:\n");
89 
90     int nGNMDriverCounter = 1;
91     for(int iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
92     {
93         GDALDriverH hDriver = GDALGetDriver(iDr);
94 
95         const char *pszRFlag = "", *pszWFlag, *pszVirtualIO, *pszSubdatasets;
96         char** papszMD = GDALGetMetadata( hDriver, nullptr );
97 
98         if( CPLFetchBool( papszMD, GDAL_DCAP_RASTER, false ) )
99             continue;
100         if( CPLFetchBool( papszMD, GDAL_DCAP_VECTOR, false ) )
101             continue;
102 
103         if( CPLFetchBool( papszMD, GDAL_DCAP_OPEN, false ) )
104             pszRFlag = "r";
105 
106         if( CPLFetchBool( papszMD, GDAL_DCAP_CREATE, false ) )
107             pszWFlag = "w+";
108         else if( CPLFetchBool( papszMD, GDAL_DCAP_CREATECOPY, false ) )
109             pszWFlag = "w";
110         else
111             pszWFlag = "o";
112 
113         if( CPLFetchBool( papszMD, GDAL_DCAP_VIRTUALIO, false ) )
114             pszVirtualIO = "v";
115         else
116             pszVirtualIO = "";
117 
118         if( CPLFetchBool( papszMD, GDAL_DMD_SUBDATASETS, false ) )
119             pszSubdatasets = "s";
120         else
121             pszSubdatasets = "";
122 
123         printf( "          %d. %s (%s%s%s%s): %s\n",
124                 nGNMDriverCounter++,
125                 GDALGetDriverShortName( hDriver ),
126                 pszRFlag, pszWFlag, pszVirtualIO, pszSubdatasets,
127                 GDALGetDriverLongName( hDriver ) );
128     }
129 
130     printf("      -t_srs srs_name: spatial reference input\n"
131            "      -dsco NAME=VALUE: network creation option set as pair=value\n"
132            "   import src_dataset_name: import external layer where src_dataset_name is a dataset name to copy from\n"
133            "      -l layer_name: layer name in dataset. If unset, 0 layer is copied\n"
134            "   connect gfid_src gfid_tgt gfid_con: make a topological connection, where the gfid_src and gfid_tgt are vertices and gfid_con is edge (gfid_con can be -1, so the virtual connection will be created)\n"
135            "      -c cost -ic inv_cost -dir dir: manually assign the following values: the cost (weight), inverse cost and direction of the edge (optional)\n"
136            "   disconnect gfid_src gfid_tgt gfid_con: removes the connection from the graph\n"
137            "   rule rule_str: creates a rule in the network by the given rule_str string\n"
138            "   autoconnect tolerance: create topology automatically with the given double tolerance\n"
139            "   delete: delete network\n"
140            "   change: modify blocking state of vertices and edges ans save them in the network"
141            "   -bl gfid: block feature before the main operation. Blocking features are saved in the special layer\n"
142            "   -unbl gfid: unblock feature before the main operation\n"
143            "   -unblall: unblock all blocked features before the main operation\n"
144            "   gnm_name: the network to work with (path and name)\n"
145            );
146 
147     if (pszAdditionalMsg)
148         fprintf(stderr, "\nFAILURE: %s\n", pszAdditionalMsg);
149 
150     exit(1);
151 }
152 
Usage(int bShort=TRUE)153 static void Usage(int bShort = TRUE)
154 {
155     Usage(nullptr, bShort);
156 }
157 
158 /************************************************************************/
159 /*                                main()                                */
160 /************************************************************************/
161 
162 #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
163     do { if (iArg + nExtraArg >= nArgc) \
164         Usage(CPLSPrintf("%s option requires %d argument(s)", \
165                          papszArgv[iArg], nExtraArg)); } while( false )
166 
MAIN_START(nArgc,papszArgv)167 MAIN_START(nArgc, papszArgv)
168 
169 {
170     int bQuiet = FALSE;
171     const char *pszFormat = nullptr;
172     const char *pszSRS = nullptr;
173     GNMGFID nSrcFID = -1;
174     GNMGFID nTgtFID = -1;
175     GNMGFID nConFID = -1;
176     double dfDirCost = 1.0;
177     double dfInvCost = 1.0;
178     GNMDirection eDir = GNM_EDGE_DIR_BOTH;
179     const char *pszRuleStr = "";
180     const char *pszDataSource = nullptr;
181     char **papszDSCO = nullptr;
182     const char *pszInputDataset = nullptr;
183     const char *pszInputLayer = nullptr;
184     double dfTolerance = 0.0001;
185     operation stOper = op_unknown;
186     char **papszLayers = nullptr;
187     GNMNetwork *poDS = nullptr;
188     std::vector<GNMGFID> anFIDsToBlock;
189     std::vector<GNMGFID> anFIDsToUnblock;
190     bool bUnblockAll = false;
191     int          nRet = 0;
192 
193     // Check strict compilation and runtime library version as we use C++ API
194     if (! GDAL_CHECK_VERSION(papszArgv[0]))
195         exit(1);
196 
197     EarlySetConfigOptions(nArgc, papszArgv);
198 
199 /* -------------------------------------------------------------------- */
200 /*      Register format(s).                                             */
201 /* -------------------------------------------------------------------- */
202     GDALAllRegister();
203 
204 /* -------------------------------------------------------------------- */
205 /*      Processing command line arguments.                              */
206 /* -------------------------------------------------------------------- */
207     nArgc = GDALGeneralCmdLineProcessor( nArgc, &papszArgv, GDAL_OF_GNM );
208 
209     if( nArgc < 1 )
210     {
211         exit( -nArgc );
212     }
213 
214     for( int iArg = 1; iArg < nArgc; iArg++ )
215     {
216         if( EQUAL(papszArgv[1], "--utility_version") )
217         {
218             printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
219                     papszArgv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
220             CSLDestroy( papszArgv );
221             return 0;
222         }
223 
224         else if( EQUAL(papszArgv[iArg],"--help") )
225         {
226             Usage();
227         }
228 
229         else if ( EQUAL(papszArgv[iArg], "--long-usage") )
230         {
231             Usage(FALSE);
232         }
233 
234         else if( EQUAL(papszArgv[iArg],"-q") || EQUAL(papszArgv[iArg],"-quiet") )
235         {
236             bQuiet = TRUE;
237         }
238 
239         else if ( EQUAL(papszArgv[iArg],"info") )
240         {
241             stOper = op_info;
242         }
243 
244         else if( EQUAL(papszArgv[iArg],"-f") || EQUAL(papszArgv[iArg],"-of") )
245         {
246             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
247             // coverity[tainted_data]
248             pszFormat = papszArgv[++iArg];
249         }
250 
251         else if( EQUAL(papszArgv[iArg],"-dsco") )
252         {
253             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
254             // coverity[tainted_data]
255             papszDSCO = CSLAddString(papszDSCO, papszArgv[++iArg] );
256         }
257 
258         else if( EQUAL(papszArgv[iArg],"create") )
259         {
260             stOper = op_create;
261         }
262 
263         else if( EQUAL(papszArgv[iArg],"-t_srs") )
264         {
265             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
266             // coverity[tainted_data]
267             pszSRS = papszArgv[++iArg];
268         }
269 
270         else if( EQUAL(papszArgv[iArg],"import") )
271         {
272             stOper = op_import;
273             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
274             // coverity[tainted_data]
275             pszInputDataset = papszArgv[++iArg];
276         }
277 
278         else if( EQUAL(papszArgv[iArg],"-l") )
279         {
280             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
281             // coverity[tainted_data]
282             pszInputLayer = papszArgv[++iArg];
283         }
284 
285         else if( EQUAL(papszArgv[iArg],"connect") )
286         {
287             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(3);
288             stOper = op_connect;
289             // coverity[tainted_data]
290             nSrcFID = atoi(papszArgv[++iArg]);
291             // coverity[tainted_data]
292             nTgtFID = atoi(papszArgv[++iArg]);
293             // coverity[tainted_data]
294             nConFID = atoi(papszArgv[++iArg]);
295         }
296 
297         else if( EQUAL(papszArgv[iArg],"-c") )
298         {
299             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
300             // coverity[tainted_data]
301             dfDirCost = CPLAtofM(papszArgv[++iArg]);
302         }
303         else if( EQUAL(papszArgv[iArg],"-ic") )
304         {
305             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
306             // coverity[tainted_data]
307             dfInvCost = CPLAtofM(papszArgv[++iArg]);
308         }
309         else if( EQUAL(papszArgv[iArg],"-dir") )
310         {
311             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
312             // coverity[tainted_data]
313             eDir = atoi(papszArgv[++iArg]);
314         }
315 
316         else if( EQUAL(papszArgv[iArg],"disconnect") )
317         {
318             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(3);
319             stOper = op_disconnect;
320             // coverity[tainted_data]
321             nSrcFID = atoi(papszArgv[++iArg]);
322             // coverity[tainted_data]
323             nTgtFID = atoi(papszArgv[++iArg]);
324             // coverity[tainted_data]
325             nConFID = atoi(papszArgv[++iArg]);
326         }
327 
328         else if ( EQUAL(papszArgv[iArg],"autoconnect") )
329         {
330             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
331             stOper = op_autoconnect;
332             // coverity[tainted_data]
333             dfTolerance = CPLAtofM(papszArgv[++iArg]);
334         }
335 
336         else if ( EQUAL(papszArgv[iArg],"rule") )
337         {
338             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
339             stOper = op_rule;
340             // coverity[tainted_data]
341             pszRuleStr = papszArgv[++iArg];
342         }
343 
344         else if ( EQUAL(papszArgv[iArg],"delete") )
345         {
346             stOper = op_delete;
347         }
348 
349         else if( EQUAL(papszArgv[iArg],"change") )
350         {
351             stOper = op_change_st;
352         }
353 
354         else if( EQUAL(papszArgv[iArg],"-bl") )
355         {
356             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
357             // coverity[tainted_data]
358             anFIDsToBlock.push_back(atoi(papszArgv[++iArg]));
359         }
360 
361         else if( EQUAL(papszArgv[iArg],"-unbl") )
362         {
363             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
364             // coverity[tainted_data]
365             anFIDsToUnblock.push_back(atoi(papszArgv[++iArg]));
366         }
367 
368         else if( EQUAL(papszArgv[iArg],"-unblall") )
369         {
370             bUnblockAll = true;
371         }
372 
373         else if( papszArgv[iArg][0] == '-' )
374         {
375             Usage(CPLSPrintf("Unknown option name '%s'", papszArgv[iArg]));
376         }
377 
378         else if( pszDataSource == nullptr )
379             pszDataSource = papszArgv[iArg];
380         else
381             papszLayers = CSLAddString( papszLayers, papszArgv[iArg] );
382     }
383 
384 // do the work ////////////////////////////////////////////////////////////////
385 
386     if(stOper == op_info)
387     {
388         if(pszDataSource == nullptr)
389             Usage("No network dataset provided");
390 
391         //TODO for output:
392         // stats about graph and blocked features
393 
394         // open
395 
396         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(
397             GDALOpenEx( pszDataSource, GDAL_OF_READONLY |
398                                     GDAL_OF_GNM, nullptr, nullptr, nullptr )));
399 
400         GDALDriver         *poDriver = nullptr;
401         if( poDS != nullptr )
402             poDriver = poDS->GetDriver();
403 
404         if( poDS == nullptr )
405         {
406             fprintf(stderr, "FAILURE:\nUnable to open datasource `%s'.\n",
407                     pszDataSource);
408             exit(1);
409         }
410 
411         if( poDriver == nullptr )
412         {
413             CPLAssert( false );
414             exit(1);
415         }
416 
417         printf( "INFO: Open of `%s'\n      using driver `%s' successful.\n",
418                     pszDataSource, poDriver->GetDescription() );
419 
420         // Report projection.
421         int nMajor = poDS->GetVersion() / 100;
422         printf( "Network version: %d.%d.\n", nMajor,
423                                             poDS->GetVersion() - nMajor * 100 );
424         const char* pszName = poDS->GetName();
425         if(nullptr != pszName)
426             printf( "Network name: %s.\n", pszName );
427         const char* pszDescript = poDS->GetDescription();
428         if(nullptr != pszDescript)
429             printf( "Network description: %s.\n", pszDescript );
430 
431         char *pszProjection = const_cast<char*>(poDS->GetProjectionRef());
432         OGRSpatialReferenceH hSRS = OSRNewSpatialReference(nullptr);
433         if( OSRImportFromWkt( hSRS, &pszProjection ) == CE_None )
434         {
435             char *pszPrettyWkt = nullptr;
436             OSRExportToPrettyWkt( hSRS, &pszPrettyWkt, FALSE );
437 
438             printf( "Coordinate System is:\n%s\n", pszPrettyWkt );
439             CPLFree( pszPrettyWkt );
440         }
441         else
442         {
443             printf( "Coordinate System is '%s'\n", pszProjection );
444         }
445         OSRDestroySpatialReference(hSRS);
446 
447         // report layers
448         if(poDS->GetLayerCount() > 0)
449         {
450             printf("\nNetwork\'s layers: \n");
451             for (int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++)
452             {
453                 OGRLayer *poLayer = poDS->GetLayer(iLayer);
454 
455                 if (poLayer != nullptr)
456                 {
457                     printf("  %d: %s", iLayer + 1, poLayer->GetName());
458 
459                     int nGeomFieldCount = poLayer->GetLayerDefn()->GetGeomFieldCount();
460                     if (nGeomFieldCount > 1)
461                     {
462                         printf(" (");
463                         for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
464                         {
465                             if (iGeom > 0)
466                                 printf(", ");
467                             OGRGeomFieldDefn* poGFldDefn =
468                                 poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
469                             printf("%s", OGRGeometryTypeToName( poGFldDefn->GetType()) );
470                         }
471                         printf(")");
472                     }
473                     else if (poLayer->GetGeomType() != wkbUnknown)
474                         printf(" (%s)", OGRGeometryTypeToName( poLayer->GetGeomType()) );
475 
476                     printf("\n");
477                 }
478             }
479         }
480 
481         // report rules
482         GNMGenericNetwork* poGenericNetwork =
483                                          dynamic_cast<GNMGenericNetwork*>(poDS);
484 
485         if(nullptr != poGenericNetwork)
486         {
487             CPLStringList oList(poGenericNetwork->GetRules());
488             if(oList.Count() > 0)
489             {
490                 printf("\nNetwork\'s rules: \n");
491                 for(int iRule = 0; iRule < oList.Count(); ++iRule)
492                 {
493                     printf("  %d: %s\n", iRule + 1, oList[iRule]);
494                 }
495             }
496         }
497     }
498     else if(stOper == op_create)
499     {
500         const char* pszPath;
501         const char* pszNetworkName = CSLFetchNameValue(papszDSCO, GNM_MD_NAME);
502 
503         if(pszDataSource == nullptr)
504             Usage("No network dataset provided");
505 
506         //the DSCO have priority on input keys
507         if(nullptr == pszNetworkName)
508         {
509             pszPath = CPLGetPath(pszDataSource);
510             pszNetworkName = CPLGetBasename(pszDataSource);
511             papszDSCO = CSLAddNameValue(papszDSCO, GNM_MD_NAME, pszNetworkName);
512         }
513         else
514         {
515             pszPath = pszDataSource;
516         }
517 
518         if( pszNetworkName == nullptr)
519             Usage("No dataset name provided");
520 
521         const char* pszFinalSRS = CSLFetchNameValue(papszDSCO, GNM_MD_SRS);
522         if(nullptr == pszFinalSRS)
523         {
524             pszFinalSRS = pszSRS;
525             papszDSCO = CSLAddNameValue(papszDSCO, GNM_MD_SRS, pszSRS);
526         }
527 
528         if(nullptr == pszFinalSRS)
529             Usage("No spatial reference provided");
530         if( pszFormat == nullptr )
531             Usage("No output format provided");
532 
533         GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
534         if( poDriver == nullptr )
535         {
536             Usage( CPLSPrintf("%s driver not available", pszFormat) );
537         }
538         else
539         {
540             char** papszMD = poDriver->GetMetadata();
541 
542             if( !CPLFetchBool( papszMD, GDAL_DCAP_GNM, false ) )
543                 Usage("not a GNM driver");
544 
545             poDS = cpl::down_cast<GNMNetwork*>(poDriver->Create( pszPath, 0, 0, 0, GDT_Unknown,
546                                                 papszDSCO ));
547 
548             if (nullptr == poDS)
549             {
550                 fprintf(stderr, "\nFAILURE: Failed to create network in a new dataset at "
551                         "%s and with driver %s\n", CPLFormFilename(pszPath,
552                         pszNetworkName, nullptr) ,pszFormat);
553                 nRet = 1;
554             }
555             else
556             {
557                 if (bQuiet == FALSE)
558                     printf("\nNetwork created successfully in a "
559                     "new dataset at %s\n", CPLFormFilename(pszPath,
560                         pszNetworkName, nullptr));
561             }
562         }
563     }
564     else if(stOper == op_import)
565     {
566         if(pszDataSource == nullptr)
567             Usage("No network dataset provided");
568 
569         if(pszInputDataset == nullptr)
570             Usage("No input dataset name provided");
571 
572         // open
573         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
574                              GDAL_OF_READONLY | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
575 
576         if(nullptr == poDS)
577         {
578             printf("\nFailed to open network at %s\n",pszDataSource);
579             goto exit;
580         }
581 
582         GDALDataset *poSrcDS = static_cast<GDALDataset*>(GDALOpenEx(pszInputDataset,
583                           GDAL_OF_VECTOR | GDAL_OF_READONLY, nullptr, nullptr, nullptr ));
584         if(nullptr == poSrcDS)
585         {
586             fprintf(stderr, "\nFAILURE: Can not open dataset at %s\n",
587                             pszInputDataset);
588 
589             nRet = 1;
590             goto exit;
591         }
592 
593         OGRLayer *poSrcLayer;
594         if (pszInputLayer != nullptr)
595             poSrcLayer = poSrcDS->GetLayerByName(pszInputLayer);
596         else
597             poSrcLayer = poSrcDS->GetLayer(0);
598 
599         if (nullptr == poSrcLayer)
600         {
601             if (pszInputLayer != nullptr)
602                 fprintf(stderr, "\nFAILURE: Can not open layer %s in %s\n",
603                     pszInputLayer,pszInputDataset);
604             else
605                 fprintf(stderr, "\nFAILURE: Can not open layer in %s\n",
606                 pszInputDataset);
607 
608             GDALClose(poSrcDS);
609 
610             nRet = 1;
611             goto exit;
612         }
613 
614         OGRLayer * poLayer = poDS->CopyLayer(poSrcLayer, poSrcLayer->GetName());
615         if (nullptr == poLayer)
616         {
617             if (pszInputLayer != nullptr)
618                 fprintf(stderr, "\nFAILURE: Can not copy layer %s from %s\n",
619                     pszInputLayer,pszInputDataset);
620             else
621                 fprintf(stderr, "\nFAILURE: Can not copy layer from %s\n",
622                 pszInputDataset);
623             GDALClose(poSrcDS);
624 
625             nRet = 1;
626             goto exit;
627         }
628 
629         if (bQuiet == FALSE)
630         {
631             if (pszInputLayer != nullptr)
632                 printf("\nLayer %s successfully copied from %s and added to the network at %s\n",
633                 pszInputLayer, pszInputDataset, pszDataSource);
634             else
635                 printf("\nLayer successfully copied from %s and added to the network at %s\n",
636                 pszInputDataset, pszDataSource);
637         }
638 
639         GDALClose(poSrcDS);
640     }
641     else if (stOper == op_connect)
642     {
643         if(pszDataSource == nullptr)
644             Usage("No network dataset provided");
645 
646         // open
647         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
648                              GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
649 
650         if(nullptr == poDS)
651         {
652             fprintf( stderr, "\nFailed to open network at %s\n", pszDataSource);
653             nRet = 1;
654             goto exit;
655         }
656 
657         GNMGenericNetwork* poGenericNetwork =
658                                          dynamic_cast<GNMGenericNetwork*>(poDS);
659 
660         if(nullptr == poGenericNetwork)
661         {
662             fprintf( stderr, "\nUnsupported datasource type for this operation\n");
663             nRet = 1;
664             goto exit;
665         }
666 
667         if(poGenericNetwork->ConnectFeatures(nSrcFID, nTgtFID, nConFID,
668                             dfDirCost, dfInvCost, eDir) != CE_None )
669         {
670             fprintf( stderr, "Failed to connect features\n" );
671             nRet = 1;
672             goto exit;
673         }
674 
675         if (bQuiet == FALSE)
676         {
677             printf("Features connected successfully\n");
678         }
679     }
680     else if (stOper == op_disconnect)
681     {
682         if(pszDataSource == nullptr)
683             Usage("No network dataset provided");
684 
685         // open
686         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
687                              GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
688 
689         if(nullptr == poDS)
690         {
691             fprintf( stderr, "\nFailed to open network at %s\n", pszDataSource);
692             nRet = 1;
693             goto exit;
694         }
695 
696         GNMGenericNetwork* poGenericNetwork =
697                                          dynamic_cast<GNMGenericNetwork*>(poDS);
698 
699         if(nullptr == poGenericNetwork)
700         {
701             fprintf( stderr, "\nUnsupported datasource type for this operation\n");
702             nRet = 1;
703             goto exit;
704         }
705 
706         if(poGenericNetwork->DisconnectFeatures(nSrcFID, nTgtFID, nConFID)
707                 != CE_None )
708         {
709             fprintf( stderr, "Failed to disconnect features\n" );
710             nRet = 1;
711             goto exit;
712         }
713 
714         if (bQuiet == FALSE)
715         {
716             printf("Features disconnected successfully\n");
717         }
718     }
719     else if (stOper == op_rule)
720     {
721         if(pszDataSource == nullptr)
722             Usage("No network dataset provided");
723 
724         // open
725         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
726                              GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
727 
728         if(nullptr == poDS)
729         {
730             fprintf( stderr, "\nFailed to open network at %s\n", pszDataSource);
731             nRet = 1;
732             goto exit;
733         }
734 
735         GNMGenericNetwork* poGenericNetwork =
736                                          dynamic_cast<GNMGenericNetwork*>(poDS);
737 
738         if(nullptr == poGenericNetwork)
739         {
740             fprintf( stderr, "\nUnsupported datasource type for this operation\n");
741             nRet = 1;
742             goto exit;
743         }
744 
745         if(poGenericNetwork->CreateRule(pszRuleStr) != CE_None )
746         {
747             fprintf( stderr, "Failed to create rule %s\n", pszRuleStr );
748             nRet = 1;
749             goto exit;
750         }
751 
752         if (bQuiet == FALSE)
753         {
754             printf("Create rule '%s' successfully\n", pszRuleStr);
755         }
756     }
757     else if (stOper == op_autoconnect)
758     {
759         if(pszDataSource == nullptr)
760             Usage("No network dataset provided");
761 
762         // open
763         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
764                              GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
765 
766         if(nullptr == poDS)
767         {
768             fprintf( stderr, "\nFailed to open network at %s\n", pszDataSource);
769             nRet = 1;
770             goto exit;
771         }
772 
773         GNMGenericNetwork* poGenericNetwork =
774                                          dynamic_cast<GNMGenericNetwork*>(poDS);
775 
776         if(nullptr == poGenericNetwork)
777         {
778             fprintf( stderr, "\nUnsupported datasource type for this operation\n");
779             nRet = 1;
780             goto exit;
781         }
782 
783         if(CSLCount(papszLayers) == 0 && poDS->GetLayerCount() > 1)
784         {
785             if(bQuiet == FALSE)
786             {
787                 printf("No layers provided. Use all layers of network:\n");
788             }
789 
790             for(int i = 0; i < poDS->GetLayerCount(); ++i)
791             {
792                 OGRLayer* poLayer = poDS->GetLayer(i);
793                 if(bQuiet == FALSE)
794                 {
795                     printf("%d. %s\n", i + 1, poLayer->GetName());
796                 }
797                 papszLayers = CSLAddString(papszLayers, poLayer->GetName() );
798             }
799         }
800 
801         if(poGenericNetwork->ConnectPointsByLines(papszLayers, dfTolerance,
802                                         dfDirCost, dfInvCost, eDir) != CE_None )
803         {
804             fprintf( stderr, "Failed to autoconnect features\n" );
805             nRet = 1;
806             goto exit;
807         }
808 
809         if (bQuiet == FALSE)
810         {
811             printf("Features connected successfully\n");
812         }
813     }
814     else if(stOper == op_delete)
815     {
816         if(pszDataSource == nullptr)
817             Usage("No network dataset provided");
818 
819         // open
820         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
821                              GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
822 
823         if(nullptr == poDS)
824         {
825             fprintf( stderr, "\nFailed to open network at %s\n", pszDataSource);
826             nRet = 1;
827             goto exit;
828         }
829 
830         if( poDS->Delete() != CE_None )
831         {
832             fprintf( stderr, "Delete failed.\n" );
833             nRet = 1;
834             goto exit;
835         }
836 
837         if (bQuiet == FALSE)
838         {
839             printf("Delete successfully\n");
840         }
841 
842        /** if hDriver == NULL this code delete everything in folder,
843         *  not only GNM files
844 
845         GDALDriverH hDriver = NULL;
846         if( pszFormat != NULL )
847         {
848             hDriver = GDALGetDriverByName( pszFormat );
849             if( hDriver == NULL )
850             {
851                 fprintf( stderr, "Unable to find driver named '%s'.\n",
852                          pszFormat );
853                 exit( 1 );
854             }
855         }
856         GDALDeleteDataset( hDriver, pszDataSource );
857         */
858     }
859     else if(stOper == op_change_st)
860     {
861         if(pszDataSource == nullptr)
862             Usage("No dataset in input");
863 
864         // open
865         poDS = cpl::down_cast<GNMNetwork*>(static_cast<GDALDataset*>(GDALOpenEx( pszDataSource,
866                              GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr, nullptr, nullptr )));
867 
868         if(nullptr == poDS)
869         {
870             fprintf( stderr, "\nFailed to open network at %s\n", pszDataSource);
871             nRet = 1;
872             goto exit;
873         }
874 
875         GNMGenericNetwork* poGenericNetwork =
876                                          dynamic_cast<GNMGenericNetwork*>(poDS);
877 
878         if(nullptr == poGenericNetwork)
879         {
880             fprintf( stderr, "\nUnsupported datasource type for this operation\n");
881             nRet = 1;
882             goto exit;
883         }
884 
885         if(bUnblockAll)
886         {
887             if(poGenericNetwork->ChangeAllBlockState(false) != CE_None)
888             {
889                 fprintf( stderr, "\nChange all block state failed\n");
890                 nRet = 1;
891                 goto exit;
892             }
893         }
894         else
895         {
896             size_t i;
897             for(i = 0; i < anFIDsToBlock.size(); ++i)
898             {
899                 if(poGenericNetwork->ChangeBlockState(anFIDsToBlock[i], true)
900                         != CE_None)
901                 {
902                     fprintf( stderr, "\nChange block state of id "
903                                      GNMGFIDFormat " failed\n", anFIDsToBlock[i]);
904                     nRet = 1;
905                     goto exit;
906                 }
907             }
908 
909             for(i = 0; i < anFIDsToUnblock.size(); ++i)
910             {
911                 if(poGenericNetwork->ChangeBlockState(anFIDsToUnblock[i], false)
912                         != CE_None)
913                 {
914                     fprintf( stderr, "\nChange block state of id "
915                                      GNMGFIDFormat " failed\n", anFIDsToBlock[i]);
916                     nRet = 1;
917                     goto exit;
918                 }
919             }
920         }
921 
922         if (bQuiet == FALSE)
923         {
924             printf("Change block state successfully\n");
925         }
926     }
927     else
928     {
929         printf("\nNeed an operation. See help what you can do with gnmmanage:\n");
930         Usage();
931     }
932 
933 exit:
934     CSLDestroy( papszArgv );
935     CSLDestroy( papszDSCO );
936     CSLDestroy( papszLayers );
937 
938     if( poDS != nullptr )
939         GDALClose(poDS);
940 
941     GDALDestroyDriverManager();
942 
943     return nRet;
944 }
945 MAIN_END
946