• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15721865619

18 Jun 2025 01:40AM UTC coverage: 71.065% (-0.001%) from 71.066%
15721865619

Pull #12592

github

web-flow
Merge 924ef7459 into dec8c71bd
Pull Request #12592: VRTDerivedBand expressions: Add _CENTER_X_ and _CENTER_Y_ built-in variables

32 of 34 new or added lines in 2 files covered. (94.12%)

67 existing lines in 32 files now uncovered.

571764 of 804570 relevant lines covered (71.06%)

251330.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.5
/frmts/gtiff/libgeotiff/geo_normalize.c
1
/******************************************************************************
2
 *
3
 * Project:  libgeotiff
4
 * Purpose:  Code to normalize PCS and other composite codes in a GeoTIFF file.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2018, Even Rouault <even.rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 *****************************************************************************/
13

14
#include <assert.h>
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>
18

19
#include "cpl_serv.h"
20
#include "geo_tiffp.h"
21
#include "geovalues.h"
22
#include "geo_normalize.h"
23
#include "geo_keyp.h"
24

25
#include "proj.h"
26

27
#ifndef KvUserDefined
28
#  define KvUserDefined 32767
29
#endif
30

31
#ifndef M_PI
32
#  define M_PI 3.14159265358979323846
33
#endif
34

35
/* EPSG Codes for projection parameters.  Unfortunately, these bear no
36
   relationship to the GeoTIFF codes even though the names are so similar. */
37

38
#define EPSGNatOriginLat         8801
39
#define EPSGNatOriginLong        8802
40
#define EPSGNatOriginScaleFactor 8805
41
#define EPSGFalseEasting         8806
42
#define EPSGFalseNorthing        8807
43
#define EPSGProjCenterLat        8811
44
#define EPSGProjCenterLong       8812
45
#define EPSGAzimuth              8813
46
#define EPSGAngleRectifiedToSkewedGrid 8814
47
#define EPSGInitialLineScaleFactor 8815
48
#define EPSGProjCenterEasting    8816
49
#define EPSGProjCenterNorthing   8817
50
#define EPSGPseudoStdParallelLat 8818
51
#define EPSGPseudoStdParallelScaleFactor 8819
52
#define EPSGFalseOriginLat       8821
53
#define EPSGFalseOriginLong      8822
54
#define EPSGStdParallel1Lat      8823
55
#define EPSGStdParallel2Lat      8824
56
#define EPSGFalseOriginEasting   8826
57
#define EPSGFalseOriginNorthing  8827
58
#define EPSGSphericalOriginLat   8828
59
#define EPSGSphericalOriginLong  8829
60
#define EPSGInitialLongitude     8830
61
#define EPSGZoneWidth            8831
62
#define EPSGLatOfStdParallel     8832
63
#define EPSGOriginLong           8833
64
#define EPSGTopocentricOriginLat 8834
65
#define EPSGTopocentricOriginLong 8835
66
#define EPSGTopocentricOriginHeight 8836
67

68
#define CT_Ext_Mercator_2SP     -CT_Mercator
69

70
#ifndef CPL_INLINE
71
#  if (defined(__GNUC__) && !defined(__NO_INLINE__)) || defined(_MSC_VER)
72
#    define HAS_CPL_INLINE  1
73
#    define CPL_INLINE __inline
74
#  elif defined(__SUNPRO_CC)
75
#    define HAS_CPL_INLINE  1
76
#    define CPL_INLINE inline
77
#  else
78
#    define CPL_INLINE
79
#  endif
80
#endif
81

82
#ifndef CPL_UNUSED
83
#if defined(__GNUC__) && __GNUC__ >= 4
84
#  define CPL_UNUSED __attribute((__unused__))
85
#else
86
/* TODO: add cases for other compilers */
87
#  define CPL_UNUSED
88
#endif
89
#endif
90

91
CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
21,196✔
92

93
/************************************************************************/
94
/*                         GTIFKeyGetSSHORT()                           */
95
/************************************************************************/
96

97
// Geotiff SHORT keys are supposed to be unsigned, but geo_normalize interface
98
// uses signed short...
99
static int GTIFKeyGetSSHORT( GTIF *gtif, geokey_t key, short* pnVal )
87,236✔
100
{
101
    unsigned short sVal;
102
    if( GTIFKeyGetSHORT(gtif, key, &sVal, 0, 1) == 1 )
87,236✔
103
    {
104
        memcpy(pnVal, &sVal, 2);
26,282✔
105
        return 1;
26,282✔
106
    }
107
    return 0;
60,954✔
108
}
109

110
/************************************************************************/
111
/*                           GTIFGetPCSInfo()                           */
112
/************************************************************************/
113

114
int GTIFGetPCSInfoEx( void* ctxIn,
7,160✔
115
                      int nPCSCode, char **ppszEPSGName,
116
                      short *pnProjOp, short *pnUOMLengthCode,
117
                      short *pnGeogCS )
118

119
{
120
    int         nDatum;
121
    int         nZone;
122

123
    /* Deal with a few well known CRS */
124
    int Proj = GTIFPCSToMapSys( nPCSCode, &nDatum, &nZone );
7,160✔
125
    if ((Proj == MapSys_UTM_North || Proj == MapSys_UTM_South) &&
7,160✔
126
        nDatum != KvUserDefined)
6,766✔
127
    {
128
        const char* pszDatumName = NULL;
6,766✔
129
        switch (nDatum)
6,766✔
130
        {
131
            case GCS_NAD27: pszDatumName = "NAD27"; break;
6,384✔
132
            case GCS_NAD83: pszDatumName = "NAD83"; break;
12✔
133
            case GCS_WGS_72: pszDatumName = "WGS 72"; break;
×
134
            case GCS_WGS_72BE: pszDatumName = "WGS 72BE"; break;
×
135
            case GCS_WGS_84: pszDatumName = "WGS 84"; break;
370✔
136
            default: break;
×
137
        }
138

139
        if (pszDatumName)
6,766✔
140
        {
141
            if (ppszEPSGName)
6,766✔
142
            {
143
                char szEPSGName[64];
144
                snprintf(
3,383✔
145
                    szEPSGName, sizeof(szEPSGName), "%s / UTM zone %d%c",
146
                    pszDatumName, nZone,
147
                    (Proj == MapSys_UTM_North) ? 'N' : 'S');
148
                *ppszEPSGName = CPLStrdup(szEPSGName);
3,383✔
149
            }
150

151
            if (pnProjOp)
6,766✔
152
                *pnProjOp = (short) (((Proj == MapSys_UTM_North) ? Proj_UTM_zone_1N - 1 : Proj_UTM_zone_1S - 1) + nZone);
3,383✔
153

154
            if (pnUOMLengthCode)
6,766✔
155
                *pnUOMLengthCode = 9001; /* Linear_Meter */
3,383✔
156

157
            if (pnGeogCS)
6,766✔
158
                *pnGeogCS = (short) nDatum;
3,383✔
159

160
            return TRUE;
6,766✔
161
        }
162
    }
163

164
    if( nPCSCode == KvUserDefined )
394✔
165
        return FALSE;
×
166

167
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
394✔
168
    {
169
        char szCode[12];
170

171
        snprintf(szCode, sizeof(szCode), "%d", nPCSCode);
394✔
172
        PJ* proj_crs = proj_create_from_database(
394✔
173
            ctx, "EPSG", szCode, PJ_CATEGORY_CRS, 0, NULL);
174
        if( !proj_crs )
394✔
175
        {
176
            return FALSE;
×
177
        }
178

179
        if( proj_get_type(proj_crs) != PJ_TYPE_PROJECTED_CRS )
394✔
180
        {
181
            proj_destroy(proj_crs);
×
182
            return FALSE;
×
183
        }
184

185
        if( ppszEPSGName )
394✔
186
        {
187
            const char* pszName = proj_get_name(proj_crs);
197✔
188
            if( !pszName )
197✔
189
            {
190
                // shouldn't happen
191
                proj_destroy(proj_crs);
×
192
                return FALSE;
×
193
            }
194
            *ppszEPSGName = CPLStrdup(pszName);
197✔
195
        }
196

197
        if( pnProjOp )
394✔
198
        {
199
            PJ* conversion = proj_crs_get_coordoperation(
197✔
200
                ctx, proj_crs);
201
            if( !conversion )
197✔
202
            {
203
                // shouldn't happen except out of memory
204
                proj_destroy(proj_crs);
×
205
                return FALSE;
×
206
            }
207

208
            {
209
                const char* pszConvCode = proj_get_id_code(conversion, 0);
197✔
210
                assert( pszConvCode );
197✔
211
                *pnProjOp = (short) atoi(pszConvCode);
197✔
212
            }
213

214
            proj_destroy(conversion);
197✔
215
        }
216

217
        if( pnUOMLengthCode )
394✔
218
        {
219
            PJ* coordSys = proj_crs_get_coordinate_system(
197✔
220
                ctx, proj_crs);
221
            if( !coordSys )
197✔
222
            {
223
                // shouldn't happen except out of memory
224
                proj_destroy(proj_crs);
×
225
                return FALSE;
×
226
            }
227

228
            {
229
                const char* pszUnitCode = NULL;
197✔
230
                if( !proj_cs_get_axis_info(
197✔
231
                    ctx, coordSys, 0,
232
                    NULL, /* name */
233
                    NULL, /* abbreviation*/
234
                    NULL, /* direction */
235
                    NULL, /* conversion factor */
236
                    NULL, /* unit name */
237
                    NULL, /* unit auth name (should be EPSG) */
238
                    &pszUnitCode) || pszUnitCode == NULL )
197✔
239
                {
240
                    proj_destroy(coordSys);
×
241
                    return FALSE;
×
242
                }
243
                *pnUOMLengthCode = (short) atoi(pszUnitCode);
197✔
244
                proj_destroy(coordSys);
197✔
245
            }
246
        }
247

248
        if( pnGeogCS )
394✔
249
        {
250
            PJ* geod_crs = proj_crs_get_geodetic_crs(ctx, proj_crs);
197✔
251
            if( !geod_crs )
197✔
252
            {
253
                // shouldn't happen except out of memory
254
                proj_destroy(proj_crs);
×
255
                return FALSE;
×
256
            }
257

258
            {
259
                const char* pszGeodCode = proj_get_id_code(geod_crs, 0);
197✔
260
                assert( pszGeodCode );
197✔
261
                *pnGeogCS = (short) atoi(pszGeodCode);
197✔
262
            }
263

264
            proj_destroy(geod_crs);
197✔
265
        }
266

267

268
        proj_destroy(proj_crs);
394✔
269
        return TRUE;
394✔
270
    }
271
}
272

273

274
int GTIFGetPCSInfo( int nPCSCode, char **ppszEPSGName,
×
275
                    short *pnProjOp, short *pnUOMLengthCode,
276
                    short *pnGeogCS )
277

278
{
279
    PJ_CONTEXT* ctx = proj_context_create();
×
280
    int ret = GTIFGetPCSInfoEx(ctx, nPCSCode, ppszEPSGName, pnProjOp,
×
281
                               pnUOMLengthCode, pnGeogCS);
282
    proj_context_destroy(ctx);
×
283
    return ret;
×
284
}
285

286
/************************************************************************/
287
/*                           GTIFAngleToDD()                            */
288
/*                                                                      */
289
/*      Convert a numeric angle to decimal degrees.                     */
290
/************************************************************************/
291

292
double GTIFAngleToDD( double dfAngle, int nUOMAngle )
434✔
293

294
{
295
    if( nUOMAngle == 9110 )                /* DDD.MMSSsss */
434✔
296
    {
297
        if( dfAngle > -999.9 && dfAngle < 999.9 )
×
298
        {
299
            char        szAngleString[32];
300

301
            snprintf(szAngleString, sizeof(szAngleString), "%12.7f", dfAngle);
×
302
            dfAngle = GTIFAngleStringToDD( szAngleString, nUOMAngle );
×
303
        }
304
    }
305
    else if ( nUOMAngle != KvUserDefined )
434✔
306
    {
307
        double                dfInDegrees = 1.0;
400✔
308

309
        GTIFGetUOMAngleInfo( nUOMAngle, NULL, &dfInDegrees );
400✔
310
        dfAngle = dfAngle * dfInDegrees;
400✔
311
    }
312

313
    return dfAngle;
434✔
314
}
315

316
/************************************************************************/
317
/*                        GTIFAngleStringToDD()                         */
318
/*                                                                      */
319
/*      Convert an angle in the specified units to decimal degrees.     */
320
/************************************************************************/
321

322
double GTIFAngleStringToDD( const char * pszAngle, int nUOMAngle )
×
323

324
{
325
    double        dfAngle;
326

327
    if( nUOMAngle == 9110 )                /* DDD.MMSSsss */
×
328
    {
329
        char        *pszDecimal;
330

331
        dfAngle = ABS(atoi(pszAngle));
×
332
        pszDecimal = strchr(pszAngle,'.');
×
333
        if( pszDecimal != NULL && strlen(pszDecimal) > 1 )
×
334
        {
335
            char        szMinutes[3];
336
            char        szSeconds[64];
337

338
            szMinutes[0] = pszDecimal[1];
×
339
            if( pszDecimal[2] >= '0' && pszDecimal[2] <= '9' )
×
340
                szMinutes[1] = pszDecimal[2];
×
341
            else
342
                szMinutes[1] = '0';
×
343

344
            szMinutes[2] = '\0';
×
345
            dfAngle += atoi(szMinutes) / 60.0;
×
346

347
            if( strlen(pszDecimal) > 3 )
×
348
            {
349
                szSeconds[0] = pszDecimal[3];
×
350
                if( pszDecimal[4] >= '0' && pszDecimal[4] <= '9' )
×
351
                {
352
                    szSeconds[1] = pszDecimal[4];
×
353
                    szSeconds[2] = '.';
×
354
                    strncpy( szSeconds+3, pszDecimal + 5, sizeof(szSeconds) - 3 );
×
355
                    szSeconds[sizeof(szSeconds) - 1] = 0;
×
356
                }
357
                else
358
                {
359
                    szSeconds[1] = '0';
×
360
                    szSeconds[2] = '\0';
×
361
                }
362
                dfAngle += GTIFAtof(szSeconds) / 3600.0;
×
363
            }
364
        }
365

366
        if( pszAngle[0] == '-' )
×
367
            dfAngle *= -1;
×
368
    }
369
    else if( nUOMAngle == 9105 || nUOMAngle == 9106 )        /* grad */
×
370
    {
371
        dfAngle = 180 * (GTIFAtof(pszAngle ) / 200);
×
372
    }
373
    else if( nUOMAngle == 9101 )                        /* radians */
×
374
    {
375
        dfAngle = 180 * (GTIFAtof(pszAngle ) / M_PI);
×
376
    }
377
    else if( nUOMAngle == 9103 )                        /* arc-minute */
×
378
    {
379
        dfAngle = GTIFAtof(pszAngle) / 60;
×
380
    }
381
    else if( nUOMAngle == 9104 )                        /* arc-second */
×
382
    {
383
        dfAngle = GTIFAtof(pszAngle) / 3600;
×
384
    }
385
    else /* decimal degrees ... some cases missing but seemingly never used */
386
    {
387
        CPLAssert( nUOMAngle == 9102 || nUOMAngle == KvUserDefined
×
388
                   || nUOMAngle == 0 );
389

390
        dfAngle = GTIFAtof(pszAngle );
×
391
    }
392

393
    return dfAngle;
×
394
}
395

396
/************************************************************************/
397
/*                           GTIFGetGCSInfo()                           */
398
/*                                                                      */
399
/*      Fetch the datum, and prime meridian related to a particular     */
400
/*      GCS.                                                            */
401
/************************************************************************/
402

403
int GTIFGetGCSInfoEx( void* ctxIn,
15,754✔
404
                      int nGCSCode, char ** ppszName,
405
                      short * pnDatum, short * pnPM, short *pnUOMAngle )
406

