LCOV - code coverage report
Current view: directory - ogr - ogr_fromepsg.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 629 454 72.2 %
Date: 2010-01-09 Functions: 26 24 92.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogr_fromepsg.cpp 18229 2009-12-09 17:06:57Z warmerdam $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Generate an OGRSpatialReference object based on an EPSG
       6                 :  *           PROJCS, or GEOGCS code.
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2000, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "ogr_spatialref.h"
      32                 : #include "ogr_p.h"
      33                 : #include "cpl_csv.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogr_fromepsg.cpp 18229 2009-12-09 17:06:57Z warmerdam $");
      36                 : 
      37                 : #ifndef PI
      38                 : #  define PI 3.14159265358979323846
      39                 : #endif
      40                 : 
      41                 : static const char *papszDatumEquiv[] =
      42                 : {
      43                 :     "Militar_Geographische_Institut",
      44                 :     "Militar_Geographische_Institute",
      45                 :     "World_Geodetic_System_1984",
      46                 :     "WGS_1984",
      47                 :     "WGS_72_Transit_Broadcast_Ephemeris",
      48                 :     "WGS_1972_Transit_Broadcast_Ephemeris",
      49                 :     "World_Geodetic_System_1972",
      50                 :     "WGS_1972",
      51                 :     "European_Terrestrial_Reference_System_89",
      52                 :     "European_Reference_System_1989",
      53                 :     NULL
      54                 : };
      55                 : 
      56                 : /************************************************************************/
      57                 : /*                      OGREPSGDatumNameMassage()                       */
      58                 : /*                                                                      */
      59                 : /*      Massage an EPSG datum name into WMT format.  Also transform     */
      60                 : /*      specific exception cases into WKT versions.                     */
      61                 : /************************************************************************/
      62                 : 
      63           25778 : void OGREPSGDatumNameMassage( char ** ppszDatum )
      64                 : 
      65                 : {
      66                 :     int         i, j;
      67           25778 :     char        *pszDatum = *ppszDatum;
      68                 : 
      69           25778 :     if (pszDatum[0] == '\0')
      70               0 :         return;
      71                 : 
      72                 : /* -------------------------------------------------------------------- */
      73                 : /*      Translate non-alphanumeric values to underscores.               */
      74                 : /* -------------------------------------------------------------------- */
      75          547861 :     for( i = 0; pszDatum[i] != '\0'; i++ )
      76                 :     {
      77         1513387 :         if( !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
      78          787470 :             && !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
      79          203834 :             && !(pszDatum[i] >= '0' && pszDatum[i] <= '9') )
      80                 :         {
      81           63562 :             pszDatum[i] = '_';
      82                 :         }
      83                 :     }
      84                 : 
      85                 : /* -------------------------------------------------------------------- */
      86                 : /*      Remove repeated and trailing underscores.                       */
      87                 : /* -------------------------------------------------------------------- */
      88          522083 :     for( i = 1, j = 0; pszDatum[i] != '\0'; i++ )
      89                 :     {
      90          496305 :         if( pszDatum[j] == '_' && pszDatum[i] == '_' )
      91            5180 :             continue;
      92                 : 
      93          491125 :         pszDatum[++j] = pszDatum[i];
      94                 :     }
      95           25778 :     if( pszDatum[j] == '_' )
      96            3785 :         pszDatum[j] = '\0';
      97                 :     else
      98           21993 :         pszDatum[j+1] = '\0';
      99                 :     
     100                 : /* -------------------------------------------------------------------- */
     101                 : /*      Search for datum equivelences.  Specific massaged names get     */
     102                 : /*      mapped to OpenGIS specified names.                              */
     103                 : /* -------------------------------------------------------------------- */
     104          153701 :     for( i = 0; papszDatumEquiv[i] != NULL; i += 2 )
     105                 :     {
     106          128187 :         if( EQUAL(*ppszDatum,papszDatumEquiv[i]) )
     107                 :         {
     108             264 :             CPLFree( *ppszDatum );
     109             264 :             *ppszDatum = CPLStrdup( papszDatumEquiv[i+1] );
     110             264 :             break;
     111                 :         }
     112                 :     }
     113                 : }
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                        EPSGAngleStringToDD()                         */
     117                 : /*                                                                      */
     118                 : /*      Convert an angle in the specified units to decimal degrees.     */
     119                 : /************************************************************************/
     120                 : 
     121                 : static double
     122             238 : EPSGAngleStringToDD( const char * pszAngle, int nUOMAngle )
     123                 : 
     124                 : {
     125                 :     double      dfAngle;
     126                 :     
     127             238 :     if( nUOMAngle == 9110 )             /* DDD.MMSSsss */
     128                 :     {
     129                 :         char    *pszDecimal;
     130                 :         
     131             172 :         dfAngle = ABS(atoi(pszAngle));
     132             172 :         pszDecimal = (char *) strchr(pszAngle,'.');
     133             172 :         if( pszDecimal != NULL && strlen(pszDecimal) > 1 )
     134                 :         {
     135                 :             char        szMinutes[3];
     136                 :             char        szSeconds[64];
     137                 : 
     138             161 :             szMinutes[0] = pszDecimal[1];
     139             180 :             if( pszDecimal[2] >= '0' && pszDecimal[2] <= '9' )
     140              19 :                 szMinutes[1] = pszDecimal[2];
     141                 :             else
     142             142 :                 szMinutes[1] = '0';
     143                 :             
     144             161 :             szMinutes[2] = '\0';
     145             161 :             dfAngle += atoi(szMinutes) / 60.0;
     146                 : 
     147             161 :             if( strlen(pszDecimal) > 3 )
     148                 :             {
     149               5 :                 szSeconds[0] = pszDecimal[3];
     150              10 :                 if( pszDecimal[4] >= '0' && pszDecimal[4] <= '9' )
     151                 :                 {
     152               5 :                     szSeconds[1] = pszDecimal[4];
     153               5 :                     szSeconds[2] = '.';
     154               5 :                     strncpy( szSeconds+3, pszDecimal + 5, sizeof(szSeconds)-3 );
     155               5 :                     szSeconds[sizeof(szSeconds)-1] = 0;
     156                 :                 }
     157                 :                 else
     158                 :                 {
     159               0 :                     szSeconds[1] = '0';
     160               0 :                     szSeconds[2] = '\0';
     161                 :                 }
     162               5 :                 dfAngle += CPLAtof(szSeconds) / 3600.0;
     163                 :             }
     164                 :         }
     165                 : 
     166             172 :         if( pszAngle[0] == '-' )
     167              11 :             dfAngle *= -1;
     168                 :     }
     169              72 :     else if( nUOMAngle == 9105 || nUOMAngle == 9106 )   /* grad */
     170                 :     {
     171               6 :         dfAngle = 180 * (CPLAtof(pszAngle ) / 200);
     172                 :     }
     173              60 :     else if( nUOMAngle == 9101 )                        /* radians */
     174                 :     {
     175               0 :         dfAngle = 180 * (CPLAtof(pszAngle ) / PI);
     176                 :     }
     177              60 :     else if( nUOMAngle == 9103 )                        /* arc-minute */
     178                 :     {
     179               0 :         dfAngle = CPLAtof(pszAngle) / 60;
     180                 :     }
     181              60 :     else if( nUOMAngle == 9104 )                        /* arc-second */
     182                 :     {
     183               0 :         dfAngle = CPLAtof(pszAngle) / 3600;
     184                 :     }
     185                 :     else /* decimal degrees ... some cases missing but seeminly never used */
     186                 :     {
     187                 :         CPLAssert( nUOMAngle == 9102 || nUOMAngle == 0 );
     188                 :         
     189              60 :         dfAngle = CPLAtof(pszAngle );
     190                 :     }
     191                 : 
     192             238 :     return( dfAngle );
     193                 : }
     194                 : 
     195                 : /************************************************************************/
     196                 : /*                        EPSGGetUOMAngleInfo()                         */
     197                 : /************************************************************************/
     198                 : 
     199             128 : int EPSGGetUOMAngleInfo( int nUOMAngleCode,
     200                 :                          char **ppszUOMName,
     201                 :                          double * pdfInDegrees )
     202                 : 
     203                 : {
     204             128 :     const char  *pszUOMName = NULL;
     205             128 :     double      dfInDegrees = 1.0;
     206             128 :     const char *pszFilename = CSVFilename( "unit_of_measure.csv" );
     207                 :     char        szSearchKey[24];
     208                 : 
     209             128 :     sprintf( szSearchKey, "%d", nUOMAngleCode );
     210                 :     pszUOMName = CSVGetField( pszFilename,
     211                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     212             128 :                               "UNIT_OF_MEAS_NAME" );
     213                 : 
     214                 : /* -------------------------------------------------------------------- */
     215                 : /*      If the file is found, read from there.  Note that FactorC is    */
     216                 : /*      an empty field for any of the DMS style formats, and in this    */
     217                 : /*      case we really want to return the default InDegrees value       */
     218                 : /*      (1.0) from above.                                               */
     219                 : /* -------------------------------------------------------------------- */
     220             128 :     if( pszUOMName != NULL )
     221                 :     {
     222                 :         double dfFactorB, dfFactorC;
     223                 :         
     224                 :         dfFactorB = 
     225                 :             CPLAtof(CSVGetField( pszFilename,
     226                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     227             128 :                               "FACTOR_B" ));
     228                 :         
     229                 :         dfFactorC = 
     230                 :             CPLAtof(CSVGetField( pszFilename,
     231                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     232             128 :                               "FACTOR_C" ));
     233                 : 
     234             128 :         if( dfFactorC != 0.0 )
     235             127 :             dfInDegrees = (dfFactorB / dfFactorC) * (180.0 / PI);
     236                 : 
     237                 :         /* We do a special override of some of the DMS formats name */
     238             128 :         if( nUOMAngleCode == 9102 || nUOMAngleCode == 9107
     239                 :             || nUOMAngleCode == 9108 || nUOMAngleCode == 9110 
     240                 :             || nUOMAngleCode == 9122 )
     241             126 :             pszUOMName = "degree";
     242                 : 
     243                 :         // For some reason, (FactorB) is not very precise in EPSG, use
     244                 :         // a more exact form for grads.
     245             128 :         if( nUOMAngleCode == 9105 )
     246               2 :             dfInDegrees = 180.0 / 200.0;
     247                 :     }
     248                 : 
     249                 : /* -------------------------------------------------------------------- */
     250                 : /*      Otherwise handle a few well known units directly.               */
     251                 : /* -------------------------------------------------------------------- */
     252                 :     else
     253                 :     {
     254               0 :         switch( nUOMAngleCode )
     255                 :         {
     256                 :           case 9101:
     257               0 :             pszUOMName = "radian";
     258               0 :             dfInDegrees = 180.0 / PI;
     259               0 :             break;
     260                 :         
     261                 :           case 9102:
     262                 :           case 9107:
     263                 :           case 9108:
     264                 :           case 9110:
     265                 :           case 9122:
     266               0 :             pszUOMName = "degree";
     267               0 :             dfInDegrees = 1.0;
     268               0 :             break;
     269                 : 
     270                 :           case 9103:
     271               0 :             pszUOMName = "arc-minute";
     272               0 :             dfInDegrees = 1 / 60.0;
     273               0 :             break;
     274                 : 
     275                 :           case 9104:
     276               0 :             pszUOMName = "arc-second";
     277               0 :             dfInDegrees = 1 / 3600.0;
     278               0 :             break;
     279                 :         
     280                 :           case 9105:
     281               0 :             pszUOMName = "grad";
     282               0 :             dfInDegrees = 180.0 / 200.0;
     283               0 :             break;
     284                 : 
     285                 :           case 9106:
     286               0 :             pszUOMName = "gon";
     287               0 :             dfInDegrees = 180.0 / 200.0;
     288               0 :             break;
     289                 :         
     290                 :           case 9109:
     291               0 :             pszUOMName = "microradian";
     292               0 :             dfInDegrees = 180.0 / (3.14159265358979 * 1000000.0);
     293               0 :             break;
     294                 : 
     295                 :           default:
     296               0 :             return FALSE;
     297                 :         }
     298                 :     }
     299                 : 
     300                 : /* -------------------------------------------------------------------- */
     301                 : /*      Return to caller.                                               */
     302                 : /* -------------------------------------------------------------------- */
     303             128 :     if( ppszUOMName != NULL )
     304                 :     {
     305             128 :         if( pszUOMName != NULL )
     306             128 :             *ppszUOMName = CPLStrdup( pszUOMName );
     307                 :         else
     308               0 :             *ppszUOMName = NULL;
     309                 :     }
     310                 : 
     311             128 :     if( pdfInDegrees != NULL )
     312             128 :         *pdfInDegrees = dfInDegrees;
     313                 : 
     314             128 :     return( TRUE );
     315                 : }
     316                 : 
     317                 : /************************************************************************/
     318                 : /*                        EPSGGetUOMLengthInfo()                        */
     319                 : /*                                                                      */
     320                 : /*      Note: This function should eventually also know how to          */
     321                 : /*      lookup length aliases in the UOM_LE_ALIAS table.                */
     322                 : /************************************************************************/
     323                 : 
     324                 : static int 
     325             272 : EPSGGetUOMLengthInfo( int nUOMLengthCode,
     326                 :                       char **ppszUOMName,
     327                 :                       double * pdfInMeters )
     328                 : 
     329                 : {
     330                 :     char        **papszUnitsRecord;
     331                 :     char        szSearchKey[24];
     332                 :     int         iNameField;
     333                 : 
     334                 : #define UOM_FILENAME CSVFilename( "unit_of_measure.csv" )
     335                 : 
     336                 : /* -------------------------------------------------------------------- */
     337                 : /*      We short cut meter to save work in the most common case.        */
     338                 : /* -------------------------------------------------------------------- */
     339             272 :     if( nUOMLengthCode == 9001 )
     340                 :     {
     341             266 :         if( ppszUOMName != NULL )
     342              42 :             *ppszUOMName = CPLStrdup( "metre" );
     343             266 :         if( pdfInMeters != NULL )
     344             266 :             *pdfInMeters = 1.0;
     345                 : 
     346             266 :         return TRUE;
     347                 :     }
     348                 : 
     349                 : /* -------------------------------------------------------------------- */
     350                 : /*      Search the units database for this unit.  If we don't find      */
     351                 : /*      it return failure.                                              */
     352                 : /* -------------------------------------------------------------------- */
     353               6 :     sprintf( szSearchKey, "%d", nUOMLengthCode );
     354                 :     papszUnitsRecord =
     355               6 :         CSVScanFileByName( UOM_FILENAME, "UOM_CODE", szSearchKey, CC_Integer );
     356                 : 
     357               6 :     if( papszUnitsRecord == NULL )
     358               0 :         return FALSE;
     359                 : 
     360                 : /* -------------------------------------------------------------------- */
     361                 : /*      Get the name, if requested.                                     */
     362                 : /* -------------------------------------------------------------------- */
     363               6 :     if( ppszUOMName != NULL )
     364                 :     {
     365               2 :         iNameField = CSVGetFileFieldId( UOM_FILENAME, "UNIT_OF_MEAS_NAME" );
     366               2 :         *ppszUOMName = CPLStrdup( CSLGetField(papszUnitsRecord, iNameField) );
     367                 :     }
     368                 :     
     369                 : /* -------------------------------------------------------------------- */
     370                 : /*      Get the A and B factor fields, and create the multiplicative    */
     371                 : /*      factor.                                                         */
     372                 : /* -------------------------------------------------------------------- */
     373               6 :     if( pdfInMeters != NULL )
     374                 :     {
     375                 :         int     iBFactorField, iCFactorField;
     376                 :         
     377               6 :         iBFactorField = CSVGetFileFieldId( UOM_FILENAME, "FACTOR_B" );
     378               6 :         iCFactorField = CSVGetFileFieldId( UOM_FILENAME, "FACTOR_C" );
     379                 : 
     380               6 :         if( CPLAtof(CSLGetField(papszUnitsRecord, iCFactorField)) > 0.0 )
     381                 :             *pdfInMeters = CPLAtof(CSLGetField(papszUnitsRecord,iBFactorField))
     382               6 :                 / CPLAtof(CSLGetField(papszUnitsRecord, iCFactorField));
     383                 :         else
     384               0 :             *pdfInMeters = 0.0;
     385                 :     }
     386                 :     
     387               6 :     return( TRUE );
     388                 : }
     389                 : 
     390                 : /************************************************************************/
     391                 : /*                       EPSGGetWGS84Transform()                        */
     392                 : /*                                                                      */
     393                 : /*      The following code attempts to find a bursa-wolf                */
     394                 : /*      transformation from this GeogCS to WGS84 (4326).                */
     395                 : /*                                                                      */
     396                 : /*      Faults:                                                         */
     397                 : /*       o I think there are codes other than 9603 and 9607 that        */
     398                 : /*         return compatible, or easily transformed parameters.         */
     399                 : /*       o Only the first path from the given GeogCS is checked due     */
     400                 : /*         to limitations in the CSV API.                               */
     401                 : /************************************************************************/
     402                 : 
     403             133 : int EPSGGetWGS84Transform( int nGeogCS, double *padfTransform )
     404                 : 
     405                 : {
     406                 :     int         nMethodCode, iDXField, iField;
     407                 :     char        szCode[32];
     408                 :     const char *pszFilename;
     409                 :     char **papszLine;
     410                 : 
     411                 : /* -------------------------------------------------------------------- */
     412                 : /*      Fetch the line from the GCS table.                              */
     413                 : /* -------------------------------------------------------------------- */
     414             133 :     pszFilename = CSVFilename("gcs.override.csv");
     415             133 :     sprintf( szCode, "%d", nGeogCS );
     416                 :     papszLine = CSVScanFileByName( pszFilename,
     417                 :                                    "COORD_REF_SYS_CODE", 
     418             133 :                                    szCode, CC_Integer );
     419             133 :     if( papszLine == NULL )
     420                 :     {
     421             132 :         pszFilename = CSVFilename("gcs.csv");
     422             132 :         sprintf( szCode, "%d", nGeogCS );
     423                 :         papszLine = CSVScanFileByName( pszFilename,
     424                 :                                        "COORD_REF_SYS_CODE", 
     425             132 :                                        szCode, CC_Integer );
     426                 :     }
     427                 : 
     428             133 :     if( papszLine == NULL )
     429               0 :         return FALSE;
     430                 : 
     431                 : /* -------------------------------------------------------------------- */
     432                 : /*      Verify that the method code is one of our accepted ones.        */
     433                 : /* -------------------------------------------------------------------- */
     434                 :     nMethodCode = 
     435                 :         atoi(CSLGetField( papszLine,
     436                 :                           CSVGetFileFieldId(pszFilename,
     437             133 :                                             "COORD_OP_METHOD_CODE")));
     438             133 :     if( nMethodCode != 9603 && nMethodCode != 9607 && nMethodCode != 9606 )
     439             120 :         return FALSE;
     440                 : 
     441                 : /* -------------------------------------------------------------------- */
     442                 : /*      Fetch the transformation parameters.                            */
     443                 : /* -------------------------------------------------------------------- */
     444              13 :     iDXField = CSVGetFileFieldId(pszFilename, "DX");
     445                 : 
     446             104 :     for( iField = 0; iField < 7; iField++ )
     447              91 :         padfTransform[iField] = CPLAtof(papszLine[iDXField+iField]);
     448                 : 
     449                 : /* -------------------------------------------------------------------- */
     450                 : /*      9607 - coordinate frame rotation has reverse signs on the       */
     451                 : /*      rotational coefficients.  Fix up now since we internal          */
     452                 : /*      operate according to method 9606 (position vector 7-parameter). */
     453                 : /* -------------------------------------------------------------------- */
     454              13 :     if( nMethodCode == 9607 )
     455                 :     {
     456               0 :         padfTransform[3] *= -1;
     457               0 :         padfTransform[4] *= -1;
     458               0 :         padfTransform[5] *= -1;
     459                 :     }
     460                 :         
     461              13 :     return TRUE;
     462                 : }
     463                 : 
     464                 : /************************************************************************/
     465                 : /*                           EPSGGetPMInfo()                            */
     466                 : /*                                                                      */
     467                 : /*      Get the offset between a given prime meridian and Greenwich     */
     468                 : /*      in degrees.                                                     */
     469                 : /************************************************************************/
     470                 : 
     471                 : static int 
     472             128 : EPSGGetPMInfo( int nPMCode, char ** ppszName, double *pdfOffset )
     473                 : 
     474                 : {
     475                 :     char        szSearchKey[24];
     476                 :     int         nUOMAngle;
     477                 : 
     478                 : #define PM_FILENAME CSVFilename("prime_meridian.csv")
     479                 : 
     480                 : /* -------------------------------------------------------------------- */
     481                 : /*      Use a special short cut for Greenwich, since it is so common.   */
     482                 : /* -------------------------------------------------------------------- */
     483             128 :     if( nPMCode == 7022 /* PM_Greenwich */ )
     484                 :     {
     485               0 :         if( pdfOffset != NULL )
     486               0 :             *pdfOffset = 0.0;
     487               0 :         if( ppszName != NULL )
     488               0 :             *ppszName = CPLStrdup( "Greenwich" );
     489               0 :         return TRUE;
     490                 :     }
     491                 : 
     492                 : /* -------------------------------------------------------------------- */
     493                 : /*      Search the database for the corresponding datum code.           */
     494                 : /* -------------------------------------------------------------------- */
     495             128 :     sprintf( szSearchKey, "%d", nPMCode );
     496                 : 
     497                 :     nUOMAngle =
     498                 :         atoi(CSVGetField( PM_FILENAME,
     499                 :                           "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     500             128 :                           "UOM_CODE" ) );
     501             128 :     if( nUOMAngle < 1 )
     502               0 :         return FALSE;
     503                 : 
     504                 : /* -------------------------------------------------------------------- */
     505                 : /*      Get the PM offset.                                              */
     506                 : /* -------------------------------------------------------------------- */
     507             128 :     if( pdfOffset != NULL )
     508                 :     {
     509                 :         *pdfOffset =
     510                 :             EPSGAngleStringToDD(
     511                 :                 CSVGetField( PM_FILENAME,
     512                 :                              "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     513                 :                              "GREENWICH_LONGITUDE" ),
     514             128 :                 nUOMAngle );
     515                 :     }
     516                 :     
     517                 : /* -------------------------------------------------------------------- */
     518                 : /*      Get the name, if requested.                                     */
     519                 : /* -------------------------------------------------------------------- */
     520             128 :     if( ppszName != NULL )
     521                 :         *ppszName =
     522                 :             CPLStrdup(
     523                 :                 CSVGetField( PM_FILENAME, 
     524                 :                              "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     525             128 :                              "PRIME_MERIDIAN_NAME" ));
     526                 :     
     527             128 :     return( TRUE );
     528                 : }
     529                 : 
     530                 : /************************************************************************/
     531                 : /*                           EPSGGetGCSInfo()                           */
     532                 : /*                                                                      */
     533                 : /*      Fetch the datum, and prime meridian related to a particular     */
     534                 : /*      GCS.                                                            */
     535                 : /************************************************************************/
     536                 : 
     537                 : static int
     538             256 : EPSGGetGCSInfo( int nGCSCode, char ** ppszName,
     539                 :                 int * pnDatum, char **ppszDatumName,
     540                 :                 int * pnPM, int *pnEllipsoid, int *pnUOMAngle,
     541                 :                 int * pnCoordSysCode )
     542                 : 
     543                 : {
     544                 :     char        szSearchKey[24];
     545                 :     int         nDatum, nPM, nUOMAngle, nEllipsoid;
     546                 :     const char  *pszFilename;
     547                 : 
     548                 : 
     549                 : /* -------------------------------------------------------------------- */
     550                 : /*      Search the database for the corresponding datum code.           */
     551                 : /* -------------------------------------------------------------------- */
     552             256 :     pszFilename = CSVFilename("gcs.override.csv");
     553             256 :     sprintf( szSearchKey, "%d", nGCSCode );
     554                 : 
     555                 :     nDatum = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     556                 :                                szSearchKey, CC_Integer,
     557             256 :                                "DATUM_CODE" ) );
     558                 : 
     559             256 :     if( nDatum < 1 )
     560                 :     {
     561             254 :         pszFilename = CSVFilename("gcs.csv");
     562             254 :         sprintf( szSearchKey, "%d", nGCSCode );
     563                 :         
     564                 :         nDatum = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     565                 :                                    szSearchKey, CC_Integer,
     566             254 :                                    "DATUM_CODE" ) );
     567                 :     }
     568                 : 
     569             256 :     if( nDatum < 1 )
     570              44 :         return FALSE;
     571                 : 
     572             212 :     if( pnDatum != NULL )
     573             128 :         *pnDatum = nDatum;
     574                 :     
     575                 : /* -------------------------------------------------------------------- */
     576                 : /*      Get the PM.                                                     */
     577                 : /* -------------------------------------------------------------------- */
     578                 :     nPM = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     579                 :                             szSearchKey, CC_Integer,
     580             212 :                             "PRIME_MERIDIAN_CODE" ) );
     581                 : 
     582             212 :     if( nPM < 1 )
     583               0 :         return FALSE;
     584                 : 
     585             212 :     if( pnPM != NULL )
     586             128 :         *pnPM = nPM;
     587                 : 
     588                 : /* -------------------------------------------------------------------- */
     589                 : /*      Get the Ellipsoid.                                              */
     590                 : /* -------------------------------------------------------------------- */
     591                 :     nEllipsoid = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     592                 :                                    szSearchKey, CC_Integer,
     593             212 :                                    "ELLIPSOID_CODE" ) );
     594                 : 
     595             212 :     if( nEllipsoid < 1 )
     596               0 :         return FALSE;
     597                 : 
     598             212 :     if( pnEllipsoid != NULL )
     599             128 :         *pnEllipsoid = nEllipsoid;
     600                 : 
     601                 : /* -------------------------------------------------------------------- */
     602                 : /*      Get the angular units.                                          */
     603                 : /* -------------------------------------------------------------------- */
     604                 :     nUOMAngle = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     605                 :                                   szSearchKey, CC_Integer,
     606             212 :                                   "UOM_CODE" ) );
     607                 : 
     608             212 :     if( nUOMAngle < 1 )
     609               0 :         return FALSE;
     610                 : 
     611             212 :     if( pnUOMAngle != NULL )
     612             128 :         *pnUOMAngle = nUOMAngle;
     613                 : 
     614                 : /* -------------------------------------------------------------------- */
     615                 : /*      Get the name, if requested.                                     */
     616                 : /* -------------------------------------------------------------------- */
     617             212 :     if( ppszName != NULL )
     618                 :         *ppszName =
     619                 :             CPLStrdup(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     620                 :                                    szSearchKey, CC_Integer,
     621             128 :                                    "COORD_REF_SYS_NAME" ));
     622                 :     
     623                 : /* -------------------------------------------------------------------- */
     624                 : /*      Get the datum name, if requested.                               */
     625                 : /* -------------------------------------------------------------------- */
     626             212 :     if( ppszDatumName != NULL )
     627                 :         *ppszDatumName =
     628                 :             CPLStrdup(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     629                 :                                    szSearchKey, CC_Integer,
     630             128 :                                    "DATUM_NAME" ));
     631                 :     
     632                 : /* -------------------------------------------------------------------- */
     633                 : /*      Get the CoordSysCode                                            */
     634                 : /* -------------------------------------------------------------------- */
     635                 :     int nCSC;
     636                 : 
     637                 :     nCSC = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     638                 :                              szSearchKey, CC_Integer,
     639             212 :                              "COORD_SYS_CODE" ) );
     640                 :     
     641             212 :     if( pnCoordSysCode != NULL )
     642             128 :         *pnCoordSysCode = nCSC;
     643                 : 
     644             212 :     return( TRUE );
     645                 : }
     646                 : 
     647                 : /************************************************************************/
     648                 : /*                         OSRGetEllipsoidInfo()                        */
     649                 : /************************************************************************/
     650                 : 
     651                 : /**
     652                 :  * Fetch info about an ellipsoid.
     653                 :  *
     654                 :  * This helper function will return ellipsoid parameters corresponding to EPSG
     655                 :  * code provided. Axes are always returned in meters.  Semi major computed
     656                 :  * based on inverse flattening where that is provided.
     657                 :  *
     658                 :  * @param nCode EPSG code of the requested ellipsoid
     659                 :  *
     660                 :  * @param ppszName pointer to string where ellipsoid name will be returned. It
     661                 :  * is caller responsibility to free this string after using with CPLFree().
     662                 :  *
     663                 :  * @param pdfSemiMajor pointer to variable where semi major axis will be
     664                 :  * returned.
     665                 :  *
     666                 :  * @param pdfInvFlattening pointer to variable where inverse flattening will
     667                 :  * be returned.
     668                 :  *
     669                 :  * @return OGRERR_NONE on success or an error code in case of failure.
     670                 :  **/
     671                 : 
     672                 : OGRErr 
     673             140 : OSRGetEllipsoidInfo( int nCode, char ** ppszName,
     674                 :                      double * pdfSemiMajor, double * pdfInvFlattening )
     675                 : 
     676                 : {
     677                 :     char        szSearchKey[24];
     678             140 :     double      dfSemiMajor, dfToMeters = 1.0;
     679                 :     int         nUOMLength;
     680                 :     
     681                 : /* -------------------------------------------------------------------- */
     682                 : /*      Get the semi major axis.                                        */
     683                 : /* -------------------------------------------------------------------- */
     684             140 :     snprintf( szSearchKey, sizeof(szSearchKey), "%d", nCode );
     685             140 :     szSearchKey[sizeof(szSearchKey) - 1] = '\n';
     686                 : 
     687                 :     dfSemiMajor =
     688                 :         CPLAtof(CSVGetField( CSVFilename("ellipsoid.csv" ),
     689                 :                              "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     690             140 :                              "SEMI_MAJOR_AXIS" ) );
     691             140 :     if( dfSemiMajor == 0.0 )
     692               0 :         return OGRERR_UNSUPPORTED_SRS;
     693                 : 
     694                 : /* -------------------------------------------------------------------- */
     695                 : /*      Get the translation factor into meters.                         */
     696                 : /* -------------------------------------------------------------------- */
     697                 :     nUOMLength = atoi(CSVGetField( CSVFilename("ellipsoid.csv" ),
     698                 :                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     699             140 :                                    "UOM_CODE" ));
     700             140 :     EPSGGetUOMLengthInfo( nUOMLength, NULL, &dfToMeters );
     701                 : 
     702             140 :     dfSemiMajor *= dfToMeters;
     703                 :     
     704             140 :     if( pdfSemiMajor != NULL )
     705             140 :         *pdfSemiMajor = dfSemiMajor;
     706                 :     
     707                 : /* -------------------------------------------------------------------- */
     708                 : /*      Get the semi-minor if requested.  If the Semi-minor axis        */
     709                 : /*      isn't available, compute it based on the inverse flattening.    */
     710                 : /* -------------------------------------------------------------------- */
     711             140 :     if( pdfInvFlattening != NULL )
     712                 :     {
     713                 :         *pdfInvFlattening = 
     714                 :             CPLAtof(CSVGetField( CSVFilename("ellipsoid.csv" ),
     715                 :                                  "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     716             140 :                                  "INV_FLATTENING" ));
     717                 : 
     718             140 :         if( *pdfInvFlattening == 0.0 )
     719                 :         {
     720                 :             double dfSemiMinor;
     721                 : 
     722                 :             dfSemiMinor =
     723                 :                 CPLAtof(CSVGetField( CSVFilename("ellipsoid.csv" ),
     724                 :                                   "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     725              19 :                                   "SEMI_MINOR_AXIS" )) * dfToMeters;
     726                 : 
     727              35 :             if( dfSemiMajor != 0.0 && dfSemiMajor != dfSemiMinor )
     728                 :                 *pdfInvFlattening = 
     729              16 :                     -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
     730                 :             else
     731               3 :                 *pdfInvFlattening = 0.0;
     732                 :         }
     733                 :     }
     734                 : 
     735                 : /* -------------------------------------------------------------------- */
     736                 : /*      Get the name, if requested.                                     */
     737                 : /* -------------------------------------------------------------------- */
     738             140 :     if( ppszName != NULL )
     739                 :         *ppszName =
     740                 :             CPLStrdup(CSVGetField( CSVFilename("ellipsoid.csv" ),
     741                 :                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     742             139 :                                    "ELLIPSOID_NAME" ));
     743                 : 
     744             140 :     return OGRERR_NONE;
     745                 : }
     746                 : 
     747                 : #define NatOriginLat         8801
     748                 : #define NatOriginLong        8802
     749                 : #define NatOriginScaleFactor 8805
     750                 : #define FalseEasting         8806
     751                 : #define FalseNorthing        8807
     752                 : #define ProjCenterLat        8811
     753                 : #define ProjCenterLong       8812
     754                 : #define Azimuth              8813
     755                 : #define AngleRectifiedToSkewedGrid 8814
     756                 : #define InitialLineScaleFactor 8815
     757                 : #define ProjCenterEasting    8816
     758                 : #define ProjCenterNorthing   8817
     759                 : #define PseudoStdParallelLat 8818
     760                 : #define PseudoStdParallelScaleFactor 8819
     761                 : #define FalseOriginLat       8821
     762                 : #define FalseOriginLong      8822
     763                 : #define StdParallel1Lat      8823
     764                 : #define StdParallel2Lat      8824
     765                 : #define FalseOriginEasting   8826
     766                 : #define FalseOriginNorthing  8827
     767                 : #define SphericalOriginLat   8828
     768                 : #define SphericalOriginLong  8829
     769                 : #define InitialLongitude     8830
     770                 : #define ZoneWidth            8831
     771                 : #define PolarLatStdParallel  8832
     772                 : #define PolarLongOrigin      8833
     773                 : 
     774                 : /************************************************************************/
     775                 : /*                         EPSGGetProjTRFInfo()                         */
     776                 : /*                                                                      */
     777                 : /*      Transform a PROJECTION_TRF_CODE into a projection method,       */
     778                 : /*      and a set of parameters.  The parameters identify will          */
     779                 : /*      depend on the returned method, but they will all have been      */
     780                 : /*      normalized into degrees and meters.                             */
     781                 : /************************************************************************/
     782                 : 
     783                 : static int
     784              44 : EPSGGetProjTRFInfo( int nPCS, int * pnProjMethod,
     785                 :                     int *panParmIds, double * padfProjParms )
     786                 : 
     787                 : {
     788                 :     int         nProjMethod, i;
     789                 :     double      adfProjParms[7];
     790                 :     char        szTRFCode[16];
     791              44 :     CPLString   osFilename;
     792                 : 
     793                 : /* -------------------------------------------------------------------- */
     794                 : /*      Get the proj method.  If this fails to return a meaningful      */
     795                 : /*      number, then the whole function fails.                          */
     796                 : /* -------------------------------------------------------------------- */
     797              44 :     osFilename = CSVFilename( "pcs.override.csv" );
     798              44 :     sprintf( szTRFCode, "%d", nPCS );
     799                 :     nProjMethod =
     800                 :         atoi( CSVGetField( osFilename,
     801                 :                            "COORD_REF_SYS_CODE", szTRFCode, CC_Integer,
     802              44 :                            "COORD_OP_METHOD_CODE" ) );
     803              44 :     if( nProjMethod == 0 )
     804                 :     {
     805              42 :         osFilename = CSVFilename( "pcs.csv" );
     806              42 :         sprintf( szTRFCode, "%d", nPCS );
     807                 :         nProjMethod =
     808                 :             atoi( CSVGetField( osFilename,
     809                 :                                "COORD_REF_SYS_CODE", szTRFCode, CC_Integer,
     810              42 :                                "COORD_OP_METHOD_CODE" ) );
     811                 :     }
     812                 : 
     813              44 :     if( nProjMethod == 0 )
     814               0 :         return FALSE;
     815                 : 
     816                 : /* -------------------------------------------------------------------- */
     817                 : /*      Get the parameters for this projection.                         */
     818                 : /* -------------------------------------------------------------------- */
     819                 : 
     820             352 :     for( i = 0; i < 7; i++ )
     821                 :     {
     822                 :         char    szParamUOMID[32], szParamValueID[32], szParamCodeID[32];
     823                 :         char    *pszValue;
     824                 :         int     nUOM;
     825                 :         
     826             308 :         sprintf( szParamCodeID, "PARAMETER_CODE_%d", i+1 );
     827             308 :         sprintf( szParamUOMID, "PARAMETER_UOM_%d", i+1 );
     828             308 :         sprintf( szParamValueID, "PARAMETER_VALUE_%d", i+1 );
     829                 : 
     830             308 :         if( panParmIds != NULL )
     831             308 :             panParmIds[i] = 
     832                 :                 atoi(CSVGetField( osFilename, "COORD_REF_SYS_CODE", szTRFCode,
     833             308 :                                   CC_Integer, szParamCodeID ));
     834                 : 
     835                 :         nUOM = atoi(CSVGetField( osFilename, "COORD_REF_SYS_CODE", szTRFCode,
     836             308 :                                  CC_Integer, szParamUOMID ));
     837                 :         pszValue = CPLStrdup(
     838                 :             CSVGetField( osFilename, "COORD_REF_SYS_CODE", szTRFCode,
     839             308 :                          CC_Integer, szParamValueID ));
     840                 : 
     841                 :         // there is a bug in the EPSG 6.2.2 database for PCS 2935 and 2936
     842                 :         // such that they have foot units for the scale factor.  Avoid this.
     843             859 :         if( (panParmIds[i] == NatOriginScaleFactor 
     844             276 :              || panParmIds[i] == InitialLineScaleFactor
     845             275 :              || panParmIds[i] == PseudoStdParallelScaleFactor) 
     846                 :             && nUOM < 9200 )
     847               0 :             nUOM = 9201;
     848                 : 
     849             418 :         if( nUOM >= 9100 && nUOM < 9200 )
     850             110 :             adfProjParms[i] = EPSGAngleStringToDD( pszValue, nUOM );
     851             286 :         else if( nUOM > 9000 && nUOM < 9100 )
     852                 :         {
     853                 :             double dfInMeters;
     854                 : 
     855              88 :             if( !EPSGGetUOMLengthInfo( nUOM, NULL, &dfInMeters ) )
     856               0 :                 dfInMeters = 1.0;
     857              88 :             adfProjParms[i] = CPLAtof(pszValue) * dfInMeters;
     858                 :         }
     859             110 :         else if( EQUAL(pszValue,"") ) /* null field */
     860                 :         {
     861              77 :             adfProjParms[i] = 0.0;
     862                 :         }
     863                 :         else /* really we should consider looking up other scaling factors */
     864                 :         {
     865              33 :             if( nUOM != 9201 )
     866               0 :                 CPLDebug( "OGR", "Non-unity scale factor units!" );
     867              33 :             adfProjParms[i] = CPLAtof(pszValue);
     868                 :         }
     869                 : 
     870             308 :         CPLFree( pszValue );
     871                 :     }
     872                 : 
     873                 : /* -------------------------------------------------------------------- */
     874                 : /*      Transfer requested data into passed variables.                  */
     875                 : /* -------------------------------------------------------------------- */
     876              44 :     if( pnProjMethod != NULL )
     877              44 :         *pnProjMethod = nProjMethod;
     878                 : 
     879              44 :     if( padfProjParms != NULL )
     880                 :     {
     881             352 :         for( i = 0; i < 7; i++ )
     882             308 :             padfProjParms[i] = adfProjParms[i];
     883                 :     }
     884                 : 
     885              44 :     return TRUE;
     886                 : }
     887                 : 
     888                 : 
     889                 : /************************************************************************/
     890                 : /*                           EPSGGetPCSInfo()                           */
     891                 : /************************************************************************/
     892                 : 
     893                 : static int 
     894              44 : EPSGGetPCSInfo( int nPCSCode, char **ppszEPSGName,
     895                 :                 int *pnUOMLengthCode, int *pnUOMAngleCode,
     896                 :                 int *pnGeogCS, int *pnTRFCode, int *pnCoordSysCode )
     897                 : 
     898                 : {
     899                 :     char        **papszRecord;
     900                 :     char        szSearchKey[24];
     901                 :     const char  *pszFilename;
     902                 :     
     903                 : /* -------------------------------------------------------------------- */
     904                 : /*      Search the units database for this unit.  If we don't find      */
     905                 : /*      it return failure.                                              */
     906                 : /* -------------------------------------------------------------------- */
     907              44 :     pszFilename = CSVFilename( "pcs.csv" );
     908              44 :     sprintf( szSearchKey, "%d", nPCSCode );
     909                 :     papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
     910              44 :                                      szSearchKey, CC_Integer );
     911                 : 
     912              44 :     if( papszRecord == NULL )
     913                 :     {
     914               0 :         pszFilename = CSVFilename( "pcs.override.csv" );
     915               0 :         sprintf( szSearchKey, "%d", nPCSCode );
     916                 :         papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
     917               0 :                                          szSearchKey, CC_Integer );
     918                 :         
     919                 :     }
     920                 : 
     921              44 :     if( papszRecord == NULL )
     922               0 :         return FALSE;
     923                 : 
     924                 : /* -------------------------------------------------------------------- */
     925                 : /*      Get the name, if requested.                                     */
     926                 : /* -------------------------------------------------------------------- */
     927              44 :     if( ppszEPSGName != NULL )
     928                 :     {
     929                 :         CPLString osPCSName = 
     930                 :             CSLGetField( papszRecord,
     931                 :                          CSVGetFileFieldId(pszFilename,
     932              44 :                                            "COORD_REF_SYS_NAME"));
     933                 :             
     934                 :         const char *pszDeprecated = 
     935                 :             CSLGetField( papszRecord,
     936                 :                          CSVGetFileFieldId(pszFilename,
     937              44 :                                            "DEPRECATED") );
     938                 : 
     939              44 :         if( pszDeprecated != NULL && *pszDeprecated == '1' )
     940               5 :             osPCSName += " (deprecated)";
     941                 : 
     942              44 :         *ppszEPSGName = CPLStrdup(osPCSName);
     943                 :     }
     944                 : 
     945                 : /* -------------------------------------------------------------------- */
     946                 : /*      Get the UOM Length code, if requested.                          */
     947                 : /* -------------------------------------------------------------------- */
     948              44 :     if( pnUOMLengthCode != NULL )
     949                 :     {
     950                 :         const char      *pszValue;
     951                 : 
     952                 :         pszValue =
     953                 :             CSLGetField( papszRecord,
     954              44 :                          CSVGetFileFieldId(pszFilename,"UOM_CODE"));
     955              44 :         if( atoi(pszValue) > 0 )
     956              44 :             *pnUOMLengthCode = atoi(pszValue);
     957                 :         else
     958               0 :             *pnUOMLengthCode = 0;
     959                 :     }
     960                 : 
     961                 : /* -------------------------------------------------------------------- */
     962                 : /*      Get the UOM Angle code, if requested.                           */
     963                 : /* -------------------------------------------------------------------- */
     964              44 :     if( pnUOMAngleCode != NULL )
     965                 :     {
     966                 :         const char      *pszValue;
     967                 :         
     968                 :         pszValue =
     969                 :             CSLGetField( papszRecord,
     970              44 :                          CSVGetFileFieldId(pszFilename,"UOM_ANGLE_CODE") );
     971                 :         
     972              44 :         if( atoi(pszValue) > 0 )
     973               0 :             *pnUOMAngleCode = atoi(pszValue);
     974                 :         else
     975              44 :             *pnUOMAngleCode = 0;
     976                 :     }
     977                 : 
     978                 : /* -------------------------------------------------------------------- */
     979                 : /*      Get the GeogCS (Datum with PM) code, if requested.              */
     980                 : /* -------------------------------------------------------------------- */
     981              44 :     if( pnGeogCS != NULL )
     982                 :     {
     983                 :         const char      *pszValue;
     984                 : 
     985                 :         pszValue =
     986                 :             CSLGetField( papszRecord,
     987              44 :                          CSVGetFileFieldId(pszFilename,"SOURCE_GEOGCRS_CODE"));
     988              44 :         if( atoi(pszValue) > 0 )
     989              44 :             *pnGeogCS = atoi(pszValue);
     990                 :         else
     991               0 :             *pnGeogCS = 0;
     992                 :     }
     993                 : 
     994                 : /* -------------------------------------------------------------------- */
     995                 : /*      Get the GeogCS (Datum with PM) code, if requested.              */
     996                 : /* -------------------------------------------------------------------- */
     997              44 :     if( pnTRFCode != NULL )
     998                 :     {
     999                 :         const char      *pszValue;
    1000                 : 
    1001                 :         pszValue =
    1002                 :             CSLGetField( papszRecord,
    1003              44 :                          CSVGetFileFieldId(pszFilename,"COORD_OP_CODE"));
    1004                 :                          
    1005                 :         
    1006              44 :         if( atoi(pszValue) > 0 )
    1007              44 :             *pnTRFCode = atoi(pszValue);
    1008                 :         else
    1009               0 :             *pnTRFCode = 0;
    1010                 :     }
    1011                 : 
    1012                 : /* -------------------------------------------------------------------- */
    1013                 : /*      Get the CoordSysCode                                            */
    1014                 : /* -------------------------------------------------------------------- */
    1015                 :     int nCSC;
    1016                 : 
    1017                 :     nCSC = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
    1018                 :                              szSearchKey, CC_Integer,
    1019              44 :                              "COORD_SYS_CODE" ) );
    1020                 :     
    1021              44 :     if( pnCoordSysCode != NULL )
    1022              44 :         *pnCoordSysCode = nCSC;
    1023                 : 
    1024              44 :     return TRUE;
    1025                 : }
    1026                 : 
    1027                 : /************************************************************************/
    1028                 : /*                          SetEPSGAxisInfo()                           */
    1029                 : /************************************************************************/
    1030                 : 
    1031             172 : static OGRErr SetEPSGAxisInfo( OGRSpatialReference *poSRS, 
    1032                 :                                const char *pszTargetKey,
    1033                 :                                int nCoordSysCode )
    1034                 : 
    1035                 : {
    1036                 : /* -------------------------------------------------------------------- */
    1037                 : /*      Special cases for well known and common values.  We short       */
    1038                 : /*      circuit these to save time doing file lookups.                  */
    1039                 : /* -------------------------------------------------------------------- */
    1040                 :     // Conventional and common Easting/Northing values.
    1041             172 :     if( nCoordSysCode >= 4400 && nCoordSysCode <= 4410 )
    1042                 :     {
    1043                 :         return 
    1044                 :             poSRS->SetAxes( pszTargetKey, 
    1045                 :                             "Easting", OAO_East, 
    1046              23 :                             "Northing", OAO_North );
    1047                 :     }
    1048                 : 
    1049                 :     // Conventional and common Easting/Northing values.
    1050             149 :     if( nCoordSysCode >= 6400 && nCoordSysCode <= 6423 )
    1051                 :     {
    1052                 :         return 
    1053                 :             poSRS->SetAxes( pszTargetKey, 
    1054                 :                             "Latitude", OAO_North, 
    1055             128 :                             "Longitude", OAO_East );
    1056                 :     }
    1057                 : 
    1058                 : /* -------------------------------------------------------------------- */
    1059                 : /*      Get the definition from the coordinate_axis.csv file.           */
    1060                 : /* -------------------------------------------------------------------- */
    1061                 :     char        **papszRecord;
    1062              21 :     char        **papszAxis1=NULL, **papszAxis2=NULL;
    1063                 :     char        szSearchKey[24];
    1064                 :     const char *pszFilename;
    1065                 : 
    1066              21 :     pszFilename = CSVFilename( "coordinate_axis.csv" );
    1067              21 :     sprintf( szSearchKey, "%d", nCoordSysCode );
    1068                 :     papszRecord = CSVScanFileByName( pszFilename, "COORD_SYS_CODE",
    1069              21 :                                      szSearchKey, CC_Integer );
    1070                 : 
    1071              21 :     if( papszRecord != NULL )
    1072                 :     {
    1073              21 :         papszAxis1 = CSLDuplicate( papszRecord );
    1074              21 :         papszRecord = CSVGetNextLine( pszFilename );
    1075              42 :         if( CSLCount(papszRecord) > 0 
    1076              21 :             && EQUAL(papszRecord[0],papszAxis1[0]) )
    1077              21 :             papszAxis2 = CSLDuplicate( papszRecord );
    1078                 :     }
    1079                 : 
    1080              21 :     if( papszAxis2 == NULL )
    1081                 :     {
    1082               0 :         CSLDestroy( papszAxis1 );
    1083                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1084                 :                   "Failed to find entries for COORD_SYS_CODE %d in coordinate_axis.csv", 
    1085               0 :                   nCoordSysCode );
    1086               0 :         return OGRERR_FAILURE;
    1087                 :     }
    1088                 : 
    1089                 : /* -------------------------------------------------------------------- */
    1090                 : /*      Confirm the records are complete, and work out which columns    */
    1091                 : /*      are which.                                                      */
    1092                 : /* -------------------------------------------------------------------- */
    1093                 :     int   iAxisOrientationField, iAxisAbbrevField, iAxisOrderField;
    1094                 : 
    1095                 :     iAxisOrientationField = 
    1096              21 :         CSVGetFileFieldId( pszFilename, "coord_axis_orientation" );
    1097                 :     iAxisAbbrevField = 
    1098              21 :         CSVGetFileFieldId( pszFilename, "coord_axis_abbreviation" );
    1099                 :     iAxisOrderField = 
    1100              21 :         CSVGetFileFieldId( pszFilename, "coord_axis_order" );
    1101                 : 
    1102              21 :     if( CSLCount(papszAxis1) < iAxisOrderField+1 
    1103                 :         || CSLCount(papszAxis2) < iAxisOrderField+1 )
    1104                 :     {
    1105               0 :         CSLDestroy( papszAxis1 );
    1106               0 :         CSLDestroy( papszAxis2 );
    1107                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1108                 :                   "Axis records appear incomplete for COORD_SYS_CODE %d in coordinate_axis.csv", 
    1109               0 :                   nCoordSysCode );
    1110               0 :         return OGRERR_FAILURE;
    1111                 :     }
    1112                 : 
    1113                 : /* -------------------------------------------------------------------- */
    1114                 : /*      Do we need to switch the axes around?                           */
    1115                 : /* -------------------------------------------------------------------- */
    1116              21 :     if( atoi(papszAxis2[iAxisOrderField]) < atoi(papszAxis1[iAxisOrderField]) )
    1117                 :     {
    1118               1 :         papszRecord = papszAxis1;
    1119               1 :         papszAxis1 = papszAxis2;
    1120               1 :         papszAxis2 = papszRecord;
    1121                 :     }
    1122                 : 
    1123                 : /* -------------------------------------------------------------------- */
    1124                 : /*      Work out axis enumeration values.                               */
    1125                 : /* -------------------------------------------------------------------- */
    1126              21 :     OGRAxisOrientation eOAxis1 = OAO_Other, eOAxis2 = OAO_Other;
    1127                 :     int iAO;
    1128                 : 
    1129             168 :     for( iAO = 0; iAO <= 6; iAO++ )
    1130                 :     {
    1131             147 :         if( EQUAL(papszAxis1[iAxisOrientationField],
    1132                 :                   OSRAxisEnumToName((OGRAxisOrientation) iAO)) )
    1133              21 :             eOAxis1 = (OGRAxisOrientation) iAO;
    1134             147 :         if( EQUAL(papszAxis2[iAxisOrientationField],
    1135                 :                   OSRAxisEnumToName((OGRAxisOrientation) iAO)) )
    1136              21 :             eOAxis2 = (OGRAxisOrientation) iAO;
    1137                 :     }
    1138                 : 
    1139                 : /* -------------------------------------------------------------------- */
    1140                 : /*      Work out the axis name.  We try to expand the abbreviation      */
    1141                 : /*      to a longer name.                                               */
    1142                 : /* -------------------------------------------------------------------- */
    1143                 :     const char *apszAxisName[2];
    1144              21 :     apszAxisName[0] = papszAxis1[iAxisAbbrevField];
    1145              21 :     apszAxisName[1] = papszAxis2[iAxisAbbrevField];
    1146                 : 
    1147              63 :     for( iAO = 0; iAO < 2; iAO++ )
    1148                 :     {
    1149              42 :         if( EQUAL(apszAxisName[iAO],"N") )
    1150               0 :             apszAxisName[iAO] = "Northing";
    1151              42 :         else if( EQUAL(apszAxisName[iAO],"E") )
    1152               0 :             apszAxisName[iAO] = "Easting";
    1153              42 :         else if( EQUAL(apszAxisName[iAO],"S") )
    1154               0 :             apszAxisName[iAO] = "Southing";
    1155              42 :         else if( EQUAL(apszAxisName[iAO],"W") )
    1156               0 :             apszAxisName[iAO] = "Westing";
    1157                 :     }
    1158                 : 
    1159                 : /* -------------------------------------------------------------------- */
    1160                 : /*      Set the axes.                                                   */
    1161                 : /* -------------------------------------------------------------------- */
    1162                 :     OGRErr eResult;
    1163                 :     eResult = poSRS->SetAxes( pszTargetKey, 
    1164                 :                               apszAxisName[0], eOAxis1,
    1165              21 :                               apszAxisName[1], eOAxis2 );
    1166                 : 
    1167              21 :     CSLDestroy( papszAxis1 );
    1168              21 :     CSLDestroy( papszAxis2 );
    1169                 :     
    1170              21 :     return eResult;
    1171                 : }
    1172                 : 
    1173                 : /************************************************************************/
    1174                 : /*                           SetEPSGGeogCS()                            */
    1175                 : /*                                                                      */
    1176                 : /*      FLAWS:                                                          */
    1177                 : /*       o Units are all hardcoded.                                     */
    1178                 : /************************************************************************/
    1179                 : 
    1180             128 : static OGRErr SetEPSGGeogCS( OGRSpatialReference * poSRS, int nGeogCS )
    1181                 : 
    1182                 : {
    1183                 :     int  nDatumCode, nPMCode, nUOMAngle, nEllipsoidCode, nCSC;
    1184             128 :     char *pszGeogCSName = NULL, *pszDatumName = NULL, *pszEllipsoidName = NULL;
    1185             128 :     char *pszPMName = NULL, *pszAngleName = NULL;
    1186                 :     double dfPMOffset, dfSemiMajor, dfInvFlattening, adfBursaTransform[7];
    1187                 :     double dfAngleInDegrees, dfAngleInRadians;
    1188                 : 
    1189             128 :     if( !EPSGGetGCSInfo( nGeogCS, &pszGeogCSName,
    1190                 :                          &nDatumCode, &pszDatumName, 
    1191                 :                          &nPMCode, &nEllipsoidCode, &nUOMAngle, &nCSC ) )
    1192               0 :         return OGRERR_UNSUPPORTED_SRS;
    1193                 : 
    1194             128 :     if( !EPSGGetPMInfo( nPMCode, &pszPMName, &dfPMOffset ) )
    1195               0 :         return OGRERR_UNSUPPORTED_SRS;
    1196                 : 
    1197             128 :     OGREPSGDatumNameMassage( &pszDatumName );
    1198                 : 
    1199             128 :     if( OSRGetEllipsoidInfo( nEllipsoidCode, &pszEllipsoidName, 
    1200                 :                              &dfSemiMajor, &dfInvFlattening ) != OGRERR_NONE )
    1201               0 :         return OGRERR_UNSUPPORTED_SRS;
    1202                 : 
    1203             128 :     if( !EPSGGetUOMAngleInfo( nUOMAngle, &pszAngleName, &dfAngleInDegrees ) )
    1204                 :     {
    1205               0 :         pszAngleName = CPLStrdup("degree");
    1206               0 :         dfAngleInDegrees = 1.0;
    1207               0 :         nUOMAngle = -1;
    1208                 :     }
    1209                 : 
    1210             128 :     if( dfAngleInDegrees == 1.0 )
    1211               1 :         dfAngleInRadians = CPLAtof(SRS_UA_DEGREE_CONV);
    1212                 :     else
    1213             127 :         dfAngleInRadians = CPLAtof(SRS_UA_DEGREE_CONV) * dfAngleInDegrees;
    1214                 : 
    1215                 :     poSRS->SetGeogCS( pszGeogCSName, pszDatumName, 
    1216                 :                       pszEllipsoidName, dfSemiMajor, dfInvFlattening,
    1217                 :                       pszPMName, dfPMOffset,
    1218             128 :                       pszAngleName, dfAngleInRadians );
    1219                 : 
    1220             128 :     if( EPSGGetWGS84Transform( nGeogCS, adfBursaTransform ) )
    1221                 :     {
    1222                 :         OGR_SRSNode     *poWGS84;
    1223                 :         char            szValue[100];
    1224                 : 
    1225              13 :         poWGS84 = new OGR_SRSNode( "TOWGS84" );
    1226                 : 
    1227             208 :         for( int iCoeff = 0; iCoeff < 7; iCoeff++ )
    1228                 :         {
    1229              91 :             sprintf( szValue, "%g", adfBursaTransform[iCoeff] );
    1230              91 :             poWGS84->AddChild( new OGR_SRSNode( szValue ) );
    1231                 :         }
    1232                 : 
    1233              13 :         poSRS->GetAttrNode( "DATUM" )->AddChild( poWGS84 );
    1234                 :     }
    1235                 : 
    1236             128 :     poSRS->SetAuthority( "GEOGCS", "EPSG", nGeogCS );
    1237             128 :     poSRS->SetAuthority( "DATUM", "EPSG", nDatumCode );
    1238             128 :     poSRS->SetAuthority( "SPHEROID", "EPSG", nEllipsoidCode );
    1239             128 :     poSRS->SetAuthority( "PRIMEM", "EPSG", nPMCode );
    1240                 : 
    1241             128 :     if( nUOMAngle > 0 )
    1242             128 :         poSRS->SetAuthority( "GEOGCS|UNIT", "EPSG", nUOMAngle );
    1243                 : 
    1244             128 :     CPLFree( pszAngleName );
    1245             128 :     CPLFree( pszDatumName );
    1246             128 :     CPLFree( pszEllipsoidName );
    1247             128 :     CPLFree( pszGeogCSName );
    1248             128 :     CPLFree( pszPMName );
    1249                 : 
    1250                 : /* -------------------------------------------------------------------- */
    1251                 : /*      Set axes                                                        */
    1252                 : /* -------------------------------------------------------------------- */
    1253             128 :     if( nCSC > 0 )
    1254                 :     {
    1255             128 :         SetEPSGAxisInfo( poSRS, "GEOGCS", nCSC );
    1256             128 :         CPLErrorReset();
    1257                 :     }
    1258                 : 
    1259             128 :     return OGRERR_NONE;
    1260                 : }
    1261                 : 
    1262                 : /************************************************************************/
    1263                 : /*                           OGR_FetchParm()                            */
    1264                 : /*                                                                      */
    1265                 : /*      Fetch a parameter from the parm list, based on it's EPSG        */
    1266                 : /*      parameter code.                                                 */
    1267                 : /************************************************************************/
    1268                 : 
    1269             232 : static double OGR_FetchParm( double *padfProjParms, int *panParmIds, 
    1270                 :                              int nTargetId, double dfFromGreenwich )
    1271                 : 
    1272                 : {
    1273                 :     int i;
    1274                 :     double dfResult;
    1275                 : 
    1276                 : /* -------------------------------------------------------------------- */
    1277                 : /*      Set default in meters/degrees.                                  */
    1278                 : /* -------------------------------------------------------------------- */
    1279             232 :     switch( nTargetId )
    1280                 :     {
    1281                 :       case NatOriginScaleFactor:
    1282                 :       case InitialLineScaleFactor:
    1283                 :       case PseudoStdParallelScaleFactor:
    1284              34 :         dfResult = 1.0;
    1285              34 :         break;
    1286                 :         
    1287                 :       case AngleRectifiedToSkewedGrid:
    1288               1 :         dfResult = 90.0;
    1289               1 :         break;
    1290                 : 
    1291                 :       default:
    1292             197 :         dfResult = 0.0;
    1293                 :     }
    1294                 : 
    1295                 : /* -------------------------------------------------------------------- */
    1296                 : /*      Try to find actual value in parameter list.                     */
    1297                 : /* -------------------------------------------------------------------- */
    1298             736 :     for( i = 0; i < 7; i++ )
    1299                 :     {
    1300             735 :         if( panParmIds[i] == nTargetId )
    1301                 :         {
    1302             231 :             dfResult = padfProjParms[i];
    1303             231 :             break;
    1304                 :         }
    1305                 :     }
    1306                 : 
    1307                 : /* -------------------------------------------------------------------- */
    1308                 : /*      EPSG longitudes are relative to greenwich.  The follow code     */
    1309                 : /*      could be used to make them relative to the prime meridian of    */
    1310                 : /*      the associated GCS if that was appropriate.  However, the       */
    1311                 : /*      SetNormProjParm() method expects longitudes relative to         */
    1312                 : /*      greenwich, so there is nothing for us to do.                    */
    1313                 : /* -------------------------------------------------------------------- */
    1314                 : #ifdef notdef
    1315                 :     switch( nTargetId )
    1316                 :     {
    1317                 :       case NatOriginLong:
    1318                 :       case ProjCenterLong:
    1319                 :       case FalseOriginLong:
    1320                 :       case SphericalOriginLong:
    1321                 :       case InitialLongitude:
    1322                 :         // Note that the EPSG values are already relative to greenwich.
    1323                 :         // This shift is really making it relative to the provided prime
    1324                 :         // meridian, so that when SetTM() and company the correction back
    1325                 :         // ends up back relative to greenwich.
    1326                 :         dfResult = dfResult + dfFromGreenwich;
    1327                 :         break;
    1328                 : 
    1329                 :       default:
    1330                 :         ;
    1331                 :     }
    1332                 : #endif
    1333                 : 
    1334             232 :     return dfResult;
    1335                 : }
    1336                 : 
    1337                 : #define OGR_FP(x) OGR_FetchParm( adfProjParms, anParmIds, (x), \
    1338                 :                                  dfFromGreenwich )
    1339                 : 
    1340                 : /************************************************************************/
    1341                 : /*                           SetEPSGProjCS()                            */
    1342                 : /************************************************************************/
    1343                 : 
    1344              44 : static OGRErr SetEPSGProjCS( OGRSpatialReference * poSRS, int nPCSCode )
    1345                 : 
    1346                 : {
    1347              44 :     int         nGCSCode, nUOMAngleCode, nUOMLength, nTRFCode, nProjMethod=0;
    1348              44 :     int         anParmIds[7], nCSC = 0;
    1349              44 :     char        *pszPCSName = NULL, *pszUOMLengthName = NULL;
    1350                 :     double      adfProjParms[7], dfInMeters, dfFromGreenwich;
    1351                 :     OGRErr      nErr;
    1352                 :     OGR_SRSNode *poNode;
    1353                 : 
    1354              44 :     if( !EPSGGetPCSInfo( nPCSCode, &pszPCSName, &nUOMLength, &nUOMAngleCode,
    1355                 :                          &nGCSCode, &nTRFCode, &nCSC ) )
    1356               0 :         return OGRERR_UNSUPPORTED_SRS;
    1357                 : 
    1358              44 :     poSRS->SetNode( "PROJCS", pszPCSName );
    1359                 :     
    1360                 : /* -------------------------------------------------------------------- */
    1361                 : /*      Set GEOGCS.                                                     */
    1362                 : /* -------------------------------------------------------------------- */
    1363              44 :     nErr = SetEPSGGeogCS( poSRS, nGCSCode );
    1364              44 :     if( nErr != OGRERR_NONE )
    1365               0 :         return nErr;
    1366                 : 
    1367              44 :     dfFromGreenwich = poSRS->GetPrimeMeridian();
    1368                 : 
    1369                 : /* -------------------------------------------------------------------- */
    1370                 : /*      Set linear units.                                               */
    1371                 : /* -------------------------------------------------------------------- */
    1372              44 :     if( !EPSGGetUOMLengthInfo( nUOMLength, &pszUOMLengthName, &dfInMeters ) )
    1373               0 :         return OGRERR_UNSUPPORTED_SRS;
    1374                 : 
    1375              44 :     poSRS->SetLinearUnits( pszUOMLengthName, dfInMeters );
    1376              44 :     poSRS->SetAuthority( "PROJCS|UNIT", "EPSG", nUOMLength );
    1377                 : 
    1378              44 :     CPLFree( pszUOMLengthName );
    1379              44 :     CPLFree( pszPCSName );
    1380                 : 
    1381                 : /* -------------------------------------------------------------------- */
    1382                 : /*      Set projection and parameters.                                  */
    1383                 : /* -------------------------------------------------------------------- */
    1384              44 :     if( !EPSGGetProjTRFInfo( nPCSCode, &nProjMethod, anParmIds, adfProjParms ))
    1385               0 :         return OGRERR_UNSUPPORTED_SRS;
    1386                 : 
    1387              44 :     switch( nProjMethod )
    1388                 :     {
    1389                 :       case 9801:
    1390                 :       case 9817: /* really LCC near conformal */
    1391                 :         poSRS->SetLCC1SP( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1392                 :                           OGR_FP( NatOriginScaleFactor ), 
    1393               2 :                           OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1394               2 :         break;
    1395                 : 
    1396                 :       case 9802:
    1397                 :         poSRS->SetLCC( OGR_FP( StdParallel1Lat ), OGR_FP( StdParallel2Lat ),
    1398                 :                        OGR_FP( FalseOriginLat ), OGR_FP( FalseOriginLong ),
    1399                 :                        OGR_FP( FalseOriginEasting ), 
    1400              10 :                        OGR_FP( FalseOriginNorthing ));
    1401              10 :         break;
    1402                 : 
    1403                 :       case 9803:
    1404                 :         poSRS->SetLCCB( OGR_FP( StdParallel1Lat ), OGR_FP( StdParallel2Lat ),
    1405                 :                         OGR_FP( FalseOriginLat ), OGR_FP( FalseOriginLong ),
    1406                 :                         OGR_FP( FalseOriginEasting ), 
    1407               0 :                         OGR_FP( FalseOriginNorthing ));
    1408               0 :         break;
    1409                 : 
    1410                 :       case 9804:
    1411                 :       case 9805: /* NOTE: treats 1SP and 2SP cases the same */
    1412                 :       case 9841: /* Mercator 1SP (Spherical) */
    1413                 :       case 1024: /* Google Mercator */
    1414                 :         poSRS->SetMercator( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1415                 :                             OGR_FP( NatOriginScaleFactor ), 
    1416               4 :                             OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1417                 : 
    1418               4 :         if( nProjMethod == 1024 || nProjMethod == 9841 ) // override hack for google mercator.
    1419                 :         {
    1420                 :             poSRS->SetExtension( "PROJCS", "PROJ4", 
    1421               4 :                                  "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs" );
    1422                 :         }
    1423               4 :         break;
    1424                 : 
    1425                 :       case 9806:
    1426                 :         poSRS->SetCS( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1427               0 :                             OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1428               0 :         break;
    1429                 : 
    1430                 :       case 9807:
    1431                 :         poSRS->SetTM( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1432                 :                       OGR_FP( NatOriginScaleFactor ), 
    1433              27 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1434              27 :         break;
    1435                 :         
    1436                 :       case 9808:
    1437                 :         poSRS->SetTMSO( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1438                 :                         OGR_FP( NatOriginScaleFactor ), 
    1439               0 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1440               0 :         break;
    1441                 :         
    1442                 :       case 9809:
    1443                 :         poSRS->SetOS( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1444                 :                       OGR_FP( NatOriginScaleFactor ), 
    1445               0 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1446               0 :         break;
    1447                 : 
    1448                 :       case 9810:
    1449                 :         poSRS->SetPS( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1450                 :                       OGR_FP( NatOriginScaleFactor ), 
    1451               0 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1452               0 :         break;
    1453                 : 
    1454                 :       case 9811:
    1455                 :         poSRS->SetNZMG( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1456               0 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1457               0 :         break;
    1458                 : 
    1459                 :       case 9812:
    1460                 :       case 9813:
    1461                 :         poSRS->SetHOM( OGR_FP( ProjCenterLat ), OGR_FP( ProjCenterLong ),
    1462                 :                        OGR_FP( Azimuth ), 
    1463                 :                        OGR_FP( AngleRectifiedToSkewedGrid ),
    1464                 :                        OGR_FP( InitialLineScaleFactor ),
    1465               0 :                        OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1466                 : 
    1467               0 :         poNode = poSRS->GetAttrNode( "PROJECTION" )->GetChild( 0 );
    1468               0 :         if( nProjMethod == 9813 )
    1469               0 :             poNode->SetValue( SRS_PT_LABORDE_OBLIQUE_MERCATOR );
    1470               0 :         break;
    1471                 : 
    1472                 :       case 9814:
    1473                 :         /* NOTE: This is no longer used!  Swiss Oblique Mercator gets
    1474                 :         ** implemented using 9815 instead.  
    1475                 :         */
    1476                 :         poSRS->SetSOC( OGR_FP( ProjCenterLat ), OGR_FP( ProjCenterLong ),
    1477               0 :                        OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1478               0 :         break;
    1479                 : 
    1480                 :       case 9815:
    1481                 :         poSRS->SetHOM( OGR_FP( ProjCenterLat ), OGR_FP( ProjCenterLong ),
    1482                 :                        OGR_FP( Azimuth ), 
    1483                 :                        OGR_FP( AngleRectifiedToSkewedGrid ),
    1484                 :                        OGR_FP( InitialLineScaleFactor ),
    1485                 :                        OGR_FP( ProjCenterEasting ), 
    1486               1 :                        OGR_FP( ProjCenterNorthing ) );
    1487               1 :         break;
    1488                 : 
    1489                 :       case 9816:
    1490                 :         poSRS->SetTMG( OGR_FP( FalseOriginLat ), OGR_FP( FalseOriginLong ),
    1491                 :                        OGR_FP( FalseOriginEasting ), 
    1492               0 :                        OGR_FP( FalseOriginNorthing ) );
    1493               0 :         break;
    1494                 : 
    1495                 :       case 9818:
    1496                 :         poSRS->SetPolyconic( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1497               0 :                              OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1498               0 :         break;
    1499                 : 
    1500                 :       case 9819:
    1501                 :       {
    1502               0 :           double dfCenterLong = OGR_FP( ProjCenterLong );
    1503                 : 
    1504               0 :           if( dfCenterLong == 0.0 ) // See ticket #2559
    1505               0 :               dfCenterLong = OGR_FP( PolarLongOrigin );
    1506                 : 
    1507                 :           poSRS->SetKrovak( OGR_FP( ProjCenterLat ), dfCenterLong,
    1508                 :                             OGR_FP( Azimuth ), 
    1509                 :                             OGR_FP( PseudoStdParallelLat ),
    1510                 :                             OGR_FP( PseudoStdParallelScaleFactor ),
    1511                 :                             OGR_FP( ProjCenterEasting ), 
    1512               0 :                             OGR_FP( ProjCenterNorthing ) );
    1513                 :       }
    1514               0 :       break;
    1515                 : 
    1516                 :       case 9820:
    1517                 :         poSRS->SetLAEA( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1518               0 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1519               0 :         break;
    1520                 : 
    1521                 :       case 9821: /* this is the spherical form, and really needs different
    1522                 :                     equations which give different results but PROJ.4 doesn't
    1523                 :                     seem to support the spherical form. */
    1524                 :         poSRS->SetLAEA( OGR_FP( SphericalOriginLat ), 
    1525                 :                         OGR_FP( SphericalOriginLong ),
    1526               0 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1527               0 :         break;
    1528                 : 
    1529                 :       case 9822: /* Albers (Conic) Equal Area */
    1530                 :         poSRS->SetACEA( OGR_FP( StdParallel1Lat ), 
    1531                 :                         OGR_FP( StdParallel2Lat ), 
    1532                 :                         OGR_FP( FalseOriginLat ),
    1533                 :                         OGR_FP( FalseOriginLong ),
    1534                 :                         OGR_FP( FalseOriginEasting ),
    1535               0 :                         OGR_FP( FalseOriginNorthing ) );
    1536               0 :         break;
    1537                 : 
    1538                 :       case 9823: /* Equidistant Cylindrical / Plate Carre / Equirectangular */
    1539                 :         poSRS->SetEquirectangular( OGR_FP( NatOriginLat ),
    1540                 :                                    OGR_FP( NatOriginLong ), 
    1541               0 :                                    0.0, 0.0 );
    1542               0 :         break;
    1543                 : 
    1544                 :       case 9829: /* Polar Stereographic (Variant B) */
    1545                 :         poSRS->SetPS( OGR_FP( PolarLatStdParallel ), OGR_FP(PolarLongOrigin),
    1546                 :                       1.0,
    1547               0 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1548               0 :         break;
    1549                 : 
    1550                 :       case 9834: /* Lambert Cylindrical Equal Area (Spherical) bug #2659 */
    1551                 :         poSRS->SetCEA( OGR_FP( StdParallel1Lat ), OGR_FP( NatOriginLong ), 
    1552               0 :                        OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1553               0 :         break;
    1554                 : 
    1555                 :       default:
    1556                 :         CPLDebug( "EPSG", "No WKT support for projection method %d.",
    1557               0 :                   nProjMethod );
    1558               0 :         return OGRERR_UNSUPPORTED_SRS;
    1559                 :     }
    1560                 : 
    1561                 : /* -------------------------------------------------------------------- */
    1562                 : /*      Set overall PCS authority code.                                 */
    1563                 : /* -------------------------------------------------------------------- */
    1564              44 :     poSRS->SetAuthority( "PROJCS", "EPSG", nPCSCode );
    1565                 : 
    1566                 : /* -------------------------------------------------------------------- */
    1567                 : /*      Set axes                                                        */
    1568                 : /* -------------------------------------------------------------------- */
    1569              44 :     if( nCSC > 0 )
    1570                 :     {
    1571              44 :         SetEPSGAxisInfo( poSRS, "PROJCS", nCSC );
    1572              44 :         CPLErrorReset();
    1573                 :     }
    1574                 : 
    1575              44 :     return OGRERR_NONE;
    1576                 : }
    1577                 : 
    1578                 : /************************************************************************/
    1579                 : /*                           importFromEPSG()                           */
    1580                 : /************************************************************************/
    1581                 : 
    1582                 : /**
    1583                 :  * \brief Initialize SRS based on EPSG GCS or PCS code.
    1584                 :  *
    1585                 :  * This method will initialize the spatial reference based on the
    1586                 :  * passed in EPSG GCS or PCS code.  The coordinate system definitions
    1587                 :  * are normally read from the EPSG derived support files such as 
    1588                 :  * pcs.csv, gcs.csv, pcs.override.csv, gcs.override.csv and falling 
    1589                 :  * back to search for a PROJ.4 epsg init file or a definition in epsg.wkt. 
    1590                 :  *
    1591                 :  * These support files are normally searched for in /usr/local/share/gdal
    1592                 :  * or in the directory identified by the GDAL_DATA configuration option.
    1593                 :  * See CPLFindFile() for details.
    1594                 :  * 
    1595                 :  * This method is relatively expensive, and generally involves quite a bit
    1596                 :  * of text file scanning.  Reasonable efforts should be made to avoid calling
    1597                 :  * it many times for the same coordinate system. 
    1598                 :  * 
    1599                 :  * This method is similar to importFromEPSGA() except that EPSG preferred 
    1600                 :  * axis ordering will *not* be applied for geographic coordinate systems.
    1601                 :  * EPSG normally defines geographic coordinate systems to use lat/long 
    1602                 :  * contrary to typical GIS use). 
    1603                 :  *
    1604                 :  * This method is the same as the C function OSRImportFromEPSG().
    1605                 :  *
    1606                 :  * @param nCode a GCS or PCS code from the horizontal coordinate system table.
    1607                 :  * 
    1608                 :  * @return OGRERR_NONE on success, or an error code on failure.
    1609                 :  */
    1610                 : 
    1611             118 : OGRErr OGRSpatialReference::importFromEPSG( int nCode )
    1612                 : 
    1613                 : {
    1614             118 :     OGRErr eErr = importFromEPSGA( nCode );
    1615                 : 
    1616                 :     // Strip any GCS axis settings found.
    1617             118 :     if( eErr == OGRERR_NONE )
    1618                 :     {
    1619             118 :         OGR_SRSNode *poGEOGCS = GetAttrNode( "GEOGCS" );
    1620                 : 
    1621             118 :         if( poGEOGCS != NULL )
    1622             118 :             poGEOGCS->StripNodes( "AXIS" );
    1623                 :     }
    1624                 : 
    1625             118 :     return eErr;
    1626                 : }
    1627                 : 
    1628                 : /************************************************************************/
    1629                 : /*                         OSRImportFromEPSG()                          */
    1630                 : /************************************************************************/
    1631                 : 
    1632              32 : OGRErr CPL_STDCALL OSRImportFromEPSG( OGRSpatialReferenceH hSRS, int nCode )
    1633                 : 
    1634                 : {
    1635              32 :     VALIDATE_POINTER1( hSRS, "OSRImportFromEPSG", CE_Failure );
    1636                 : 
    1637              32 :     return ((OGRSpatialReference *) hSRS)->importFromEPSG( nCode );
    1638                 : }
    1639                 : 
    1640                 : /************************************************************************/
    1641                 : /*                          importFromEPSGA()                           */
    1642                 : /************************************************************************/
    1643                 : 
    1644                 : /**
    1645                 :  * \brief Initialize SRS based on EPSG GCS or PCS code.
    1646                 :  *
    1647                 :  * This method will initialize the spatial reference based on the
    1648                 :  * passed in EPSG GCS or PCS code.  
    1649                 :  * 
    1650                 :  * This method is similar to importFromEPSG() except that EPSG preferred 
    1651                 :  * axis ordering *will* be applied for geographic coordinate systems.
    1652                 :  * EPSG normally defines geographic coordinate systems to use lat/long 
    1653                 :  * contrary to typical GIS use).  See OGRSpatialReference::importFromEPSG() 
    1654                 :  * for more details on operation of this method.
    1655                 :  *
    1656                 :  * This method is the same as the C function OSRImportFromEPSGA().
    1657                 :  *
    1658                 :  * @param nCode a GCS or PCS code from the horizontal coordinate system table.
    1659                 :  * 
    1660                 :  * @return OGRERR_NONE on success, or an error code on failure.
    1661                 :  */
    1662                 : 
    1663             128 : OGRErr OGRSpatialReference::importFromEPSGA( int nCode )
    1664                 : 
    1665                 : {
    1666                 :     OGRErr  eErr;
    1667                 : 
    1668             128 :     bNormInfoSet = FALSE;
    1669                 : 
    1670                 : /* -------------------------------------------------------------------- */
    1671                 : /*      Clear any existing definition.                                  */
    1672                 : /* -------------------------------------------------------------------- */
    1673             128 :     if( GetRoot() != NULL )
    1674                 :     {
    1675               3 :         delete poRoot;
    1676               3 :         poRoot = NULL;
    1677                 :     }
    1678                 : 
    1679                 : /* -------------------------------------------------------------------- */
    1680                 : /*      Verify that we can find the required filename(s).               */
    1681                 : /* -------------------------------------------------------------------- */
    1682             128 :     if( CSVScanFileByName( CSVFilename( "gcs.csv" ),
    1683                 :                            "COORD_REF_SYS_CODE", 
    1684                 :                            "4269", CC_Integer ) == NULL )
    1685                 :     {
    1686                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    1687                 :                   "Unable to open EPSG support file %s.\n"
    1688                 :                   "Try setting the GDAL_DATA environment variable to point to the\n"
    1689                 :                   "directory containing EPSG csv files.", 
    1690               0 :                   CSVFilename( "gcs.csv" ) );
    1691               0 :         return OGRERR_FAILURE;
    1692                 :     }
    1693                 : 
    1694                 : /* -------------------------------------------------------------------- */
    1695                 : /*      Is this a GeogCS code?   this is inadequate as a criteria       */
    1696                 : /* -------------------------------------------------------------------- */
    1697             128 :     if( EPSGGetGCSInfo( nCode, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) )
    1698              84 :         eErr = SetEPSGGeogCS( this, nCode );
    1699                 :     else
    1700              44 :         eErr = SetEPSGProjCS( this, nCode );
    1701                 : 
    1702                 : /* -------------------------------------------------------------------- */
    1703                 : /*      If we get it as an unsupported code, try looking it up in       */
    1704                 : /*      the epsg.wkt coordinate system dictionary.                      */
    1705                 : /* -------------------------------------------------------------------- */
    1706             128 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    1707                 :     {
    1708                 :         char szCode[32];
    1709               0 :         sprintf( szCode, "%d", nCode );
    1710               0 :         eErr = importFromDict( "epsg.wkt", szCode );
    1711                 :     }
    1712                 : 
    1713                 : /* -------------------------------------------------------------------- */
    1714                 : /*      If we get it as an unsupported code, try looking it up in       */
    1715                 : /*      the PROJ.4 support file(s).                                     */
    1716                 : /* -------------------------------------------------------------------- */
    1717             128 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    1718                 :     {
    1719                 :         char szWrkDefn[100];
    1720                 :         char *pszNormalized;
    1721                 : 
    1722               0 :         sprintf( szWrkDefn, "+init=epsg:%d", nCode );
    1723                 :         
    1724               0 :         pszNormalized = OCTProj4Normalize( szWrkDefn );
    1725                 : 
    1726               0 :         if( strstr(pszNormalized,"proj=") != NULL )
    1727               0 :             eErr = importFromProj4( pszNormalized );
    1728                 :         
    1729               0 :         CPLFree( pszNormalized );
    1730                 :     }
    1731                 : 
    1732                 : /* -------------------------------------------------------------------- */
    1733                 : /*      Push in authority information if we were successful, and it     */
    1734                 : /*      is not already present.                                         */
    1735                 : /* -------------------------------------------------------------------- */
    1736                 :     const char *pszAuthName;
    1737                 : 
    1738             128 :     if( IsProjected() )
    1739              44 :         pszAuthName = GetAuthorityName( "PROJCS" );
    1740                 :     else
    1741              84 :         pszAuthName = GetAuthorityName( "GEOGCS" );
    1742                 : 
    1743                 : 
    1744             128 :     if( eErr == OGRERR_NONE && pszAuthName == NULL )
    1745                 :     {
    1746               0 :         if( IsProjected() )
    1747               0 :             SetAuthority( "PROJCS", "EPSG", nCode );
    1748               0 :         else if( IsGeographic() )
    1749               0 :             SetAuthority( "GEOGCS", "EPSG", nCode );
    1750                 : 
    1751               0 :         eErr = FixupOrdering();
    1752                 :     }
    1753                 : 
    1754                 : /* -------------------------------------------------------------------- */
    1755                 : /*      Otherwise officially issue an error message.                    */
    1756                 : /* -------------------------------------------------------------------- */
    1757             128 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    1758                 :     {
    1759                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1760                 :                   "EPSG PCS/GCS code %d not found in EPSG support files.  Is this a valid\nEPSG coordinate system?", 
    1761               0 :                   nCode );
    1762                 :     }
    1763                 : 
    1764             128 :     return eErr;
    1765                 : }
    1766                 : 
    1767                 : /************************************************************************/
    1768                 : /*                         OSRImportFromEPSGA()                         */
    1769                 : /************************************************************************/
    1770                 : 
    1771               2 : OGRErr CPL_STDCALL OSRImportFromEPSGA( OGRSpatialReferenceH hSRS, int nCode )
    1772                 : 
    1773                 : {
    1774               2 :     VALIDATE_POINTER1( hSRS, "OSRImportFromEPSGA", CE_Failure );
    1775                 : 
    1776               2 :     return ((OGRSpatialReference *) hSRS)->importFromEPSGA( nCode );
    1777                 : }
    1778                 : 
    1779                 : /************************************************************************/
    1780                 : /*                           SetStatePlane()                            */
    1781                 : /************************************************************************/
    1782                 : 
    1783                 : /**
    1784                 :  * \brief Set State Plane projection definition.
    1785                 :  *
    1786                 :  * This will attempt to generate a complete definition of a state plane
    1787                 :  * zone based on generating the entire SRS from the EPSG tables.  If the
    1788                 :  * EPSG tables are unavailable, it will produce a stubbed LOCAL_CS definition
    1789                 :  * and return OGRERR_FAILURE.
    1790                 :  *
    1791                 :  * This method is the same as the C function OSRSetStatePlaneWithUnits().
    1792                 :  *
    1793                 :  * @param nZone State plane zone number, in the USGS numbering scheme (as
    1794                 :  * dinstinct from the Arc/Info and Erdas numbering scheme. 
    1795                 :  *
    1796                 :  * @param bNAD83 TRUE if the NAD83 zone definition should be used or FALSE
    1797                 :  * if the NAD27 zone definition should be used.  
    1798                 :  *
    1799                 :  * @param pszOverrideUnitName Linear unit name to apply overriding the 
    1800                 :  * legal definition for this zone.
    1801                 :  *
    1802                 :  * @param dfOverrideUnit Linear unit conversion factor to apply overriding
    1803                 :  * the legal definition for this zone. 
    1804                 :  * 
    1805                 :  * @return OGRERR_NONE on success, or OGRERR_FAILURE on failure, mostly likely
    1806                 :  * due to the EPSG tables not being accessable. 
    1807                 :  */
    1808                 : 
    1809              10 : OGRErr OGRSpatialReference::SetStatePlane( int nZone, int bNAD83,
    1810                 :                                            const char *pszOverrideUnitName,
    1811                 :                                            double dfOverrideUnit )
    1812                 : 
    1813                 : {
    1814                 :     int         nAdjustedId;
    1815                 :     int         nPCSCode;
    1816                 :     char        szID[32];
    1817                 : 
    1818                 : /* -------------------------------------------------------------------- */
    1819                 : /*      Get the index id from stateplane.csv.                           */
    1820                 : /* -------------------------------------------------------------------- */
    1821              10 :     if( bNAD83 )
    1822               9 :         nAdjustedId = nZone;
    1823                 :     else
    1824               1 :         nAdjustedId = nZone + 10000;
    1825                 : 
    1826                 : /* -------------------------------------------------------------------- */
    1827                 : /*      Turn this into a PCS code.  We assume there will only be one    */
    1828                 : /*      PCS corresponding to each Proj_ code since the proj code        */
    1829                 : /*      already effectively indicates NAD27 or NAD83.                   */
    1830                 : /* -------------------------------------------------------------------- */
    1831              10 :     sprintf( szID, "%d", nAdjustedId );
    1832                 :     nPCSCode =
    1833                 :         atoi( CSVGetField( CSVFilename( "stateplane.csv" ),
    1834                 :                            "ID", szID, CC_Integer,
    1835              10 :                            "EPSG_PCS_CODE" ) );
    1836              10 :     if( nPCSCode < 1 )
    1837                 :     {
    1838                 :         char    szName[128];
    1839                 :         static int bFailureReported = FALSE;
    1840                 : 
    1841               0 :         if( !bFailureReported )
    1842                 :         {
    1843               0 :             bFailureReported = TRUE;
    1844                 :             CPLError( CE_Warning, CPLE_OpenFailed, 
    1845                 :                       "Unable to find state plane zone in stateplane.csv,\n"
    1846                 :                       "likely because the GDAL data files cannot be found.  Using\n"
    1847               0 :                       "incomplete definition of state plane zone.\n" );
    1848                 :         }
    1849                 : 
    1850               0 :         Clear();
    1851               0 :         if( bNAD83 )
    1852                 :         {
    1853               0 :             sprintf( szName, "State Plane Zone %d / NAD83", nZone );
    1854               0 :             SetLocalCS( szName );
    1855               0 :             SetLinearUnits( SRS_UL_METER, 1.0 );
    1856                 :         }
    1857                 :         else
    1858                 :         {
    1859               0 :             sprintf( szName, "State Plane Zone %d / NAD27", nZone );
    1860               0 :             SetLocalCS( szName );
    1861               0 :             SetLinearUnits( SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV) );
    1862                 :         }
    1863                 : 
    1864               0 :         return OGRERR_FAILURE;
    1865                 :     }
    1866                 : 
    1867                 : /* -------------------------------------------------------------------- */
    1868                 : /*      Define based on a full EPSG definition of the zone.             */
    1869                 : /* -------------------------------------------------------------------- */
    1870              10 :     OGRErr eErr = importFromEPSG( nPCSCode );
    1871                 : 
    1872              10 :     if( eErr != OGRERR_NONE )
    1873               0 :         return eErr;
    1874                 : 
    1875                 : /* -------------------------------------------------------------------- */
    1876                 : /*      Apply units override if required.                               */
    1877                 : /*                                                                      */
    1878                 : /*      We will need to adjust the linear projection parameter to       */
    1879                 : /*      match the provided units, and clear the authority code.         */
    1880                 : /* -------------------------------------------------------------------- */
    1881              10 :     if( dfOverrideUnit != 0.0 
    1882                 :         && fabs(dfOverrideUnit - GetLinearUnits()) > 0.0000000001 )
    1883                 :     {
    1884               4 :         double dfFalseEasting = GetNormProjParm( SRS_PP_FALSE_EASTING );
    1885               4 :         double dfFalseNorthing= GetNormProjParm( SRS_PP_FALSE_NORTHING);
    1886                 :         OGR_SRSNode *poPROJCS;
    1887                 : 
    1888               4 :         SetLinearUnits( pszOverrideUnitName, dfOverrideUnit );
    1889                 :         
    1890               4 :         SetNormProjParm( SRS_PP_FALSE_EASTING, dfFalseEasting );
    1891               4 :         SetNormProjParm( SRS_PP_FALSE_NORTHING, dfFalseNorthing );
    1892                 : 
    1893               4 :         poPROJCS = GetAttrNode( "PROJCS" );
    1894               4 :         if( poPROJCS != NULL && poPROJCS->FindChild( "AUTHORITY" ) != -1 )
    1895                 :         {
    1896               4 :             poPROJCS->DestroyChild( poPROJCS->FindChild( "AUTHORITY" ) );
    1897                 :         }
    1898                 :     }
    1899                 : 
    1900              10 :     return OGRERR_NONE;
    1901                 : }
    1902                 : 
    1903                 : /************************************************************************/
    1904                 : /*                          OSRSetStatePlane()                          */
    1905                 : /************************************************************************/
    1906                 : 
    1907               0 : OGRErr OSRSetStatePlane( OGRSpatialReferenceH hSRS, int nZone, int bNAD83 )
    1908                 : 
    1909                 : {
    1910               0 :     VALIDATE_POINTER1( hSRS, "OSRSetStatePlane", CE_Failure );
    1911                 : 
    1912               0 :     return ((OGRSpatialReference *) hSRS)->SetStatePlane( nZone, bNAD83 );
    1913                 : }
    1914                 : 
    1915                 : /************************************************************************/
    1916                 : /*                     OSRSetStatePlaneWithUnits()                      */
    1917                 : /************************************************************************/
    1918                 : 
    1919               2 : OGRErr OSRSetStatePlaneWithUnits( OGRSpatialReferenceH hSRS, 
    1920                 :                                   int nZone, int bNAD83,
    1921                 :                                   const char *pszOverrideUnitName,
    1922                 :                                   double dfOverrideUnit )
    1923                 : 
    1924                 : {
    1925               2 :     VALIDATE_POINTER1( hSRS, "OSRSetStatePlaneWithUnits", CE_Failure );
    1926                 : 
    1927                 :     return ((OGRSpatialReference *) hSRS)->SetStatePlane( nZone, bNAD83,
    1928                 :                                                           pszOverrideUnitName,
    1929               2 :                                                           dfOverrideUnit );
    1930                 : }
    1931                 : 
    1932                 : /************************************************************************/
    1933                 : /*                           GetEPSGGeogCS()                            */
    1934                 : /*                                                                      */
    1935                 : /*      Try to establish what the EPSG code for this coordinate         */
    1936                 : /*      systems GEOGCS might be.  Returns -1 if no reasonable guess     */
    1937                 : /*      can be made.                                                    */
    1938                 : /*                                                                      */
    1939                 : /*      TODO: We really need to do some name lookups.                   */
    1940                 : /************************************************************************/
    1941                 : 
    1942              58 : int OGRSpatialReference::GetEPSGGeogCS()
    1943                 : 
    1944                 : {
    1945              58 :     const char *pszAuthName = GetAuthorityName( "GEOGCS" );
    1946                 : 
    1947                 : /* -------------------------------------------------------------------- */
    1948                 : /*      Do we already have it?                                          */
    1949                 : /* -------------------------------------------------------------------- */
    1950              58 :     if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
    1951              45 :         return atoi(GetAuthorityCode( "GEOGCS" ));
    1952                 : 
    1953                 : /* -------------------------------------------------------------------- */
    1954                 : /*      Get the datum and geogcs names.                                 */
    1955                 : /* -------------------------------------------------------------------- */
    1956              13 :     const char *pszGEOGCS = GetAttrValue( "GEOGCS" );
    1957              13 :     const char *pszDatum = GetAttrValue( "DATUM" );
    1958                 : 
    1959                 :     // We can only operate on coordinate systems with a geogcs.
    1960              13 :     if( pszGEOGCS == NULL || pszDatum == NULL )
    1961               0 :         return -1;
    1962                 : 
    1963                 : /* -------------------------------------------------------------------- */
    1964                 : /*      Is this a "well known" geographic coordinate system?            */
    1965                 : /* -------------------------------------------------------------------- */
    1966                 :     int bWGS, bNAD;
    1967                 : 
    1968                 :     bWGS = strstr(pszGEOGCS,"WGS") != NULL
    1969                 :         || strstr(pszDatum, "WGS")
    1970                 :         || strstr(pszGEOGCS,"World Geodetic System")
    1971                 :         || strstr(pszGEOGCS,"World_Geodetic_System")
    1972                 :         || strstr(pszDatum, "World Geodetic System")
    1973              13 :         || strstr(pszDatum, "World_Geodetic_System"); 
    1974                 : 
    1975                 :     bNAD = strstr(pszGEOGCS,"NAD") != NULL
    1976                 :         || strstr(pszDatum, "NAD")
    1977                 :         || strstr(pszGEOGCS,"North American")
    1978                 :         || strstr(pszGEOGCS,"North_American")
    1979                 :         || strstr(pszDatum, "North American")
    1980              13 :         || strstr(pszDatum, "North_American"); 
    1981                 : 
    1982              13 :     if( bWGS && (strstr(pszGEOGCS,"84") || strstr(pszDatum,"84")) )
    1983               2 :         return 4326;
    1984                 : 
    1985              11 :     if( bWGS && (strstr(pszGEOGCS,"72") || strstr(pszDatum,"72")) )
    1986               0 :         return 4322;
    1987                 : 
    1988              11 :     if( bNAD && (strstr(pszGEOGCS,"83") || strstr(pszDatum,"83")) )
    1989               2 :         return 4269;
    1990                 : 
    1991               9 :     if( bNAD && (strstr(pszGEOGCS,"27") || strstr(pszDatum,"27")) )
    1992               1 :         return 4267;
    1993                 : 
    1994                 : /* -------------------------------------------------------------------- */
    1995                 : /*      If we know the datum, associate the most likely GCS with        */
    1996                 : /*      it.                                                             */
    1997                 : /* -------------------------------------------------------------------- */
    1998               8 :     pszAuthName = GetAuthorityName( "GEOGCS|DATUM" );
    1999                 : 
    2000               8 :     if( pszAuthName != NULL 
    2001                 :         && EQUAL(pszAuthName,"epsg") 
    2002                 :         && GetPrimeMeridian() == 0.0 )
    2003                 :     {
    2004               0 :         int nDatum = atoi(GetAuthorityCode("GEOGCS|DATUM"));
    2005                 :         
    2006               0 :         if( nDatum >= 6000 && nDatum <= 6999 )
    2007               0 :             return nDatum - 2000;
    2008                 :     }
    2009                 : 
    2010               8 :     return -1;
    2011                 : }
    2012                 : 
    2013                 : /************************************************************************/
    2014                 : /*                          AutoIdentifyEPSG()                          */
    2015                 : /************************************************************************/
    2016                 : 
    2017                 : /**
    2018                 :  * \brief Set EPSG authority info if possible.
    2019                 :  *
    2020                 :  * This method inspects a WKT definition, and adds EPSG authority nodes
    2021                 :  * where an aspect of the coordinate system can be easily and safely 
    2022                 :  * corresponded with an EPSG identifier.  In practice, this method will 
    2023                 :  * evolve over time.  In theory it can add authority nodes for any object
    2024                 :  * (ie. spheroid, datum, GEOGCS, units, and PROJCS) that could have an 
    2025                 :  * authority node.  Mostly this is useful to inserting appropriate 
    2026                 :  * PROJCS codes for common formulations (like UTM n WGS84). 
    2027                 :  *
    2028                 :  * If it success the OGRSpatialReference is updated in place, and the 
    2029                 :  * method return OGRERR_NONE.  If the method fails to identify the 
    2030                 :  * general coordinate system OGRERR_UNSUPPORTED_SRS is returned but no 
    2031                 :  * error message is posted via CPLError(). 
    2032                 :  *
    2033                 :  * This method is the same as the C function OSRAutoIdentifyEPSG().
    2034                 :  *
    2035                 :  * @return OGRERR_NONE or OGRERR_UNSUPPORTED_SRS.
    2036                 :  */
    2037                 : 
    2038              32 : OGRErr OGRSpatialReference::AutoIdentifyEPSG()
    2039                 : 
    2040                 : {
    2041                 : /* -------------------------------------------------------------------- */
    2042                 : /*      Do we have a GEOGCS node, but no authority?  If so, try         */
    2043                 : /*      guessing it.                                                    */
    2044                 : /* -------------------------------------------------------------------- */
    2045              32 :     if( (IsProjected() || IsGeographic()) 
    2046                 :         && GetAuthorityCode( "GEOGCS" ) == NULL )
    2047                 :     {
    2048               8 :         int nGCS = GetEPSGGeogCS();
    2049               8 :         if( nGCS != -1 )
    2050               0 :             SetAuthority( "GEOGCS", "EPSG", nGCS );
    2051                 :     }
    2052                 : 
    2053                 : /* -------------------------------------------------------------------- */
    2054                 : /*      Is this a UTM coordinate system with a common GEOGCS?           */
    2055                 : /* -------------------------------------------------------------------- */
    2056                 :     int nZone, bNorth;
    2057              32 :     if( (nZone = GetUTMZone( &bNorth )) != 0 
    2058                 :         && GetAuthorityCode( "PROJCS") == NULL )
    2059                 :     {
    2060                 :         const char *pszAuthName, *pszAuthCode;
    2061                 : 
    2062              29 :         pszAuthName = GetAuthorityName( "PROJCS|GEOGCS" );
    2063              29 :         pszAuthCode = GetAuthorityCode( "PROJCS|GEOGCS" );
    2064                 : 
    2065              29 :         if( pszAuthName == NULL ||  pszAuthCode == NULL )
    2066                 :         {
    2067                 :             /* don't exactly recognise datum */
    2068                 :         }
    2069              21 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4326 )
    2070                 :         { // WGS84
    2071               0 :             if( bNorth ) 
    2072               0 :                 SetAuthority( "PROJCS", "EPSG", 32600 + nZone );
    2073                 :             else
    2074               0 :                 SetAuthority( "PROJCS", "EPSG", 32700 + nZone );
    2075                 :         }
    2076              42 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4267 
    2077                 :                  && nZone >= 3 && nZone <= 22 && bNorth )
    2078              21 :             SetAuthority( "PROJCS", "EPSG", 26700 + nZone ); // NAD27
    2079               0 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4269
    2080                 :                  && nZone >= 3 && nZone <= 23 && bNorth )
    2081               0 :             SetAuthority( "PROJCS", "EPSG", 26900 + nZone ); // NAD83
    2082               0 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4322 )
    2083                 :         { // WGS72
    2084               0 :             if( bNorth ) 
    2085               0 :                 SetAuthority( "PROJCS", "EPSG", 32200 + nZone );
    2086                 :             else
    2087               0 :                 SetAuthority( "PROJCS", "EPSG", 32300 + nZone );
    2088                 :         }
    2089                 :     }
    2090                 : 
    2091                 : /* -------------------------------------------------------------------- */
    2092                 : /*      Return.                                                         */
    2093                 : /* -------------------------------------------------------------------- */
    2094              32 :     if( IsProjected() && GetAuthorityCode("PROJCS") != NULL )
    2095              21 :         return OGRERR_NONE;
    2096              11 :     else if( IsGeographic() && GetAuthorityCode("GEOGCS") != NULL )
    2097               0 :         return OGRERR_NONE;
    2098                 :     else
    2099              11 :         return OGRERR_UNSUPPORTED_SRS;
    2100                 : }
    2101                 : 
    2102                 : /************************************************************************/
    2103                 : /*                        OSRAutoIdentifyEPSG()                         */
    2104                 : /************************************************************************/
    2105                 : 
    2106               0 : OGRErr OSRAutoIdentifyEPSG( OGRSpatialReferenceH hSRS )
    2107                 : 
    2108                 : {
    2109               0 :     VALIDATE_POINTER1( hSRS, "OSRAutoIdentifyEPSG", CE_Failure );
    2110                 : 
    2111               0 :     return ((OGRSpatialReference *) hSRS)->AutoIdentifyEPSG();
    2112                 : }
    2113                 : 
    2114                 : /************************************************************************/
    2115                 : /*                        EPSGTreatsAsLatLong()                         */
    2116                 : /************************************************************************/
    2117                 : 
    2118                 : /**
    2119                 :  * \brief This method returns TRUE if EPSG feels this geographic coordinate
    2120                 :  * system should be treated as having lat/long coordinate ordering.
    2121                 :  *
    2122                 :  * Currently this returns TRUE for all geographic coordinate systems
    2123                 :  * with an EPSG code set, and AXIS values set defining it as lat, long.
    2124                 :  * Note that coordinate systems with an EPSG code and no axis settings
    2125                 :  * will be assumed to not be lat/long.  
    2126                 :  *
    2127                 :  * FALSE will be returned for all coordinate systems that are not geographic,
    2128                 :  * or that do not have an EPSG code set. 
    2129                 :  *
    2130                 :  * @return TRUE or FALSE. 
    2131                 :  */ 
    2132                 : 
    2133               2 : int OGRSpatialReference::EPSGTreatsAsLatLong()
    2134                 : 
    2135                 : {
    2136               2 :     if( !IsGeographic() )
    2137               0 :         return FALSE;
    2138                 : 
    2139               2 :     const char *pszAuth = GetAuthorityName( "GEOGCS" );
    2140                 : 
    2141               2 :     if( pszAuth == NULL || !EQUAL(pszAuth,"EPSG") )
    2142               0 :         return FALSE;
    2143                 : 
    2144               2 :     OGR_SRSNode *poFirstAxis = GetAttrNode( "GEOGCS|AXIS" );
    2145                 : 
    2146               2 :     if( poFirstAxis == NULL )
    2147               0 :         return TRUE;
    2148                 : 
    2149               2 :     if( poFirstAxis->GetChildCount() >= 2 
    2150                 :         && EQUAL(poFirstAxis->GetChild(1)->GetValue(),"NORTH") )
    2151               2 :         return TRUE;
    2152                 : 
    2153               0 :     return FALSE;
    2154                 : }
    2155                 : 
    2156                 : /************************************************************************/
    2157                 : /*                       OSREPSGTreatsAsLatLong()                       */
    2158                 : /************************************************************************/
    2159                 : 
    2160               2 : int OSREPSGTreatsAsLatLong( OGRSpatialReferenceH hSRS )
    2161                 : 
    2162                 : {
    2163               2 :     VALIDATE_POINTER1( hSRS, "OSREPSGTreatsAsLatLong", CE_Failure );
    2164                 : 
    2165               2 :     return ((OGRSpatialReference *) hSRS)->EPSGTreatsAsLatLong();
    2166                 : }
    2167                 : 

Generated by: LCOV version 1.7