1 : /******************************************************************************
2 : * $Id: gdal_misc.cpp 18246 2009-12-10 17:21:30Z warmerdam $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Free standing functions for GDAL.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
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 "gdal_priv.h"
31 : #include "cpl_string.h"
32 : #include "cpl_minixml.h"
33 : #include "cpl_multiproc.h"
34 : #include <ctype.h>
35 : #include <string>
36 :
37 : CPL_CVSID("$Id: gdal_misc.cpp 18246 2009-12-10 17:21:30Z warmerdam $");
38 :
39 : #include "ogr_spatialref.h"
40 :
41 : /************************************************************************/
42 : /* __pure_virtual() */
43 : /* */
44 : /* The following is a gross hack to remove the last remaining */
45 : /* dependency on the GNU C++ standard library. */
46 : /************************************************************************/
47 :
48 : #ifdef __GNUC__
49 :
50 : extern "C"
51 0 : void __pure_virtual()
52 :
53 : {
54 0 : }
55 :
56 : #endif
57 :
58 : /************************************************************************/
59 : /* GDALDataTypeUnion() */
60 : /************************************************************************/
61 :
62 : /**
63 : * \brief Return the smallest data type that can fully express both input data
64 : * types.
65 : *
66 : * @param eType1
67 : * @param eType2
68 : *
69 : * @return a data type able to express eType1 and eType2.
70 : */
71 :
72 : GDALDataType CPL_STDCALL
73 597 : GDALDataTypeUnion( GDALDataType eType1, GDALDataType eType2 )
74 :
75 : {
76 : int bFloating, bComplex, nBits, bSigned;
77 :
78 597 : bComplex = GDALDataTypeIsComplex(eType1) | GDALDataTypeIsComplex(eType2);
79 :
80 597 : switch( eType1 )
81 : {
82 : case GDT_Byte:
83 377 : nBits = 8;
84 377 : bSigned = FALSE;
85 377 : bFloating = FALSE;
86 377 : break;
87 :
88 : case GDT_Int16:
89 : case GDT_CInt16:
90 0 : nBits = 16;
91 0 : bSigned = TRUE;
92 0 : bFloating = FALSE;
93 0 : break;
94 :
95 : case GDT_UInt16:
96 0 : nBits = 16;
97 0 : bSigned = FALSE;
98 0 : bFloating = FALSE;
99 0 : break;
100 :
101 : case GDT_Int32:
102 : case GDT_CInt32:
103 0 : nBits = 32;
104 0 : bSigned = TRUE;
105 0 : bFloating = FALSE;
106 0 : break;
107 :
108 : case GDT_UInt32:
109 0 : nBits = 32;
110 0 : bSigned = FALSE;
111 0 : bFloating = FALSE;
112 0 : break;
113 :
114 : case GDT_Float32:
115 : case GDT_CFloat32:
116 220 : nBits = 32;
117 220 : bSigned = TRUE;
118 220 : bFloating = TRUE;
119 220 : break;
120 :
121 : case GDT_Float64:
122 : case GDT_CFloat64:
123 0 : nBits = 64;
124 0 : bSigned = TRUE;
125 0 : bFloating = TRUE;
126 0 : break;
127 :
128 : default:
129 : CPLAssert( FALSE );
130 0 : return GDT_Unknown;
131 : }
132 :
133 597 : switch( eType2 )
134 : {
135 : case GDT_Byte:
136 130 : break;
137 :
138 : case GDT_Int16:
139 : case GDT_CInt16:
140 62 : nBits = MAX(nBits,16);
141 62 : bSigned = TRUE;
142 62 : break;
143 :
144 : case GDT_UInt16:
145 24 : nBits = MAX(nBits,16);
146 24 : break;
147 :
148 : case GDT_Int32:
149 : case GDT_CInt32:
150 265 : nBits = MAX(nBits,32);
151 265 : bSigned = TRUE;
152 265 : break;
153 :
154 : case GDT_UInt32:
155 23 : nBits = MAX(nBits,32);
156 23 : break;
157 :
158 : case GDT_Float32:
159 : case GDT_CFloat32:
160 46 : nBits = MAX(nBits,32);
161 46 : bSigned = TRUE;
162 46 : bFloating = TRUE;
163 46 : break;
164 :
165 : case GDT_Float64:
166 : case GDT_CFloat64:
167 47 : nBits = MAX(nBits,64);
168 47 : bSigned = TRUE;
169 47 : bFloating = TRUE;
170 47 : break;
171 :
172 : default:
173 : CPLAssert( FALSE );
174 0 : return GDT_Unknown;
175 : }
176 :
177 597 : if( nBits == 8 )
178 130 : return GDT_Byte;
179 467 : else if( nBits == 16 && bComplex )
180 22 : return GDT_CInt16;
181 445 : else if( nBits == 16 && bSigned )
182 40 : return GDT_Int16;
183 405 : else if( nBits == 16 && !bSigned )
184 24 : return GDT_UInt16;
185 381 : else if( nBits == 32 && bFloating && bComplex )
186 23 : return GDT_CFloat32;
187 358 : else if( nBits == 32 && bFloating )
188 243 : return GDT_Float32;
189 115 : else if( nBits == 32 && bComplex )
190 22 : return GDT_CInt32;
191 93 : else if( nBits == 32 && bSigned )
192 23 : return GDT_Int32;
193 70 : else if( nBits == 32 && !bSigned )
194 23 : return GDT_UInt32;
195 47 : else if( nBits == 64 && bComplex )
196 23 : return GDT_CFloat64;
197 : else
198 24 : return GDT_Float64;
199 : }
200 :
201 :
202 : /************************************************************************/
203 : /* GDALGetDataTypeSize() */
204 : /************************************************************************/
205 :
206 : /**
207 : * \brief Get data type size in bits.
208 : *
209 : * Returns the size of a a GDT_* type in bits, <b>not bytes</b>!
210 : *
211 : * @param data type, such as GDT_Byte.
212 : * @return the number of bits or zero if it is not recognised.
213 : */
214 :
215 6011722 : int CPL_STDCALL GDALGetDataTypeSize( GDALDataType eDataType )
216 :
217 : {
218 6011722 : switch( eDataType )
219 : {
220 : case GDT_Byte:
221 3149810 : return 8;
222 :
223 : case GDT_UInt16:
224 : case GDT_Int16:
225 1238129 : return 16;
226 :
227 : case GDT_UInt32:
228 : case GDT_Int32:
229 : case GDT_Float32:
230 : case GDT_CInt16:
231 1419541 : return 32;
232 :
233 : case GDT_Float64:
234 : case GDT_CInt32:
235 : case GDT_CFloat32:
236 32792 : return 64;
237 :
238 : case GDT_CFloat64:
239 171450 : return 128;
240 :
241 : default:
242 0 : return 0;
243 : }
244 : }
245 :
246 : /************************************************************************/
247 : /* GDALDataTypeIsComplex() */
248 : /************************************************************************/
249 :
250 : /**
251 : * \brief Is data type complex?
252 : *
253 : * @return TRUE if the passed type is complex (one of GDT_CInt16, GDT_CInt32,
254 : * GDT_CFloat32 or GDT_CFloat64), that is it consists of a real and imaginary
255 : * component.
256 : */
257 :
258 5804 : int CPL_STDCALL GDALDataTypeIsComplex( GDALDataType eDataType )
259 :
260 : {
261 5804 : switch( eDataType )
262 : {
263 : case GDT_CInt16:
264 : case GDT_CInt32:
265 : case GDT_CFloat32:
266 : case GDT_CFloat64:
267 318 : return TRUE;
268 :
269 : default:
270 5486 : return FALSE;
271 : }
272 : }
273 :
274 : /************************************************************************/
275 : /* GDALGetDataTypeName() */
276 : /************************************************************************/
277 :
278 : /**
279 : * \brief Get name of data type.
280 : *
281 : * Returns a symbolic name for the data type. This is essentially the
282 : * the enumerated item name with the GDT_ prefix removed. So GDT_Byte returns
283 : * "Byte". The returned strings are static strings and should not be modified
284 : * or freed by the application. These strings are useful for reporting
285 : * datatypes in debug statements, errors and other user output.
286 : *
287 : * @param eDataType type to get name of.
288 : * @return string corresponding to type.
289 : */
290 :
291 11487 : const char * CPL_STDCALL GDALGetDataTypeName( GDALDataType eDataType )
292 :
293 : {
294 11487 : switch( eDataType )
295 : {
296 : case GDT_Unknown:
297 84 : return "Unknown";
298 :
299 : case GDT_Byte:
300 7663 : return "Byte";
301 :
302 : case GDT_UInt16:
303 525 : return "UInt16";
304 :
305 : case GDT_Int16:
306 468 : return "Int16";
307 :
308 : case GDT_UInt32:
309 413 : return "UInt32";
310 :
311 : case GDT_Int32:
312 382 : return "Int32";
313 :
314 : case GDT_Float32:
315 407 : return "Float32";
316 :
317 : case GDT_Float64:
318 325 : return "Float64";
319 :
320 : case GDT_CInt16:
321 307 : return "CInt16";
322 :
323 : case GDT_CInt32:
324 305 : return "CInt32";
325 :
326 : case GDT_CFloat32:
327 304 : return "CFloat32";
328 :
329 : case GDT_CFloat64:
330 304 : return "CFloat64";
331 :
332 : default:
333 0 : return NULL;
334 : }
335 : }
336 :
337 : /************************************************************************/
338 : /* GDALGetDataTypeByName() */
339 : /************************************************************************/
340 :
341 : /**
342 : * \brief Get data type by symbolic name.
343 : *
344 : * Returns a data type corresponding to the given symbolic name. This
345 : * function is opposite to the GDALGetDataTypeName().
346 : *
347 : * @param pszName string containing the symbolic name of the type.
348 : *
349 : * @return GDAL data type.
350 : */
351 :
352 255 : GDALDataType CPL_STDCALL GDALGetDataTypeByName( const char *pszName )
353 :
354 : {
355 255 : VALIDATE_POINTER1( pszName, "GDALGetDataTypeByName", GDT_Unknown );
356 :
357 : int iType;
358 :
359 517 : for( iType = 1; iType < GDT_TypeCount; iType++ )
360 : {
361 517 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
362 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType), pszName) )
363 : {
364 255 : return (GDALDataType)iType;
365 : }
366 : }
367 :
368 0 : return GDT_Unknown;
369 : }
370 :
371 : /************************************************************************/
372 : /* GDALGetPaletteInterpretationName() */
373 : /************************************************************************/
374 :
375 : /**
376 : * \brief Get name of palette interpretation
377 : *
378 : * Returns a symbolic name for the palette interpretation. This is the
379 : * the enumerated item name with the GPI_ prefix removed. So GPI_Gray returns
380 : * "Gray". The returned strings are static strings and should not be modified
381 : * or freed by the application.
382 : *
383 : * @param eInterp palette interpretation to get name of.
384 : * @return string corresponding to palette interpretation.
385 : */
386 :
387 2 : const char *GDALGetPaletteInterpretationName( GDALPaletteInterp eInterp )
388 :
389 : {
390 2 : switch( eInterp )
391 : {
392 : case GPI_Gray:
393 0 : return "Gray";
394 :
395 : case GPI_RGB:
396 2 : return "RGB";
397 :
398 : case GPI_CMYK:
399 0 : return "CMYK";
400 :
401 : case GPI_HLS:
402 0 : return "HLS";
403 :
404 : default:
405 0 : return "Unknown";
406 : }
407 : }
408 :
409 : /************************************************************************/
410 : /* GDALGetColorInterpretationName() */
411 : /************************************************************************/
412 :
413 : /**
414 : * \brief Get name of color interpretation
415 : *
416 : * Returns a symbolic name for the color interpretation. This is derived from
417 : * the enumerated item name with the GCI_ prefix removed, but there are some
418 : * variations. So GCI_GrayIndex returns "Gray" and GCI_RedBand returns "Red".
419 : * The returned strings are static strings and should not be modified
420 : * or freed by the application.
421 : *
422 : * @param eInterp color interpretation to get name of.
423 : * @return string corresponding to color interpretation.
424 : */
425 :
426 1384 : const char *GDALGetColorInterpretationName( GDALColorInterp eInterp )
427 :
428 : {
429 1384 : switch( eInterp )
430 : {
431 : case GCI_Undefined:
432 355 : return "Undefined";
433 :
434 : case GCI_GrayIndex:
435 589 : return "Gray";
436 :
437 : case GCI_PaletteIndex:
438 90 : return "Palette";
439 :
440 : case GCI_RedBand:
441 110 : return "Red";
442 :
443 : case GCI_GreenBand:
444 85 : return "Green";
445 :
446 : case GCI_BlueBand:
447 66 : return "Blue";
448 :
449 : case GCI_AlphaBand:
450 32 : return "Alpha";
451 :
452 : case GCI_HueBand:
453 6 : return "Hue";
454 :
455 : case GCI_SaturationBand:
456 6 : return "Saturation";
457 :
458 : case GCI_LightnessBand:
459 6 : return "Lightness";
460 :
461 : case GCI_CyanBand:
462 6 : return "Cyan";
463 :
464 : case GCI_MagentaBand:
465 6 : return "Magenta";
466 :
467 : case GCI_YellowBand:
468 6 : return "Yellow";
469 :
470 : case GCI_BlackBand:
471 6 : return "Black";
472 :
473 : case GCI_YCbCr_YBand:
474 7 : return "YCbCr_Y";
475 :
476 : case GCI_YCbCr_CbBand:
477 5 : return "YCbCr_Cb";
478 :
479 : case GCI_YCbCr_CrBand:
480 3 : return "YCbCr_Cr";
481 :
482 : default:
483 0 : return "Unknown";
484 : }
485 : }
486 :
487 : /************************************************************************/
488 : /* GDALGetColorInterpretationByName() */
489 : /************************************************************************/
490 :
491 : /**
492 : * \brief Get color interpreation by symbolic name.
493 : *
494 : * Returns a color interpreation corresponding to the given symbolic name. This
495 : * function is opposite to the GDALGetColorInterpretationName().
496 : *
497 : * @param pszName string containing the symbolic name of the color interpretation.
498 : *
499 : * @return GDAL color interpretation.
500 : *
501 : * @since GDAL 1.7.0
502 : */
503 :
504 354 : GDALColorInterp GDALGetColorInterpretationByName( const char *pszName )
505 :
506 : {
507 354 : VALIDATE_POINTER1( pszName, "GDALGetColorInterpretationByName", GCI_Undefined );
508 :
509 : int iType;
510 :
511 1047 : for( iType = 0; iType <= GCI_Max; iType++ )
512 : {
513 1047 : if( EQUAL(GDALGetColorInterpretationName((GDALColorInterp)iType), pszName) )
514 : {
515 354 : return (GDALColorInterp)iType;
516 : }
517 : }
518 :
519 0 : return GCI_Undefined;
520 : }
521 :
522 : /************************************************************************/
523 : /* GDALDummyProgress() */
524 : /************************************************************************/
525 :
526 : /**
527 : * \brief Stub progress function.
528 : *
529 : * This is a stub (does nothing) implementation of the GDALProgressFunc()
530 : * semantics. It is primarily useful for passing to functions that take
531 : * a GDALProgressFunc() argument but for which the application does not want
532 : * to use one of the other progress functions that actually do something.
533 : */
534 :
535 75158 : int CPL_STDCALL GDALDummyProgress( double dfComplete, const char *pszMessage,
536 : void *pData )
537 :
538 : {
539 75158 : return TRUE;
540 : }
541 :
542 : /************************************************************************/
543 : /* GDALScaledProgress() */
544 : /************************************************************************/
545 : typedef struct {
546 : GDALProgressFunc pfnProgress;
547 : void *pData;
548 : double dfMin;
549 : double dfMax;
550 : } GDALScaledProgressInfo;
551 :
552 : /**
553 : * \brief Scaled progress transformer.
554 : *
555 : * This is the progress function that should be passed along with the
556 : * callback data returned by GDALCreateScaledProgress().
557 : */
558 :
559 598 : int CPL_STDCALL GDALScaledProgress( double dfComplete, const char *pszMessage,
560 : void *pData )
561 :
562 : {
563 598 : GDALScaledProgressInfo *psInfo = (GDALScaledProgressInfo *) pData;
564 :
565 : return psInfo->pfnProgress( dfComplete * (psInfo->dfMax - psInfo->dfMin)
566 : + psInfo->dfMin,
567 598 : pszMessage, psInfo->pData );
568 : }
569 :
570 : /************************************************************************/
571 : /* GDALCreateScaledProgress() */
572 : /************************************************************************/
573 :
574 : /**
575 : * \brief Create scaled progress transformer.
576 : *
577 : * Sometimes when an operations wants to report progress it actually
578 : * invokes several subprocesses which also take GDALProgressFunc()s,
579 : * and it is desirable to map the progress of each sub operation into
580 : * a portion of 0.0 to 1.0 progress of the overall process. The scaled
581 : * progress function can be used for this.
582 : *
583 : * For each subsection a scaled progress function is created and
584 : * instead of passing the overall progress func down to the sub functions,
585 : * the GDALScaledProgress() function is passed instead.
586 : *
587 : * @param dfMin the value to which 0.0 in the sub operation is mapped.
588 : * @param dfMax the value to which 1.0 is the sub operation is mapped.
589 : * @param pfnProgress the overall progress function.
590 : * @param pData the overall progress function callback data.
591 : *
592 : * @return pointer to pass as pProgressArg to sub functions. Should be freed
593 : * with GDALDestroyScaledProgress().
594 : *
595 : * Example:
596 : *
597 : * \code
598 : * int MyOperation( ..., GDALProgressFunc pfnProgress, void *pProgressData );
599 : *
600 : * {
601 : * void *pScaledProgress;
602 : *
603 : * pScaledProgress = GDALCreateScaledProgress( 0.0, 0.5, pfnProgress,
604 : * pProgressData );
605 : * GDALDoLongSlowOperation( ..., GDALScaledProgress, pScaledProgress );
606 : * GDALDestroyScaledProgress( pScaledProgress );
607 : *
608 : * pScaledProgress = GDALCreateScaledProgress( 0.5, 1.0, pfnProgress,
609 : * pProgressData );
610 : * GDALDoAnotherOperation( ..., GDALScaledProgress, pScaledProgress );
611 : * GDALDestroyScaledProgress( pScaledProgress );
612 : *
613 : * return ...;
614 : * }
615 : * \endcode
616 : */
617 :
618 152 : void * CPL_STDCALL GDALCreateScaledProgress( double dfMin, double dfMax,
619 : GDALProgressFunc pfnProgress,
620 : void * pData )
621 :
622 : {
623 : GDALScaledProgressInfo *psInfo;
624 :
625 : psInfo = (GDALScaledProgressInfo *)
626 152 : CPLCalloc(sizeof(GDALScaledProgressInfo),1);
627 :
628 152 : if( ABS(dfMin-dfMax) < 0.0000001 )
629 0 : dfMax = dfMin + 0.01;
630 :
631 152 : psInfo->pData = pData;
632 152 : psInfo->pfnProgress = pfnProgress;
633 152 : psInfo->dfMin = dfMin;
634 152 : psInfo->dfMax = dfMax;
635 :
636 152 : return (void *) psInfo;
637 : }
638 :
639 : /************************************************************************/
640 : /* GDALDestroyScaledProgress() */
641 : /************************************************************************/
642 :
643 : /**
644 : * \brief Cleanup scaled progress handle.
645 : *
646 : * This function cleans up the data associated with a scaled progress function
647 : * as returned by GADLCreateScaledProgress().
648 : *
649 : * @param pData scaled progress handle returned by GDALCreateScaledProgress().
650 : */
651 :
652 152 : void CPL_STDCALL GDALDestroyScaledProgress( void * pData )
653 :
654 : {
655 152 : CPLFree( pData );
656 152 : }
657 :
658 : /************************************************************************/
659 : /* GDALTermProgress() */
660 : /************************************************************************/
661 :
662 : /**
663 : * \brief Simple progress report to terminal.
664 : *
665 : * This progress reporter prints simple progress report to the
666 : * terminal window. The progress report generally looks something like
667 : * this:
668 :
669 : \verbatim
670 : 0...10...20...30...40...50...60...70...80...90...100 - done.
671 : \endverbatim
672 :
673 : * Every 2.5% of progress another number or period is emitted. Note that
674 : * GDALTermProgress() uses internal static data to keep track of the last
675 : * percentage reported and will get confused if two terminal based progress
676 : * reportings are active at the same time.
677 : *
678 : * The GDALTermProgress() function maintains an internal memory of the
679 : * last percentage complete reported in a static variable, and this makes
680 : * it unsuitable to have multiple GDALTermProgress()'s active eithin a
681 : * single thread or across multiple threads.
682 : *
683 : * @param dfComplete completion ratio from 0.0 to 1.0.
684 : * @param pszMessage optional message.
685 : * @param pProgressArg ignored callback data argument.
686 : *
687 : * @return Always returns TRUE indicating the process should continue.
688 : */
689 :
690 5910 : int CPL_STDCALL GDALTermProgress( double dfComplete, const char *pszMessage,
691 : void * pProgressArg )
692 :
693 : {
694 : static int nLastTick = -1;
695 5910 : int nThisTick = (int) (dfComplete * 40.0);
696 :
697 : (void) pProgressArg;
698 :
699 5910 : nThisTick = MIN(40,MAX(0,nThisTick));
700 :
701 : // Have we started a new progress run?
702 5910 : if( nThisTick < nLastTick && nLastTick >= 39 )
703 0 : nLastTick = -1;
704 :
705 5910 : if( nThisTick <= nLastTick )
706 3504 : return TRUE;
707 :
708 16990 : while( nThisTick > nLastTick )
709 : {
710 12178 : nLastTick++;
711 12178 : if( nLastTick % 4 == 0 )
712 3268 : fprintf( stdout, "%d", (nLastTick / 4) * 10 );
713 : else
714 8910 : fprintf( stdout, "." );
715 : }
716 :
717 2406 : if( nThisTick == 40 )
718 297 : fprintf( stdout, " - done.\n" );
719 : else
720 2109 : fflush( stdout );
721 :
722 2406 : return TRUE;
723 : }
724 :
725 : /************************************************************************/
726 : /* GDALGetRandomRasterSample() */
727 : /************************************************************************/
728 :
729 : int CPL_STDCALL
730 0 : GDALGetRandomRasterSample( GDALRasterBandH hBand, int nSamples,
731 : float *pafSampleBuf )
732 :
733 : {
734 0 : VALIDATE_POINTER1( hBand, "GDALGetRandomRasterSample", 0 );
735 :
736 : GDALRasterBand *poBand;
737 :
738 0 : poBand = (GDALRasterBand *) GDALGetRasterSampleOverview( hBand, nSamples );
739 : CPLAssert( NULL != poBand );
740 :
741 : /* -------------------------------------------------------------------- */
742 : /* Figure out the ratio of blocks we will read to get an */
743 : /* approximate value. */
744 : /* -------------------------------------------------------------------- */
745 : int nBlockXSize, nBlockYSize;
746 : int nBlocksPerRow, nBlocksPerColumn;
747 : int nSampleRate;
748 : int bGotNoDataValue;
749 : double dfNoDataValue;
750 0 : int nActualSamples = 0;
751 : int nBlockSampleRate;
752 : int nBlockPixels, nBlockCount;
753 :
754 0 : dfNoDataValue = poBand->GetNoDataValue( &bGotNoDataValue );
755 :
756 0 : poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
757 :
758 0 : nBlocksPerRow = (poBand->GetXSize() + nBlockXSize - 1) / nBlockXSize;
759 0 : nBlocksPerColumn = (poBand->GetYSize() + nBlockYSize - 1) / nBlockYSize;
760 :
761 0 : nBlockPixels = nBlockXSize * nBlockYSize;
762 0 : nBlockCount = nBlocksPerRow * nBlocksPerColumn;
763 :
764 0 : if( nBlocksPerRow == 0 || nBlocksPerColumn == 0 || nBlockPixels == 0
765 : || nBlockCount == 0 )
766 : {
767 : CPLError( CE_Failure, CPLE_AppDefined,
768 : "GDALGetRandomRasterSample(): returning because band"
769 0 : " appears degenerate." );
770 :
771 0 : return FALSE;
772 : }
773 :
774 0 : nSampleRate = (int) MAX(1,sqrt((double) nBlockCount)-2.0);
775 :
776 0 : if( nSampleRate == nBlocksPerRow && nSampleRate > 1 )
777 0 : nSampleRate--;
778 :
779 0 : while( nSampleRate > 1
780 : && ((nBlockCount-1) / nSampleRate + 1) * nBlockPixels < nSamples )
781 0 : nSampleRate--;
782 :
783 0 : if ((nSamples / ((nBlockCount-1) / nSampleRate + 1)) == 0)
784 0 : nBlockSampleRate = 1;
785 : else
786 : nBlockSampleRate =
787 0 : MAX(1,nBlockPixels / (nSamples / ((nBlockCount-1) / nSampleRate + 1)));
788 :
789 0 : for( int iSampleBlock = 0;
790 : iSampleBlock < nBlockCount;
791 : iSampleBlock += nSampleRate )
792 : {
793 0 : double dfValue = 0.0, dfReal, dfImag;
794 0 : int iXBlock, iYBlock, iX, iY, iXValid, iYValid, iRemainder = 0;
795 : GDALRasterBlock *poBlock;
796 :
797 0 : iYBlock = iSampleBlock / nBlocksPerRow;
798 0 : iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
799 :
800 0 : poBlock = poBand->GetLockedBlockRef( iXBlock, iYBlock );
801 0 : if( poBlock == NULL )
802 0 : continue;
803 0 : if( poBlock->GetDataRef() == NULL )
804 : {
805 0 : poBlock->DropLock();
806 0 : continue;
807 : }
808 :
809 0 : if( (iXBlock + 1) * nBlockXSize > poBand->GetXSize() )
810 0 : iXValid = poBand->GetXSize() - iXBlock * nBlockXSize;
811 : else
812 0 : iXValid = nBlockXSize;
813 :
814 0 : if( (iYBlock + 1) * nBlockYSize > poBand->GetYSize() )
815 0 : iYValid = poBand->GetYSize() - iYBlock * nBlockYSize;
816 : else
817 0 : iYValid = nBlockYSize;
818 :
819 0 : for( iY = 0; iY < iYValid; iY++ )
820 : {
821 0 : for( iX = iRemainder; iX < iXValid; iX += nBlockSampleRate )
822 : {
823 : int iOffset;
824 :
825 0 : iOffset = iX + iY * nBlockXSize;
826 0 : switch( poBlock->GetDataType() )
827 : {
828 : case GDT_Byte:
829 0 : dfValue = ((GByte *) poBlock->GetDataRef())[iOffset];
830 0 : break;
831 : case GDT_UInt16:
832 0 : dfValue = ((GUInt16 *) poBlock->GetDataRef())[iOffset];
833 0 : break;
834 : case GDT_Int16:
835 0 : dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset];
836 0 : break;
837 : case GDT_UInt32:
838 0 : dfValue = ((GUInt32 *) poBlock->GetDataRef())[iOffset];
839 0 : break;
840 : case GDT_Int32:
841 0 : dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset];
842 0 : break;
843 : case GDT_Float32:
844 0 : dfValue = ((float *) poBlock->GetDataRef())[iOffset];
845 0 : break;
846 : case GDT_Float64:
847 0 : dfValue = ((double *) poBlock->GetDataRef())[iOffset];
848 0 : break;
849 : case GDT_CInt16:
850 0 : dfReal = ((GInt16 *) poBlock->GetDataRef())[iOffset*2];
851 0 : dfImag = ((GInt16 *) poBlock->GetDataRef())[iOffset*2+1];
852 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
853 0 : break;
854 : case GDT_CInt32:
855 0 : dfReal = ((GInt32 *) poBlock->GetDataRef())[iOffset*2];
856 0 : dfImag = ((GInt32 *) poBlock->GetDataRef())[iOffset*2+1];
857 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
858 0 : break;
859 : case GDT_CFloat32:
860 0 : dfReal = ((float *) poBlock->GetDataRef())[iOffset*2];
861 0 : dfImag = ((float *) poBlock->GetDataRef())[iOffset*2+1];
862 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
863 0 : break;
864 : case GDT_CFloat64:
865 0 : dfReal = ((double *) poBlock->GetDataRef())[iOffset*2];
866 0 : dfImag = ((double *) poBlock->GetDataRef())[iOffset*2+1];
867 0 : dfValue = sqrt(dfReal*dfReal + dfImag*dfImag);
868 : break;
869 : default:
870 : CPLAssert( FALSE );
871 : }
872 :
873 0 : if( bGotNoDataValue && dfValue == dfNoDataValue )
874 0 : continue;
875 :
876 0 : if( nActualSamples < nSamples )
877 0 : pafSampleBuf[nActualSamples++] = (float) dfValue;
878 : }
879 :
880 0 : iRemainder = iX - iXValid;
881 : }
882 :
883 0 : poBlock->DropLock();
884 : }
885 :
886 0 : return nActualSamples;
887 : }
888 :
889 : /************************************************************************/
890 : /* GDALInitGCPs() */
891 : /************************************************************************/
892 :
893 5538 : void CPL_STDCALL GDALInitGCPs( int nCount, GDAL_GCP * psGCP )
894 :
895 : {
896 5538 : if( nCount > 0 )
897 : {
898 5513 : VALIDATE_POINTER0( psGCP, "GDALInitGCPs" );
899 : }
900 :
901 39425 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
902 : {
903 33887 : memset( psGCP, 0, sizeof(GDAL_GCP) );
904 33887 : psGCP->pszId = CPLStrdup("");
905 33887 : psGCP->pszInfo = CPLStrdup("");
906 33887 : psGCP++;
907 : }
908 : }
909 :
910 : /************************************************************************/
911 : /* GDALDeinitGCPs() */
912 : /************************************************************************/
913 :
914 10740 : void CPL_STDCALL GDALDeinitGCPs( int nCount, GDAL_GCP * psGCP )
915 :
916 : {
917 10740 : if ( nCount > 0 )
918 : {
919 5463 : VALIDATE_POINTER0( psGCP, "GDALDeinitGCPs" );
920 : }
921 :
922 44863 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
923 : {
924 34123 : CPLFree( psGCP->pszId );
925 34123 : CPLFree( psGCP->pszInfo );
926 34123 : psGCP++;
927 : }
928 : }
929 :
930 : /************************************************************************/
931 : /* GDALDuplicateGCPs() */
932 : /************************************************************************/
933 :
934 : GDAL_GCP * CPL_STDCALL
935 69 : GDALDuplicateGCPs( int nCount, const GDAL_GCP *pasGCPList )
936 :
937 : {
938 : GDAL_GCP *pasReturn;
939 :
940 69 : pasReturn = (GDAL_GCP *) CPLMalloc(sizeof(GDAL_GCP) * nCount);
941 69 : GDALInitGCPs( nCount, pasReturn );
942 :
943 267 : for( int iGCP = 0; iGCP < nCount; iGCP++ )
944 : {
945 198 : CPLFree( pasReturn[iGCP].pszId );
946 198 : pasReturn[iGCP].pszId = CPLStrdup( pasGCPList[iGCP].pszId );
947 :
948 198 : CPLFree( pasReturn[iGCP].pszInfo );
949 198 : pasReturn[iGCP].pszInfo = CPLStrdup( pasGCPList[iGCP].pszInfo );
950 :
951 198 : pasReturn[iGCP].dfGCPPixel = pasGCPList[iGCP].dfGCPPixel;
952 198 : pasReturn[iGCP].dfGCPLine = pasGCPList[iGCP].dfGCPLine;
953 198 : pasReturn[iGCP].dfGCPX = pasGCPList[iGCP].dfGCPX;
954 198 : pasReturn[iGCP].dfGCPY = pasGCPList[iGCP].dfGCPY;
955 198 : pasReturn[iGCP].dfGCPZ = pasGCPList[iGCP].dfGCPZ;
956 : }
957 :
958 69 : return pasReturn;
959 : }
960 :
961 : /************************************************************************/
962 : /* GDALLoadOziMapFile() */
963 : /************************************************************************/
964 :
965 : #define MAX_GCP 30
966 :
967 0 : int CPL_STDCALL GDALLoadOziMapFile( const char *pszFilename,
968 : double *padfGeoTransform, char **ppszWKT,
969 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
970 :
971 :
972 : {
973 : char **papszLines;
974 0 : char **papszTok=NULL;
975 0 : int iLine, nLines=0;
976 0 : int nCoordinateCount = 0;
977 : GDAL_GCP asGCPs[MAX_GCP];
978 :
979 0 : VALIDATE_POINTER1( pszFilename, "GDALLoadOziMapFile", FALSE );
980 0 : VALIDATE_POINTER1( padfGeoTransform, "GDALLoadOziMapFile", FALSE );
981 0 : VALIDATE_POINTER1( pnGCPCount, "GDALLoadOziMapFile", FALSE );
982 0 : VALIDATE_POINTER1( ppasGCPs, "GDALLoadOziMapFile", FALSE );
983 :
984 0 : papszLines = CSLLoad2( pszFilename, 1000, 200, NULL );
985 :
986 0 : if ( !papszLines )
987 0 : return FALSE;
988 :
989 0 : nLines = CSLCount( papszLines );
990 :
991 : // Check the OziExplorer Map file signature
992 0 : if ( nLines < 5
993 0 : || !EQUALN(papszLines[0], "OziExplorer Map Data File Version ", 34) )
994 : {
995 : CPLError( CE_Failure, CPLE_AppDefined,
996 : "GDALLoadOziMapFile(): file \"%s\" is not in OziExplorer Map format.",
997 0 : pszFilename );
998 0 : CSLDestroy( papszLines );
999 0 : return FALSE;
1000 : }
1001 :
1002 0 : OGRSpatialReference oSRS, *poLatLong = NULL;
1003 0 : OGRCoordinateTransformation *poTransform = NULL;
1004 0 : const char *pszProj = NULL, *pszProjParms = NULL;
1005 :
1006 0 : for ( iLine = 5; iLine < nLines; iLine++ )
1007 : {
1008 0 : if ( EQUALN(papszLines[iLine], "Map Projection", 14) )
1009 : {
1010 0 : pszProj = papszLines[iLine];
1011 0 : continue;
1012 : }
1013 :
1014 0 : if ( EQUALN(papszLines[iLine], "Projection Setup", 16) )
1015 : {
1016 0 : pszProjParms = papszLines[iLine];
1017 0 : continue;
1018 : }
1019 : }
1020 :
1021 0 : if ( papszLines[4][0] != '\0' && pszProj && pszProjParms )
1022 : {
1023 0 : if (oSRS.importFromOzi( papszLines[4], pszProj, pszProjParms ) ==
1024 : OGRERR_NONE)
1025 : {
1026 0 : if ( ppszWKT != NULL )
1027 0 : oSRS.exportToWkt( ppszWKT );
1028 :
1029 0 : poLatLong = oSRS.CloneGeogCS();
1030 0 : poTransform = OGRCreateCoordinateTransformation( poLatLong, &oSRS );
1031 : }
1032 : }
1033 :
1034 : // Iterate all lines in the TAB-file
1035 0 : for ( iLine = 5; iLine < nLines; iLine++ )
1036 : {
1037 0 : CSLDestroy( papszTok );
1038 0 : papszTok = CSLTokenizeString2( papszLines[iLine], ",",
1039 : CSLT_ALLOWEMPTYTOKENS
1040 : | CSLT_STRIPLEADSPACES
1041 0 : | CSLT_STRIPENDSPACES );
1042 :
1043 0 : if ( CSLCount(papszTok) < 12 )
1044 0 : continue;
1045 :
1046 0 : if ( CSLCount(papszTok) >= 12
1047 0 : && EQUALN(papszTok[0], "Point", 5)
1048 0 : && !EQUAL(papszTok[3], "")
1049 0 : && !EQUAL(papszTok[6], "")
1050 0 : && !EQUAL(papszTok[7], "")
1051 0 : && !EQUAL(papszTok[9], "")
1052 0 : && !EQUAL(papszTok[10], "")
1053 : && nCoordinateCount < MAX_GCP )
1054 : {
1055 : double dfLon, dfLat;
1056 :
1057 0 : GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1058 :
1059 : // Set pixel/line part
1060 0 : asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]);
1061 0 : asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]);
1062 :
1063 : // Set geographical coordinates of the pixels
1064 0 : dfLon = CPLAtofM(papszTok[9]) + CPLAtofM(papszTok[10]) / 60.0;
1065 0 : dfLat = CPLAtofM(papszTok[6]) + CPLAtofM(papszTok[7]) / 60.0;
1066 0 : if (EQUAL(papszTok[11], "W") )
1067 0 : dfLon = -dfLon;
1068 0 : if ( EQUAL(papszTok[8], "S") )
1069 0 : dfLat = -dfLat;
1070 :
1071 0 : if ( poTransform )
1072 0 : poTransform->Transform( 1, &dfLon, &dfLat );
1073 :
1074 0 : asGCPs[nCoordinateCount].dfGCPX = dfLon;
1075 0 : asGCPs[nCoordinateCount].dfGCPY = dfLat;
1076 :
1077 0 : nCoordinateCount++;
1078 : }
1079 : }
1080 :
1081 0 : if ( poTransform )
1082 0 : delete poTransform;
1083 0 : if ( poLatLong )
1084 0 : delete poLatLong;
1085 :
1086 0 : CSLDestroy( papszTok );
1087 0 : CSLDestroy( papszLines );
1088 :
1089 0 : if ( nCoordinateCount == 0 )
1090 : {
1091 : CPLDebug( "GDAL", "GDALLoadOziMapFile(\"%s\") did not get any GCPs.",
1092 0 : pszFilename );
1093 0 : return FALSE;
1094 : }
1095 :
1096 : /* -------------------------------------------------------------------- */
1097 : /* Try to convert the GCPs into a geotransform definition, if */
1098 : /* possible. Otherwise we will need to use them as GCPs. */
1099 : /* -------------------------------------------------------------------- */
1100 0 : if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform,
1101 : FALSE ) )
1102 : {
1103 0 : if ( pnGCPCount && ppasGCPs )
1104 : {
1105 : CPLDebug( "GDAL",
1106 : "GDALLoadOziMapFile(%s) found file, wasn't able to derive a\n"
1107 : "first order geotransform. Using points as GCPs.",
1108 0 : pszFilename );
1109 :
1110 : *ppasGCPs = (GDAL_GCP *)
1111 0 : CPLCalloc( sizeof(GDAL_GCP),nCoordinateCount );
1112 0 : memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1113 0 : *pnGCPCount = nCoordinateCount;
1114 : }
1115 : }
1116 : else
1117 : {
1118 0 : GDALDeinitGCPs( nCoordinateCount, asGCPs );
1119 : }
1120 :
1121 0 : return TRUE;
1122 : }
1123 :
1124 : #undef MAX_GCP
1125 :
1126 : /************************************************************************/
1127 : /* GDALReadOziMapFile() */
1128 : /************************************************************************/
1129 :
1130 23 : int CPL_STDCALL GDALReadOziMapFile( const char * pszBaseFilename,
1131 : double *padfGeoTransform, char **ppszWKT,
1132 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1133 :
1134 :
1135 : {
1136 : const char *pszOzi;
1137 : FILE *fpOzi;
1138 :
1139 : /* -------------------------------------------------------------------- */
1140 : /* Try lower case, then upper case. */
1141 : /* -------------------------------------------------------------------- */
1142 23 : pszOzi = CPLResetExtension( pszBaseFilename, "map" );
1143 :
1144 23 : fpOzi = VSIFOpen( pszOzi, "rt" );
1145 :
1146 : #ifndef WIN32
1147 23 : if ( fpOzi == NULL )
1148 : {
1149 23 : pszOzi = CPLResetExtension( pszBaseFilename, "MAP" );
1150 23 : fpOzi = VSIFOpen( pszOzi, "rt" );
1151 : }
1152 : #endif
1153 :
1154 23 : if ( fpOzi == NULL )
1155 23 : return FALSE;
1156 :
1157 0 : VSIFClose( fpOzi );
1158 :
1159 : /* -------------------------------------------------------------------- */
1160 : /* We found the file, now load and parse it. */
1161 : /* -------------------------------------------------------------------- */
1162 : return GDALLoadOziMapFile( pszOzi, padfGeoTransform, ppszWKT,
1163 0 : pnGCPCount, ppasGCPs );
1164 : }
1165 :
1166 : /************************************************************************/
1167 : /* GDALLoadTabFile() */
1168 : /* */
1169 : /* Helper function for translator implementators wanting */
1170 : /* support for MapInfo .tab-files. */
1171 : /************************************************************************/
1172 :
1173 : #define MAX_GCP 256
1174 :
1175 0 : int CPL_STDCALL GDALLoadTabFile( const char *pszFilename,
1176 : double *padfGeoTransform, char **ppszWKT,
1177 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1178 :
1179 :
1180 : {
1181 : char **papszLines;
1182 0 : char **papszTok=NULL;
1183 0 : int bTypeRasterFound = FALSE;
1184 0 : int bInsideTableDef = FALSE;
1185 0 : int iLine, numLines=0;
1186 0 : int nCoordinateCount = 0;
1187 : GDAL_GCP asGCPs[MAX_GCP];
1188 :
1189 0 : papszLines = CSLLoad2( pszFilename, 1000, 200, NULL );
1190 :
1191 0 : if ( !papszLines )
1192 0 : return FALSE;
1193 :
1194 0 : numLines = CSLCount(papszLines);
1195 :
1196 : // Iterate all lines in the TAB-file
1197 0 : for(iLine=0; iLine<numLines; iLine++)
1198 : {
1199 0 : CSLDestroy(papszTok);
1200 0 : papszTok = CSLTokenizeStringComplex(papszLines[iLine], " \t(),;",
1201 0 : TRUE, FALSE);
1202 :
1203 0 : if (CSLCount(papszTok) < 2)
1204 0 : continue;
1205 :
1206 : // Did we find table definition
1207 0 : if (EQUAL(papszTok[0], "Definition") && EQUAL(papszTok[1], "Table") )
1208 : {
1209 0 : bInsideTableDef = TRUE;
1210 : }
1211 0 : else if (bInsideTableDef && (EQUAL(papszTok[0], "Type")) )
1212 : {
1213 : // Only RASTER-type will be handled
1214 0 : if (EQUAL(papszTok[1], "RASTER"))
1215 : {
1216 0 : bTypeRasterFound = TRUE;
1217 : }
1218 : else
1219 : {
1220 0 : CSLDestroy(papszTok);
1221 0 : CSLDestroy(papszLines);
1222 0 : return FALSE;
1223 : }
1224 : }
1225 0 : else if (bTypeRasterFound && bInsideTableDef
1226 : && CSLCount(papszTok) > 4
1227 0 : && EQUAL(papszTok[4], "Label")
1228 : && nCoordinateCount < MAX_GCP )
1229 : {
1230 0 : GDALInitGCPs( 1, asGCPs + nCoordinateCount );
1231 :
1232 0 : asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]);
1233 0 : asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]);
1234 0 : asGCPs[nCoordinateCount].dfGCPX = CPLAtofM(papszTok[0]);
1235 0 : asGCPs[nCoordinateCount].dfGCPY = CPLAtofM(papszTok[1]);
1236 0 : if( papszTok[5] != NULL )
1237 : {
1238 0 : CPLFree( asGCPs[nCoordinateCount].pszId );
1239 0 : asGCPs[nCoordinateCount].pszId = CPLStrdup(papszTok[5]);
1240 : }
1241 :
1242 0 : nCoordinateCount++;
1243 : }
1244 0 : else if( bTypeRasterFound && bInsideTableDef
1245 0 : && EQUAL(papszTok[0],"CoordSys")
1246 : && ppszWKT != NULL )
1247 : {
1248 0 : OGRSpatialReference oSRS;
1249 :
1250 0 : if( oSRS.importFromMICoordSys( papszLines[iLine] ) == OGRERR_NONE )
1251 0 : oSRS.exportToWkt( ppszWKT );
1252 : }
1253 0 : else if( EQUAL(papszTok[0],"Units")
1254 : && CSLCount(papszTok) > 1
1255 0 : && EQUAL(papszTok[1],"degree") )
1256 : {
1257 : /*
1258 : ** If we have units of "degree", but a projected coordinate
1259 : ** system we need to convert it to geographic. See to01_02.TAB.
1260 : */
1261 0 : if( ppszWKT != NULL && *ppszWKT != NULL
1262 : && EQUALN(*ppszWKT,"PROJCS",6) )
1263 : {
1264 0 : OGRSpatialReference oSRS, oSRSGeogCS;
1265 0 : char *pszSrcWKT = *ppszWKT;
1266 :
1267 0 : oSRS.importFromWkt( &pszSrcWKT );
1268 0 : oSRSGeogCS.CopyGeogCSFrom( &oSRS );
1269 0 : CPLFree( *ppszWKT );
1270 0 : oSRSGeogCS.exportToWkt( ppszWKT );
1271 : }
1272 : }
1273 :
1274 : }
1275 :
1276 0 : CSLDestroy(papszTok);
1277 0 : CSLDestroy(papszLines);
1278 :
1279 0 : if( nCoordinateCount == 0 )
1280 : {
1281 : CPLDebug( "GDAL", "GDALLoadTabFile(%s) did not get any GCPs.",
1282 0 : pszFilename );
1283 0 : return FALSE;
1284 : }
1285 :
1286 : /* -------------------------------------------------------------------- */
1287 : /* Try to convert the GCPs into a geotransform definition, if */
1288 : /* possible. Otherwise we will need to use them as GCPs. */
1289 : /* -------------------------------------------------------------------- */
1290 0 : if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform,
1291 : FALSE ) )
1292 : {
1293 0 : if (pnGCPCount && ppasGCPs)
1294 : {
1295 : CPLDebug( "GDAL",
1296 : "GDALLoadTabFile(%s) found file, wasn't able to derive a\n"
1297 : "first order geotransform. Using points as GCPs.",
1298 0 : pszFilename );
1299 :
1300 : *ppasGCPs = (GDAL_GCP *)
1301 0 : CPLCalloc( sizeof(GDAL_GCP),nCoordinateCount );
1302 0 : memcpy( *ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount );
1303 0 : *pnGCPCount = nCoordinateCount;
1304 : }
1305 : }
1306 : else
1307 : {
1308 0 : GDALDeinitGCPs( nCoordinateCount, asGCPs );
1309 : }
1310 :
1311 0 : return TRUE;
1312 : }
1313 :
1314 : #undef MAX_GCP
1315 :
1316 : /************************************************************************/
1317 : /* GDALReadTabFile() */
1318 : /* */
1319 : /* Helper function for translator implementators wanting */
1320 : /* support for MapInfo .tab-files. */
1321 : /************************************************************************/
1322 :
1323 614 : int CPL_STDCALL GDALReadTabFile( const char * pszBaseFilename,
1324 : double *padfGeoTransform, char **ppszWKT,
1325 : int *pnGCPCount, GDAL_GCP **ppasGCPs )
1326 :
1327 :
1328 : {
1329 : const char *pszTAB;
1330 : FILE *fpTAB;
1331 :
1332 : /* -------------------------------------------------------------------- */
1333 : /* Try lower case, then upper case. */
1334 : /* -------------------------------------------------------------------- */
1335 614 : pszTAB = CPLResetExtension( pszBaseFilename, "tab" );
1336 :
1337 614 : fpTAB = VSIFOpen( pszTAB, "rt" );
1338 :
1339 : #ifndef WIN32
1340 614 : if( fpTAB == NULL )
1341 : {
1342 614 : pszTAB = CPLResetExtension( pszBaseFilename, "TAB" );
1343 614 : fpTAB = VSIFOpen( pszTAB, "rt" );
1344 : }
1345 : #endif
1346 :
1347 614 : if( fpTAB == NULL )
1348 614 : return FALSE;
1349 :
1350 0 : VSIFClose( fpTAB );
1351 :
1352 : /* -------------------------------------------------------------------- */
1353 : /* We found the file, now load and parse it. */
1354 : /* -------------------------------------------------------------------- */
1355 : return GDALLoadTabFile( pszTAB, padfGeoTransform, ppszWKT,
1356 0 : pnGCPCount, ppasGCPs );
1357 : }
1358 :
1359 : /************************************************************************/
1360 : /* GDALLoadWorldFile() */
1361 : /************************************************************************/
1362 :
1363 : /**
1364 : * \brief Read ESRI world file.
1365 : *
1366 : * This function reads an ESRI style world file, and formats a geotransform
1367 : * from its contents.
1368 : *
1369 : * The world file contains an affine transformation with the parameters
1370 : * in a different order than in a geotransform array.
1371 : *
1372 : * <ul>
1373 : * <li> geotransform[1] : width of pixel
1374 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1375 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1376 : * <li> geotransform[5] : height of pixel (but negative)
1377 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1378 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1379 : * </ul>
1380 : *
1381 : * @param pszFilename the world file name.
1382 : * @param padfGeoTransform the six double array into which the
1383 : * geotransformation should be placed.
1384 : *
1385 : * @return TRUE on success or FALSE on failure.
1386 : */
1387 :
1388 : int CPL_STDCALL
1389 13 : GDALLoadWorldFile( const char *pszFilename, double *padfGeoTransform )
1390 :
1391 : {
1392 : char **papszLines;
1393 :
1394 13 : VALIDATE_POINTER1( pszFilename, "GDALLoadWorldFile", FALSE );
1395 13 : VALIDATE_POINTER1( padfGeoTransform, "GDALLoadWorldFile", FALSE );
1396 :
1397 13 : papszLines = CSLLoad2( pszFilename, 100, 100, NULL );
1398 :
1399 13 : if ( !papszLines )
1400 0 : return FALSE;
1401 :
1402 : double world[6];
1403 : // reads the first 6 non-empty lines
1404 13 : int nLines = 0;
1405 13 : int nLinesCount = CSLCount(papszLines);
1406 13 : for( int i = 0; i < nLinesCount && nLines < 6; ++i )
1407 : {
1408 78 : CPLString line(papszLines[i]);
1409 78 : if( line.Trim().empty() )
1410 0 : continue;
1411 :
1412 78 : world[nLines] = CPLAtofM(line);
1413 78 : ++nLines;
1414 : }
1415 :
1416 39 : if( nLines == 6
1417 13 : && (world[0] != 0.0 || world[2] != 0.0)
1418 13 : && (world[3] != 0.0 || world[1] != 0.0) )
1419 : {
1420 13 : padfGeoTransform[0] = world[4];
1421 13 : padfGeoTransform[1] = world[0];
1422 13 : padfGeoTransform[2] = world[2];
1423 13 : padfGeoTransform[3] = world[5];
1424 13 : padfGeoTransform[4] = world[1];
1425 13 : padfGeoTransform[5] = world[3];
1426 :
1427 : // correct for center of pixel vs. top left of pixel
1428 13 : padfGeoTransform[0] -= 0.5 * padfGeoTransform[1];
1429 13 : padfGeoTransform[0] -= 0.5 * padfGeoTransform[2];
1430 13 : padfGeoTransform[3] -= 0.5 * padfGeoTransform[4];
1431 13 : padfGeoTransform[3] -= 0.5 * padfGeoTransform[5];
1432 :
1433 13 : CSLDestroy(papszLines);
1434 :
1435 13 : return TRUE;
1436 : }
1437 : else
1438 : {
1439 : CPLDebug( "GDAL",
1440 : "GDALLoadWorldFile(%s) found file, but it was corrupt.",
1441 0 : pszFilename );
1442 0 : CSLDestroy(papszLines);
1443 0 : return FALSE;
1444 : }
1445 : }
1446 :
1447 : /************************************************************************/
1448 : /* GDALReadWorldFile() */
1449 : /************************************************************************/
1450 :
1451 : /**
1452 : * \brief Read ESRI world file.
1453 : *
1454 : * This function reads an ESRI style world file, and formats a geotransform
1455 : * from its contents. It does the same as GDALLoadWorldFile() function, but
1456 : * it will form the filename for the worldfile from the filename of the raster
1457 : * file referred and the suggested extension. If no extension is provided,
1458 : * the code will internally try the unix style and windows style world file
1459 : * extensions (eg. for .tif these would be .tfw and .tifw).
1460 : *
1461 : * The world file contains an affine transformation with the parameters
1462 : * in a different order than in a geotransform array.
1463 : *
1464 : * <ul>
1465 : * <li> geotransform[1] : width of pixel
1466 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1467 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1468 : * <li> geotransform[5] : height of pixel (but negative)
1469 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1470 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1471 : * </ul>
1472 : *
1473 : * @param pszBaseFilename the target raster file.
1474 : * @param pszExtension the extension to use (ie. ".wld") or NULL to derive it
1475 : * from the pszBaseFilename
1476 : * @param padfGeoTransform the six double array into which the
1477 : * geotransformation should be placed.
1478 : *
1479 : * @return TRUE on success or FALSE on failure.
1480 : */
1481 :
1482 : int CPL_STDCALL
1483 3473 : GDALReadWorldFile( const char *pszBaseFilename, const char *pszExtension,
1484 : double *padfGeoTransform )
1485 :
1486 : {
1487 : const char *pszTFW;
1488 : char szExtUpper[32], szExtLower[32];
1489 : int i;
1490 :
1491 3473 : VALIDATE_POINTER1( pszBaseFilename, "GDALReadWorldFile", FALSE );
1492 3473 : VALIDATE_POINTER1( padfGeoTransform, "GDALReadWorldFile", FALSE );
1493 :
1494 : /* -------------------------------------------------------------------- */
1495 : /* If we aren't given an extension, try both the unix and */
1496 : /* windows style extensions. */
1497 : /* -------------------------------------------------------------------- */
1498 3473 : if( pszExtension == NULL )
1499 : {
1500 : char szDerivedExtension[100];
1501 815 : std::string oBaseExt = CPLGetExtension( pszBaseFilename );
1502 :
1503 1630 : if( oBaseExt.length() < 2 )
1504 49 : return FALSE;
1505 :
1506 : // windows version - first + last + 'w'
1507 766 : szDerivedExtension[0] = oBaseExt[0];
1508 766 : szDerivedExtension[1] = oBaseExt[oBaseExt.length()-1];
1509 766 : szDerivedExtension[2] = 'w';
1510 766 : szDerivedExtension[3] = '\0';
1511 :
1512 766 : if( GDALReadWorldFile( pszBaseFilename, szDerivedExtension,
1513 : padfGeoTransform ) )
1514 5 : return TRUE;
1515 :
1516 : // unix version - extension + 'w'
1517 761 : if( oBaseExt.length() > sizeof(szDerivedExtension)-2 )
1518 0 : return FALSE;
1519 :
1520 761 : strcpy( szDerivedExtension, oBaseExt.c_str() );
1521 761 : strcat( szDerivedExtension, "w" );
1522 : return GDALReadWorldFile( pszBaseFilename, szDerivedExtension,
1523 761 : padfGeoTransform );
1524 : }
1525 :
1526 : /* -------------------------------------------------------------------- */
1527 : /* Skip the leading period in the extension if there is one. */
1528 : /* -------------------------------------------------------------------- */
1529 2658 : if( *pszExtension == '.' )
1530 330 : pszExtension++;
1531 :
1532 : /* -------------------------------------------------------------------- */
1533 : /* Generate upper and lower case versions of the extension. */
1534 : /* -------------------------------------------------------------------- */
1535 2658 : CPLStrlcpy( szExtUpper, pszExtension, sizeof(szExtUpper) );
1536 2658 : CPLStrlcpy( szExtLower, pszExtension, sizeof(szExtLower) );
1537 :
1538 11441 : for( i = 0; szExtUpper[i] != '\0'; i++ )
1539 : {
1540 8783 : szExtUpper[i] = (char) toupper(szExtUpper[i]);
1541 8783 : szExtLower[i] = (char) tolower(szExtLower[i]);
1542 : }
1543 :
1544 : /* -------------------------------------------------------------------- */
1545 : /* Try lower case, then upper case. */
1546 : /* -------------------------------------------------------------------- */
1547 : VSIStatBufL sStatBuf;
1548 : int bGotTFW;
1549 :
1550 2658 : pszTFW = CPLResetExtension( pszBaseFilename, szExtLower );
1551 :
1552 2658 : bGotTFW = VSIStatL( pszTFW, &sStatBuf ) == 0;
1553 :
1554 : #ifndef WIN32
1555 2658 : if( !bGotTFW )
1556 : {
1557 2645 : pszTFW = CPLResetExtension( pszBaseFilename, szExtUpper );
1558 2645 : bGotTFW = VSIStatL( pszTFW, &sStatBuf ) == 0;
1559 : }
1560 : #endif
1561 :
1562 2658 : if( !bGotTFW )
1563 2645 : return FALSE;
1564 :
1565 : /* -------------------------------------------------------------------- */
1566 : /* We found the file, now load and parse it. */
1567 : /* -------------------------------------------------------------------- */
1568 13 : return GDALLoadWorldFile( pszTFW, padfGeoTransform );
1569 : }
1570 :
1571 : /************************************************************************/
1572 : /* GDALWriteWorldFile() */
1573 : /* */
1574 : /* Helper function for translator implementators wanting */
1575 : /* support for ESRI world files. */
1576 : /************************************************************************/
1577 :
1578 : /**
1579 : * \brief Write ESRI world file.
1580 : *
1581 : * This function writes an ESRI style world file from the passed geotransform.
1582 : *
1583 : * The world file contains an affine transformation with the parameters
1584 : * in a different order than in a geotransform array.
1585 : *
1586 : * <ul>
1587 : * <li> geotransform[1] : width of pixel
1588 : * <li> geotransform[4] : rotational coefficient, zero for north up images.
1589 : * <li> geotransform[2] : rotational coefficient, zero for north up images.
1590 : * <li> geotransform[5] : height of pixel (but negative)
1591 : * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x offset to center of top left pixel.
1592 : * <li> geotransform[3] + 0.5 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left pixel.
1593 : * </ul>
1594 : *
1595 : * @param pszBaseFilename the target raster file.
1596 : * @param pszExtension the extension to use (ie. ".wld"). Must not be NULL
1597 : * @param padfGeoTransform the six double array from which the
1598 : * geotransformation should be read.
1599 : *
1600 : * @return TRUE on success or FALSE on failure.
1601 : */
1602 :
1603 : int CPL_STDCALL
1604 6 : GDALWriteWorldFile( const char * pszBaseFilename, const char *pszExtension,
1605 : double *padfGeoTransform )
1606 :
1607 : {
1608 6 : VALIDATE_POINTER1( pszBaseFilename, "GDALWriteWorldFile", FALSE );
1609 6 : VALIDATE_POINTER1( pszExtension, "GDALWriteWorldFile", FALSE );
1610 6 : VALIDATE_POINTER1( padfGeoTransform, "GDALWriteWorldFile", FALSE );
1611 :
1612 : /* -------------------------------------------------------------------- */
1613 : /* Prepare the text to write to the file. */
1614 : /* -------------------------------------------------------------------- */
1615 6 : CPLString osTFWText;
1616 :
1617 : osTFWText.Printf( "%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n%.10f\n",
1618 : padfGeoTransform[1],
1619 : padfGeoTransform[4],
1620 : padfGeoTransform[2],
1621 : padfGeoTransform[5],
1622 6 : padfGeoTransform[0]
1623 6 : + 0.5 * padfGeoTransform[1]
1624 6 : + 0.5 * padfGeoTransform[2],
1625 6 : padfGeoTransform[3]
1626 6 : + 0.5 * padfGeoTransform[4]
1627 18 : + 0.5 * padfGeoTransform[5] );
1628 :
1629 : /* -------------------------------------------------------------------- */
1630 : /* Update extention, and write to disk. */
1631 : /* -------------------------------------------------------------------- */
1632 : const char *pszTFW;
1633 : FILE *fpTFW;
1634 :
1635 6 : pszTFW = CPLResetExtension( pszBaseFilename, pszExtension );
1636 6 : fpTFW = VSIFOpenL( pszTFW, "wt" );
1637 6 : if( fpTFW == NULL )
1638 0 : return FALSE;
1639 :
1640 6 : VSIFWriteL( (void *) osTFWText.c_str(), 1, osTFWText.size(), fpTFW );
1641 6 : VSIFCloseL( fpTFW );
1642 :
1643 6 : return TRUE;
1644 : }
1645 :
1646 : /************************************************************************/
1647 : /* GDALVersionInfo() */
1648 : /************************************************************************/
1649 :
1650 : /**
1651 : * \brief Get runtime version information.
1652 : *
1653 : * Available pszRequest values:
1654 : * <ul>
1655 : * <li> "VERSION_NUM": Returns GDAL_VERSION_NUM formatted as a string. ie. "1170"
1656 : * <li> "RELEASE_DATE": Returns GDAL_RELEASE_DATE formatted as a string.
1657 : * ie. "20020416".
1658 : * <li> "RELEASE_NAME": Returns the GDAL_RELEASE_NAME. ie. "1.1.7"
1659 : * <li> "--version": Returns one line version message suitable for use in
1660 : * response to --version requests. ie. "GDAL 1.1.7, released 2002/04/16"
1661 : * <li> "LICENCE": Returns the content of the LICENSE.TXT file from the GDAL_DATA directory.
1662 : * Before GDAL 1.7.0, the returned string was leaking memory but this is now resolved.
1663 : * So the result should not been freed by the caller.
1664 : * </ul>
1665 : *
1666 : * @param pszRequest the type of version info desired, as listed above.
1667 : *
1668 : * @return an internal string containing the requested information.
1669 : */
1670 :
1671 312 : const char * CPL_STDCALL GDALVersionInfo( const char *pszRequest )
1672 :
1673 : {
1674 : /* -------------------------------------------------------------------- */
1675 : /* LICENSE is a special case. We try to find and read the */
1676 : /* LICENSE.TXT file from the GDAL_DATA directory and return it */
1677 : /* -------------------------------------------------------------------- */
1678 312 : if( pszRequest != NULL && EQUAL(pszRequest,"LICENSE") )
1679 : {
1680 0 : char* pszResultLicence = (char*) CPLGetTLS( CTLS_VERSIONINFO_LICENCE );
1681 0 : if( pszResultLicence != NULL )
1682 : {
1683 0 : return pszResultLicence;
1684 : }
1685 :
1686 0 : const char *pszFilename = CPLFindFile( "etc", "LICENSE.TXT" );
1687 0 : FILE *fp = NULL;
1688 : int nLength;
1689 :
1690 0 : if( pszFilename != NULL )
1691 0 : fp = VSIFOpenL( pszFilename, "r" );
1692 :
1693 0 : if( fp != NULL )
1694 : {
1695 0 : VSIFSeekL( fp, 0, SEEK_END );
1696 0 : nLength = (int) VSIFTellL( fp ) + 1;
1697 0 : VSIFSeekL( fp, SEEK_SET, 0 );
1698 :
1699 0 : pszResultLicence = (char *) VSICalloc(1,nLength);
1700 0 : if (pszResultLicence)
1701 0 : VSIFReadL( pszResultLicence, 1, nLength-1, fp );
1702 :
1703 0 : VSIFCloseL( fp );
1704 : }
1705 :
1706 0 : if (!pszResultLicence)
1707 : {
1708 : pszResultLicence = CPLStrdup(
1709 : "GDAL/OGR is released under the MIT/X license.\n"
1710 : "The LICENSE.TXT distributed with GDAL/OGR should\n"
1711 0 : "contain additional details.\n" );
1712 : }
1713 :
1714 0 : CPLSetTLS( CTLS_VERSIONINFO_LICENCE, pszResultLicence, TRUE );
1715 0 : return pszResultLicence;
1716 : }
1717 :
1718 312 : char* pszResultSmall = (char*) CPLGetTLS( CTLS_VERSIONINFO );
1719 312 : if( pszResultSmall == NULL )
1720 : {
1721 296 : pszResultSmall = (char*) CPLCalloc(128, 1);
1722 296 : CPLSetTLS( CTLS_VERSIONINFO, pszResultSmall, TRUE );
1723 : }
1724 :
1725 608 : if( pszRequest == NULL || EQUAL(pszRequest,"VERSION_NUM") )
1726 296 : sprintf(pszResultSmall, "%d", GDAL_VERSION_NUM );
1727 16 : else if( EQUAL(pszRequest,"RELEASE_DATE") )
1728 0 : sprintf(pszResultSmall, "%d", GDAL_RELEASE_DATE );
1729 16 : else if( EQUAL(pszRequest,"RELEASE_NAME") )
1730 16 : sprintf(pszResultSmall, GDAL_RELEASE_NAME );
1731 : else // --version
1732 : sprintf(pszResultSmall, "GDAL %s, released %d/%02d/%02d",
1733 : GDAL_RELEASE_NAME,
1734 : GDAL_RELEASE_DATE / 10000,
1735 : (GDAL_RELEASE_DATE % 10000) / 100,
1736 0 : GDAL_RELEASE_DATE % 100 );
1737 :
1738 312 : return pszResultSmall;
1739 : }
1740 :
1741 : /************************************************************************/
1742 : /* GDALCheckVersion() */
1743 : /************************************************************************/
1744 :
1745 : /** Return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor.
1746 :
1747 : The purpose of this method is to ensure that calling code will run with the GDAL
1748 : version it is compiled for. It is primarly intented for external plugins.
1749 :
1750 : @param nVersionMajor Major version to be tested against
1751 : @param nVersionMinor Minor version to be tested against
1752 : @param pszCallingComponentName If not NULL, in case of version mismatch, the method
1753 : will issue a failure mentionning the name of
1754 : the calling component.
1755 :
1756 : @return TRUE if GDAL library version at runtime matches nVersionMajor.nVersionMinor, FALSE otherwise.
1757 : */
1758 4711 : int CPL_STDCALL GDALCheckVersion( int nVersionMajor, int nVersionMinor,
1759 : const char* pszCallingComponentName)
1760 : {
1761 4711 : if (nVersionMajor == GDAL_VERSION_MAJOR &&
1762 : nVersionMinor == GDAL_VERSION_MINOR)
1763 4711 : return TRUE;
1764 :
1765 0 : if (pszCallingComponentName)
1766 : {
1767 : CPLError( CE_Failure, CPLE_AppDefined,
1768 : "%s was compiled against GDAL %d.%d but current library version is %d.%d\n",
1769 : pszCallingComponentName, nVersionMajor, nVersionMinor,
1770 0 : GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
1771 : }
1772 0 : return FALSE;
1773 : }
1774 :
1775 : /************************************************************************/
1776 : /* GDALDecToDMS() */
1777 : /* */
1778 : /* Translate a decimal degrees value to a DMS string with */
1779 : /* hemisphere. */
1780 : /************************************************************************/
1781 :
1782 70 : const char * CPL_STDCALL GDALDecToDMS( double dfAngle, const char * pszAxis,
1783 : int nPrecision )
1784 :
1785 : {
1786 70 : return CPLDecToDMS( dfAngle, pszAxis, nPrecision );
1787 : }
1788 :
1789 : /************************************************************************/
1790 : /* GDALPackedDMSToDec() */
1791 : /************************************************************************/
1792 :
1793 : /**
1794 : * \brief Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
1795 : *
1796 : * See CPLPackedDMSToDec().
1797 : */
1798 :
1799 4 : double CPL_STDCALL GDALPackedDMSToDec( double dfPacked )
1800 :
1801 : {
1802 4 : return CPLPackedDMSToDec( dfPacked );
1803 : }
1804 :
1805 : /************************************************************************/
1806 : /* GDALDecToPackedDMS() */
1807 : /************************************************************************/
1808 :
1809 : /**
1810 : * \brief Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
1811 : *
1812 : * See CPLDecToPackedDMS().
1813 : */
1814 :
1815 4 : double CPL_STDCALL GDALDecToPackedDMS( double dfDec )
1816 :
1817 : {
1818 4 : return CPLDecToPackedDMS( dfDec );
1819 : }
1820 :
1821 : /************************************************************************/
1822 : /* GDALGCPsToGeoTransform() */
1823 : /************************************************************************/
1824 :
1825 : /**
1826 : * \brief Generate Geotransform from GCPs.
1827 : *
1828 : * Given a set of GCPs perform first order fit as a geotransform.
1829 : *
1830 : * Due to imprecision in the calculations the fit algorithm will often
1831 : * return non-zero rotational coefficients even if given perfectly non-rotated
1832 : * inputs. A special case has been implemented for corner corner coordinates
1833 : * given in TL, TR, BR, BL order. So when using this to get a geotransform
1834 : * from 4 corner coordinates, pass them in this order.
1835 : *
1836 : * @param nGCPCount the number of GCPs being passed in.
1837 : * @param pasGCPs the list of GCP structures.
1838 : * @param padfGeoTransform the six double array in which the affine
1839 : * geotransformation will be returned.
1840 : * @param bApproxOK If FALSE the function will fail if the geotransform is not
1841 : * essentially an exact fit (within 0.25 pixel) for all GCPs.
1842 : *
1843 : * @return TRUE on success or FALSE if there aren't enough points to prepare a
1844 : * geotransform, the pointers are ill-determined or if bApproxOK is FALSE
1845 : * and the fit is poor.
1846 : */
1847 :
1848 : int CPL_STDCALL
1849 240 : GDALGCPsToGeoTransform( int nGCPCount, const GDAL_GCP *pasGCPs,
1850 : double *padfGeoTransform, int bApproxOK )
1851 :
1852 : {
1853 : int i;
1854 :
1855 : /* -------------------------------------------------------------------- */
1856 : /* Recognise a few special cases. */
1857 : /* -------------------------------------------------------------------- */
1858 240 : if( nGCPCount < 2 )
1859 7 : return FALSE;
1860 :
1861 233 : if( nGCPCount == 2 )
1862 : {
1863 0 : if( pasGCPs[1].dfGCPPixel == pasGCPs[0].dfGCPPixel
1864 0 : || pasGCPs[1].dfGCPLine == pasGCPs[0].dfGCPLine )
1865 0 : return FALSE;
1866 :
1867 0 : padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
1868 0 : / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
1869 0 : padfGeoTransform[2] = 0.0;
1870 :
1871 0 : padfGeoTransform[4] = 0.0;
1872 0 : padfGeoTransform[5] = (pasGCPs[1].dfGCPY - pasGCPs[0].dfGCPY)
1873 0 : / (pasGCPs[1].dfGCPLine - pasGCPs[0].dfGCPLine);
1874 :
1875 : padfGeoTransform[0] = pasGCPs[0].dfGCPX
1876 0 : - pasGCPs[0].dfGCPPixel * padfGeoTransform[1]
1877 0 : - pasGCPs[0].dfGCPLine * padfGeoTransform[2];
1878 :
1879 0 : padfGeoTransform[3] = pasGCPs[0].dfGCPY
1880 0 : - pasGCPs[0].dfGCPPixel * padfGeoTransform[4]
1881 0 : - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
1882 :
1883 0 : return TRUE;
1884 : }
1885 :
1886 : /* -------------------------------------------------------------------- */
1887 : /* Special case of 4 corner coordinates of a non-rotated */
1888 : /* image. The points must be in TL-TR-BR-BL order for now. */
1889 : /* This case helps avoid some imprecision in the general */
1890 : /* calcuations. */
1891 : /* -------------------------------------------------------------------- */
1892 3783 : if( nGCPCount == 4
1893 231 : && pasGCPs[0].dfGCPLine == pasGCPs[1].dfGCPLine
1894 462 : && pasGCPs[2].dfGCPLine == pasGCPs[3].dfGCPLine
1895 231 : && pasGCPs[0].dfGCPPixel == pasGCPs[3].dfGCPPixel
1896 462 : && pasGCPs[1].dfGCPPixel == pasGCPs[2].dfGCPPixel
1897 231 : && pasGCPs[0].dfGCPLine != pasGCPs[2].dfGCPLine
1898 231 : && pasGCPs[0].dfGCPPixel != pasGCPs[1].dfGCPPixel
1899 231 : && pasGCPs[0].dfGCPY == pasGCPs[1].dfGCPY
1900 442 : && pasGCPs[2].dfGCPY == pasGCPs[3].dfGCPY
1901 221 : && pasGCPs[0].dfGCPX == pasGCPs[3].dfGCPX
1902 442 : && pasGCPs[1].dfGCPX == pasGCPs[2].dfGCPX
1903 221 : && pasGCPs[0].dfGCPY != pasGCPs[2].dfGCPY
1904 145 : && pasGCPs[0].dfGCPX != pasGCPs[1].dfGCPX )
1905 : {
1906 145 : padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX)
1907 145 : / (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
1908 145 : padfGeoTransform[2] = 0.0;
1909 145 : padfGeoTransform[4] = 0.0;
1910 290 : padfGeoTransform[5] = (pasGCPs[2].dfGCPY - pasGCPs[1].dfGCPY)
1911 290 : / (pasGCPs[2].dfGCPLine - pasGCPs[1].dfGCPLine);
1912 :
1913 : padfGeoTransform[0] =
1914 145 : pasGCPs[0].dfGCPX - pasGCPs[0].dfGCPPixel * padfGeoTransform[1];
1915 145 : padfGeoTransform[3] =
1916 145 : pasGCPs[0].dfGCPY - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
1917 145 : return TRUE;
1918 : }
1919 :
1920 : /* -------------------------------------------------------------------- */
1921 : /* In the general case, do a least squares error approximation by */
1922 : /* solving the equation Sum[(A - B*x + C*y - Lon)^2] = minimum */
1923 : /* -------------------------------------------------------------------- */
1924 :
1925 88 : double sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_xx = 0.0, sum_yy = 0.0;
1926 88 : double sum_Lon = 0.0, sum_Lonx = 0.0, sum_Lony = 0.0;
1927 88 : double sum_Lat = 0.0, sum_Latx = 0.0, sum_Laty = 0.0;
1928 : double divisor;
1929 :
1930 442 : for (i = 0; i < nGCPCount; ++i) {
1931 354 : sum_x += pasGCPs[i].dfGCPPixel;
1932 354 : sum_y += pasGCPs[i].dfGCPLine;
1933 354 : sum_xy += pasGCPs[i].dfGCPPixel * pasGCPs[i].dfGCPLine;
1934 354 : sum_xx += pasGCPs[i].dfGCPPixel * pasGCPs[i].dfGCPPixel;
1935 354 : sum_yy += pasGCPs[i].dfGCPLine * pasGCPs[i].dfGCPLine;
1936 354 : sum_Lon += pasGCPs[i].dfGCPX;
1937 354 : sum_Lonx += pasGCPs[i].dfGCPX * pasGCPs[i].dfGCPPixel;
1938 354 : sum_Lony += pasGCPs[i].dfGCPX * pasGCPs[i].dfGCPLine;
1939 354 : sum_Lat += pasGCPs[i].dfGCPY;
1940 354 : sum_Latx += pasGCPs[i].dfGCPY * pasGCPs[i].dfGCPPixel;
1941 354 : sum_Laty += pasGCPs[i].dfGCPY * pasGCPs[i].dfGCPLine;
1942 : }
1943 :
1944 : divisor = nGCPCount * (sum_xx * sum_yy - sum_xy * sum_xy)
1945 : + 2 * sum_x * sum_y * sum_xy - sum_y * sum_y * sum_xx
1946 88 : - sum_x * sum_x * sum_yy;
1947 :
1948 : /* -------------------------------------------------------------------- */
1949 : /* If the divisor is zero, there is no valid solution. */
1950 : /* -------------------------------------------------------------------- */
1951 88 : if (divisor == 0.0)
1952 0 : return FALSE;
1953 :
1954 : /* -------------------------------------------------------------------- */
1955 : /* Compute top/left origin. */
1956 : /* -------------------------------------------------------------------- */
1957 :
1958 : padfGeoTransform[0] = (sum_Lon * (sum_xx * sum_yy - sum_xy * sum_xy)
1959 : + sum_Lonx * (sum_y * sum_xy - sum_x * sum_yy)
1960 : + sum_Lony * (sum_x * sum_xy - sum_y * sum_xx))
1961 88 : / divisor;
1962 :
1963 88 : padfGeoTransform[3] = (sum_Lat * (sum_xx * sum_yy - sum_xy * sum_xy)
1964 : + sum_Latx * (sum_y * sum_xy - sum_x * sum_yy)
1965 : + sum_Laty * (sum_x * sum_xy - sum_y * sum_xx))
1966 88 : / divisor;
1967 :
1968 : /* -------------------------------------------------------------------- */
1969 : /* Compute X related coefficients. */
1970 : /* -------------------------------------------------------------------- */
1971 88 : padfGeoTransform[1] = (sum_Lon * (sum_y * sum_xy - sum_x * sum_yy)
1972 : + sum_Lonx * (nGCPCount * sum_yy - sum_y * sum_y)
1973 : + sum_Lony * (sum_x * sum_y - sum_xy * nGCPCount))
1974 88 : / divisor;
1975 :
1976 88 : padfGeoTransform[2] = (sum_Lon * (sum_x * sum_xy - sum_y * sum_xx)
1977 : + sum_Lonx * (sum_x * sum_y - nGCPCount * sum_xy)
1978 : + sum_Lony * (nGCPCount * sum_xx - sum_x * sum_x))
1979 88 : / divisor;
1980 :
1981 : /* -------------------------------------------------------------------- */
1982 : /* Compute Y related coefficients. */
1983 : /* -------------------------------------------------------------------- */
1984 88 : padfGeoTransform[4] = (sum_Lat * (sum_y * sum_xy - sum_x * sum_yy)
1985 : + sum_Latx * (nGCPCount * sum_yy - sum_y * sum_y)
1986 : + sum_Laty * (sum_x * sum_y - sum_xy * nGCPCount))
1987 88 : / divisor;
1988 :
1989 88 : padfGeoTransform[5] = (sum_Lat * (sum_x * sum_xy - sum_y * sum_xx)
1990 : + sum_Latx * (sum_x * sum_y - nGCPCount * sum_xy)
1991 : + sum_Laty * (nGCPCount * sum_xx - sum_x * sum_x))
1992 88 : / divisor;
1993 :
1994 : /* -------------------------------------------------------------------- */
1995 : /* Now check if any of the input points fit this poorly. */
1996 : /* -------------------------------------------------------------------- */
1997 88 : if( !bApproxOK )
1998 : {
1999 8 : double dfPixelSize = ABS(padfGeoTransform[1])
2000 8 : + ABS(padfGeoTransform[2])
2001 8 : + ABS(padfGeoTransform[4])
2002 24 : + ABS(padfGeoTransform[5]);
2003 :
2004 22 : for( i = 0; i < nGCPCount; i++ )
2005 : {
2006 : double dfErrorX, dfErrorY;
2007 :
2008 : dfErrorX =
2009 36 : (pasGCPs[i].dfGCPPixel * padfGeoTransform[1]
2010 36 : + pasGCPs[i].dfGCPLine * padfGeoTransform[2]
2011 18 : + padfGeoTransform[0])
2012 90 : - pasGCPs[i].dfGCPX;
2013 : dfErrorY =
2014 36 : (pasGCPs[i].dfGCPPixel * padfGeoTransform[4]
2015 36 : + pasGCPs[i].dfGCPLine * padfGeoTransform[5]
2016 18 : + padfGeoTransform[3])
2017 90 : - pasGCPs[i].dfGCPY;
2018 :
2019 18 : if( ABS(dfErrorX) > 0.25 * dfPixelSize
2020 : || ABS(dfErrorY) > 0.25 * dfPixelSize )
2021 0 : return FALSE;
2022 : }
2023 : }
2024 :
2025 88 : return TRUE;
2026 : }
2027 :
2028 : /************************************************************************/
2029 : /* GDALGeneralCmdLineProcessor() */
2030 : /************************************************************************/
2031 :
2032 : /**
2033 : * \brief General utility option processing.
2034 : *
2035 : * This function is intended to provide a variety of generic commandline
2036 : * options for all GDAL commandline utilities. It takes care of the following
2037 : * commandline options:
2038 : *
2039 : * --version: report version of GDAL in use.
2040 : * --license: report GDAL license info.
2041 : * --formats: report all format drivers configured.
2042 : * --format [format]: report details of one format driver.
2043 : * --optfile filename: expand an option file into the argument list.
2044 : * --config key value: set system configuration option.
2045 : * --debug [on/off/value]: set debug level.
2046 : * --mempreload dir: preload directory contents into /vsimem
2047 : * --help-general: report detailed help on general options.
2048 : *
2049 : * The argument array is replaced "in place" and should be freed with
2050 : * CSLDestroy() when no longer needed. The typical usage looks something
2051 : * like the following. Note that the formats should be registered so that
2052 : * the --formats and --format options will work properly.
2053 : *
2054 : * int main( int argc, char ** argv )
2055 : * {
2056 : * GDALAllRegister();
2057 : *
2058 : * argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
2059 : * if( argc < 1 )
2060 : * exit( -argc );
2061 : *
2062 : * @param nArgc number of values in the argument list.
2063 : * @param Pointer to the argument list array (will be updated in place).
2064 : *
2065 : * @return updated nArgc argument count. Return of 0 requests terminate
2066 : * without error, return of -1 requests exit with error code.
2067 : */
2068 :
2069 : int CPL_STDCALL
2070 338 : GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
2071 :
2072 : {
2073 338 : char **papszReturn = NULL;
2074 : int iArg;
2075 338 : char **papszArgv = *ppapszArgv;
2076 :
2077 : (void) nOptions;
2078 :
2079 : /* -------------------------------------------------------------------- */
2080 : /* Preserve the program name. */
2081 : /* -------------------------------------------------------------------- */
2082 338 : papszReturn = CSLAddString( papszReturn, papszArgv[0] );
2083 :
2084 : /* ==================================================================== */
2085 : /* Loop over all arguments. */
2086 : /* ==================================================================== */
2087 1843 : for( iArg = 1; iArg < nArgc; iArg++ )
2088 : {
2089 : /* -------------------------------------------------------------------- */
2090 : /* --version */
2091 : /* -------------------------------------------------------------------- */
2092 1505 : if( EQUAL(papszArgv[iArg],"--version") )
2093 : {
2094 0 : printf( "%s\n", GDALVersionInfo( "--version" ) );
2095 0 : CSLDestroy( papszReturn );
2096 0 : return 0;
2097 : }
2098 :
2099 : /* -------------------------------------------------------------------- */
2100 : /* --license */
2101 : /* -------------------------------------------------------------------- */
2102 1505 : else if( EQUAL(papszArgv[iArg],"--license") )
2103 : {
2104 0 : printf( "%s\n", GDALVersionInfo( "LICENSE" ) );
2105 0 : CSLDestroy( papszReturn );
2106 0 : return 0;
2107 : }
2108 :
2109 : /* -------------------------------------------------------------------- */
2110 : /* --config */
2111 : /* -------------------------------------------------------------------- */
2112 1505 : else if( EQUAL(papszArgv[iArg],"--config") )
2113 : {
2114 0 : if( iArg + 2 >= nArgc )
2115 : {
2116 : CPLError( CE_Failure, CPLE_AppDefined,
2117 0 : "--config option given without a key and value argument." );
2118 0 : CSLDestroy( papszReturn );
2119 0 : return -1;
2120 : }
2121 :
2122 0 : CPLSetConfigOption( papszArgv[iArg+1], papszArgv[iArg+2] );
2123 :
2124 0 : iArg += 2;
2125 : }
2126 :
2127 : /* -------------------------------------------------------------------- */
2128 : /* --mempreload */
2129 : /* -------------------------------------------------------------------- */
2130 1505 : else if( EQUAL(papszArgv[iArg],"--mempreload") )
2131 : {
2132 : int i;
2133 :
2134 0 : if( iArg + 1 >= nArgc )
2135 : {
2136 : CPLError( CE_Failure, CPLE_AppDefined,
2137 0 : "--mempreload option given without directory path.");
2138 0 : CSLDestroy( papszReturn );
2139 0 : return -1;
2140 : }
2141 :
2142 0 : char **papszFiles = CPLReadDir( papszArgv[iArg+1] );
2143 0 : if( CSLCount(papszFiles) == 0 )
2144 : {
2145 : CPLError( CE_Failure, CPLE_AppDefined,
2146 0 : "--mempreload given invalid or empty directory.");
2147 0 : CSLDestroy( papszReturn );
2148 0 : return -1;
2149 : }
2150 :
2151 0 : for( i = 0; papszFiles[i] != NULL; i++ )
2152 : {
2153 0 : CPLString osOldPath, osNewPath;
2154 :
2155 0 : if( EQUAL(papszFiles[i],".") || EQUAL(papszFiles[i],"..") )
2156 0 : continue;
2157 :
2158 0 : osOldPath = CPLFormFilename( papszArgv[iArg+1],
2159 0 : papszFiles[i], NULL );
2160 0 : osNewPath.Printf( "/vsimem/%s", papszFiles[i] );
2161 :
2162 : CPLDebug( "VSI", "Preloading %s to %s.",
2163 0 : osOldPath.c_str(), osNewPath.c_str() );
2164 :
2165 0 : if( CPLCopyFile( osNewPath, osOldPath ) != 0 )
2166 0 : return -1;
2167 : }
2168 :
2169 0 : CSLDestroy( papszFiles );
2170 0 : iArg += 1;
2171 : }
2172 :
2173 : /* -------------------------------------------------------------------- */
2174 : /* --debug */
2175 : /* -------------------------------------------------------------------- */
2176 1505 : else if( EQUAL(papszArgv[iArg],"--debug") )
2177 : {
2178 0 : if( iArg + 1 >= nArgc )
2179 : {
2180 : CPLError( CE_Failure, CPLE_AppDefined,
2181 0 : "--debug option given without debug level." );
2182 0 : CSLDestroy( papszReturn );
2183 0 : return -1;
2184 : }
2185 :
2186 0 : CPLSetConfigOption( "CPL_DEBUG", papszArgv[iArg+1] );
2187 0 : iArg += 1;
2188 : }
2189 :
2190 : /* -------------------------------------------------------------------- */
2191 : /* --optfile */
2192 : /* */
2193 : /* Annoyingly the options inserted by --optfile will *not* be */
2194 : /* processed properly if they are general options. */
2195 : /* -------------------------------------------------------------------- */
2196 1505 : else if( EQUAL(papszArgv[iArg],"--optfile") )
2197 : {
2198 : const char *pszLine;
2199 : FILE *fpOptFile;
2200 :
2201 0 : if( iArg + 1 >= nArgc )
2202 : {
2203 : CPLError( CE_Failure, CPLE_AppDefined,
2204 0 : "--optfile option given without filename." );
2205 0 : CSLDestroy( papszReturn );
2206 0 : return -1;
2207 : }
2208 :
2209 0 : fpOptFile = VSIFOpen( papszArgv[iArg+1], "rb" );
2210 :
2211 0 : if( fpOptFile == NULL )
2212 : {
2213 : CPLError( CE_Failure, CPLE_AppDefined,
2214 : "Unable to open optfile '%s'.\n%s",
2215 0 : papszArgv[iArg+1], VSIStrerror( errno ) );
2216 0 : CSLDestroy( papszReturn );
2217 0 : return -1;
2218 : }
2219 :
2220 0 : while( (pszLine = CPLReadLine( fpOptFile )) != NULL )
2221 : {
2222 : char **papszTokens;
2223 : int i;
2224 :
2225 0 : if( pszLine[0] == '#' || strlen(pszLine) == 0 )
2226 0 : continue;
2227 :
2228 0 : papszTokens = CSLTokenizeString( pszLine );
2229 0 : for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++)
2230 0 : papszReturn = CSLAddString( papszReturn, papszTokens[i] );
2231 0 : CSLDestroy( papszTokens );
2232 : }
2233 :
2234 0 : VSIFClose( fpOptFile );
2235 :
2236 0 : iArg += 1;
2237 : }
2238 :
2239 : /* -------------------------------------------------------------------- */
2240 : /* --formats */
2241 : /* -------------------------------------------------------------------- */
2242 1505 : else if( EQUAL(papszArgv[iArg], "--formats") )
2243 : {
2244 : int iDr;
2245 :
2246 0 : printf( "Supported Formats:\n" );
2247 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
2248 : {
2249 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
2250 : const char *pszRWFlag, *pszVirtualIO;
2251 :
2252 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) )
2253 0 : pszRWFlag = "rw+";
2254 0 : else if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
2255 : NULL ) )
2256 0 : pszRWFlag = "rw";
2257 : else
2258 0 : pszRWFlag = "ro";
2259 :
2260 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL) )
2261 0 : pszVirtualIO = "v";
2262 : else
2263 0 : pszVirtualIO = "";
2264 :
2265 : printf( " %s (%s%s): %s\n",
2266 : GDALGetDriverShortName( hDriver ),
2267 : pszRWFlag, pszVirtualIO,
2268 0 : GDALGetDriverLongName( hDriver ) );
2269 : }
2270 :
2271 0 : CSLDestroy( papszReturn );
2272 0 : return 0;
2273 : }
2274 :
2275 : /* -------------------------------------------------------------------- */
2276 : /* --format */
2277 : /* -------------------------------------------------------------------- */
2278 1505 : else if( EQUAL(papszArgv[iArg], "--format") )
2279 : {
2280 : GDALDriverH hDriver;
2281 : char **papszMD;
2282 :
2283 0 : CSLDestroy( papszReturn );
2284 :
2285 0 : if( iArg + 1 >= nArgc )
2286 : {
2287 : CPLError( CE_Failure, CPLE_AppDefined,
2288 0 : "--format option given without a format code." );
2289 0 : return -1;
2290 : }
2291 :
2292 0 : hDriver = GDALGetDriverByName( papszArgv[iArg+1] );
2293 0 : if( hDriver == NULL )
2294 : {
2295 : CPLError( CE_Failure, CPLE_AppDefined,
2296 : "--format option given with format '%s', but that format not\n"
2297 : "recognised. Use the --formats option to get a list of available formats,\n"
2298 : "and use the short code (ie. GTiff or HFA) as the format identifier.\n",
2299 0 : papszArgv[iArg+1] );
2300 0 : return -1;
2301 : }
2302 :
2303 0 : printf( "Format Details:\n" );
2304 0 : printf( " Short Name: %s\n", GDALGetDriverShortName( hDriver ) );
2305 0 : printf( " Long Name: %s\n", GDALGetDriverLongName( hDriver ) );
2306 :
2307 0 : papszMD = GDALGetMetadata( hDriver, NULL );
2308 :
2309 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) )
2310 : printf( " Extension: %s\n",
2311 0 : CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) );
2312 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) )
2313 : printf( " Mime Type: %s\n",
2314 0 : CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) );
2315 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) )
2316 : printf( " Help Topic: %s\n",
2317 0 : CSLFetchNameValue( papszMD, GDAL_DMD_HELPTOPIC ) );
2318 :
2319 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATE, FALSE ) )
2320 0 : printf( " Supports: Create() - Create writeable dataset.\n" );
2321 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATECOPY, FALSE ) )
2322 0 : printf( " Supports: CreateCopy() - Create dataset by copying another.\n" );
2323 0 : if( CSLFetchBoolean( papszMD, GDAL_DCAP_VIRTUALIO, FALSE ) )
2324 0 : printf( " Supports: Virtual IO - eg. /vsimem/\n" );
2325 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) )
2326 : printf( " Creation Datatypes: %s\n",
2327 0 : CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) );
2328 0 : if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONOPTIONLIST ) )
2329 : {
2330 : CPLXMLNode *psCOL =
2331 : CPLParseXMLString(
2332 : CSLFetchNameValue( papszMD,
2333 0 : GDAL_DMD_CREATIONOPTIONLIST ) );
2334 : char *pszFormattedXML =
2335 0 : CPLSerializeXMLTree( psCOL );
2336 :
2337 0 : CPLDestroyXMLNode( psCOL );
2338 :
2339 0 : printf( "\n%s\n", pszFormattedXML );
2340 0 : CPLFree( pszFormattedXML );
2341 : }
2342 0 : return 0;
2343 : }
2344 :
2345 : /* -------------------------------------------------------------------- */
2346 : /* --help-general */
2347 : /* -------------------------------------------------------------------- */
2348 1505 : else if( EQUAL(papszArgv[iArg],"--help-general") )
2349 : {
2350 0 : printf( "Generic GDAL utility command options:\n" );
2351 0 : printf( " --version: report version of GDAL in use.\n" );
2352 0 : printf( " --license: report GDAL license info.\n" );
2353 0 : printf( " --formats: report all configured format drivers.\n" );
2354 0 : printf( " --format [format]: details of one format.\n" );
2355 0 : printf( " --optfile filename: expand an option file into the argument list.\n" );
2356 0 : printf( " --config key value: set system configuration option.\n" );
2357 0 : printf( " --debug [on/off/value]: set debug level.\n" );
2358 0 : printf( " --help-general: report detailed help on general options.\n" );
2359 0 : CSLDestroy( papszReturn );
2360 0 : return 0;
2361 : }
2362 :
2363 : /* -------------------------------------------------------------------- */
2364 : /* --locale */
2365 : /* -------------------------------------------------------------------- */
2366 1505 : else if( EQUAL(papszArgv[iArg],"--locale") && iArg < nArgc-1 )
2367 : {
2368 0 : setlocale( LC_ALL, papszArgv[++iArg] );
2369 : }
2370 :
2371 : /* -------------------------------------------------------------------- */
2372 : /* carry through unrecognised options. */
2373 : /* -------------------------------------------------------------------- */
2374 : else
2375 : {
2376 1505 : papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
2377 : }
2378 : }
2379 :
2380 338 : *ppapszArgv = papszReturn;
2381 :
2382 338 : return CSLCount( *ppapszArgv );
2383 : }
2384 :
2385 :
2386 : /************************************************************************/
2387 : /* _FetchDblFromMD() */
2388 : /************************************************************************/
2389 :
2390 36 : static int _FetchDblFromMD( char **papszMD, const char *pszKey,
2391 : double *padfTarget, int nCount, double dfDefault )
2392 :
2393 : {
2394 : char szFullKey[200];
2395 :
2396 36 : sprintf( szFullKey, "%s", pszKey );
2397 :
2398 36 : const char *pszValue = CSLFetchNameValue( papszMD, szFullKey );
2399 : int i;
2400 :
2401 224 : for( i = 0; i < nCount; i++ )
2402 188 : padfTarget[i] = dfDefault;
2403 :
2404 36 : if( pszValue == NULL )
2405 8 : return FALSE;
2406 :
2407 28 : if( nCount == 1 )
2408 : {
2409 20 : *padfTarget = CPLAtofM( pszValue );
2410 20 : return TRUE;
2411 : }
2412 :
2413 : char **papszTokens = CSLTokenizeStringComplex( pszValue, " ,",
2414 8 : FALSE, FALSE );
2415 :
2416 8 : if( CSLCount( papszTokens ) != nCount )
2417 : {
2418 0 : CSLDestroy( papszTokens );
2419 0 : return FALSE;
2420 : }
2421 :
2422 168 : for( i = 0; i < nCount; i++ )
2423 160 : padfTarget[i] = CPLAtofM(papszTokens[i]);
2424 :
2425 8 : CSLDestroy( papszTokens );
2426 :
2427 8 : return TRUE;
2428 : }
2429 :
2430 : /************************************************************************/
2431 : /* GDALExtractRPCInfo() */
2432 : /* */
2433 : /* Extract RPC info from metadata, and apply to an RPCInfo */
2434 : /* structure. The inverse of this function is RPCInfoToMD() in */
2435 : /* alg/gdal_rpc.cpp (should it be needed). */
2436 : /************************************************************************/
2437 :
2438 2 : int CPL_STDCALL GDALExtractRPCInfo( char **papszMD, GDALRPCInfo *psRPC )
2439 :
2440 : {
2441 2 : if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL )
2442 0 : return FALSE;
2443 :
2444 2 : if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL
2445 : || CSLFetchNameValue( papszMD, "LINE_DEN_COEFF" ) == NULL
2446 : || CSLFetchNameValue( papszMD, "SAMP_NUM_COEFF" ) == NULL
2447 : || CSLFetchNameValue( papszMD, "SAMP_DEN_COEFF" ) == NULL )
2448 : {
2449 : CPLError( CE_Failure, CPLE_AppDefined,
2450 0 : "Some required RPC metadata missing in GDALExtractRPCInfo()");
2451 0 : return FALSE;
2452 : }
2453 :
2454 2 : _FetchDblFromMD( papszMD, "LINE_OFF", &(psRPC->dfLINE_OFF), 1, 0.0 );
2455 2 : _FetchDblFromMD( papszMD, "LINE_SCALE", &(psRPC->dfLINE_SCALE), 1, 1.0 );
2456 2 : _FetchDblFromMD( papszMD, "SAMP_OFF", &(psRPC->dfSAMP_OFF), 1, 0.0 );
2457 2 : _FetchDblFromMD( papszMD, "SAMP_SCALE", &(psRPC->dfSAMP_SCALE), 1, 1.0 );
2458 2 : _FetchDblFromMD( papszMD, "HEIGHT_OFF", &(psRPC->dfHEIGHT_OFF), 1, 0.0 );
2459 2 : _FetchDblFromMD( papszMD, "HEIGHT_SCALE", &(psRPC->dfHEIGHT_SCALE),1, 1.0);
2460 2 : _FetchDblFromMD( papszMD, "LAT_OFF", &(psRPC->dfLAT_OFF), 1, 0.0 );
2461 2 : _FetchDblFromMD( papszMD, "LAT_SCALE", &(psRPC->dfLAT_SCALE), 1, 1.0 );
2462 2 : _FetchDblFromMD( papszMD, "LONG_OFF", &(psRPC->dfLONG_OFF), 1, 0.0 );
2463 2 : _FetchDblFromMD( papszMD, "LONG_SCALE", &(psRPC->dfLONG_SCALE), 1, 1.0 );
2464 :
2465 : _FetchDblFromMD( papszMD, "LINE_NUM_COEFF", psRPC->adfLINE_NUM_COEFF,
2466 2 : 20, 0.0 );
2467 : _FetchDblFromMD( papszMD, "LINE_DEN_COEFF", psRPC->adfLINE_DEN_COEFF,
2468 2 : 20, 0.0 );
2469 : _FetchDblFromMD( papszMD, "SAMP_NUM_COEFF", psRPC->adfSAMP_NUM_COEFF,
2470 2 : 20, 0.0 );
2471 : _FetchDblFromMD( papszMD, "SAMP_DEN_COEFF", psRPC->adfSAMP_DEN_COEFF,
2472 2 : 20, 0.0 );
2473 :
2474 2 : _FetchDblFromMD( papszMD, "MIN_LONG", &(psRPC->dfMIN_LONG), 1, -180.0 );
2475 2 : _FetchDblFromMD( papszMD, "MIN_LAT", &(psRPC->dfMIN_LAT), 1, -90.0 );
2476 2 : _FetchDblFromMD( papszMD, "MAX_LONG", &(psRPC->dfMAX_LONG), 1, 180.0 );
2477 2 : _FetchDblFromMD( papszMD, "MAX_LAT", &(psRPC->dfMAX_LAT), 1, 90.0 );
2478 :
2479 2 : return TRUE;
2480 : }
2481 :
2482 : /************************************************************************/
2483 : /* GDALFindAssociatedAuxFile() */
2484 : /************************************************************************/
2485 :
2486 5637 : GDALDataset *GDALFindAssociatedAuxFile( const char *pszBasename,
2487 : GDALAccess eAccess,
2488 : GDALDataset *poDependentDS )
2489 :
2490 : {
2491 5637 : const char *pszAuxSuffixLC = "aux";
2492 : #ifndef WIN32
2493 5637 : const char *pszAuxSuffixUC = "AUX";
2494 : #endif
2495 :
2496 5637 : if( EQUAL(CPLGetExtension(pszBasename), pszAuxSuffixLC) )
2497 18 : return NULL;
2498 :
2499 : /* -------------------------------------------------------------------- */
2500 : /* Don't even try to look for an .aux file if we don't have a */
2501 : /* path of any kind. */
2502 : /* -------------------------------------------------------------------- */
2503 5619 : if( strlen(pszBasename) == 0 )
2504 0 : return NULL;
2505 :
2506 : /* -------------------------------------------------------------------- */
2507 : /* We didn't find that, so try and find a corresponding aux */
2508 : /* file. Check that we are the dependent file of the aux */
2509 : /* file, or if we aren't verify that the dependent file does */
2510 : /* not exist, likely mean it is us but some sort of renaming */
2511 : /* has occured. */
2512 : /* -------------------------------------------------------------------- */
2513 5619 : CPLString osJustFile = CPLGetFilename(pszBasename); // without dir
2514 5619 : CPLString osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixLC);
2515 5619 : GDALDataset *poODS = NULL;
2516 : GByte abyHeader[32];
2517 : FILE *fp;
2518 :
2519 5619 : fp = VSIFOpenL( osAuxFilename, "rb" );
2520 :
2521 :
2522 5619 : if ( fp == NULL )
2523 : {
2524 : // Can't found file with lower case suffix. Try the upper case one.
2525 : // no point in doing this on Win32 with case insensitive filenames.
2526 : #ifndef WIN32
2527 5588 : osAuxFilename = CPLResetExtension(pszBasename, pszAuxSuffixUC);
2528 5588 : fp = VSIFOpenL( osAuxFilename, "rb" );
2529 : #endif
2530 : }
2531 :
2532 5619 : if( fp != NULL )
2533 : {
2534 31 : VSIFReadL( abyHeader, 1, 32, fp );
2535 31 : if( EQUALN((char *) abyHeader,"EHFA_HEADER_TAG",15) )
2536 10 : poODS = (GDALDataset *) GDALOpenShared( osAuxFilename, eAccess );
2537 31 : VSIFCloseL( fp );
2538 : }
2539 :
2540 : /* -------------------------------------------------------------------- */
2541 : /* Try replacing extension with .aux */
2542 : /* -------------------------------------------------------------------- */
2543 5619 : if( poODS != NULL )
2544 : {
2545 : const char *pszDep
2546 10 : = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
2547 10 : if( pszDep == NULL )
2548 : {
2549 : CPLDebug( "AUX",
2550 : "Found %s but it has no dependent file, ignoring.",
2551 0 : osAuxFilename.c_str() );
2552 0 : GDALClose( poODS );
2553 0 : poODS = NULL;
2554 : }
2555 10 : else if( !EQUAL(pszDep,osJustFile) )
2556 : {
2557 : VSIStatBufL sStatBuf;
2558 :
2559 0 : if( VSIStatL( pszDep, &sStatBuf ) == 0 )
2560 : {
2561 : CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
2562 : osAuxFilename.c_str(),
2563 0 : pszDep, osJustFile.c_str() );
2564 0 : GDALClose( poODS );
2565 0 : poODS = NULL;
2566 : }
2567 : else
2568 : {
2569 : CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
2570 : "%s does not exist, we will use .aux file as our own.",
2571 : osAuxFilename.c_str(),
2572 : pszDep, osJustFile.c_str(),
2573 0 : pszDep );
2574 : }
2575 : }
2576 :
2577 : /* -------------------------------------------------------------------- */
2578 : /* Confirm that the aux file matches the configuration of the */
2579 : /* dependent dataset. */
2580 : /* -------------------------------------------------------------------- */
2581 10 : if( poODS != NULL && poDependentDS != NULL
2582 : && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
2583 : || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
2584 : || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
2585 : {
2586 : CPLDebug( "AUX",
2587 : "Ignoring aux file %s as its raster configuration\n"
2588 : "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
2589 : osAuxFilename.c_str(),
2590 : poODS->GetRasterXSize(),
2591 : poODS->GetRasterYSize(),
2592 : poODS->GetRasterCount(),
2593 : poDependentDS->GetRasterXSize(),
2594 : poDependentDS->GetRasterYSize(),
2595 5 : poDependentDS->GetRasterCount() );
2596 :
2597 5 : GDALClose( poODS );
2598 5 : poODS = NULL;
2599 : }
2600 : }
2601 :
2602 : /* -------------------------------------------------------------------- */
2603 : /* Try appending .aux to the end of the filename. */
2604 : /* -------------------------------------------------------------------- */
2605 5619 : if( poODS == NULL )
2606 : {
2607 5614 : osAuxFilename = pszBasename;
2608 5614 : osAuxFilename += ".";
2609 5614 : osAuxFilename += pszAuxSuffixLC;
2610 5614 : fp = VSIFOpenL( osAuxFilename, "rb" );
2611 : #ifndef WIN32
2612 5614 : if ( fp == NULL )
2613 : {
2614 : // Can't found file with lower case suffix. Try the upper case one.
2615 5598 : osAuxFilename = pszBasename;
2616 5598 : osAuxFilename += ".";
2617 5598 : osAuxFilename += pszAuxSuffixUC;
2618 5598 : fp = VSIFOpenL( osAuxFilename, "rb" );
2619 : }
2620 : #endif
2621 :
2622 5614 : if( fp != NULL )
2623 : {
2624 16 : VSIFReadL( abyHeader, 1, 32, fp );
2625 16 : if( EQUALN((char *) abyHeader,"EHFA_HEADER_TAG",15) )
2626 0 : poODS = (GDALDataset *) GDALOpenShared( osAuxFilename, eAccess );
2627 16 : VSIFCloseL( fp );
2628 : }
2629 :
2630 5614 : if( poODS != NULL )
2631 : {
2632 : const char *pszDep
2633 0 : = poODS->GetMetadataItem( "HFA_DEPENDENT_FILE", "HFA" );
2634 0 : if( pszDep == NULL )
2635 : {
2636 : CPLDebug( "AUX",
2637 : "Found %s but it has no dependent file, ignoring.",
2638 0 : osAuxFilename.c_str() );
2639 0 : GDALClose( poODS );
2640 0 : poODS = NULL;
2641 : }
2642 0 : else if( !EQUAL(pszDep,osJustFile) )
2643 : {
2644 : VSIStatBufL sStatBuf;
2645 :
2646 0 : if( VSIStatL( pszDep, &sStatBuf ) == 0 )
2647 : {
2648 : CPLDebug( "AUX", "%s is for file %s, not %s, ignoring.",
2649 : osAuxFilename.c_str(),
2650 0 : pszDep, osJustFile.c_str() );
2651 0 : GDALClose( poODS );
2652 0 : poODS = NULL;
2653 : }
2654 : else
2655 : {
2656 : CPLDebug( "AUX", "%s is for file %s, not %s, but since\n"
2657 : "%s does not exist, we will use .aux file as our own.",
2658 : osAuxFilename.c_str(),
2659 : pszDep, osJustFile.c_str(),
2660 0 : pszDep );
2661 : }
2662 : }
2663 : }
2664 : }
2665 :
2666 : /* -------------------------------------------------------------------- */
2667 : /* Confirm that the aux file matches the configuration of the */
2668 : /* dependent dataset. */
2669 : /* -------------------------------------------------------------------- */
2670 5619 : if( poODS != NULL && poDependentDS != NULL
2671 : && (poODS->GetRasterCount() != poDependentDS->GetRasterCount()
2672 : || poODS->GetRasterXSize() != poDependentDS->GetRasterXSize()
2673 : || poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()) )
2674 : {
2675 : CPLDebug( "AUX",
2676 : "Ignoring aux file %s as its raster configuration\n"
2677 : "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
2678 : osAuxFilename.c_str(),
2679 : poODS->GetRasterXSize(),
2680 : poODS->GetRasterYSize(),
2681 : poODS->GetRasterCount(),
2682 : poDependentDS->GetRasterXSize(),
2683 : poDependentDS->GetRasterYSize(),
2684 0 : poDependentDS->GetRasterCount() );
2685 :
2686 0 : GDALClose( poODS );
2687 0 : poODS = NULL;
2688 : }
2689 :
2690 5619 : return poODS;
2691 : }
2692 :
2693 : /************************************************************************/
2694 : /* -------------------------------------------------------------------- */
2695 : /* The following stubs are present to ensure that older GDAL */
2696 : /* bridges don't fail with newer libraries. */
2697 : /* -------------------------------------------------------------------- */
2698 : /************************************************************************/
2699 :
2700 : CPL_C_START
2701 :
2702 0 : void * CPL_STDCALL GDALCreateProjDef( const char * )
2703 : {
2704 0 : CPLDebug( "GDAL", "GDALCreateProjDef no longer supported." );
2705 0 : return NULL;
2706 : }
2707 :
2708 0 : CPLErr CPL_STDCALL GDALReprojectToLongLat( void *, double *, double * )
2709 : {
2710 0 : CPLDebug( "GDAL", "GDALReprojectToLatLong no longer supported." );
2711 0 : return CE_Failure;
2712 : }
2713 :
2714 0 : CPLErr CPL_STDCALL GDALReprojectFromLongLat( void *, double *, double * )
2715 : {
2716 0 : CPLDebug( "GDAL", "GDALReprojectFromLatLong no longer supported." );
2717 0 : return CE_Failure;
2718 : }
2719 :
2720 0 : void CPL_STDCALL GDALDestroyProjDef( void * )
2721 :
2722 : {
2723 0 : CPLDebug( "GDAL", "GDALDestroyProjDef no longer supported." );
2724 0 : }
2725 :
2726 : CPL_C_END
2727 :
2728 : /************************************************************************/
2729 : /* Infrastructure to check that dataset characteristics are valid */
2730 : /************************************************************************/
2731 :
2732 : CPL_C_START
2733 :
2734 : /**
2735 : * \brief Return TRUE if the dataset dimensions are valid.
2736 : *
2737 : * @param nXSize raster width
2738 : * @param nYSize raster height
2739 : *
2740 : * @since GDAL 1.7.0
2741 : */
2742 716 : int GDALCheckDatasetDimensions( int nXSize, int nYSize )
2743 : {
2744 716 : if (nXSize <= 0 || nYSize <= 0)
2745 : {
2746 : CPLError(CE_Failure, CPLE_AppDefined,
2747 0 : "Invalid dataset dimensions : %d x %d", nXSize, nYSize);
2748 0 : return FALSE;
2749 : }
2750 716 : return TRUE;
2751 : }
2752 :
2753 : /**
2754 : * \brief Return TRUE if the band count is valid.
2755 : *
2756 : * If the configuration option GDAL_MAX_BAND_COUNT is defined,
2757 : * the band count will be compared to the maximum number of band allowed.
2758 : *
2759 : * @param nBands the band count
2760 : * @param bIsZeroAllowed TRUE if band count == 0 is allowed
2761 : *
2762 : * @since GDAL 1.7.0
2763 : */
2764 :
2765 265 : int GDALCheckBandCount( int nBands, int bIsZeroAllowed )
2766 : {
2767 265 : int nMaxBands = -1;
2768 265 : const char* pszMaxBandCount = CPLGetConfigOption("GDAL_MAX_BAND_COUNT", NULL);
2769 265 : if (pszMaxBandCount != NULL)
2770 : {
2771 0 : nMaxBands = atoi(pszMaxBandCount);
2772 : }
2773 265 : if (nBands < 0 || (!bIsZeroAllowed && nBands == 0) ||
2774 : (nMaxBands >= 0 && nBands > nMaxBands) )
2775 : {
2776 : CPLError(CE_Failure, CPLE_AppDefined,
2777 2 : "Invalid band count : %d", nBands);
2778 2 : return FALSE;
2779 : }
2780 263 : return TRUE;
2781 : }
2782 :
2783 : CPL_C_END
2784 :
|