407
{
408
    int                nDatum=0;
15,754✔
409

410
/* -------------------------------------------------------------------- */
411
/*      Handle some "well known" GCS codes directly                     */
412
/* -------------------------------------------------------------------- */
413
    const char * pszName = NULL;
15,754✔
414
    const int nPM = PM_Greenwich;
15,754✔
415
    const int nUOMAngle = Angular_DMS_Hemisphere;
15,754✔
416
    if( nGCSCode == GCS_NAD27 )
15,754✔
417
    {
418
        nDatum = Datum_North_American_Datum_1927;
6,438✔
419
        pszName = "NAD27";
6,438✔
420
    }
421
    else if( nGCSCode == GCS_NAD83 )
9,316✔
422
    {
423
        nDatum = Datum_North_American_Datum_1983;
34✔
424
        pszName = "NAD83";
34✔
425
    }
426
    else if( nGCSCode == GCS_WGS_84 )
9,282✔
427
    {
428
        nDatum = Datum_WGS84;
8,975✔
429
        pszName = "WGS 84";
8,975✔
430
    }
431
    else if( nGCSCode == GCS_WGS_72 )
307✔
432
    {
433
        nDatum = Datum_WGS72;
10✔
434
        pszName = "WGS 72";
10✔
435
    }
436
    else if ( nGCSCode == KvUserDefined )
297✔
437
    {
438
        return FALSE;
99✔
439
    }
440

441
    if (pszName != NULL)
15,655✔
442
    {
443
        if( ppszName != NULL )
15,457✔
444
            *ppszName = CPLStrdup( pszName );
7,724✔
445
        if( pnDatum != NULL )
15,457✔
446
            *pnDatum = (short) nDatum;
7,733✔
447
        if( pnPM != NULL )
15,457✔
448
            *pnPM = (short) nPM;
7,733✔
449
        if( pnUOMAngle != NULL )
15,457✔
450
            *pnUOMAngle = (short) nUOMAngle;
7,733✔
451

452
        return TRUE;
15,457✔
453
    }
454

455
/* -------------------------------------------------------------------- */
456
/*      Search the database.                                            */
457
/* -------------------------------------------------------------------- */
458

459
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
198✔
460
    {
461
        char szCode[12];
462

463
        snprintf(szCode, sizeof(szCode), "%d", nGCSCode);
198✔
464
        PJ* geod_crs = proj_create_from_database(
198✔
465
            ctx, "EPSG", szCode, PJ_CATEGORY_CRS, 0, NULL);
466
        if( !geod_crs )
198✔
467
        {
468
            return FALSE;
×
469
        }
470

471
        {
472
            const int objType = proj_get_type(geod_crs);
198✔
473
            if( objType != PJ_TYPE_GEODETIC_CRS &&
198✔
474
                objType != PJ_TYPE_GEOCENTRIC_CRS &&
198✔
475
                objType != PJ_TYPE_GEOGRAPHIC_2D_CRS &&
2✔
476
                objType != PJ_TYPE_GEOGRAPHIC_3D_CRS )
477
            {
478
                proj_destroy(geod_crs);
×
479
                return FALSE;
×
480
            }
481
        }
482

483
        if( ppszName )
198✔
484
        {
485
            pszName = proj_get_name(geod_crs);
99✔
486
            if( !pszName )
99✔
487
            {
488
                // shouldn't happen
489
                proj_destroy(geod_crs);
×
490
                return FALSE;
×
491
            }
492
            *ppszName = CPLStrdup(pszName);
99✔
493
        }
494

495
        if( pnDatum )
198✔
496
        {
497
#if PROJ_VERSION_MAJOR >= 8
498
            PJ* datum = proj_crs_get_datum_forced(ctx, geod_crs);
499
#else
500
            PJ* datum = proj_crs_get_datum(ctx, geod_crs);
99✔
501
#endif
502
            if( !datum )
99✔
503
            {
504
                proj_destroy(geod_crs);
×
505
                return FALSE;
×
506
            }
507

508
            {
509
                const char* pszDatumCode = proj_get_id_code(datum, 0);
99✔
510
                assert( pszDatumCode );
99✔
511
                *pnDatum = (short) atoi(pszDatumCode);
99✔
512
            }
513

514
            proj_destroy(datum);
99✔
515
        }
516

517
        if( pnPM )
198✔
518
        {
519
            PJ* pm = proj_get_prime_meridian(ctx, geod_crs);
99✔
520
            if( !pm )
99✔
521
            {
522
                proj_destroy(geod_crs);
×
523
                return FALSE;
×
524
            }
525

526
            {
527
                const char* pszPMCode = proj_get_id_code(pm, 0);
99✔
528
                assert( pszPMCode );
99✔
529
                *pnPM = (short) atoi(pszPMCode);
99✔
530
            }
531

532
            proj_destroy(pm);
99✔
533
        }
534

535
        if( pnUOMAngle )
198✔
536
        {
537
            PJ* coordSys = proj_crs_get_coordinate_system(
99✔
538
                ctx, geod_crs);
539
            if( !coordSys )
99✔
540
            {
541
                // shouldn't happen except out of memory
542
                proj_destroy(geod_crs);
×
543
                return FALSE;
×
544
            }
545

546
            {
547
                const char* pszUnitCode = NULL;
99✔
548
                if( !proj_cs_get_axis_info(
99✔
549
                    ctx, coordSys, 0,
550
                    NULL, /* name */
551
                    NULL, /* abbreviation*/
552
                    NULL, /* direction */
553
                    NULL, /* conversion factor */
554
                    NULL, /* unit name */
555
                    NULL, /* unit auth name (should be EPSG) */
556
                    &pszUnitCode) || pszUnitCode == NULL )
99✔
557
                {
558
                    proj_destroy(coordSys);
×
559
                    return FALSE;
×
560
                }
561
                *pnUOMAngle = (short) atoi(pszUnitCode);
99✔
562
                proj_destroy(coordSys);
99✔
563
            }
564
        }
565

566
        proj_destroy(geod_crs);
198✔
567
        return TRUE;
198✔
568
    }
569
}
570

571
int GTIFGetGCSInfo( int nGCSCode, char ** ppszName,
20✔
572
                    short * pnDatum, short * pnPM, short *pnUOMAngle )
573

574
{
575
    PJ_CONTEXT* ctx = proj_context_create();
20✔
576
    const int ret = GTIFGetGCSInfoEx(ctx, nGCSCode, ppszName, pnDatum,
20✔
577
                                     pnPM, pnUOMAngle);
578
    proj_context_destroy(ctx);
20✔
579
    return ret;
20✔
580
}
581

582
/************************************************************************/
583
/*                        GTIFGetEllipsoidInfo()                        */
584
/*                                                                      */
585
/*      Fetch info about an ellipsoid.  Axes are always returned in     */
586
/*      meters.  SemiMajor computed based on inverse flattening         */
587
/*      where that is provided.                                         */
588
/************************************************************************/
589

590
int GTIFGetEllipsoidInfoEx( void* ctxIn,
15,717✔
591
                            int nEllipseCode, char ** ppszName,
592
                            double * pdfSemiMajor, double * pdfSemiMinor )
593

594
{
595
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
15,717✔
596
/* -------------------------------------------------------------------- */
597
/*      Try some well known ellipsoids.                                 */
598
/* -------------------------------------------------------------------- */
599
    double        dfSemiMajor=0.0;
15,717✔
600
    double     dfInvFlattening=0.0, dfSemiMinor=0.0;
15,717✔
601
    const char *pszName = NULL;
15,717✔
602

603
    if( nEllipseCode == Ellipse_Clarke_1866 )
15,717✔
604
    {
605
        pszName = "Clarke 1866";
6,442✔
606
        dfSemiMajor = 6378206.4;
6,442✔
607
        dfSemiMinor = 6356583.8;
6,442✔
608
        dfInvFlattening = 0.0;
6,442✔
609
    }
610
    else if( nEllipseCode == Ellipse_GRS_1980 )
9,275✔
611
    {
612
        pszName = "GRS 1980";
147✔
613
        dfSemiMajor = 6378137.0;
147✔
614
        dfSemiMinor = 0.0;
147✔
615
        dfInvFlattening = 298.257222101;
147✔
616
    }
617
    else if( nEllipseCode == Ellipse_WGS_84 )
9,128✔
618
    {
619
        pszName = "WGS 84";
9,009✔
620
        dfSemiMajor = 6378137.0;
9,009✔
621
        dfSemiMinor = 0.0;
9,009✔
622
        dfInvFlattening = 298.257223563;
9,009✔
623
    }
624
    else if( nEllipseCode == 7043 )
119✔
625
    {
626
        pszName = "WGS 72";
10✔
627
        dfSemiMajor = 6378135.0;
10✔
628
        dfSemiMinor = 0.0;
10✔
629
        dfInvFlattening = 298.26;
10✔
630
    }
631

632
    if (pszName != NULL)
15,717✔
633
    {
634
        if( dfSemiMinor == 0.0 )
15,608✔
635
            dfSemiMinor = dfSemiMajor * (1 - 1.0/dfInvFlattening);
9,166✔
636

637
        if( pdfSemiMinor != NULL )
15,608✔
638
            *pdfSemiMinor = dfSemiMinor;
7,809✔
639
        if( pdfSemiMajor != NULL )
15,608✔
640
            *pdfSemiMajor = dfSemiMajor;
7,809✔
641
        if( ppszName != NULL )
15,608✔
642
            *ppszName = CPLStrdup( pszName );
7,799✔
643

644
        return TRUE;
15,608✔
645
    }
646

647
    if( nEllipseCode == KvUserDefined )
109✔
648
        return FALSE;
13✔
649

650
/* -------------------------------------------------------------------- */
651
/*      Search the database.                                            */
652
/* -------------------------------------------------------------------- */
653
    {
654
        char szCode[12];
655

656
        snprintf(szCode, sizeof(szCode), "%d", nEllipseCode);
96✔
657
        PJ* ellipsoid = proj_create_from_database(
96✔
658
            ctx, "EPSG", szCode, PJ_CATEGORY_ELLIPSOID, 0, NULL);
659
        if( !ellipsoid )
96✔
660
        {
661
            return FALSE;
3✔
662
        }
663

664
        if( ppszName )
93✔
665
        {
666
            pszName = proj_get_name(ellipsoid);
46✔
667
            if( !pszName )
46✔
668
            {
669
                // shouldn't happen
670
                proj_destroy(ellipsoid);
×
671
                return FALSE;
×
672
            }
673
            *ppszName = CPLStrdup(pszName);
46✔
674
        }
675

676
        proj_ellipsoid_get_parameters(
93✔
677
            ctx, ellipsoid, pdfSemiMajor, pdfSemiMinor, NULL, NULL);
678

679
        proj_destroy(ellipsoid);
93✔
680

681
        return TRUE;
93✔
682
    }
683
}
684

685
int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
20✔
686
                          double * pdfSemiMajor, double * pdfSemiMinor )
687

688
{
689
    PJ_CONTEXT* ctx = proj_context_create();
20✔
690
    const int ret = GTIFGetEllipsoidInfoEx(ctx, nEllipseCode, ppszName, pdfSemiMajor,
20✔
691
                                           pdfSemiMinor);
692
    proj_context_destroy(ctx);
20✔
693
    return ret;
20✔
694
}
695

696
/************************************************************************/
697
/*                           GTIFGetPMInfo()                            */
698
/*                                                                      */
699
/*      Get the offset between a given prime meridian and Greenwich     */
700
/*      in degrees.                                                     */
701
/************************************************************************/
702

703
int GTIFGetPMInfoEx( void* ctxIn,
15,672✔
704
                     int nPMCode, char ** ppszName, double *pdfOffset )
705

706
{
707
/* -------------------------------------------------------------------- */
708
/*      Use a special short cut for Greenwich, since it is so common.   */
709
/* -------------------------------------------------------------------- */
710
    if( nPMCode == PM_Greenwich )
15,672✔
711
    {
712
        if( pdfOffset != NULL )
15,637✔
713
            *pdfOffset = 0.0;
7,823✔
714
        if( ppszName != NULL )
15,637✔
715
            *ppszName = CPLStrdup( "Greenwich" );
7,814✔
716
        return TRUE;
15,637✔
717
    }
718

719

720
    if( nPMCode == KvUserDefined )
35✔
721
        return FALSE;
13✔
722

723
/* -------------------------------------------------------------------- */
724
/*      Search the database.                                            */
725
/* -------------------------------------------------------------------- */
726
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
22✔
727
    {
728
        char szCode[12];
729

730
        snprintf(szCode, sizeof(szCode), "%d", nPMCode);
22✔
731
        PJ* pm = proj_create_from_database(
22✔
732
            ctx, "EPSG", szCode, PJ_CATEGORY_PRIME_MERIDIAN, 0, NULL);
733
        if( !pm )
22✔
734
        {
735
            return FALSE;
×
736
        }
737

738
        if( ppszName )
22✔
739
        {
740
            const char* pszName = proj_get_name(pm);
11✔
741
            if( !pszName )
11✔
742
            {
743
                // shouldn't happen
744
                proj_destroy(pm);
×
745
                return FALSE;
×
746
            }
747
            *ppszName = CPLStrdup(pszName);
11✔
748
        }
749

750
        if( pdfOffset )
22✔
751
        {
752
            double conv_factor = 0;
11✔
753
            proj_prime_meridian_get_parameters(
11✔
754
                ctx, pm, pdfOffset, &conv_factor, NULL);
755
            *pdfOffset *= conv_factor * 180.0 / M_PI;
11✔
756
        }
757

758
        proj_destroy(pm);
22✔
759

760
        return TRUE;
22✔
761
    }
762
}
763

764
int GTIFGetPMInfo( int nPMCode, char ** ppszName, double *pdfOffset )
20✔
765

766
{
767
    PJ_CONTEXT* ctx = proj_context_create();
20✔
768
    const int ret = GTIFGetPMInfoEx(ctx, nPMCode, ppszName, pdfOffset);
20✔
769
    proj_context_destroy(ctx);
20✔
770
    return ret;
20✔
771
}
772

773
/************************************************************************/
774
/*                          GTIFGetDatumInfo()                          */
775
/*                                                                      */
776
/*      Fetch the ellipsoid, and name for a datum.                      */
777
/************************************************************************/
778

779
int GTIFGetDatumInfoEx( void* ctxIn,
15,713✔
780
                        int nDatumCode, char ** ppszName, short * pnEllipsoid )
781

782
{
783
    const char* pszName = NULL;
15,713✔
784
    int                nEllipsoid = 0;
15,713✔
785

786
/* -------------------------------------------------------------------- */
787
/*      Handle a few built-in datums.                                   */
788
/* -------------------------------------------------------------------- */
789
    if( nDatumCode == Datum_North_American_Datum_1927 )
15,713✔
790
    {
791
        nEllipsoid = Ellipse_Clarke_1866;
6,440✔
792
        pszName = "North American Datum 1927";
6,440✔
793
    }
794
    else if( nDatumCode == Datum_North_American_Datum_1983 )
9,273✔
795
    {
796
        nEllipsoid = Ellipse_GRS_1980;
38✔
797
        pszName = "North American Datum 1983";
38✔
798
    }
799
    else if( nDatumCode == Datum_WGS84 )
9,235✔
800
    {
801
        nEllipsoid = Ellipse_WGS_84;
9,008✔
802
        pszName = "World Geodetic System 1984";
9,008✔
803
    }
804
    else if( nDatumCode == Datum_WGS72 )
227✔
805
    {
806
        nEllipsoid = 7043; /* WGS72 */
10✔
807
        pszName = "World Geodetic System 1972";
10✔
808
    }
809

810
    if (pszName != NULL)
15,713✔
811
    {
812
        if( pnEllipsoid != NULL )
15,496✔
813
            *pnEllipsoid = (short) nEllipsoid;
7,753✔
814

815
        if( ppszName != NULL )
15,496✔
816
            *ppszName = CPLStrdup( pszName );
7,743✔
817

818
        return TRUE;
15,496✔
819
    }
820

821
    if( nDatumCode == KvUserDefined )
217✔
822
        return FALSE;
13✔
823

824
/* -------------------------------------------------------------------- */
825
/*      Search the database.                                            */
826
/* -------------------------------------------------------------------- */
827
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
204✔
828
    {
829
        char szCode[12];
830

831
        snprintf(szCode, sizeof(szCode), "%d", nDatumCode);
204✔
832
        PJ* datum = proj_create_from_database(
204✔
833
            ctx, "EPSG", szCode, PJ_CATEGORY_DATUM, 0, NULL);
834
        if( !datum )
204✔
835
        {
836
            return FALSE;
2✔
837
        }
838

839
        const PJ_TYPE pjType = proj_get_type(datum);
202✔
840
        if( pjType != PJ_TYPE_GEODETIC_REFERENCE_FRAME &&
202✔
841
            pjType != PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME )
842
        {
843
            proj_destroy(datum);
×
844
            return FALSE;
×
845
        }
846

847
        if( ppszName )
202✔
848
        {
849
            pszName = proj_get_name(datum);
101✔
850
            if( !pszName )
101✔
851
            {
852
                // shouldn't happen
853
                proj_destroy(datum);
×
854
                return FALSE;
×
855
            }
856
            *ppszName = CPLStrdup(pszName);
101✔
857
        }
858

859
        if( pnEllipsoid )
202✔
860
        {
861
            PJ* ellipsoid = proj_get_ellipsoid(ctx, datum);
101✔
862
            if( !ellipsoid )
101✔
863
            {
864
                proj_destroy(datum);
×
865
                return FALSE;
×
866
            }
867

868
            {
869
                const char* pszEllipsoidCode = proj_get_id_code(
101✔
870
                    ellipsoid, 0);
871
                assert( pszEllipsoidCode );
101✔
872
                *pnEllipsoid = (short) atoi(pszEllipsoidCode);
101✔
873
            }
874

875
            proj_destroy(ellipsoid);
101✔
876
        }
877

878
        proj_destroy(datum);
202✔
879

880
        return TRUE;
202✔
881
    }
882
}
883

