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

Generated by: LCOV version 1.14