LCOV - code coverage report
Current view: directory - frmts/gtiff/libgeotiff - geo_normalize.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1057 772 73.0 %
Date: 2012-12-26 Functions: 18 16 88.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: geo_normalize.c 2210 2012-05-16 00:18:02Z warmerdam $
       3                 :  *
       4                 :  * Project:  libgeotiff
       5                 :  * Purpose:  Code to normalize PCS and other composite codes in a GeoTIFF file.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 1999, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  *****************************************************************************/
      29                 :  
      30                 : #include "cpl_serv.h"
      31                 : #include "geo_tiffp.h"
      32                 : #include "geovalues.h"
      33                 : #include "geo_normalize.h"
      34                 : 
      35                 : #ifndef KvUserDefined
      36                 : #  define KvUserDefined 32767
      37                 : #endif
      38                 : 
      39                 : #ifndef PI
      40                 : #  define PI 3.14159265358979323846
      41                 : #endif
      42                 : 
      43                 : /* EPSG Codes for projection parameters.  Unfortunately, these bear no
      44                 :    relationship to the GeoTIFF codes even though the names are so similar. */
      45                 : 
      46                 : #define EPSGNatOriginLat         8801
      47                 : #define EPSGNatOriginLong        8802
      48                 : #define EPSGNatOriginScaleFactor 8805
      49                 : #define EPSGFalseEasting         8806
      50                 : #define EPSGFalseNorthing        8807
      51                 : #define EPSGProjCenterLat        8811
      52                 : #define EPSGProjCenterLong       8812
      53                 : #define EPSGAzimuth              8813
      54                 : #define EPSGAngleRectifiedToSkewedGrid 8814
      55                 : #define EPSGInitialLineScaleFactor 8815
      56                 : #define EPSGProjCenterEasting    8816
      57                 : #define EPSGProjCenterNorthing   8817
      58                 : #define EPSGPseudoStdParallelLat 8818
      59                 : #define EPSGPseudoStdParallelScaleFactor 8819
      60                 : #define EPSGFalseOriginLat       8821
      61                 : #define EPSGFalseOriginLong      8822
      62                 : #define EPSGStdParallel1Lat      8823
      63                 : #define EPSGStdParallel2Lat      8824
      64                 : #define EPSGFalseOriginEasting   8826
      65                 : #define EPSGFalseOriginNorthing  8827
      66                 : #define EPSGSphericalOriginLat   8828
      67                 : #define EPSGSphericalOriginLong  8829
      68                 : #define EPSGInitialLongitude     8830
      69                 : #define EPSGZoneWidth            8831
      70                 : #define EPSGLatOfStdParallel     8832
      71                 : #define EPSGOriginLong           8833
      72                 : #define EPSGTopocentricOriginLat 8834
      73                 : #define EPSGTopocentricOriginLong 8835
      74                 : #define EPSGTopocentricOriginHeight 8836
      75                 : 
      76                 : /************************************************************************/
      77                 : /*                           GTIFGetPCSInfo()                           */
      78                 : /************************************************************************/
      79                 : 
      80            1102 : int GTIFGetPCSInfo( int nPCSCode, char **ppszEPSGName, 
      81                 :                     short *pnProjOp, short *pnUOMLengthCode, 
      82                 :                     short *pnGeogCS )
      83                 : 
      84                 : {
      85                 :     char  **papszRecord;
      86                 :     char  szSearchKey[24];
      87                 :     const char  *pszFilename;
      88                 :     int         nDatum;
      89                 :     int         nZone;
      90                 : 
      91            1102 :     int Proj = GTIFPCSToMapSys( nPCSCode, &nDatum, &nZone );
      92            2134 :     if ((Proj == MapSys_UTM_North || Proj == MapSys_UTM_South) &&
      93            1032 :         nDatum != KvUserDefined)
      94                 :     {
      95            1032 :         const char* pszDatumName = NULL;
      96            1032 :         switch (nDatum)
      97                 :         {
      98             954 :             case GCS_NAD27: pszDatumName = "NAD27"; break;
      99               0 :             case GCS_NAD83: pszDatumName = "NAD83"; break;
     100               0 :             case GCS_WGS_72: pszDatumName = "WGS 72"; break;
     101               0 :             case GCS_WGS_72BE: pszDatumName = "WGS 72BE"; break;
     102              78 :             case GCS_WGS_84: pszDatumName = "WGS 84"; break;
     103                 :             default: break;
     104                 :         }
     105                 : 
     106            1032 :         if (pszDatumName)
     107                 :         {
     108            1032 :             if (ppszEPSGName)
     109                 :             {
     110                 :                 char szEPSGName[64];
     111             516 :                 sprintf(szEPSGName, "%s / UTM zone %d%c",
     112                 :                         pszDatumName, nZone, (Proj == MapSys_UTM_North) ? 'N' : 'S');
     113             516 :                 *ppszEPSGName = CPLStrdup(szEPSGName);
     114                 :             }
     115                 : 
     116            1032 :             if (pnProjOp)
     117             516 :                 *pnProjOp = (short) (((Proj == MapSys_UTM_North) ? Proj_UTM_zone_1N - 1 : Proj_UTM_zone_1S - 1) + nZone);
     118                 : 
     119            1032 :             if (pnUOMLengthCode)
     120             516 :                 *pnUOMLengthCode = 9001; /* Linear_Meter */
     121                 : 
     122            1032 :             if (pnGeogCS)
     123             516 :                 *pnGeogCS = (short) nDatum;
     124                 : 
     125            1032 :             return TRUE;
     126                 :         }
     127                 :     }
     128                 : 
     129                 : /* -------------------------------------------------------------------- */
     130                 : /*      Search the pcs.override table for this PCS.                     */
     131                 : /* -------------------------------------------------------------------- */
     132              70 :     pszFilename = CSVFilename( "pcs.override.csv" );
     133              70 :     sprintf( szSearchKey, "%d", nPCSCode );
     134              70 :     papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
     135                 :                                      szSearchKey, CC_Integer );
     136                 : 
     137                 : /* -------------------------------------------------------------------- */
     138                 : /*      If not found, search the EPSG PCS database.                     */
     139                 : /* -------------------------------------------------------------------- */
     140              70 :     if( papszRecord == NULL )
     141                 :     {
     142              70 :         pszFilename = CSVFilename( "pcs.csv" );
     143                 :         
     144              70 :         sprintf( szSearchKey, "%d", nPCSCode );
     145              70 :         papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
     146                 :                                          szSearchKey, CC_Integer );
     147                 : 
     148              70 :         if( papszRecord == NULL )
     149               0 :             return FALSE;
     150                 :     }
     151                 : 
     152                 : /* -------------------------------------------------------------------- */
     153                 : /*      Get the name, if requested.                                     */
     154                 : /* -------------------------------------------------------------------- */
     155              70 :     if( ppszEPSGName != NULL )
     156                 :     {
     157              35 :         *ppszEPSGName =
     158              35 :             CPLStrdup( CSLGetField( papszRecord,
     159                 :                                     CSVGetFileFieldId(pszFilename,
     160                 :                                                       "COORD_REF_SYS_NAME") ));
     161                 :     }
     162                 : 
     163                 : /* -------------------------------------------------------------------- */
     164                 : /*      Get the UOM Length code, if requested.                          */
     165                 : /* -------------------------------------------------------------------- */
     166              70 :     if( pnUOMLengthCode != NULL )
     167                 :     {
     168                 :         const char  *pszValue;
     169                 : 
     170              35 :         pszValue =
     171              35 :             CSLGetField( papszRecord,
     172                 :                          CSVGetFileFieldId(pszFilename,"UOM_CODE"));
     173              35 :         if( atoi(pszValue) > 0 )
     174              35 :             *pnUOMLengthCode = (short) atoi(pszValue);
     175                 :         else
     176               0 :             *pnUOMLengthCode = KvUserDefined;
     177                 :     }
     178                 : 
     179                 : /* -------------------------------------------------------------------- */
     180                 : /*      Get the UOM Length code, if requested.                          */
     181                 : /* -------------------------------------------------------------------- */
     182              70 :     if( pnProjOp != NULL )
     183                 :     {
     184                 :         const char  *pszValue;
     185                 : 
     186              35 :         pszValue =
     187              35 :             CSLGetField( papszRecord,
     188                 :                          CSVGetFileFieldId(pszFilename,"COORD_OP_CODE"));
     189              35 :         if( atoi(pszValue) > 0 )
     190              35 :             *pnProjOp = (short) atoi(pszValue);
     191                 :         else
     192               0 :             *pnUOMLengthCode = KvUserDefined;
     193                 :     }
     194                 : 
     195                 : /* -------------------------------------------------------------------- */
     196                 : /*      Get the GeogCS (Datum with PM) code, if requested.    */
     197                 : /* -------------------------------------------------------------------- */
     198              70 :     if( pnGeogCS != NULL )
     199                 :     {
     200                 :         const char  *pszValue;
     201                 : 
     202              35 :         pszValue =
     203              35 :             CSLGetField( papszRecord,
     204                 :                          CSVGetFileFieldId(pszFilename,"SOURCE_GEOGCRS_CODE"));
     205              35 :         if( atoi(pszValue) > 0 )
     206              35 :             *pnGeogCS = (short) atoi(pszValue);
     207                 :         else
     208               0 :             *pnGeogCS = KvUserDefined;
     209                 :     }
     210                 : 
     211              70 :     return TRUE;
     212                 : }
     213                 : 
     214                 : /************************************************************************/
     215                 : /*                           GTIFAngleToDD()                            */
     216                 : /*                                                                      */
     217                 : /*      Convert a numeric angle to decimal degress.                     */
     218                 : /************************************************************************/
     219                 : 
     220              48 : double GTIFAngleToDD( double dfAngle, int nUOMAngle )
     221                 : 
     222                 : {
     223              48 :     if( nUOMAngle == 9110 )   /* DDD.MMSSsss */
     224                 :     {
     225                 :         char  szAngleString[32];
     226                 : 
     227               0 :         sprintf( szAngleString, "%12.7f", dfAngle );
     228               0 :         dfAngle = GTIFAngleStringToDD( szAngleString, nUOMAngle );
     229                 :     }
     230              48 :     else if ( nUOMAngle != KvUserDefined )
     231                 :     {
     232              31 :         double    dfInDegrees = 1.0;
     233                 :         
     234              31 :         GTIFGetUOMAngleInfo( nUOMAngle, NULL, &dfInDegrees );
     235              31 :         dfAngle = dfAngle * dfInDegrees;
     236                 :     }
     237                 : 
     238              48 :     return( dfAngle );
     239                 : }
     240                 : 
     241                 : /************************************************************************/
     242                 : /*                        GTIFAngleStringToDD()                         */
     243                 : /*                                                                      */
     244                 : /*      Convert an angle in the specified units to decimal degrees.     */
     245                 : /************************************************************************/
     246                 : 
     247              83 : double GTIFAngleStringToDD( const char * pszAngle, int nUOMAngle )
     248                 : 
     249                 : {
     250                 :     double  dfAngle;
     251                 :     
     252              83 :     if( nUOMAngle == 9110 )   /* DDD.MMSSsss */
     253                 :     {
     254                 :         char  *pszDecimal;
     255                 :         
     256              23 :         dfAngle = ABS(atoi(pszAngle));
     257              23 :         pszDecimal = strchr(pszAngle,'.');
     258              23 :         if( pszDecimal != NULL && strlen(pszDecimal) > 1 )
     259                 :         {
     260                 :             char  szMinutes[3];
     261                 :             char  szSeconds[64];
     262                 : 
     263              21 :             szMinutes[0] = pszDecimal[1];
     264              36 :             if( pszDecimal[2] >= '0' && pszDecimal[2] <= '9' )
     265              15 :                 szMinutes[1] = pszDecimal[2];
     266                 :             else
     267               6 :                 szMinutes[1] = '0';
     268                 :             
     269              21 :             szMinutes[2] = '\0';
     270              21 :             dfAngle += atoi(szMinutes) / 60.0;
     271                 : 
     272              21 :             if( strlen(pszDecimal) > 3 )
     273                 :             {
     274              10 :                 szSeconds[0] = pszDecimal[3];
     275              20 :                 if( pszDecimal[4] >= '0' && pszDecimal[4] <= '9' )
     276                 :                 {
     277              10 :                     szSeconds[1] = pszDecimal[4];
     278              10 :                     szSeconds[2] = '.';
     279              10 :                     strncpy( szSeconds+3, pszDecimal + 5, sizeof(szSeconds) - 3 );
     280              10 :                     szSeconds[sizeof(szSeconds) - 1] = 0;
     281                 :                 }
     282                 :                 else
     283                 :                 {
     284               0 :                     szSeconds[1] = '0';
     285               0 :                     szSeconds[2] = '\0';
     286                 :                 }
     287              10 :                 dfAngle += GTIFAtof(szSeconds) / 3600.0;
     288                 :             }
     289                 :         }
     290                 : 
     291              23 :         if( pszAngle[0] == '-' )
     292               6 :             dfAngle *= -1;
     293                 :     }
     294              69 :     else if( nUOMAngle == 9105 || nUOMAngle == 9106 ) /* grad */
     295                 :     {
     296               9 :         dfAngle = 180 * (GTIFAtof(pszAngle ) / 200);
     297                 :     }
     298              51 :     else if( nUOMAngle == 9101 )      /* radians */
     299                 :     {
     300               0 :         dfAngle = 180 * (GTIFAtof(pszAngle ) / PI);
     301                 :     }
     302              51 :     else if( nUOMAngle == 9103 )      /* arc-minute */
     303                 :     {
     304               0 :         dfAngle = GTIFAtof(pszAngle) / 60;
     305                 :     }
     306              51 :     else if( nUOMAngle == 9104 )      /* arc-second */
     307                 :     {
     308               0 :         dfAngle = GTIFAtof(pszAngle) / 3600;
     309                 :     }
     310                 :     else /* decimal degrees ... some cases missing but seeminly never used */
     311                 :     {
     312              51 :         CPLAssert( nUOMAngle == 9102 || nUOMAngle == KvUserDefined
     313                 :                    || nUOMAngle == 0 );
     314                 :         
     315              51 :         dfAngle = GTIFAtof(pszAngle );
     316                 :     }
     317                 : 
     318              83 :     return( dfAngle );
     319                 : }
     320                 : 
     321                 : /************************************************************************/
     322                 : /*                           GTIFGetGCSInfo()                           */
     323                 : /*                                                                      */
     324                 : /*      Fetch the datum, and prime meridian related to a particular     */
     325                 : /*      GCS.                                                            */
     326                 : /************************************************************************/
     327                 : 
     328            2045 : int GTIFGetGCSInfo( int nGCSCode, char ** ppszName,
     329                 :                     short * pnDatum, short * pnPM, short *pnUOMAngle )
     330                 : 
     331                 : {
     332                 :     char  szSearchKey[24];
     333            2045 :     int   nDatum=0, nPM, nUOMAngle;
     334                 :     const char *pszFilename;
     335                 : 
     336                 : /* -------------------------------------------------------------------- */
     337                 : /*      Handle some "well known" GCS codes directly                     */
     338                 : /* -------------------------------------------------------------------- */
     339            2045 :     const char * pszName = NULL;
     340            2045 :     nPM = PM_Greenwich;
     341            2045 :     nUOMAngle = Angular_DMS_Hemisphere; 
     342            2045 :     if( nGCSCode == GCS_NAD27 )
     343                 :     {
     344             991 :         nDatum = Datum_North_American_Datum_1927;
     345             991 :         pszName = "NAD27";
     346                 :     }
     347            1054 :     else if( nGCSCode == GCS_NAD83 )
     348                 :     {
     349               4 :         nDatum = Datum_North_American_Datum_1983;
     350               4 :         pszName = "NAD83";
     351                 :     }
     352            1050 :     else if( nGCSCode == GCS_WGS_84 )
     353                 :     {
     354             976 :         nDatum = Datum_WGS84;
     355             976 :         pszName = "WGS 84";
     356                 :     }
     357              74 :     else if( nGCSCode == GCS_WGS_72 )
     358                 :     {
     359               0 :         nDatum = Datum_WGS72;
     360               0 :         pszName = "WGS 72";
     361                 :     }
     362              74 :     else if ( nGCSCode == KvUserDefined )
     363                 :     {
     364              30 :         return FALSE;
     365                 :     }
     366                 : 
     367            2015 :     if (pszName != NULL)
     368                 :     {
     369            1971 :         if( ppszName != NULL )
     370             985 :             *ppszName = CPLStrdup( pszName );
     371            1971 :         if( pnDatum != NULL )
     372             986 :             *pnDatum = (short) nDatum;
     373            1971 :         if( pnPM != NULL )
     374             986 :             *pnPM = (short) nPM;
     375            1971 :         if( pnUOMAngle != NULL )
     376             986 :             *pnUOMAngle = (short) nUOMAngle;
     377                 : 
     378            1971 :         return TRUE;
     379                 :     }
     380                 : 
     381                 : /* -------------------------------------------------------------------- */
     382                 : /*      Search the database for the corresponding datum code.           */
     383                 : /* -------------------------------------------------------------------- */
     384              44 :     pszFilename = CSVFilename("gcs.override.csv");
     385              44 :     sprintf( szSearchKey, "%d", nGCSCode );
     386              44 :     nDatum = atoi(CSVGetField( pszFilename,
     387                 :                                "COORD_REF_SYS_CODE", szSearchKey, 
     388                 :                                CC_Integer, "DATUM_CODE" ) );
     389                 : 
     390              44 :     if( nDatum < 1 )
     391                 :     {
     392              44 :         pszFilename = CSVFilename("gcs.csv");
     393              44 :         sprintf( szSearchKey, "%d", nGCSCode );
     394              44 :         nDatum = atoi(CSVGetField( pszFilename,
     395                 :                                    "COORD_REF_SYS_CODE", szSearchKey, 
     396                 :                                    CC_Integer, "DATUM_CODE" ) );
     397                 :     }
     398                 : 
     399              44 :     if( nDatum < 1 )
     400                 :     {
     401               0 :         return FALSE;
     402                 :     }
     403                 : 
     404              44 :     if( pnDatum != NULL )
     405              22 :         *pnDatum = (short) nDatum;
     406                 :     
     407                 : /* -------------------------------------------------------------------- */
     408                 : /*      Get the PM.                                                     */
     409                 : /* -------------------------------------------------------------------- */
     410              44 :     if( pnPM != NULL )
     411                 :     {
     412              22 :         nPM = atoi(CSVGetField( pszFilename,
     413                 :                                 "COORD_REF_SYS_CODE", szSearchKey, CC_Integer,
     414                 :                                 "PRIME_MERIDIAN_CODE" ) );
     415                 : 
     416              22 :         if( nPM < 1 )
     417               0 :             return FALSE;
     418                 : 
     419              22 :         *pnPM = (short) nPM;
     420                 :     }
     421                 : 
     422                 : /* -------------------------------------------------------------------- */
     423                 : /*      Get the angular units.                                          */
     424                 : /* -------------------------------------------------------------------- */
     425              44 :     nUOMAngle = atoi(CSVGetField( pszFilename,
     426                 :                                   "COORD_REF_SYS_CODE",szSearchKey, CC_Integer,
     427                 :                                   "UOM_CODE" ) );
     428                 : 
     429              44 :     if( nUOMAngle < 1 )
     430               0 :         return FALSE;
     431                 : 
     432              44 :     if( pnUOMAngle != NULL )
     433              22 :         *pnUOMAngle = (short) nUOMAngle;
     434                 : 
     435                 : /* -------------------------------------------------------------------- */
     436                 : /*      Get the name, if requested.                                     */
     437                 : /* -------------------------------------------------------------------- */
     438              44 :     if( ppszName != NULL )
     439              22 :         *ppszName =
     440              22 :             CPLStrdup(CSVGetField( pszFilename,
     441                 :                                    "COORD_REF_SYS_CODE",szSearchKey,CC_Integer,
     442                 :                                    "COORD_REF_SYS_NAME" ));
     443                 :     
     444              44 :     return( TRUE );
     445                 : }
     446                 : 
     447                 : /************************************************************************/
     448                 : /*                        GTIFGetEllipsoidInfo()                        */
     449                 : /*                                                                      */
     450                 : /*      Fetch info about an ellipsoid.  Axes are always returned in     */
     451                 : /*      meters.  SemiMajor computed based on inverse flattening         */
     452                 : /*      where that is provided.                                         */
     453                 : /************************************************************************/
     454                 : 
     455            2022 : int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
     456                 :                           double * pdfSemiMajor, double * pdfSemiMinor )
     457                 : 
     458                 : {
     459                 :     char  szSearchKey[24];
     460            2022 :     double  dfSemiMajor=0.0, dfToMeters = 1.0;
     461                 :     int   nUOMLength;
     462                 :     const char* pszFilename;
     463                 : 
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*      Try some well known ellipsoids.                                 */
     466                 : /* -------------------------------------------------------------------- */
     467            2022 :     double     dfInvFlattening=0.0, dfSemiMinor=0.0;
     468            2022 :     const char *pszName = NULL;
     469                 :     
     470            2022 :     if( nEllipseCode == Ellipse_Clarke_1866 )
     471                 :     {
     472             994 :         pszName = "Clarke 1866";
     473             994 :         dfSemiMajor = 6378206.4;
     474             994 :         dfSemiMinor = 6356583.8;
     475             994 :         dfInvFlattening = 0.0;
     476                 :     }
     477            1028 :     else if( nEllipseCode == Ellipse_GRS_1980 )
     478                 :     {
     479              16 :         pszName = "GRS 1980";
     480              16 :         dfSemiMajor = 6378137.0;
     481              16 :         dfSemiMinor = 0.0;
     482              16 :         dfInvFlattening = 298.257222101;
     483                 :     }
     484            1012 :     else if( nEllipseCode == Ellipse_WGS_84 )
     485                 :     {
     486             978 :         pszName = "WGS 84";
     487             978 :         dfSemiMajor = 6378137.0;
     488             978 :         dfSemiMinor = 0.0;
     489             978 :         dfInvFlattening = 298.257223563;
     490                 :     }
     491              34 :     else if( nEllipseCode == 7043 )
     492                 :     {
     493               6 :         pszName = "WGS 72";
     494               6 :         dfSemiMajor = 6378135.0;
     495               6 :         dfSemiMinor = 0.0;
     496               6 :         dfInvFlattening = 298.26;
     497                 :     }
     498                 : 
     499            2022 :     if (pszName != NULL)
     500                 :     {
     501            1994 :         if( dfSemiMinor == 0.0 )
     502            1000 :             dfSemiMinor = dfSemiMajor * (1 - 1.0/dfInvFlattening);
     503                 : 
     504            1994 :         if( pdfSemiMinor != NULL )
     505             997 :             *pdfSemiMinor = dfSemiMinor;
     506            1994 :         if( pdfSemiMajor != NULL )
     507             997 :             *pdfSemiMajor = dfSemiMajor;
     508            1994 :         if( ppszName != NULL )
     509             997 :             *ppszName = CPLStrdup( pszName );
     510                 : 
     511            1994 :         return TRUE;
     512                 :     }
     513                 : 
     514                 : /* -------------------------------------------------------------------- */
     515                 : /*      Get the semi major axis.                                        */
     516                 : /* -------------------------------------------------------------------- */
     517              28 :     sprintf( szSearchKey, "%d", nEllipseCode );
     518              28 :     pszFilename = CSVFilename("ellipsoid.csv" );
     519                 : 
     520              28 :     dfSemiMajor =
     521              28 :         GTIFAtof(CSVGetField( pszFilename,
     522                 :                           "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     523                 :                           "SEMI_MAJOR_AXIS" ) );
     524                 : 
     525              28 :     if( dfSemiMajor == 0.0 )
     526                 :     {
     527               0 :         return FALSE;
     528                 :     }
     529                 : 
     530                 : /* -------------------------------------------------------------------- */
     531                 : /*  Get the translation factor into meters.       */
     532                 : /* -------------------------------------------------------------------- */
     533              28 :     nUOMLength = atoi(CSVGetField( pszFilename,
     534                 :                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     535                 :                                    "UOM_CODE" ));
     536              28 :     GTIFGetUOMLengthInfo( nUOMLength, NULL, &dfToMeters );
     537                 : 
     538              28 :     dfSemiMajor *= dfToMeters;
     539                 :     
     540              28 :     if( pdfSemiMajor != NULL )
     541              14 :         *pdfSemiMajor = dfSemiMajor;
     542                 :     
     543                 : /* -------------------------------------------------------------------- */
     544                 : /*      Get the semi-minor if requested.  If the Semi-minor axis        */
     545                 : /*      isn't available, compute it based on the inverse flattening.    */
     546                 : /* -------------------------------------------------------------------- */
     547              28 :     if( pdfSemiMinor != NULL )
     548                 :     {
     549              14 :         *pdfSemiMinor =
     550              14 :             GTIFAtof(CSVGetField( pszFilename,
     551                 :                               "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     552                 :                               "SEMI_MINOR_AXIS" )) * dfToMeters;
     553                 : 
     554              14 :         if( *pdfSemiMinor == 0.0 )
     555                 :         {
     556                 :             double  dfInvFlattening;
     557                 :             
     558               8 :             dfInvFlattening = 
     559               8 :                 GTIFAtof(CSVGetField( pszFilename,
     560                 :                                   "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     561                 :                                   "INV_FLATTENING" ));
     562               8 :             *pdfSemiMinor = dfSemiMajor * (1 - 1.0/dfInvFlattening);
     563                 :         }
     564                 :     }
     565                 : 
     566                 : /* -------------------------------------------------------------------- */
     567                 : /*      Get the name, if requested.                                     */
     568                 : /* -------------------------------------------------------------------- */
     569              28 :     if( ppszName != NULL )
     570              14 :         *ppszName =
     571              14 :             CPLStrdup(CSVGetField( pszFilename,
     572                 :                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     573                 :                                    "ELLIPSOID_NAME" ));
     574                 :     
     575              28 :     return( TRUE );
     576                 : }
     577                 : 
     578                 : /************************************************************************/
     579                 : /*                           GTIFGetPMInfo()                            */
     580                 : /*                                                                      */
     581                 : /*      Get the offset between a given prime meridian and Greenwich     */
     582                 : /*      in degrees.                                                     */
     583                 : /************************************************************************/
     584                 : 
     585            2019 : int GTIFGetPMInfo( int nPMCode, char ** ppszName, double *pdfOffset )
     586                 : 
     587                 : {
     588                 :     char  szSearchKey[24];
     589                 :     int   nUOMAngle;
     590                 :     const char *pszFilename;
     591                 : 
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Use a special short cut for Greenwich, since it is so common.   */
     594                 : /* -------------------------------------------------------------------- */
     595            2019 :     if( nPMCode == PM_Greenwich )
     596                 :     {
     597            2004 :         if( pdfOffset != NULL )
     598            1002 :             *pdfOffset = 0.0;
     599            2004 :         if( ppszName != NULL )
     600            1002 :             *ppszName = CPLStrdup( "Greenwich" );
     601            2004 :         return TRUE;
     602                 :     }
     603                 : 
     604                 : /* -------------------------------------------------------------------- */
     605                 : /*      Search the database for the corresponding datum code.           */
     606                 : /* -------------------------------------------------------------------- */
     607              15 :     pszFilename = CSVFilename("prime_meridian.csv");
     608              15 :     sprintf( szSearchKey, "%d", nPMCode );
     609                 : 
     610              15 :     nUOMAngle =
     611              15 :         atoi(CSVGetField( pszFilename, 
     612                 :                           "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     613                 :                           "UOM_CODE" ) );
     614              15 :     if( nUOMAngle < 1 )
     615               3 :         return FALSE;
     616                 : 
     617                 : /* -------------------------------------------------------------------- */
     618                 : /*      Get the PM offset.                                              */
     619                 : /* -------------------------------------------------------------------- */
     620              12 :     if( pdfOffset != NULL )
     621                 :     {
     622               6 :         *pdfOffset =
     623               6 :             GTIFAngleStringToDD(
     624                 :                 CSVGetField( pszFilename, 
     625                 :                              "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     626                 :                              "GREENWICH_LONGITUDE" ),
     627                 :                 nUOMAngle );
     628                 :     }
     629                 :     
     630                 : /* -------------------------------------------------------------------- */
     631                 : /*      Get the name, if requested.                                     */
     632                 : /* -------------------------------------------------------------------- */
     633              12 :     if( ppszName != NULL )
     634               6 :         *ppszName =
     635               6 :             CPLStrdup(
     636                 :                 CSVGetField( pszFilename, 
     637                 :                              "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     638                 :                              "PRIME_MERIDIAN_NAME" ));
     639                 :     
     640              12 :     return( TRUE );
     641                 : }
     642                 : 
     643                 : /************************************************************************/
     644                 : /*                          GTIFGetDatumInfo()                          */
     645                 : /*                                                                      */
     646                 : /*      Fetch the ellipsoid, and name for a datum.                      */
     647                 : /************************************************************************/
     648                 : 
     649            2022 : int GTIFGetDatumInfo( int nDatumCode, char ** ppszName, short * pnEllipsoid )
     650                 : 
     651                 : {
     652                 :     char  szSearchKey[24];
     653            2022 :     int   nEllipsoid = 0;
     654                 :     const char *pszFilename;
     655                 :     FILE       *fp;
     656            2022 :     const char *pszName = NULL;
     657                 : 
     658                 : /* -------------------------------------------------------------------- */
     659                 : /*      Handle a few built-in datums.                                   */
     660                 : /* -------------------------------------------------------------------- */
     661            2022 :     if( nDatumCode == Datum_North_American_Datum_1927 )
     662                 :     {
     663             992 :         nEllipsoid = Ellipse_Clarke_1866;
     664             992 :         pszName = "North American Datum 1927";
     665                 :     }
     666            1030 :     else if( nDatumCode == Datum_North_American_Datum_1983 )
     667                 :     {
     668               4 :         nEllipsoid = Ellipse_GRS_1980;
     669               4 :         pszName = "North American Datum 1983";
     670                 :     }
     671            1026 :     else if( nDatumCode == Datum_WGS84 )
     672                 :     {
     673             976 :         nEllipsoid = Ellipse_WGS_84;
     674             976 :         pszName = "World Geodetic System 1984";
     675                 :     }
     676              50 :     else if( nDatumCode == Datum_WGS72 )
     677                 :     {
     678               6 :         nEllipsoid = 7043; /* WGS72 */
     679               6 :         pszName = "World Geodetic System 1972";
     680                 :     }
     681                 : 
     682            2022 :     if (pszName != NULL)
     683                 :     {
     684            1978 :         if( pnEllipsoid != NULL )
     685             989 :             *pnEllipsoid = (short) nEllipsoid;
     686                 : 
     687            1978 :         if( ppszName != NULL )
     688             989 :             *ppszName = CPLStrdup( pszName );
     689                 : 
     690            1978 :         return TRUE;
     691                 :     }
     692                 : 
     693                 : /* -------------------------------------------------------------------- */
     694                 : /*      If we can't find datum.csv then gdal_datum.csv is an            */
     695                 : /*      acceptable fallback.  Mostly this is for GDAL.                  */
     696                 : /* -------------------------------------------------------------------- */
     697              44 :     pszFilename = CSVFilename( "datum.csv" );
     698              44 :     if( (fp = VSIFOpen(pszFilename,"r")) == NULL )
     699                 :     {
     700              44 :         if( (fp = VSIFOpen(CSVFilename("gdal_datum.csv"), "r")) != NULL )
     701                 :         {
     702              44 :             pszFilename = CSVFilename( "gdal_datum.csv" );
     703              44 :             VSIFClose( fp );
     704                 :         }        
     705                 :     }
     706                 :     else
     707               0 :         VSIFClose( fp );
     708                 : 
     709                 : /* -------------------------------------------------------------------- */
     710                 : /*      Search the database for the corresponding datum code.           */
     711                 : /* -------------------------------------------------------------------- */
     712              44 :     sprintf( szSearchKey, "%d", nDatumCode );
     713                 : 
     714              44 :     nEllipsoid = atoi(CSVGetField( pszFilename,
     715                 :                                    "DATUM_CODE", szSearchKey, CC_Integer,
     716                 :                                    "ELLIPSOID_CODE" ) );
     717                 : 
     718              44 :     if( pnEllipsoid != NULL )
     719              22 :         *pnEllipsoid = (short) nEllipsoid;
     720                 : 
     721              44 :     if( nEllipsoid < 1 )
     722                 :     {
     723               0 :         return FALSE;
     724                 :     }
     725                 : 
     726                 : /* -------------------------------------------------------------------- */
     727                 : /*      Get the name, if requested.                                     */
     728                 : /* -------------------------------------------------------------------- */
     729              44 :     if( ppszName != NULL )
     730              22 :         *ppszName =
     731              22 :             CPLStrdup(CSVGetField( pszFilename,
     732                 :                                    "DATUM_CODE", szSearchKey, CC_Integer,
     733                 :                                    "DATUM_NAME" ));
     734                 :     
     735              44 :     return( TRUE );
     736                 : }
     737                 : 
     738                 : 
     739                 : /************************************************************************/
     740                 : /*                        GTIFGetUOMLengthInfo()                        */
     741                 : /*                                                                      */
     742                 : /*      Note: This function should eventually also know how to          */
     743                 : /*      lookup length aliases in the UOM_LE_ALIAS table.                */
     744                 : /************************************************************************/
     745                 : 
     746            1370 : int GTIFGetUOMLengthInfo( int nUOMLengthCode,
     747                 :                           char **ppszUOMName,
     748                 :                           double * pdfInMeters )
     749                 : 
     750                 : {
     751                 :     char  **papszUnitsRecord;
     752                 :     char  szSearchKey[24];
     753                 :     int   iNameField;
     754                 :     const char *pszFilename;
     755                 : 
     756                 : /* -------------------------------------------------------------------- */
     757                 : /*      We short cut meter to save work and avoid failure for missing   */
     758                 : /*      in the most common cases.               */
     759                 : /* -------------------------------------------------------------------- */
     760            1370 :     if( nUOMLengthCode == 9001 )
     761                 :     {
     762            1319 :         if( ppszUOMName != NULL )
     763             640 :             *ppszUOMName = CPLStrdup( "metre" );
     764            1319 :         if( pdfInMeters != NULL )
     765             679 :             *pdfInMeters = 1.0;
     766                 : 
     767            1319 :         return TRUE;
     768                 :     }
     769                 : 
     770              51 :     if( nUOMLengthCode == 9002 )
     771                 :     {
     772               0 :         if( ppszUOMName != NULL )
     773               0 :             *ppszUOMName = CPLStrdup( "foot" );
     774               0 :         if( pdfInMeters != NULL )
     775               0 :             *pdfInMeters = 0.3048;
     776                 : 
     777               0 :         return TRUE;
     778                 :     }
     779                 : 
     780              51 :     if( nUOMLengthCode == 9003 )
     781                 :     {
     782              38 :         if( ppszUOMName != NULL )
     783              22 :             *ppszUOMName = CPLStrdup( "US survey foot" );
     784              38 :         if( pdfInMeters != NULL )
     785              16 :             *pdfInMeters = 12.0 / 39.37;
     786                 : 
     787              38 :         return TRUE;
     788                 :     }
     789                 : 
     790                 : /* -------------------------------------------------------------------- */
     791                 : /*      Search the units database for this unit.  If we don't find      */
     792                 : /*      it return failure.                                              */
     793                 : /* -------------------------------------------------------------------- */
     794              13 :     pszFilename = CSVFilename( "unit_of_measure.csv" );
     795                 : 
     796              13 :     sprintf( szSearchKey, "%d", nUOMLengthCode );
     797              13 :     papszUnitsRecord =
     798              13 :         CSVScanFileByName( pszFilename,
     799                 :                            "UOM_CODE", szSearchKey, CC_Integer );
     800                 : 
     801              13 :     if( papszUnitsRecord == NULL )
     802               7 :         return FALSE;
     803                 : 
     804                 : /* -------------------------------------------------------------------- */
     805                 : /*      Get the name, if requested.                                     */
     806                 : /* -------------------------------------------------------------------- */
     807               6 :     if( ppszUOMName != NULL )
     808                 :     {
     809               1 :         iNameField = CSVGetFileFieldId( pszFilename,
     810                 :                                         "UNIT_OF_MEAS_NAME" );
     811               1 :         *ppszUOMName = CPLStrdup( CSLGetField(papszUnitsRecord, iNameField) );
     812                 :     }
     813                 :     
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      Get the A and B factor fields, and create the multiplicative    */
     816                 : /*      factor.                                                         */
     817                 : /* -------------------------------------------------------------------- */
     818               6 :     if( pdfInMeters != NULL )
     819                 :     {
     820                 :         int iBFactorField, iCFactorField;
     821                 :         
     822               5 :         iBFactorField = CSVGetFileFieldId( pszFilename, "FACTOR_B" );
     823               5 :         iCFactorField = CSVGetFileFieldId( pszFilename, "FACTOR_C" );
     824                 : 
     825               5 :         if( GTIFAtof(CSLGetField(papszUnitsRecord, iCFactorField)) > 0.0 )
     826               5 :             *pdfInMeters = GTIFAtof(CSLGetField(papszUnitsRecord, iBFactorField))
     827                 :                 / GTIFAtof(CSLGetField(papszUnitsRecord, iCFactorField));
     828                 :         else
     829               0 :             *pdfInMeters = 0.0;
     830                 :     }
     831                 :     
     832               6 :     return( TRUE );
     833                 : }
     834                 : 
     835                 : /************************************************************************/
     836                 : /*                        GTIFGetUOMAngleInfo()                         */
     837                 : /************************************************************************/
     838                 : 
     839            2108 : int GTIFGetUOMAngleInfo( int nUOMAngleCode,
     840                 :                          char **ppszUOMName,
     841                 :                          double * pdfInDegrees )
     842                 : 
     843                 : {
     844            2108 :     const char  *pszUOMName = NULL;
     845            2108 :     double  dfInDegrees = 1.0;
     846                 :     const char *pszFilename;
     847                 :     char  szSearchKey[24];
     848                 : 
     849            2108 :     switch( nUOMAngleCode )
     850                 :     {
     851                 :       case 9101:
     852               0 :         pszUOMName = "radian";
     853               0 :         dfInDegrees = 180.0 / PI;
     854               0 :         break;
     855                 : 
     856                 :       case 9102:
     857                 :       case 9107:
     858                 :       case 9108:
     859                 :       case 9110:
     860                 :       case 9122:
     861            2102 :         pszUOMName = "degree";
     862            2102 :         dfInDegrees = 1.0;
     863            2102 :         break;
     864                 : 
     865                 :       case 9103:
     866               0 :         pszUOMName = "arc-minute";
     867               0 :         dfInDegrees = 1 / 60.0;
     868               0 :         break;
     869                 : 
     870                 :       case 9104:
     871               0 :         pszUOMName = "arc-second";
     872               0 :         dfInDegrees = 1 / 3600.0;
     873               0 :         break;
     874                 : 
     875                 :       case 9105:
     876               6 :         pszUOMName = "grad";
     877               6 :         dfInDegrees = 180.0 / 200.0;
     878               6 :         break;
     879                 : 
     880                 :       case 9106:
     881               0 :         pszUOMName = "gon";
     882               0 :         dfInDegrees = 180.0 / 200.0;
     883               0 :         break;
     884                 : 
     885                 :       case 9109:
     886               0 :         pszUOMName = "microradian";
     887               0 :         dfInDegrees = 180.0 / (PI * 1000000.0);
     888                 :         break;
     889                 : 
     890                 :       default:
     891                 :         break;
     892                 :     }
     893                 :     
     894            2108 :     if (pszUOMName)
     895                 :     {
     896            2108 :         if( ppszUOMName != NULL )
     897                 :         {
     898            1038 :             if( pszUOMName != NULL )
     899            1038 :                 *ppszUOMName = CPLStrdup( pszUOMName );
     900                 :             else
     901               0 :                 *ppszUOMName = NULL;
     902                 :         }
     903                 : 
     904            2108 :         if( pdfInDegrees != NULL )
     905            1070 :             *pdfInDegrees = dfInDegrees;
     906                 : 
     907            2108 :         return TRUE;
     908                 :     }
     909                 : 
     910               0 :     pszFilename = CSVFilename( "unit_of_measure.csv" );
     911               0 :     sprintf( szSearchKey, "%d", nUOMAngleCode );
     912               0 :     pszUOMName = CSVGetField( pszFilename,
     913                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     914                 :                               "UNIT_OF_MEAS_NAME" );
     915                 : 
     916                 : /* -------------------------------------------------------------------- */
     917                 : /*      If the file is found, read from there.  Note that FactorC is    */
     918                 : /*      an empty field for any of the DMS style formats, and in this    */
     919                 : /*      case we really want to return the default InDegrees value       */
     920                 : /*      (1.0) from above.                                               */
     921                 : /* -------------------------------------------------------------------- */
     922               0 :     if( pszUOMName != NULL )
     923                 :     {
     924                 :         double dfFactorB, dfFactorC, dfInRadians;
     925                 :         
     926               0 :         dfFactorB = 
     927               0 :             GTIFAtof(CSVGetField( pszFilename,
     928                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     929                 :                               "FACTOR_B" ));
     930                 :         
     931               0 :         dfFactorC = 
     932               0 :             GTIFAtof(CSVGetField( pszFilename,
     933                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     934                 :                               "FACTOR_C" ));
     935                 : 
     936               0 :         if( dfFactorC != 0.0 )
     937                 :         {
     938               0 :             dfInRadians = (dfFactorB / dfFactorC);
     939               0 :             dfInDegrees = dfInRadians * 180.0 / PI;
     940                 :         }
     941                 :     }
     942                 :     else
     943                 :     {
     944               0 :         return FALSE;
     945                 :     }
     946                 : 
     947                 : /* -------------------------------------------------------------------- */
     948                 : /*      Return to caller.                                               */
     949                 : /* -------------------------------------------------------------------- */
     950               0 :     if( ppszUOMName != NULL )
     951                 :     {
     952               0 :         if( pszUOMName != NULL )
     953               0 :             *ppszUOMName = CPLStrdup( pszUOMName );
     954                 :         else
     955               0 :             *ppszUOMName = NULL;
     956                 :     }
     957                 : 
     958               0 :     if( pdfInDegrees != NULL )
     959               0 :         *pdfInDegrees = dfInDegrees;
     960                 : 
     961               0 :     return( TRUE );
     962                 : }
     963                 : 
     964                 : /************************************************************************/
     965                 : /*                    EPSGProjMethodToCTProjMethod()                    */
     966                 : /*                                                                      */
     967                 : /*      Convert between the EPSG enumeration for projection methods,    */
     968                 : /*      and the GeoTIFF CT codes.                                       */
     969                 : /************************************************************************/
     970                 : 
     971             582 : static int EPSGProjMethodToCTProjMethod( int nEPSG )
     972                 : 
     973                 : {
     974                 :     /* see trf_method.csv for list of EPSG codes */
     975                 :     
     976             582 :     switch( nEPSG )
     977                 :     {
     978                 :       case 9801:
     979               8 :         return( CT_LambertConfConic_1SP );
     980                 : 
     981                 :       case 9802:
     982               8 :         return( CT_LambertConfConic_2SP );
     983                 : 
     984                 :       case 9803:
     985               0 :         return( CT_LambertConfConic_2SP ); /* Belgian variant not supported */
     986                 : 
     987                 :       case 9804:
     988               2 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
     989                 : 
     990                 :       case 9805:
     991               0 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
     992                 :         
     993                 :       /* Mercator 1SP (Spherical) For EPSG:3785 */
     994                 :       case 9841:
     995               0 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
     996                 :         
     997                 :       /* Google Mercator For EPSG:3857 */
     998                 :       case 1024:
     999              16 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
    1000                 : 
    1001                 :       case 9806:
    1002               2 :         return( CT_CassiniSoldner );
    1003                 : 
    1004                 :       case 9807:
    1005             516 :         return( CT_TransverseMercator );
    1006                 : 
    1007                 :       case 9808:
    1008               2 :         return( CT_TransvMercator_SouthOriented );
    1009                 : 
    1010                 :       case 9809:
    1011               2 :         return( CT_ObliqueStereographic );
    1012                 : 
    1013                 :       case 9810:
    1014                 :       case 9829: /* variant B not quite the same - not sure how to handle */ 
    1015               4 :         return( CT_PolarStereographic );
    1016                 : 
    1017                 :       case 9811:
    1018               2 :         return( CT_NewZealandMapGrid );
    1019                 : 
    1020                 :       case 9812:
    1021               0 :         return( CT_ObliqueMercator ); /* is hotine actually different? */
    1022                 : 
    1023                 :       case 9813:
    1024               0 :         return( CT_ObliqueMercator_Laborde );
    1025                 : 
    1026                 :       case 9814:
    1027               0 :         return( CT_ObliqueMercator_Rosenmund ); /* swiss  */
    1028                 : 
    1029                 :       case 9815:
    1030               4 :         return( CT_HotineObliqueMercatorAzimuthCenter );
    1031                 : 
    1032                 :       case 9816: /* tunesia mining grid has no counterpart */
    1033               0 :         return( KvUserDefined );
    1034                 : 
    1035                 :       case 9820:
    1036                 :       case 1027:
    1037               2 :         return( CT_LambertAzimEqualArea );
    1038                 : 
    1039                 :       case 9822:
    1040               6 :         return( CT_AlbersEqualArea );
    1041                 : 
    1042                 :       case 9834:
    1043               2 :         return( CT_CylindricalEqualArea );
    1044                 : 
    1045                 :       default: /* use the EPSG code for other methods */
    1046               6 :         return nEPSG;
    1047                 :     }
    1048                 : 
    1049                 :     return( KvUserDefined );
    1050                 : }
    1051                 : 
    1052                 : /************************************************************************/
    1053                 : /*                            SetGTParmIds()                            */
    1054                 : /*                                                                      */
    1055                 : /*      This is hardcoded logic to set the GeoTIFF parmaeter            */
    1056                 : /*      identifiers for all the EPSG supported projections.  As the     */
    1057                 : /*      trf_method.csv table grows with new projections, this code      */
    1058                 : /*      will need to be updated.                                        */
    1059                 : /************************************************************************/
    1060                 : 
    1061             582 : static int SetGTParmIds( int nCTProjection, 
    1062                 :                          int *panProjParmId, 
    1063                 :                          int *panEPSGCodes )
    1064                 : 
    1065                 : {
    1066                 :     int anWorkingDummy[7];
    1067                 : 
    1068             582 :     if( panEPSGCodes == NULL )
    1069             548 :         panEPSGCodes = anWorkingDummy;
    1070             582 :     if( panProjParmId == NULL )
    1071              34 :         panProjParmId = anWorkingDummy;
    1072                 : 
    1073             582 :     memset( panEPSGCodes, 0, sizeof(int) * 7 );
    1074                 : 
    1075                 :     /* psDefn->nParms = 7; */
    1076                 :     
    1077             582 :     switch( nCTProjection )
    1078                 :     {
    1079                 :       case CT_CassiniSoldner:
    1080                 :       case CT_NewZealandMapGrid:
    1081               4 :         panProjParmId[0] = ProjNatOriginLatGeoKey;
    1082               4 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1083               4 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1084               4 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1085                 : 
    1086               4 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1087               4 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1088               4 :         panEPSGCodes[5] = EPSGFalseEasting;
    1089               4 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1090               4 :         return TRUE;
    1091                 : 
    1092                 :       case CT_ObliqueMercator:
    1093                 :       case CT_HotineObliqueMercatorAzimuthCenter:
    1094               4 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1095               4 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1096               4 :         panProjParmId[2] = ProjAzimuthAngleGeoKey;
    1097               4 :         panProjParmId[3] = ProjRectifiedGridAngleGeoKey;
    1098               4 :         panProjParmId[4] = ProjScaleAtCenterGeoKey;
    1099               4 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1100               4 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1101                 : 
    1102               4 :         panEPSGCodes[0] = EPSGProjCenterLat;
    1103               4 :         panEPSGCodes[1] = EPSGProjCenterLong;
    1104               4 :         panEPSGCodes[2] = EPSGAzimuth;
    1105               4 :         panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
    1106               4 :         panEPSGCodes[4] = EPSGInitialLineScaleFactor;
    1107               4 :         panEPSGCodes[5] = EPSGProjCenterEasting; /* EPSG proj method 9812 uses EPSGFalseEasting, but 9815 uses EPSGProjCenterEasting */
    1108               4 :         panEPSGCodes[6] = EPSGProjCenterNorthing; /* EPSG proj method 9812 uses EPSGFalseNorthing, but 9815 uses EPSGProjCenterNorthing */
    1109               4 :         return TRUE;
    1110                 : 
    1111                 :       case CT_ObliqueMercator_Laborde:
    1112               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1113               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1114               0 :         panProjParmId[2] = ProjAzimuthAngleGeoKey;
    1115               0 :         panProjParmId[4] = ProjScaleAtCenterGeoKey;
    1116               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1117               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1118                 : 
    1119               0 :         panEPSGCodes[0] = EPSGProjCenterLat;
    1120               0 :         panEPSGCodes[1] = EPSGProjCenterLong;
    1121               0 :         panEPSGCodes[2] = EPSGAzimuth;
    1122               0 :         panEPSGCodes[4] = EPSGInitialLineScaleFactor;
    1123               0 :         panEPSGCodes[5] = EPSGProjCenterEasting;
    1124               0 :         panEPSGCodes[6] = EPSGProjCenterNorthing;
    1125               0 :         return TRUE;
    1126                 :         
    1127                 :       case CT_LambertConfConic_1SP:
    1128                 :       case CT_Mercator:
    1129                 :       case CT_ObliqueStereographic:
    1130                 :       case CT_PolarStereographic:
    1131                 :       case CT_TransverseMercator:
    1132                 :       case CT_TransvMercator_SouthOriented:
    1133             550 :         panProjParmId[0] = ProjNatOriginLatGeoKey;
    1134             550 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1135             550 :         panProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1136             550 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1137             550 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1138                 : 
    1139             550 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1140             550 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1141             550 :         panEPSGCodes[4] = EPSGNatOriginScaleFactor;
    1142             550 :         panEPSGCodes[5] = EPSGFalseEasting;
    1143             550 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1144             550 :         return TRUE;
    1145                 : 
    1146                 :       case CT_LambertConfConic_2SP:
    1147               8 :         panProjParmId[0] = ProjFalseOriginLatGeoKey;
    1148               8 :         panProjParmId[1] = ProjFalseOriginLongGeoKey;
    1149               8 :         panProjParmId[2] = ProjStdParallel1GeoKey;
    1150               8 :         panProjParmId[3] = ProjStdParallel2GeoKey;
    1151               8 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1152               8 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1153                 : 
    1154               8 :         panEPSGCodes[0] = EPSGFalseOriginLat;
    1155               8 :         panEPSGCodes[1] = EPSGFalseOriginLong;
    1156               8 :         panEPSGCodes[2] = EPSGStdParallel1Lat;
    1157               8 :         panEPSGCodes[3] = EPSGStdParallel2Lat;
    1158               8 :         panEPSGCodes[5] = EPSGFalseOriginEasting;
    1159               8 :         panEPSGCodes[6] = EPSGFalseOriginNorthing;
    1160               8 :         return TRUE;
    1161                 : 
    1162                 :       case CT_AlbersEqualArea:
    1163               6 :         panProjParmId[0] = ProjStdParallel1GeoKey;
    1164               6 :         panProjParmId[1] = ProjStdParallel2GeoKey;
    1165               6 :         panProjParmId[2] = ProjNatOriginLatGeoKey;
    1166               6 :         panProjParmId[3] = ProjNatOriginLongGeoKey;
    1167               6 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1168               6 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1169                 : 
    1170               6 :         panEPSGCodes[0] = EPSGStdParallel1Lat;
    1171               6 :         panEPSGCodes[1] = EPSGStdParallel2Lat;
    1172               6 :         panEPSGCodes[2] = EPSGFalseOriginLat;
    1173               6 :         panEPSGCodes[3] = EPSGFalseOriginLong;
    1174               6 :         panEPSGCodes[5] = EPSGFalseOriginEasting;
    1175               6 :         panEPSGCodes[6] = EPSGFalseOriginNorthing;
    1176               6 :         return TRUE;
    1177                 : 
    1178                 :       case CT_SwissObliqueCylindrical:
    1179               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1180               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1181               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1182               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1183                 : 
    1184                 :         /* EPSG codes? */
    1185               0 :         return TRUE;
    1186                 : 
    1187                 :       case CT_LambertAzimEqualArea:
    1188               2 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1189               2 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1190               2 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1191               2 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1192                 : 
    1193               2 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1194               2 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1195               2 :         panEPSGCodes[5] = EPSGFalseEasting;
    1196               2 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1197               2 :         return TRUE;
    1198                 : 
    1199                 :       case CT_CylindricalEqualArea:
    1200               2 :         panProjParmId[0] = ProjStdParallel1GeoKey;
    1201               2 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1202               2 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1203               2 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1204                 : 
    1205               2 :         panEPSGCodes[0] = EPSGStdParallel1Lat;
    1206               2 :         panEPSGCodes[1] = EPSGFalseOriginLong;
    1207               2 :         panEPSGCodes[5] = EPSGFalseOriginEasting;
    1208               2 :         panEPSGCodes[6] = EPSGFalseOriginNorthing;
    1209               2 :         return TRUE;
    1210                 : 
    1211                 :       default:
    1212               6 :         return( FALSE );
    1213                 :     }
    1214                 : }
    1215                 : 
    1216                 : /************************************************************************/
    1217                 : /*                         GTIFGetProjTRFInfo()                         */
    1218                 : /*                                                                      */
    1219                 : /*      Transform a PROJECTION_TRF_CODE into a projection method,       */
    1220                 : /*      and a set of parameters.  The parameters identify will          */
    1221                 : /*      depend on the returned method, but they will all have been      */
    1222                 : /*      normalized into degrees and meters.                             */
    1223                 : /************************************************************************/
    1224                 : 
    1225             553 : int GTIFGetProjTRFInfo( /* COORD_OP_CODE from coordinate_operation.csv */
    1226                 :                         int nProjTRFCode, 
    1227                 :                         char **ppszProjTRFName,
    1228                 :                         short * pnProjMethod,
    1229                 :                         double * padfProjParms )
    1230                 : 
    1231                 : {
    1232                 :     int   nProjMethod, i, anEPSGCodes[7];
    1233                 :     double  adfProjParms[7];
    1234                 :     char  szTRFCode[16];
    1235                 :     int         nCTProjMethod;
    1236                 :     char       *pszFilename;
    1237                 :     
    1238             553 :     if ((nProjTRFCode >= Proj_UTM_zone_1N && nProjTRFCode <= Proj_UTM_zone_60N) ||
    1239                 :         (nProjTRFCode >= Proj_UTM_zone_1S && nProjTRFCode <= Proj_UTM_zone_60S))
    1240                 :     {
    1241                 :         int bNorth;
    1242                 :         int nZone;
    1243             519 :         if (nProjTRFCode <= Proj_UTM_zone_60N)
    1244                 :         {
    1245             519 :             bNorth = TRUE;
    1246             519 :             nZone = nProjTRFCode - Proj_UTM_zone_1N + 1;
    1247                 :         }
    1248                 :         else
    1249                 :         {
    1250               0 :             bNorth = FALSE;
    1251               0 :             nZone = nProjTRFCode - Proj_UTM_zone_1S + 1;
    1252                 :         }
    1253                 : 
    1254             519 :         if (ppszProjTRFName)
    1255                 :         {
    1256                 :             char szProjTRFName[64];
    1257               0 :             sprintf(szProjTRFName, "UTM zone %d%c",
    1258                 :                     nZone, (bNorth) ? 'N' : 'S');
    1259               0 :             *ppszProjTRFName = CPLStrdup(szProjTRFName);
    1260                 :         }
    1261                 : 
    1262             519 :         if (pnProjMethod)
    1263             519 :             *pnProjMethod = 9807;
    1264                 : 
    1265             519 :         if (padfProjParms)
    1266                 :         {
    1267             519 :             padfProjParms[0] = 0;
    1268             519 :             padfProjParms[1] = -183 + 6 * nZone;
    1269             519 :             padfProjParms[2] = 0;
    1270             519 :             padfProjParms[3] = 0;
    1271             519 :             padfProjParms[4] = 0.9996;
    1272             519 :             padfProjParms[5] = 500000;
    1273             519 :             padfProjParms[6] = (bNorth) ? 0 : 10000000;
    1274                 :         }
    1275                 : 
    1276             519 :         return TRUE;
    1277                 :     }
    1278                 : 
    1279                 : /* -------------------------------------------------------------------- */
    1280                 : /*      Get the proj method.  If this fails to return a meaningful      */
    1281                 : /*      number, then the whole function fails.                          */
    1282                 : /* -------------------------------------------------------------------- */
    1283              34 :     pszFilename = CPLStrdup(CSVFilename("projop_wparm.csv"));
    1284              34 :     sprintf( szTRFCode, "%d", nProjTRFCode );
    1285              34 :     nProjMethod =
    1286              34 :         atoi( CSVGetField( pszFilename,
    1287                 :                            "COORD_OP_CODE", szTRFCode, CC_Integer,
    1288                 :                            "COORD_OP_METHOD_CODE" ) );
    1289              34 :     if( nProjMethod == 0 )
    1290                 :     {
    1291               0 :         CPLFree( pszFilename );
    1292               0 :         return FALSE;
    1293                 :     }
    1294                 : 
    1295                 : /* -------------------------------------------------------------------- */
    1296                 : /*      Initialize a definition of what EPSG codes need to be loaded    */
    1297                 : /*      into what fields in adfProjParms.                               */
    1298                 : /* -------------------------------------------------------------------- */
    1299              34 :     nCTProjMethod = EPSGProjMethodToCTProjMethod( nProjMethod );
    1300              34 :     SetGTParmIds( nCTProjMethod, NULL, anEPSGCodes );
    1301                 : 
    1302                 : /* -------------------------------------------------------------------- */
    1303                 : /*      Get the parameters for this projection.  For the time being     */
    1304                 : /*      I am assuming the first four parameters are angles, the         */
    1305                 : /*      fifth is unitless (normally scale), and the remainder are       */
    1306                 : /*      linear measures.  This works fine for the existing              */
    1307                 : /*      projections, but is a pretty fragile approach.                  */
    1308                 : /* -------------------------------------------------------------------- */
    1309                 : 
    1310             272 :     for( i = 0; i < 7; i++ )
    1311                 :     {
    1312                 :         char    szParamUOMID[32], szParamValueID[32], szParamCodeID[32];
    1313                 :         const char *pszValue;
    1314                 :         int     nUOM;
    1315             238 :         int     nEPSGCode = anEPSGCodes[i];
    1316                 :         int     iEPSG;
    1317                 : 
    1318                 :         /* Establish default */
    1319             238 :         if( nEPSGCode == EPSGAngleRectifiedToSkewedGrid )
    1320               2 :             adfProjParms[i] = 90.0;
    1321             256 :         else if( nEPSGCode == EPSGNatOriginScaleFactor
    1322                 :                  || nEPSGCode == EPSGInitialLineScaleFactor
    1323                 :                  || nEPSGCode == EPSGPseudoStdParallelScaleFactor )
    1324              20 :             adfProjParms[i] = 1.0;
    1325                 :         else
    1326             216 :             adfProjParms[i] = 0.0;
    1327                 : 
    1328                 :         /* If there is no parameter, skip */
    1329             238 :         if( nEPSGCode == 0 )
    1330              76 :             continue;
    1331                 : 
    1332                 :         /* Find the matching parameter */
    1333             567 :         for( iEPSG = 0; iEPSG < 7; iEPSG++ )
    1334                 :         {
    1335             553 :             sprintf( szParamCodeID, "PARAMETER_CODE_%d", iEPSG+1 );
    1336                 : 
    1337             553 :             if( atoi(CSVGetField( pszFilename,
    1338                 :                                   "COORD_OP_CODE", szTRFCode, CC_Integer, 
    1339                 :                                   szParamCodeID )) == nEPSGCode )
    1340             148 :                 break;
    1341                 :         }
    1342                 : 
    1343                 :         /* not found, accept the default */
    1344             162 :         if( iEPSG == 7 )
    1345                 :         {
    1346                 :             /* for CT_ObliqueMercator try alternate parameter codes first */
    1347                 :             /* because EPSG proj method 9812 uses EPSGFalseXXXXX, but 9815 uses EPSGProjCenterXXXXX */
    1348              14 :             if ( nCTProjMethod == CT_ObliqueMercator && nEPSGCode == EPSGProjCenterEasting )
    1349               0 :                 nEPSGCode = EPSGFalseEasting;
    1350              14 :             else if ( nCTProjMethod == CT_ObliqueMercator && nEPSGCode == EPSGProjCenterNorthing )
    1351               0 :                 nEPSGCode = EPSGFalseNorthing;
    1352                 :             else
    1353              14 :                 continue;
    1354                 :                 
    1355               0 :             for( iEPSG = 0; iEPSG < 7; iEPSG++ )
    1356                 :             {
    1357               0 :                 sprintf( szParamCodeID, "PARAMETER_CODE_%d", iEPSG+1 );
    1358                 : 
    1359               0 :                 if( atoi(CSVGetField( pszFilename,
    1360                 :                                       "COORD_OP_CODE", szTRFCode, CC_Integer, 
    1361                 :                                       szParamCodeID )) == nEPSGCode )
    1362               0 :                     break;
    1363                 :             }
    1364                 :             
    1365               0 :             if( iEPSG == 7 )
    1366               0 :                 continue;
    1367                 :         }
    1368                 : 
    1369                 :         /* Get the value, and UOM */
    1370             148 :         sprintf( szParamUOMID, "PARAMETER_UOM_%d", iEPSG+1 );
    1371             148 :         sprintf( szParamValueID, "PARAMETER_VALUE_%d", iEPSG+1 );
    1372                 : 
    1373             148 :         nUOM = atoi(CSVGetField( pszFilename,
    1374                 :                                  "COORD_OP_CODE", szTRFCode, CC_Integer, 
    1375                 :                                  szParamUOMID ));
    1376             148 :         pszValue = CSVGetField( pszFilename,
    1377                 :                                 "COORD_OP_CODE", szTRFCode, CC_Integer, 
    1378                 :                                 szParamValueID );
    1379                 : 
    1380                 :         /* Transform according to the UOM */
    1381             225 :         if( nUOM >= 9100 && nUOM < 9200 )
    1382              77 :             adfProjParms[i] = GTIFAngleStringToDD( pszValue, nUOM );
    1383             131 :         else if( nUOM > 9000 && nUOM < 9100 )
    1384                 :         {
    1385                 :             double dfInMeters;
    1386                 : 
    1387              60 :             if( !GTIFGetUOMLengthInfo( nUOM, NULL, &dfInMeters ) )
    1388               0 :                 dfInMeters = 1.0;
    1389              60 :             adfProjParms[i] = GTIFAtof(pszValue) * dfInMeters;
    1390                 :         }
    1391                 :         else
    1392              11 :             adfProjParms[i] = GTIFAtof(pszValue);
    1393                 :     }
    1394                 : 
    1395                 : /* -------------------------------------------------------------------- */
    1396                 : /*      Get the name, if requested.                                     */
    1397                 : /* -------------------------------------------------------------------- */
    1398              34 :     if( ppszProjTRFName != NULL )
    1399                 :     {
    1400               0 :         *ppszProjTRFName =
    1401               0 :             CPLStrdup(CSVGetField( pszFilename,
    1402                 :                                    "COORD_OP_CODE", szTRFCode, CC_Integer,
    1403                 :                                    "COORD_OP_NAME" ));
    1404                 :     }
    1405                 :     
    1406                 : /* -------------------------------------------------------------------- */
    1407                 : /*      Transfer requested data into passed variables.                  */
    1408                 : /* -------------------------------------------------------------------- */
    1409              34 :     if( pnProjMethod != NULL )
    1410              34 :         *pnProjMethod = (short) nProjMethod;
    1411                 : 
    1412              34 :     if( padfProjParms != NULL )
    1413                 :     {
    1414             272 :         for( i = 0; i < 7; i++ )
    1415             238 :             padfProjParms[i] = adfProjParms[i];
    1416                 :     }
    1417                 : 
    1418              34 :     CPLFree( pszFilename );
    1419                 : 
    1420              34 :     return TRUE;
    1421                 : }
    1422                 : 
    1423                 : /************************************************************************/
    1424                 : /*                         GTIFFetchProjParms()                         */
    1425                 : /*                                                                      */
    1426                 : /*      Fetch the projection parameters for a particular projection     */
    1427                 : /*      from a GeoTIFF file, and fill the GTIFDefn structure out        */
    1428                 : /*      with them.                                                      */
    1429                 : /************************************************************************/
    1430                 : 
    1431              51 : static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
    1432                 : 
    1433                 : {
    1434              51 :     double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
    1435              51 :     double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
    1436              51 :     double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
    1437                 :     int iParm;
    1438                 : 
    1439                 : /* -------------------------------------------------------------------- */
    1440                 : /*      Get the false easting, and northing if available.               */
    1441                 : /* -------------------------------------------------------------------- */
    1442              71 :     if( !GTIFKeyGet(psGTIF, ProjFalseEastingGeoKey, &dfFalseEasting, 0, 1)
    1443              10 :         && !GTIFKeyGet(psGTIF, ProjCenterEastingGeoKey,
    1444                 :                        &dfFalseEasting, 0, 1) 
    1445              10 :         && !GTIFKeyGet(psGTIF, ProjFalseOriginEastingGeoKey,
    1446                 :                        &dfFalseEasting, 0, 1) )
    1447               0 :         dfFalseEasting = 0.0;
    1448                 :         
    1449              71 :     if( !GTIFKeyGet(psGTIF, ProjFalseNorthingGeoKey, &dfFalseNorthing,0,1)
    1450              10 :         && !GTIFKeyGet(psGTIF, ProjCenterNorthingGeoKey,
    1451                 :                        &dfFalseNorthing, 0, 1)
    1452              10 :         && !GTIFKeyGet(psGTIF, ProjFalseOriginNorthingGeoKey,
    1453                 :                        &dfFalseNorthing, 0, 1) )
    1454               0 :         dfFalseNorthing = 0.0;
    1455                 :         
    1456              51 :     switch( psDefn->CTProjection )
    1457                 :     {
    1458                 : /* -------------------------------------------------------------------- */
    1459                 :       case CT_Stereographic:
    1460                 : /* -------------------------------------------------------------------- */
    1461               6 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1462                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1463               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1464                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1465               2 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1466               2 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1467               0 :             dfNatOriginLong = 0.0;
    1468                 : 
    1469               6 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1470                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1471               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1472                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1473               2 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1474               2 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1475               0 :             dfNatOriginLat = 0.0;
    1476                 : 
    1477               2 :         if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
    1478                 :                        &dfNatOriginScale, 0, 1 ) == 0 )
    1479               0 :             dfNatOriginScale = 1.0;
    1480                 :             
    1481                 :         /* notdef: should transform to decimal degrees at this point */
    1482                 : 
    1483               2 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1484               2 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    1485               2 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1486               2 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    1487               2 :         psDefn->ProjParm[4] = dfNatOriginScale;
    1488               2 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1489               2 :         psDefn->ProjParm[5] = dfFalseEasting;
    1490               2 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1491               2 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1492               2 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1493                 : 
    1494               2 :         psDefn->nParms = 7;
    1495               2 :         break;
    1496                 : 
    1497                 : /* -------------------------------------------------------------------- */
    1498                 :       case CT_LambertConfConic_1SP:
    1499                 :       case CT_Mercator:
    1500                 :       case CT_ObliqueStereographic:
    1501                 :       case CT_TransverseMercator:
    1502                 :       case CT_TransvMercator_SouthOriented:
    1503                 : /* -------------------------------------------------------------------- */
    1504               7 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1505                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1506               7 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1507                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1508               0 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1509               0 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1510               0 :             dfNatOriginLong = 0.0;
    1511                 : 
    1512               7 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1513                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1514               7 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1515                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1516               0 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1517               0 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1518               0 :             dfNatOriginLat = 0.0;
    1519                 : 
    1520               7 :         if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
    1521                 :                        &dfNatOriginScale, 0, 1 ) == 0 )
    1522               0 :             dfNatOriginScale = 1.0;
    1523                 :             
    1524                 :         /* notdef: should transform to decimal degrees at this point */
    1525                 : 
    1526               7 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1527               7 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    1528               7 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1529               7 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    1530               7 :         psDefn->ProjParm[4] = dfNatOriginScale;
    1531               7 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1532               7 :         psDefn->ProjParm[5] = dfFalseEasting;
    1533               7 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1534               7 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1535               7 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1536                 : 
    1537               7 :         psDefn->nParms = 7;
    1538               7 :         break;
    1539                 : 
    1540                 : /* -------------------------------------------------------------------- */
    1541                 :       case CT_ObliqueMercator: /* hotine */
    1542                 :       case CT_HotineObliqueMercatorAzimuthCenter: 
    1543                 : /* -------------------------------------------------------------------- */
    1544               6 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1545                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1546               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1547                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1548               2 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1549               2 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1550               0 :             dfNatOriginLong = 0.0;
    1551                 : 
    1552               6 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1553                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1554               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1555                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1556               2 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1557               2 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1558               0 :             dfNatOriginLat = 0.0;
    1559                 : 
    1560               2 :         if( GTIFKeyGet(psGTIF, ProjAzimuthAngleGeoKey, 
    1561                 :                        &dfAzimuth, 0, 1 ) == 0 )
    1562               0 :             dfAzimuth = 0.0;
    1563                 : 
    1564               2 :         if( GTIFKeyGet(psGTIF, ProjRectifiedGridAngleGeoKey,
    1565                 :                        &dfRectGridAngle, 0, 1 ) == 0 )
    1566               0 :             dfRectGridAngle = 90.0;
    1567                 : 
    1568               4 :         if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
    1569                 :                        &dfNatOriginScale, 0, 1 ) == 0
    1570               2 :             && GTIFKeyGet(psGTIF, ProjScaleAtCenterGeoKey,
    1571               2 :                           &dfNatOriginScale, 0, 1 ) == 0 )
    1572               0 :             dfNatOriginScale = 1.0;
    1573                 :             
    1574                 :         /* notdef: should transform to decimal degrees at this point */
    1575                 : 
    1576               2 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1577               2 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    1578               2 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1579               2 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    1580               2 :         psDefn->ProjParm[2] = dfAzimuth;
    1581               2 :         psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
    1582               2 :         psDefn->ProjParm[3] = dfRectGridAngle;
    1583               2 :         psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
    1584               2 :         psDefn->ProjParm[4] = dfNatOriginScale;
    1585               2 :         psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
    1586               2 :         psDefn->ProjParm[5] = dfFalseEasting;
    1587               2 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1588               2 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1589               2 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1590                 : 
    1591               2 :         psDefn->nParms = 7;
    1592               2 :         break;
    1593                 : 
    1594                 : /* -------------------------------------------------------------------- */
    1595                 :       case CT_CassiniSoldner:
    1596                 :       case CT_Polyconic:
    1597                 : /* -------------------------------------------------------------------- */
    1598               2 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1599                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1600               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1601                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1602               0 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1603               0 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1604               0 :             dfNatOriginLong = 0.0;
    1605                 : 
    1606               2 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1607                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1608               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1609                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1610               0 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1611               0 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1612               0 :             dfNatOriginLat = 0.0;
    1613                 : 
    1614               3 :         if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
    1615                 :                        &dfNatOriginScale, 0, 1 ) == 0
    1616               2 :             && GTIFKeyGet(psGTIF, ProjScaleAtCenterGeoKey,
    1617               1 :                           &dfNatOriginScale, 0, 1 ) == 0 )
    1618               1 :             dfNatOriginScale = 1.0;
    1619                 :             
    1620                 :         /* notdef: should transform to decimal degrees at this point */
    1621                 : 
    1622               2 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1623               2 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    1624               2 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1625               2 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    1626               2 :         psDefn->ProjParm[4] = dfNatOriginScale;
    1627               2 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1628               2 :         psDefn->ProjParm[5] = dfFalseEasting;
    1629               2 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1630               2 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1631               2 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1632                 : 
    1633               2 :         psDefn->nParms = 7;
    1634               2 :         break;
    1635                 : 
    1636                 : /* -------------------------------------------------------------------- */
    1637                 :       case CT_AzimuthalEquidistant:
    1638                 :       case CT_MillerCylindrical:
    1639                 :       case CT_Gnomonic:
    1640                 :       case CT_LambertAzimEqualArea:
    1641                 :       case CT_Orthographic:
    1642                 :       case CT_NewZealandMapGrid:
    1643                 : /* -------------------------------------------------------------------- */
    1644              49 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1645                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1646              17 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1647                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1648              16 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1649              16 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1650               0 :             dfNatOriginLong = 0.0;
    1651                 : 
    1652              49 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1653                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1654              17 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1655                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1656              16 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1657              16 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1658               0 :             dfNatOriginLat = 0.0;
    1659                 : 
    1660                 :         /* notdef: should transform to decimal degrees at this point */
    1661                 : 
    1662              17 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1663              17 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    1664              17 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1665              17 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    1666              17 :         psDefn->ProjParm[5] = dfFalseEasting;
    1667              17 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1668              17 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1669              17 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1670                 : 
    1671              17 :         psDefn->nParms = 7;
    1672              17 :         break;
    1673                 : 
    1674                 : /* -------------------------------------------------------------------- */
    1675                 :       case CT_Equirectangular:
    1676                 : /* -------------------------------------------------------------------- */
    1677               6 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1678                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1679               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1680                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1681               2 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1682               2 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1683               0 :             dfNatOriginLong = 0.0;
    1684                 : 
    1685               6 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1686                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1687               2 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1688                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1689               2 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1690               2 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1691               0 :             dfNatOriginLat = 0.0;
    1692                 : 
    1693               2 :         if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
    1694                 :                        &dfStdParallel1, 0, 1 ) == 0 )
    1695               0 :             dfStdParallel1 = 0.0;
    1696                 : 
    1697                 :         /* notdef: should transform to decimal degrees at this point */
    1698                 : 
    1699               2 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1700               2 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    1701               2 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1702               2 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    1703               2 :         psDefn->ProjParm[2] = dfStdParallel1;
    1704               2 :         psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
    1705               2 :         psDefn->ProjParm[5] = dfFalseEasting;
    1706               2 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1707               2 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1708               2 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1709                 : 
    1710               2 :         psDefn->nParms = 7;
    1711               2 :         break;
    1712                 : 
    1713                 : /* -------------------------------------------------------------------- */
    1714                 :       case CT_Robinson:
    1715                 :       case CT_Sinusoidal:
    1716                 :       case CT_VanDerGrinten:
    1717                 : /* -------------------------------------------------------------------- */
    1718               3 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1719                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1720               1 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1721                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1722               1 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1723               1 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1724               0 :             dfNatOriginLong = 0.0;
    1725                 : 
    1726                 :         /* notdef: should transform to decimal degrees at this point */
    1727                 : 
    1728               1 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1729               1 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    1730               1 :         psDefn->ProjParm[5] = dfFalseEasting;
    1731               1 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1732               1 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1733               1 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1734                 : 
    1735               1 :         psDefn->nParms = 7;
    1736               1 :         break;
    1737                 : 
    1738                 : /* -------------------------------------------------------------------- */
    1739                 :       case CT_PolarStereographic:
    1740                 : /* -------------------------------------------------------------------- */
    1741               4 :         if( GTIFKeyGet(psGTIF, ProjStraightVertPoleLongGeoKey, 
    1742                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1743               4 :             && GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1744                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1745               0 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1746                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1747               0 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1748               0 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1749               0 :             dfNatOriginLong = 0.0;
    1750                 : 
    1751               4 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1752                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1753               4 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1754                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1755               0 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1756               0 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1757               0 :             dfNatOriginLat = 0.0;
    1758                 : 
    1759               4 :         if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
    1760                 :                        &dfNatOriginScale, 0, 1 ) == 0
    1761               4 :             && GTIFKeyGet(psGTIF, ProjScaleAtCenterGeoKey,
    1762               0 :                           &dfNatOriginScale, 0, 1 ) == 0 )
    1763               0 :             dfNatOriginScale = 1.0;
    1764                 :             
    1765                 :         /* notdef: should transform to decimal degrees at this point */
    1766                 : 
    1767               4 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1768               4 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;;
    1769               4 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1770               4 :         psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
    1771               4 :         psDefn->ProjParm[4] = dfNatOriginScale;
    1772               4 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1773               4 :         psDefn->ProjParm[5] = dfFalseEasting;
    1774               4 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1775               4 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1776               4 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1777                 : 
    1778               4 :         psDefn->nParms = 7;
    1779               4 :         break;
    1780                 : 
    1781                 : /* -------------------------------------------------------------------- */
    1782                 :       case CT_LambertConfConic_2SP:
    1783                 : /* -------------------------------------------------------------------- */
    1784              10 :         if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
    1785                 :                        &dfStdParallel1, 0, 1 ) == 0 )
    1786               0 :             dfStdParallel1 = 0.0;
    1787                 : 
    1788              10 :         if( GTIFKeyGet(psGTIF, ProjStdParallel2GeoKey, 
    1789                 :                        &dfStdParallel2, 0, 1 ) == 0 )
    1790               0 :             dfStdParallel1 = 0.0;
    1791                 : 
    1792              20 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1793                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1794              10 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1795                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1796              10 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1797               0 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1798               0 :             dfNatOriginLong = 0.0;
    1799                 : 
    1800              20 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1801                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1802              10 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1803                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1804              10 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1805               0 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1806               0 :             dfNatOriginLat = 0.0;
    1807                 : 
    1808                 :         /* notdef: should transform to decimal degrees at this point */
    1809                 : 
    1810              10 :         psDefn->ProjParm[0] = dfNatOriginLat;
    1811              10 :         psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
    1812              10 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1813              10 :         psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
    1814              10 :         psDefn->ProjParm[2] = dfStdParallel1;
    1815              10 :         psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
    1816              10 :         psDefn->ProjParm[3] = dfStdParallel2;
    1817              10 :         psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
    1818              10 :         psDefn->ProjParm[5] = dfFalseEasting;
    1819              10 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1820              10 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1821              10 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1822                 : 
    1823              10 :         psDefn->nParms = 7;
    1824              10 :         break;
    1825                 : 
    1826                 : /* -------------------------------------------------------------------- */
    1827                 :       case CT_AlbersEqualArea:
    1828                 :       case CT_EquidistantConic:
    1829                 : /* -------------------------------------------------------------------- */
    1830               1 :         if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
    1831                 :                        &dfStdParallel1, 0, 1 ) == 0 )
    1832               0 :             dfStdParallel1 = 0.0;
    1833                 : 
    1834               1 :         if( GTIFKeyGet(psGTIF, ProjStdParallel2GeoKey, 
    1835                 :                        &dfStdParallel2, 0, 1 ) == 0 )
    1836               0 :             dfStdParallel2 = 0.0;
    1837                 : 
    1838               1 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1839                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1840               1 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1841                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1842               0 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1843               0 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1844               0 :             dfNatOriginLong = 0.0;
    1845                 : 
    1846               1 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
    1847                 :                        &dfNatOriginLat, 0, 1 ) == 0
    1848               1 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
    1849                 :                           &dfNatOriginLat, 0, 1 ) == 0
    1850               0 :             && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
    1851               0 :                           &dfNatOriginLat, 0, 1 ) == 0 )
    1852               0 :             dfNatOriginLat = 0.0;
    1853                 : 
    1854                 :         /* notdef: should transform to decimal degrees at this point */
    1855                 : 
    1856               1 :         psDefn->ProjParm[0] = dfStdParallel1;
    1857               1 :         psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
    1858               1 :         psDefn->ProjParm[1] = dfStdParallel2;
    1859               1 :         psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
    1860               1 :         psDefn->ProjParm[2] = dfNatOriginLat;
    1861               1 :         psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
    1862               1 :         psDefn->ProjParm[3] = dfNatOriginLong;
    1863               1 :         psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
    1864               1 :         psDefn->ProjParm[5] = dfFalseEasting;
    1865               1 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1866               1 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1867               1 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1868                 : 
    1869               1 :         psDefn->nParms = 7;
    1870               1 :         break;
    1871                 : 
    1872                 : /* -------------------------------------------------------------------- */
    1873                 :       case CT_CylindricalEqualArea:
    1874                 : /* -------------------------------------------------------------------- */
    1875               3 :         if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
    1876                 :                        &dfStdParallel1, 0, 1 ) == 0 )
    1877               0 :             dfStdParallel1 = 0.0;
    1878                 : 
    1879               3 :         if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
    1880                 :                        &dfNatOriginLong, 0, 1 ) == 0
    1881               3 :             && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
    1882                 :                           &dfNatOriginLong, 0, 1 ) == 0
    1883               0 :             && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
    1884               0 :                           &dfNatOriginLong, 0, 1 ) == 0 )
    1885               0 :             dfNatOriginLong = 0.0;
    1886                 : 
    1887                 :         /* notdef: should transform to decimal degrees at this point */
    1888                 : 
    1889               3 :         psDefn->ProjParm[0] = dfStdParallel1;
    1890               3 :         psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
    1891               3 :         psDefn->ProjParm[1] = dfNatOriginLong;
    1892               3 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    1893               3 :         psDefn->ProjParm[5] = dfFalseEasting;
    1894               3 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    1895               3 :         psDefn->ProjParm[6] = dfFalseNorthing;
    1896               3 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    1897                 : 
    1898               3 :         psDefn->nParms = 7;
    1899                 :         break;
    1900                 :     }
    1901                 : 
    1902                 : /* -------------------------------------------------------------------- */
    1903                 : /*      Normalize any linear parameters into meters.  In GeoTIFF        */
    1904                 : /*      the linear projection parameter tags are normally in the        */
    1905                 : /*      units of the coordinate system described.                       */
    1906                 : /* -------------------------------------------------------------------- */
    1907             408 :     for( iParm = 0; iParm < psDefn->nParms; iParm++ )
    1908                 :     {
    1909             357 :         switch( psDefn->ProjParmId[iParm] )
    1910                 :         {
    1911                 :           case ProjFalseEastingGeoKey:
    1912                 :           case ProjFalseNorthingGeoKey:
    1913                 :           case ProjFalseOriginEastingGeoKey:
    1914                 :           case ProjFalseOriginNorthingGeoKey:
    1915                 :           case ProjCenterEastingGeoKey:
    1916                 :           case ProjCenterNorthingGeoKey:
    1917             204 :             if( psDefn->UOMLengthInMeters != 0 
    1918             204 :                 && psDefn->UOMLengthInMeters != 1.0 )
    1919                 :             {
    1920              22 :                 psDefn->ProjParm[iParm] *= psDefn->UOMLengthInMeters;
    1921                 :             }
    1922                 :             break;
    1923                 : 
    1924                 :           default:
    1925                 :             break;
    1926                 :         }
    1927                 :     }
    1928              51 : }
    1929                 : 
    1930                 : /************************************************************************/
    1931                 : /*                            GTIFGetDefn()                             */
    1932                 : /************************************************************************/
    1933                 : 
    1934                 : /**
    1935                 : @param psGTIF GeoTIFF information handle as returned by GTIFNew.
    1936                 : @param psDefn Pointer to an existing GTIFDefn structure.  This structure
    1937                 : does not need to have been pre-initialized at all.
    1938                 : 
    1939                 : @return TRUE if the function has been successful, otherwise FALSE.
    1940                 : 
    1941                 : This function reads the coordinate system definition from a GeoTIFF file,
    1942                 : and <i>normalizes</i> it into a set of component information using 
    1943                 : definitions from CSV (Comma Seperated Value ASCII) files derived from 
    1944                 : EPSG tables.  This function is intended to simplify correct support for
    1945                 : reading files with defined PCS (Projected Coordinate System) codes that
    1946                 : wouldn't otherwise be directly known by application software by reducing
    1947                 : it to the underlying projection method, parameters, datum, ellipsoid, 
    1948                 : prime meridian and units.<p>
    1949                 : 
    1950                 : The application should pass a pointer to an existing uninitialized 
    1951                 : GTIFDefn structure, and GTIFGetDefn() will fill it in.  The fuction 
    1952                 : currently always returns TRUE but in the future will return FALSE if 
    1953                 : CSV files are not found.  In any event, all geokeys actually found in the
    1954                 : file will be copied into the GTIFDefn.  However, if the CSV files aren't
    1955                 : found codes implied by other codes will not be set properly.<p>
    1956                 : 
    1957                 : GTIFGetDefn() will not generally work if the EPSG derived CSV files cannot
    1958                 : be found.  By default a modest attempt will be made to find them, but 
    1959                 : in general it is necessary for the calling application to override the
    1960                 : logic to find them.  This can be done by calling the 
    1961                 : SetCSVFilenameHook() function to
    1962                 : override the search method based on application knowledge of where they are
    1963                 : found.<p>
    1964                 : 
    1965                 : The normalization methodology operates by fetching tags from the GeoTIFF
    1966                 : file, and then setting all other tags implied by them in the structure.  The
    1967                 : implied relationships are worked out by reading definitions from the 
    1968                 : various EPSG derived CSV tables.<p>
    1969                 : 
    1970                 : For instance, if a PCS (ProjectedCSTypeGeoKey) is found in the GeoTIFF file
    1971                 : this code is used to lookup a record in the <tt>horiz_cs.csv</tt> CSV
    1972                 : file.  For example given the PCS 26746 we can find the name
    1973                 : (NAD27 / California zone VI), the GCS 4257 (NAD27), and the ProjectionCode
    1974                 : 10406 (California CS27 zone VI).  The GCS, and ProjectionCode can in turn
    1975                 : be looked up in other tables until all the details of units, ellipsoid, 
    1976                 : prime meridian, datum, projection (LambertConfConic_2SP) and projection
    1977                 : parameters are established.  A full listgeo dump of a file 
    1978                 : for this result might look like the following, all based on a single PCS
    1979                 : value:<p>
    1980                 : 
    1981                 : <pre>
    1982                 : % listgeo -norm ~/data/geotiff/pci_eg/spaf27.tif
    1983                 : Geotiff_Information:
    1984                 :    Version: 1
    1985                 :    Key_Revision: 1.0
    1986                 :    Tagged_Information:
    1987                 :       ModelTiepointTag (2,3):
    1988                 :          0                0                0                
    1989                 :          1577139.71       634349.176       0                
    1990                 :       ModelPixelScaleTag (1,3):
    1991                 :          195.509321       198.32184        0                
    1992                 :       End_Of_Tags.
    1993                 :    Keyed_Information:
    1994                 :       GTModelTypeGeoKey (Short,1): ModelTypeProjected
    1995                 :       GTRasterTypeGeoKey (Short,1): RasterPixelIsArea
    1996                 :       ProjectedCSTypeGeoKey (Short,1): PCS_NAD27_California_VI
    1997                 :       End_Of_Keys.
    1998                 :    End_Of_Geotiff.
    1999                 : 
    2000                 : PCS = 26746 (NAD27 / California zone VI)
    2001                 : Projection = 10406 (California CS27 zone VI)
    2002                 : Projection Method: CT_LambertConfConic_2SP
    2003                 :    ProjStdParallel1GeoKey: 33.883333
    2004                 :    ProjStdParallel2GeoKey: 32.766667
    2005                 :    ProjFalseOriginLatGeoKey: 32.166667
    2006                 :    ProjFalseOriginLongGeoKey: -116.233333
    2007                 :    ProjFalseEastingGeoKey: 609601.219202
    2008                 :    ProjFalseNorthingGeoKey: 0.000000
    2009                 : GCS: 4267/NAD27
    2010                 : Datum: 6267/North American Datum 1927
    2011                 : Ellipsoid: 7008/Clarke 1866 (6378206.40,6356583.80)
    2012                 : Prime Meridian: 8901/Greenwich (0.000000)
    2013                 : Projection Linear Units: 9003/US survey foot (0.304801m)
    2014                 : </pre>
    2015                 : 
    2016                 : Note that GTIFGetDefn() does not inspect or return the tiepoints and scale.
    2017                 : This must be handled seperately as it normally would.  It is intended to
    2018                 : simplify capture and normalization of the coordinate system definition.  
    2019                 : Note that GTIFGetDefn() also does the following things:
    2020                 : 
    2021                 : <ol>
    2022                 : <li> Convert all angular values to decimal degrees.
    2023                 : <li> Convert all linear values to meters. 
    2024                 : <li> Return the linear units and conversion to meters for the tiepoints and
    2025                 : scale (though the tiepoints and scale remain in their native units). 
    2026                 : <li> When reading projection parameters a variety of differences between
    2027                 : different GeoTIFF generators are handled, and a normalized set of parameters
    2028                 : for each projection are always returned.
    2029                 : </ol>
    2030                 : 
    2031                 : Code fields in the GTIFDefn are filled with KvUserDefined if there is not
    2032                 : value to assign.  The parameter lists for each of the underlying projection
    2033                 : transform methods can be found at the
    2034                 : <a href="http://www.remotesensing.org/geotiff/proj_list">Projections</a>
    2035                 : page.  Note that nParms will be set based on the maximum parameter used.
    2036                 : Some of the parameters may not be used in which case the
    2037                 : GTIFDefn::ProjParmId[] will
    2038                 : be zero.  This is done to retain correspondence to the EPSG parameter
    2039                 : numbering scheme.<p>
    2040                 : 
    2041                 : The 
    2042                 : <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 
    2043                 : be used as an example of code that converts a GTIFDefn into another projection
    2044                 : system.<p>
    2045                 : 
    2046                 : @see GTIFKeySet(), SetCSVFilenameHook()
    2047                 : 
    2048                 : */
    2049                 : 
    2050            1076 : int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
    2051                 : 
    2052                 : {
    2053                 :     int   i;
    2054                 :     short nGeogUOMLinear;
    2055                 :     double  dfInvFlattening;
    2056                 :     
    2057                 : /* -------------------------------------------------------------------- */
    2058                 : /*      Initially we default all the information we can.                */
    2059                 : /* -------------------------------------------------------------------- */
    2060            1076 :     psDefn->DefnSet = 1;
    2061            1076 :     psDefn->Model = KvUserDefined;
    2062            1076 :     psDefn->PCS = KvUserDefined;
    2063            1076 :     psDefn->GCS = KvUserDefined;
    2064            1076 :     psDefn->UOMLength = KvUserDefined;
    2065            1076 :     psDefn->UOMLengthInMeters = 1.0;
    2066            1076 :     psDefn->UOMAngle = KvUserDefined;
    2067            1076 :     psDefn->UOMAngleInDegrees = 1.0;
    2068            1076 :     psDefn->Datum = KvUserDefined;
    2069            1076 :     psDefn->Ellipsoid = KvUserDefined;
    2070            1076 :     psDefn->SemiMajor = 0.0;
    2071            1076 :     psDefn->SemiMinor = 0.0;
    2072            1076 :     psDefn->PM = KvUserDefined;
    2073            1076 :     psDefn->PMLongToGreenwich = 0.0;
    2074            1076 :     psDefn->TOWGS84Count = 0;
    2075            1076 :     memset( psDefn->TOWGS84, 0, sizeof(psDefn->TOWGS84) );
    2076                 : 
    2077            1076 :     psDefn->ProjCode = KvUserDefined;
    2078            1076 :     psDefn->Projection = KvUserDefined;
    2079            1076 :     psDefn->CTProjection = KvUserDefined;
    2080                 : 
    2081            1076 :     psDefn->nParms = 0;
    2082           11836 :     for( i = 0; i < MAX_GTIF_PROJPARMS; i++ )
    2083                 :     {
    2084           10760 :         psDefn->ProjParm[i] = 0.0;
    2085           10760 :         psDefn->ProjParmId[i] = 0;
    2086                 :     }
    2087                 : 
    2088            1076 :     psDefn->MapSys = KvUserDefined;
    2089            1076 :     psDefn->Zone = 0;
    2090                 : 
    2091                 : /* -------------------------------------------------------------------- */
    2092                 : /*      Do we have any geokeys?                                         */
    2093                 : /* -------------------------------------------------------------------- */
    2094                 :     {
    2095            1076 :         int     nKeyCount = 0;
    2096                 :         int     anVersion[3];
    2097            1076 :         GTIFDirectoryInfo( psGTIF, anVersion, &nKeyCount );
    2098                 : 
    2099            1076 :         if( nKeyCount == 0 )
    2100                 :         {
    2101              47 :             psDefn->DefnSet = 0;
    2102              47 :             return FALSE;
    2103                 :         }
    2104                 :     }
    2105                 : 
    2106                 : /* -------------------------------------------------------------------- */
    2107                 : /*  Try to get the overall model type.        */
    2108                 : /* -------------------------------------------------------------------- */
    2109            1029 :     GTIFKeyGet(psGTIF,GTModelTypeGeoKey,&(psDefn->Model),0,1);
    2110                 : 
    2111                 : /* -------------------------------------------------------------------- */
    2112                 : /*  Extract the Geog units.           */
    2113                 : /* -------------------------------------------------------------------- */
    2114            1029 :     nGeogUOMLinear = 9001; /* Linear_Meter */
    2115            1029 :     GTIFKeyGet(psGTIF, GeogLinearUnitsGeoKey, &nGeogUOMLinear, 0, 1 );
    2116                 : 
    2117                 : /* -------------------------------------------------------------------- */
    2118                 : /*      Try to get a PCS.                                               */
    2119                 : /* -------------------------------------------------------------------- */
    2120            2657 :     if( GTIFKeyGet(psGTIF,ProjectedCSTypeGeoKey, &(psDefn->PCS),0,1) == 1
    2121            1628 :         && psDefn->PCS != KvUserDefined )
    2122                 :     {
    2123                 :         /*
    2124                 :          * Translate this into useful information.
    2125                 :          */
    2126             546 :         GTIFGetPCSInfo( psDefn->PCS, NULL, &(psDefn->ProjCode),
    2127                 :                         &(psDefn->UOMLength), &(psDefn->GCS) );
    2128                 :     }
    2129                 : 
    2130                 : /* -------------------------------------------------------------------- */
    2131                 : /*       If we have the PCS code, but didn't find it in the CSV files   */
    2132                 : /*      (likely because we can't find them) we will try some ``jiffy    */
    2133                 : /*      rules'' for UTM and state plane.                                */
    2134                 : /* -------------------------------------------------------------------- */
    2135            1029 :     if( psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined )
    2136                 :     {
    2137                 :         int nMapSys, nZone;
    2138               0 :         int nGCS = psDefn->GCS;
    2139                 : 
    2140               0 :         nMapSys = GTIFPCSToMapSys( psDefn->PCS, &nGCS, &nZone );
    2141               0 :         if( nMapSys != KvUserDefined )
    2142                 :         {
    2143               0 :             psDefn->ProjCode = (short) GTIFMapSysToProj( nMapSys, nZone );
    2144               0 :             psDefn->GCS = (short) nGCS;
    2145                 :         }
    2146                 :     }
    2147                 : 
    2148                 : /* -------------------------------------------------------------------- */
    2149                 : /*      If the Proj_ code is specified directly, use that.              */
    2150                 : /* -------------------------------------------------------------------- */
    2151            1029 :     if( psDefn->ProjCode == KvUserDefined )
    2152             483 :         GTIFKeyGet(psGTIF, ProjectionGeoKey, &(psDefn->ProjCode), 0, 1 );
    2153                 :     
    2154            1029 :     if( psDefn->ProjCode != KvUserDefined )
    2155                 :     {
    2156                 :         /*
    2157                 :          * We have an underlying projection transformation value.  Look
    2158                 :          * this up.  For a PCS of ``WGS 84 / UTM 11'' the transformation
    2159                 :          * would be Transverse Mercator, with a particular set of options.
    2160                 :          * The nProjTRFCode itself would correspond to the name
    2161                 :          * ``UTM zone 11N'', and doesn't include datum info.
    2162                 :          */
    2163             548 :         GTIFGetProjTRFInfo( psDefn->ProjCode, NULL, &(psDefn->Projection),
    2164                 :                             psDefn->ProjParm );
    2165                 :         
    2166                 :         /*
    2167                 :          * Set the GeoTIFF identity of the parameters.
    2168                 :          */
    2169             548 :         psDefn->CTProjection = (short) 
    2170             548 :             EPSGProjMethodToCTProjMethod( psDefn->Projection );
    2171                 : 
    2172             548 :         SetGTParmIds( psDefn->CTProjection, psDefn->ProjParmId, NULL);
    2173             548 :         psDefn->nParms = 7;
    2174                 :     }
    2175                 : 
    2176                 : /* -------------------------------------------------------------------- */
    2177                 : /*      Try to get a GCS.  If found, it will override any implied by    */
    2178                 : /*      the PCS.                                                        */
    2179                 : /* -------------------------------------------------------------------- */
    2180            1029 :     GTIFKeyGet(psGTIF, GeographicTypeGeoKey, &(psDefn->GCS), 0, 1 );
    2181            1029 :     if( psDefn->GCS < 1 || psDefn->GCS >= KvUserDefined )
    2182              36 :         psDefn->GCS = KvUserDefined;
    2183                 : 
    2184                 : /* -------------------------------------------------------------------- */
    2185                 : /*      Derive the datum, and prime meridian from the GCS.              */
    2186                 : /* -------------------------------------------------------------------- */
    2187            1029 :     if( psDefn->GCS != KvUserDefined )
    2188                 :     {
    2189             993 :         GTIFGetGCSInfo( psDefn->GCS, NULL, &(psDefn->Datum), &(psDefn->PM),
    2190                 :                         &(psDefn->UOMAngle) );
    2191                 :     }
    2192                 :     
    2193                 : /* -------------------------------------------------------------------- */
    2194                 : /*      Handle the GCS angular units.  GeogAngularUnitsGeoKey           */
    2195                 : /*      overrides the GCS or PCS setting.                               */
    2196                 : /* -------------------------------------------------------------------- */
    2197            1029 :     GTIFKeyGet(psGTIF, GeogAngularUnitsGeoKey, &(psDefn->UOMAngle), 0, 1 );
    2198            1029 :     if( psDefn->UOMAngle != KvUserDefined )
    2199                 :     {
    2200            1024 :         GTIFGetUOMAngleInfo( psDefn->UOMAngle, NULL,
    2201                 :                              &(psDefn->UOMAngleInDegrees) );
    2202                 :     }
    2203                 : 
    2204                 : /* -------------------------------------------------------------------- */
    2205                 : /*      Check for a datum setting, and then use the datum to derive     */
    2206                 : /*      an ellipsoid.                                                   */
    2207                 : /* -------------------------------------------------------------------- */
    2208            1029 :     GTIFKeyGet(psGTIF, GeogGeodeticDatumGeoKey, &(psDefn->Datum), 0, 1 );
    2209                 : 
    2210            1029 :     if( psDefn->Datum != KvUserDefined )
    2211                 :     {
    2212             996 :         GTIFGetDatumInfo( psDefn->Datum, NULL, &(psDefn->Ellipsoid) );
    2213                 :     }
    2214                 : 
    2215                 : /* -------------------------------------------------------------------- */
    2216                 : /*      Check for an explicit ellipsoid.  Use the ellipsoid to          */
    2217                 : /*      derive the ellipsoid characteristics, if possible.              */
    2218                 : /* -------------------------------------------------------------------- */
    2219            1029 :     GTIFKeyGet(psGTIF, GeogEllipsoidGeoKey, &(psDefn->Ellipsoid), 0, 1 );
    2220                 : 
    2221            1029 :     if( psDefn->Ellipsoid != KvUserDefined )
    2222                 :     {
    2223             996 :         GTIFGetEllipsoidInfo( psDefn->Ellipsoid, NULL,
    2224                 :                               &(psDefn->SemiMajor), &(psDefn->SemiMinor) );
    2225                 :     }
    2226                 : 
    2227                 : /* -------------------------------------------------------------------- */
    2228                 : /*      Check for overridden ellipsoid parameters.  It would be nice    */
    2229                 : /*      to warn if they conflict with provided information, but for     */
    2230                 : /*      now we just override.                                           */
    2231                 : /* -------------------------------------------------------------------- */
    2232            1029 :     GTIFKeyGet(psGTIF, GeogSemiMajorAxisGeoKey, &(psDefn->SemiMajor), 0, 1 );
    2233            1029 :     GTIFKeyGet(psGTIF, GeogSemiMinorAxisGeoKey, &(psDefn->SemiMinor), 0, 1 );
    2234                 :     
    2235            1029 :     if( GTIFKeyGet(psGTIF, GeogInvFlatteningGeoKey, &dfInvFlattening, 
    2236                 :                    0, 1 ) == 1 )
    2237                 :     {
    2238             433 :         if( dfInvFlattening != 0.0 )
    2239             433 :             psDefn->SemiMinor = 
    2240             433 :                 psDefn->SemiMajor * (1 - 1.0/dfInvFlattening);
    2241                 :         else
    2242               0 :             psDefn->SemiMinor = psDefn->SemiMajor;
    2243                 :     }
    2244                 :     
    2245                 : /* -------------------------------------------------------------------- */
    2246                 : /*      Get the prime meridian info.                                    */
    2247                 : /* -------------------------------------------------------------------- */
    2248            1029 :     GTIFKeyGet(psGTIF, GeogPrimeMeridianGeoKey, &(psDefn->PM), 0, 1 );
    2249                 : 
    2250            1029 :     if( psDefn->PM != KvUserDefined )
    2251                 :     {
    2252             993 :         GTIFGetPMInfo( psDefn->PM, NULL, &(psDefn->PMLongToGreenwich) );
    2253                 :     }
    2254                 :     else
    2255                 :     {
    2256              36 :         GTIFKeyGet(psGTIF, GeogPrimeMeridianLongGeoKey,
    2257              36 :                    &(psDefn->PMLongToGreenwich), 0, 1 );
    2258                 : 
    2259              36 :         psDefn->PMLongToGreenwich =
    2260              36 :             GTIFAngleToDD( psDefn->PMLongToGreenwich,
    2261              36 :                            psDefn->UOMAngle );
    2262                 :     }
    2263                 : 
    2264                 : /* -------------------------------------------------------------------- */
    2265                 : /*      Get the TOWGS84 parameters.                                     */
    2266                 : /* -------------------------------------------------------------------- */
    2267            1029 :     psDefn->TOWGS84Count = 
    2268            1029 :         GTIFKeyGet(psGTIF, GeogTOWGS84GeoKey, &(psDefn->TOWGS84), 0, 7 );
    2269                 : 
    2270                 : /* -------------------------------------------------------------------- */
    2271                 : /*      Have the projection units of measure been overridden?  We       */
    2272                 : /*      should likely be doing something about angular units too,       */
    2273                 : /*      but these are very rarely not decimal degrees for actual        */
    2274                 : /*      file coordinates.                                               */
    2275                 : /* -------------------------------------------------------------------- */
    2276            1029 :     GTIFKeyGet(psGTIF,ProjLinearUnitsGeoKey,&(psDefn->UOMLength),0,1);
    2277                 : 
    2278            1029 :     if( psDefn->UOMLength != KvUserDefined )
    2279                 :     {
    2280             599 :         GTIFGetUOMLengthInfo( psDefn->UOMLength, NULL,
    2281                 :                               &(psDefn->UOMLengthInMeters) );
    2282                 :     }
    2283                 :     else
    2284                 :     {
    2285             430 :         GTIFKeyGet(psGTIF,ProjLinearUnitSizeGeoKey,&(psDefn->UOMLengthInMeters),0,1);
    2286                 :     }
    2287                 : 
    2288                 : /* -------------------------------------------------------------------- */
    2289                 : /*      Handle a variety of user defined transform types.               */
    2290                 : /* -------------------------------------------------------------------- */
    2291            1029 :     if( GTIFKeyGet(psGTIF,ProjCoordTransGeoKey,
    2292            1029 :                    &(psDefn->CTProjection),0,1) == 1)
    2293                 :     {
    2294              51 :         GTIFFetchProjParms( psGTIF, psDefn );
    2295                 :     }
    2296                 : 
    2297                 : /* -------------------------------------------------------------------- */
    2298                 : /*      Try to set the zoned map system information.                    */
    2299                 : /* -------------------------------------------------------------------- */
    2300            1029 :     psDefn->MapSys = GTIFProjToMapSys( psDefn->ProjCode, &(psDefn->Zone) );
    2301                 : 
    2302                 : /* -------------------------------------------------------------------- */
    2303                 : /*      If this is UTM, and we were unable to extract the projection    */
    2304                 : /*      parameters from the CSV file, just set them directly now,       */
    2305                 : /*      since it's pretty easy, and a common case.                      */
    2306                 : /* -------------------------------------------------------------------- */
    2307            2058 :     if( (psDefn->MapSys == MapSys_UTM_North
    2308            1544 :          || psDefn->MapSys == MapSys_UTM_South)
    2309             514 :         && psDefn->CTProjection == KvUserDefined )
    2310                 :     {
    2311               0 :         psDefn->CTProjection = CT_TransverseMercator;
    2312               0 :         psDefn->nParms = 7;
    2313               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2314               0 :         psDefn->ProjParm[0] = 0.0;
    2315                 :             
    2316               0 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2317               0 :         psDefn->ProjParm[1] = psDefn->Zone*6 - 183.0;
    2318                 :         
    2319               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2320               0 :         psDefn->ProjParm[4] = 0.9996;
    2321                 :         
    2322               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2323               0 :         psDefn->ProjParm[5] = 500000.0;
    2324                 :         
    2325               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2326                 : 
    2327               0 :         if( psDefn->MapSys == MapSys_UTM_North )
    2328               0 :             psDefn->ProjParm[6] = 0.0;
    2329                 :         else
    2330               0 :             psDefn->ProjParm[6] = 10000000.0;
    2331                 :     }
    2332                 : 
    2333            1029 :     return TRUE;
    2334                 : }
    2335                 : 
    2336                 : /************************************************************************/
    2337                 : /*                            GTIFDecToDMS()                            */
    2338                 : /*                                                                      */
    2339                 : /*      Convenient function to translate decimal degrees to DMS         */
    2340                 : /*      format for reporting to a user.                                 */
    2341                 : /************************************************************************/
    2342                 : 
    2343               0 : const char *GTIFDecToDMS( double dfAngle, const char * pszAxis,
    2344                 :                           int nPrecision )
    2345                 : 
    2346                 : {
    2347                 :     int   nDegrees, nMinutes;
    2348                 :     double  dfSeconds;
    2349                 :     char  szFormat[30];
    2350                 :     static char szBuffer[50];
    2351               0 :     const char  *pszHemisphere = NULL;
    2352                 :     double  dfRound;
    2353                 :     int   i;
    2354                 : 
    2355               0 :     dfRound = 0.5/60;
    2356               0 :     for( i = 0; i < nPrecision; i++ )
    2357               0 :         dfRound = dfRound * 0.1;
    2358                 : 
    2359               0 :     nDegrees = (int) ABS(dfAngle);
    2360               0 :     nMinutes = (int) ((ABS(dfAngle) - nDegrees) * 60 + dfRound);
    2361               0 :     dfSeconds = ABS((ABS(dfAngle) * 3600 - nDegrees*3600 - nMinutes*60));
    2362                 : 
    2363               0 :     if( EQUAL(pszAxis,"Long") && dfAngle < 0.0 )
    2364               0 :         pszHemisphere = "W";
    2365               0 :     else if( EQUAL(pszAxis,"Long") )
    2366               0 :         pszHemisphere = "E";
    2367               0 :     else if( dfAngle < 0.0 )
    2368               0 :         pszHemisphere = "S";
    2369                 :     else
    2370               0 :         pszHemisphere = "N";
    2371                 : 
    2372               0 :     sprintf( szFormat, "%%3dd%%2d\'%%%d.%df\"%s",
    2373                 :              nPrecision+3, nPrecision, pszHemisphere );
    2374               0 :     sprintf( szBuffer, szFormat, nDegrees, nMinutes, dfSeconds );
    2375                 : 
    2376               0 :     return( szBuffer );
    2377                 : }
    2378                 : 
    2379                 : /************************************************************************/
    2380                 : /*                           GTIFPrintDefn()                            */
    2381                 : /*                                                                      */
    2382                 : /*      Report the contents of a GTIFDefn structure ... mostly for      */
    2383                 : /*      debugging.                                                      */
    2384                 : /************************************************************************/
    2385                 : 
    2386               0 : void GTIFPrintDefn( GTIFDefn * psDefn, FILE * fp )
    2387                 : 
    2388                 : {
    2389                 : /* -------------------------------------------------------------------- */
    2390                 : /*      Do we have anything to report?                                  */
    2391                 : /* -------------------------------------------------------------------- */
    2392               0 :     if( !psDefn->DefnSet )
    2393                 :     {
    2394               0 :         fprintf( fp, "No GeoKeys found.\n" );
    2395               0 :         return;
    2396                 :     }
    2397                 : 
    2398                 : /* -------------------------------------------------------------------- */
    2399                 : /*      Get the PCS name if possible.                                   */
    2400                 : /* -------------------------------------------------------------------- */
    2401               0 :     if( psDefn->PCS != KvUserDefined )
    2402                 :     {
    2403               0 :         char  *pszPCSName = NULL;
    2404                 :     
    2405               0 :         GTIFGetPCSInfo( psDefn->PCS, &pszPCSName, NULL, NULL, NULL );
    2406               0 :         if( pszPCSName == NULL )
    2407               0 :             pszPCSName = CPLStrdup("name unknown");
    2408                 :         
    2409               0 :         fprintf( fp, "PCS = %d (%s)\n", psDefn->PCS, pszPCSName );
    2410               0 :         CPLFree( pszPCSName );
    2411                 :     }
    2412                 : 
    2413                 : /* -------------------------------------------------------------------- */
    2414                 : /*  Dump the projection code if possible.       */
    2415                 : /* -------------------------------------------------------------------- */
    2416               0 :     if( psDefn->ProjCode != KvUserDefined )
    2417                 :     {
    2418               0 :         char  *pszTRFName = NULL;
    2419                 : 
    2420               0 :         GTIFGetProjTRFInfo( psDefn->ProjCode, &pszTRFName, NULL, NULL );
    2421               0 :         if( pszTRFName == NULL )
    2422               0 :             pszTRFName = CPLStrdup("");
    2423                 :                 
    2424               0 :         fprintf( fp, "Projection = %d (%s)\n",
    2425               0 :                  psDefn->ProjCode, pszTRFName );
    2426                 : 
    2427               0 :         CPLFree( pszTRFName );
    2428                 :     }
    2429                 : 
    2430                 : /* -------------------------------------------------------------------- */
    2431                 : /*      Try to dump the projection method name, and parameters if possible.*/
    2432                 : /* -------------------------------------------------------------------- */
    2433               0 :     if( psDefn->CTProjection != KvUserDefined )
    2434                 :     {
    2435               0 :         char  *pszName = GTIFValueName(ProjCoordTransGeoKey,
    2436               0 :                                          psDefn->CTProjection);
    2437                 :         int     i;
    2438                 : 
    2439               0 :         if( pszName == NULL )
    2440               0 :             pszName = "(unknown)";
    2441                 :             
    2442               0 :         fprintf( fp, "Projection Method: %s\n", pszName );
    2443                 : 
    2444               0 :         for( i = 0; i < psDefn->nParms; i++ )
    2445                 :         {
    2446               0 :             if( psDefn->ProjParmId[i] == 0 )
    2447               0 :                 continue;
    2448                 : 
    2449               0 :             pszName = GTIFKeyName((geokey_t) psDefn->ProjParmId[i]);
    2450               0 :             if( pszName == NULL )
    2451               0 :                 pszName = "(unknown)";
    2452                 : 
    2453               0 :             if( i < 4 )
    2454                 :             {
    2455                 :                 char  *pszAxisName;
    2456                 :                 
    2457               0 :                 if( strstr(pszName,"Long") != NULL )
    2458               0 :                     pszAxisName = "Long";
    2459               0 :                 else if( strstr(pszName,"Lat") != NULL )
    2460               0 :                     pszAxisName = "Lat";
    2461                 :                 else
    2462               0 :                     pszAxisName = "?";
    2463                 :                 
    2464               0 :                 fprintf( fp, "   %s: %f (%s)\n",
    2465                 :                          pszName, psDefn->ProjParm[i],
    2466                 :                          GTIFDecToDMS( psDefn->ProjParm[i], pszAxisName, 2 ) );
    2467                 :             }
    2468               0 :             else if( i == 4 )
    2469               0 :                 fprintf( fp, "   %s: %f\n", pszName, psDefn->ProjParm[i] );
    2470                 :             else
    2471               0 :                 fprintf( fp, "   %s: %f m\n", pszName, psDefn->ProjParm[i] );
    2472                 :         }
    2473                 :     }
    2474                 : 
    2475                 : /* -------------------------------------------------------------------- */
    2476                 : /*      Report the GCS name, and number.                                */
    2477                 : /* -------------------------------------------------------------------- */
    2478               0 :     if( psDefn->GCS != KvUserDefined )
    2479                 :     {
    2480               0 :         char  *pszName = NULL;
    2481                 : 
    2482               0 :         GTIFGetGCSInfo( psDefn->GCS, &pszName, NULL, NULL, NULL );
    2483               0 :         if( pszName == NULL )
    2484               0 :             pszName = CPLStrdup("(unknown)");
    2485                 :         
    2486               0 :         fprintf( fp, "GCS: %d/%s\n", psDefn->GCS, pszName );
    2487               0 :         CPLFree( pszName );
    2488                 :     }
    2489                 : 
    2490                 : /* -------------------------------------------------------------------- */
    2491                 : /*      Report the datum name.                                          */
    2492                 : /* -------------------------------------------------------------------- */
    2493               0 :     if( psDefn->Datum != KvUserDefined )
    2494                 :     {
    2495               0 :         char  *pszName = NULL;
    2496                 : 
    2497               0 :         GTIFGetDatumInfo( psDefn->Datum, &pszName, NULL );
    2498               0 :         if( pszName == NULL )
    2499               0 :             pszName = CPLStrdup("(unknown)");
    2500                 :         
    2501               0 :         fprintf( fp, "Datum: %d/%s\n", psDefn->Datum, pszName );
    2502               0 :         CPLFree( pszName );
    2503                 :     }
    2504                 : 
    2505                 : /* -------------------------------------------------------------------- */
    2506                 : /*      Report the ellipsoid.                                           */
    2507                 : /* -------------------------------------------------------------------- */
    2508               0 :     if( psDefn->Ellipsoid != KvUserDefined )
    2509                 :     {
    2510               0 :         char  *pszName = NULL;
    2511                 : 
    2512               0 :         GTIFGetEllipsoidInfo( psDefn->Ellipsoid, &pszName, NULL, NULL );
    2513               0 :         if( pszName == NULL )
    2514               0 :             pszName = CPLStrdup("(unknown)");
    2515                 :         
    2516               0 :         fprintf( fp, "Ellipsoid: %d/%s (%.2f,%.2f)\n",
    2517               0 :                  psDefn->Ellipsoid, pszName,
    2518                 :                  psDefn->SemiMajor, psDefn->SemiMinor );
    2519               0 :         CPLFree( pszName );
    2520                 :     }
    2521                 :     
    2522                 : /* -------------------------------------------------------------------- */
    2523                 : /*      Report the prime meridian.                                      */
    2524                 : /* -------------------------------------------------------------------- */
    2525               0 :     if( psDefn->PM != KvUserDefined )
    2526                 :     {
    2527               0 :         char  *pszName = NULL;
    2528                 : 
    2529               0 :         GTIFGetPMInfo( psDefn->PM, &pszName, NULL );
    2530                 : 
    2531               0 :         if( pszName == NULL )
    2532               0 :             pszName = CPLStrdup("(unknown)");
    2533                 :         
    2534               0 :         fprintf( fp, "Prime Meridian: %d/%s (%f/%s)\n",
    2535               0 :                  psDefn->PM, pszName,
    2536                 :                  psDefn->PMLongToGreenwich,
    2537                 :                  GTIFDecToDMS( psDefn->PMLongToGreenwich, "Long", 2 ) );
    2538               0 :         CPLFree( pszName );
    2539                 :     }
    2540                 : 
    2541                 : /* -------------------------------------------------------------------- */
    2542                 : /*      Report TOWGS84 parameters.                                      */
    2543                 : /* -------------------------------------------------------------------- */
    2544               0 :     if( psDefn->TOWGS84Count > 0 )
    2545                 :     {
    2546                 :         int i;
    2547                 : 
    2548               0 :         fprintf( fp, "TOWGS84: " );
    2549                 :         
    2550               0 :         for( i = 0; i < psDefn->TOWGS84Count; i++ )
    2551                 :         {
    2552               0 :             if( i > 0 )
    2553               0 :                 fprintf( fp, "," );
    2554               0 :             fprintf( fp, "%g", psDefn->TOWGS84[i] );
    2555                 :         }
    2556                 : 
    2557               0 :         fprintf( fp, "\n" );
    2558                 :     }
    2559                 : 
    2560                 : /* -------------------------------------------------------------------- */
    2561                 : /*      Report the projection units of measure (currently just          */
    2562                 : /*      linear).                                                        */
    2563                 : /* -------------------------------------------------------------------- */
    2564               0 :     if( psDefn->UOMLength != KvUserDefined )
    2565                 :     {
    2566               0 :         char  *pszName = NULL;
    2567                 : 
    2568               0 :         GTIFGetUOMLengthInfo( psDefn->UOMLength, &pszName, NULL );
    2569               0 :         if( pszName == NULL )
    2570               0 :             pszName = CPLStrdup( "(unknown)" );
    2571                 :         
    2572               0 :         fprintf( fp, "Projection Linear Units: %d/%s (%fm)\n",
    2573               0 :                  psDefn->UOMLength, pszName, psDefn->UOMLengthInMeters );
    2574               0 :         CPLFree( pszName );
    2575                 :     }
    2576                 :     else
    2577                 :     {
    2578               0 :         fprintf( fp, "Projection Linear Units: User-Defined (%fm)\n",
    2579                 :                  psDefn->UOMLengthInMeters );
    2580                 :     }
    2581                 : }
    2582                 : 
    2583                 : /************************************************************************/
    2584                 : /*                           GTIFFreeMemory()                           */
    2585                 : /*                                                                      */
    2586                 : /*      Externally visible function to free memory allocated within     */
    2587                 : /*      geo_normalize.c.                                                */
    2588                 : /************************************************************************/
    2589                 : 
    2590            6295 : void GTIFFreeMemory( char * pMemory )
    2591                 : 
    2592                 : {
    2593            6295 :     if( pMemory != NULL )
    2594            6289 :         VSIFree( pMemory );
    2595            6295 : }
    2596                 : 
    2597                 : /************************************************************************/
    2598                 : /*                          GTIFDeaccessCSV()                           */
    2599                 : /*                                                                      */
    2600                 : /*      Free all cached CSV info.                                       */
    2601                 : /************************************************************************/
    2602                 : 
    2603             542 : void GTIFDeaccessCSV()
    2604                 : 
    2605                 : {
    2606             542 :     CSVDeaccess( NULL );
    2607             542 : }

Generated by: LCOV version 1.7