884
int GTIFGetDatumInfo( int nDatumCode, char ** ppszName, short * pnEllipsoid )
20✔
885

886
{
887
    PJ_CONTEXT* ctx = proj_context_create();
20✔
888
    const int ret = GTIFGetDatumInfoEx(ctx, nDatumCode, ppszName, pnEllipsoid);
20✔
889
    proj_context_destroy(ctx);
20✔
890
    return ret;
20✔
891
}
892

893
/************************************************************************/
894
/*                        GTIFGetUOMLengthInfo()                        */
895
/*                                                                      */
896
/*      Note: This function should eventually also know how to          */
897
/*      lookup length aliases in the UOM_LE_ALIAS table.                */
898
/************************************************************************/
899

900
int GTIFGetUOMLengthInfoEx( void* ctxIn,
8,109✔
901
                            int nUOMLengthCode,
902
                            char **ppszUOMName,
903
                            double * pdfInMeters )
904

905
{
906
/* -------------------------------------------------------------------- */
907
/*      We short cut meter to save work and avoid failure for missing   */
908
/*      in the most common cases.                                       */
909
/* -------------------------------------------------------------------- */
910
    if( nUOMLengthCode == 9001 )
8,109✔
911
    {
912
        if( ppszUOMName != NULL )
8,044✔
913
            *ppszUOMName = CPLStrdup( "metre" );
4,052✔
914
        if( pdfInMeters != NULL )
8,044✔
915
            *pdfInMeters = 1.0;
3,992✔
916

917
        return TRUE;
8,044✔
918
    }
919

920
    if( nUOMLengthCode == 9002 )
65✔
921
    {
922
        if( ppszUOMName != NULL )
×
923
            *ppszUOMName = CPLStrdup( "foot" );
×
924
        if( pdfInMeters != NULL )
×
925
            *pdfInMeters = 0.3048;
×
926

927
        return TRUE;
×
928
    }
929

930
    if( nUOMLengthCode == 9003 )
65✔
931
    {
932
        if( ppszUOMName != NULL )
55✔
933
            *ppszUOMName = CPLStrdup( "US survey foot" );
34✔
934
        if( pdfInMeters != NULL )
55✔
935
            *pdfInMeters = 12.0 / 39.37;
21✔
936

937
        return TRUE;
55✔
938
    }
939

940
    if( nUOMLengthCode == KvUserDefined )
10✔
941
        return FALSE;
8✔
942

943
/* -------------------------------------------------------------------- */
944
/*      Search the units database for this unit.  If we don't find      */
945
/*      it return failure.                                              */
946
/* -------------------------------------------------------------------- */
947
    char szCode[12];
948
    const char* pszName = NULL;
2✔
949

950
    snprintf(szCode, sizeof(szCode), "%d", nUOMLengthCode);
2✔
951
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
2✔
952
    if( !proj_uom_get_info_from_database(
2✔
953
        ctx, "EPSG", szCode, &pszName, pdfInMeters,  NULL) )
954
    {
955
        return FALSE;
×
956
    }
957
    if( ppszUOMName )
2✔
958
    {
959
        *ppszUOMName = CPLStrdup(pszName);
1✔
960
    }
961
    return TRUE;
2✔
962
}
963

964
int GTIFGetUOMLengthInfo( int nUOMLengthCode,
117✔
965
                          char **ppszUOMName,
966
                          double * pdfInMeters )
967

968
{
969
    PJ_CONTEXT* ctx = proj_context_create();
117✔
970
    const int ret = GTIFGetUOMLengthInfoEx(
117✔
971
        ctx, nUOMLengthCode, ppszUOMName, pdfInMeters);
972
    proj_context_destroy(ctx);
117✔
973
    return ret;
117✔
974
}
975

976
/************************************************************************/
977
/*                        GTIFGetUOMAngleInfo()                         */
978
/************************************************************************/
979

980
int GTIFGetUOMAngleInfoEx( void* ctxIn,
16,541✔
981
                           int nUOMAngleCode,
982
                           char **ppszUOMName,
983
                           double * pdfInDegrees )
984

985
{
986
    const char        *pszUOMName = NULL;
16,541✔
987
    double        dfInDegrees = 1.0;
16,541✔
988

989
    switch( nUOMAngleCode )
16,541✔
990
    {
991
      case 9101:
4✔
992
        pszUOMName = "radian";
4✔
993
        dfInDegrees = 180.0 / M_PI;
4✔
994
        break;
4✔
995

996
      case 9102:
16,490✔
997
      case 9107:
998
      case 9108:
999
      case 9110:
1000
      case 9122:
1001
        pszUOMName = "degree";
16,490✔
1002
        dfInDegrees = 1.0;
16,490✔
1003
        break;
16,490✔
1004

1005
      case 9103:
4✔
1006
        pszUOMName = "arc-minute";
4✔
1007
        dfInDegrees = 1 / 60.0;
4✔
1008
        break;
4✔
1009

1010
      case 9104:
6✔
1011
        pszUOMName = "arc-second";
6✔
1012
        dfInDegrees = 1 / 3600.0;
6✔
1013
        break;
6✔
1014

1015
      case 9105:
22✔
1016
        pszUOMName = "grad";
22✔
1017
        dfInDegrees = 180.0 / 200.0;
22✔
1018
        break;
22✔
1019

1020
      case 9106:
4✔
1021
        pszUOMName = "gon";
4✔
1022
        dfInDegrees = 180.0 / 200.0;
4✔
1023
        break;
4✔
1024

1025
      case 9109:
×
1026
        pszUOMName = "microradian";
×
1027
        dfInDegrees = 180.0 / (M_PI * 1000000.0);
×
1028
        break;
×
1029

1030
      default:
11✔
1031
        break;
11✔
1032
    }
1033

1034
    if (pszUOMName)
16,541✔
1035
    {
1036
        if( ppszUOMName != NULL )
16,530✔
1037
        {
1038
            *ppszUOMName = CPLStrdup( pszUOMName );
7,896✔
1039
        }
1040

1041
        if( pdfInDegrees != NULL )
16,530✔
1042
            *pdfInDegrees = dfInDegrees;
16,520✔
1043

1044
        return TRUE;
16,530✔
1045
    }
1046

1047
    if( nUOMAngleCode == KvUserDefined )
11✔
1048
        return FALSE;
11✔
1049

1050
/* -------------------------------------------------------------------- */
1051
/*      Search the units database for this unit.  If we don't find      */
1052
/*      it return failure.                                              */
1053
/* -------------------------------------------------------------------- */
1054
    char szCode[12];
UNCOV
1055
    const char* pszName = NULL;
×
UNCOV
1056
    double dfConvFactorToRadians = 0;
×
1057

UNCOV
1058
    snprintf(szCode, sizeof(szCode), "%d", nUOMAngleCode);
×
UNCOV
1059
    PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
×
UNCOV
1060
    if( !proj_uom_get_info_from_database(
×
1061
        ctx, "EPSG", szCode, &pszName, &dfConvFactorToRadians, NULL) )
1062
    {
1063
        return FALSE;
×
1064
    }
1065
    if( ppszUOMName )
×
1066
    {
1067
        *ppszUOMName = CPLStrdup(pszName);
×
1068
    }
1069
    if( pdfInDegrees )
×
1070
    {
1071
        *pdfInDegrees = dfConvFactorToRadians * 180.0 / M_PI;
×
1072
    }
1073
    return TRUE;
×
1074
}
1075

1076
int GTIFGetUOMAngleInfo( int nUOMAngleCode,
420✔
1077
                         char **ppszUOMName,
1078
                         double * pdfInDegrees )
1079

1080
{
1081
    PJ_CONTEXT* ctx = proj_context_create();
420✔
1082
    const int ret = GTIFGetUOMAngleInfoEx(
420✔
1083
        ctx, nUOMAngleCode, ppszUOMName, pdfInDegrees);
1084
    proj_context_destroy(ctx);
420✔
1085
    return ret;
420✔
1086
}
1087

1088
/************************************************************************/
1089
/*                    EPSGProjMethodToCTProjMethod()                    */
1090
/*                                                                      */
1091
/*      Convert between the EPSG enumeration for projection methods,    */
1092
/*      and the GeoTIFF CT codes.                                       */
1093
/************************************************************************/
1094

1095
static int EPSGProjMethodToCTProjMethod( int nEPSG, int bReturnExtendedCTCode )
7,370✔
1096

1097
{
1098
    switch( nEPSG )
7,370✔
1099
    {
1100
      case 9801:
21✔
1101
        return CT_LambertConfConic_1SP;
21✔
1102

1103
      case 9802:
12✔
1104
        return CT_LambertConfConic_2SP;
12✔
1105

1106
      case 9803:
×
1107
        return CT_LambertConfConic_2SP; /* Belgian variant not supported */
×
1108

1109
      case 9804:
3✔
1110
        return CT_Mercator;  /* 1SP and 2SP not differentiated */
3✔
1111

1112
      case 9805:
3✔
1113
        if( bReturnExtendedCTCode )
3✔
1114
            return CT_Ext_Mercator_2SP;
2✔
1115
        else
1116
            return CT_Mercator;  /* 1SP and 2SP not differentiated */
1✔
1117

1118
      /* Mercator 1SP (Spherical) For EPSG:3785 */
1119
      case 9841:
×
1120
        return CT_Mercator;  /* 1SP and 2SP not differentiated */
×
1121

1122
      /* Google Mercator For EPSG:3857 */
1123
      case 1024:
267✔
1124
        return CT_Mercator;  /* 1SP and 2SP not differentiated */
267✔
1125

1126
      case 9806:
3✔
1127
        return CT_CassiniSoldner;
3✔
1128

1129
      case 9807:
6,986✔
1130
        return CT_TransverseMercator;
6,986✔
1131

1132
      case 9808:
×
1133
        return CT_TransvMercator_SouthOriented;
×
1134

1135
      case 9809:
12✔
1136
        return CT_ObliqueStereographic;
12✔
1137

1138
      case 9810:
18✔
1139
      case 9829: /* variant B not quite the same - not sure how to handle */
1140
        return CT_PolarStereographic;
18✔
1141

1142
      case 9811:
3✔
1143
        return CT_NewZealandMapGrid;
3✔
1144

1145
      case 9812:
3✔
1146
        return CT_ObliqueMercator; /* is hotine actually different? */
3✔
1147

1148
      case 9813:
×
1149
        return CT_ObliqueMercator_Laborde;
×
1150

1151
      case 9814:
×
1152
        return CT_ObliqueMercator_Rosenmund; /* swiss  */
×
1153

1154
      case 9815:
6✔
1155
        return CT_HotineObliqueMercatorAzimuthCenter;
6✔
1156

1157
      case 9816: /* tunesia mining grid has no counterpart */
×
1158
        return KvUserDefined;
×
1159

1160
      case 9818:
3✔
1161
        return CT_Polyconic;
3✔
1162

1163
      case 9820:
3✔
1164
      case 1027:
1165
        return CT_LambertAzimEqualArea;
3✔
1166

1167
      case 9822:
3✔
1168
        return CT_AlbersEqualArea;
3✔
1169

1170
      case 9834:
×
1171
        return CT_CylindricalEqualArea;
×
1172

1173
      case 1028:
9✔
1174
      case 1029:
1175
      case 9823: /* spherical */
1176
      case 9842: /* elliptical */
1177
        return CT_Equirectangular;
9✔
1178

1179
      default: /* use the EPSG code for other methods */
15✔
1180
        return nEPSG;
15✔
1181
    }
1182
}
1183

1184
/************************************************************************/
1185
/*                           SetGTParamIds()                            */
1186
/*                                                                      */
1187
/*      This is hardcoded logic to set the GeoTIFF parameter            */
1188
/*      identifiers for all the EPSG supported projections.  As new     */
1189
/*      projection methods are added, this code will need to be updated */
1190
/************************************************************************/
1191

1192
static int SetGTParamIds( int nCTProjection,
3,778✔
1193
                          int nEPSGProjMethod,
1194
                          int *panProjParamId,
1195
                          int *panEPSGCodes )
1196

