Line data Source code
1 : /******************************************************************************
2 : * Project: ogr linear referencing utility
3 : * Purpose: main source file
4 : * Author: Dmitry Baryshnikov (aka Bishop), polimax@mail.ru
5 : *
6 : ******************************************************************************
7 : * Copyright (C) 2014 NextGIS
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 :
12 : #include "cpl_port.h"
13 :
14 : #include "commonutils.h"
15 : #include "cpl_conv.h"
16 : #include "cpl_error.h"
17 : #include "cpl_string.h"
18 : #include "gdal_version.h"
19 : #include "gdal.h"
20 : #include "gdal_alg.h"
21 : #include "ogr_api.h"
22 : #include "ogr_p.h"
23 : #include "ogrsf_frmts.h"
24 : #include "gdalargumentparser.h"
25 :
26 : #include <limits>
27 : #include <map>
28 : #include <set>
29 : #include <vector>
30 :
31 : #define FIELD_START "beg"
32 : #define FIELD_FINISH "end"
33 : #define FIELD_SCALE_FACTOR "scale"
34 : constexpr double DELTA = 0.00000001; // - delta
35 : #ifdef HAVE_GEOS
36 : constexpr double TOLERANCE_DEGREE = 0.00008983153;
37 : constexpr double TOLERANCE_METER = 10.0;
38 : #endif
39 :
40 : enum operation
41 : {
42 : op_unknown = 0,
43 : op_create,
44 : op_get_pos,
45 : op_get_coord,
46 : op_get_subline
47 : };
48 :
49 : typedef struct _curve_data
50 : {
51 : OGRLineString *pPart;
52 : double dfBeg, dfEnd, dfFactor;
53 :
54 70 : bool IsInside(const double &dfDist) const
55 : {
56 70 : return (dfDist + DELTA >= dfBeg) && (dfDist - DELTA <= dfEnd);
57 : }
58 : } CURVE_DATA;
59 :
60 : /************************************************************************/
61 : /* SetupTargetLayer() */
62 : /************************************************************************/
63 :
64 3 : static OGRLayer *SetupTargetLayer(OGRLayer *poSrcLayer, GDALDataset *poDstDS,
65 : char **papszLCO, const char *pszNewLayerName,
66 : const char *pszOutputSepFieldName = nullptr)
67 : {
68 : const CPLString szLayerName =
69 : pszNewLayerName == nullptr
70 6 : ? CPLGetBasenameSafe(poDstDS->GetDescription())
71 6 : : pszNewLayerName;
72 :
73 : /* -------------------------------------------------------------------- */
74 : /* Get other info. */
75 : /* -------------------------------------------------------------------- */
76 3 : OGRFeatureDefn *poSrcFDefn = poSrcLayer->GetLayerDefn();
77 :
78 : /* -------------------------------------------------------------------- */
79 : /* Find requested geometry fields. */
80 : /* -------------------------------------------------------------------- */
81 :
82 3 : OGRSpatialReference *poOutputSRS = poSrcLayer->GetSpatialRef();
83 :
84 : /* -------------------------------------------------------------------- */
85 : /* Find the layer. */
86 : /* -------------------------------------------------------------------- */
87 :
88 : // GetLayerByName() can instantiate layers that would have been
89 : // 'hidden' otherwise, for example, non-spatial tables in a
90 : // PostGIS-enabled database, so this apparently useless command is
91 : // not useless... (#4012)
92 3 : CPLPushErrorHandler(CPLQuietErrorHandler);
93 3 : OGRLayer *poDstLayer = poDstDS->GetLayerByName(szLayerName);
94 3 : CPLPopErrorHandler();
95 3 : CPLErrorReset();
96 :
97 3 : if (poDstLayer != nullptr)
98 : {
99 0 : const int nLayerCount = poDstDS->GetLayerCount();
100 0 : int iLayer = -1; // Used after for.
101 0 : for (iLayer = 0; iLayer < nLayerCount; iLayer++)
102 : {
103 0 : OGRLayer *poLayer = poDstDS->GetLayer(iLayer);
104 0 : if (poLayer == poDstLayer)
105 0 : break;
106 : }
107 :
108 0 : if (iLayer == nLayerCount)
109 : // Should not happen with an ideal driver.
110 0 : poDstLayer = nullptr;
111 : }
112 :
113 : /* -------------------------------------------------------------------- */
114 : /* If the layer does not exist, then create it. */
115 : /* -------------------------------------------------------------------- */
116 3 : if (poDstLayer == nullptr)
117 : {
118 3 : if (!poDstDS->TestCapability(ODsCCreateLayer))
119 : {
120 0 : fprintf(stderr,
121 : _("Layer %s not found, and "
122 : "CreateLayer not supported by driver.\n"),
123 : szLayerName.c_str());
124 0 : return nullptr;
125 : }
126 :
127 3 : OGRwkbGeometryType eGType = wkbLineString;
128 :
129 3 : CPLErrorReset();
130 :
131 3 : if (poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
132 : {
133 0 : eGType = wkbNone;
134 : }
135 :
136 3 : poDstLayer = poDstDS->CreateLayer(
137 : szLayerName, poOutputSRS, static_cast<OGRwkbGeometryType>(eGType),
138 : papszLCO);
139 :
140 3 : if (poDstLayer == nullptr)
141 0 : return nullptr;
142 :
143 3 : if (poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
144 : {
145 0 : OGRGeomFieldDefn oGFldDefn(poSrcFDefn->GetGeomFieldDefn(0));
146 0 : if (poOutputSRS != nullptr)
147 0 : oGFldDefn.SetSpatialRef(poOutputSRS);
148 0 : oGFldDefn.SetType(wkbLineString);
149 0 : poDstLayer->CreateGeomField(&oGFldDefn);
150 : }
151 : }
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Otherwise we will append to it, if append was requested. */
155 : /* -------------------------------------------------------------------- */
156 : else
157 : {
158 0 : fprintf(stderr, _("FAILED: Layer %s already exists.\n"),
159 : szLayerName.c_str());
160 0 : return nullptr;
161 : }
162 :
163 : // Create beg, end, scale factor fields.
164 6 : OGRFieldDefn oFieldDefn_Beg(FIELD_START, OFTReal);
165 3 : if (poDstLayer->CreateField(&oFieldDefn_Beg) != OGRERR_NONE)
166 : {
167 0 : CPLError(CE_Failure, CPLE_AppDefined, "Create %s field failed!",
168 : oFieldDefn_Beg.GetNameRef());
169 0 : return nullptr;
170 : }
171 :
172 6 : OGRFieldDefn oFieldDefn_End(FIELD_FINISH, OFTReal);
173 3 : if (poDstLayer->CreateField(&oFieldDefn_End) != OGRERR_NONE)
174 : {
175 0 : CPLError(CE_Failure, CPLE_AppDefined, "Create %s field failed!",
176 : oFieldDefn_End.GetNameRef());
177 0 : return nullptr;
178 : }
179 :
180 6 : OGRFieldDefn oFieldDefn_SF(FIELD_SCALE_FACTOR, OFTReal);
181 3 : if (poDstLayer->CreateField(&oFieldDefn_SF) != OGRERR_NONE)
182 : {
183 0 : CPLError(CE_Failure, CPLE_AppDefined, "Create %s field failed!",
184 : oFieldDefn_SF.GetNameRef());
185 0 : return nullptr;
186 : }
187 :
188 3 : if (pszOutputSepFieldName != nullptr)
189 : {
190 0 : OGRFieldDefn oSepField(pszOutputSepFieldName, OFTString);
191 0 : oSepField.SetWidth(254);
192 0 : if (poDstLayer->CreateField(&oSepField) != OGRERR_NONE)
193 : {
194 0 : CPLError(CE_Failure, CPLE_AppDefined, "Create %s field failed!",
195 : oSepField.GetNameRef());
196 0 : return nullptr;
197 : }
198 : }
199 :
200 : // Now that we've created a field, GetLayerDefn() won't return NULL.
201 3 : OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
202 :
203 : // Sanity check: if it fails, the driver is buggy.
204 3 : if (poDstFDefn != nullptr && poDstFDefn->GetFieldCount() != 3)
205 : {
206 1 : CPLError(CE_Warning, CPLE_AppDefined,
207 : "The output driver has claimed to have added the %s field, "
208 : "but it did not!",
209 : oFieldDefn_Beg.GetNameRef());
210 : }
211 :
212 3 : return poDstLayer;
213 : }
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* CheckDestDataSourceNameConsistency() */
217 : /* -------------------------------------------------------------------- */
218 :
219 3 : static void CheckDestDataSourceNameConsistency(const char *pszDestFilename,
220 : const char *pszDriverName)
221 : {
222 : char *pszDestExtension =
223 3 : CPLStrdup(CPLGetExtensionSafe(pszDestFilename).c_str());
224 :
225 : // TODO: Would be good to have driver metadata like for GDAL drivers.
226 : static const char *apszExtensions[][2] = {{"shp", "ESRI Shapefile"},
227 : {"dbf", "ESRI Shapefile"},
228 : {"sqlite", "SQLite"},
229 : {"db", "SQLite"},
230 : {"mif", "MapInfo File"},
231 : {"tab", "MapInfo File"},
232 : {"s57", "S57"},
233 : {"bna", "BNA"},
234 : {"csv", "CSV"},
235 : {"gml", "GML"},
236 : {"kml", "KML"},
237 : {"kmz", "LIBKML"},
238 : {"json", "GeoJSON"},
239 : {"geojson", "GeoJSON"},
240 : {"dxf", "DXF"},
241 : {"gdb", "FileGDB"},
242 : {"pix", "PCIDSK"},
243 : {"sql", "PGDump"},
244 : {"gtm", "GPSTrackMaker"},
245 : {"gmt", "GMT"},
246 : {"pdf", "PDF"},
247 : {nullptr, nullptr}};
248 : static const char *apszBeginName[][2] = {{"PG:", "PG"},
249 : {"MySQL:", "MySQL"},
250 : {"CouchDB:", "CouchDB"},
251 : {"GFT:", "GFT"},
252 : {"MSSQL:", "MSSQLSpatial"},
253 : {"ODBC:", "ODBC"},
254 : {"OCI:", "OCI"},
255 : {"SDE:", "SDE"},
256 : {"WFS:", "WFS"},
257 : {nullptr, nullptr}};
258 :
259 66 : for (int i = 0; apszExtensions[i][0] != nullptr; i++)
260 : {
261 63 : if (EQUAL(pszDestExtension, apszExtensions[i][0]) &&
262 3 : !EQUAL(pszDriverName, apszExtensions[i][1]))
263 : {
264 0 : fprintf(stderr,
265 : _("Warning: The target file has a '%s' extension, "
266 : "which is normally used by the %s driver,\n"
267 : "but the requested output driver is %s. "
268 : "Is it really what you want ?\n"),
269 : pszDestExtension, apszExtensions[i][1], pszDriverName);
270 0 : break;
271 : }
272 : }
273 :
274 30 : for (int i = 0; apszBeginName[i][0] != nullptr; i++)
275 : {
276 27 : if (EQUALN(pszDestFilename, apszBeginName[i][0],
277 0 : strlen(apszBeginName[i][0])) &&
278 0 : !EQUAL(pszDriverName, apszBeginName[i][1]))
279 : {
280 0 : fprintf(stderr,
281 : _("Warning: The target file has a name which is normally "
282 : "recognized by the %s driver,\n"
283 : "but the requested output driver is %s. "
284 : "Is it really what you want ?\n"),
285 : apszBeginName[i][1], pszDriverName);
286 0 : break;
287 : }
288 : }
289 :
290 3 : CPLFree(pszDestExtension);
291 3 : }
292 :
293 : //------------------------------------------------------------------------
294 : // AddFeature
295 : //------------------------------------------------------------------------
296 :
297 44 : static OGRErr AddFeature(OGRLayer *const poOutLayer, OGRLineString *pPart,
298 : double dfFrom, double dfTo, double dfScaleFactor,
299 : bool bQuiet,
300 : const char *pszOutputSepFieldName = nullptr,
301 : const char *pszOutputSepFieldValue = nullptr)
302 : {
303 : OGRFeature *poFeature =
304 44 : OGRFeature::CreateFeature(poOutLayer->GetLayerDefn());
305 :
306 44 : poFeature->SetField(FIELD_START, dfFrom);
307 44 : poFeature->SetField(FIELD_FINISH, dfTo);
308 44 : poFeature->SetField(FIELD_SCALE_FACTOR, dfScaleFactor);
309 :
310 44 : if (pszOutputSepFieldName != nullptr)
311 : {
312 0 : poFeature->SetField(pszOutputSepFieldName, pszOutputSepFieldValue);
313 : }
314 :
315 44 : poFeature->SetGeometryDirectly(pPart);
316 :
317 44 : if (poOutLayer->CreateFeature(poFeature) != OGRERR_NONE)
318 : {
319 0 : if (!bQuiet)
320 0 : printf("Failed to create feature in shapefile.\n");
321 0 : return OGRERR_FAILURE;
322 : }
323 :
324 44 : OGRFeature::DestroyFeature(poFeature);
325 :
326 44 : return OGRERR_NONE;
327 : }
328 :
329 : //------------------------------------------------------------------------
330 : // CreateSubline
331 : //------------------------------------------------------------------------
332 1 : static OGRErr CreateSubline(OGRLayer *const poPkLayer, double dfPosBeg,
333 : double dfPosEnd, OGRLayer *const poOutLayer,
334 : CPL_UNUSED int bDisplayProgress, bool bQuiet)
335 : {
336 : // Get step
337 1 : poPkLayer->ResetReading();
338 1 : OGRFeature *pFeature = poPkLayer->GetNextFeature();
339 1 : if (nullptr != pFeature)
340 : {
341 : // FIXME: Clang Static Analyzer rightly found that the following
342 : // code is dead
343 : // dfBeg = pFeature->GetFieldAsDouble(FIELD_START);
344 : // dfEnd = pFeature->GetFieldAsDouble(FIELD_FINISH);
345 1 : OGRFeature::DestroyFeature(pFeature);
346 : }
347 : else
348 : {
349 0 : fprintf(stderr, _("Get step for positions %f - %f failed\n"), dfPosBeg,
350 : dfPosEnd);
351 0 : return OGRERR_FAILURE;
352 : }
353 : // Get second part.
354 1 : double dfBeg = 0.0;
355 1 : double dfEnd = 0.0;
356 1 : pFeature = poPkLayer->GetNextFeature();
357 1 : if (nullptr != pFeature)
358 : {
359 1 : dfBeg = pFeature->GetFieldAsDouble(FIELD_START);
360 1 : dfEnd = pFeature->GetFieldAsDouble(FIELD_FINISH);
361 1 : OGRFeature::DestroyFeature(pFeature);
362 : }
363 : else
364 : {
365 0 : fprintf(stderr, _("Get step for positions %f - %f failed\n"), dfPosBeg,
366 : dfPosEnd);
367 0 : return OGRERR_FAILURE;
368 : }
369 1 : const double dfStep = dfEnd - dfBeg;
370 :
371 : // Round input to step
372 1 : const double dfPosBegLow = floor(dfPosBeg / dfStep) * dfStep;
373 1 : const double dfPosEndHigh = ceil(dfPosEnd / dfStep) * dfStep;
374 :
375 2 : CPLString szAttributeFilter;
376 : szAttributeFilter.Printf("%s >= %f AND %s <= %f", FIELD_START, dfPosBegLow,
377 1 : FIELD_FINISH, dfPosEndHigh);
378 : // TODO: ExecuteSQL should be faster.
379 1 : poPkLayer->SetAttributeFilter(szAttributeFilter);
380 1 : poPkLayer->ResetReading();
381 :
382 2 : std::map<double, OGRFeature *> moParts;
383 :
384 6 : while ((pFeature = poPkLayer->GetNextFeature()) != nullptr)
385 : {
386 5 : double dfStart = pFeature->GetFieldAsDouble(FIELD_START);
387 5 : moParts[dfStart] = pFeature;
388 : }
389 :
390 1 : if (moParts.empty())
391 : {
392 0 : fprintf(stderr, _("Get parts for positions %f - %f failed\n"), dfPosBeg,
393 : dfPosEnd);
394 0 : return OGRERR_FAILURE;
395 : }
396 :
397 2 : OGRLineString SubLine;
398 1 : if (moParts.size() == 1)
399 : {
400 0 : std::map<double, OGRFeature *>::iterator IT = moParts.begin();
401 0 : const double dfStart = IT->first;
402 0 : double dfPosBegCorr = dfPosBeg - dfStart;
403 0 : const double dfSF = IT->second->GetFieldAsDouble(FIELD_SCALE_FACTOR);
404 0 : dfPosBegCorr *= dfSF;
405 :
406 0 : const double dfPosEndCorr = (dfPosEnd - dfStart) * dfSF;
407 :
408 0 : OGRLineString *pLine = IT->second->GetGeometryRef()->toLineString();
409 :
410 : OGRLineString *pSubLine =
411 0 : pLine->getSubLine(dfPosBegCorr, dfPosEndCorr, FALSE);
412 :
413 0 : OGRFeature::DestroyFeature(IT->second);
414 : // Store.
415 0 : return AddFeature(poOutLayer, pSubLine, dfPosBeg, dfPosEnd, 1.0,
416 0 : bQuiet);
417 : }
418 : else
419 : {
420 1 : int nCounter = static_cast<int>(moParts.size());
421 1 : std::map<double, OGRFeature *>::iterator IT = moParts.begin();
422 1 : OGRLineString *pOutLine = new OGRLineString();
423 : // Get first part.
424 1 : const double dfStart = IT->first;
425 1 : double dfPosBegCorr = dfPosBeg - dfStart;
426 1 : double dfSF = IT->second->GetFieldAsDouble(FIELD_SCALE_FACTOR);
427 1 : dfPosBegCorr *= dfSF;
428 :
429 1 : OGRLineString *pLine = IT->second->GetGeometryRef()->toLineString();
430 :
431 : OGRLineString *pSubLine =
432 1 : pLine->getSubLine(dfPosBegCorr, pLine->get_Length(), FALSE);
433 :
434 1 : pOutLine->addSubLineString(pSubLine);
435 1 : delete pSubLine;
436 1 : OGRFeature::DestroyFeature(IT->second);
437 :
438 1 : ++IT;
439 1 : nCounter--;
440 :
441 4 : while (nCounter > 1)
442 : {
443 3 : pLine = IT->second->GetGeometryRef()->toLineString();
444 3 : pOutLine->addSubLineString(pLine);
445 3 : OGRFeature::DestroyFeature(IT->second);
446 3 : ++IT;
447 3 : nCounter--;
448 : }
449 :
450 : // Get last part
451 1 : double dfPosEndCorr = dfPosEnd - IT->first;
452 1 : dfSF = IT->second->GetFieldAsDouble(FIELD_SCALE_FACTOR);
453 1 : dfPosEndCorr *= dfSF;
454 :
455 1 : pLine = IT->second->GetGeometryRef()->toLineString();
456 :
457 1 : pSubLine = pLine->getSubLine(0, dfPosEndCorr, FALSE);
458 :
459 1 : pOutLine->addSubLineString(pSubLine);
460 1 : delete pSubLine;
461 :
462 1 : OGRFeature::DestroyFeature(IT->second);
463 : // Store
464 1 : return AddFeature(poOutLayer, pOutLine, dfPosBeg, dfPosEnd, 1.0,
465 1 : bQuiet);
466 : }
467 : }
468 :
469 : //------------------------------------------------------------------------
470 : // Project
471 : //------------------------------------------------------------------------
472 : #ifdef HAVE_GEOS
473 66 : static double Project(OGRLineString *pLine, OGRPoint *pPoint)
474 : {
475 66 : if (nullptr == pLine || nullptr == pPoint)
476 0 : return -1;
477 132 : OGRPoint TestPoint;
478 66 : pLine->StartPoint(&TestPoint);
479 66 : if (TestPoint.Equals(pPoint))
480 2 : return 0.0;
481 64 : pLine->EndPoint(&TestPoint);
482 64 : if (TestPoint.Equals(pPoint))
483 2 : return pLine->get_Length();
484 :
485 62 : return pLine->Project(pPoint);
486 : }
487 : #endif
488 :
489 : //------------------------------------------------------------------------
490 : // CreatePartsFromLineString
491 : //------------------------------------------------------------------------
492 : #ifdef HAVE_GEOS
493 2 : static OGRErr CreatePartsFromLineString(
494 : OGRLineString *pPathGeom, OGRLayer *const poPkLayer, int nMValField,
495 : double dfStep, OGRLayer *const poOutLayer, int bDisplayProgress,
496 : bool bQuiet, const char *pszOutputSepFieldName = nullptr,
497 : const char *pszOutputSepFieldValue = nullptr)
498 : {
499 : // Check repers/milestones/reference points type
500 2 : OGRwkbGeometryType eGeomType = poPkLayer->GetGeomType();
501 2 : if (wkbFlatten(eGeomType) != wkbPoint)
502 : {
503 0 : fprintf(stderr, _("Unsupported geometry type %s for path\n"),
504 : OGRGeometryTypeToName(eGeomType));
505 0 : return OGRERR_FAILURE;
506 : }
507 :
508 2 : double dfTolerance = 1.0;
509 2 : const OGRSpatialReference *pSpaRef = pPathGeom->getSpatialReference();
510 2 : if (pSpaRef->IsGeographic())
511 : {
512 2 : dfTolerance = TOLERANCE_DEGREE;
513 : }
514 : else
515 : {
516 0 : dfTolerance = TOLERANCE_METER;
517 : }
518 :
519 : // Create sorted list of repers.
520 4 : std::map<double, OGRPoint *> moRepers;
521 2 : poPkLayer->ResetReading();
522 2 : OGRFeature *pReperFeature = nullptr;
523 16 : while ((pReperFeature = poPkLayer->GetNextFeature()) != nullptr)
524 : {
525 14 : const double dfReperPos = pReperFeature->GetFieldAsDouble(nMValField);
526 14 : OGRGeometry *pGeom = pReperFeature->GetGeometryRef();
527 14 : if (nullptr != pGeom)
528 : {
529 14 : OGRPoint *pPt = pGeom->clone()->toPoint();
530 14 : if (!bQuiet)
531 : {
532 14 : if (moRepers.find(dfReperPos) != moRepers.end())
533 : {
534 0 : CPLError(
535 : CE_Warning, CPLE_AppDefined,
536 : "The distance %f is already present in repers file!",
537 : dfReperPos);
538 : }
539 : }
540 : // Check if reper is inside the path
541 14 : const double dfTestDistance = Project(pPathGeom, pPt);
542 14 : if (dfTestDistance < 0)
543 : {
544 0 : if (!bQuiet)
545 : {
546 0 : CPLError(CE_Warning, CPLE_AppDefined,
547 : "The distance %f is out of path!", dfReperPos);
548 : }
549 0 : delete pPt;
550 : }
551 : else
552 : {
553 14 : const double dfDist = pPathGeom->Distance(pPt);
554 14 : if (dfDist < dfTolerance)
555 6 : moRepers[dfReperPos] = pPt;
556 : else
557 8 : delete pPt;
558 : }
559 : }
560 14 : OGRFeature::DestroyFeature(pReperFeature);
561 : }
562 :
563 2 : if (moRepers.size() < 2)
564 : {
565 0 : fprintf(stderr, _("Not enough repers to proceed.\n"));
566 0 : return OGRERR_FAILURE;
567 : }
568 :
569 : // Check direction.
570 2 : if (!bQuiet)
571 : {
572 2 : fprintf(stdout, "Check path direction.\n");
573 : }
574 :
575 : // Get distance along path from pt1 and pt2.
576 : // If pt1 distance > pt2 distance, reverse path
577 2 : std::map<double, OGRPoint *>::const_iterator IT;
578 2 : IT = moRepers.begin();
579 2 : double dfPosition = IT->first;
580 2 : double dfBeginPosition = IT->first;
581 2 : OGRPoint *pt1 = IT->second;
582 2 : ++IT;
583 2 : OGRPoint *pt2 = IT->second;
584 :
585 2 : double dfDistance1 = Project(pPathGeom, pt1);
586 2 : double dfDistance2 = Project(pPathGeom, pt2);
587 :
588 2 : if (dfDistance1 > dfDistance2)
589 : {
590 0 : if (!bQuiet)
591 : {
592 0 : fprintf(stderr,
593 : _("Warning: The path is opposite the repers direction. "
594 : "Let's reverse path.\n"));
595 : }
596 0 : pPathGeom->reversePoints();
597 :
598 0 : dfDistance1 = Project(pPathGeom, pt1);
599 0 : dfDistance2 = Project(pPathGeom, pt2);
600 : }
601 :
602 2 : OGRLineString *pPart = nullptr;
603 :
604 2 : std::vector<CURVE_DATA> astSubLines;
605 :
606 2 : if (!bQuiet)
607 : {
608 2 : fprintf(stdout, "Create parts\n");
609 : }
610 :
611 : // Get first part
612 : // If first point is not at the beginning of the path
613 : // The first part should be from the beginning of the path
614 : // to the first point. length == part.getLength
615 2 : OGRPoint *pPtBeg = nullptr;
616 2 : OGRPoint *pPtEnd = nullptr;
617 2 : double dfPtBegPosition = 0.0;
618 2 : double dfPtEndPosition = 0.0;
619 :
620 2 : if (dfDistance1 > DELTA)
621 : {
622 2 : pPart = pPathGeom->getSubLine(0, dfDistance1, FALSE);
623 2 : if (nullptr != pPart)
624 : {
625 2 : double dfLen = pPart->get_Length();
626 2 : if (pSpaRef->IsGeographic())
627 : {
628 : // convert to UTM/WGS84
629 4 : OGRPoint pt;
630 2 : pPart->Value(dfLen / 2, &pt);
631 : const int nZoneEnv =
632 2 : static_cast<int>(30 + (pt.getX() + 3.0) / 6.0 + 0.5);
633 : int nEPSG;
634 2 : if (pt.getY() > 0)
635 : {
636 2 : nEPSG = 32600 + nZoneEnv;
637 : }
638 : else
639 : {
640 0 : nEPSG = 32700 + nZoneEnv;
641 : }
642 4 : OGRSpatialReference SpatRef;
643 2 : SpatRef.importFromEPSG(nEPSG);
644 2 : OGRGeometry *pTransformPart = pPart->clone();
645 2 : if (pTransformPart->transformTo(&SpatRef) == OGRERR_NONE)
646 : {
647 : OGRLineString *pTransformPartLS =
648 2 : pTransformPart->toLineString();
649 2 : dfLen = pTransformPartLS->get_Length();
650 : }
651 :
652 2 : CURVE_DATA data = {pPart, dfPosition - dfLen, dfPosition,
653 2 : pPart->get_Length() / dfLen};
654 2 : astSubLines.push_back(data);
655 :
656 2 : pPtBeg = new OGRPoint();
657 2 : pPart->getPoint(0, pPtBeg);
658 2 : dfPtBegPosition = dfPosition - dfLen;
659 :
660 : // AddFeature(poOutLayer, pPart, dfPosition - dfLen, dfPosition,
661 : // pPart->get_Length() / dfLen, bQuiet);
662 2 : delete pTransformPart;
663 : }
664 : else
665 : {
666 0 : CURVE_DATA data = {pPart, dfPosition - dfLen, dfPosition, 1.0};
667 0 : astSubLines.push_back(data);
668 : // AddFeature(poOutLayer, pPart, dfPosition - dfLen, dfPosition,
669 : // 1.0, bQuiet);
670 0 : pPtBeg = new OGRPoint();
671 0 : pPart->getPoint(0, pPtBeg);
672 0 : dfPtBegPosition = dfPosition - dfLen;
673 : }
674 : }
675 : }
676 :
677 2 : if (dfDistance2 - dfDistance1 > DELTA)
678 : {
679 2 : pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
680 2 : if (nullptr != pPart)
681 : {
682 4 : CURVE_DATA data = {pPart, dfPosition, IT->first,
683 2 : pPart->get_Length() / (IT->first - dfPosition)};
684 2 : astSubLines.push_back(data);
685 : // AddFeature(poOutLayer, pPart, dfPosition, IT->first,
686 : // pPart->get_Length() / (IT->first - dfPosition),
687 : // bQuiet);
688 : }
689 : }
690 :
691 2 : GDALProgressFunc pfnProgress = nullptr;
692 2 : void *pProgressArg = nullptr;
693 :
694 2 : double dfFactor = 1.0 / moRepers.size();
695 2 : if (bDisplayProgress)
696 : {
697 0 : pfnProgress = GDALScaledProgress;
698 : pProgressArg =
699 0 : GDALCreateScaledProgress(0.0, 1.0, GDALTermProgress, nullptr);
700 : }
701 :
702 2 : int nCount = 2;
703 2 : dfDistance1 = dfDistance2;
704 2 : dfPosition = IT->first;
705 2 : ++IT; // Get third point
706 :
707 2 : double dfEndPosition = 0.0;
708 4 : while (IT != moRepers.end())
709 : {
710 2 : if (bDisplayProgress)
711 : {
712 0 : pfnProgress(nCount * dfFactor, "", pProgressArg);
713 0 : nCount++;
714 : }
715 :
716 2 : dfEndPosition = IT->first;
717 :
718 2 : dfDistance2 = Project(pPathGeom, IT->second);
719 :
720 2 : if (dfDistance2 - dfDistance1 > DELTA)
721 : {
722 2 : pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
723 2 : if (nullptr != pPart)
724 : {
725 4 : CURVE_DATA data = {pPart, dfPosition, IT->first,
726 6 : pPart->get_Length() /
727 2 : (IT->first - dfPosition)};
728 2 : astSubLines.push_back(data);
729 : // AddFeature(poOutLayer, pPart, dfPosition, IT->first,
730 : // pPart->get_Length() / (IT->first - dfPosition),
731 : // bQuiet);
732 2 : dfDistance1 = dfDistance2;
733 2 : dfPosition = IT->first;
734 : }
735 : }
736 :
737 2 : ++IT;
738 : }
739 :
740 : // Get last part
741 2 : if (pPathGeom->get_Length() - dfDistance1 > DELTA)
742 : {
743 : pPart =
744 2 : pPathGeom->getSubLine(dfDistance1, pPathGeom->get_Length(), FALSE);
745 2 : if (nullptr != pPart)
746 : {
747 2 : double dfLen = pPart->get_Length();
748 2 : if (pSpaRef->IsGeographic())
749 : {
750 : // convert to UTM/WGS84
751 4 : OGRPoint pt;
752 2 : pPart->Value(dfLen / 2, &pt);
753 : const int nZoneEnv =
754 2 : static_cast<int>(30 + (pt.getX() + 3.0) / 6.0 + 0.5);
755 : int nEPSG;
756 2 : if (pt.getY() > 0)
757 : {
758 2 : nEPSG = 32600 + nZoneEnv;
759 : }
760 : else
761 : {
762 0 : nEPSG = 32700 + nZoneEnv;
763 : }
764 4 : OGRSpatialReference SpatRef;
765 2 : SpatRef.importFromEPSG(nEPSG);
766 2 : OGRGeometry *pTransformPart = pPart->clone();
767 2 : if (pTransformPart->transformTo(&SpatRef) == OGRERR_NONE)
768 : {
769 : OGRLineString *pTransformPartLS =
770 2 : pTransformPart->toLineString();
771 2 : dfLen = pTransformPartLS->get_Length();
772 : }
773 2 : CURVE_DATA data = {pPart, dfPosition, dfPosition + dfLen,
774 2 : pPart->get_Length() / dfLen};
775 2 : astSubLines.push_back(data);
776 : // AddFeature(poOutLayer, pPart, dfPosition, dfPosition + dfLen,
777 : // pPart->get_Length() / dfLen, bQuiet);
778 :
779 2 : pPtEnd = new OGRPoint();
780 2 : pPart->getPoint(pPart->getNumPoints() - 1, pPtEnd);
781 2 : dfPtEndPosition = dfPosition + dfLen;
782 :
783 2 : delete pTransformPart;
784 : }
785 : else
786 : {
787 0 : CURVE_DATA data = {pPart, dfPosition, dfPosition + dfLen, 1.0};
788 0 : astSubLines.push_back(data);
789 : // AddFeature(poOutLayer, pPart, dfPosition - dfLen, dfPosition,
790 : // 1.0, bQuiet);
791 0 : pPtEnd = new OGRPoint();
792 0 : pPart->getPoint(pPart->getNumPoints() - 1, pPtEnd);
793 0 : dfPtEndPosition = dfPosition + dfLen;
794 : }
795 : }
796 : }
797 :
798 : // Create pickets
799 2 : if (!bQuiet)
800 : {
801 2 : fprintf(stdout, "\nCreate pickets.\n");
802 : }
803 :
804 2 : const double dfRoundBeg = pPtBeg != nullptr
805 2 : ? ceil(dfPtBegPosition / dfStep) * dfStep
806 0 : : ceil(dfBeginPosition / dfStep) * dfStep;
807 :
808 2 : if (pPtEnd != nullptr)
809 2 : dfEndPosition = dfPtEndPosition;
810 :
811 2 : dfFactor = dfStep / (dfEndPosition - dfRoundBeg);
812 2 : nCount = 0;
813 8 : for (std::map<double, OGRPoint *>::iterator oIter = moRepers.begin();
814 14 : oIter != moRepers.end(); ++oIter)
815 : {
816 6 : delete oIter->second;
817 : }
818 :
819 2 : moRepers.clear();
820 :
821 2 : if (pPtBeg != nullptr)
822 2 : moRepers[dfPtBegPosition] = pPtBeg;
823 2 : if (pPtEnd != nullptr)
824 2 : moRepers[dfPtEndPosition] = pPtEnd;
825 :
826 43 : for (double dfDist = dfRoundBeg; dfDist <= dfEndPosition; dfDist += dfStep)
827 : {
828 41 : if (bDisplayProgress)
829 : {
830 0 : pfnProgress(nCount * dfFactor, "", pProgressArg);
831 0 : nCount++;
832 : }
833 :
834 70 : for (int j = 0; j < static_cast<int>(astSubLines.size()); j++)
835 : {
836 70 : if (astSubLines[j].IsInside(dfDist))
837 : {
838 : const double dfRealDist =
839 41 : (dfDist - astSubLines[j].dfBeg) * astSubLines[j].dfFactor;
840 41 : OGRPoint *pReperPoint = new OGRPoint();
841 41 : astSubLines[j].pPart->Value(dfRealDist, pReperPoint);
842 :
843 41 : moRepers[dfDist] = pReperPoint;
844 41 : break;
845 : }
846 : }
847 : }
848 :
849 10 : for (int i = 0; i < static_cast<int>(astSubLines.size()); i++)
850 : {
851 8 : delete astSubLines[i].pPart;
852 : }
853 2 : astSubLines.clear();
854 :
855 2 : if (!bQuiet)
856 : {
857 2 : fprintf(stdout, "\nCreate sublines.\n");
858 : }
859 :
860 2 : IT = moRepers.begin();
861 2 : dfFactor = 1.0 / moRepers.size();
862 2 : nCount = 0;
863 2 : dfDistance1 = 0;
864 2 : dfPosition = IT->first;
865 :
866 47 : while (IT != moRepers.end())
867 : {
868 45 : if (bDisplayProgress)
869 : {
870 0 : pfnProgress(nCount * dfFactor, "", pProgressArg);
871 0 : nCount++;
872 : }
873 :
874 45 : dfDistance2 = Project(pPathGeom, IT->second);
875 :
876 45 : if (dfDistance2 - dfDistance1 > DELTA)
877 : {
878 43 : pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
879 43 : if (nullptr != pPart)
880 : {
881 43 : AddFeature(poOutLayer, pPart, dfPosition, IT->first,
882 43 : pPart->get_Length() / (IT->first - dfPosition),
883 : bQuiet, pszOutputSepFieldName,
884 : pszOutputSepFieldValue);
885 43 : dfDistance1 = dfDistance2;
886 43 : dfPosition = IT->first;
887 : }
888 : }
889 :
890 45 : ++IT;
891 : }
892 :
893 47 : for (std::map<double, OGRPoint *>::iterator oIter = moRepers.begin();
894 92 : oIter != moRepers.end(); ++oIter)
895 : {
896 45 : delete oIter->second;
897 : }
898 :
899 2 : if (!bQuiet)
900 : {
901 2 : fprintf(stdout, "\nSuccess!\n\n");
902 : }
903 :
904 2 : if (nullptr != pProgressArg)
905 : {
906 0 : GDALDestroyScaledProgress(pProgressArg);
907 : }
908 :
909 2 : return OGRERR_NONE;
910 : }
911 : #endif
912 :
913 : //------------------------------------------------------------------------
914 : // CreateParts
915 : //------------------------------------------------------------------------
916 : #ifdef HAVE_GEOS
917 2 : static OGRErr CreateParts(OGRLayer *const poLnLayer, OGRLayer *const poPkLayer,
918 : int nMValField, double dfStep,
919 : OGRLayer *const poOutLayer, int bDisplayProgress,
920 : bool bQuiet,
921 : const char *pszOutputSepFieldName = nullptr,
922 : const char *pszOutputSepFieldValue = nullptr)
923 : {
924 2 : OGRErr eRetCode = OGRERR_FAILURE;
925 :
926 : // check path and get first line
927 2 : OGRwkbGeometryType eGeomType = poLnLayer->GetGeomType();
928 2 : if (wkbFlatten(eGeomType) != wkbLineString &&
929 0 : wkbFlatten(eGeomType) != wkbMultiLineString)
930 : {
931 0 : fprintf(stderr, _("Unsupported geometry type %s for path.\n"),
932 : OGRGeometryTypeToName(eGeomType));
933 0 : return eRetCode;
934 : }
935 :
936 2 : poLnLayer->ResetReading();
937 : // Get first geometry
938 : // TODO: Attribute filter for path geometry.
939 2 : OGRFeature *pPathFeature = poLnLayer->GetNextFeature();
940 2 : if (nullptr != pPathFeature)
941 : {
942 2 : OGRGeometry *pGeom = pPathFeature->GetGeometryRef();
943 :
944 4 : if (pGeom != nullptr &&
945 2 : wkbFlatten(pGeom->getGeometryType()) == wkbMultiLineString)
946 : {
947 0 : if (!bQuiet)
948 : {
949 0 : fprintf(stdout,
950 : _("\nThe geometry " CPL_FRMT_GIB
951 : " is wkbMultiLineString type.\n"),
952 : pPathFeature->GetFID());
953 : }
954 :
955 0 : OGRGeometryCollection *pGeomColl = pGeom->toGeometryCollection();
956 0 : for (int i = 0; i < pGeomColl->getNumGeometries(); ++i)
957 : {
958 : OGRLineString *pPath =
959 0 : pGeomColl->getGeometryRef(i)->clone()->toLineString();
960 0 : pPath->assignSpatialReference(pGeomColl->getSpatialReference());
961 0 : eRetCode = CreatePartsFromLineString(
962 : pPath, poPkLayer, nMValField, dfStep, poOutLayer,
963 : bDisplayProgress, bQuiet, pszOutputSepFieldName,
964 : pszOutputSepFieldValue);
965 :
966 0 : if (eRetCode != OGRERR_NONE)
967 : {
968 0 : OGRFeature::DestroyFeature(pPathFeature);
969 0 : return eRetCode;
970 : }
971 : }
972 : }
973 4 : else if (pGeom != nullptr &&
974 2 : wkbFlatten(pGeom->getGeometryType()) == wkbLineString)
975 : {
976 2 : OGRLineString *pGeomClone = pGeom->clone()->toLineString();
977 2 : eRetCode = CreatePartsFromLineString(
978 : pGeomClone, poPkLayer, nMValField, dfStep, poOutLayer,
979 : bDisplayProgress, bQuiet, pszOutputSepFieldName,
980 : pszOutputSepFieldValue);
981 2 : delete pGeomClone;
982 : }
983 :
984 2 : OGRFeature::DestroyFeature(pPathFeature);
985 : }
986 :
987 : // Should never reach
988 :
989 2 : return eRetCode;
990 : }
991 : #endif
992 :
993 : //------------------------------------------------------------------------
994 : // CreatePartsMultiple
995 : //------------------------------------------------------------------------
996 : #ifdef HAVE_GEOS
997 0 : static OGRErr CreatePartsMultiple(
998 : OGRLayer *const poLnLayer, const char *pszLineSepFieldName,
999 : OGRLayer *const poPkLayer, const char *pszPicketsSepFieldName,
1000 : int nMValField, double dfStep, OGRLayer *const poOutLayer,
1001 : const char *pszOutputSepFieldName, int bDisplayProgress, bool bQuiet)
1002 : {
1003 : // Read all separate field values into array
1004 0 : OGRFeatureDefn *pDefn = poLnLayer->GetLayerDefn();
1005 0 : const int nLineSepFieldInd = pDefn->GetFieldIndex(pszLineSepFieldName);
1006 0 : if (nLineSepFieldInd == -1)
1007 : {
1008 0 : fprintf(stderr, _("The field was %s not found.\n"),
1009 : pszLineSepFieldName);
1010 0 : return OGRERR_FAILURE;
1011 : }
1012 :
1013 0 : poLnLayer->ResetReading();
1014 :
1015 0 : std::set<CPLString> asIDs;
1016 0 : OGRFeature *pFeature = nullptr;
1017 0 : while ((pFeature = poLnLayer->GetNextFeature()) != nullptr)
1018 : {
1019 0 : CPLString sID = pFeature->GetFieldAsString(nLineSepFieldInd);
1020 0 : asIDs.insert(sID);
1021 :
1022 0 : OGRFeature::DestroyFeature(pFeature);
1023 : }
1024 :
1025 0 : for (std::set<CPLString>::const_iterator it = asIDs.begin();
1026 0 : it != asIDs.end(); ++it)
1027 : {
1028 : // Create select clause
1029 0 : CPLString sLineWhere;
1030 0 : sLineWhere.Printf("%s = '%s'", pszLineSepFieldName, it->c_str());
1031 0 : poLnLayer->SetAttributeFilter(sLineWhere);
1032 :
1033 0 : CPLString sPkWhere;
1034 0 : sPkWhere.Printf("%s = '%s'", pszPicketsSepFieldName, it->c_str());
1035 0 : poPkLayer->SetAttributeFilter(sPkWhere);
1036 :
1037 0 : if (!bQuiet)
1038 : {
1039 0 : fprintf(stdout, "The %s %s\n", pszPicketsSepFieldName, it->c_str());
1040 : }
1041 :
1042 : // Don't check success as we want to try all paths
1043 0 : CreateParts(poLnLayer, poPkLayer, nMValField, dfStep, poOutLayer,
1044 0 : bDisplayProgress, bQuiet, pszOutputSepFieldName, *it);
1045 : }
1046 :
1047 0 : return OGRERR_NONE;
1048 : }
1049 : #endif
1050 :
1051 : //------------------------------------------------------------------------
1052 : // GetPosition
1053 : //------------------------------------------------------------------------
1054 : #ifdef HAVE_GEOS
1055 1 : static OGRErr GetPosition(OGRLayer *const poPkLayer, double dfX, double dfY,
1056 : int /* bDisplayProgress */, int bQuiet)
1057 : {
1058 : // Create point
1059 2 : OGRPoint pt;
1060 1 : pt.setX(dfX);
1061 1 : pt.setY(dfY);
1062 1 : pt.assignSpatialReference(poPkLayer->GetSpatialRef());
1063 :
1064 1 : poPkLayer->ResetReading();
1065 1 : OGRLineString *pCloserPart = nullptr;
1066 1 : double dfBeg = 0.0;
1067 1 : double dfScale = 0.0;
1068 1 : double dfMinDistance = std::numeric_limits<double>::max();
1069 1 : OGRFeature *pFeature = nullptr;
1070 10 : while ((pFeature = poPkLayer->GetNextFeature()) != nullptr)
1071 : {
1072 9 : OGRGeometry *pCurrentGeom = pFeature->GetGeometryRef();
1073 9 : if (pCurrentGeom != nullptr)
1074 : {
1075 9 : double dfCurrentDistance = pCurrentGeom->Distance(&pt);
1076 9 : if (dfCurrentDistance < dfMinDistance)
1077 : {
1078 5 : dfMinDistance = dfCurrentDistance;
1079 5 : if (pCloserPart != nullptr)
1080 4 : delete pCloserPart;
1081 5 : pCloserPart = pFeature->StealGeometry()->toLineString();
1082 5 : dfBeg = pFeature->GetFieldAsDouble(FIELD_START);
1083 5 : dfScale = pFeature->GetFieldAsDouble(FIELD_SCALE_FACTOR);
1084 : }
1085 : }
1086 9 : OGRFeature::DestroyFeature(pFeature);
1087 : }
1088 :
1089 1 : if (nullptr == pCloserPart)
1090 : {
1091 0 : fprintf(stderr, _("Failed to find closest part.\n"));
1092 0 : return OGRERR_FAILURE;
1093 : }
1094 : // Now we have closest part
1095 : // Get real distance
1096 1 : const double dfRealDist = Project(pCloserPart, &pt);
1097 1 : delete pCloserPart;
1098 1 : if (dfScale == 0)
1099 : {
1100 0 : fprintf(stderr, _("dfScale == 0.\n"));
1101 0 : return OGRERR_FAILURE;
1102 : }
1103 : // Compute reference distance
1104 : // coverity[divide_by_zero]
1105 1 : const double dfRefDist = dfBeg + dfRealDist / dfScale;
1106 1 : if (bQuiet)
1107 : {
1108 1 : fprintf(stdout, "%s", CPLSPrintf("%f\n", dfRefDist));
1109 : }
1110 : else
1111 : {
1112 0 : fprintf(stdout, "%s",
1113 : CPLSPrintf(
1114 : _("The position for coordinates lat:%f, long:%f is %f\n"),
1115 : dfY, dfX, dfRefDist));
1116 : }
1117 :
1118 1 : return OGRERR_NONE;
1119 : }
1120 : #endif
1121 :
1122 : //------------------------------------------------------------------------
1123 : // GetCoordinates
1124 : //------------------------------------------------------------------------
1125 1 : static OGRErr GetCoordinates(OGRLayer *const poPkLayer, double dfPos,
1126 : /* CPL_UNUSED */ int /* bDisplayProgress */,
1127 : bool bQuiet)
1128 : {
1129 2 : CPLString szAttributeFilter;
1130 : szAttributeFilter.Printf("%s < %f AND %s > %f", FIELD_START, dfPos,
1131 1 : FIELD_FINISH, dfPos);
1132 : // TODO: ExecuteSQL should be faster.
1133 1 : poPkLayer->SetAttributeFilter(szAttributeFilter);
1134 1 : poPkLayer->ResetReading();
1135 :
1136 1 : bool bHaveCoords = false;
1137 2 : for (auto &pFeature : poPkLayer)
1138 : {
1139 1 : bHaveCoords = true;
1140 1 : const double dfStart = pFeature->GetFieldAsDouble(FIELD_START);
1141 1 : double dfPosCorr = dfPos - dfStart;
1142 1 : const double dfSF = pFeature->GetFieldAsDouble(FIELD_SCALE_FACTOR);
1143 1 : dfPosCorr *= dfSF;
1144 1 : OGRLineString *pLine = pFeature->GetGeometryRef()->toLineString();
1145 :
1146 2 : OGRPoint pt;
1147 1 : pLine->Value(dfPosCorr, &pt);
1148 :
1149 1 : if (bQuiet)
1150 : {
1151 1 : fprintf(stdout, "%s",
1152 : CPLSPrintf("%f,%f,%f\n", pt.getX(), pt.getY(), pt.getZ()));
1153 : }
1154 : else
1155 : {
1156 0 : fprintf(stdout, "%s",
1157 : CPLSPrintf(_("The position for distance %f is lat:%f, "
1158 : "long:%f, height:%f\n"),
1159 : dfPos, pt.getY(), pt.getX(), pt.getZ()));
1160 : }
1161 : }
1162 :
1163 1 : if (bHaveCoords)
1164 : {
1165 1 : return OGRERR_NONE;
1166 : }
1167 : else
1168 : {
1169 0 : fprintf(stderr, _("Get coordinates for position %f failed.\n"), dfPos);
1170 0 : return OGRERR_FAILURE;
1171 : }
1172 : }
1173 :
1174 : /************************************************************************/
1175 : /* OGRLineRefOptions */
1176 : /************************************************************************/
1177 :
1178 : struct OGRLineRefOptions
1179 : {
1180 : bool bQuiet = false;
1181 : bool bDisplayProgress = false;
1182 : std::string osFormat = "ESRI Shapefile";
1183 :
1184 : std::string osSrcLineDataSourceName;
1185 : std::string osSrcLineLayerName;
1186 : #ifdef HAVE_GEOS
1187 : std::string osSrcLineSepFieldName;
1188 : #endif
1189 :
1190 : std::string osSrcPicketsDataSourceName;
1191 : #ifdef HAVE_GEOS
1192 : std::string osSrcPicketsLayerName;
1193 : std::string osSrcPicketsSepFieldName;
1194 : std::string osSrcPicketsMFieldName;
1195 : #endif
1196 :
1197 : std::string osSrcPartsDataSourceName;
1198 : std::string osSrcPartsLayerName;
1199 :
1200 : #ifdef HAVE_GEOS
1201 : std::string osOutputSepFieldName = "uniq_uid";
1202 : #endif
1203 : std::string osOutputDataSourceName;
1204 : std::string osOutputLayerName;
1205 :
1206 : CPLStringList aosDSCO;
1207 : CPLStringList aosLCO;
1208 :
1209 : // Operations
1210 : bool bCreate = false;
1211 : bool bGetPos = false;
1212 : bool bGetSubLine = false;
1213 : bool bGetCoord = false;
1214 :
1215 : #ifdef HAVE_GEOS
1216 : double dfXPos = std::numeric_limits<double>::quiet_NaN();
1217 : double dfYPos = std::numeric_limits<double>::quiet_NaN();
1218 : double dfStep = std::numeric_limits<double>::quiet_NaN();
1219 : #endif
1220 : double dfPosBeg = std::numeric_limits<double>::quiet_NaN();
1221 : double dfPosEnd = std::numeric_limits<double>::quiet_NaN();
1222 : double dfPos = std::numeric_limits<double>::quiet_NaN();
1223 : };
1224 :
1225 : /************************************************************************/
1226 : /* OGRLineRefGetParser */
1227 : /************************************************************************/
1228 :
1229 : static std::unique_ptr<GDALArgumentParser>
1230 6 : OGRLineRefAppOptionsGetParser(OGRLineRefOptions *psOptions)
1231 : {
1232 : auto argParser = std::make_unique<GDALArgumentParser>(
1233 6 : "ogrlineref", /* bForBinary */ true);
1234 :
1235 6 : argParser->add_description(
1236 6 : _("Create linear reference and provide some calculations using it."));
1237 :
1238 6 : argParser->add_epilog(_("For more details, consult the full documentation "
1239 : "for the ogrlineref utility "
1240 6 : "https://gdal.org/programs/ogrlineref.html"));
1241 :
1242 6 : auto &quietArg{argParser->add_quiet_argument(&psOptions->bQuiet)};
1243 6 : argParser->add_hidden_alias_for(quietArg, "-quiet");
1244 :
1245 6 : argParser->add_argument("-progress")
1246 6 : .flag()
1247 6 : .store_into(psOptions->bDisplayProgress)
1248 6 : .help(_("Display progress."));
1249 :
1250 6 : argParser->add_output_format_argument(psOptions->osFormat);
1251 :
1252 6 : argParser->add_dataset_creation_options_argument(psOptions->aosDSCO);
1253 :
1254 6 : argParser->add_layer_creation_options_argument(psOptions->aosLCO);
1255 :
1256 : #ifdef HAVE_GEOS
1257 6 : argParser->add_argument("-create")
1258 6 : .flag()
1259 6 : .store_into(psOptions->bCreate)
1260 6 : .help(_("Create the linear reference file (linestring of parts)."));
1261 : #endif
1262 :
1263 6 : argParser->add_argument("-l")
1264 12 : .metavar("<src_line_datasource_name>")
1265 6 : .store_into(psOptions->osSrcLineDataSourceName)
1266 6 : .help(_("Name of the line path datasource."));
1267 :
1268 6 : argParser->add_argument("-ln")
1269 12 : .metavar("<layer_name>")
1270 6 : .store_into(psOptions->osSrcLineLayerName)
1271 6 : .help(_("Layer name in the line path datasource."));
1272 :
1273 : #ifdef HAVE_GEOS
1274 :
1275 6 : argParser->add_argument("-lf")
1276 12 : .metavar("<field_name>")
1277 6 : .store_into(psOptions->osSrcLineSepFieldName)
1278 6 : .help(_("Field name for unique paths in layer."));
1279 : #endif
1280 :
1281 6 : argParser->add_argument("-p")
1282 12 : .metavar("<src_repers_datasource_name>")
1283 6 : .store_into(psOptions->osSrcPicketsDataSourceName)
1284 6 : .help(_("Datasource of repers name."));
1285 :
1286 : #ifdef HAVE_GEOS
1287 6 : argParser->add_argument("-pn")
1288 12 : .metavar("<layer_name>")
1289 6 : .store_into(psOptions->osSrcPicketsLayerName)
1290 6 : .help(_("Layer name in repers datasource."));
1291 :
1292 6 : argParser->add_argument("-pm")
1293 12 : .metavar("<pos_field_name>")
1294 6 : .store_into(psOptions->osSrcPicketsMFieldName)
1295 6 : .help(_("Line position field name."));
1296 :
1297 6 : argParser->add_argument("-pf")
1298 12 : .metavar("<field_name>")
1299 6 : .store_into(psOptions->osSrcPicketsSepFieldName)
1300 : .help(_("Field name of unique values to map input reference points "
1301 6 : "to lines."));
1302 : #endif
1303 :
1304 6 : argParser->add_argument("-r")
1305 12 : .metavar("<src_parts_datasource_name>")
1306 6 : .store_into(psOptions->osSrcPartsDataSourceName)
1307 6 : .help(_("Path to linear reference file."));
1308 :
1309 6 : argParser->add_argument("-rn")
1310 12 : .metavar("<layer_name>")
1311 6 : .store_into(psOptions->osSrcPartsLayerName)
1312 6 : .help(_("Name of the layer in the input linear reference datasource."));
1313 :
1314 6 : argParser->add_argument("-o")
1315 12 : .metavar("<dst_datasource_name>")
1316 6 : .store_into(psOptions->osOutputDataSourceName)
1317 : .help(_("Path to output linear reference file (linestring "
1318 6 : "datasource)."));
1319 :
1320 6 : argParser->add_argument("-on")
1321 12 : .metavar("<layer_name>")
1322 6 : .store_into(psOptions->osOutputLayerName)
1323 : .help(_("Name of the layer in the output linear reference "
1324 6 : "datasource."));
1325 :
1326 : #ifdef HAVE_GEOS
1327 6 : argParser->add_argument("-of")
1328 12 : .metavar("<field_name>")
1329 6 : .store_into(psOptions->osOutputSepFieldName)
1330 : .help(_(
1331 6 : "Name of the field for storing the unique values of input lines."));
1332 :
1333 6 : argParser->add_argument("-s")
1334 12 : .metavar("<step>")
1335 6 : .scan<'g', double>()
1336 6 : .store_into(psOptions->dfStep)
1337 6 : .help(_("Part size in linear units."));
1338 :
1339 6 : argParser->add_argument("-get_pos")
1340 6 : .flag()
1341 6 : .store_into(psOptions->bGetPos)
1342 6 : .help(_("Get the position for the given coordinates."));
1343 :
1344 6 : argParser->add_argument("-x")
1345 12 : .metavar("<x>")
1346 6 : .scan<'g', double>()
1347 6 : .store_into(psOptions->dfXPos)
1348 6 : .help(_("X coordinate."));
1349 :
1350 6 : argParser->add_argument("-y")
1351 12 : .metavar("<y>")
1352 6 : .scan<'g', double>()
1353 6 : .store_into(psOptions->dfYPos)
1354 6 : .help(_("Y coordinate."));
1355 : #endif
1356 :
1357 6 : argParser->add_argument("-get_coord")
1358 6 : .flag()
1359 6 : .store_into(psOptions->bGetCoord)
1360 6 : .help(_("Return point on path for input linear distance."));
1361 :
1362 6 : argParser->add_argument("-m")
1363 12 : .metavar("<position>")
1364 6 : .scan<'g', double>()
1365 6 : .store_into(psOptions->dfPos)
1366 6 : .help(_("Input linear distance."));
1367 :
1368 6 : argParser->add_argument("-get_subline")
1369 6 : .flag()
1370 6 : .store_into(psOptions->bGetSubLine)
1371 : .help(_("Return the portion of the input path from and to input linear "
1372 6 : "positions."));
1373 :
1374 6 : argParser->add_argument("-mb")
1375 12 : .metavar("<position>")
1376 6 : .scan<'g', double>()
1377 6 : .store_into(psOptions->dfPosBeg)
1378 6 : .help(_("Input linear distance begin."));
1379 :
1380 6 : argParser->add_argument("-me")
1381 12 : .metavar("<position>")
1382 6 : .scan<'g', double>()
1383 6 : .store_into(psOptions->dfPosEnd)
1384 6 : .help(_("Input linear distance end."));
1385 :
1386 6 : return argParser;
1387 : }
1388 :
1389 : /************************************************************************/
1390 : /* main() */
1391 : /************************************************************************/
1392 :
1393 6 : MAIN_START(argc, argv)
1394 :
1395 : {
1396 6 : OGRErr eErr = OGRERR_NONE;
1397 :
1398 6 : operation stOper = op_unknown;
1399 :
1400 6 : EarlySetConfigOptions(argc, argv);
1401 :
1402 6 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
1403 :
1404 6 : if (argc < 1)
1405 : {
1406 : try
1407 : {
1408 2 : OGRLineRefOptions sOptions;
1409 1 : auto argParser = OGRLineRefAppOptionsGetParser(&sOptions);
1410 1 : fprintf(stderr, "%s\n", argParser->usage().c_str());
1411 : }
1412 0 : catch (const std::exception &err)
1413 : {
1414 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
1415 0 : err.what());
1416 : }
1417 1 : exit(1);
1418 : }
1419 :
1420 5 : OGRRegisterAll();
1421 :
1422 10 : OGRLineRefOptions psOptions;
1423 5 : auto argParser = OGRLineRefAppOptionsGetParser(&psOptions);
1424 :
1425 : try
1426 : {
1427 5 : argParser->parse_args_without_binary_name(argv + 1);
1428 5 : CSLDestroy(argv);
1429 : }
1430 0 : catch (const std::exception &error)
1431 : {
1432 0 : argParser->display_error_and_usage(error);
1433 0 : CSLDestroy(argv);
1434 0 : exit(1);
1435 : }
1436 :
1437 : // Select operation mode
1438 5 : if (psOptions.bCreate)
1439 2 : stOper = op_create;
1440 :
1441 5 : if (psOptions.bGetPos)
1442 : {
1443 1 : if (stOper != op_unknown)
1444 : {
1445 0 : fprintf(stderr, _("Only one operation can be specified\n"));
1446 0 : argParser->usage();
1447 0 : exit(1);
1448 : }
1449 1 : stOper = op_get_pos;
1450 : }
1451 :
1452 5 : if (psOptions.bGetCoord)
1453 : {
1454 1 : if (stOper != op_unknown)
1455 : {
1456 0 : fprintf(stderr, _("Only one operation can be specified\n"));
1457 0 : argParser->usage();
1458 0 : exit(1);
1459 : }
1460 1 : stOper = op_get_coord;
1461 : }
1462 :
1463 5 : if (psOptions.bGetSubLine)
1464 : {
1465 1 : if (stOper != op_unknown)
1466 : {
1467 0 : fprintf(stderr, _("Only one operation can be specified\n"));
1468 0 : argParser->usage();
1469 0 : exit(1);
1470 : }
1471 1 : stOper = op_get_subline;
1472 : }
1473 :
1474 5 : if (stOper == op_unknown)
1475 : {
1476 0 : fprintf(stderr, _("No operation specified\n"));
1477 0 : argParser->usage();
1478 0 : exit(1);
1479 : }
1480 :
1481 : /* -------------------------------------------------------------------- */
1482 : /* Create linear reference */
1483 : /* -------------------------------------------------------------------- */
1484 :
1485 5 : switch (stOper)
1486 : {
1487 2 : case op_create:
1488 : {
1489 : #ifdef HAVE_GEOS
1490 2 : if (psOptions.osOutputDataSourceName.empty())
1491 : {
1492 0 : fprintf(stderr, _("No output datasource provided.\n"));
1493 0 : argParser->usage();
1494 0 : exit(1);
1495 : }
1496 2 : if (psOptions.osSrcLineDataSourceName.empty())
1497 : {
1498 0 : fprintf(stderr, _("No path datasource provided.\n"));
1499 0 : argParser->usage();
1500 0 : exit(1);
1501 : }
1502 2 : if (psOptions.osSrcPicketsMFieldName.empty())
1503 : {
1504 0 : fprintf(stderr, _("No repers position field provided.\n"));
1505 0 : argParser->usage();
1506 0 : exit(1);
1507 : }
1508 2 : if (psOptions.osSrcPicketsDataSourceName.empty())
1509 : {
1510 0 : fprintf(stderr, _("No repers datasource provided.\n"));
1511 0 : argParser->usage();
1512 0 : exit(1);
1513 : }
1514 2 : if (psOptions.dfStep == std::numeric_limits<double>::quiet_NaN())
1515 : {
1516 0 : fprintf(stderr, _("No step provided.\n"));
1517 0 : argParser->usage();
1518 0 : exit(1);
1519 : }
1520 :
1521 : /* ------------------------------------------------------------- */
1522 : /* Open data source. */
1523 : /* ------------------------------------------------------------- */
1524 :
1525 2 : GDALDataset *poLnDS = GDALDataset::FromHandle(OGROpen(
1526 : psOptions.osSrcLineDataSourceName.c_str(), FALSE, nullptr));
1527 :
1528 : /* ------------------------------------------------------------- */
1529 : /* Report failure */
1530 : /* ------------------------------------------------------------- */
1531 2 : if (poLnDS == nullptr)
1532 : {
1533 : OGRSFDriverRegistrar *poR =
1534 0 : OGRSFDriverRegistrar::GetRegistrar();
1535 :
1536 0 : fprintf(stderr,
1537 : _("FAILURE:\n"
1538 : "Unable to open path datasource `%s' with "
1539 : "the following drivers.\n"),
1540 : psOptions.osSrcLineDataSourceName.c_str());
1541 :
1542 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1543 : iDriver++)
1544 : {
1545 0 : fprintf(stderr, " -> %s\n",
1546 0 : poR->GetDriver(iDriver)->GetDescription());
1547 : }
1548 :
1549 0 : exit(1);
1550 : }
1551 :
1552 2 : GDALDataset *poPkDS = GDALDataset::FromHandle(OGROpen(
1553 : psOptions.osSrcPicketsDataSourceName.c_str(), FALSE, nullptr));
1554 :
1555 : /* --------------------------------------------------------------- */
1556 : /* Report failure */
1557 : /* --------------------------------------------------------------- */
1558 :
1559 2 : if (poPkDS == nullptr)
1560 : {
1561 : OGRSFDriverRegistrar *poR =
1562 0 : OGRSFDriverRegistrar::GetRegistrar();
1563 :
1564 0 : fprintf(stderr,
1565 : _("FAILURE:\n"
1566 : "Unable to open repers datasource `%s' "
1567 : "with the following drivers.\n"),
1568 : psOptions.osSrcPicketsDataSourceName.c_str());
1569 :
1570 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1571 : iDriver++)
1572 : {
1573 0 : fprintf(stderr, " -> %s\n",
1574 0 : poR->GetDriver(iDriver)->GetDescription());
1575 : }
1576 :
1577 0 : exit(1);
1578 : }
1579 :
1580 : /* ----------------------------------------------------------------- */
1581 : /* Find the output driver. */
1582 : /* ----------------------------------------------------------------- */
1583 :
1584 2 : if (!psOptions.bQuiet)
1585 2 : CheckDestDataSourceNameConsistency(
1586 : psOptions.osOutputDataSourceName.c_str(),
1587 : psOptions.osFormat.c_str());
1588 :
1589 2 : OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
1590 :
1591 : GDALDriver *poDriver =
1592 2 : poR->GetDriverByName(psOptions.osFormat.c_str());
1593 2 : if (poDriver == nullptr)
1594 : {
1595 0 : fprintf(stderr, _("Unable to find driver `%s'.\n"),
1596 : psOptions.osFormat.c_str());
1597 0 : fprintf(stderr, _("The following drivers are available:\n"));
1598 :
1599 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1600 : iDriver++)
1601 : {
1602 0 : fprintf(stderr, " -> `%s'\n",
1603 0 : poR->GetDriver(iDriver)->GetDescription());
1604 : }
1605 0 : exit(1);
1606 : }
1607 :
1608 2 : if (!CPLTestBool(CSLFetchNameValueDef(poDriver->GetMetadata(),
1609 : GDAL_DCAP_CREATE, "FALSE")))
1610 : {
1611 0 : fprintf(stderr,
1612 : _("%s driver does not support data source creation.\n"),
1613 : psOptions.osSrcPicketsDataSourceName.c_str());
1614 0 : exit(1);
1615 : }
1616 :
1617 : /* ---------------------------------------------------------------- */
1618 : /* Create the output data source. */
1619 : /* ---------------------------------------------------------------- */
1620 : GDALDataset *poODS =
1621 2 : poDriver->Create(psOptions.osOutputDataSourceName.c_str(), 0, 0,
1622 2 : 0, GDT_Unknown, psOptions.aosDSCO);
1623 2 : if (poODS == nullptr)
1624 : {
1625 0 : fprintf(stderr, _("%s driver failed to create %s.\n"),
1626 : psOptions.osFormat.c_str(),
1627 : psOptions.osOutputDataSourceName.c_str());
1628 0 : exit(1);
1629 : }
1630 :
1631 : OGRLayer *poLnLayer =
1632 2 : psOptions.osSrcLineLayerName.empty()
1633 2 : ? poLnDS->GetLayer(0)
1634 0 : : poLnDS->GetLayerByName(
1635 0 : psOptions.osSrcLineLayerName.c_str());
1636 :
1637 2 : if (poLnLayer == nullptr)
1638 : {
1639 0 : fprintf(stderr, _("Get path layer failed.\n"));
1640 0 : exit(1);
1641 : }
1642 :
1643 : OGRLayer *poPkLayer =
1644 2 : psOptions.osSrcPicketsLayerName.empty()
1645 2 : ? poPkDS->GetLayer(0)
1646 0 : : poPkDS->GetLayerByName(
1647 0 : psOptions.osSrcPicketsLayerName.c_str());
1648 :
1649 2 : if (poPkLayer == nullptr)
1650 : {
1651 0 : fprintf(stderr, _("Get repers layer failed.\n"));
1652 0 : exit(1);
1653 : }
1654 :
1655 2 : OGRFeatureDefn *poPkFDefn = poPkLayer->GetLayerDefn();
1656 2 : int nMValField = poPkFDefn->GetFieldIndex(
1657 2 : psOptions.osSrcPicketsMFieldName.c_str());
1658 :
1659 2 : OGRLayer *poOutLayer = nullptr;
1660 2 : if (!psOptions.osSrcLineSepFieldName.empty() &&
1661 0 : !psOptions.osSrcPicketsSepFieldName.empty())
1662 : {
1663 : poOutLayer =
1664 0 : SetupTargetLayer(poLnLayer, poODS, psOptions.aosLCO,
1665 : psOptions.osOutputLayerName.c_str(),
1666 : psOptions.osOutputSepFieldName.c_str());
1667 0 : if (poOutLayer == nullptr)
1668 : {
1669 0 : fprintf(stderr, _("Create output layer failed.\n"));
1670 0 : exit(1);
1671 : }
1672 :
1673 : // Do the work
1674 0 : eErr = CreatePartsMultiple(
1675 : poLnLayer, psOptions.osSrcLineSepFieldName.c_str(),
1676 : poPkLayer, psOptions.osSrcPicketsSepFieldName.c_str(),
1677 : nMValField, psOptions.dfStep, poOutLayer,
1678 : psOptions.osOutputSepFieldName.c_str(),
1679 0 : psOptions.bDisplayProgress, psOptions.bQuiet);
1680 : }
1681 : else
1682 : {
1683 : poOutLayer =
1684 2 : SetupTargetLayer(poLnLayer, poODS, psOptions.aosLCO,
1685 : psOptions.osOutputLayerName.c_str());
1686 2 : if (poOutLayer == nullptr)
1687 : {
1688 0 : fprintf(stderr, _("Create output layer failed.\n"));
1689 0 : exit(1);
1690 : }
1691 :
1692 : // Do the work
1693 2 : eErr = CreateParts(
1694 : poLnLayer, poPkLayer, nMValField, psOptions.dfStep,
1695 2 : poOutLayer, psOptions.bDisplayProgress, psOptions.bQuiet);
1696 : }
1697 :
1698 2 : GDALClose(poLnDS);
1699 2 : GDALClose(poPkDS);
1700 2 : if (GDALClose(poODS) != CE_None)
1701 0 : eErr = CE_Failure;
1702 :
1703 : #else // HAVE_GEOS
1704 : fprintf(stderr,
1705 : _("GEOS support not enabled or incompatible version.\n"));
1706 : exit(1);
1707 : #endif // HAVE_GEOS
1708 2 : break;
1709 : }
1710 1 : case op_get_pos:
1711 : {
1712 : #ifdef HAVE_GEOS
1713 :
1714 2 : if (psOptions.dfXPos == std::numeric_limits<double>::quiet_NaN() ||
1715 1 : psOptions.dfYPos == std::numeric_limits<double>::quiet_NaN())
1716 : {
1717 0 : fprintf(stderr, _("no coordinates provided\n"));
1718 0 : argParser->usage();
1719 0 : exit(1);
1720 : }
1721 1 : if (psOptions.osSrcPartsDataSourceName.empty())
1722 : {
1723 0 : fprintf(stderr, _("no parts datasource provided\n"));
1724 0 : argParser->usage();
1725 0 : exit(1);
1726 : }
1727 :
1728 1 : GDALDataset *poPartsDS = GDALDataset::FromHandle(OGROpen(
1729 : psOptions.osSrcPartsDataSourceName.c_str(), FALSE, nullptr));
1730 : /* ------------------------------------------------------------------ */
1731 : /* Report failure */
1732 : /* ------------------------------------------------------------------ */
1733 1 : if (poPartsDS == nullptr)
1734 : {
1735 : OGRSFDriverRegistrar *poR =
1736 0 : OGRSFDriverRegistrar::GetRegistrar();
1737 :
1738 0 : fprintf(stderr,
1739 : _("FAILURE:\n"
1740 : "Unable to open parts datasource `%s' with "
1741 : "the following drivers.\n"),
1742 : psOptions.osSrcPicketsDataSourceName.c_str());
1743 :
1744 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1745 : iDriver++)
1746 : {
1747 0 : fprintf(stderr, " -> %s\n",
1748 0 : poR->GetDriver(iDriver)->GetDescription());
1749 : }
1750 :
1751 0 : exit(1);
1752 : }
1753 :
1754 : OGRLayer *poPartsLayer =
1755 1 : psOptions.osSrcPartsLayerName.empty()
1756 1 : ? poPartsDS->GetLayer(0)
1757 0 : : poPartsDS->GetLayerByName(
1758 0 : psOptions.osSrcPartsLayerName.c_str());
1759 :
1760 1 : if (poPartsLayer == nullptr)
1761 : {
1762 0 : fprintf(stderr, _("Get parts layer failed.\n"));
1763 0 : exit(1);
1764 : }
1765 :
1766 : // Do the work
1767 2 : eErr = GetPosition(poPartsLayer, psOptions.dfXPos, psOptions.dfYPos,
1768 1 : psOptions.bDisplayProgress, psOptions.bQuiet);
1769 :
1770 1 : GDALClose(poPartsDS);
1771 :
1772 : #else // HAVE_GEOS
1773 : fprintf(stderr,
1774 : "GEOS support not enabled or incompatible version.\n");
1775 : exit(1);
1776 : #endif // HAVE_GEOS
1777 1 : break;
1778 : }
1779 1 : case op_get_coord:
1780 : {
1781 1 : if (psOptions.osSrcPartsDataSourceName.empty())
1782 : {
1783 0 : fprintf(stderr, _("No parts datasource provided.\n"));
1784 0 : argParser->usage();
1785 0 : exit(1);
1786 : }
1787 1 : if (psOptions.dfPos == std::numeric_limits<double>::quiet_NaN())
1788 : {
1789 0 : fprintf(stderr, _("No position provided.\n"));
1790 0 : argParser->usage();
1791 0 : exit(1);
1792 : }
1793 :
1794 1 : GDALDataset *poPartsDS = GDALDataset::FromHandle(OGROpen(
1795 : psOptions.osSrcPartsDataSourceName.c_str(), FALSE, nullptr));
1796 : /* ----------------------------------------------------------------- */
1797 : /* Report failure */
1798 : /* ----------------------------------------------------------------- */
1799 1 : if (poPartsDS == nullptr)
1800 : {
1801 : OGRSFDriverRegistrar *poR =
1802 0 : OGRSFDriverRegistrar::GetRegistrar();
1803 :
1804 0 : fprintf(stderr,
1805 : _("FAILURE:\n"
1806 : "Unable to open parts datasource `%s' with "
1807 : "the following drivers.\n"),
1808 : psOptions.osSrcPicketsDataSourceName.c_str());
1809 :
1810 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1811 : iDriver++)
1812 : {
1813 0 : fprintf(stderr, " -> %s\n",
1814 0 : poR->GetDriver(iDriver)->GetDescription());
1815 : }
1816 :
1817 0 : exit(1);
1818 : }
1819 :
1820 : OGRLayer *poPartsLayer =
1821 1 : psOptions.osSrcPartsLayerName.empty()
1822 1 : ? poPartsDS->GetLayer(0)
1823 0 : : poPartsDS->GetLayerByName(
1824 0 : psOptions.osSrcPartsLayerName.c_str());
1825 :
1826 1 : if (poPartsLayer == nullptr)
1827 : {
1828 0 : fprintf(stderr, _("Get parts layer failed.\n"));
1829 0 : exit(1);
1830 : }
1831 : // Do the work
1832 2 : eErr = GetCoordinates(poPartsLayer, psOptions.dfPos,
1833 1 : psOptions.bDisplayProgress, psOptions.bQuiet);
1834 :
1835 1 : GDALClose(poPartsDS);
1836 :
1837 1 : break;
1838 : }
1839 1 : case op_get_subline:
1840 : {
1841 1 : if (psOptions.dfPosBeg == std::numeric_limits<double>::quiet_NaN())
1842 : {
1843 0 : fprintf(stderr, _("No begin position provided.\n"));
1844 0 : argParser->usage();
1845 0 : exit(1);
1846 : }
1847 1 : if (psOptions.dfPosEnd == std::numeric_limits<double>::quiet_NaN())
1848 : {
1849 0 : fprintf(stderr, _("No end position provided.\n"));
1850 0 : argParser->usage();
1851 0 : exit(1);
1852 : }
1853 1 : if (psOptions.osSrcPartsDataSourceName.empty())
1854 : {
1855 0 : fprintf(stderr, _("No parts datasource provided.\n"));
1856 0 : argParser->usage();
1857 0 : exit(1);
1858 : }
1859 :
1860 1 : GDALDataset *poPartsDS = GDALDataset::FromHandle(OGROpen(
1861 : psOptions.osSrcPartsDataSourceName.c_str(), FALSE, nullptr));
1862 :
1863 : // Report failure.
1864 1 : if (poPartsDS == nullptr)
1865 : {
1866 : OGRSFDriverRegistrar *poR =
1867 0 : OGRSFDriverRegistrar::GetRegistrar();
1868 :
1869 0 : fprintf(stderr,
1870 : _("FAILURE:\n"
1871 : "Unable to open parts datasource `%s' with "
1872 : "the following drivers.\n"),
1873 : psOptions.osSrcPicketsDataSourceName.c_str());
1874 :
1875 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1876 : iDriver++)
1877 : {
1878 0 : fprintf(stderr, " -> %s\n",
1879 0 : poR->GetDriver(iDriver)->GetDescription());
1880 : }
1881 :
1882 0 : exit(1);
1883 : }
1884 :
1885 : // Find the output driver.
1886 1 : if (!psOptions.bQuiet)
1887 1 : CheckDestDataSourceNameConsistency(
1888 : psOptions.osOutputDataSourceName.c_str(),
1889 : psOptions.osFormat.c_str());
1890 :
1891 1 : OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
1892 :
1893 : GDALDriver *poDriver =
1894 1 : poR->GetDriverByName(psOptions.osFormat.c_str());
1895 1 : if (poDriver == nullptr)
1896 : {
1897 0 : fprintf(stderr, _("Unable to find driver `%s'.\n"),
1898 : psOptions.osFormat.c_str());
1899 0 : fprintf(stderr, _("The following drivers are available:\n"));
1900 :
1901 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount();
1902 : iDriver++)
1903 : {
1904 0 : fprintf(stderr, " -> `%s'\n",
1905 0 : poR->GetDriver(iDriver)->GetDescription());
1906 : }
1907 0 : exit(1);
1908 : }
1909 :
1910 1 : if (!CPLTestBool(CSLFetchNameValueDef(poDriver->GetMetadata(),
1911 : GDAL_DCAP_CREATE, "FALSE")))
1912 : {
1913 0 : fprintf(stderr,
1914 : _("%s driver does not support data source creation.\n"),
1915 : psOptions.osFormat.c_str());
1916 0 : exit(1);
1917 : }
1918 :
1919 : // Create the output data source.
1920 :
1921 : GDALDataset *poODS =
1922 1 : poDriver->Create(psOptions.osOutputDataSourceName.c_str(), 0, 0,
1923 1 : 0, GDT_Unknown, psOptions.aosDSCO);
1924 1 : if (poODS == nullptr)
1925 : {
1926 0 : fprintf(stderr, _("%s driver failed to create %s\n"),
1927 : psOptions.osFormat.c_str(),
1928 : psOptions.osOutputDataSourceName.c_str());
1929 0 : exit(1);
1930 : }
1931 :
1932 : OGRLayer *poPartsLayer =
1933 1 : psOptions.osSrcLineLayerName.empty()
1934 1 : ? poPartsDS->GetLayer(0)
1935 0 : : poPartsDS->GetLayerByName(
1936 0 : psOptions.osSrcLineLayerName.c_str());
1937 :
1938 1 : if (poPartsLayer == nullptr)
1939 : {
1940 0 : fprintf(stderr, _("Get parts layer failed.\n"));
1941 0 : exit(1);
1942 : }
1943 :
1944 : OGRLayer *poOutLayer =
1945 1 : SetupTargetLayer(poPartsLayer, poODS, psOptions.aosLCO,
1946 : psOptions.osOutputLayerName.c_str());
1947 :
1948 1 : if (poOutLayer == nullptr)
1949 : {
1950 0 : fprintf(stderr, _("Create output layer failed.\n"));
1951 0 : exit(1);
1952 : }
1953 :
1954 : // Do the work
1955 :
1956 2 : eErr = CreateSubline(poPartsLayer, psOptions.dfPosBeg,
1957 : psOptions.dfPosEnd, poOutLayer,
1958 1 : psOptions.bDisplayProgress, psOptions.bQuiet);
1959 :
1960 1 : GDALClose(poPartsDS);
1961 1 : if (GDALClose(poODS) != CE_None)
1962 0 : eErr = CE_Failure;
1963 :
1964 1 : break;
1965 : }
1966 0 : default:
1967 0 : fprintf(stderr, _("Unknown operation.\n"));
1968 0 : argParser->usage();
1969 0 : exit(1);
1970 : }
1971 :
1972 5 : OGRCleanupAll();
1973 :
1974 : #ifdef DBMALLOC
1975 : malloc_dump(1);
1976 : #endif
1977 :
1978 5 : return eErr == OGRERR_NONE ? 0 : 1;
1979 : }
1980 :
1981 0 : MAIN_END
|