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