1197
{
1198
    int anWorkingDummy[7];
1199

1200
    if( panEPSGCodes == NULL )
3,778✔
1201
        panEPSGCodes = anWorkingDummy;
3,592✔
1202
    if( panProjParamId == NULL )
3,778✔
1203
        panProjParamId = anWorkingDummy;
186✔
1204

1205
    memset( panEPSGCodes, 0, sizeof(int) * 7 );
3,778✔
1206

1207
    /* psDefn->nParms = 7; */
1208

1209
    switch( nCTProjection )
3,778✔
1210
    {
1211
      case CT_CassiniSoldner:
6✔
1212
      case CT_NewZealandMapGrid:
1213
      case CT_Polyconic:
1214
        panProjParamId[0] = ProjNatOriginLatGeoKey;
6✔
1215
        panProjParamId[1] = ProjNatOriginLongGeoKey;
6✔
1216
        panProjParamId[5] = ProjFalseEastingGeoKey;
6✔
1217
        panProjParamId[6] = ProjFalseNorthingGeoKey;
6✔
1218

1219
        panEPSGCodes[0] = EPSGNatOriginLat;
6✔
1220
        panEPSGCodes[1] = EPSGNatOriginLong;
6✔
1221
        panEPSGCodes[5] = EPSGFalseEasting;
6✔
1222
        panEPSGCodes[6] = EPSGFalseNorthing;
6✔
1223
        return TRUE;
6✔
1224

1225
      case CT_ObliqueMercator:
6✔
1226
      case CT_HotineObliqueMercatorAzimuthCenter:
1227
        panProjParamId[0] = ProjCenterLatGeoKey;
6✔
1228
        panProjParamId[1] = ProjCenterLongGeoKey;
6✔
1229
        panProjParamId[2] = ProjAzimuthAngleGeoKey;
6✔
1230
        panProjParamId[3] = ProjRectifiedGridAngleGeoKey;
6✔
1231
        panProjParamId[4] = ProjScaleAtCenterGeoKey;
6✔
1232
        panProjParamId[5] = ProjFalseEastingGeoKey;
6✔
1233
        panProjParamId[6] = ProjFalseNorthingGeoKey;
6✔
1234

1235
        panEPSGCodes[0] = EPSGProjCenterLat;
6✔
1236
        panEPSGCodes[1] = EPSGProjCenterLong;
6✔
1237
        panEPSGCodes[2] = EPSGAzimuth;
6✔
1238
        panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
6✔
1239
        panEPSGCodes[4] = EPSGInitialLineScaleFactor;
6✔
1240
        panEPSGCodes[5] = EPSGProjCenterEasting; /* EPSG proj method 9812 uses EPSGFalseEasting, but 9815 uses EPSGProjCenterEasting */
6✔
1241
        panEPSGCodes[6] = EPSGProjCenterNorthing; /* EPSG proj method 9812 uses EPSGFalseNorthing, but 9815 uses EPSGProjCenterNorthing */
6✔
1242
        return TRUE;
6✔
1243

1244
      case CT_ObliqueMercator_Laborde:
×
1245
        panProjParamId[0] = ProjCenterLatGeoKey;
×
1246
        panProjParamId[1] = ProjCenterLongGeoKey;
×
1247
        panProjParamId[2] = ProjAzimuthAngleGeoKey;
×
1248
        panProjParamId[4] = ProjScaleAtCenterGeoKey;
×
1249
        panProjParamId[5] = ProjFalseEastingGeoKey;
×
1250
        panProjParamId[6] = ProjFalseNorthingGeoKey;
×
1251

1252
        panEPSGCodes[0] = EPSGProjCenterLat;
×
1253
        panEPSGCodes[1] = EPSGProjCenterLong;
×
1254
        panEPSGCodes[2] = EPSGAzimuth;
×
1255
        panEPSGCodes[4] = EPSGInitialLineScaleFactor;
×
1256
        panEPSGCodes[5] = EPSGFalseEasting;
×
1257
        panEPSGCodes[6] = EPSGFalseNorthing;
×
1258
        return TRUE;
×
1259

1260
      case CT_LambertConfConic_1SP:
3,736✔
1261
      case CT_Mercator:
1262
      case CT_ObliqueStereographic:
1263
      case CT_PolarStereographic:
1264
      case CT_TransverseMercator:
1265
      case CT_TransvMercator_SouthOriented:
1266
        panProjParamId[0] = ProjNatOriginLatGeoKey;
3,736✔
1267
        if( nCTProjection == CT_PolarStereographic )
3,736✔
1268
        {
1269
            panProjParamId[1] = ProjStraightVertPoleLongGeoKey;
12✔
1270
        }
1271
        else
1272
        {
1273
            panProjParamId[1] = ProjNatOriginLongGeoKey;
3,724✔
1274
        }
1275
        if( nEPSGProjMethod == 9805 ) /* Mercator_2SP */
3,736✔
1276
        {
1277
            panProjParamId[2] = ProjStdParallel1GeoKey;
×
1278
        }
1279
        panProjParamId[4] = ProjScaleAtNatOriginGeoKey;
3,736✔
1280
        panProjParamId[5] = ProjFalseEastingGeoKey;
3,736✔
1281
        panProjParamId[6] = ProjFalseNorthingGeoKey;
3,736✔
1282

1283
        panEPSGCodes[0] = EPSGNatOriginLat;
3,736✔
1284
        panEPSGCodes[1] = EPSGNatOriginLong;
3,736✔
1285
        if( nEPSGProjMethod == 9805 ) /* Mercator_2SP */
3,736✔
1286
        {
1287
            panEPSGCodes[2] = EPSGStdParallel1Lat;
×
1288
        }
1289
        panEPSGCodes[4] = EPSGNatOriginScaleFactor;
3,736✔
1290
        panEPSGCodes[5] = EPSGFalseEasting;
3,736✔
1291
        panEPSGCodes[6] = EPSGFalseNorthing;
3,736✔
1292
        return TRUE;
3,736✔
1293

1294
      case CT_LambertConfConic_2SP:
8✔
1295
        panProjParamId[0] = ProjFalseOriginLatGeoKey;
8✔
1296
        panProjParamId[1] = ProjFalseOriginLongGeoKey;
8✔
1297
        panProjParamId[2] = ProjStdParallel1GeoKey;
8✔
1298
        panProjParamId[3] = ProjStdParallel2GeoKey;
8✔
1299
        panProjParamId[5] = ProjFalseEastingGeoKey;
8✔
1300
        panProjParamId[6] = ProjFalseNorthingGeoKey;
8✔
1301

1302
        panEPSGCodes[0] = EPSGFalseOriginLat;
8✔
1303
        panEPSGCodes[1] = EPSGFalseOriginLong;
8✔
1304
        panEPSGCodes[2] = EPSGStdParallel1Lat;
8✔
1305
        panEPSGCodes[3] = EPSGStdParallel2Lat;
8✔
1306
        panEPSGCodes[5] = EPSGFalseOriginEasting;
8✔
1307
        panEPSGCodes[6] = EPSGFalseOriginNorthing;
8✔
1308
        return TRUE;
8✔
1309

1310
      case CT_AlbersEqualArea:
2✔
1311
        panProjParamId[0] = ProjStdParallel1GeoKey;
2✔
1312
        panProjParamId[1] = ProjStdParallel2GeoKey;
2✔
1313
        panProjParamId[2] = ProjNatOriginLatGeoKey;
2✔
1314
        panProjParamId[3] = ProjNatOriginLongGeoKey;
2✔
1315
        panProjParamId[5] = ProjFalseEastingGeoKey;
2✔
1316
        panProjParamId[6] = ProjFalseNorthingGeoKey;
2✔
1317

1318
        panEPSGCodes[0] = EPSGStdParallel1Lat;
2✔
1319
        panEPSGCodes[1] = EPSGStdParallel2Lat;
2✔
1320
        panEPSGCodes[2] = EPSGFalseOriginLat;
2✔
1321
        panEPSGCodes[3] = EPSGFalseOriginLong;
2✔
1322
        panEPSGCodes[5] = EPSGFalseOriginEasting;
2✔
1323
        panEPSGCodes[6] = EPSGFalseOriginNorthing;
2✔
1324
        return TRUE;
2✔
1325

1326
      case CT_SwissObliqueCylindrical:
×
1327
        panProjParamId[0] = ProjCenterLatGeoKey;
×
1328
        panProjParamId[1] = ProjCenterLongGeoKey;
×
1329
        panProjParamId[5] = ProjFalseEastingGeoKey;
×
1330
        panProjParamId[6] = ProjFalseNorthingGeoKey;
×
1331

1332
        /* EPSG codes? */
1333
        return TRUE;
×
1334

1335
      case CT_LambertAzimEqualArea:
2✔
1336
        panProjParamId[0] = ProjCenterLatGeoKey;
2✔
1337
        panProjParamId[1] = ProjCenterLongGeoKey;
2✔
1338
        panProjParamId[5] = ProjFalseEastingGeoKey;
2✔
1339
        panProjParamId[6] = ProjFalseNorthingGeoKey;
2✔
1340

1341
        panEPSGCodes[0] = EPSGNatOriginLat;
2✔
1342
        panEPSGCodes[1] = EPSGNatOriginLong;
2✔
1343
        panEPSGCodes[5] = EPSGFalseEasting;
2✔
1344
        panEPSGCodes[6] = EPSGFalseNorthing;
2✔
1345
        return TRUE;
2✔
1346

1347
      case CT_CylindricalEqualArea:
×
1348
        panProjParamId[0] = ProjStdParallel1GeoKey;
×
1349
        panProjParamId[1] = ProjNatOriginLongGeoKey;
×
1350
        panProjParamId[5] = ProjFalseEastingGeoKey;
×
1351
        panProjParamId[6] = ProjFalseNorthingGeoKey;
×
1352

1353
        panEPSGCodes[0] = EPSGStdParallel1Lat;
×
1354
        panEPSGCodes[1] = EPSGFalseOriginLong;
×
1355
        panEPSGCodes[5] = EPSGFalseOriginEasting;
×
1356
        panEPSGCodes[6] = EPSGFalseOriginNorthing;
×
1357
        return TRUE;
×
1358

1359
      case CT_Equirectangular:
6✔
1360
        panProjParamId[0] = ProjCenterLatGeoKey;
6✔
1361
        panProjParamId[1] = ProjCenterLongGeoKey;
6✔
1362
        panProjParamId[2] = ProjStdParallel1GeoKey;
6✔
1363
        panProjParamId[5] = ProjFalseEastingGeoKey;
6✔
1364
        panProjParamId[6] = ProjFalseNorthingGeoKey;
6✔
1365

1366
        panEPSGCodes[0] = EPSGNatOriginLat;
6✔
1367
        panEPSGCodes[1] = EPSGNatOriginLong;
6✔
1368
        panEPSGCodes[2] = EPSGStdParallel1Lat;
6✔
1369
        panEPSGCodes[5] = EPSGFalseEasting;
6✔
1370
        panEPSGCodes[6] = EPSGFalseNorthing;
6✔
1371
        return TRUE;
6✔
1372

1373
      case CT_Ext_Mercator_2SP:
2✔
1374
        panProjParamId[0] = ProjNatOriginLatGeoKey;
2✔
1375
        panProjParamId[1] = ProjNatOriginLongGeoKey;
2✔
1376
        panProjParamId[2] = ProjStdParallel1GeoKey;
2✔
1377
        panProjParamId[5] = ProjFalseEastingGeoKey;
2✔
1378
        panProjParamId[6] = ProjFalseNorthingGeoKey;
2✔
1379

1380
        panEPSGCodes[0] = EPSGNatOriginLat;
2✔
1381
        panEPSGCodes[1] = EPSGNatOriginLong;
2✔
1382
        panEPSGCodes[2] = EPSGStdParallel1Lat;
2✔
1383
        panEPSGCodes[5] = EPSGFalseEasting;
2✔
1384
        panEPSGCodes[6] = EPSGFalseNorthing;
2✔
1385
        return TRUE;
2✔
1386

1387
      default:
10✔
1388
        return FALSE;
10✔
1389
    }
1390
}
1391

1392
/************************************************************************/
1393
/*                         GTIFGetProjTRFInfo()                         */
1394
/*                                                                      */
1395
/*      Transform a PROJECTION_TRF_CODE into a projection method,       */
1396
/*      and a set of parameters.  The parameters identify will          */
1397
/*      depend on the returned method, but they will all have been      */
1398
/*      normalized into degrees and meters.                             */
1399
/************************************************************************/
1400

1401
int GTIFGetProjTRFInfoEx( void* ctxIn,
3,592✔
1402
                          int nProjTRFCode,
1403
                          char **ppszProjTRFName,
1404
                          short * pnProjMethod,
1405
                          double * padfProjParams )
1406

1407
{
1408
    if ((nProjTRFCode >= Proj_UTM_zone_1N && nProjTRFCode <= Proj_UTM_zone_60N) ||
3,592✔
1409
        (nProjTRFCode >= Proj_UTM_zone_1S && nProjTRFCode <= Proj_UTM_zone_60S))
50✔
1410
    {
1411
        int bNorth;
1412
        int nZone;
1413
        if (nProjTRFCode <= Proj_UTM_zone_60N)
3,406✔
1414
        {
1415
            bNorth = TRUE;
3,403✔
1416
            nZone = nProjTRFCode - Proj_UTM_zone_1N + 1;
3,403✔
1417
        }
1418
        else
1419
        {
1420
            bNorth = FALSE;
3✔
1421
            nZone = nProjTRFCode - Proj_UTM_zone_1S + 1;
3✔
1422
        }
1423

1424
        if (ppszProjTRFName)
3,406✔
1425
        {
1426
            char szProjTRFName[64];
1427
            snprintf(szProjTRFName, sizeof(szProjTRFName), "UTM zone %d%c",
×
1428
                     nZone, (bNorth) ? 'N' : 'S');
1429
            *ppszProjTRFName = CPLStrdup(szProjTRFName);
×
1430
        }
1431

1432
        if (pnProjMethod)
3,406✔
1433
            *pnProjMethod = 9807;
3,406✔
1434

1435
        if (padfProjParams)
3,406✔
1436
        {
1437
            padfProjParams[0] = 0;
3,406✔
1438
            padfProjParams[1] = -183 + 6 * nZone;
3,406✔
1439
            padfProjParams[2] = 0;
3,406✔
1440
            padfProjParams[3] = 0;
3,406✔
1441
            padfProjParams[4] = 0.9996;
3,406✔
1442
            padfProjParams[5] = 500000;
3,406✔
1443
            padfProjParams[6] = (bNorth) ? 0 : 10000000;
3,406✔
1444
        }
1445

1446
        return TRUE;
3,406✔
1447
    }
1448

1449
    if( nProjTRFCode == KvUserDefined )
186✔
1450
        return FALSE;
×
1451

1452
    {
1453
        char    szCode[12];
1454
        snprintf(szCode, sizeof(szCode), "%d", nProjTRFCode);
186✔
1455
        PJ_CONTEXT* ctx = (PJ_CONTEXT*)ctxIn;
186✔
1456
        PJ *transf = proj_create_from_database(
186✔
1457
            ctx, "EPSG", szCode, PJ_CATEGORY_COORDINATE_OPERATION, 0, NULL);
1458
        if( !transf )
186✔
1459
        {
1460
            return FALSE;
×
1461
        }
1462

1463
        if( proj_get_type(transf) != PJ_TYPE_CONVERSION )
186✔
1464
        {
1465
            proj_destroy(transf);
×
1466
            return FALSE;
×
1467
        }
1468

1469
        /* Get the projection method code */
1470
        const char* pszMethodCode = NULL;
186✔
1471
        proj_coordoperation_get_method_info(ctx, transf,
186✔
1472
                                            NULL, /* method name */
1473
                                            NULL, /* method auth name (should be EPSG) */
1474
                                            &pszMethodCode);
1475
        assert( pszMethodCode );
186✔
1476
        const int nProjMethod = atoi(pszMethodCode);
186✔
1477

1478
/* -------------------------------------------------------------------- */
1479
/*      Initialize a definition of what EPSG codes need to be loaded    */
1480
/*      into what fields in adfProjParams.                               */
1481
/* -------------------------------------------------------------------- */
1482
        const int nCTProjMethod = EPSGProjMethodToCTProjMethod( nProjMethod, TRUE );
186✔
1483
        int anEPSGCodes[7];
1484
        SetGTParamIds( nCTProjMethod, nProjMethod, NULL, anEPSGCodes );
186✔
1485

1486

1487
/* -------------------------------------------------------------------- */
1488
/*      Get the parameters for this projection.                         */
1489
/* -------------------------------------------------------------------- */
1490

1491
        double  adfProjParams[7];
1492

1493
        for( int i = 0; i < 7; i++ )
1,488✔
1494
        {
1495
            int nEPSGCode = anEPSGCodes[i];
1,302✔
1496

1497
            /* Establish default */
1498
            if( nEPSGCode == EPSGAngleRectifiedToSkewedGrid )
1,302✔
1499
                adfProjParams[i] = 90.0;
3✔
1500
            else if( nEPSGCode == EPSGNatOriginScaleFactor
1,299✔
1501
                    || nEPSGCode == EPSGInitialLineScaleFactor
1,134✔
1502
                    || nEPSGCode == EPSGPseudoStdParallelScaleFactor )
1,131✔
1503
                adfProjParams[i] = 1.0;
168✔
1504
            else
1505
                adfProjParams[i] = 0.0;
1,131✔
1506

1507
            /* If there is no parameter, skip */
1508
            if( nEPSGCode == 0 )
1,302✔
1509
                continue;
485✔
1510

1511
            const int nParamCount = proj_coordoperation_get_param_count(ctx, transf);
912✔
1512

1513
            /* Find the matching parameter */
1514
            const char *pszUOMCategory = NULL;
912✔
1515
            double  dfValue = 0.0;
912✔
1516
            double  dfUnitConvFactor = 0.0;
912✔
1517
            int iEPSG;  /* Used after for */
1518
            for( iEPSG = 0; iEPSG < nParamCount; iEPSG++ )
2,781✔
1519
            {
1520
                const char* pszParamCode = NULL;
2,680✔
1521
                proj_coordoperation_get_param(
2,680✔
1522
                    ctx, transf, iEPSG,
1523
                    NULL, /* name */
1524
                    NULL, /* auth name */
1525
                    &pszParamCode,
1526
                    &dfValue,
1527
                    NULL, /* value (string) */
1528
                    &dfUnitConvFactor, /* unit conv factor */
1529
                    NULL, /* unit name */
1530
                    NULL, /* unit auth name */
1531
                    NULL, /* unit code */
1532
                    &pszUOMCategory /* unit category */);
1533
                assert(pszParamCode);
2,680✔
1534
                if( atoi(pszParamCode) == nEPSGCode )
2,680✔
1535
                {
1536
                    break;
811✔
1537
                }
1538
            }
1539

1540
            /* not found, accept the default */
1541
            if( iEPSG == nParamCount )
912✔
1542
            {
1543
                /* for CT_ObliqueMercator try alternate parameter codes first */
1544
                /* because EPSG proj method 9812 uses EPSGFalseXXXXX, but 9815 uses EPSGProjCenterXXXXX */
1545
                if ( nCTProjMethod == CT_ObliqueMercator && nEPSGCode == EPSGProjCenterEasting )
101✔
1546
                    nEPSGCode = EPSGFalseEasting;
1✔
1547
                else if ( nCTProjMethod == CT_ObliqueMercator && nEPSGCode == EPSGProjCenterNorthing )
100✔
1548
                    nEPSGCode = EPSGFalseNorthing;
1✔
1549
                /* for CT_PolarStereographic try alternate parameter codes first */
1550
                /* because EPSG proj method 9829 uses EPSGLatOfStdParallel instead of EPSGNatOriginLat */
1551
                /* and EPSGOriginLong instead of EPSGNatOriginLong */
1552
                else if( nCTProjMethod == CT_PolarStereographic && nEPSGCode == EPSGNatOriginLat )
99✔
1553
                    nEPSGCode = EPSGLatOfStdParallel;
2✔
1554
                else if( nCTProjMethod == CT_PolarStereographic && nEPSGCode == EPSGNatOriginLong )
97✔
1555
                    nEPSGCode = EPSGOriginLong;
2✔
1556
                else
1557
                    continue;
95✔
1558

1559
                for( iEPSG = 0; iEPSG < nParamCount; iEPSG++ )
19✔
1560
                {
1561
                    const char* pszParamCode = NULL;
19✔
1562
                    proj_coordoperation_get_param(
19✔
1563
                        ctx, transf, iEPSG,
1564
                        NULL, /* name */
1565
                        NULL, /* auth name */
1566
                        &pszParamCode,
1567
                        &dfValue,
1568
                        NULL, /* value (string) */
1569
                        &dfUnitConvFactor, /* unit conv factor */
1570
                        NULL, /* unit name */
1571
                        NULL, /* unit auth name */
1572
                        NULL, /* unit code */
1573
                        &pszUOMCategory /* unit category */);
1574
                    assert(pszParamCode);
19✔
1575
                    if( atoi(pszParamCode) == nEPSGCode )
19✔
1576
                    {
1577
                        break;
6✔
1578
                    }
1579
                }
1580

1581
                if( iEPSG == nParamCount )
6✔
1582
                    continue;
×
1583
            }
1584

1585
            assert(pszUOMCategory);
817✔
1586

1587
            adfProjParams[i] = dfValue * dfUnitConvFactor;
817✔
1588
            if( strcmp(pszUOMCategory, "angular") == 0.0 )
817✔
1589
            {
1590
                /* Convert from radians to degrees */
1591
                adfProjParams[i] *= 180 / M_PI;
378✔
1592
            }
1593
        }
1594

1595
/* -------------------------------------------------------------------- */
1596
/*      Get the name, if requested.                                     */
1597
/* -------------------------------------------------------------------- */
1598
        if( ppszProjTRFName != NULL )
186✔
1599
        {
1600
            const char* pszName = proj_get_name(transf);
×
1601
            if( !pszName )
×
1602
            {
1603
                // shouldn't happen
1604
                proj_destroy(transf);
×
1605
                return FALSE;
×
1606
            }
1607
            *ppszProjTRFName = CPLStrdup(pszName);
×
1608
        }
1609

1610
/* -------------------------------------------------------------------- */
1611
/*      Transfer requested data into passed variables.                  */
1612
/* -------------------------------------------------------------------- */
1613
        if( pnProjMethod != NULL )
186✔
1614
            *pnProjMethod = (short) nProjMethod;
186✔
1615

1616
        if( padfProjParams != NULL )
186✔
1617
        {
1618
            for( int i = 0; i < 7; i++ )
1,488✔
1619
                padfProjParams[i] = adfProjParams[i];
1,302✔
1620
        }
1621

1622
        proj_destroy(transf);
186✔
1623

1624
        return TRUE;
186✔
1625
    }
1626
}
1627

