LCOV - code coverage report
Current view: directory - frmts/gtiff/libgeotiff - geo_normalize.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1055 727 68.9 %
Date: 2012-04-28 Functions: 18 16 88.9 %

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

Generated by: LCOV version 1.7