LCOV - code coverage report
Current view: top level - apps - ogrlineref.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 578 866 66.7 %
Date: 2024-11-21 22:18:42 Functions: 12 13 92.3 %

          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

Generated by: LCOV version 1.14