1628
int GTIFGetProjTRFInfo( /* Conversion code */
×
1629
                        int nProjTRFCode,
1630
                        char **ppszProjTRFName,
1631
                        short * pnProjMethod,
1632
                        double * padfProjParams )
1633
{
1634
    PJ_CONTEXT* ctx = proj_context_create();
×
1635
    const int ret = GTIFGetProjTRFInfoEx(
×
1636
        ctx, nProjTRFCode, ppszProjTRFName, pnProjMethod, padfProjParams);
1637
    proj_context_destroy(ctx);
×
1638
    return ret;
×
1639
}
1640

1641
/************************************************************************/
1642
/*                         GTIFFetchProjParms()                         */
1643
/*                                                                      */
1644
/*      Fetch the projection parameters for a particular projection     */
1645
/*      from a GeoTIFF file, and fill the GTIFDefn structure out        */
1646
/*      with them.                                                      */
1647
/************************************************************************/
1648

1649
static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
87✔
1650
{
1651

1652
/* -------------------------------------------------------------------- */
1653
/*      Get the false easting, and northing if available.               */
1654
/* -------------------------------------------------------------------- */
1655
    double dfFalseEasting = 0.0;
87✔
1656
    if( !GTIFKeyGetDOUBLE(psGTIF, ProjFalseEastingGeoKey, &dfFalseEasting, 0, 1)
87✔
1657
        && !GTIFKeyGetDOUBLE(psGTIF, ProjCenterEastingGeoKey,
15✔
1658
                       &dfFalseEasting, 0, 1)
1659
        && !GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginEastingGeoKey,
15✔
1660
                       &dfFalseEasting, 0, 1) )
1661
        dfFalseEasting = 0.0;
×
1662

1663
    double dfFalseNorthing = 0.0;
87✔
1664
    if( !GTIFKeyGetDOUBLE(psGTIF, ProjFalseNorthingGeoKey, &dfFalseNorthing,0,1)
87✔
1665
        && !GTIFKeyGetDOUBLE(psGTIF, ProjCenterNorthingGeoKey,
15✔
1666
                       &dfFalseNorthing, 0, 1)
1667
        && !GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginNorthingGeoKey,
15✔
1668
                       &dfFalseNorthing, 0, 1) )
1669
        dfFalseNorthing = 0.0;
×
1670

1671
    double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
87✔
1672
    double dfNatOriginScale = 1.0;
87✔
1673
    double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
87✔
1674

1675
    switch( psDefn->CTProjection )
87✔
1676
    {
1677
/* -------------------------------------------------------------------- */
1678
      case CT_Stereographic:
×
1679
/* -------------------------------------------------------------------- */
1680
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
×
1681
                       &dfNatOriginLong, 0, 1 ) == 0
1682
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
1683
                          &dfNatOriginLong, 0, 1 ) == 0
1684
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
1685
                          &dfNatOriginLong, 0, 1 ) == 0 )
1686
            dfNatOriginLong = 0.0;
×
1687

1688
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
×
1689
                       &dfNatOriginLat, 0, 1 ) == 0
1690
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
1691
                          &dfNatOriginLat, 0, 1 ) == 0
1692
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
1693
                          &dfNatOriginLat, 0, 1 ) == 0 )
1694
            dfNatOriginLat = 0.0;
×
1695

1696
        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
×
1697
                       &dfNatOriginScale, 0, 1 ) == 0 )
1698
            dfNatOriginScale = 1.0;
×
1699

1700
        /* notdef: should transform to decimal degrees at this point */
1701

1702
        psDefn->ProjParm[0] = dfNatOriginLat;
×
1703
        psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
×
1704
        psDefn->ProjParm[1] = dfNatOriginLong;
×
1705
        psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
×
1706
        psDefn->ProjParm[4] = dfNatOriginScale;
×
1707
        psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
×
1708
        psDefn->ProjParm[5] = dfFalseEasting;
×
1709
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
×
1710
        psDefn->ProjParm[6] = dfFalseNorthing;
×
1711
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
×
1712

1713
        psDefn->nParms = 7;
×
1714
        break;
×
1715

1716
/* -------------------------------------------------------------------- */
1717
      case CT_Mercator:
11✔
1718
/* -------------------------------------------------------------------- */
1719
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
11✔
1720
                       &dfNatOriginLong, 0, 1 ) == 0
1721
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
1722
                          &dfNatOriginLong, 0, 1 ) == 0
1723
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
1724
                          &dfNatOriginLong, 0, 1 ) == 0 )
1725
            dfNatOriginLong = 0.0;
×
1726

1727
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
11✔
1728
                       &dfNatOriginLat, 0, 1 ) == 0
1729
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
1730
                          &dfNatOriginLat, 0, 1 ) == 0
1731
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
1732
                          &dfNatOriginLat, 0, 1 ) == 0 )
1733
            dfNatOriginLat = 0.0;
×
1734

1735

1736
        const int bHaveSP1 = GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey,
11✔
1737
                              &dfStdParallel1, 0, 1 );
1738

1739
        int bHaveNOS = GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
11✔
1740
                              &dfNatOriginScale, 0, 1 );
1741

1742
        /* Default scale only if dfStdParallel1 isn't defined either */
1743
        if( !bHaveNOS && !bHaveSP1)
11✔
1744
        {
1745
            bHaveNOS = TRUE;
×
1746
            dfNatOriginScale = 1.0;
×
1747
        }
1748

1749
        /* notdef: should transform to decimal degrees at this point */
1750

1751
        psDefn->ProjParm[0] = dfNatOriginLat;
11✔
1752
        psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
11✔
1753
        psDefn->ProjParm[1] = dfNatOriginLong;
11✔
1754
        psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
11✔
1755
        if( bHaveSP1 )
11✔
1756
        {
1757
            psDefn->ProjParm[2] = dfStdParallel1;
3✔
1758
            psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
3✔
1759
        }
1760
        if( bHaveNOS )
11✔
1761
        {
1762
            psDefn->ProjParm[4] = dfNatOriginScale;
10✔
1763
            psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
10✔
1764
        }
1765
        psDefn->ProjParm[5] = dfFalseEasting;
11✔
1766
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
11✔
1767
        psDefn->ProjParm[6] = dfFalseNorthing;
11✔
1768
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
11✔
1769

1770
        psDefn->nParms = 7;
11✔
1771
        break;
11✔
1772

1773
/* -------------------------------------------------------------------- */
1774
      case CT_LambertConfConic_1SP:
10✔
1775
      case CT_ObliqueStereographic:
1776
      case CT_TransverseMercator:
1777
      case CT_TransvMercator_SouthOriented:
1778
/* -------------------------------------------------------------------- */
1779
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
10✔
1780
                       &dfNatOriginLong, 0, 1 ) == 0
1781
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
1782
                          &dfNatOriginLong, 0, 1 ) == 0
1783
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
1784
                          &dfNatOriginLong, 0, 1 ) == 0 )
1785
            dfNatOriginLong = 0.0;
×
1786

1787
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
10✔
1788
                       &dfNatOriginLat, 0, 1 ) == 0
1789
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
1790
                          &dfNatOriginLat, 0, 1 ) == 0
1791
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
1792
                          &dfNatOriginLat, 0, 1 ) == 0 )
1793
            dfNatOriginLat = 0.0;
×
1794

1795
        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
10✔
1796
                       &dfNatOriginScale, 0, 1 ) == 0
1797
            /* See https://github.com/OSGeo/gdal/files/1665718/lasinfo.txt */
1798
            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
×
1799
                       &dfNatOriginScale, 0, 1 ) == 0 )
1800
            dfNatOriginScale = 1.0;
×
1801

1802
        /* notdef: should transform to decimal degrees at this point */
1803

1804
        psDefn->ProjParm[0] = dfNatOriginLat;
10✔
1805
        psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
10✔
1806
        psDefn->ProjParm[1] = dfNatOriginLong;
10✔
1807
        psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
10✔
1808
        psDefn->ProjParm[4] = dfNatOriginScale;
10✔
1809
        psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
10✔
1810
        psDefn->ProjParm[5] = dfFalseEasting;
10✔
1811
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
10✔
1812
        psDefn->ProjParm[6] = dfFalseNorthing;
10✔
1813
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
10✔
1814

1815
        psDefn->nParms = 7;
10✔
1816
        break;
10✔
1817

1818
/* -------------------------------------------------------------------- */
1819
      case CT_ObliqueMercator: /* hotine */
3✔
1820
      case CT_HotineObliqueMercatorAzimuthCenter:
1821
/* -------------------------------------------------------------------- */
1822
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
3✔
1823
                       &dfNatOriginLong, 0, 1 ) == 0
1824
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
3✔
1825
                          &dfNatOriginLong, 0, 1 ) == 0
1826
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
3✔
1827
                          &dfNatOriginLong, 0, 1 ) == 0 )
1828
            dfNatOriginLong = 0.0;
×
1829

1830
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
3✔
1831
                       &dfNatOriginLat, 0, 1 ) == 0
1832
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
3✔
1833
                          &dfNatOriginLat, 0, 1 ) == 0
1834
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
3✔
1835
                          &dfNatOriginLat, 0, 1 ) == 0 )
1836
            dfNatOriginLat = 0.0;
×
1837

1838
        if( GTIFKeyGetDOUBLE(psGTIF, ProjAzimuthAngleGeoKey,
3✔
1839
                       &dfAzimuth, 0, 1 ) == 0 )
1840
            dfAzimuth = 0.0;
×
1841

1842
        if( GTIFKeyGetDOUBLE(psGTIF, ProjRectifiedGridAngleGeoKey,
3✔
1843
                       &dfRectGridAngle, 0, 1 ) == 0 )
1844
            dfRectGridAngle = 90.0;
×
1845

1846
        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
3✔
1847
                       &dfNatOriginScale, 0, 1 ) == 0
1848
            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
3✔
1849
                          &dfNatOriginScale, 0, 1 ) == 0 )
1850
            dfNatOriginScale = 1.0;
×
1851

1852
        /* notdef: should transform to decimal degrees at this point */
1853

1854
        psDefn->ProjParm[0] = dfNatOriginLat;
3✔
1855
        psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
3✔
1856
        psDefn->ProjParm[1] = dfNatOriginLong;
3✔
1857
        psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
3✔
1858
        psDefn->ProjParm[2] = dfAzimuth;
3✔
1859
        psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
3✔
1860
        psDefn->ProjParm[3] = dfRectGridAngle;
3✔
1861
        psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
3✔
1862
        psDefn->ProjParm[4] = dfNatOriginScale;
3✔
1863
        psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
3✔
1864
        psDefn->ProjParm[5] = dfFalseEasting;
3✔
1865
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
3✔
1866
        psDefn->ProjParm[6] = dfFalseNorthing;
3✔
1867
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
3✔
1868

1869
        psDefn->nParms = 7;
3✔
1870
        break;
3✔
1871

1872
/* -------------------------------------------------------------------- */
1873
      case CT_ObliqueMercator_Laborde:
×
1874
/* -------------------------------------------------------------------- */
1875
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
×
1876
                       &dfNatOriginLong, 0, 1 ) == 0
1877
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
1878
                          &dfNatOriginLong, 0, 1 ) == 0
1879
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
1880
                          &dfNatOriginLong, 0, 1 ) == 0 )
1881
            dfNatOriginLong = 0.0;
×
1882

1883
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
×
1884
                       &dfNatOriginLat, 0, 1 ) == 0
1885
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
1886
                          &dfNatOriginLat, 0, 1 ) == 0
1887
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
1888
                          &dfNatOriginLat, 0, 1 ) == 0 )
1889
            dfNatOriginLat = 0.0;
×
1890

1891
        if( GTIFKeyGetDOUBLE(psGTIF, ProjAzimuthAngleGeoKey,
×
1892
                       &dfAzimuth, 0, 1 ) == 0 )
1893
            dfAzimuth = 0.0;
×
1894

1895
        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
×
1896
                       &dfNatOriginScale, 0, 1 ) == 0
1897
            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
×
1898
                          &dfNatOriginScale, 0, 1 ) == 0 )
1899
            dfNatOriginScale = 1.0;
×
1900

1901
        /* notdef: should transform to decimal degrees at this point */
1902

1903
        psDefn->ProjParm[0] = dfNatOriginLat;
×
1904
        psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
×
1905
        psDefn->ProjParm[1] = dfNatOriginLong;
×
1906
        psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
×
1907
        psDefn->ProjParm[2] = dfAzimuth;
×
1908
        psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
×
1909
        psDefn->ProjParm[4] = dfNatOriginScale;
×
1910
        psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
×
1911
        psDefn->ProjParm[5] = dfFalseEasting;
×
1912
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
×
1913
        psDefn->ProjParm[6] = dfFalseNorthing;
×
1914
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
×
1915

1916
        psDefn->nParms = 7;
×
1917
        break;
×
1918

1919
/* -------------------------------------------------------------------- */
1920
      case CT_CassiniSoldner:
2✔
1921
      case CT_Polyconic:
1922
/* -------------------------------------------------------------------- */
1923
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
2✔
1924
                       &dfNatOriginLong, 0, 1 ) == 0
1925
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
1926
                          &dfNatOriginLong, 0, 1 ) == 0
1927
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
1928
                          &dfNatOriginLong, 0, 1 ) == 0 )
1929
            dfNatOriginLong = 0.0;
×
1930

1931
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
2✔
1932
                       &dfNatOriginLat, 0, 1 ) == 0
1933
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
1934
                          &dfNatOriginLat, 0, 1 ) == 0
1935
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
1936
                          &dfNatOriginLat, 0, 1 ) == 0 )
1937
            dfNatOriginLat = 0.0;
×
1938

1939
        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
2✔
1940
                       &dfNatOriginScale, 0, 1 ) == 0
1941
            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
1✔
1942
                          &dfNatOriginScale, 0, 1 ) == 0 )
1943
            dfNatOriginScale = 1.0;
1✔
1944

1945
        /* notdef: should transform to decimal degrees at this point */
1946

1947
        psDefn->ProjParm[0] = dfNatOriginLat;
2✔
1948
        psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2✔
1949
        psDefn->ProjParm[1] = dfNatOriginLong;
2✔
1950
        psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2✔
1951
        psDefn->ProjParm[4] = dfNatOriginScale;
2✔
1952
        psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2✔
1953
        psDefn->ProjParm[5] = dfFalseEasting;
2✔
1954
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2✔
1955
        psDefn->ProjParm[6] = dfFalseNorthing;
2✔
1956
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2✔
1957

1958
        psDefn->nParms = 7;
2✔
1959
        break;
2✔
1960

1961
/* -------------------------------------------------------------------- */
1962
      case CT_AzimuthalEquidistant:
21✔
1963
      case CT_MillerCylindrical:
1964
      case CT_Gnomonic:
1965
      case CT_LambertAzimEqualArea:
1966
      case CT_Orthographic:
1967
      case CT_NewZealandMapGrid:
1968
/* -------------------------------------------------------------------- */
1969
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
21✔
1970
                       &dfNatOriginLong, 0, 1 ) == 0
1971
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
20✔
1972
                          &dfNatOriginLong, 0, 1 ) == 0
1973
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
20✔
1974
                          &dfNatOriginLong, 0, 1 ) == 0 )
1975
            dfNatOriginLong = 0.0;
×
1976

1977
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
21✔
1978
                       &dfNatOriginLat, 0, 1 ) == 0
1979
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
20✔
1980
                          &dfNatOriginLat, 0, 1 ) == 0
1981
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
20✔
1982
                          &dfNatOriginLat, 0, 1 ) == 0 )
1983
            dfNatOriginLat = 0.0;
×
1984

1985
        /* notdef: should transform to decimal degrees at this point */
1986

1987
        psDefn->ProjParm[0] = dfNatOriginLat;
