Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Command line raster query tool.
5 : * Author: Frank Warmerdam <warmerdam@pobox.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_string.h"
15 : #include "cpl_minixml.h"
16 : #include "gdal_version.h"
17 : #include "gdal.h"
18 : #include "gdal_priv.h"
19 : #include "commonutils.h"
20 : #include "ogr_spatialref.h"
21 : #include "gdalargumentparser.h"
22 :
23 : #include <cmath>
24 : #include <limits>
25 : #include <vector>
26 :
27 : #include <cctype>
28 :
29 : /************************************************************************/
30 : /* GetSRSAsWKT */
31 : /************************************************************************/
32 :
33 1 : static std::string GetSRSAsWKT(const char *pszUserInput)
34 :
35 : {
36 2 : OGRSpatialReference oSRS;
37 1 : oSRS.SetFromUserInput(pszUserInput);
38 2 : return oSRS.exportToWkt();
39 : }
40 :
41 : /************************************************************************/
42 : /* main() */
43 : /************************************************************************/
44 :
45 34 : MAIN_START(argc, argv)
46 :
47 : {
48 34 : double dfGeoX = std::numeric_limits<double>::quiet_NaN();
49 34 : double dfGeoY = std::numeric_limits<double>::quiet_NaN();
50 64 : std::string osSrcFilename;
51 64 : std::string osSourceSRS;
52 64 : std::vector<int> anBandList;
53 34 : bool bAsXML = false, bLIFOnly = false;
54 34 : bool bQuiet = false, bValOnly = false;
55 34 : int nOverview = 0;
56 64 : CPLStringList aosOpenOptions;
57 64 : std::string osFieldSep;
58 34 : bool bIgnoreExtraInput = false;
59 34 : bool bEcho = false;
60 :
61 34 : GDALAllRegister();
62 34 : argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
63 34 : if (argc < 1)
64 0 : exit(-argc);
65 64 : CPLStringList aosArgv;
66 34 : aosArgv.Assign(argv, /* bAssign = */ true);
67 :
68 98 : GDALArgumentParser argParser(aosArgv[0], /* bForBinary=*/true);
69 :
70 34 : argParser.add_description(_("Raster query tool."));
71 :
72 34 : const char *pszEpilog =
73 : _("For more details, consult "
74 : "https://gdal.org/programs/gdallocationinfo.html");
75 34 : argParser.add_epilog(pszEpilog);
76 :
77 34 : argParser.add_argument("-xml").flag().store_into(bAsXML).help(
78 34 : _("Format the output report as XML."));
79 :
80 34 : argParser.add_argument("-lifonly")
81 34 : .flag()
82 34 : .store_into(bLIFOnly)
83 : .help(_("Only outputs filenames from the LocationInfo request against "
84 34 : "the database."));
85 :
86 34 : argParser.add_argument("-valonly")
87 34 : .flag()
88 34 : .store_into(bValOnly)
89 : .help(_("Only outputs pixel values of the selected pixel on each of "
90 34 : "the selected bands."));
91 :
92 34 : argParser.add_argument("-E").flag().store_into(bEcho).help(
93 : _("Enable Echo mode, where input coordinates are prepended to the "
94 34 : "output lines in -valonly mode."));
95 :
96 34 : argParser.add_argument("-field_sep")
97 68 : .metavar("<sep>")
98 34 : .store_into(osFieldSep)
99 : .help(_("Defines the field separator, used in -valonly mode, to "
100 34 : "separate different values."));
101 :
102 34 : argParser.add_argument("-ignore_extra_input")
103 34 : .flag()
104 34 : .store_into(bIgnoreExtraInput)
105 : .help(_("Set this flag to avoid extra non-numeric content at end of "
106 34 : "input lines."));
107 :
108 34 : argParser.add_argument("-b")
109 34 : .append()
110 68 : .metavar("<band>")
111 34 : .store_into(anBandList)
112 34 : .help(_("Select band(s)."));
113 :
114 34 : argParser.add_argument("-overview")
115 68 : .metavar("<overview_level>")
116 34 : .store_into(nOverview)
117 : .help(_("Query the (overview_level)th overview (overview_level=1 is "
118 34 : "the 1st overview)."));
119 :
120 64 : std::string osResampling;
121 34 : argParser.add_argument("-r")
122 34 : .store_into(osResampling)
123 68 : .metavar("nearest|bilinear|cubic|cubicspline")
124 34 : .help(_("Select an interpolation algorithm."));
125 :
126 : {
127 34 : auto &group = argParser.add_mutually_exclusive_group();
128 :
129 34 : group.add_argument("-l_srs")
130 68 : .metavar("<srs_def>")
131 34 : .store_into(osSourceSRS)
132 34 : .help(_("Coordinate system of the input x, y location."));
133 :
134 34 : group.add_argument("-geoloc")
135 34 : .flag()
136 4 : .action([&osSourceSRS](const std::string &)
137 38 : { osSourceSRS = "-geoloc"; })
138 : .help(_("Indicates input x,y points are in the georeferencing "
139 34 : "system of the image."));
140 :
141 34 : group.add_argument("-wgs84")
142 34 : .flag()
143 2 : .action([&osSourceSRS](const std::string &)
144 35 : { osSourceSRS = GetSRSAsWKT("WGS84"); })
145 34 : .help(_("Indicates input x,y points are WGS84 long, lat."));
146 : }
147 :
148 34 : argParser.add_open_options_argument(&aosOpenOptions);
149 :
150 34 : argParser.add_argument("srcfile")
151 68 : .metavar("<srcfile>")
152 34 : .nargs(1)
153 34 : .store_into(osSrcFilename)
154 34 : .help(_("The source GDAL raster datasource name."));
155 :
156 34 : argParser.add_argument("x")
157 68 : .metavar("<x>")
158 34 : .nargs(argparse::nargs_pattern::optional)
159 34 : .store_into(dfGeoX)
160 34 : .help(_("X location of target pixel."));
161 :
162 34 : argParser.add_argument("y")
163 68 : .metavar("<y>")
164 34 : .nargs(argparse::nargs_pattern::optional)
165 34 : .store_into(dfGeoY)
166 34 : .help(_("Y location of target pixel."));
167 :
168 0 : const auto displayUsage = [&argParser]()
169 : {
170 0 : std::stringstream usageStringStream;
171 0 : usageStringStream << argParser.usage();
172 0 : std::cerr << CPLString(usageStringStream.str())
173 0 : .replaceAll("<x> <y>", "[<x> <y>]")
174 0 : << std::endl
175 0 : << std::endl;
176 : std::cout << _("Note: ") << "gdallocationinfo"
177 0 : << _(" --long-usage for full help.") << std::endl;
178 0 : };
179 :
180 : try
181 : {
182 34 : argParser.parse_args(aosArgv);
183 : }
184 0 : catch (const std::exception &err)
185 : {
186 0 : std::cerr << _("Error: ") << err.what() << std::endl;
187 0 : displayUsage();
188 0 : std::exit(1);
189 : }
190 :
191 33 : if (bLIFOnly || bValOnly)
192 23 : bQuiet = true;
193 :
194 : // User specifies with 1-based index, but internally we use 0-based index
195 33 : --nOverview;
196 :
197 : // Deal with special characters
198 33 : osFieldSep = CPLString(osFieldSep)
199 66 : .replaceAll("\\t", '\t')
200 66 : .replaceAll("\\r", '\r')
201 33 : .replaceAll("\\n", '\n');
202 :
203 33 : if (!std::isnan(dfGeoX) && std::isnan(dfGeoY))
204 : {
205 0 : fprintf(stderr, "<y> should be specified when <x> is specified\n\n");
206 0 : displayUsage();
207 0 : exit(1);
208 : }
209 :
210 33 : const bool bIsXYSpecifiedAsArgument = !std::isnan(dfGeoX);
211 :
212 33 : if (bEcho && !bValOnly)
213 : {
214 1 : fprintf(stderr, "-E can only be used with -valonly\n");
215 1 : exit(1);
216 : }
217 32 : if (bEcho && osFieldSep.empty())
218 : {
219 1 : fprintf(stderr, "-E can only be used if -field_sep is specified (to a "
220 : "non-newline value)\n");
221 1 : exit(1);
222 : }
223 :
224 31 : if (osFieldSep.empty())
225 : {
226 22 : osFieldSep = "\n";
227 : }
228 9 : else if (!bValOnly)
229 : {
230 0 : fprintf(stderr, "-field_sep can only be used with -valonly\n");
231 0 : exit(1);
232 : }
233 :
234 : const GDALRIOResampleAlg eInterpolation =
235 31 : osResampling.empty() ? GRIORA_NearestNeighbour
236 10 : : GDALRasterIOGetResampleAlg(osResampling.c_str());
237 31 : if (eInterpolation != GRIORA_NearestNeighbour &&
238 4 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
239 : eInterpolation != GRIORA_CubicSpline)
240 : {
241 1 : fprintf(stderr, "-r can only be used with values nearest, bilinear, "
242 : "cubic and cubicspline\n");
243 1 : exit(1);
244 : }
245 :
246 : /* -------------------------------------------------------------------- */
247 : /* Open source file. */
248 : /* -------------------------------------------------------------------- */
249 30 : GDALDatasetH hSrcDS = GDALOpenEx(osSrcFilename.c_str(),
250 : GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
251 30 : nullptr, aosOpenOptions.List(), nullptr);
252 30 : if (hSrcDS == nullptr)
253 0 : exit(1);
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* Setup coordinate transformation, if required */
257 : /* -------------------------------------------------------------------- */
258 30 : OGRSpatialReferenceH hSrcSRS = nullptr;
259 30 : OGRCoordinateTransformationH hCT = nullptr;
260 30 : if (!osSourceSRS.empty() && !EQUAL(osSourceSRS.c_str(), "-geoloc"))
261 : {
262 4 : hSrcSRS = OSRNewSpatialReference(nullptr);
263 4 : OGRErr err = OSRSetFromUserInput(hSrcSRS, osSourceSRS.c_str());
264 4 : if (err != OGRERR_NONE)
265 0 : exit(1);
266 4 : OSRSetAxisMappingStrategy(hSrcSRS, OAMS_TRADITIONAL_GIS_ORDER);
267 4 : auto hTrgSRS = GDALGetSpatialRef(hSrcDS);
268 4 : if (!hTrgSRS)
269 0 : exit(1);
270 :
271 4 : hCT = OCTNewCoordinateTransformation(hSrcSRS, hTrgSRS);
272 4 : if (hCT == nullptr)
273 0 : exit(1);
274 : }
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* If no bands were requested, we will query them all. */
278 : /* -------------------------------------------------------------------- */
279 30 : if (anBandList.empty())
280 : {
281 64 : for (int i = 0; i < GDALGetRasterCount(hSrcDS); i++)
282 35 : anBandList.push_back(i + 1);
283 : }
284 :
285 : /* -------------------------------------------------------------------- */
286 : /* Turn the location into a pixel and line location. */
287 : /* -------------------------------------------------------------------- */
288 30 : bool inputAvailable = true;
289 60 : CPLString osXML;
290 : char szLine[1024];
291 30 : int nLine = 0;
292 30 : std::string osExtraContent;
293 :
294 30 : if (std::isnan(dfGeoX))
295 : {
296 : // Is it an interactive terminal ?
297 14 : if (CPLIsInteractive(stdin))
298 : {
299 0 : if (!osSourceSRS.empty())
300 : {
301 0 : fprintf(stderr, "Enter X Y values separated by space, and "
302 : "press Return.\n");
303 : }
304 : else
305 : {
306 0 : fprintf(stderr, "Enter pixel line values separated by space, "
307 : "and press Return.\n");
308 : }
309 : }
310 :
311 14 : if (fgets(szLine, sizeof(szLine) - 1, stdin))
312 : {
313 28 : const CPLStringList aosTokens(CSLTokenizeString(szLine));
314 14 : const int nCount = aosTokens.size();
315 :
316 14 : ++nLine;
317 14 : if (nCount < 2)
318 : {
319 0 : fprintf(stderr, "Not enough values at line %d\n", nLine);
320 0 : inputAvailable = false;
321 : }
322 : else
323 : {
324 14 : dfGeoX = CPLAtof(aosTokens[0]);
325 14 : dfGeoY = CPLAtof(aosTokens[1]);
326 14 : if (!bIgnoreExtraInput)
327 : {
328 22 : for (int i = 2; i < nCount; ++i)
329 : {
330 9 : if (!osExtraContent.empty())
331 4 : osExtraContent += ' ';
332 9 : osExtraContent += aosTokens[i];
333 : }
334 18 : while (!osExtraContent.empty() &&
335 5 : isspace(static_cast<int>(osExtraContent.back())))
336 : {
337 0 : osExtraContent.pop_back();
338 : }
339 : }
340 : }
341 : }
342 : else
343 : {
344 0 : inputAvailable = false;
345 : }
346 : }
347 :
348 30 : int nRetCode = 0;
349 38 : while (inputAvailable)
350 : {
351 : int iPixel, iLine;
352 38 : double dfPixel{0}, dfLine{0};
353 38 : const double dfXIn = dfGeoX;
354 38 : const double dfYIn = dfGeoY;
355 :
356 38 : if (hCT)
357 : {
358 4 : if (!OCTTransform(hCT, 1, &dfGeoX, &dfGeoY, nullptr))
359 0 : exit(1);
360 : }
361 :
362 38 : if (!osSourceSRS.empty())
363 : {
364 8 : double adfGeoTransform[6] = {};
365 8 : if (GDALGetGeoTransform(hSrcDS, adfGeoTransform) != CE_None)
366 : {
367 0 : CPLError(CE_Failure, CPLE_AppDefined,
368 : "Cannot get geotransform");
369 0 : exit(1);
370 : }
371 :
372 8 : double adfInvGeoTransform[6] = {};
373 8 : if (!GDALInvGeoTransform(adfGeoTransform, adfInvGeoTransform))
374 : {
375 0 : CPLError(CE_Failure, CPLE_AppDefined,
376 : "Cannot invert geotransform");
377 0 : exit(1);
378 : }
379 :
380 8 : dfPixel = adfInvGeoTransform[0] + adfInvGeoTransform[1] * dfGeoX +
381 8 : adfInvGeoTransform[2] * dfGeoY;
382 8 : dfLine = adfInvGeoTransform[3] + adfInvGeoTransform[4] * dfGeoX +
383 8 : adfInvGeoTransform[5] * dfGeoY;
384 : }
385 : else
386 : {
387 30 : dfPixel = dfGeoX;
388 30 : dfLine = dfGeoY;
389 : }
390 38 : iPixel = static_cast<int>(floor(dfPixel));
391 38 : iLine = static_cast<int>(floor(dfLine));
392 :
393 : /* --------------------------------------------------------------------
394 : */
395 : /* Prepare report. */
396 : /* --------------------------------------------------------------------
397 : */
398 38 : CPLString osXmlLine;
399 :
400 38 : if (bAsXML)
401 : {
402 : osXmlLine.Printf("<Report pixel=\"%d\" line=\"%d\">", iPixel,
403 2 : iLine);
404 2 : osXML += osXmlLine;
405 2 : if (!osExtraContent.empty())
406 : {
407 : char *pszEscaped =
408 1 : CPLEscapeString(osExtraContent.c_str(), -1, CPLES_XML);
409 2 : osXML += CPLString().Printf(" <ExtraInput>%s</ExtraInput>",
410 1 : pszEscaped);
411 1 : CPLFree(pszEscaped);
412 : }
413 : }
414 36 : else if (!bQuiet)
415 : {
416 7 : printf("Report:\n");
417 14 : CPLString osPixel, osLine;
418 7 : if (eInterpolation == GRIORA_NearestNeighbour)
419 : {
420 4 : osPixel.Printf("%d", iPixel);
421 4 : osLine.Printf("%d", iLine);
422 : }
423 : else
424 : {
425 3 : osPixel.Printf("%.15g", dfPixel);
426 3 : osLine.Printf("%.15g", dfLine);
427 : }
428 7 : printf(" Location: (%sP,%sL)\n", osPixel.c_str(), osLine.c_str());
429 7 : if (!osExtraContent.empty())
430 : {
431 1 : printf(" Extra input: %s\n", osExtraContent.c_str());
432 : }
433 : }
434 29 : else if (bEcho)
435 : {
436 9 : printf("%.15g%s%.15g%s", dfXIn, osFieldSep.c_str(), dfYIn,
437 : osFieldSep.c_str());
438 : }
439 :
440 38 : bool bPixelReport = true;
441 :
442 72 : if (iPixel < 0 || iLine < 0 || iPixel >= GDALGetRasterXSize(hSrcDS) ||
443 34 : iLine >= GDALGetRasterYSize(hSrcDS))
444 : {
445 4 : if (bAsXML)
446 : osXML += "<Alert>Location is off this file! No further details "
447 0 : "to report.</Alert>";
448 4 : else if (bValOnly)
449 : {
450 8 : for (int i = 1; i < static_cast<int>(anBandList.size()); i++)
451 : {
452 4 : printf("%s", osFieldSep.c_str());
453 : }
454 : }
455 0 : else if (!bQuiet)
456 0 : printf("\nLocation is off this file! No further details to "
457 : "report.\n");
458 4 : bPixelReport = false;
459 4 : nRetCode = 1;
460 : }
461 :
462 : /* --------------------------------------------------------------------
463 : */
464 : /* Process each band. */
465 : /* --------------------------------------------------------------------
466 : */
467 82 : for (int i = 0; bPixelReport && i < static_cast<int>(anBandList.size());
468 : i++)
469 : {
470 44 : GDALRasterBandH hBand = GDALGetRasterBand(hSrcDS, anBandList[i]);
471 :
472 44 : int iPixelToQuery = iPixel;
473 44 : int iLineToQuery = iLine;
474 :
475 44 : double dfPixelToQuery = dfPixel;
476 44 : double dfLineToQuery = dfLine;
477 :
478 44 : if (nOverview >= 0 && hBand != nullptr)
479 : {
480 1 : GDALRasterBandH hOvrBand = GDALGetOverview(hBand, nOverview);
481 1 : if (hOvrBand != nullptr)
482 : {
483 1 : int nOvrXSize = GDALGetRasterBandXSize(hOvrBand);
484 1 : int nOvrYSize = GDALGetRasterBandYSize(hOvrBand);
485 1 : iPixelToQuery = static_cast<int>(
486 1 : 0.5 +
487 1 : 1.0 * iPixel / GDALGetRasterXSize(hSrcDS) * nOvrXSize);
488 1 : iLineToQuery = static_cast<int>(
489 1 : 0.5 +
490 1 : 1.0 * iLine / GDALGetRasterYSize(hSrcDS) * nOvrYSize);
491 1 : if (iPixelToQuery >= nOvrXSize)
492 0 : iPixelToQuery = nOvrXSize - 1;
493 1 : if (iLineToQuery >= nOvrYSize)
494 0 : iLineToQuery = nOvrYSize - 1;
495 1 : dfPixelToQuery =
496 1 : dfPixel / GDALGetRasterXSize(hSrcDS) * nOvrXSize;
497 1 : dfLineToQuery =
498 1 : dfLine / GDALGetRasterYSize(hSrcDS) * nOvrYSize;
499 : }
500 : else
501 : {
502 0 : CPLError(CE_Failure, CPLE_AppDefined,
503 : "Cannot get overview %d of band %d", nOverview + 1,
504 0 : anBandList[i]);
505 : }
506 1 : hBand = hOvrBand;
507 : }
508 :
509 44 : if (hBand == nullptr)
510 0 : continue;
511 :
512 44 : if (bAsXML)
513 : {
514 2 : osXmlLine.Printf("<BandReport band=\"%d\">", anBandList[i]);
515 2 : osXML += osXmlLine;
516 : }
517 42 : else if (!bQuiet)
518 : {
519 7 : printf(" Band %d:\n", anBandList[i]);
520 : }
521 :
522 : /* --------------------------------------------------------------------
523 : */
524 : /* Request location info for this location. It is possible */
525 : /* only the VRT driver actually supports this. */
526 : /* --------------------------------------------------------------------
527 : */
528 88 : CPLString osItem;
529 :
530 44 : osItem.Printf("Pixel_%d_%d", iPixelToQuery, iLineToQuery);
531 :
532 : const char *pszLI =
533 44 : GDALGetMetadataItem(hBand, osItem, "LocationInfo");
534 :
535 44 : if (pszLI != nullptr)
536 : {
537 1 : if (bAsXML)
538 0 : osXML += pszLI;
539 1 : else if (!bQuiet)
540 0 : printf(" %s\n", pszLI);
541 1 : else if (bLIFOnly)
542 : {
543 : /* Extract all files, if any. */
544 :
545 1 : CPLXMLNode *psRoot = CPLParseXMLString(pszLI);
546 :
547 1 : if (psRoot != nullptr && psRoot->psChild != nullptr &&
548 1 : psRoot->eType == CXT_Element &&
549 1 : EQUAL(psRoot->pszValue, "LocationInfo"))
550 : {
551 1 : for (CPLXMLNode *psNode = psRoot->psChild;
552 2 : psNode != nullptr; psNode = psNode->psNext)
553 : {
554 1 : if (psNode->eType == CXT_Element &&
555 1 : EQUAL(psNode->pszValue, "File") &&
556 1 : psNode->psChild != nullptr)
557 : {
558 : char *pszUnescaped =
559 1 : CPLUnescapeString(psNode->psChild->pszValue,
560 : nullptr, CPLES_XML);
561 1 : printf("%s\n", pszUnescaped);
562 1 : CPLFree(pszUnescaped);
563 : }
564 : }
565 : }
566 1 : CPLDestroyXMLNode(psRoot);
567 : }
568 : }
569 :
570 : /* --------------------------------------------------------------------
571 : */
572 : /* Report the pixel value of this band. */
573 : /* --------------------------------------------------------------------
574 : */
575 44 : double adfPixel[2] = {0, 0};
576 44 : const bool bIsComplex = CPL_TO_BOOL(
577 : GDALDataTypeIsComplex(GDALGetRasterDataType(hBand)));
578 :
579 : CPLErr err;
580 44 : err = GDALRasterInterpolateAtPoint(hBand, dfPixelToQuery,
581 : dfLineToQuery, eInterpolation,
582 : &adfPixel[0], &adfPixel[1]);
583 :
584 44 : if (err == CE_None)
585 : {
586 86 : CPLString osValue;
587 :
588 43 : if (bIsComplex)
589 0 : osValue.Printf("%.15g+%.15gi", adfPixel[0], adfPixel[1]);
590 : else
591 43 : osValue.Printf("%.15g", adfPixel[0]);
592 :
593 43 : if (bAsXML)
594 : {
595 2 : osXML += "<Value>";
596 2 : osXML += osValue;
597 2 : osXML += "</Value>";
598 : }
599 41 : else if (!bQuiet)
600 7 : printf(" Value: %s\n", osValue.c_str());
601 34 : else if (bValOnly)
602 : {
603 34 : if (i > 0)
604 10 : printf("%s", osFieldSep.c_str());
605 34 : printf("%s", osValue.c_str());
606 : }
607 :
608 : // Report unscaled if we have scale/offset values.
609 : int bSuccess;
610 :
611 43 : double dfOffset = GDALGetRasterOffset(hBand, &bSuccess);
612 : // TODO: Should we turn on checking of bSuccess?
613 : // Alternatively, delete these checks and put a comment as to
614 : // why checking bSuccess does not matter.
615 : #if 0
616 : if (bSuccess == FALSE)
617 : {
618 : CPLError( CE_Debug, CPLE_AppDefined,
619 : "Unable to get raster offset." );
620 : }
621 : #endif
622 43 : double dfScale = GDALGetRasterScale(hBand, &bSuccess);
623 : #if 0
624 : if (bSuccess == FALSE)
625 : {
626 : CPLError( CE_Debug, CPLE_AppDefined,
627 : "Unable to get raster scale." );
628 : }
629 : #endif
630 43 : if (dfOffset != 0.0 || dfScale != 1.0)
631 : {
632 0 : adfPixel[0] = adfPixel[0] * dfScale + dfOffset;
633 :
634 0 : if (bIsComplex)
635 : {
636 0 : adfPixel[1] = adfPixel[1] * dfScale + dfOffset;
637 : osValue.Printf("%.15g+%.15gi", adfPixel[0],
638 0 : adfPixel[1]);
639 : }
640 : else
641 0 : osValue.Printf("%.15g", adfPixel[0]);
642 :
643 0 : if (bAsXML)
644 : {
645 0 : osXML += "<DescaledValue>";
646 0 : osXML += osValue;
647 0 : osXML += "</DescaledValue>";
648 : }
649 0 : else if (!bQuiet)
650 0 : printf(" Descaled Value: %s\n", osValue.c_str());
651 : }
652 : }
653 :
654 44 : if (bAsXML)
655 2 : osXML += "</BandReport>";
656 : }
657 :
658 38 : osXML += "</Report>";
659 :
660 38 : if (bValOnly)
661 : {
662 28 : if (!osExtraContent.empty() && osFieldSep != "\n")
663 2 : printf("%s%s", osFieldSep.c_str(), osExtraContent.c_str());
664 28 : printf("\n");
665 : }
666 :
667 38 : if (bIsXYSpecifiedAsArgument)
668 16 : break;
669 :
670 22 : osExtraContent.clear();
671 22 : if (fgets(szLine, sizeof(szLine) - 1, stdin))
672 : {
673 8 : const CPLStringList aosTokens(CSLTokenizeString(szLine));
674 8 : const int nCount = aosTokens.size();
675 :
676 8 : ++nLine;
677 8 : if (nCount < 2)
678 : {
679 0 : fprintf(stderr, "Not enough values at line %d\n", nLine);
680 0 : continue;
681 : }
682 : else
683 : {
684 8 : dfGeoX = CPLAtof(aosTokens[0]);
685 8 : dfGeoY = CPLAtof(aosTokens[1]);
686 8 : if (!bIgnoreExtraInput)
687 : {
688 8 : for (int i = 2; i < nCount; ++i)
689 : {
690 0 : if (!osExtraContent.empty())
691 0 : osExtraContent += ' ';
692 0 : osExtraContent += aosTokens[i];
693 : }
694 8 : while (!osExtraContent.empty() &&
695 0 : isspace(static_cast<int>(osExtraContent.back())))
696 : {
697 0 : osExtraContent.pop_back();
698 : }
699 : }
700 : }
701 : }
702 : else
703 : {
704 14 : break;
705 : }
706 : }
707 :
708 : /* -------------------------------------------------------------------- */
709 : /* Finalize xml report and print. */
710 : /* -------------------------------------------------------------------- */
711 30 : if (bAsXML)
712 : {
713 2 : CPLXMLNode *psRoot = CPLParseXMLString(osXML);
714 2 : char *pszFormattedXML = CPLSerializeXMLTree(psRoot);
715 2 : CPLDestroyXMLNode(psRoot);
716 :
717 2 : printf("%s", pszFormattedXML);
718 2 : CPLFree(pszFormattedXML);
719 : }
720 :
721 : /* -------------------------------------------------------------------- */
722 : /* Cleanup */
723 : /* -------------------------------------------------------------------- */
724 30 : if (hCT)
725 : {
726 4 : OSRDestroySpatialReference(hSrcSRS);
727 4 : OCTDestroyCoordinateTransformation(hCT);
728 : }
729 :
730 30 : GDALClose(hSrcDS);
731 :
732 30 : GDALDumpOpenDatasets(stderr);
733 30 : GDALDestroyDriverManager();
734 :
735 30 : return nRetCode;
736 : }
737 :
738 0 : MAIN_END
|