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 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 * DEALINGS IN THE SOFTWARE. 28 ****************************************************************************/ 29 30 #include "cpl_port.h" 31 32 #include <cstdio> 33 #include <cstdlib> 34 35 #include "cpl_conv.h" 36 #include "cpl_error.h" 37 #include "cpl_string.h" 38 #include "gdal_version.h" 39 #include "gdal_alg.h" 40 #include "gdalwarper.h" 41 #include "gdal.h" 42 #include "gdal_version.h" 43 #include "ogr_api.h" 44 #include "ogr_core.h" 45 #include "ogr_spatialref.h" 46 #include "ogr_srs_api.h" 47 #include "commonutils.h" 48 49 #ifdef _WIN32 50 #include <io.h> 51 #else 52 #include <unistd.h> 53 #endif 54 55 CPL_CVSID("$Id: gdaltransform.cpp 900cac300559af80bca19917f9acd1915c13995e 2019-08-12 22:17:29 +0200 Even Rouault $") 56 57 /************************************************************************/ 58 /* Usage() */ 59 /************************************************************************/ 60 61 static void Usage(const char* pszErrorMsg = nullptr) 62 63 { 64 printf( 65 "Usage: gdaltransform [--help-general]\n" 66 " [-i] [-s_srs srs_def] [-t_srs srs_def] [-to \"NAME=VALUE\"]\n" 67 " [-ct proj_string] [-order n] [-tps] [-rpc] [-geoloc] \n" 68 " [-gcp pixel line easting northing [elevation]]* [-output_xy]\n" 69 " [srcfile [dstfile]]\n" 70 "\n" ); 71 72 if( pszErrorMsg != nullptr ) 73 fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg); 74 75 exit( 1 ); 76 } 77 78 /************************************************************************/ 79 /* IsValidSRS */ 80 /************************************************************************/ 81 82 static bool IsValidSRS( const char *pszUserInput ) 83 84 { 85 OGRSpatialReferenceH hSRS; 86 bool bRes = true; 87 88 CPLErrorReset(); 89 90 hSRS = OSRNewSpatialReference( nullptr ); 91 if( OSRSetFromUserInput( hSRS, pszUserInput ) != OGRERR_NONE ) 92 { 93 bRes = false; 94 CPLError( CE_Failure, CPLE_AppDefined, 95 "Translating source or target SRS failed:\n%s", 96 pszUserInput ); 97 } 98 99 OSRDestroySpatialReference( hSRS ); 100 101 return bRes; 102 } 103 104 /************************************************************************/ 105 /* main() */ 106 /************************************************************************/ 107 108 #define CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(nExtraArg) \ 109 do { if (i + nExtraArg >= argc) \ 110 Usage(CPLSPrintf("%s option requires %d argument(s)", \ 111 argv[i], nExtraArg)); } while( false ) 112 113 MAIN_START(argc, argv) 114 115 { 116 // Check that we are running against at least GDAL 1.5. 117 // Note to developers: if we use newer API, please change the requirement. 118 if (atoi(GDALVersionInfo("VERSION_NUM")) < 1500) 119 { 120 fprintf(stderr, 121 "At least, GDAL >= 1.5.0 is required for this version of %s, " 122 "which was compiled against GDAL %s\n", 123 argv[0], GDAL_RELEASE_NAME); 124 exit(1); 125 } 126 127 GDALAllRegister(); 128 argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); 129 if( argc < 1 ) 130 exit( -argc ); 131 132 const char *pszSrcFilename = nullptr; 133 const char *pszDstFilename = nullptr; 134 int nOrder = 0; 135 void *hTransformArg; 136 GDALTransformerFunc pfnTransformer = nullptr; 137 int nGCPCount = 0; 138 GDAL_GCP *pasGCPs = nullptr; 139 int bInverse = FALSE; 140 CPLStringList aosTO; 141 int bOutputXY = FALSE; 142 double dfX = 0.0; 143 double dfY = 0.0; 144 double dfZ = 0.0; 145 double dfT = 0.0; 146 bool bCoordOnCommandLine = false; 147 148 /* -------------------------------------------------------------------- */ 149 /* Parse arguments. */ 150 /* -------------------------------------------------------------------- */ 151 for( int i = 1; i < argc && argv[i] != nullptr; i++ ) 152 { 153 if( EQUAL(argv[i], "--utility_version") ) 154 { 155 printf("%s was compiled against GDAL %s and " 156 "is running against GDAL %s\n", 157 argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME")); 158 CSLDestroy(argv); 159 return 0; 160 } 161 else if( EQUAL(argv[i],"--help") ) 162 { 163 Usage(); 164 } 165 else if( EQUAL(argv[i],"-t_srs") ) 166 { 167 CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); 168 const char *pszSRS = argv[++i]; 169 if( !IsValidSRS(pszSRS) ) 170 exit(1); 171 aosTO.SetNameValue("DST_SRS", pszSRS ); 172 } 173 else if( EQUAL(argv[i],"-s_srs") ) 174 { 175 CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); 176 const char *pszSRS = argv[++i]; 177 // coverity[tainted_data] 178 if( !IsValidSRS(pszSRS) ) 179 exit(1); 180 aosTO.SetNameValue("SRC_SRS", pszSRS ); 181 } 182 else if( EQUAL(argv[i],"-ct") ) 183 { 184 CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); 185 const char *pszCT = argv[++i]; 186 aosTO.SetNameValue("COORDINATE_OPERATION", pszCT ); 187 } 188 else if( EQUAL(argv[i],"-order") ) 189 { 190 CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); 191 nOrder = atoi(argv[++i]); 192 aosTO.SetNameValue("MAX_GCP_ORDER", argv[i] ); 193 } 194 else if( EQUAL(argv[i],"-tps") ) 195 { 196 aosTO.SetNameValue("METHOD", "GCP_TPS" ); 197 nOrder = -1; 198 } 199 else if( EQUAL(argv[i],"-rpc") ) 200 { 201 aosTO.SetNameValue("METHOD", "RPC" ); 202 } 203 else if( EQUAL(argv[i],"-geoloc") ) 204 { 205 aosTO.SetNameValue("METHOD", "GEOLOC_ARRAY" ); 206 } 207 else if( EQUAL(argv[i],"-i") ) 208 { 209 bInverse = TRUE; 210 } 211 else if( EQUAL(argv[i],"-to") ) 212 { 213 CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1); 214 aosTO.AddString( argv[++i] ); 215 } 216 else if( EQUAL(argv[i],"-gcp") ) 217 { 218 CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4); 219 char* endptr = nullptr; 220 /* -gcp pixel line easting northing [elev] */ 221 222 nGCPCount++; 223 pasGCPs = static_cast<GDAL_GCP *>( 224 CPLRealloc(pasGCPs, sizeof(GDAL_GCP) * nGCPCount)); 225 GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 ); 226 227 // coverity[tainted_data] 228 pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtof(argv[++i]); 229 // coverity[tainted_data] 230 pasGCPs[nGCPCount-1].dfGCPLine = CPLAtof(argv[++i]); 231 // coverity[tainted_data] 232 pasGCPs[nGCPCount-1].dfGCPX = CPLAtof(argv[++i]); 233 // coverity[tainted_data] 234 pasGCPs[nGCPCount-1].dfGCPY = CPLAtof(argv[++i]); 235 if( argv[i+1] != nullptr && 236 (CPLStrtod(argv[i+1], &endptr) != 0.0 || argv[i+1][0] == '0') ) 237 { 238 // Check that last argument is really a number and not a 239 // filename looking like a number (see ticket #863). 240 if (endptr && *endptr == 0) 241 { 242 // coverity[tainted_data] 243 pasGCPs[nGCPCount-1].dfGCPZ = CPLAtof(argv[++i]); 244 } 245 } 246 247 /* should set id and info? */ 248 } 249 else if( EQUAL(argv[i],"-output_xy") ) 250 { 251 bOutputXY = TRUE; 252 } 253 else if( EQUAL(argv[i],"-coord") && i + 2 < argc) 254 { 255 bCoordOnCommandLine = true; 256 dfX = CPLAtof(argv[++i]); 257 dfY = CPLAtof(argv[++i]); 258 if( i + 1 < argc && CPLGetValueType(argv[i+1]) != CPL_VALUE_STRING ) 259 dfZ = CPLAtof(argv[++i]); 260 if( i + 1 < argc && CPLGetValueType(argv[i+1]) != CPL_VALUE_STRING ) 261 dfT = CPLAtof(argv[++i]); 262 } 263 else if( argv[i][0] == '-' ) 264 { 265 Usage(CPLSPrintf("Unknown option name '%s'", argv[i])); 266 } 267 else if( pszSrcFilename == nullptr ) 268 { 269 pszSrcFilename = argv[i]; 270 } 271 else if( pszDstFilename == nullptr ) 272 { 273 pszDstFilename = argv[i]; 274 } 275 else 276 { 277 Usage("Too many command options."); 278 } 279 } 280 281 /* -------------------------------------------------------------------- */ 282 /* Open src and destination file, if appropriate. */ 283 /* -------------------------------------------------------------------- */ 284 GDALDatasetH hSrcDS = nullptr; 285 if( pszSrcFilename != nullptr ) 286 { 287 hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly ); 288 if( hSrcDS == nullptr ) 289 exit( 1 ); 290 } 291 292 GDALDatasetH hDstDS = nullptr; 293 if( pszDstFilename != nullptr ) 294 { 295 hDstDS = GDALOpen( pszDstFilename, GA_ReadOnly ); 296 if( hDstDS == nullptr ) 297 exit( 1 ); 298 } 299 300 if( hSrcDS != nullptr && nGCPCount > 0 ) 301 { 302 fprintf(stderr, 303 "Command line GCPs and input file specified, " 304 "specify one or the other.\n"); 305 exit( 1 ); 306 } 307 308 /* -------------------------------------------------------------------- */ 309 /* Create a transformation object from the source to */ 310 /* destination coordinate system. */ 311 /* -------------------------------------------------------------------- */ 312 if( nGCPCount != 0 && nOrder == -1 ) 313 { 314 pfnTransformer = GDALTPSTransform; 315 hTransformArg = 316 GDALCreateTPSTransformer( nGCPCount, pasGCPs, FALSE ); 317 } 318 else if( nGCPCount != 0 ) 319 { 320 pfnTransformer = GDALGCPTransform; 321 hTransformArg = 322 GDALCreateGCPTransformer( nGCPCount, pasGCPs, nOrder, FALSE ); 323 } 324 else 325 { 326 pfnTransformer = GDALGenImgProjTransform; 327 hTransformArg = 328 GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, aosTO.List() ); 329 } 330 331 if( hTransformArg == nullptr ) 332 { 333 exit( 1 ); 334 } 335 336 /* -------------------------------------------------------------------- */ 337 /* Read points from stdin, transform and write to stdout. */ 338 /* -------------------------------------------------------------------- */ 339 double dfLastT = 0.0; 340 341 if( !bCoordOnCommandLine ) 342 { 343 // Is it an interactive terminal ? 344 if( isatty(static_cast<int>(fileno(stdin))) ) 345 { 346 if( pszSrcFilename != nullptr ) 347 { 348 fprintf(stderr, "Enter column line values separated by space, and press Return.\n"); 349 } 350 else 351 { 352 fprintf(stderr, "Enter X Y [Z [T]] values separated by space, and press Return.\n"); 353 } 354 } 355 } 356 357 while( bCoordOnCommandLine || !feof(stdin) ) 358 { 359 if( !bCoordOnCommandLine ) 360 { 361 char szLine[1024]; 362 363 if( fgets( szLine, sizeof(szLine)-1, stdin ) == nullptr ) 364 break; 365 366 char **papszTokens = CSLTokenizeString(szLine); 367 const int nCount = CSLCount(papszTokens); 368 369 if( nCount < 2 ) 370 { 371 CSLDestroy(papszTokens); 372 continue; 373 } 374 375 dfX = CPLAtof(papszTokens[0]); 376 dfY = CPLAtof(papszTokens[1]); 377 if( nCount >= 3 ) 378 dfZ = CPLAtof(papszTokens[2]); 379 else 380 dfZ = 0.0; 381 if( nCount == 4 ) 382 dfT = CPLAtof(papszTokens[3]); 383 else 384 dfT = 0.0; 385 CSLDestroy(papszTokens); 386 } 387 if( dfT != dfLastT && nGCPCount == 0 ) 388 { 389 if( dfT != 0.0 ) 390 { 391 aosTO.SetNameValue("COORDINATE_EPOCH", CPLSPrintf("%g", dfT)); 392 } 393 else 394 { 395 aosTO.SetNameValue("COORDINATE_EPOCH", nullptr); 396 } 397 GDALDestroyGenImgProjTransformer(hTransformArg); 398 hTransformArg = 399 GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, aosTO.List() ); 400 } 401 402 int bSuccess = TRUE; 403 if( pfnTransformer( hTransformArg, bInverse, 1, 404 &dfX, &dfY, &dfZ, &bSuccess ) 405 && bSuccess ) 406 { 407 if( bOutputXY ) 408 CPLprintf( "%.15g %.15g\n", dfX, dfY ); 409 else 410 CPLprintf( "%.15g %.15g %.15g\n", dfX, dfY, dfZ ); 411 } 412 else 413 { 414 printf( "transformation failed.\n" ); 415 } 416 417 if( bCoordOnCommandLine ) 418 break; 419 dfLastT = dfT; 420 } 421 422 if( nGCPCount != 0 && nOrder == -1 ) 423 { 424 GDALDestroyTPSTransformer(hTransformArg); 425 } 426 else if( nGCPCount != 0 ) 427 { 428 GDALDestroyGCPTransformer(hTransformArg); 429 } 430 else 431 { 432 GDALDestroyGenImgProjTransformer(hTransformArg); 433 } 434 435 if (nGCPCount) 436 { 437 GDALDeinitGCPs( nGCPCount, pasGCPs ); 438 CPLFree( pasGCPs ); 439 } 440 441 if (hSrcDS) 442 GDALClose(hSrcDS); 443 444 if (hDstDS) 445 GDALClose(hDstDS); 446 447 GDALDumpOpenDatasets( stderr ); 448 GDALDestroyDriverManager(); 449 450 CSLDestroy( argv ); 451 452 return 0; 453 } 454 MAIN_END 455