21✔
1988
        psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
21✔
1989
        psDefn->ProjParm[1] = dfNatOriginLong;
21✔
1990
        psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
21✔
1991
        psDefn->ProjParm[5] = dfFalseEasting;
21✔
1992
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
21✔
1993
        psDefn->ProjParm[6] = dfFalseNorthing;
21✔
1994
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
21✔
1995

1996
        psDefn->nParms = 7;
21✔
1997
        break;
21✔
1998

1999
/* -------------------------------------------------------------------- */
2000
      case CT_Equirectangular:
5✔
2001
/* -------------------------------------------------------------------- */
2002
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
5✔
2003
                       &dfNatOriginLong, 0, 1 ) == 0
2004
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
5✔
2005
                          &dfNatOriginLong, 0, 1 ) == 0
2006
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
5✔
2007
                          &dfNatOriginLong, 0, 1 ) == 0 )
2008
            dfNatOriginLong = 0.0;
×
2009

2010
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
5✔
2011
                       &dfNatOriginLat, 0, 1 ) == 0
2012
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
5✔
2013
                          &dfNatOriginLat, 0, 1 ) == 0
2014
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
5✔
2015
                          &dfNatOriginLat, 0, 1 ) == 0 )
2016
            dfNatOriginLat = 0.0;
×
2017

2018
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey,
5✔
2019
                       &dfStdParallel1, 0, 1 ) == 0 )
2020
            dfStdParallel1 = 0.0;
×
2021

2022
        /* notdef: should transform to decimal degrees at this point */
2023

2024
        psDefn->ProjParm[0] = dfNatOriginLat;
5✔
2025
        psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
5✔
2026
        psDefn->ProjParm[1] = dfNatOriginLong;
5✔
2027
        psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
5✔
2028
        psDefn->ProjParm[2] = dfStdParallel1;
5✔
2029
        psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
5✔
2030
        psDefn->ProjParm[5] = dfFalseEasting;
5✔
2031
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
5✔
2032
        psDefn->ProjParm[6] = dfFalseNorthing;
5✔
2033
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
5✔
2034

2035
        psDefn->nParms = 7;
5✔
2036
        break;
5✔
2037

2038
/* -------------------------------------------------------------------- */
2039
      case CT_Robinson:
7✔
2040
      case CT_Sinusoidal:
2041
      case CT_VanDerGrinten:
2042
/* -------------------------------------------------------------------- */
2043
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
7✔
2044
                       &dfNatOriginLong, 0, 1 ) == 0
2045
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
7✔
2046
                          &dfNatOriginLong, 0, 1 ) == 0
2047
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
7✔
2048
                          &dfNatOriginLong, 0, 1 ) == 0 )
2049
            dfNatOriginLong = 0.0;
×
2050

2051
        /* notdef: should transform to decimal degrees at this point */
2052

2053
        psDefn->ProjParm[1] = dfNatOriginLong;
7✔
2054
        psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
7✔
2055
        psDefn->ProjParm[5] = dfFalseEasting;
7✔
2056
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
7✔
2057
        psDefn->ProjParm[6] = dfFalseNorthing;
7✔
2058
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
7✔
2059

2060
        psDefn->nParms = 7;
7✔
2061
        break;
7✔
2062

2063
/* -------------------------------------------------------------------- */
2064
      case CT_PolarStereographic:
6✔
2065
/* -------------------------------------------------------------------- */
2066
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStraightVertPoleLongGeoKey,
6✔
2067
                       &dfNatOriginLong, 0, 1 ) == 0
2068
            && GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
×
2069
                          &dfNatOriginLong, 0, 1 ) == 0
2070
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
2071
                          &dfNatOriginLong, 0, 1 ) == 0
2072
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
2073
                          &dfNatOriginLong, 0, 1 ) == 0 )
2074
            dfNatOriginLong = 0.0;
×
2075

2076
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
6✔
2077
                       &dfNatOriginLat, 0, 1 ) == 0
2078
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
2079
                          &dfNatOriginLat, 0, 1 ) == 0
2080
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
2081
                          &dfNatOriginLat, 0, 1 ) == 0 )
2082
            dfNatOriginLat = 0.0;
×
2083

2084
        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
6✔
2085
                       &dfNatOriginScale, 0, 1 ) == 0
2086
            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
×
2087
                          &dfNatOriginScale, 0, 1 ) == 0 )
2088
            dfNatOriginScale = 1.0;
×
2089

2090
        /* notdef: should transform to decimal degrees at this point */
2091

2092
        psDefn->ProjParm[0] = dfNatOriginLat;
6✔
2093
        psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;;
6✔
2094
        psDefn->ProjParm[1] = dfNatOriginLong;
6✔
2095
        psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
6✔
2096
        psDefn->ProjParm[4] = dfNatOriginScale;
6✔
2097
        psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
6✔
2098
        psDefn->ProjParm[5] = dfFalseEasting;
6✔
2099
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
6✔
2100
        psDefn->ProjParm[6] = dfFalseNorthing;
6✔
2101
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
6✔
2102

2103
        psDefn->nParms = 7;
6✔
2104
        break;
6✔
2105

2106
/* -------------------------------------------------------------------- */
2107
      case CT_LambertConfConic_2SP:
15✔
2108
/* -------------------------------------------------------------------- */
2109
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey,
15✔
2110
                       &dfStdParallel1, 0, 1 ) == 0 )
2111
            dfStdParallel1 = 0.0;
×
2112

2113
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel2GeoKey,
15✔
2114
                       &dfStdParallel2, 0, 1 ) == 0 )
2115
            dfStdParallel1 = 0.0;
×
2116

2117
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
15✔
2118
                       &dfNatOriginLong, 0, 1 ) == 0
2119
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
15✔
2120
                          &dfNatOriginLong, 0, 1 ) == 0
2121
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
2122
                          &dfNatOriginLong, 0, 1 ) == 0 )
2123
            dfNatOriginLong = 0.0;
×
2124

2125
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
15✔
2126
                       &dfNatOriginLat, 0, 1 ) == 0
2127
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
15✔
2128
                          &dfNatOriginLat, 0, 1 ) == 0
2129
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
2130
                          &dfNatOriginLat, 0, 1 ) == 0 )
2131
            dfNatOriginLat = 0.0;
×
2132

2133
        /* notdef: should transform to decimal degrees at this point */
2134

2135
        psDefn->ProjParm[0] = dfNatOriginLat;
15✔
2136
        psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
15✔
2137
        psDefn->ProjParm[1] = dfNatOriginLong;
15✔
2138
        psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
15✔
2139
        psDefn->ProjParm[2] = dfStdParallel1;
15✔
2140
        psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
15✔
2141
        psDefn->ProjParm[3] = dfStdParallel2;
15✔
2142
        psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
15✔
2143
        psDefn->ProjParm[5] = dfFalseEasting;
15✔
2144
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
15✔
2145
        psDefn->ProjParm[6] = dfFalseNorthing;
15✔
2146
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
15✔
2147

2148
        psDefn->nParms = 7;
15✔
2149
        break;
15✔
2150

2151
/* -------------------------------------------------------------------- */
2152
      case CT_AlbersEqualArea:
6✔
2153
      case CT_EquidistantConic:
2154
/* -------------------------------------------------------------------- */
2155
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey,
6✔
2156
                       &dfStdParallel1, 0, 1 ) == 0 )
2157
            dfStdParallel1 = 0.0;
×
2158

2159
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel2GeoKey,
6✔
2160
                       &dfStdParallel2, 0, 1 ) == 0 )
2161
            dfStdParallel2 = 0.0;
×
2162

2163
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
6✔
2164
                       &dfNatOriginLong, 0, 1 ) == 0
2165
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
2166
                          &dfNatOriginLong, 0, 1 ) == 0
2167
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
2168
                          &dfNatOriginLong, 0, 1 ) == 0 )
2169
            dfNatOriginLong = 0.0;
×
2170

2171
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
6✔
2172
                       &dfNatOriginLat, 0, 1 ) == 0
2173
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
×
2174
                          &dfNatOriginLat, 0, 1 ) == 0
2175
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
×
2176
                          &dfNatOriginLat, 0, 1 ) == 0 )
2177
            dfNatOriginLat = 0.0;
×
2178

2179
        /* notdef: should transform to decimal degrees at this point */
2180

2181
        psDefn->ProjParm[0] = dfStdParallel1;
6✔
2182
        psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
6✔
2183
        psDefn->ProjParm[1] = dfStdParallel2;
6✔
2184
        psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
6✔
2185
        psDefn->ProjParm[2] = dfNatOriginLat;
6✔
2186
        psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
6✔
2187
        psDefn->ProjParm[3] = dfNatOriginLong;
6✔
2188
        psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
6✔
2189
        psDefn->ProjParm[5] = dfFalseEasting;
6✔
2190
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
6✔
2191
        psDefn->ProjParm[6] = dfFalseNorthing;
6✔
2192
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
6✔
2193

2194
        psDefn->nParms = 7;
6✔
2195
        break;
6✔
2196

2197
/* -------------------------------------------------------------------- */
2198
      case CT_CylindricalEqualArea:
1✔
2199
/* -------------------------------------------------------------------- */
2200
        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey,
1✔
2201
                       &dfStdParallel1, 0, 1 ) == 0 )
2202
            dfStdParallel1 = 0.0;
×
2203

2204
        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
1✔
2205
                       &dfNatOriginLong, 0, 1 ) == 0
2206
            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
×
2207
                          &dfNatOriginLong, 0, 1 ) == 0
2208
            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
×
2209
                          &dfNatOriginLong, 0, 1 ) == 0 )
2210
            dfNatOriginLong = 0.0;
×
2211

2212
        /* notdef: should transform to decimal degrees at this point */
2213

2214
        psDefn->ProjParm[0] = dfStdParallel1;
1✔
2215
        psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
1✔
2216
        psDefn->ProjParm[1] = dfNatOriginLong;
1✔
2217
        psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
1✔
2218
        psDefn->ProjParm[5] = dfFalseEasting;
1✔
2219
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
1✔
2220
        psDefn->ProjParm[6] = dfFalseNorthing;
1✔
2221
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
1✔
2222

2223
        psDefn->nParms = 7;
1✔
2224
        break;
1✔
2225
    }
2226

2227
    for( int iParam = 0; iParam < psDefn->nParms; iParam++ )
696✔
2228
    {
2229
        switch( psDefn->ProjParmId[iParam] )
609✔
2230
        {
2231

2232
/* -------------------------------------------------------------------- */
2233
/*      Normalize any linear parameters into meters.  In GeoTIFF        */
2234
/*      the linear projection parameter tags are normally in the        */
2235
/*      units of the coordinate system described.                       */
2236
/* -------------------------------------------------------------------- */
2237
          case ProjFalseEastingGeoKey:
174✔
2238
          case ProjFalseNorthingGeoKey:
2239
          case ProjFalseOriginEastingGeoKey:
2240
          case ProjFalseOriginNorthingGeoKey:
2241
          case ProjCenterEastingGeoKey:
2242
          case ProjCenterNorthingGeoKey:
2243
            if( psDefn->UOMLengthInMeters != 0
174✔
2244
                && psDefn->UOMLengthInMeters != 1.0 )
174✔
2245
            {
2246
                psDefn->ProjParm[iParam] *= psDefn->UOMLengthInMeters;
32✔
2247
            }
2248
            break;
174✔
2249

2250
/* -------------------------------------------------------------------- */
2251
/*      Normalize any angular parameters into degrees.  In GeoTIFF      */
2252
/*      the angular projection parameter tags are normally in the       */
2253
/*      units of GeogAngularUnit. Note: this conversion is only done    */
2254
/*      since libgeotiff 1.7.4                                          */
2255
/* -------------------------------------------------------------------- */
2256

2257
          case ProjStdParallel1GeoKey:
220✔
2258
          case ProjStdParallel2GeoKey:
2259
          case ProjNatOriginLongGeoKey:
2260
          case ProjNatOriginLatGeoKey:
2261
          case ProjFalseOriginLongGeoKey:
2262
          case ProjFalseOriginLatGeoKey:
2263
          case ProjCenterLongGeoKey:
2264
          case ProjCenterLatGeoKey:
2265
          case ProjStraightVertPoleLongGeoKey:
2266
          case ProjRectifiedGridAngleGeoKey:
2267
            if( psDefn->UOMAngleInDegrees != 0
220✔
2268
                && psDefn->UOMAngleInDegrees != 1.0 )
220✔
2269
            {
2270
                psDefn->ProjParm[iParam] *= psDefn->UOMAngleInDegrees;
6✔
2271
            }
2272
            break;
220✔
2273

2274
          default:
215✔
2275
            break;
215✔
2276
        }
2277
    }
2278
}
87✔
2279

2280
/************************************************************************/
2281
/*                            GTIFGetDefn()                             */
2282
/************************************************************************/
2283

2284
/**
2285
@param psGTIF GeoTIFF information handle as returned by GTIFNew.
2286
@param psDefn Pointer to an existing GTIFDefn structure allocated by GTIFAllocDefn().
2287

2288
@return TRUE if the function has been successful, otherwise FALSE.
2289

2290
This function reads the coordinate system definition from a GeoTIFF file,
2291
and <i>normalizes</i> it into a set of component information using
2292
definitions from the EPSG database as provided by the PROJ library.
2293
This function is intended to simplify correct support for
2294
reading files with defined PCS (Projected Coordinate System) codes that
2295
wouldn't otherwise be directly known by application software by reducing
2296
it to the underlying projection method, parameters, datum, ellipsoid,
2297
prime meridian and units.<p>
2298

2299
The application should pass a pointer to an existing uninitialized
2300
GTIFDefn structure, and GTIFGetDefn() will fill it in.  The function
2301
currently always returns TRUE but in the future will return FALSE if
2302
the database is not found.  In any event, all geokeys actually found in the
2303
file will be copied into the GTIFDefn.  However, if the database isn't
2304
found, codes implied by other codes will not be set properly.<p>
2305

2306
GTIFGetDefn() will not generally work if the EPSG derived database cannot
2307
be found.<p>
2308

2309
The normalization methodology operates by fetching tags from the GeoTIFF
2310
file, and then setting all other tags implied by them in the structure.  The
2311
implied relationships are worked out by reading definitions from the
2312
various EPSG derived database tables.<p>
2313

2314
For instance, if a PCS (ProjectedCSTypeGeoKey) is found in the GeoTIFF file
2315
this code is used to lookup a record in the database.
2316
For example given the PCS 26746 we can find the name
2317
(NAD27 / California zone VI), the GCS 4257 (NAD27), and the ProjectionCode
2318
10406 (California CS27 zone VI).  The GCS, and ProjectionCode can in turn
2319
be looked up in other tables until all the details of units, ellipsoid,
2320
prime meridian, datum, projection (LambertConfConic_2SP) and projection
2321
parameters are established.  A full listgeo dump of a file
2322
for this result might look like the following, all based on a single PCS
2323
value:<p>
2324

2325
<pre>
2326
% listgeo -norm ~/data/geotiff/pci_eg/spaf27.tif
2327
Geotiff_Information:
2328
   Version: 1
2329
   Key_Revision: 1.0
2330
   Tagged_Information:
2331
      ModelTiepointTag (2,3):
2332
         0                0                0
2333
         1577139.71       634349.176       0
2334
      ModelPixelScaleTag (1,3):
2335
         195.509321       198.32184        0
2336
      End_Of_Tags.
2337
   Keyed_Information:
2338
      GTModelTypeGeoKey (Short,1): ModelTypeProjected
2339
      GTRasterTypeGeoKey (Short,1): RasterPixelIsArea
2340
      ProjectedCSTypeGeoKey (Short,1): PCS_NAD27_California_VI
2341
      End_Of_Keys.
2342
   End_Of_Geotiff.
2343

2344
PCS = 26746 (NAD27 / California zone VI)
2345
Projection = 10406 (California CS27 zone VI)
2346
Projection Method: CT_LambertConfConic_2SP
2347
   ProjStdParallel1GeoKey: 33.883333
2348
   ProjStdParallel2GeoKey: 32.766667
2349
   ProjFalseOriginLatGeoKey: 32.166667
2350
   ProjFalseOriginLongGeoKey: -116.233333
2351
   ProjFalseEastingGeoKey: 609601.219202
2352
   ProjFalseNorthingGeoKey: 0.000000
2353
GCS: 4267/NAD27
2354
Datum: 6267/North American Datum 1927
2355
Ellipsoid: 7008/Clarke 1866 (6378206.40,6356583.80)
2356
Prime Meridian: 8901/Greenwich (0.000000)
2357
Projection Linear Units: 9003/US survey foot (0.304801m)
2358
</pre>
2359

2360
Note that GTIFGetDefn() does not inspect or return the tiepoints and scale.
2361
This must be handled separately as it normally would.  It is intended to
2362
simplify capture and normalization of the coordinate system definition.
2363
Note that GTIFGetDefn() also does the following things:
2364

2365
<ol>
2366
<li> Convert all angular values to decimal degrees.
2367
<li> Convert all linear values to meters.
2368
<li> Return the linear units and conversion to meters for the tiepoints and
2369
scale (though the tiepoints and scale remain in their native units).
2370
<li> When reading projection parameters a variety of differences between
2371
different GeoTIFF generators are handled, and a normalized set of parameters
2372
for each projection are always returned.
2373
</ol>
2374

2375
Code fields in the GTIFDefn are filled with KvUserDefined if there is not
2376
value to assign.  The parameter lists for each of the underlying projection
2377
transform methods can be found at the
2378
<a href="http://www.remotesensing.org/geotiff/proj_list">Projections</a>
2379
page.  Note that nParms will be set based on the maximum parameter used.
2380
Some of the parameters may not be used in which case the
2381
GTIFDefn::ProjParmId[] will
2382
be zero.  This is done to retain correspondence to the EPSG parameter
2383
numbering scheme.<p>
2384

2385
The
2386
<a href="http://www.remotesensing.org/cgi-bin/cvsweb.cgi/~checkout~/osrs/geotiff/libgeotiff/geotiff_proj4.c">geotiff_proj4.c</a> module distributed with libgeotiff can
2387
be used as an example of code that converts a GTIFDefn into another projection
2388
system.<p>
2389

2390
@see GTIFKeySet()
2391

2392
*/
2393

