Line data Source code
1 : /******************************************************************************
2 : * Project: geography network utility
3 : * Purpose: Analyse 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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "commonutils.h"
15 : #include "gdal_version.h"
16 : #include "gnm.h"
17 : #include "gnm_priv.h"
18 : #include "ogr_p.h"
19 :
20 : enum operation
21 : {
22 : op_unknown = 0, /** no operation */
23 : op_dijkstra, /** create shortest path using Dijkstra algorithm */
24 : op_kpaths, /** create k shortest paths using Yens algorithm */
25 : op_resource /** create resource distribution layer */
26 : };
27 :
28 : /************************************************************************/
29 : /* Usage() */
30 : /************************************************************************/
31 0 : static void Usage(bool bIsError, const char *pszAdditionalMsg = nullptr,
32 : bool bShort = true)
33 : {
34 0 : fprintf(
35 : bIsError ? stderr : stdout,
36 : "Usage: gnmanalyse [--help][--help-general][-q][-quiet][--long-usage]\n"
37 : " [dijkstra <start_gfid> <end_gfid "
38 : "[-alo <NAME>=<VALUE>]...]\n"
39 : " [kpaths <start_gfid> <end_gfid> <k> "
40 : "[-alo NAME=VALUE]...]\n"
41 : " [resource [-alo <NAME>=<VALUE>]...]\n"
42 : " [-ds <ds_name>][-f <ds_format>][-l <layer_name>]\n"
43 : " [-dsco <NAME>=<VALUE>]... [-lco <NAME>=<VALUE>]...\n"
44 : " <gnm_name>\n");
45 :
46 0 : if (bShort)
47 : {
48 0 : printf("\nNote: gnmanalyse --long-usage for full help.\n");
49 0 : if (pszAdditionalMsg)
50 0 : fprintf(stderr, "\nFAILURE: %s\n", pszAdditionalMsg);
51 0 : exit(1);
52 : }
53 :
54 0 : fprintf(bIsError ? stderr : stdout,
55 : "\n dijkstra start_gfid end_gfid: calculates the best path "
56 : "between two points using Dijkstra algorithm from start_gfid point "
57 : "to end_gfid point\n"
58 : " kpaths start_gfid end_gfid k: calculates k (up to 10) best "
59 : "paths between two points using Yen\'s algorithm (which internally "
60 : "uses Dijkstra algorithm for single path calculating) from "
61 : "start_gfid point to end_gfid point\n"
62 : " resource: calculates the \"resource distribution\". The "
63 : "connected components search is performed using breadth-first "
64 : "search and starting from that features which are marked by rules "
65 : "as \'EMITTERS\'\n"
66 : " -ds ds_name: the name&path of the dataset to save the layer "
67 : "with resulting paths. Not need to be existed dataset\n"
68 : " -f ds_format: define this to set the format of newly created "
69 : "dataset\n"
70 : " -l layer_name: the name of the resulting layer. If the layer "
71 : "exists already - it will be rewritten. For K shortest paths "
72 : "several layers are created in format layer_nameN, where N - is "
73 : "number of the path (0 - is the most shortest one)\n"
74 : " -dsco NAME=VALUE: Dataset creation option (format specific)\n"
75 : " -lco NAME=VALUE: Layer creation option (format specific)\n"
76 : " -alo NAME=VALUE: Algorithm option (format specific)\n"
77 : " gnm_name: the network to work with (path and name)\n");
78 :
79 0 : if (pszAdditionalMsg)
80 0 : fprintf(stderr, "\nFAILURE: %s\n", pszAdditionalMsg);
81 :
82 0 : exit(bIsError ? 1 : 0);
83 : }
84 :
85 : /************************************************************************/
86 : /* GetLayerAndOverwriteIfNecessary() */
87 : /************************************************************************/
88 :
89 0 : static OGRLayer *GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
90 : const char *pszNewLayerName,
91 : int bOverwrite,
92 : int *pbErrorOccurred)
93 : {
94 0 : if (pbErrorOccurred)
95 0 : *pbErrorOccurred = FALSE;
96 :
97 : /* GetLayerByName() can instantiate layers that would have been */
98 : /* 'hidden' otherwise, for example, non-spatial tables in a */
99 : /* PostGIS-enabled database, so this apparently useless command is */
100 : /* not useless... (#4012) */
101 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
102 0 : OGRLayer *poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
103 0 : CPLPopErrorHandler();
104 0 : CPLErrorReset();
105 :
106 0 : int iLayer = -1;
107 0 : if (poDstLayer != nullptr)
108 : {
109 0 : int nLayerCount = poDstDS->GetLayerCount();
110 0 : for (iLayer = 0; iLayer < nLayerCount; iLayer++)
111 : {
112 0 : OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
113 0 : if (poLayer == poDstLayer)
114 0 : break;
115 : }
116 :
117 0 : if (iLayer == nLayerCount)
118 : /* should not happen with an ideal driver */
119 0 : poDstLayer = nullptr;
120 : }
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* If the user requested overwrite, and we have the layer in */
124 : /* question we need to delete it now so it will get recreated */
125 : /* (overwritten). */
126 : /* -------------------------------------------------------------------- */
127 0 : if (poDstLayer != nullptr && bOverwrite)
128 : {
129 0 : if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
130 : {
131 0 : fprintf(stderr, "DeleteLayer() failed when overwrite requested.\n");
132 0 : if (pbErrorOccurred)
133 0 : *pbErrorOccurred = TRUE;
134 : }
135 0 : poDstLayer = nullptr;
136 : }
137 :
138 0 : return poDstLayer;
139 : }
140 :
141 : /************************************************************************/
142 : /* CreateAndFillOutputDataset */
143 : /************************************************************************/
144 0 : static OGRErr CreateAndFillOutputDataset(OGRLayer *poSrcLayer,
145 : const char *pszDestDataSource,
146 : const char *pszFormat,
147 : const char *pszLayer, char **papszDSCO,
148 : char **papszLCO, int bQuiet)
149 : {
150 0 : GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
151 0 : if (poDriver == nullptr)
152 : {
153 0 : fprintf(stderr, "%s driver not available\n", pszFormat);
154 0 : return OGRERR_FAILURE;
155 : }
156 :
157 0 : if (!CPLTestBool(CSLFetchNameValueDef(poDriver->GetMetadata(),
158 : GDAL_DCAP_CREATE, "FALSE")))
159 : {
160 0 : fprintf(stderr, "%s driver does not support data source creation.\n",
161 : pszFormat);
162 0 : return OGRERR_FAILURE;
163 : }
164 :
165 : GDALDataset *poODS =
166 0 : poDriver->Create(pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO);
167 0 : if (poODS == nullptr)
168 : {
169 0 : fprintf(stderr, "%s driver failed to create %s\n", pszFormat,
170 : pszDestDataSource);
171 0 : return OGRERR_FAILURE;
172 : }
173 :
174 0 : if (nullptr == pszLayer)
175 0 : pszLayer = poSrcLayer->GetName();
176 : int nError;
177 0 : GetLayerAndOverwriteIfNecessary(poODS, pszLayer, TRUE, &nError);
178 0 : if (nError == TRUE)
179 : {
180 0 : return OGRERR_FAILURE;
181 : }
182 :
183 : // create layer
184 0 : OGRLayer *poLayer = poODS->CopyLayer(poSrcLayer, pszLayer, papszLCO);
185 0 : if (nullptr == poLayer)
186 : {
187 0 : fprintf(stderr, "\nFAILURE: Can not copy path to %s\n",
188 : pszDestDataSource);
189 0 : GDALClose(poODS);
190 :
191 0 : return OGRERR_FAILURE;
192 : }
193 :
194 0 : if (bQuiet == FALSE)
195 : {
196 0 : printf("\nPath successfully copied and added to the network at %s\n",
197 : pszDestDataSource);
198 : }
199 :
200 0 : GDALClose(poODS);
201 :
202 0 : return OGRERR_NONE;
203 : }
204 :
205 : /************************************************************************/
206 : /* ReportOnLayer() */
207 : /************************************************************************/
208 :
209 2 : static void ReportOnLayer(OGRLayer *poLayer, int bVerbose)
210 :
211 : {
212 2 : OGRFeatureDefn *poDefn = poLayer->GetLayerDefn();
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Report various overall information. */
216 : /* -------------------------------------------------------------------- */
217 2 : printf("\n");
218 :
219 2 : printf("Layer name: %s\n", poLayer->GetName());
220 :
221 2 : if (bVerbose)
222 : {
223 2 : int nGeomFieldCount = poLayer->GetLayerDefn()->GetGeomFieldCount();
224 2 : if (nGeomFieldCount > 1)
225 : {
226 0 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
227 : {
228 : OGRGeomFieldDefn *poGFldDefn =
229 0 : poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
230 0 : printf("Geometry (%s): %s\n", poGFldDefn->GetNameRef(),
231 : OGRGeometryTypeToName(poGFldDefn->GetType()));
232 : }
233 : }
234 : else
235 : {
236 2 : printf("Geometry: %s\n",
237 2 : OGRGeometryTypeToName(poLayer->GetGeomType()));
238 : }
239 :
240 2 : printf("Feature Count: " CPL_FRMT_GIB "\n", poLayer->GetFeatureCount());
241 :
242 2 : OGREnvelope oExt;
243 2 : if (nGeomFieldCount > 1)
244 : {
245 0 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
246 : {
247 0 : if (poLayer->GetExtent(iGeom, &oExt, TRUE) == OGRERR_NONE)
248 : {
249 : OGRGeomFieldDefn *poGFldDefn =
250 0 : poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
251 0 : CPLprintf("Extent (%s): (%f, %f) - (%f, %f)\n",
252 : poGFldDefn->GetNameRef(), oExt.MinX, oExt.MinY,
253 : oExt.MaxX, oExt.MaxY);
254 : }
255 : }
256 : }
257 2 : else if (poLayer->GetExtent(&oExt, TRUE) == OGRERR_NONE)
258 : {
259 2 : CPLprintf("Extent: (%f, %f) - (%f, %f)\n", oExt.MinX, oExt.MinY,
260 : oExt.MaxX, oExt.MaxY);
261 : }
262 :
263 : char *pszWKT;
264 :
265 2 : if (nGeomFieldCount > 1)
266 : {
267 0 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
268 : {
269 : OGRGeomFieldDefn *poGFldDefn =
270 0 : poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
271 0 : const OGRSpatialReference *poSRS = poGFldDefn->GetSpatialRef();
272 0 : if (poSRS == nullptr)
273 0 : pszWKT = CPLStrdup("(unknown)");
274 : else
275 : {
276 0 : poSRS->exportToPrettyWkt(&pszWKT);
277 : }
278 :
279 0 : printf("SRS WKT (%s):\n%s\n", poGFldDefn->GetNameRef(), pszWKT);
280 0 : CPLFree(pszWKT);
281 : }
282 : }
283 : else
284 : {
285 2 : if (poLayer->GetSpatialRef() == nullptr)
286 0 : pszWKT = CPLStrdup("(unknown)");
287 : else
288 : {
289 2 : poLayer->GetSpatialRef()->exportToPrettyWkt(&pszWKT);
290 : }
291 :
292 2 : printf("Layer SRS WKT:\n%s\n", pszWKT);
293 2 : CPLFree(pszWKT);
294 : }
295 :
296 2 : if (strlen(poLayer->GetFIDColumn()) > 0)
297 0 : printf("FID Column = %s\n", poLayer->GetFIDColumn());
298 :
299 2 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
300 : {
301 : OGRGeomFieldDefn *poGFldDefn =
302 2 : poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
303 4 : if (nGeomFieldCount == 1 && EQUAL(poGFldDefn->GetNameRef(), "") &&
304 2 : poGFldDefn->IsNullable())
305 2 : break;
306 0 : printf("Geometry Column ");
307 0 : if (nGeomFieldCount > 1)
308 0 : printf("%d ", iGeom + 1);
309 0 : if (!poGFldDefn->IsNullable())
310 0 : printf("NOT NULL ");
311 0 : printf("= %s\n", poGFldDefn->GetNameRef());
312 : }
313 :
314 18 : for (int iAttr = 0; iAttr < poDefn->GetFieldCount(); iAttr++)
315 : {
316 16 : OGRFieldDefn *poField = poDefn->GetFieldDefn(iAttr);
317 : const char *pszType =
318 16 : (poField->GetSubType() != OFSTNone)
319 16 : ? CPLSPrintf(
320 : "%s(%s)",
321 : poField->GetFieldTypeName(poField->GetType()),
322 : poField->GetFieldSubTypeName(poField->GetSubType()))
323 16 : : poField->GetFieldTypeName(poField->GetType());
324 16 : printf("%s: %s (%d.%d)", poField->GetNameRef(), pszType,
325 : poField->GetWidth(), poField->GetPrecision());
326 16 : if (!poField->IsNullable())
327 0 : printf(" NOT NULL");
328 16 : if (poField->GetDefault() != nullptr)
329 0 : printf(" DEFAULT %s", poField->GetDefault());
330 16 : printf("\n");
331 : }
332 : }
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Read, and dump features. */
336 : /* -------------------------------------------------------------------- */
337 82 : for (auto &poFeature : poLayer)
338 : {
339 80 : poFeature->DumpReadable(nullptr);
340 : }
341 2 : }
342 :
343 : /************************************************************************/
344 : /* main() */
345 : /************************************************************************/
346 :
347 : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \
348 : do \
349 : { \
350 : if (iArg + nExtraArg >= nArgc) \
351 : Usage(true, CPLSPrintf("%s option requires %d argument(s)", \
352 : papszArgv[iArg], nExtraArg)); \
353 : } while (false)
354 :
355 3 : MAIN_START(nArgc, papszArgv)
356 :
357 : {
358 3 : int bQuiet = FALSE;
359 :
360 3 : const char *pszDataSource = nullptr;
361 :
362 3 : GNMGFID nFromFID = -1;
363 3 : GNMGFID nToFID = -1;
364 3 : int nK = 1;
365 3 : const char *pszDataset = nullptr;
366 3 : const char *pszFormat = "ESRI Shapefile";
367 3 : const char *pszLayer = nullptr;
368 3 : GNMNetwork *poDS = nullptr;
369 3 : OGRLayer *poResultLayer = nullptr;
370 3 : char **papszDSCO = nullptr, **papszLCO = nullptr, **papszALO = nullptr;
371 :
372 3 : operation stOper = op_unknown;
373 :
374 3 : int nRet = 0;
375 :
376 : // Check strict compilation and runtime library version as we use C++ API
377 3 : if (!GDAL_CHECK_VERSION(papszArgv[0]))
378 0 : exit(1);
379 :
380 3 : EarlySetConfigOptions(nArgc, papszArgv);
381 :
382 : /* -------------------------------------------------------------------- */
383 : /* Register format(s). */
384 : /* -------------------------------------------------------------------- */
385 3 : GDALAllRegister();
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* Processing command line arguments. */
389 : /* -------------------------------------------------------------------- */
390 3 : nArgc = GDALGeneralCmdLineProcessor(nArgc, &papszArgv, GDAL_OF_GNM);
391 :
392 3 : if (nArgc < 1)
393 : {
394 0 : exit(-nArgc);
395 : }
396 :
397 7 : for (int iArg = 1; iArg < nArgc; iArg++)
398 : {
399 5 : if (EQUAL(papszArgv[1], "--utility_version"))
400 : {
401 1 : printf("%s was compiled against GDAL %s and is running against "
402 : "GDAL %s\n",
403 : papszArgv[0], GDAL_RELEASE_NAME,
404 : GDALVersionInfo("RELEASE_NAME"));
405 1 : CSLDestroy(papszArgv);
406 1 : return 0;
407 : }
408 :
409 4 : else if (EQUAL(papszArgv[iArg], "--help"))
410 : {
411 0 : Usage(false);
412 : }
413 :
414 4 : else if (EQUAL(papszArgv[iArg], "--long-usage"))
415 : {
416 0 : Usage(false, nullptr, false);
417 : }
418 :
419 4 : else if (EQUAL(papszArgv[iArg], "-q") ||
420 4 : EQUAL(papszArgv[iArg], "-quiet"))
421 : {
422 0 : bQuiet = TRUE;
423 : }
424 :
425 4 : else if (EQUAL(papszArgv[iArg], "dijkstra"))
426 : {
427 1 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2);
428 1 : stOper = op_dijkstra;
429 1 : nFromFID = atoi(papszArgv[++iArg]);
430 1 : nToFID = atoi(papszArgv[++iArg]);
431 : }
432 :
433 3 : else if (EQUAL(papszArgv[iArg], "kpaths"))
434 : {
435 1 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(3);
436 1 : stOper = op_kpaths;
437 1 : nFromFID = atoi(papszArgv[++iArg]);
438 1 : nToFID = atoi(papszArgv[++iArg]);
439 1 : nK = atoi(papszArgv[++iArg]);
440 : }
441 :
442 2 : else if (EQUAL(papszArgv[iArg], "resource"))
443 : {
444 0 : stOper = op_resource;
445 : }
446 :
447 2 : else if (EQUAL(papszArgv[iArg], "-ds"))
448 : {
449 0 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
450 0 : pszDataset = papszArgv[++iArg];
451 : }
452 :
453 2 : else if ((EQUAL(papszArgv[iArg], "-f") ||
454 2 : EQUAL(papszArgv[iArg], "-of")))
455 : {
456 0 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
457 0 : pszFormat = papszArgv[++iArg];
458 : }
459 :
460 2 : else if (EQUAL(papszArgv[iArg], "-l"))
461 : {
462 0 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
463 0 : pszLayer = papszArgv[++iArg];
464 : }
465 2 : else if (EQUAL(papszArgv[iArg], "-dsco"))
466 : {
467 0 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
468 0 : papszDSCO = CSLAddString(papszDSCO, papszArgv[++iArg]);
469 : }
470 2 : else if (EQUAL(papszArgv[iArg], "-lco"))
471 : {
472 0 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
473 0 : papszLCO = CSLAddString(papszLCO, papszArgv[++iArg]);
474 : }
475 2 : else if (EQUAL(papszArgv[iArg], "-alo"))
476 : {
477 0 : CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
478 0 : papszALO = CSLAddString(papszALO, papszArgv[++iArg]);
479 : }
480 2 : else if (papszArgv[iArg][0] == '-')
481 : {
482 0 : Usage(true,
483 0 : CPLSPrintf("Unknown option name '%s'", papszArgv[iArg]));
484 : }
485 :
486 2 : else if (pszDataSource == nullptr)
487 2 : pszDataSource = papszArgv[iArg];
488 : }
489 :
490 : // do the work
491 : // ////////////////////////////////////////////////////////////////
492 :
493 2 : if (stOper == op_dijkstra)
494 : {
495 1 : if (pszDataSource == nullptr)
496 0 : Usage(true, "No network dataset provided");
497 :
498 1 : if (nFromFID == -1 || nToFID == -1)
499 0 : Usage(true, "Invalid input from or to identificators");
500 :
501 : // open
502 2 : poDS = cpl::down_cast<GNMNetwork *>(static_cast<GDALDataset *>(
503 1 : GDALOpenEx(pszDataSource, GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr,
504 : nullptr, nullptr)));
505 1 : if (nullptr == poDS)
506 : {
507 0 : fprintf(stderr, "\nFailed to open network at %s\n", pszDataSource);
508 0 : nRet = 1;
509 0 : goto exit;
510 : }
511 :
512 : poResultLayer =
513 1 : poDS->GetPath(nFromFID, nToFID, GATDijkstraShortestPath, papszALO);
514 1 : if (nullptr == pszDataset)
515 : {
516 1 : ReportOnLayer(poResultLayer, bQuiet == FALSE);
517 : }
518 : else
519 : {
520 0 : if (CreateAndFillOutputDataset(poResultLayer, pszDataset, pszFormat,
521 : pszLayer, papszDSCO, papszLCO,
522 0 : bQuiet) != OGRERR_NONE)
523 : {
524 0 : nRet = 1;
525 0 : goto exit;
526 : }
527 : }
528 : }
529 1 : else if (stOper == op_kpaths)
530 : {
531 1 : if (pszDataSource == nullptr)
532 0 : Usage(true, "No network dataset provided");
533 :
534 1 : if (nFromFID == -1 || nToFID == -1)
535 0 : Usage(true, "Invalid input from or to identificators");
536 :
537 : // open
538 2 : poDS = cpl::down_cast<GNMNetwork *>(static_cast<GDALDataset *>(
539 1 : GDALOpenEx(pszDataSource, GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr,
540 : nullptr, nullptr)));
541 1 : if (nullptr == poDS)
542 : {
543 0 : fprintf(stderr, "\nFailed to open network at %s\n", pszDataSource);
544 0 : nRet = 1;
545 0 : goto exit;
546 : }
547 :
548 1 : if (CSLFindName(papszALO, GNM_MD_NUM_PATHS) == -1)
549 : {
550 1 : CPLDebug("GNM", "No K in options, add %d value", nK);
551 1 : papszALO = CSLAddNameValue(papszALO, GNM_MD_NUM_PATHS,
552 : CPLSPrintf("%d", nK));
553 : }
554 :
555 : poResultLayer =
556 1 : poDS->GetPath(nFromFID, nToFID, GATKShortestPath, papszALO);
557 :
558 1 : if (nullptr == pszDataset)
559 : {
560 1 : ReportOnLayer(poResultLayer, bQuiet == FALSE);
561 : }
562 : else
563 : {
564 0 : if (CreateAndFillOutputDataset(poResultLayer, pszDataset, pszFormat,
565 : pszLayer, papszDSCO, papszLCO,
566 0 : bQuiet) != OGRERR_NONE)
567 : {
568 0 : nRet = 1;
569 0 : goto exit;
570 : }
571 : }
572 : }
573 0 : else if (stOper == op_resource)
574 : {
575 0 : if (pszDataSource == nullptr)
576 0 : Usage(true, "No network dataset provided");
577 :
578 : // open
579 0 : poDS = cpl::down_cast<GNMNetwork *>(static_cast<GDALDataset *>(
580 0 : GDALOpenEx(pszDataSource, GDAL_OF_UPDATE | GDAL_OF_GNM, nullptr,
581 : nullptr, nullptr)));
582 0 : if (nullptr == poDS)
583 : {
584 0 : fprintf(stderr, "\nFailed to open network at %s\n", pszDataSource);
585 0 : nRet = 1;
586 0 : goto exit;
587 : }
588 :
589 : poResultLayer =
590 0 : poDS->GetPath(nFromFID, nToFID, GATConnectedComponents, papszALO);
591 :
592 0 : if (nullptr == pszDataset)
593 : {
594 0 : ReportOnLayer(poResultLayer, bQuiet == FALSE);
595 : }
596 : else
597 : {
598 0 : if (CreateAndFillOutputDataset(poResultLayer, pszDataset, pszFormat,
599 : pszLayer, papszDSCO, papszLCO,
600 0 : bQuiet) != OGRERR_NONE)
601 : {
602 0 : nRet = 1;
603 0 : goto exit;
604 : }
605 : }
606 : }
607 : else
608 : {
609 0 : fprintf(
610 : stderr,
611 : "Need an operation. See help what you can do with gnmanalyse:\n");
612 0 : Usage(true);
613 : }
614 :
615 2 : exit:
616 2 : CSLDestroy(papszDSCO);
617 2 : CSLDestroy(papszLCO);
618 2 : CSLDestroy(papszALO);
619 2 : CSLDestroy(papszArgv);
620 :
621 2 : if (poResultLayer != nullptr)
622 2 : poDS->ReleaseResultSet(poResultLayer);
623 :
624 2 : if (poDS)
625 : {
626 2 : if (GDALClose(poDS) != CE_None)
627 0 : nRet = 1;
628 : }
629 :
630 2 : GDALDestroyDriverManager();
631 :
632 2 : return nRet;
633 : }
634 :
635 0 : MAIN_END
|