LCOV - code coverage report
Current view: top level - apps - gdaltransform.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 201 245 82.0 %
Date: 2025-03-28 11:40:40 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Command line point transformer.
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : 
      16             : #include <cstdio>
      17             : #include <cstdlib>
      18             : #include <cctype>
      19             : 
      20             : #include "cpl_conv.h"
      21             : #include "cpl_error.h"
      22             : #include "cpl_string.h"
      23             : #include "gdal_version.h"
      24             : #include "gdal_alg.h"
      25             : #include "gdalwarper.h"
      26             : #include "gdal.h"
      27             : #include "ogr_api.h"
      28             : #include "ogr_core.h"
      29             : #include "ogr_spatialref.h"
      30             : #include "ogr_srs_api.h"
      31             : #include "commonutils.h"
      32             : 
      33             : /************************************************************************/
      34             : /*                               Usage()                                */
      35             : /************************************************************************/
      36             : 
      37           0 : static void Usage(bool bIsError, const char *pszErrorMsg = nullptr,
      38             :                   bool bHelpDoc = false)
      39             : 
      40             : {
      41           0 :     fprintf(bIsError ? stderr : stdout,
      42             :             "Usage: gdaltransform [--help] [--help-general]\n"
      43             :             "       [-i] [-s_srs <srs_def>] [-t_srs <srs_def>] "
      44             :             "[-to >NAME>=<VALUE>]...\n"
      45             :             "       [-s_coord_epoch <epoch>] [-t_coord_epoch <epoch>]\n"
      46             :             "       [-ct <proj_string>] [-order <n>] [-tps] [-rpc] [-geoloc] \n"
      47             :             "       [-gcp <pixel> <line> <easting> <northing> [elevation]]...\n"
      48             :             "       [-output_xy] [-E] [-field_sep <sep>] "
      49             :             "[-ignore_extra_input]\n"
      50             :             "       [<srcfile> [<dstfile>]]\n");
      51             : 
      52           0 :     if (bHelpDoc)
      53           0 :         exit(0);
      54             : 
      55           0 :     fprintf(bIsError ? stderr : stdout, "\n");
      56           0 :     if (pszErrorMsg != nullptr)
      57           0 :         fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
      58             : 
      59           0 :     exit(bIsError ? 1 : 0);
      60             : }
      61             : 
      62             : /************************************************************************/
      63             : /*                             IsValidSRS                               */
      64             : /************************************************************************/
      65             : 
      66           8 : static bool IsValidSRS(const char *pszUserInput)
      67             : 
      68             : {
      69             :     OGRSpatialReferenceH hSRS;
      70           8 :     bool bRes = true;
      71             : 
      72           8 :     CPLErrorReset();
      73             : 
      74           8 :     hSRS = OSRNewSpatialReference(nullptr);
      75           8 :     if (OSRSetFromUserInput(hSRS, pszUserInput) != OGRERR_NONE)
      76             :     {
      77           0 :         bRes = false;
      78           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      79             :                  "Translating source or target SRS failed:\n%s", pszUserInput);
      80             :     }
      81             : 
      82           8 :     OSRDestroySpatialReference(hSRS);
      83             : 
      84           8 :     return bRes;
      85             : }
      86             : 
      87             : /************************************************************************/
      88             : /*                                main()                                */
      89             : /************************************************************************/
      90             : 
      91             : #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg)                            \
      92             :     do                                                                         \
      93             :     {                                                                          \
      94             :         if (i + nExtraArg >= argc)                                             \
      95             :             Usage(true, CPLSPrintf("%s option requires %d argument(s)",        \
      96             :                                    argv[i], nExtraArg));                       \
      97             :     } while (false)
      98             : 
      99          15 : MAIN_START(argc, argv)
     100             : 
     101             : {
     102             :     // Check that we are running against at least GDAL 1.5.
     103             :     // Note to developers: if we use newer API, please change the requirement.
     104          15 :     if (atoi(GDALVersionInfo("VERSION_NUM")) < 1500)
     105             :     {
     106           0 :         fprintf(stderr,
     107             :                 "At least, GDAL >= 1.5.0 is required for this version of %s, "
     108             :                 "which was compiled against GDAL %s\n",
     109             :                 argv[0], GDAL_RELEASE_NAME);
     110           0 :         exit(1);
     111             :     }
     112             : 
     113          15 :     GDALAllRegister();
     114          15 :     argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
     115          15 :     if (argc < 1)
     116           1 :         exit(-argc);
     117             : 
     118          14 :     const char *pszSrcFilename = nullptr;
     119          14 :     const char *pszDstFilename = nullptr;
     120          14 :     int nOrder = 0;
     121             :     void *hTransformArg;
     122          14 :     GDALTransformerFunc pfnTransformer = nullptr;
     123          14 :     int nGCPCount = 0;
     124          14 :     GDAL_GCP *pasGCPs = nullptr;
     125          14 :     int bInverse = FALSE;
     126          28 :     CPLStringList aosTO;
     127          14 :     int bOutputXY = FALSE;
     128          14 :     double dfX = 0.0;
     129          14 :     double dfY = 0.0;
     130          14 :     double dfZ = 0.0;
     131          14 :     double dfT = 0.0;
     132          14 :     bool bCoordOnCommandLine = false;
     133          14 :     bool bIgnoreExtraInput = false;
     134          14 :     bool bEchoInput = false;
     135          28 :     std::string osFieldSep = " ";
     136             : 
     137             :     /* -------------------------------------------------------------------- */
     138             :     /*      Parse arguments.                                                */
     139             :     /* -------------------------------------------------------------------- */
     140          53 :     for (int i = 1; i < argc && argv[i] != nullptr; i++)
     141             :     {
     142          39 :         if (EQUAL(argv[i], "--utility_version"))
     143             :         {
     144           0 :             printf("%s was compiled against GDAL %s and "
     145             :                    "is running against GDAL %s\n",
     146             :                    argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
     147           0 :             CSLDestroy(argv);
     148           0 :             return 0;
     149             :         }
     150          39 :         else if (EQUAL(argv[i], "--help"))
     151             :         {
     152           0 :             Usage(false);
     153             :         }
     154          39 :         else if (EQUAL(argv[i], "--help-doc"))
     155             :         {
     156           0 :             Usage(false, nullptr, true);
     157             :         }
     158          39 :         else if (EQUAL(argv[i], "-t_srs"))
     159             :         {
     160           5 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     161           5 :             const char *pszSRS = argv[++i];
     162           5 :             if (!IsValidSRS(pszSRS))
     163           0 :                 exit(1);
     164           5 :             aosTO.SetNameValue("DST_SRS", pszSRS);
     165             :         }
     166          34 :         else if (EQUAL(argv[i], "-s_srs"))
     167             :         {
     168           3 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     169           3 :             const char *pszSRS = argv[++i];
     170             :             // coverity[tainted_data]
     171           3 :             if (!IsValidSRS(pszSRS))
     172           0 :                 exit(1);
     173           3 :             aosTO.SetNameValue("SRC_SRS", pszSRS);
     174             :         }
     175          31 :         else if (EQUAL(argv[i], "-s_coord_epoch"))
     176             :         {
     177           0 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     178           0 :             const char *pszCoordinateEpoch = argv[++i];
     179           0 :             aosTO.SetNameValue("SRC_COORDINATE_EPOCH", pszCoordinateEpoch);
     180             :         }
     181          31 :         else if (EQUAL(argv[i], "-t_coord_epoch"))
     182             :         {
     183           0 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     184           0 :             const char *pszCoordinateEpoch = argv[++i];
     185           0 :             aosTO.SetNameValue("DST_COORDINATE_EPOCH", pszCoordinateEpoch);
     186             :         }
     187          31 :         else if (EQUAL(argv[i], "-ct"))
     188             :         {
     189           1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     190           1 :             const char *pszCT = argv[++i];
     191           1 :             aosTO.SetNameValue("COORDINATE_OPERATION", pszCT);
     192             :         }
     193          30 :         else if (EQUAL(argv[i], "-order"))
     194             :         {
     195           1 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     196           1 :             nOrder = atoi(argv[++i]);
     197           1 :             aosTO.SetNameValue("MAX_GCP_ORDER", argv[i]);
     198             :         }
     199          29 :         else if (EQUAL(argv[i], "-tps"))
     200             :         {
     201           1 :             aosTO.SetNameValue("METHOD", "GCP_TPS");
     202           1 :             nOrder = -1;
     203             :         }
     204          28 :         else if (EQUAL(argv[i], "-rpc"))
     205             :         {
     206           0 :             aosTO.SetNameValue("METHOD", "RPC");
     207             :         }
     208          28 :         else if (EQUAL(argv[i], "-geoloc"))
     209             :         {
     210           0 :             aosTO.SetNameValue("METHOD", "GEOLOC_ARRAY");
     211             :         }
     212          28 :         else if (EQUAL(argv[i], "-i"))
     213             :         {
     214           1 :             bInverse = TRUE;
     215             :         }
     216          27 :         else if (EQUAL(argv[i], "-to"))
     217             :         {
     218           2 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
     219           2 :             aosTO.AddString(argv[++i]);
     220             :         }
     221          25 :         else if (EQUAL(argv[i], "-gcp"))
     222             :         {
     223          12 :             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
     224          12 :             char *endptr = nullptr;
     225             :             /* -gcp pixel line easting northing [elev] */
     226             : 
     227          12 :             nGCPCount++;
     228             :             pasGCPs = static_cast<GDAL_GCP *>(
     229          12 :                 CPLRealloc(pasGCPs, sizeof(GDAL_GCP) * nGCPCount));
     230          12 :             GDALInitGCPs(1, pasGCPs + nGCPCount - 1);
     231             : 
     232             :             // coverity[tainted_data]
     233          12 :             pasGCPs[nGCPCount - 1].dfGCPPixel = CPLAtof(argv[++i]);
     234             :             // coverity[tainted_data]
     235          12 :             pasGCPs[nGCPCount - 1].dfGCPLine = CPLAtof(argv[++i]);
     236             :             // coverity[tainted_data]
     237          12 :             pasGCPs[nGCPCount - 1].dfGCPX = CPLAtof(argv[++i]);
     238             :             // coverity[tainted_data]
     239          12 :             pasGCPs[nGCPCount - 1].dfGCPY = CPLAtof(argv[++i]);
     240          21 :             if (argv[i + 1] != nullptr &&
     241           9 :                 (CPLStrtod(argv[i + 1], &endptr) != 0.0 ||
     242           9 :                  argv[i + 1][0] == '0'))
     243             :             {
     244             :                 // Check that last argument is really a number and not a
     245             :                 // filename looking like a number (see ticket #863).
     246           3 :                 if (endptr && *endptr == 0)
     247             :                 {
     248             :                     // coverity[tainted_data]
     249           3 :                     pasGCPs[nGCPCount - 1].dfGCPZ = CPLAtof(argv[++i]);
     250             :                 }
     251             :             }
     252             : 
     253             :             /* should set id and info? */
     254             :         }
     255          13 :         else if (EQUAL(argv[i], "-output_xy"))
     256             :         {
     257           2 :             bOutputXY = TRUE;
     258             :         }
     259          11 :         else if (EQUAL(argv[i], "-ignore_extra_input"))
     260             :         {
     261           1 :             bIgnoreExtraInput = true;
     262             :         }
     263          10 :         else if (EQUAL(argv[i], "-E"))
     264             :         {
     265           2 :             bEchoInput = true;
     266             :         }
     267           8 :         else if (i < argc - 1 && EQUAL(argv[i], "-field_sep"))
     268             :         {
     269           4 :             osFieldSep = CPLString(argv[++i])
     270           4 :                              .replaceAll("\\t", '\t')
     271           4 :                              .replaceAll("\\r", '\r')
     272           2 :                              .replaceAll("\\n", '\n');
     273             :         }
     274           6 :         else if (EQUAL(argv[i], "-coord") && i + 2 < argc)
     275             :         {
     276           1 :             bCoordOnCommandLine = true;
     277           1 :             dfX = CPLAtof(argv[++i]);
     278           1 :             dfY = CPLAtof(argv[++i]);
     279           2 :             if (i + 1 < argc &&
     280           1 :                 CPLGetValueType(argv[i + 1]) != CPL_VALUE_STRING)
     281           1 :                 dfZ = CPLAtof(argv[++i]);
     282           2 :             if (i + 1 < argc &&
     283           1 :                 CPLGetValueType(argv[i + 1]) != CPL_VALUE_STRING)
     284           1 :                 dfT = CPLAtof(argv[++i]);
     285             :         }
     286           5 :         else if (argv[i][0] == '-')
     287             :         {
     288           0 :             Usage(true, CPLSPrintf("Unknown option name '%s'", argv[i]));
     289             :         }
     290           5 :         else if (pszSrcFilename == nullptr)
     291             :         {
     292           4 :             pszSrcFilename = argv[i];
     293             :         }
     294           1 :         else if (pszDstFilename == nullptr)
     295             :         {
     296           1 :             pszDstFilename = argv[i];
     297             :         }
     298             :         else
     299             :         {
     300           0 :             Usage(true, "Too many command options.");
     301             :         }
     302             :     }
     303             : 
     304             :     /* -------------------------------------------------------------------- */
     305             :     /*      Open src and destination file, if appropriate.                  */
     306             :     /* -------------------------------------------------------------------- */
     307          14 :     GDALDatasetH hSrcDS = nullptr;
     308          14 :     if (pszSrcFilename != nullptr)
     309             :     {
     310           4 :         hSrcDS = GDALOpen(pszSrcFilename, GA_ReadOnly);
     311           4 :         if (hSrcDS == nullptr)
     312           0 :             exit(1);
     313             :     }
     314             : 
     315          14 :     GDALDatasetH hDstDS = nullptr;
     316          14 :     if (pszDstFilename != nullptr)
     317             :     {
     318           1 :         hDstDS = GDALOpen(pszDstFilename, GA_ReadOnly);
     319           1 :         if (hDstDS == nullptr)
     320           0 :             exit(1);
     321             :     }
     322             : 
     323          14 :     if (hSrcDS != nullptr && nGCPCount > 0)
     324             :     {
     325           0 :         fprintf(stderr, "Command line GCPs and input file specified, "
     326             :                         "specify one or the other.\n");
     327           0 :         exit(1);
     328             :     }
     329             : 
     330             :     /* -------------------------------------------------------------------- */
     331             :     /*      Create a transformation object from the source to               */
     332             :     /*      destination coordinate system.                                  */
     333             :     /* -------------------------------------------------------------------- */
     334          14 :     if (nGCPCount != 0 && nOrder == -1)
     335             :     {
     336           1 :         pfnTransformer = GDALTPSTransform;
     337           1 :         hTransformArg = GDALCreateTPSTransformer(nGCPCount, pasGCPs, FALSE);
     338             :     }
     339          13 :     else if (nGCPCount != 0)
     340             :     {
     341           2 :         pfnTransformer = GDALGCPTransform;
     342             :         hTransformArg =
     343           2 :             GDALCreateGCPTransformer(nGCPCount, pasGCPs, nOrder, FALSE);
     344             :     }
     345             :     else
     346             :     {
     347          11 :         pfnTransformer = GDALGenImgProjTransform;
     348             :         hTransformArg =
     349          11 :             GDALCreateGenImgProjTransformer2(hSrcDS, hDstDS, aosTO.List());
     350             :     }
     351             : 
     352          14 :     if (hTransformArg == nullptr)
     353             :     {
     354           0 :         exit(1);
     355             :     }
     356             : 
     357             :     /* -------------------------------------------------------------------- */
     358             :     /*      Read points from stdin, transform and write to stdout.          */
     359             :     /* -------------------------------------------------------------------- */
     360          14 :     double dfLastT = 0.0;
     361             : 
     362          14 :     if (!bCoordOnCommandLine)
     363             :     {
     364             :         // Is it an interactive terminal ?
     365          13 :         if (CPLIsInteractive(stdin))
     366             :         {
     367           0 :             if (pszSrcFilename != nullptr)
     368             :             {
     369           0 :                 fprintf(stderr, "Enter column line values separated by space, "
     370             :                                 "and press Return.\n");
     371             :             }
     372             :             else
     373             :             {
     374           0 :                 fprintf(stderr, "Enter X Y [Z [T]] values separated by space, "
     375             :                                 "and press Return.\n");
     376             :             }
     377             :         }
     378             :     }
     379             : 
     380          14 :     int nLine = 0;
     381          39 :     while (bCoordOnCommandLine || !feof(stdin))
     382             :     {
     383          39 :         std::string osExtraContent;
     384          39 :         if (!bCoordOnCommandLine)
     385             :         {
     386             :             char szLine[1024];
     387             : 
     388          38 :             if (fgets(szLine, sizeof(szLine) - 1, stdin) == nullptr)
     389          13 :                 break;
     390             : 
     391          25 :             size_t nLen = strlen(szLine);
     392          25 :             if (nLen && szLine[nLen - 1] == '\n')
     393          25 :                 szLine[--nLen] = 0;
     394          25 :             if (nLen && szLine[nLen - 1] == '\r')
     395           0 :                 szLine[--nLen] = 0;
     396          25 :             const CPLStringList aosTokens(CSLTokenizeString(szLine));
     397          25 :             const int nCount = aosTokens.size();
     398             : 
     399          25 :             ++nLine;
     400          25 :             if (nCount < 2)
     401             :             {
     402           0 :                 fprintf(stderr, "Not enough values at line %d\n", nLine);
     403           0 :                 continue;
     404             :             }
     405             : 
     406          25 :             dfX = CPLAtof(aosTokens[0]);
     407          25 :             dfY = CPLAtof(aosTokens[1]);
     408          25 :             dfZ = 0.0;
     409          25 :             dfT = 0.0;
     410          25 :             int iStartExtraContent = nCount;
     411          25 :             if (nCount >= 3)
     412             :             {
     413          10 :                 if (CPLGetValueType(aosTokens[2]) == CPL_VALUE_STRING)
     414             :                 {
     415           1 :                     iStartExtraContent = 2;
     416             :                 }
     417             :                 else
     418             :                 {
     419           9 :                     dfZ = CPLAtof(aosTokens[2]);
     420             : 
     421           9 :                     if (nCount >= 4)
     422             :                     {
     423           5 :                         if (CPLGetValueType(aosTokens[3]) == CPL_VALUE_STRING)
     424             :                         {
     425           4 :                             iStartExtraContent = 3;
     426             :                         }
     427             :                         else
     428             :                         {
     429           1 :                             dfT = CPLAtof(aosTokens[3]);
     430           1 :                             iStartExtraContent = 4;
     431             :                         }
     432             :                     }
     433             :                 }
     434             :             }
     435             : 
     436          25 :             if (!bIgnoreExtraInput)
     437             :             {
     438          37 :                 for (int i = iStartExtraContent; i < nCount; ++i)
     439             :                 {
     440          13 :                     if (!osExtraContent.empty())
     441           8 :                         osExtraContent += ' ';
     442          13 :                     osExtraContent += aosTokens[i];
     443             :                 }
     444          29 :                 while (!osExtraContent.empty() &&
     445           5 :                        isspace(static_cast<int>(osExtraContent.back())))
     446             :                 {
     447           0 :                     osExtraContent.pop_back();
     448             :                 }
     449          24 :                 if (!osExtraContent.empty())
     450           5 :                     osExtraContent = osFieldSep + osExtraContent;
     451             :             }
     452             :         }
     453          26 :         if (dfT != dfLastT && nGCPCount == 0)
     454             :         {
     455           2 :             if (dfT != 0.0)
     456             :             {
     457           2 :                 aosTO.SetNameValue("COORDINATE_EPOCH", CPLSPrintf("%g", dfT));
     458             :             }
     459             :             else
     460             :             {
     461           0 :                 aosTO.SetNameValue("COORDINATE_EPOCH", nullptr);
     462             :             }
     463           2 :             GDALDestroyGenImgProjTransformer(hTransformArg);
     464             :             hTransformArg =
     465           2 :                 GDALCreateGenImgProjTransformer2(hSrcDS, hDstDS, aosTO.List());
     466             :         }
     467             : 
     468          26 :         int bSuccess = TRUE;
     469          26 :         const double dfXBefore = dfX;
     470          26 :         const double dfYBefore = dfY;
     471          26 :         const double dfZBefore = dfZ;
     472          26 :         if (pfnTransformer(hTransformArg, bInverse, 1, &dfX, &dfY, &dfZ,
     473          52 :                            &bSuccess) &&
     474          26 :             bSuccess)
     475             :         {
     476          26 :             if (bEchoInput)
     477             :             {
     478           2 :                 if (bOutputXY)
     479           1 :                     CPLprintf("%.15g%s%.15g%s", dfXBefore, osFieldSep.c_str(),
     480             :                               dfYBefore, osFieldSep.c_str());
     481             :                 else
     482           1 :                     CPLprintf("%.15g%s%.15g%s%.15g%s", dfXBefore,
     483             :                               osFieldSep.c_str(), dfYBefore, osFieldSep.c_str(),
     484             :                               dfZBefore, osFieldSep.c_str());
     485             :             }
     486          26 :             if (bOutputXY)
     487           2 :                 CPLprintf("%.15g%s%.15g%s\n", dfX, osFieldSep.c_str(), dfY,
     488             :                           osExtraContent.c_str());
     489             :             else
     490          24 :                 CPLprintf("%.15g%s%.15g%s%.15g%s\n", dfX, osFieldSep.c_str(),
     491             :                           dfY, osFieldSep.c_str(), dfZ, osExtraContent.c_str());
     492             :         }
     493             :         else
     494             :         {
     495           0 :             printf("transformation failed.\n");
     496             :         }
     497             : 
     498          26 :         if (bCoordOnCommandLine)
     499           1 :             break;
     500          25 :         dfLastT = dfT;
     501             :     }
     502             : 
     503          14 :     if (nGCPCount != 0 && nOrder == -1)
     504             :     {
     505           1 :         GDALDestroyTPSTransformer(hTransformArg);
     506             :     }
     507          13 :     else if (nGCPCount != 0)
     508             :     {
     509           2 :         GDALDestroyGCPTransformer(hTransformArg);
     510             :     }
     511             :     else
     512             :     {
     513          11 :         GDALDestroyGenImgProjTransformer(hTransformArg);
     514             :     }
     515             : 
     516          14 :     if (nGCPCount)
     517             :     {
     518           3 :         GDALDeinitGCPs(nGCPCount, pasGCPs);
     519           3 :         CPLFree(pasGCPs);
     520             :     }
     521             : 
     522          14 :     if (hSrcDS)
     523           4 :         GDALClose(hSrcDS);
     524             : 
     525          14 :     if (hDstDS)
     526           1 :         GDALClose(hDstDS);
     527             : 
     528          14 :     GDALDumpOpenDatasets(stderr);
     529          14 :     GDALDestroyDriverManager();
     530             : 
     531          14 :     CSLDestroy(argv);
     532             : 
     533          14 :     return 0;
     534             : }
     535             : 
     536           0 : MAIN_END

Generated by: LCOV version 1.14