2394
int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
12,853✔
2395

2396
{
2397
    if( !GTIFGetPROJContext(psGTIF, TRUE, NULL) )
12,853✔
2398
    {
2399
        return FALSE;
×
2400
    }
2401

2402
/* -------------------------------------------------------------------- */
2403
/*      Initially we default all the information we can.                */
2404
/* -------------------------------------------------------------------- */
2405
    psDefn->DefnSet = 1;
12,853✔
2406
    psDefn->Model = KvUserDefined;
12,853✔
2407
    psDefn->PCS = KvUserDefined;
12,853✔
2408
    psDefn->GCS = KvUserDefined;
12,853✔
2409
    psDefn->UOMLength = KvUserDefined;
12,853✔
2410
    psDefn->UOMLengthInMeters = 1.0;
12,853✔
2411
    psDefn->UOMAngle = KvUserDefined;
12,853✔
2412
    psDefn->UOMAngleInDegrees = 1.0;
12,853✔
2413
    psDefn->Datum = KvUserDefined;
12,853✔
2414
    psDefn->Ellipsoid = KvUserDefined;
12,853✔
2415
    psDefn->SemiMajor = 0.0;
12,853✔
2416
    psDefn->SemiMinor = 0.0;
12,853✔
2417
    psDefn->PM = KvUserDefined;
12,853✔
2418
    psDefn->PMLongToGreenwich = 0.0;
12,853✔
2419
#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
2420
    psDefn->TOWGS84Count = 0;
12,853✔
2421
    memset( psDefn->TOWGS84, 0, sizeof(psDefn->TOWGS84) );
12,853✔
2422
#endif
2423

2424
    psDefn->ProjCode = KvUserDefined;
12,853✔
2425
    psDefn->Projection = KvUserDefined;
12,853✔
2426
    psDefn->CTProjection = KvUserDefined;
12,853✔
2427

2428
    psDefn->nParms = 0;
12,853✔
2429
    for( int i = 0; i < MAX_GTIF_PROJPARMS; i++ )
141,383✔
2430
    {
2431
        psDefn->ProjParm[i] = 0.0;
128,530✔
2432
        psDefn->ProjParmId[i] = 0;
128,530✔
2433
    }
2434

2435
    psDefn->MapSys = KvUserDefined;
12,853✔
2436
    psDefn->Zone = 0;
12,853✔
2437

2438
/* -------------------------------------------------------------------- */
2439
/*      Do we have any geokeys?                                         */
2440
/* -------------------------------------------------------------------- */
2441
    {
2442
        int     nKeyCount = 0;
12,853✔
2443
        int     anVersion[3];
2444
        GTIFDirectoryInfo( psGTIF, anVersion, &nKeyCount );
12,853✔
2445

2446
        if( nKeyCount == 0 )
12,853✔
2447
        {
2448
            psDefn->DefnSet = 0;
4,597✔
2449
            return FALSE;
4,597✔
2450
        }
2451
    }
2452

2453
/* -------------------------------------------------------------------- */
2454
/*        Try to get the overall model type.                                */
2455
/* -------------------------------------------------------------------- */
2456
    GTIFKeyGetSSHORT(psGTIF,GTModelTypeGeoKey,&(psDefn->Model));
8,256✔
2457

2458
/* -------------------------------------------------------------------- */
2459
/*        Extract the Geog units.                                          */
2460
/* -------------------------------------------------------------------- */
2461
    short nGeogUOMLinear = 9001; /* Linear_Meter */
8,256✔
2462
    if( GTIFKeyGetSSHORT(psGTIF, GeogLinearUnitsGeoKey, &nGeogUOMLinear) == 1 )
8,256✔
2463
    {
2464
        psDefn->UOMLength = nGeogUOMLinear;
23✔
2465
    }
2466

2467
/* -------------------------------------------------------------------- */
2468
/*      Try to get a PCS.                                               */
2469
/* -------------------------------------------------------------------- */
2470
    if( GTIFKeyGetSSHORT(psGTIF,ProjectedCSTypeGeoKey, &(psDefn->PCS)) == 1
8,256✔
2471
        && psDefn->PCS != KvUserDefined )
3,680✔
2472
    {
2473
        /*
2474
         * Translate this into useful information.
2475
         */
2476
        GTIFGetPCSInfoEx( psGTIF->pj_context,
3,580✔
2477
                          psDefn->PCS, NULL, &(psDefn->ProjCode),
3,580✔
2478
                          &(psDefn->UOMLength), &(psDefn->GCS) );
2479
    }
2480

2481
/* -------------------------------------------------------------------- */
2482
/*       If we have the PCS code, but didn't find it in the database    */
2483
/*      (likely because we can't find them) we will try some ``jiffy    */
2484
/*      rules'' for UTM and state plane.                                */
2485
/* -------------------------------------------------------------------- */
2486
    if( psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined )
8,256✔
2487
    {
2488
        int        nZone;
2489
        int        nGCS = psDefn->GCS;
×
2490

2491
        const int nMapSys = GTIFPCSToMapSys( psDefn->PCS, &nGCS, &nZone );
×
2492
        if( nMapSys != KvUserDefined )
×
2493
        {
2494
            psDefn->ProjCode = (short) GTIFMapSysToProj( nMapSys, nZone );
×
2495
            psDefn->GCS = (short) nGCS;
×
2496
        }
2497
    }
2498

2499
/* -------------------------------------------------------------------- */
2500
/*      If the Proj_ code is specified directly, use that.              */
2501
/* -------------------------------------------------------------------- */
2502
    if( psDefn->ProjCode == KvUserDefined )
8,256✔
2503
        GTIFKeyGetSSHORT(psGTIF, ProjectionGeoKey, &(psDefn->ProjCode));
4,676✔
2504

2505
    if( psDefn->ProjCode != KvUserDefined )
8,256✔
2506
    {
2507
        /*
2508
         * We have an underlying projection transformation value.  Look
2509
         * this up.  For a PCS of ``WGS 84 / UTM 11'' the transformation
2510
         * would be Transverse Mercator, with a particular set of options.
2511
         * The nProjTRFCode itself would correspond to the name
2512
         * ``UTM zone 11N'', and doesn't include datum info.
2513
         */
2514
        GTIFGetProjTRFInfoEx( psGTIF->pj_context,
3,592✔
2515
                              psDefn->ProjCode, NULL, &(psDefn->Projection),
3,592✔
2516
                              psDefn->ProjParm );
3,592✔
2517

2518
        /*
2519
         * Set the GeoTIFF identity of the parameters.
2520
         */
2521
        psDefn->CTProjection = (short)
3,592✔
2522
            EPSGProjMethodToCTProjMethod( psDefn->Projection, FALSE );
3,592✔
2523

2524
        SetGTParamIds( EPSGProjMethodToCTProjMethod(psDefn->Projection, TRUE),
3,592✔
2525
                      psDefn->Projection,
3,592✔
2526
                      psDefn->ProjParmId, NULL);
3,592✔
2527
        psDefn->nParms = 7;
3,592✔
2528
    }
2529

2530
/* -------------------------------------------------------------------- */
2531
/*      Try to get a GCS.  If found, it will override any implied by    */
2532
/*      the PCS.                                                        */
2533
/* -------------------------------------------------------------------- */
2534
    GTIFKeyGetSSHORT(psGTIF, GeographicTypeGeoKey, &(psDefn->GCS));
8,256✔
2535
    if( psDefn->GCS < 1 || psDefn->GCS >= KvUserDefined )
8,256✔
2536
        psDefn->GCS = KvUserDefined;
434✔
2537

2538
/* -------------------------------------------------------------------- */
2539
/*      Derive the datum, and prime meridian from the GCS.              */
2540
/* -------------------------------------------------------------------- */
2541
    if( psDefn->GCS != KvUserDefined )
8,256✔
2542
    {
2543
        GTIFGetGCSInfoEx( psGTIF->pj_context,
7,822✔
2544
                          psDefn->GCS, NULL, &(psDefn->Datum), &(psDefn->PM),
7,822✔
2545
                          &(psDefn->UOMAngle) );
2546
    }
2547

2548
/* -------------------------------------------------------------------- */
2549
/*      Handle the GCS angular units.  GeogAngularUnitsGeoKey           */
2550
/*      overrides the GCS or PCS setting.                               */
2551
/* -------------------------------------------------------------------- */
2552
    GTIFKeyGetSSHORT(psGTIF, GeogAngularUnitsGeoKey, &(psDefn->UOMAngle));
8,256✔
2553
    if( psDefn->UOMAngle != KvUserDefined )
8,256✔
2554
    {
2555
        GTIFGetUOMAngleInfoEx( psGTIF->pj_context,
8,224✔
2556
                               psDefn->UOMAngle, NULL,
8,224✔
2557
                               &(psDefn->UOMAngleInDegrees) );
2558
    }
2559

2560
/* -------------------------------------------------------------------- */
2561
/*      Check for a datum setting, and then use the datum to derive     */
2562
/*      an ellipsoid.                                                   */
2563
/* -------------------------------------------------------------------- */
2564
    GTIFKeyGetSSHORT(psGTIF, GeogGeodeticDatumGeoKey, &(psDefn->Datum));
8,256✔
2565

2566
    if( psDefn->Datum != KvUserDefined )
8,256✔
2567
    {
2568
        GTIFGetDatumInfoEx( psGTIF->pj_context,
7,845✔
2569
                            psDefn->Datum, NULL, &(psDefn->Ellipsoid) );
7,845✔
2570
    }
2571

2572
/* -------------------------------------------------------------------- */
2573
/*      Check for an explicit ellipsoid.  Use the ellipsoid to          */
2574
/*      derive the ellipsoid characteristics, if possible.              */
2575
/* -------------------------------------------------------------------- */
2576
    GTIFKeyGetSSHORT(psGTIF, GeogEllipsoidGeoKey, &(psDefn->Ellipsoid));
8,256✔
2577

2578
    if( psDefn->Ellipsoid != KvUserDefined )
8,256✔
2579
    {
2580
        GTIFGetEllipsoidInfoEx( psGTIF->pj_context,
7,848✔
2581
                                psDefn->Ellipsoid, NULL,
7,848✔
2582
                                &(psDefn->SemiMajor), &(psDefn->SemiMinor) );
2583
    }
2584

2585
/* -------------------------------------------------------------------- */
2586
/*      Check for overridden ellipsoid parameters.  It would be nice    */
2587
/*      to warn if they conflict with provided information, but for     */
2588
/*      now we just override.                                           */
2589
/* -------------------------------------------------------------------- */
2590
    CPL_IGNORE_RET_VAL_INT(GTIFKeyGetDOUBLE(psGTIF, GeogSemiMajorAxisGeoKey, &(psDefn->SemiMajor), 0, 1 ));
8,256✔
2591
    CPL_IGNORE_RET_VAL_INT(GTIFKeyGetDOUBLE(psGTIF, GeogSemiMinorAxisGeoKey, &(psDefn->SemiMinor), 0, 1 ));
8,256✔
2592

2593
    double dfInvFlattening;
2594
    if( GTIFKeyGetDOUBLE(psGTIF, GeogInvFlatteningGeoKey, &dfInvFlattening,
8,256✔
2595
                   0, 1 ) == 1 )
2596
    {
2597
        if( dfInvFlattening != 0.0 )
3,787✔
2598
            psDefn->SemiMinor =
3,787✔
2599
                psDefn->SemiMajor * (1 - 1.0/dfInvFlattening);
3,787✔
2600
        else
2601
            psDefn->SemiMinor = psDefn->SemiMajor;
×
2602
    }
2603

2604
/* -------------------------------------------------------------------- */
2605
/*      Get the prime meridian info.                                    */
2606
/* -------------------------------------------------------------------- */
2607
    GTIFKeyGetSSHORT(psGTIF, GeogPrimeMeridianGeoKey, &(psDefn->PM));
8,256✔
2608

2609
    if( psDefn->PM != KvUserDefined )
8,256✔
2610
    {
2611
        GTIFGetPMInfoEx( psGTIF->pj_context,
7,824✔
2612
                         psDefn->PM, NULL, &(psDefn->PMLongToGreenwich) );
7,824✔
2613
    }
2614
    else
2615
    {
2616
        CPL_IGNORE_RET_VAL_INT(GTIFKeyGetDOUBLE(psGTIF, GeogPrimeMeridianLongGeoKey,
432✔
2617
                   &(psDefn->PMLongToGreenwich), 0, 1 ));
2618

2619
        psDefn->PMLongToGreenwich =
432✔
2620
            GTIFAngleToDD( psDefn->PMLongToGreenwich,
432✔
2621
                           psDefn->UOMAngle );
432✔
2622
    }
2623

2624
/* -------------------------------------------------------------------- */
2625
/*      Get the TOWGS84 parameters.                                     */
2626
/* -------------------------------------------------------------------- */
2627
#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
2628
    psDefn->TOWGS84Count =
8,256✔
2629
        (short)GTIFKeyGetDOUBLE(psGTIF, GeogTOWGS84GeoKey, psDefn->TOWGS84, 0, 7 );
8,256✔
2630
#endif
2631

2632
/* -------------------------------------------------------------------- */
2633
/*      Have the projection units of measure been overridden?  We       */
2634
/*      should likely be doing something about angular units too,       */
2635
/*      but these are very rarely not decimal degrees for actual        */
2636
/*      file coordinates.                                               */
2637
/* -------------------------------------------------------------------- */
2638
    GTIFKeyGetSSHORT(psGTIF,ProjLinearUnitsGeoKey,&(psDefn->UOMLength));
8,256✔
2639

2640
    if( psDefn->UOMLength != KvUserDefined )
8,256✔
2641
    {
2642
        GTIFGetUOMLengthInfoEx( psGTIF->pj_context,
4,004✔
2643
                                psDefn->UOMLength, NULL,
4,004✔
2644
                                &(psDefn->UOMLengthInMeters) );
2645
    }
2646
    else
2647
    {
2648
        CPL_IGNORE_RET_VAL_INT(GTIFKeyGetDOUBLE(psGTIF,ProjLinearUnitSizeGeoKey,&(psDefn->UOMLengthInMeters),0,1));
4,252✔
2649
    }
2650

2651
/* -------------------------------------------------------------------- */
2652
/*      Handle a variety of user defined transform types.               */
2653
/* -------------------------------------------------------------------- */
2654
    if( GTIFKeyGetSSHORT(psGTIF,ProjCoordTransGeoKey,
8,256✔
2655
                   &(psDefn->CTProjection)) == 1)
2656
    {
2657
        GTIFFetchProjParms( psGTIF, psDefn );
87✔
2658
    }
2659

2660
/* -------------------------------------------------------------------- */
2661
/*      Try to set the zoned map system information.                    */
2662
/* -------------------------------------------------------------------- */
2663
    psDefn->MapSys = GTIFProjToMapSys( psDefn->ProjCode, &(psDefn->Zone) );
8,256✔
2664

2665
/* -------------------------------------------------------------------- */
2666
/*      If this is UTM, and we were unable to extract the projection    */
2667
/*      parameters from the database just set them directly now,        */
2668
/*      since it's pretty easy, and a common case.                      */
2669
/* -------------------------------------------------------------------- */
2670
    if( (psDefn->MapSys == MapSys_UTM_North
8,256✔
2671
         || psDefn->MapSys == MapSys_UTM_South)
4,853✔
2672
        && psDefn->CTProjection == KvUserDefined )
3,406✔
2673
    {
2674
        psDefn->CTProjection = CT_TransverseMercator;
×
2675
        psDefn->nParms = 7;
×
2676
        psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
×
2677
        psDefn->ProjParm[0] = 0.0;
×
2678

2679
        psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
×
2680
        psDefn->ProjParm[1] = psDefn->Zone*6 - 183.0;
×
2681

2682
        psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
×
2683
        psDefn->ProjParm[4] = 0.9996;
×
2684

2685
        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
×
2686
        psDefn->ProjParm[5] = 500000.0;
×
2687

2688
        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
×
2689

2690
        if( psDefn->MapSys == MapSys_UTM_North )
×
2691
            psDefn->ProjParm[6] = 0.0;
×
2692
        else
2693
            psDefn->ProjParm[6] = 10000000.0;
×
2694
    }
2695

2696
    return TRUE;
8,256✔
2697
}
2698

2699
/************************************************************************/
2700
/*                            GTIFDecToDMS()                            */
2701
/*                                                                      */
2702
/*      Convenient function to translate decimal degrees to DMS         */
2703
/*      format for reporting to a user.                                 */
2704
/************************************************************************/
2705

2706
const char *GTIFDecToDMS( double dfAngle, const char * pszAxis,
×
2707
                          int nPrecision )
2708
{
2709
    if( !(dfAngle >= -360 && dfAngle <= 360) )
×
2710
        return "";
×
2711

2712
    double dfRound = 0.5/60;
×
2713
    for( int i = 0; i < nPrecision; i++ )
×
2714
        dfRound = dfRound * 0.1;
×
2715

2716
    int nDegrees = (int) ABS(dfAngle);
×
2717
    int nMinutes = (int) ((ABS(dfAngle) - nDegrees) * 60 + dfRound);
×
2718
    if( nMinutes == 60 )
×
2719
    {
2720
        nDegrees ++;
×
2721
        nMinutes = 0;
×
2722
    }
2723
    const double dfSeconds = ABS((ABS(dfAngle) * 3600 - nDegrees*3600 - nMinutes*60));
×
2724

2725
    const char        *pszHemisphere = NULL;
×
2726
    if( EQUAL(pszAxis,"Long") && dfAngle < 0.0 )
×
2727
        pszHemisphere = "W";
×
2728
    else if( EQUAL(pszAxis,"Long") )
×
2729
        pszHemisphere = "E";
×
2730
    else if( dfAngle < 0.0 )
×
2731
        pszHemisphere = "S";
×
2732
    else
2733
        pszHemisphere = "N";
×
2734

2735
    char szFormat[30];
2736
    snprintf(szFormat, sizeof(szFormat), "%%3dd%%2d\'%%%d.%df\"%s",
×
2737
             nPrecision+3, nPrecision, pszHemisphere);
2738
    static char szBuffer[50];
2739
    snprintf(
×
2740
        szBuffer, sizeof(szBuffer), szFormat, nDegrees, nMinutes, dfSeconds);
2741

2742
    return szBuffer;
×
2743
}
2744

2745
/************************************************************************/
2746
/*                           GTIFPrintDefn()                            */
2747
/*                                                                      */
2748
/*      Report the contents of a GTIFDefn structure ... mostly for      */
2749
/*      debugging.                                                      */
2750
/************************************************************************/
2751

2752
void GTIFPrintDefnEx( GTIF *psGTIF, GTIFDefn * psDefn, FILE * fp )
×
2753

2754
{
2755
    GTIFGetPROJContext(psGTIF, TRUE, NULL);
×
2756

2757
/* -------------------------------------------------------------------- */
2758
/*      Do we have anything to report?                                  */
2759
/* -------------------------------------------------------------------- */
2760
    if( !psDefn->DefnSet )
×
2761
    {
2762
        fprintf( fp, "No GeoKeys found.\n" );
×
2763
        return;
×
2764
    }
2765

2766
/* -------------------------------------------------------------------- */
2767
/*      Get the PCS name if possible.                                   */
2768
/* -------------------------------------------------------------------- */
2769
    if( psDefn->PCS != KvUserDefined )
×
2770
    {
2771
        char        *pszPCSName = NULL;
×
2772

2773
        if( psGTIF->pj_context )
×
2774
        {
2775
            GTIFGetPCSInfoEx( psGTIF->pj_context,
×
2776
                              psDefn->PCS, &pszPCSName, NULL, NULL, NULL );
×
2777
        }
2778
        if( pszPCSName == NULL )
×
2779
            pszPCSName = CPLStrdup("name unknown");
×
2780

2781
        fprintf( fp, "PCS = %d (%s)\n", psDefn->PCS, pszPCSName );
×
2782
        CPLFree( pszPCSName );
×
2783
    }
2784

2785
/* -------------------------------------------------------------------- */
2786
/*        Dump the projection code if possible.                                */
2787
/* -------------------------------------------------------------------- */
2788
    if( psDefn->ProjCode != KvUserDefined )
×
2789
    {
2790
        char        *pszTRFName = NULL;
×
2791

2792
        if( psGTIF->pj_context )
×
2793
        {
2794
            GTIFGetProjTRFInfoEx( psGTIF->pj_context,
×
2795
                                  psDefn->ProjCode, &pszTRFName, NULL, NULL );
×
2796
        }
2797
        if( pszTRFName == NULL )
×
2798
            pszTRFName = CPLStrdup("");
×
2799

2800
        fprintf( fp, "Projection = %d (%s)\n",
×
2801
                 psDefn->ProjCode, pszTRFName );
×
2802

2803
        CPLFree( pszTRFName );
×
2804
    }
2805

2806
/* -------------------------------------------------------------------- */
2807
/*      Try to dump the projection method name, and parameters if possible.*/
2808
/* -------------------------------------------------------------------- */
2809
    if( psDefn->CTProjection != KvUserDefined )
×
2810
    {
2811
        const char *pszProjectionMethodName =
2812
            GTIFValueNameEx(psGTIF,
×
2813
                            ProjCoordTransGeoKey,
2814
                            psDefn->CTProjection);
×
2815

2816
        if( pszProjectionMethodName == NULL )
×
2817
            pszProjectionMethodName = "(unknown)";
×
2818

2819
        fprintf( fp, "Projection Method: %s\n", pszProjectionMethodName );
×
2820

2821
        for( int i = 0; i < psDefn->nParms; i++ )
×
2822
        {
2823
            if( psDefn->ProjParmId[i] == 0 )
×
2824
                continue;
×
2825

2826
            char* pszName = GTIFKeyName((geokey_t) psDefn->ProjParmId[i]);
×
2827
            if( pszName == NULL )
×
2828
                pszName = "(unknown)";
×
2829

2830
            if( i < 4 )
×
2831
            {
2832
                char        *pszAxisName;
2833

2834
                if( strstr(pszName,"Long") != NULL )
×
2835
                    pszAxisName = "Long";
×
2836
                else if( strstr(pszName,"Lat") != NULL )
×
2837
                    pszAxisName = "Lat";
×
2838
                else
2839
                    pszAxisName = "?";
×
2840

2841
                fprintf( fp, "   %s: %f (%s)\n",
×
2842
                         pszName, psDefn->ProjParm[i],
2843
                         GTIFDecToDMS( psDefn->ProjParm[i], pszAxisName, 2 ) );
2844
            }
2845
            else if( i == 4 )
×
2846
                fprintf( fp, "   %s: %f\n", pszName, psDefn->ProjParm[i] );
×
2847
            else
2848
                fprintf( fp, "   %s: %f m\n", pszName, psDefn->ProjParm[i] );
×
2849
        }
2850
    }
2851

2852
/* -------------------------------------------------------------------- */
2853
/*      Report the GCS name, and number.                                */
2854
/* -------------------------------------------------------------------- */
2855
    if( psDefn->GCS != KvUserDefined )
×
2856
    {
2857
        char        *pszName = NULL;
×
2858

2859
        if( psGTIF->pj_context )
×
2860
        {
2861
            GTIFGetGCSInfoEx( psGTIF->pj_context,
×
2862
                              psDefn->GCS, &pszName, NULL, NULL, NULL );
×
2863
        }
2864
        if( pszName == NULL )
×
2865
            pszName = CPLStrdup("(unknown)");
×
2866

2867
        fprintf( fp, "GCS: %d/%s\n", psDefn->GCS, pszName );
×
2868
        CPLFree( pszName );
×
2869
    }
2870

2871
/* -------------------------------------------------------------------- */
2872
/*      Report the datum name.                                          */
2873
/* -------------------------------------------------------------------- */
2874
    if( psDefn->Datum != KvUserDefined )
×
2875
    {
2876
        char        *pszName = NULL;
×
2877

2878
        if( psGTIF->pj_context )
×
2879
        {
2880
            GTIFGetDatumInfoEx( psGTIF->pj_context,
×
2881
                                psDefn->Datum, &pszName, NULL );
×
2882
        }
2883
        if( pszName == NULL )
×
2884
            pszName = CPLStrdup("(unknown)");
×
2885

2886
        fprintf( fp, "Datum: %d/%s\n", psDefn->Datum, pszName );
×
2887
        CPLFree( pszName );
×
2888
    }
2889

2890
/* -------------------------------------------------------------------- */
2891
/*      Report the ellipsoid.                                           */
2892
/* -------------------------------------------------------------------- */
2893
    if( psDefn->Ellipsoid != KvUserDefined )
×
2894
    {
2895
        char        *pszName = NULL;
×
2896

2897
        if( psGTIF->pj_context )
×
2898
        {
2899
            GTIFGetEllipsoidInfoEx( psGTIF->pj_context,
×
2900
                                    psDefn->Ellipsoid, &pszName, NULL, NULL );
×
2901
        }
2902
        if( pszName == NULL )
×
2903
            pszName = CPLStrdup("(unknown)");
×
2904

2905
        fprintf( fp, "Ellipsoid: %d/%s (%.2f,%.2f)\n",
×
2906
                 psDefn->Ellipsoid, pszName,
×
2907
                 psDefn->SemiMajor, psDefn->SemiMinor );
2908
        CPLFree( pszName );
×
2909
    }
2910

2911
/* -------------------------------------------------------------------- */
2912
/*      Report the prime meridian.                                      */
2913
/* -------------------------------------------------------------------- */
2914
    if( psDefn->PM != KvUserDefined )
×
2915
    {
2916
        char        *pszName = NULL;
×
2917

2918
        if( psGTIF->pj_context )
×
2919
        {
2920
            GTIFGetPMInfoEx( psGTIF->pj_context,
×
2921
                             psDefn->PM, &pszName, NULL );
×
2922
        }
2923

2924
        if( pszName == NULL )
×
2925
            pszName = CPLStrdup("(unknown)");
×
2926

2927
        fprintf( fp, "Prime Meridian: %d/%s (%f/%s)\n",
×
2928
                 psDefn->PM, pszName,
×
2929
                 psDefn->PMLongToGreenwich,
2930
                 GTIFDecToDMS( psDefn->PMLongToGreenwich, "Long", 2 ) );
2931
        CPLFree( pszName );
×
2932
    }
2933

2934
/* -------------------------------------------------------------------- */
2935
/*      Report TOWGS84 parameters.                                      */
2936
/* -------------------------------------------------------------------- */
2937
#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
2938
    if( psDefn->TOWGS84Count > 0 )
×
2939
    {
2940
        fprintf( fp, "TOWGS84: " );
×
2941

2942
        for( int i = 0; i < psDefn->TOWGS84Count; i++ )
×
2943
        {
2944
            if( i > 0 )
×
2945
                fprintf( fp, "," );
×
2946
            fprintf( fp, "%g", psDefn->TOWGS84[i] );
×
2947
        }
2948

2949
        fprintf( fp, "\n" );
×
2950
    }
2951
#endif
2952

2953
/* -------------------------------------------------------------------- */
2954
/*      Report the projection units of measure (currently just          */
2955
/*      linear).                                                        */
2956
/* -------------------------------------------------------------------- */
2957
    if( psDefn->UOMLength != KvUserDefined )
×
2958
    {
2959
        char        *pszName = NULL;
×
2960

2961
        if( psGTIF->pj_context )
×
2962
        {
2963
            GTIFGetUOMLengthInfoEx(
×
2964
                psGTIF->pj_context, psDefn->UOMLength, &pszName, NULL );
×
2965
        }
2966
        if( pszName == NULL )
×
2967
            pszName = CPLStrdup( "(unknown)" );
×
2968

2969
        fprintf( fp, "Projection Linear Units: %d/%s (%fm)\n",
×
2970
                 psDefn->UOMLength, pszName, psDefn->UOMLengthInMeters );
×
2971
        CPLFree( pszName );
×
2972
    }
2973
    else
2974
    {
2975
        fprintf( fp, "Projection Linear Units: User-Defined (%fm)\n",
×
2976
                 psDefn->UOMLengthInMeters );
2977
    }
2978
}
2979

2980
void GTIFPrintDefn( GTIFDefn * psDefn, FILE * fp )
×
2981
{
2982
    GTIF *psGTIF = GTIFNew(NULL);
×
2983
    if( psGTIF )
×
2984
    {
2985
        GTIFPrintDefnEx(psGTIF, psDefn, fp);
×
2986
        GTIFFree(psGTIF);
×
2987
    }
2988
}
×
2989

2990
/************************************************************************/
2991
/*                           GTIFFreeMemory()                           */
2992
/*                                                                      */
2993
/*      Externally visible function to free memory allocated within     */
2994
/*      geo_normalize.c.                                                */
2995
/************************************************************************/
2996

2997
void GTIFFreeMemory( char * pMemory )
46,919✔
2998

2999
{
3000
    if( pMemory != NULL )
46,919✔
3001
        VSIFree( pMemory );
46,900✔
3002
}
46,919✔
3003

3004
/************************************************************************/
3005
/*                           GTIFAllocDefn()                            */
3006
/*                                                                      */
3007
/*      This allocates a GTIF structure in such a way that the          */
3008
/*      calling application doesn't need to know the size and           */
3009
/*      initializes it appropriately.                                   */
3010
/************************************************************************/
3011

3012
GTIFDefn *GTIFAllocDefn()
12,853✔
3013
{
3014
    return (GTIFDefn *) CPLCalloc(sizeof(GTIFDefn),1);
12,853✔
3015
}
3016

3017
/************************************************************************/
3018
/*                            GTIFFreeDefn()                            */
3019
/*                                                                      */
3020
/*      Free a GTIF structure allocated by GTIFAllocDefn().             */
3021
/************************************************************************/
3022

3023
void GTIFFreeDefn( GTIFDefn *defn )
12,853✔
3024
{
3025
    VSIFree( defn );
12,853✔
3026
}
12,853✔
3027

3028
/************************************************************************/
3029
/*                       GTIFAttachPROJContext()                        */
3030
/*                                                                      */
3031
/*      Attach an existing PROJ context to the GTIF handle, but         */
3032
/*      ownership of the context remains to the caller.                 */
3033
/************************************************************************/
3034

3035
void GTIFAttachPROJContext( GTIF *psGTIF, void* pjContext )
33,165✔
3036
{
3037
    if( psGTIF->own_pj_context )
33,165✔
3038
    {
3039
        proj_context_destroy(psGTIF->pj_context);
×
3040
    }
3041
    psGTIF->own_pj_context = FALSE;
33,165✔
3042
    psGTIF->pj_context = (PJ_CONTEXT*) pjContext;
33,165✔
3043
}
33,165✔
3044

3045
/************************************************************************/
3046
/*                         GTIFGetPROJContext()                         */
3047
/*                                                                      */
3048
/*      Return the PROJ context attached to the GTIF handle.            */
3049
/*      If it has not yet been instantiated and instantiateIfNeeded=TRUE*/
3050
/*      then, it will be instantiated (and owned by GTIF handle).       */
3051
/************************************************************************/
3052

3053
void *GTIFGetPROJContext( GTIF *psGTIF, int instantiateIfNeeded,
29,024✔
3054
                          int* out_gtif_own_pj_context )
3055
{
3056
    if( psGTIF->pj_context || !instantiateIfNeeded )
29,024✔
3057
    {
3058
        if( out_gtif_own_pj_context )
29,024✔
3059
        {
3060
            *out_gtif_own_pj_context = psGTIF->own_pj_context;
×
3061
        }
3062
        return psGTIF->pj_context;
29,024✔
3063
    }
3064
    psGTIF->pj_context = proj_context_create();
×
3065
    psGTIF->own_pj_context = psGTIF->pj_context != NULL;
×
3066
    if( out_gtif_own_pj_context )
×
3067
    {
3068
        *out_gtif_own_pj_context = psGTIF->own_pj_context;
×
3069
    }
3070
    return psGTIF->pj_context;
×
3071
}
3072

3073

3074
void GTIFDeaccessCSV( void )
×
3075
{
3076
    /* No operation */
3077
}
×
3078

3079
#ifndef GDAL_COMPILATION
3080
void SetCSVFilenameHook( const char *(*CSVFileOverride)(const char *) )
3081
{
3082
    (void)CSVFileOverride;
3083
    /* No operation */
3084
}
3085
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc