LCOV - code coverage report
Current view: directory - ogr - ogr_fromepsg.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 787 667 84.8 %
Date: 2012-04-28 Functions: 29 27 93.1 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogr_fromepsg.cpp 24323 2012-04-27 05:45:18Z 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 24323 2012-04-27 05:45:18Z warmerdam $");
      36                 : 
      37                 : #ifndef PI
      38                 : #  define PI 3.14159265358979323846
      39                 : #endif
      40                 : 
      41                 : void OGRPrintDouble( char * pszStrBuf, double dfValue );
      42                 : 
      43                 : static const char *papszDatumEquiv[] =
      44                 : {
      45                 :     "Militar_Geographische_Institut",
      46                 :     "Militar_Geographische_Institute",
      47                 :     "World_Geodetic_System_1984",
      48                 :     "WGS_1984",
      49                 :     "WGS_72_Transit_Broadcast_Ephemeris",
      50                 :     "WGS_1972_Transit_Broadcast_Ephemeris",
      51                 :     "World_Geodetic_System_1972",
      52                 :     "WGS_1972",
      53                 :     "European_Terrestrial_Reference_System_89",
      54                 :     "European_Reference_System_1989",
      55                 :     NULL
      56                 : };
      57                 : 
      58                 : /************************************************************************/
      59                 : /*                      OGREPSGDatumNameMassage()                       */
      60                 : /*                                                                      */
      61                 : /*      Massage an EPSG datum name into WMT format.  Also transform     */
      62                 : /*      specific exception cases into WKT versions.                     */
      63                 : /************************************************************************/
      64                 : 
      65          137800 : void OGREPSGDatumNameMassage( char ** ppszDatum )
      66                 : 
      67                 : {
      68                 :     int         i, j;
      69          137800 :     char        *pszDatum = *ppszDatum;
      70                 : 
      71          137800 :     if (pszDatum[0] == '\0')
      72               0 :         return;
      73                 : 
      74                 : /* -------------------------------------------------------------------- */
      75                 : /*      Translate non-alphanumeric values to underscores.               */
      76                 : /* -------------------------------------------------------------------- */
      77         3130025 :     for( i = 0; pszDatum[i] != '\0'; i++ )
      78                 :     {
      79        13875505 :         if( pszDatum[i] != '+'
      80         5223496 :             && !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
      81         4497820 :             && !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
      82         1161964 :             && !(pszDatum[i] >= '0' && pszDatum[i] <= '9') )
      83                 :         {
      84          359700 :             pszDatum[i] = '_';
      85                 :         }
      86                 :     }
      87                 : 
      88                 : /* -------------------------------------------------------------------- */
      89                 : /*      Remove repeated and trailing underscores.                       */
      90                 : /* -------------------------------------------------------------------- */
      91         2992225 :     for( i = 1, j = 0; pszDatum[i] != '\0'; i++ )
      92                 :     {
      93         2854425 :         if( pszDatum[j] == '_' && pszDatum[i] == '_' )
      94           25072 :             continue;
      95                 : 
      96         2829353 :         pszDatum[++j] = pszDatum[i];
      97                 :     }
      98          137800 :     if( pszDatum[j] == '_' )
      99           20028 :         pszDatum[j] = '\0';
     100                 :     else
     101          117772 :         pszDatum[j+1] = '\0';
     102                 :     
     103                 : /* -------------------------------------------------------------------- */
     104                 : /*      Search for datum equivelences.  Specific massaged names get     */
     105                 : /*      mapped to OpenGIS specified names.                              */
     106                 : /* -------------------------------------------------------------------- */
     107          806246 :     for( i = 0; papszDatumEquiv[i] != NULL; i += 2 )
     108                 :     {
     109          674339 :         if( EQUAL(*ppszDatum,papszDatumEquiv[i]) )
     110                 :         {
     111            5893 :             CPLFree( *ppszDatum );
     112            5893 :             *ppszDatum = CPLStrdup( papszDatumEquiv[i+1] );
     113            5893 :             break;
     114                 :         }
     115                 :     }
     116                 : }
     117                 : 
     118                 : /************************************************************************/
     119                 : /*                        EPSGAngleStringToDD()                         */
     120                 : /*                                                                      */
     121                 : /*      Convert an angle in the specified units to decimal degrees.     */
     122                 : /************************************************************************/
     123                 : 
     124                 : static double
     125           56640 : EPSGAngleStringToDD( const char * pszAngle, int nUOMAngle )
     126                 : 
     127                 : {
     128                 :     double      dfAngle;
     129                 :     
     130           56640 :     if( nUOMAngle == 9110 )             /* DDD.MMSSsss */
     131                 :     {
     132                 :         char    *pszDecimal;
     133                 :         
     134           25546 :         dfAngle = ABS(atoi(pszAngle));
     135           25546 :         pszDecimal = (char *) strchr(pszAngle,'.');
     136           25546 :         if( pszDecimal != NULL && strlen(pszDecimal) > 1 )
     137                 :         {
     138                 :             char        szMinutes[3];
     139                 :             char        szSeconds[64];
     140                 : 
     141           20238 :             szMinutes[0] = pszDecimal[1];
     142           29854 :             if( pszDecimal[2] >= '0' && pszDecimal[2] <= '9' )
     143            9616 :                 szMinutes[1] = pszDecimal[2];
     144                 :             else
     145           10622 :                 szMinutes[1] = '0';
     146                 :             
     147           20238 :             szMinutes[2] = '\0';
     148           20238 :             dfAngle += atoi(szMinutes) / 60.0;
     149                 : 
     150           20238 :             if( strlen(pszDecimal) > 3 )
     151                 :             {
     152            2654 :                 szSeconds[0] = pszDecimal[3];
     153            5142 :                 if( pszDecimal[4] >= '0' && pszDecimal[4] <= '9' )
     154                 :                 {
     155            2488 :                     szSeconds[1] = pszDecimal[4];
     156            2488 :                     szSeconds[2] = '.';
     157            2488 :                     strncpy( szSeconds+3, pszDecimal + 5, sizeof(szSeconds)-3 );
     158            2488 :                     szSeconds[sizeof(szSeconds)-1] = 0;
     159                 :                 }
     160                 :                 else
     161                 :                 {
     162             166 :                     szSeconds[1] = '0';
     163             166 :                     szSeconds[2] = '\0';
     164                 :                 }
     165            2654 :                 dfAngle += CPLAtof(szSeconds) / 3600.0;
     166                 :             }
     167                 :         }
     168                 : 
     169           25546 :         if( pszAngle[0] == '-' )
     170            7984 :             dfAngle *= -1;
     171                 :     }
     172           31826 :     else if( nUOMAngle == 9105 || nUOMAngle == 9106 )   /* grad */
     173                 :     {
     174             732 :         dfAngle = 180 * (CPLAtof(pszAngle ) / 200);
     175                 :     }
     176           30362 :     else if( nUOMAngle == 9101 )                        /* radians */
     177                 :     {
     178               0 :         dfAngle = 180 * (CPLAtof(pszAngle ) / PI);
     179                 :     }
     180           30362 :     else if( nUOMAngle == 9103 )                        /* arc-minute */
     181                 :     {
     182               0 :         dfAngle = CPLAtof(pszAngle) / 60;
     183                 :     }
     184           30362 :     else if( nUOMAngle == 9104 )                        /* arc-second */
     185                 :     {
     186               0 :         dfAngle = CPLAtof(pszAngle) / 3600;
     187                 :     }
     188                 :     else /* decimal degrees ... some cases missing but seeminly never used */
     189                 :     {
     190           30362 :         CPLAssert( nUOMAngle == 9102 || nUOMAngle == 0 );
     191                 :         
     192           30362 :         dfAngle = CPLAtof(pszAngle );
     193                 :     }
     194                 : 
     195           56640 :     return( dfAngle );
     196                 : }
     197                 : 
     198                 : /************************************************************************/
     199                 : /*                        EPSGGetUOMAngleInfo()                         */
     200                 : /************************************************************************/
     201                 : 
     202           36204 : int EPSGGetUOMAngleInfo( int nUOMAngleCode,
     203                 :                          char **ppszUOMName,
     204                 :                          double * pdfInDegrees )
     205                 : 
     206                 : {
     207           36204 :     const char  *pszUOMName = NULL;
     208           36204 :     double      dfInDegrees = 1.0;
     209                 :     const char *pszFilename;
     210                 :     char        szSearchKey[24];
     211                 : 
     212                 :     /* We do a special override of some of the DMS formats name */
     213                 :     /* This will also solve accuracy problems when computing */
     214                 :     /* the dfInDegree value from the CSV values (#3643) */
     215           36204 :     if( nUOMAngleCode == 9102 || nUOMAngleCode == 9107
     216                 :         || nUOMAngleCode == 9108 || nUOMAngleCode == 9110
     217                 :         || nUOMAngleCode == 9122 )
     218                 :     {
     219           35926 :         if( ppszUOMName != NULL )
     220           35926 :             *ppszUOMName = CPLStrdup("degree");
     221           35926 :         if( pdfInDegrees != NULL )
     222           35926 :             *pdfInDegrees = 1.0;
     223           35926 :         return TRUE;
     224                 :     }
     225                 : 
     226             278 :     pszFilename = CSVFilename( "unit_of_measure.csv" );
     227                 : 
     228             278 :     sprintf( szSearchKey, "%d", nUOMAngleCode );
     229                 :     pszUOMName = CSVGetField( pszFilename,
     230                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     231             278 :                               "UNIT_OF_MEAS_NAME" );
     232                 : 
     233                 : /* -------------------------------------------------------------------- */
     234                 : /*      If the file is found, read from there.  Note that FactorC is    */
     235                 : /*      an empty field for any of the DMS style formats, and in this    */
     236                 : /*      case we really want to return the default InDegrees value       */
     237                 : /*      (1.0) from above.                                               */
     238                 : /* -------------------------------------------------------------------- */
     239             278 :     if( pszUOMName != NULL )
     240                 :     {
     241                 :         double dfFactorB, dfFactorC;
     242                 :         
     243                 :         dfFactorB = 
     244                 :             CPLAtof(CSVGetField( pszFilename,
     245                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     246             278 :                               "FACTOR_B" ));
     247                 :         
     248                 :         dfFactorC = 
     249                 :             CPLAtof(CSVGetField( pszFilename,
     250                 :                               "UOM_CODE", szSearchKey, CC_Integer,
     251             278 :                               "FACTOR_C" ));
     252                 : 
     253             278 :         if( dfFactorC != 0.0 )
     254             278 :             dfInDegrees = (dfFactorB / dfFactorC) * (180.0 / PI);
     255                 : 
     256                 :         // For some reason, (FactorB) is not very precise in EPSG, use
     257                 :         // a more exact form for grads.
     258             278 :         if( nUOMAngleCode == 9105 )
     259             278 :             dfInDegrees = 180.0 / 200.0;
     260                 :     }
     261                 : 
     262                 : /* -------------------------------------------------------------------- */
     263                 : /*      Otherwise handle a few well known units directly.               */
     264                 : /* -------------------------------------------------------------------- */
     265                 :     else
     266                 :     {
     267               0 :         switch( nUOMAngleCode )
     268                 :         {
     269                 :           case 9101:
     270               0 :             pszUOMName = "radian";
     271               0 :             dfInDegrees = 180.0 / PI;
     272               0 :             break;
     273                 : 
     274                 :           case 9102:
     275                 :           case 9107:
     276                 :           case 9108:
     277                 :           case 9110:
     278                 :           case 9122:
     279               0 :             pszUOMName = "degree";
     280               0 :             dfInDegrees = 1.0;
     281               0 :             break;
     282                 : 
     283                 :           case 9103:
     284               0 :             pszUOMName = "arc-minute";
     285               0 :             dfInDegrees = 1 / 60.0;
     286               0 :             break;
     287                 : 
     288                 :           case 9104:
     289               0 :             pszUOMName = "arc-second";
     290               0 :             dfInDegrees = 1 / 3600.0;
     291               0 :             break;
     292                 :         
     293                 :           case 9105:
     294               0 :             pszUOMName = "grad";
     295               0 :             dfInDegrees = 180.0 / 200.0;
     296               0 :             break;
     297                 : 
     298                 :           case 9106:
     299               0 :             pszUOMName = "gon";
     300               0 :             dfInDegrees = 180.0 / 200.0;
     301               0 :             break;
     302                 :         
     303                 :           case 9109:
     304               0 :             pszUOMName = "microradian";
     305               0 :             dfInDegrees = 180.0 / (3.14159265358979 * 1000000.0);
     306               0 :             break;
     307                 : 
     308                 :           default:
     309               0 :             return FALSE;
     310                 :         }
     311                 :     }
     312                 : 
     313                 : /* -------------------------------------------------------------------- */
     314                 : /*      Return to caller.                                               */
     315                 : /* -------------------------------------------------------------------- */
     316             278 :     if( ppszUOMName != NULL )
     317                 :     {
     318             278 :         if( pszUOMName != NULL )
     319             278 :             *ppszUOMName = CPLStrdup( pszUOMName );
     320                 :         else
     321               0 :             *ppszUOMName = NULL;
     322                 :     }
     323                 : 
     324             278 :     if( pdfInDegrees != NULL )
     325             278 :         *pdfInDegrees = dfInDegrees;
     326                 : 
     327             278 :     return( TRUE );
     328                 : }
     329                 : 
     330                 : /************************************************************************/
     331                 : /*                        EPSGGetUOMLengthInfo()                        */
     332                 : /*                                                                      */
     333                 : /*      Note: This function should eventually also know how to          */
     334                 : /*      lookup length aliases in the UOM_LE_ALIAS table.                */
     335                 : /************************************************************************/
     336                 : 
     337                 : static int 
     338          106530 : EPSGGetUOMLengthInfo( int nUOMLengthCode,
     339                 :                       char **ppszUOMName,
     340                 :                       double * pdfInMeters )
     341                 : 
     342                 : {
     343                 :     char        **papszUnitsRecord;
     344                 :     char        szSearchKey[24];
     345                 :     int         iNameField;
     346                 : 
     347                 : #define UOM_FILENAME CSVFilename( "unit_of_measure.csv" )
     348                 : 
     349                 : /* -------------------------------------------------------------------- */
     350                 : /*      We short cut meter to save work in the most common case.        */
     351                 : /* -------------------------------------------------------------------- */
     352          106530 :     if( nUOMLengthCode == 9001 )
     353                 :     {
     354           95996 :         if( ppszUOMName != NULL )
     355           20128 :             *ppszUOMName = CPLStrdup( "metre" );
     356           95996 :         if( pdfInMeters != NULL )
     357           95996 :             *pdfInMeters = 1.0;
     358                 : 
     359           95996 :         return TRUE;
     360                 :     }
     361                 : 
     362                 : /* -------------------------------------------------------------------- */
     363                 : /*      Search the units database for this unit.  If we don't find      */
     364                 : /*      it return failure.                                              */
     365                 : /* -------------------------------------------------------------------- */
     366           10534 :     sprintf( szSearchKey, "%d", nUOMLengthCode );
     367                 :     papszUnitsRecord =
     368           10534 :         CSVScanFileByName( UOM_FILENAME, "UOM_CODE", szSearchKey, CC_Integer );
     369                 : 
     370           10534 :     if( papszUnitsRecord == NULL )
     371               0 :         return FALSE;
     372                 : 
     373                 : /* -------------------------------------------------------------------- */
     374                 : /*      Get the name, if requested.                                     */
     375                 : /* -------------------------------------------------------------------- */
     376           10534 :     if( ppszUOMName != NULL )
     377                 :     {
     378            3302 :         iNameField = CSVGetFileFieldId( UOM_FILENAME, "UNIT_OF_MEAS_NAME" );
     379            3302 :         *ppszUOMName = CPLStrdup( CSLGetField(papszUnitsRecord, iNameField) );
     380                 :     }
     381                 :     
     382                 : /* -------------------------------------------------------------------- */
     383                 : /*      Get the A and B factor fields, and create the multiplicative    */
     384                 : /*      factor.                                                         */
     385                 : /* -------------------------------------------------------------------- */
     386           10534 :     if( pdfInMeters != NULL )
     387                 :     {
     388                 :         int     iBFactorField, iCFactorField;
     389                 :         
     390           10534 :         iBFactorField = CSVGetFileFieldId( UOM_FILENAME, "FACTOR_B" );
     391           10534 :         iCFactorField = CSVGetFileFieldId( UOM_FILENAME, "FACTOR_C" );
     392                 : 
     393           10534 :         if( CPLAtof(CSLGetField(papszUnitsRecord, iCFactorField)) > 0.0 )
     394                 :             *pdfInMeters = CPLAtof(CSLGetField(papszUnitsRecord,iBFactorField))
     395           10534 :                 / CPLAtof(CSLGetField(papszUnitsRecord, iCFactorField));
     396                 :         else
     397               0 :             *pdfInMeters = 0.0;
     398                 :     }
     399                 :     
     400           10534 :     return( TRUE );
     401                 : }
     402                 : 
     403                 : /************************************************************************/
     404                 : /*                       EPSGGetWGS84Transform()                        */
     405                 : /*                                                                      */
     406                 : /*      The following code attempts to find a bursa-wolf                */
     407                 : /*      transformation from this GeogCS to WGS84 (4326).                */
     408                 : /*                                                                      */
     409                 : /*      Faults:                                                         */
     410                 : /*       o I think there are codes other than 9603 and 9607 that        */
     411                 : /*         return compatible, or easily transformed parameters.         */
     412                 : /*       o Only the first path from the given GeogCS is checked due     */
     413                 : /*         to limitations in the CSV API.                               */
     414                 : /************************************************************************/
     415                 : 
     416           36218 : int EPSGGetWGS84Transform( int nGeogCS, double *padfTransform )
     417                 : 
     418                 : {
     419                 :     int         nMethodCode, iDXField, iField;
     420                 :     char        szCode[32];
     421                 :     const char *pszFilename;
     422                 :     char **papszLine;
     423                 : 
     424                 : /* -------------------------------------------------------------------- */
     425                 : /*      Fetch the line from the GCS table.                              */
     426                 : /* -------------------------------------------------------------------- */
     427           36218 :     pszFilename = CSVFilename("gcs.override.csv");
     428           36218 :     sprintf( szCode, "%d", nGeogCS );
     429                 :     papszLine = CSVScanFileByName( pszFilename,
     430                 :                                    "COORD_REF_SYS_CODE", 
     431           36218 :                                    szCode, CC_Integer );
     432           36218 :     if( papszLine == NULL )
     433                 :     {
     434           36218 :         pszFilename = CSVFilename("gcs.csv");
     435           36218 :         sprintf( szCode, "%d", nGeogCS );
     436                 :         papszLine = CSVScanFileByName( pszFilename,
     437                 :                                        "COORD_REF_SYS_CODE", 
     438           36218 :                                        szCode, CC_Integer );
     439                 :     }
     440                 : 
     441           36218 :     if( papszLine == NULL )
     442               0 :         return FALSE;
     443                 : 
     444                 : /* -------------------------------------------------------------------- */
     445                 : /*      Verify that the method code is one of our accepted ones.        */
     446                 : /* -------------------------------------------------------------------- */
     447                 :     nMethodCode = 
     448                 :         atoi(CSLGetField( papszLine,
     449                 :                           CSVGetFileFieldId(pszFilename,
     450           36218 :                                             "COORD_OP_METHOD_CODE")));
     451           36218 :     if( nMethodCode != 9603 && nMethodCode != 9607 && nMethodCode != 9606 )
     452            8742 :         return FALSE;
     453                 : 
     454                 : /* -------------------------------------------------------------------- */
     455                 : /*      Fetch the transformation parameters.                            */
     456                 : /* -------------------------------------------------------------------- */
     457           27476 :     iDXField = CSVGetFileFieldId(pszFilename, "DX");
     458           27476 :     if (iDXField < 0 || CSLCount(papszLine) < iDXField + 7)
     459               0 :         return FALSE;
     460                 : 
     461          219808 :     for( iField = 0; iField < 7; iField++ )
     462          192332 :         padfTransform[iField] = CPLAtof(papszLine[iDXField+iField]);
     463                 : 
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*      9607 - coordinate frame rotation has reverse signs on the       */
     466                 : /*      rotational coefficients.  Fix up now since we internal          */
     467                 : /*      operate according to method 9606 (position vector 7-parameter). */
     468                 : /* -------------------------------------------------------------------- */
     469           27476 :     if( nMethodCode == 9607 )
     470                 :     {
     471            4430 :         padfTransform[3] *= -1;
     472            4430 :         padfTransform[4] *= -1;
     473            4430 :         padfTransform[5] *= -1;
     474                 :     }
     475                 :         
     476           27476 :     return TRUE;
     477                 : }
     478                 : 
     479                 : /************************************************************************/
     480                 : /*                           EPSGGetPMInfo()                            */
     481                 : /*                                                                      */
     482                 : /*      Get the offset between a given prime meridian and Greenwich     */
     483                 : /*      in degrees.                                                     */
     484                 : /************************************************************************/
     485                 : 
     486                 : static int 
     487           36208 : EPSGGetPMInfo( int nPMCode, char ** ppszName, double *pdfOffset )
     488                 : 
     489                 : {
     490                 :     char        szSearchKey[24];
     491                 :     int         nUOMAngle;
     492                 : 
     493                 : #define PM_FILENAME CSVFilename("prime_meridian.csv")
     494                 : 
     495                 : /* -------------------------------------------------------------------- */
     496                 : /*      Use a special short cut for Greenwich, since it is so common.   */
     497                 : /* -------------------------------------------------------------------- */
     498                 :     /* FIXME? Where does 7022 come from ? Let's keep it just in case */
     499                 :     /* 8901 is the official current code for Greenwich */
     500           36208 :     if( nPMCode == 7022 /* PM_Greenwich */ || nPMCode == 8901 )
     501                 :     {
     502           35294 :         if( pdfOffset != NULL )
     503           35294 :             *pdfOffset = 0.0;
     504           35294 :         if( ppszName != NULL )
     505           35294 :             *ppszName = CPLStrdup( "Greenwich" );
     506           35294 :         return TRUE;
     507                 :     }
     508                 : 
     509                 : /* -------------------------------------------------------------------- */
     510                 : /*      Search the database for the corresponding datum code.           */
     511                 : /* -------------------------------------------------------------------- */
     512             914 :     sprintf( szSearchKey, "%d", nPMCode );
     513                 : 
     514                 :     nUOMAngle =
     515                 :         atoi(CSVGetField( PM_FILENAME,
     516                 :                           "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     517             914 :                           "UOM_CODE" ) );
     518             914 :     if( nUOMAngle < 1 )
     519               0 :         return FALSE;
     520                 : 
     521                 : /* -------------------------------------------------------------------- */
     522                 : /*      Get the PM offset.                                              */
     523                 : /* -------------------------------------------------------------------- */
     524             914 :     if( pdfOffset != NULL )
     525                 :     {
     526                 :         *pdfOffset =
     527                 :             EPSGAngleStringToDD(
     528                 :                 CSVGetField( PM_FILENAME,
     529                 :                              "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     530                 :                              "GREENWICH_LONGITUDE" ),
     531             914 :                 nUOMAngle );
     532                 :     }
     533                 :     
     534                 : /* -------------------------------------------------------------------- */
     535                 : /*      Get the name, if requested.                                     */
     536                 : /* -------------------------------------------------------------------- */
     537             914 :     if( ppszName != NULL )
     538                 :         *ppszName =
     539                 :             CPLStrdup(
     540                 :                 CSVGetField( PM_FILENAME, 
     541                 :                              "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
     542             914 :                              "PRIME_MERIDIAN_NAME" ));
     543                 :     
     544             914 :     return( TRUE );
     545                 : }
     546                 : 
     547                 : /************************************************************************/
     548                 : /*                           EPSGGetGCSInfo()                           */
     549                 : /*                                                                      */
     550                 : /*      Fetch the datum, and prime meridian related to a particular     */
     551                 : /*      GCS.                                                            */
     552                 : /************************************************************************/
     553                 : 
     554                 : static int
     555           60382 : EPSGGetGCSInfo( int nGCSCode, char ** ppszName,
     556                 :                 int * pnDatum, char **ppszDatumName,
     557                 :                 int * pnPM, int *pnEllipsoid, int *pnUOMAngle,
     558                 :                 int * pnCoordSysCode )
     559                 : 
     560                 : {
     561                 :     char        szSearchKey[24];
     562                 :     int         nDatum, nPM, nUOMAngle, nEllipsoid;
     563                 :     const char  *pszFilename;
     564                 : 
     565                 : 
     566                 : /* -------------------------------------------------------------------- */
     567                 : /*      Search the database for the corresponding datum code.           */
     568                 : /* -------------------------------------------------------------------- */
     569           60382 :     pszFilename = CSVFilename("gcs.override.csv");
     570           60382 :     sprintf( szSearchKey, "%d", nGCSCode );
     571                 : 
     572                 :     nDatum = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     573                 :                                szSearchKey, CC_Integer,
     574           60382 :                                "DATUM_CODE" ) );
     575                 : 
     576           60382 :     if( nDatum < 1 )
     577                 :     {
     578           60382 :         pszFilename = CSVFilename("gcs.csv");
     579           60382 :         sprintf( szSearchKey, "%d", nGCSCode );
     580                 :         
     581                 :         nDatum = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     582                 :                                    szSearchKey, CC_Integer,
     583           60382 :                                    "DATUM_CODE" ) );
     584                 :     }
     585                 : 
     586           60382 :     if( nDatum < 1 )
     587           24178 :         return FALSE;
     588                 : 
     589           36204 :     if( pnDatum != NULL )
     590           36204 :         *pnDatum = nDatum;
     591                 :     
     592                 : /* -------------------------------------------------------------------- */
     593                 : /*      Get the PM.                                                     */
     594                 : /* -------------------------------------------------------------------- */
     595                 :     nPM = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     596                 :                             szSearchKey, CC_Integer,
     597           36204 :                             "PRIME_MERIDIAN_CODE" ) );
     598                 : 
     599           36204 :     if( nPM < 1 )
     600               0 :         return FALSE;
     601                 : 
     602           36204 :     if( pnPM != NULL )
     603           36204 :         *pnPM = nPM;
     604                 : 
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*      Get the Ellipsoid.                                              */
     607                 : /* -------------------------------------------------------------------- */
     608                 :     nEllipsoid = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     609                 :                                    szSearchKey, CC_Integer,
     610           36204 :                                    "ELLIPSOID_CODE" ) );
     611                 : 
     612           36204 :     if( nEllipsoid < 1 )
     613               0 :         return FALSE;
     614                 : 
     615           36204 :     if( pnEllipsoid != NULL )
     616           36204 :         *pnEllipsoid = nEllipsoid;
     617                 : 
     618                 : /* -------------------------------------------------------------------- */
     619                 : /*      Get the angular units.                                          */
     620                 : /* -------------------------------------------------------------------- */
     621                 :     nUOMAngle = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     622                 :                                   szSearchKey, CC_Integer,
     623           36204 :                                   "UOM_CODE" ) );
     624                 : 
     625           36204 :     if( nUOMAngle < 1 )
     626               0 :         return FALSE;
     627                 : 
     628           36204 :     if( pnUOMAngle != NULL )
     629           36204 :         *pnUOMAngle = nUOMAngle;
     630                 : 
     631                 : /* -------------------------------------------------------------------- */
     632                 : /*      Get the name, if requested.                                     */
     633                 : /* -------------------------------------------------------------------- */
     634           36204 :     if( ppszName != NULL )
     635                 :         *ppszName =
     636                 :             CPLStrdup(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     637                 :                                    szSearchKey, CC_Integer,
     638           36204 :                                    "COORD_REF_SYS_NAME" ));
     639                 :     
     640                 : /* -------------------------------------------------------------------- */
     641                 : /*      Get the datum name, if requested.                               */
     642                 : /* -------------------------------------------------------------------- */
     643           36204 :     if( ppszDatumName != NULL )
     644                 :         *ppszDatumName =
     645                 :             CPLStrdup(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     646                 :                                    szSearchKey, CC_Integer,
     647           36204 :                                    "DATUM_NAME" ));
     648                 :     
     649                 : /* -------------------------------------------------------------------- */
     650                 : /*      Get the CoordSysCode                                            */
     651                 : /* -------------------------------------------------------------------- */
     652                 :     int nCSC;
     653                 : 
     654                 :     nCSC = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
     655                 :                              szSearchKey, CC_Integer,
     656           36204 :                              "COORD_SYS_CODE" ) );
     657                 :     
     658           36204 :     if( pnCoordSysCode != NULL )
     659           36204 :         *pnCoordSysCode = nCSC;
     660                 : 
     661           36204 :     return( TRUE );
     662                 : }
     663                 : 
     664                 : /************************************************************************/
     665                 : /*                         OSRGetEllipsoidInfo()                        */
     666                 : /************************************************************************/
     667                 : 
     668                 : /**
     669                 :  * Fetch info about an ellipsoid.
     670                 :  *
     671                 :  * This helper function will return ellipsoid parameters corresponding to EPSG
     672                 :  * code provided. Axes are always returned in meters.  Semi major computed
     673                 :  * based on inverse flattening where that is provided.
     674                 :  *
     675                 :  * @param nCode EPSG code of the requested ellipsoid
     676                 :  *
     677                 :  * @param ppszName pointer to string where ellipsoid name will be returned. It
     678                 :  * is caller responsibility to free this string after using with CPLFree().
     679                 :  *
     680                 :  * @param pdfSemiMajor pointer to variable where semi major axis will be
     681                 :  * returned.
     682                 :  *
     683                 :  * @param pdfInvFlattening pointer to variable where inverse flattening will
     684                 :  * be returned.
     685                 :  *
     686                 :  * @return OGRERR_NONE on success or an error code in case of failure.
     687                 :  **/
     688                 : 
     689                 : OGRErr 
     690           36340 : OSRGetEllipsoidInfo( int nCode, char ** ppszName,
     691                 :                      double * pdfSemiMajor, double * pdfInvFlattening )
     692                 : 
     693                 : {
     694                 :     char        szSearchKey[24];
     695           36340 :     double      dfSemiMajor, dfToMeters = 1.0;
     696                 :     int         nUOMLength;
     697                 :     
     698                 : /* -------------------------------------------------------------------- */
     699                 : /*      Get the semi major axis.                                        */
     700                 : /* -------------------------------------------------------------------- */
     701           36340 :     snprintf( szSearchKey, sizeof(szSearchKey), "%d", nCode );
     702           36340 :     szSearchKey[sizeof(szSearchKey) - 1] = '\n';
     703                 : 
     704                 :     dfSemiMajor =
     705                 :         CPLAtof(CSVGetField( CSVFilename("ellipsoid.csv" ),
     706                 :                              "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     707           36340 :                              "SEMI_MAJOR_AXIS" ) );
     708           36340 :     if( dfSemiMajor == 0.0 )
     709               0 :         return OGRERR_UNSUPPORTED_SRS;
     710                 : 
     711                 : /* -------------------------------------------------------------------- */
     712                 : /*      Get the translation factor into meters.                         */
     713                 : /* -------------------------------------------------------------------- */
     714                 :     nUOMLength = atoi(CSVGetField( CSVFilename("ellipsoid.csv" ),
     715                 :                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     716           36340 :                                    "UOM_CODE" ));
     717           36340 :     EPSGGetUOMLengthInfo( nUOMLength, NULL, &dfToMeters );
     718                 : 
     719           36340 :     dfSemiMajor *= dfToMeters;
     720                 :     
     721           36340 :     if( pdfSemiMajor != NULL )
     722           36340 :         *pdfSemiMajor = dfSemiMajor;
     723                 :     
     724                 : /* -------------------------------------------------------------------- */
     725                 : /*      Get the semi-minor if requested.  If the Semi-minor axis        */
     726                 : /*      isn't available, compute it based on the inverse flattening.    */
     727                 : /* -------------------------------------------------------------------- */
     728           36340 :     if( pdfInvFlattening != NULL )
     729                 :     {
     730                 :         *pdfInvFlattening = 
     731                 :             CPLAtof(CSVGetField( CSVFilename("ellipsoid.csv" ),
     732                 :                                  "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     733           36340 :                                  "INV_FLATTENING" ));
     734                 : 
     735           36340 :         if( *pdfInvFlattening == 0.0 )
     736                 :         {
     737                 :             double dfSemiMinor;
     738                 : 
     739                 :             dfSemiMinor =
     740                 :                 CPLAtof(CSVGetField( CSVFilename("ellipsoid.csv" ),
     741                 :                                   "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     742            3955 :                                   "SEMI_MINOR_AXIS" )) * dfToMeters;
     743                 : 
     744            7800 :             if( dfSemiMajor != 0.0 && dfSemiMajor != dfSemiMinor )
     745                 :                 *pdfInvFlattening = 
     746            3845 :                     -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
     747                 :             else
     748             110 :                 *pdfInvFlattening = 0.0;
     749                 :         }
     750                 :     }
     751                 : 
     752                 : /* -------------------------------------------------------------------- */
     753                 : /*      Get the name, if requested.                                     */
     754                 : /* -------------------------------------------------------------------- */
     755           36340 :     if( ppszName != NULL )
     756                 :         *ppszName =
     757                 :             CPLStrdup(CSVGetField( CSVFilename("ellipsoid.csv" ),
     758                 :                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
     759           36244 :                                    "ELLIPSOID_NAME" ));
     760                 : 
     761           36340 :     return OGRERR_NONE;
     762                 : }
     763                 : 
     764                 : #define CoLatConeAxis        1036 /* see #4223 */
     765                 : #define NatOriginLat         8801
     766                 : #define NatOriginLong        8802
     767                 : #define NatOriginScaleFactor 8805
     768                 : #define FalseEasting         8806
     769                 : #define FalseNorthing        8807
     770                 : #define ProjCenterLat        8811
     771                 : #define ProjCenterLong       8812
     772                 : #define Azimuth              8813
     773                 : #define AngleRectifiedToSkewedGrid 8814
     774                 : #define InitialLineScaleFactor 8815
     775                 : #define ProjCenterEasting    8816
     776                 : #define ProjCenterNorthing   8817
     777                 : #define PseudoStdParallelLat 8818
     778                 : #define PseudoStdParallelScaleFactor 8819
     779                 : #define FalseOriginLat       8821
     780                 : #define FalseOriginLong      8822
     781                 : #define StdParallel1Lat      8823
     782                 : #define StdParallel2Lat      8824
     783                 : #define FalseOriginEasting   8826
     784                 : #define FalseOriginNorthing  8827
     785                 : #define SphericalOriginLat   8828
     786                 : #define SphericalOriginLong  8829
     787                 : #define InitialLongitude     8830
     788                 : #define ZoneWidth            8831
     789                 : #define PolarLatStdParallel  8832
     790                 : #define PolarLongOrigin      8833
     791                 : 
     792                 : /************************************************************************/
     793                 : /*                         EPSGGetProjTRFInfo()                         */
     794                 : /*                                                                      */
     795                 : /*      Transform a PROJECTION_TRF_CODE into a projection method,       */
     796                 : /*      and a set of parameters.  The parameters identify will          */
     797                 : /*      depend on the returned method, but they will all have been      */
     798                 : /*      normalized into degrees and meters.                             */
     799                 : /************************************************************************/
     800                 : 
     801                 : static int
     802           23410 : EPSGGetProjTRFInfo( int nPCS, int * pnProjMethod,
     803                 :                     int *panParmIds, double * padfProjParms )
     804                 : 
     805                 : {
     806                 :     int         nProjMethod, i;
     807                 :     double      adfProjParms[7];
     808                 :     char        szTRFCode[16];
     809           23410 :     CPLString   osFilename;
     810                 : 
     811                 : /* -------------------------------------------------------------------- */
     812                 : /*      Get the proj method.  If this fails to return a meaningful      */
     813                 : /*      number, then the whole function fails.                          */
     814                 : /* -------------------------------------------------------------------- */
     815           23410 :     osFilename = CSVFilename( "pcs.override.csv" );
     816           23410 :     sprintf( szTRFCode, "%d", nPCS );
     817                 :     nProjMethod =
     818                 :         atoi( CSVGetField( osFilename,
     819                 :                            "COORD_REF_SYS_CODE", szTRFCode, CC_Integer,
     820           23410 :                            "COORD_OP_METHOD_CODE" ) );
     821           23410 :     if( nProjMethod == 0 )
     822                 :     {
     823           23388 :         osFilename = CSVFilename( "pcs.csv" );
     824           23388 :         sprintf( szTRFCode, "%d", nPCS );
     825                 :         nProjMethod =
     826                 :             atoi( CSVGetField( osFilename,
     827                 :                                "COORD_REF_SYS_CODE", szTRFCode, CC_Integer,
     828           23388 :                                "COORD_OP_METHOD_CODE" ) );
     829                 :     }
     830                 : 
     831           23410 :     if( nProjMethod == 0 )
     832               0 :         return FALSE;
     833                 : 
     834                 : /* -------------------------------------------------------------------- */
     835                 : /*      Get the parameters for this projection.                         */
     836                 : /* -------------------------------------------------------------------- */
     837                 : 
     838          187280 :     for( i = 0; i < 7; i++ )
     839                 :     {
     840                 :         char    szParamUOMID[32], szParamValueID[32], szParamCodeID[32];
     841                 :         char    *pszValue;
     842                 :         int     nUOM;
     843                 :         
     844          163870 :         sprintf( szParamCodeID, "PARAMETER_CODE_%d", i+1 );
     845          163870 :         sprintf( szParamUOMID, "PARAMETER_UOM_%d", i+1 );
     846          163870 :         sprintf( szParamValueID, "PARAMETER_VALUE_%d", i+1 );
     847                 : 
     848          163870 :         if( panParmIds != NULL )
     849          163870 :             panParmIds[i] = 
     850                 :                 atoi(CSVGetField( osFilename, "COORD_REF_SYS_CODE", szTRFCode,
     851          163870 :                                   CC_Integer, szParamCodeID ));
     852                 : 
     853                 :         nUOM = atoi(CSVGetField( osFilename, "COORD_REF_SYS_CODE", szTRFCode,
     854          163870 :                                  CC_Integer, szParamUOMID ));
     855                 :         pszValue = CPLStrdup(
     856                 :             CSVGetField( osFilename, "COORD_REF_SYS_CODE", szTRFCode,
     857          163870 :                          CC_Integer, szParamValueID ));
     858                 : 
     859                 :         // there is a bug in the EPSG 6.2.2 database for PCS 2935 and 2936
     860                 :         // such that they have foot units for the scale factor.  Avoid this.
     861          454826 :         if( (panParmIds[i] == NatOriginScaleFactor 
     862          145557 :              || panParmIds[i] == InitialLineScaleFactor
     863          145399 :              || panParmIds[i] == PseudoStdParallelScaleFactor) 
     864                 :             && nUOM < 9200 )
     865              24 :             nUOM = 9201;
     866                 : 
     867          219596 :         if( nUOM >= 9100 && nUOM < 9200 )
     868           55726 :             adfProjParms[i] = EPSGAngleStringToDD( pszValue, nUOM );
     869          154904 :         else if( nUOM > 9000 && nUOM < 9100 )
     870                 :         {
     871                 :             double dfInMeters;
     872                 : 
     873           46760 :             if( !EPSGGetUOMLengthInfo( nUOM, NULL, &dfInMeters ) )
     874               0 :                 dfInMeters = 1.0;
     875           46760 :             adfProjParms[i] = CPLAtof(pszValue) * dfInMeters;
     876                 :         }
     877           61384 :         else if( EQUAL(pszValue,"") ) /* null field */
     878                 :         {
     879           42581 :             adfProjParms[i] = 0.0;
     880                 :         }
     881                 :         else /* really we should consider looking up other scaling factors */
     882                 :         {
     883           18803 :             if( nUOM != 9201 )
     884                 :                 CPLDebug( "OGR", 
     885                 :                           "Non-unity scale factor units! (UOM=%d, PCS=%d)",
     886             180 :                           nUOM, nPCS );
     887           18803 :             adfProjParms[i] = CPLAtof(pszValue);
     888                 :         }
     889                 : 
     890          163870 :         CPLFree( pszValue );
     891                 :     }
     892                 : 
     893                 : /* -------------------------------------------------------------------- */
     894                 : /*      Transfer requested data into passed variables.                  */
     895                 : /* -------------------------------------------------------------------- */
     896           23410 :     if( pnProjMethod != NULL )
     897           23410 :         *pnProjMethod = nProjMethod;
     898                 : 
     899           23410 :     if( padfProjParms != NULL )
     900                 :     {
     901          187280 :         for( i = 0; i < 7; i++ )
     902          163870 :             padfProjParms[i] = adfProjParms[i];
     903                 :     }
     904                 : 
     905           23410 :     return TRUE;
     906                 : }
     907                 : 
     908                 : 
     909                 : /************************************************************************/
     910                 : /*                           EPSGGetPCSInfo()                           */
     911                 : /************************************************************************/
     912                 : 
     913                 : static int 
     914           24168 : EPSGGetPCSInfo( int nPCSCode, char **ppszEPSGName,
     915                 :                 int *pnUOMLengthCode, int *pnUOMAngleCode,
     916                 :                 int *pnGeogCS, int *pnTRFCode, int *pnCoordSysCode )
     917                 : 
     918                 : {
     919                 :     char        **papszRecord;
     920                 :     char        szSearchKey[24];
     921                 :     const char  *pszFilename;
     922                 :     
     923                 : /* -------------------------------------------------------------------- */
     924                 : /*      Search the units database for this unit.  If we don't find      */
     925                 : /*      it return failure.                                              */
     926                 : /* -------------------------------------------------------------------- */
     927           24168 :     pszFilename = CSVFilename( "pcs.csv" );
     928           24168 :     sprintf( szSearchKey, "%d", nPCSCode );
     929                 :     papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
     930           24168 :                                      szSearchKey, CC_Integer );
     931                 : 
     932           24168 :     if( papszRecord == NULL )
     933                 :     {
     934             740 :         pszFilename = CSVFilename( "pcs.override.csv" );
     935             740 :         sprintf( szSearchKey, "%d", nPCSCode );
     936                 :         papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
     937             740 :                                          szSearchKey, CC_Integer );
     938                 :         
     939                 :     }
     940                 : 
     941           24168 :     if( papszRecord == NULL )
     942             740 :         return FALSE;
     943                 : 
     944                 : /* -------------------------------------------------------------------- */
     945                 : /*      Get the name, if requested.                                     */
     946                 : /* -------------------------------------------------------------------- */
     947           23428 :     if( ppszEPSGName != NULL )
     948                 :     {
     949                 :         CPLString osPCSName = 
     950                 :             CSLGetField( papszRecord,
     951                 :                          CSVGetFileFieldId(pszFilename,
     952           23428 :                                            "COORD_REF_SYS_NAME"));
     953                 :             
     954                 :         const char *pszDeprecated = 
     955                 :             CSLGetField( papszRecord,
     956                 :                          CSVGetFileFieldId(pszFilename,
     957           23428 :                                            "DEPRECATED") );
     958                 : 
     959           23428 :         if( pszDeprecated != NULL && *pszDeprecated == '1' )
     960            1786 :             osPCSName += " (deprecated)";
     961                 : 
     962           23428 :         *ppszEPSGName = CPLStrdup(osPCSName);
     963                 :     }
     964                 : 
     965                 : /* -------------------------------------------------------------------- */
     966                 : /*      Get the UOM Length code, if requested.                          */
     967                 : /* -------------------------------------------------------------------- */
     968           23428 :     if( pnUOMLengthCode != NULL )
     969                 :     {
     970                 :         const char      *pszValue;
     971                 : 
     972                 :         pszValue =
     973                 :             CSLGetField( papszRecord,
     974           23428 :                          CSVGetFileFieldId(pszFilename,"UOM_CODE"));
     975           23428 :         if( atoi(pszValue) > 0 )
     976           23428 :             *pnUOMLengthCode = atoi(pszValue);
     977                 :         else
     978               0 :             *pnUOMLengthCode = 0;
     979                 :     }
     980                 : 
     981                 : /* -------------------------------------------------------------------- */
     982                 : /*      Get the UOM Angle code, if requested.                           */
     983                 : /* -------------------------------------------------------------------- */
     984           23428 :     if( pnUOMAngleCode != NULL )
     985                 :     {
     986                 :         const char      *pszValue;
     987                 :         
     988                 :         pszValue =
     989                 :             CSLGetField( papszRecord,
     990           23428 :                          CSVGetFileFieldId(pszFilename,"UOM_ANGLE_CODE") );
     991                 :         
     992           23428 :         if( atoi(pszValue) > 0 )
     993               0 :             *pnUOMAngleCode = atoi(pszValue);
     994                 :         else
     995           23428 :             *pnUOMAngleCode = 0;
     996                 :     }
     997                 : 
     998                 : /* -------------------------------------------------------------------- */
     999                 : /*      Get the GeogCS (Datum with PM) code, if requested.              */
    1000                 : /* -------------------------------------------------------------------- */
    1001           23428 :     if( pnGeogCS != NULL )
    1002                 :     {
    1003                 :         const char      *pszValue;
    1004                 : 
    1005                 :         pszValue =
    1006                 :             CSLGetField( papszRecord,
    1007           23428 :                          CSVGetFileFieldId(pszFilename,"SOURCE_GEOGCRS_CODE"));
    1008           23428 :         if( atoi(pszValue) > 0 )
    1009           23428 :             *pnGeogCS = atoi(pszValue);
    1010                 :         else
    1011               0 :             *pnGeogCS = 0;
    1012                 :     }
    1013                 : 
    1014                 : /* -------------------------------------------------------------------- */
    1015                 : /*      Get the GeogCS (Datum with PM) code, if requested.              */
    1016                 : /* -------------------------------------------------------------------- */
    1017           23428 :     if( pnTRFCode != NULL )
    1018                 :     {
    1019                 :         const char      *pszValue;
    1020                 : 
    1021                 :         pszValue =
    1022                 :             CSLGetField( papszRecord,
    1023           23428 :                          CSVGetFileFieldId(pszFilename,"COORD_OP_CODE"));
    1024                 :                          
    1025                 :         
    1026           23428 :         if( atoi(pszValue) > 0 )
    1027           23428 :             *pnTRFCode = atoi(pszValue);
    1028                 :         else
    1029               0 :             *pnTRFCode = 0;
    1030                 :     }
    1031                 : 
    1032                 : /* -------------------------------------------------------------------- */
    1033                 : /*      Get the CoordSysCode                                            */
    1034                 : /* -------------------------------------------------------------------- */
    1035                 :     int nCSC;
    1036                 : 
    1037                 :     nCSC = atoi(CSVGetField( pszFilename, "COORD_REF_SYS_CODE", 
    1038                 :                              szSearchKey, CC_Integer,
    1039           23428 :                              "COORD_SYS_CODE" ) );
    1040                 :     
    1041           23428 :     if( pnCoordSysCode != NULL )
    1042           23428 :         *pnCoordSysCode = nCSC;
    1043                 : 
    1044           23428 :     return TRUE;
    1045                 : }
    1046                 : 
    1047                 : /************************************************************************/
    1048                 : /*                          SetEPSGAxisInfo()                           */
    1049                 : /************************************************************************/
    1050                 : 
    1051           59404 : static OGRErr SetEPSGAxisInfo( OGRSpatialReference *poSRS, 
    1052                 :                                const char *pszTargetKey,
    1053                 :                                int nCoordSysCode )
    1054                 : 
    1055                 : {
    1056                 : /* -------------------------------------------------------------------- */
    1057                 : /*      Special cases for well known and common values.  We short       */
    1058                 : /*      circuit these to save time doing file lookups.                  */
    1059                 : /* -------------------------------------------------------------------- */
    1060                 :     // Conventional and common Easting/Northing values.
    1061           59404 :     if( nCoordSysCode >= 4400 && nCoordSysCode <= 4410 )
    1062                 :     {
    1063                 :         return 
    1064                 :             poSRS->SetAxes( pszTargetKey, 
    1065                 :                             "Easting", OAO_East, 
    1066            8129 :                             "Northing", OAO_North );
    1067                 :     }
    1068                 : 
    1069                 :     // Conventional and common Easting/Northing values.
    1070           51275 :     if( nCoordSysCode >= 6400 && nCoordSysCode <= 6423 )
    1071                 :     {
    1072                 :         return 
    1073                 :             poSRS->SetAxes( pszTargetKey, 
    1074                 :                             "Latitude", OAO_North, 
    1075           36204 :                             "Longitude", OAO_East );
    1076                 :     }
    1077                 : 
    1078                 : /* -------------------------------------------------------------------- */
    1079                 : /*      Get the definition from the coordinate_axis.csv file.           */
    1080                 : /* -------------------------------------------------------------------- */
    1081                 :     char        **papszRecord;
    1082           15071 :     char        **papszAxis1=NULL, **papszAxis2=NULL;
    1083                 :     char        szSearchKey[24];
    1084                 :     const char *pszFilename;
    1085                 : 
    1086           15071 :     pszFilename = CSVFilename( "coordinate_axis.csv" );
    1087           15071 :     sprintf( szSearchKey, "%d", nCoordSysCode );
    1088                 :     papszRecord = CSVScanFileByName( pszFilename, "COORD_SYS_CODE",
    1089           15071 :                                      szSearchKey, CC_Integer );
    1090                 : 
    1091           15071 :     if( papszRecord != NULL )
    1092                 :     {
    1093           15071 :         papszAxis1 = CSLDuplicate( papszRecord );
    1094           15071 :         papszRecord = CSVGetNextLine( pszFilename );
    1095           30142 :         if( CSLCount(papszRecord) > 0 
    1096           15071 :             && EQUAL(papszRecord[0],papszAxis1[0]) )
    1097           15071 :             papszAxis2 = CSLDuplicate( papszRecord );
    1098                 :     }
    1099                 : 
    1100           15071 :     if( papszAxis2 == NULL )
    1101                 :     {
    1102               0 :         CSLDestroy( papszAxis1 );
    1103                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1104                 :                   "Failed to find entries for COORD_SYS_CODE %d in coordinate_axis.csv", 
    1105               0 :                   nCoordSysCode );
    1106               0 :         return OGRERR_FAILURE;
    1107                 :     }
    1108                 : 
    1109                 : /* -------------------------------------------------------------------- */
    1110                 : /*      Confirm the records are complete, and work out which columns    */
    1111                 : /*      are which.                                                      */
    1112                 : /* -------------------------------------------------------------------- */
    1113                 :     int   iAxisOrientationField, iAxisAbbrevField, iAxisOrderField;
    1114                 :     int   iAxisNameCodeField;
    1115                 : 
    1116                 :     iAxisOrientationField = 
    1117           15071 :         CSVGetFileFieldId( pszFilename, "coord_axis_orientation" );
    1118                 :     iAxisAbbrevField = 
    1119           15071 :         CSVGetFileFieldId( pszFilename, "coord_axis_abbreviation" );
    1120                 :     iAxisOrderField = 
    1121           15071 :         CSVGetFileFieldId( pszFilename, "coord_axis_order" );
    1122                 :     iAxisNameCodeField = 
    1123           15071 :         CSVGetFileFieldId( pszFilename, "coord_axis_name_code" );
    1124                 : 
    1125                 :     /* Check that all fields are available and that the axis_order field */
    1126                 :     /* is the one with highest index */
    1127           15071 :     if ( !( iAxisOrientationField >= 0 &&
    1128                 :             iAxisOrientationField < iAxisOrderField &&
    1129                 :             iAxisAbbrevField >= 0 &&
    1130                 :             iAxisAbbrevField < iAxisOrderField &&
    1131                 :             iAxisOrderField >= 0 &&
    1132                 :             iAxisNameCodeField >= 0 &&
    1133                 :             iAxisNameCodeField < iAxisOrderField ) )
    1134                 :     {
    1135               0 :         CSLDestroy( papszAxis1 );
    1136               0 :         CSLDestroy( papszAxis2 );
    1137                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1138               0 :                   "coordinate_axis.csv corrupted" );
    1139               0 :         return OGRERR_FAILURE;
    1140                 :     }
    1141                 : 
    1142           15071 :     if( CSLCount(papszAxis1) < iAxisOrderField+1 
    1143                 :         || CSLCount(papszAxis2) < iAxisOrderField+1 )
    1144                 :     {
    1145               0 :         CSLDestroy( papszAxis1 );
    1146               0 :         CSLDestroy( papszAxis2 );
    1147                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1148                 :                   "Axis records appear incomplete for COORD_SYS_CODE %d in coordinate_axis.csv", 
    1149               0 :                   nCoordSysCode );
    1150               0 :         return OGRERR_FAILURE;
    1151                 :     }
    1152                 : 
    1153                 : /* -------------------------------------------------------------------- */
    1154                 : /*      Do we need to switch the axes around?                           */
    1155                 : /* -------------------------------------------------------------------- */
    1156           15071 :     if( atoi(papszAxis2[iAxisOrderField]) < atoi(papszAxis1[iAxisOrderField]) )
    1157                 :     {
    1158            7168 :         papszRecord = papszAxis1;
    1159            7168 :         papszAxis1 = papszAxis2;
    1160            7168 :         papszAxis2 = papszRecord;
    1161                 :     }
    1162                 : 
    1163                 : /* -------------------------------------------------------------------- */
    1164                 : /*      Work out axis enumeration values.                               */
    1165                 : /* -------------------------------------------------------------------- */
    1166           15071 :     OGRAxisOrientation eOAxis1 = OAO_Other, eOAxis2 = OAO_Other;
    1167                 :     int iAO;
    1168                 :     static int anCodes[7] = { -1, 9907, 9909, 9906, 9908, -1, -1 };
    1169                 : 
    1170          120568 :     for( iAO = 0; iAO < 7; iAO++ )
    1171                 :     {
    1172          105497 :         if( EQUAL(papszAxis1[iAxisOrientationField],
    1173                 :                   OSRAxisEnumToName((OGRAxisOrientation) iAO)) )
    1174           14813 :             eOAxis1 = (OGRAxisOrientation) iAO;
    1175          105497 :         if( EQUAL(papszAxis2[iAxisOrientationField],
    1176                 :                   OSRAxisEnumToName((OGRAxisOrientation) iAO)) )
    1177           14813 :             eOAxis2 = (OGRAxisOrientation) iAO;
    1178                 : 
    1179          168395 :         if( eOAxis1 == OAO_Other 
    1180           62898 :             && anCodes[iAO] == atoi(papszAxis1[iAxisNameCodeField]) )
    1181             258 :             eOAxis1 = (OGRAxisOrientation) iAO;
    1182          165455 :         if( eOAxis2 == OAO_Other 
    1183           59958 :             && anCodes[iAO] == atoi(papszAxis2[iAxisNameCodeField]) )
    1184             258 :             eOAxis2 = (OGRAxisOrientation) iAO;
    1185                 :     }
    1186                 : 
    1187                 : /* -------------------------------------------------------------------- */
    1188                 : /*      Work out the axis name.  We try to expand the abbreviation      */
    1189                 : /*      to a longer name.                                               */
    1190                 : /* -------------------------------------------------------------------- */
    1191                 :     const char *apszAxisName[2];
    1192           15071 :     apszAxisName[0] = papszAxis1[iAxisAbbrevField];
    1193           15071 :     apszAxisName[1] = papszAxis2[iAxisAbbrevField];
    1194                 : 
    1195           45213 :     for( iAO = 0; iAO < 2; iAO++ )
    1196                 :     {
    1197           30142 :         if( EQUAL(apszAxisName[iAO],"N") )
    1198            1338 :             apszAxisName[iAO] = "Northing";
    1199           28804 :         else if( EQUAL(apszAxisName[iAO],"E") )
    1200            1338 :             apszAxisName[iAO] = "Easting";
    1201           27466 :         else if( EQUAL(apszAxisName[iAO],"S") )
    1202               0 :             apszAxisName[iAO] = "Southing";
    1203           27466 :         else if( EQUAL(apszAxisName[iAO],"W") )
    1204               0 :             apszAxisName[iAO] = "Westing";
    1205                 :     }
    1206                 : 
    1207                 : /* -------------------------------------------------------------------- */
    1208                 : /*      Set the axes.                                                   */
    1209                 : /* -------------------------------------------------------------------- */
    1210                 :     OGRErr eResult;
    1211                 :     eResult = poSRS->SetAxes( pszTargetKey, 
    1212                 :                               apszAxisName[0], eOAxis1,
    1213           15071 :                               apszAxisName[1], eOAxis2 );
    1214                 : 
    1215           15071 :     CSLDestroy( papszAxis1 );
    1216           15071 :     CSLDestroy( papszAxis2 );
    1217                 :     
    1218           15071 :     return eResult;
    1219                 : }
    1220                 : 
    1221                 : /************************************************************************/
    1222                 : /*                           SetEPSGGeogCS()                            */
    1223                 : /*                                                                      */
    1224                 : /*      FLAWS:                                                          */
    1225                 : /*       o Units are all hardcoded.                                     */
    1226                 : /************************************************************************/
    1227                 : 
    1228           60382 : static OGRErr SetEPSGGeogCS( OGRSpatialReference * poSRS, int nGeogCS )
    1229                 : 
    1230                 : {
    1231                 :     int  nDatumCode, nPMCode, nUOMAngle, nEllipsoidCode, nCSC;
    1232           60382 :     char *pszGeogCSName = NULL, *pszDatumName = NULL, *pszEllipsoidName = NULL;
    1233           60382 :     char *pszPMName = NULL, *pszAngleName = NULL;
    1234                 :     double dfPMOffset, dfSemiMajor, dfInvFlattening, adfBursaTransform[7];
    1235                 :     double dfAngleInDegrees, dfAngleInRadians;
    1236                 : 
    1237           60382 :     if( !EPSGGetGCSInfo( nGeogCS, &pszGeogCSName,
    1238                 :                          &nDatumCode, &pszDatumName, 
    1239                 :                          &nPMCode, &nEllipsoidCode, &nUOMAngle, &nCSC ) )
    1240           24178 :         return OGRERR_UNSUPPORTED_SRS;
    1241                 : 
    1242           36204 :     if( !EPSGGetPMInfo( nPMCode, &pszPMName, &dfPMOffset ) )
    1243                 :     {
    1244               0 :         CPLFree( pszDatumName );
    1245               0 :         CPLFree( pszGeogCSName );
    1246               0 :         return OGRERR_UNSUPPORTED_SRS;
    1247                 :     }
    1248                 : 
    1249           36204 :     OGREPSGDatumNameMassage( &pszDatumName );
    1250                 : 
    1251           36204 :     if( OSRGetEllipsoidInfo( nEllipsoidCode, &pszEllipsoidName, 
    1252                 :                              &dfSemiMajor, &dfInvFlattening ) != OGRERR_NONE )
    1253                 :     {
    1254               0 :         CPLFree( pszDatumName );
    1255               0 :         CPLFree( pszGeogCSName );
    1256               0 :         CPLFree( pszPMName );
    1257               0 :         return OGRERR_UNSUPPORTED_SRS;
    1258                 :     }
    1259                 : 
    1260           36204 :     if( !EPSGGetUOMAngleInfo( nUOMAngle, &pszAngleName, &dfAngleInDegrees ) )
    1261                 :     {
    1262               0 :         pszAngleName = CPLStrdup("degree");
    1263               0 :         dfAngleInDegrees = 1.0;
    1264               0 :         nUOMAngle = -1;
    1265                 :     }
    1266                 : 
    1267           36204 :     if( dfAngleInDegrees == 1.0 )
    1268           35926 :         dfAngleInRadians = CPLAtof(SRS_UA_DEGREE_CONV);
    1269                 :     else
    1270             278 :         dfAngleInRadians = CPLAtof(SRS_UA_DEGREE_CONV) * dfAngleInDegrees;
    1271                 : 
    1272                 :     poSRS->SetGeogCS( pszGeogCSName, pszDatumName, 
    1273                 :                       pszEllipsoidName, dfSemiMajor, dfInvFlattening,
    1274                 :                       pszPMName, dfPMOffset,
    1275           36204 :                       pszAngleName, dfAngleInRadians );
    1276                 : 
    1277           36204 :     if( EPSGGetWGS84Transform( nGeogCS, adfBursaTransform ) )
    1278                 :     {
    1279                 :         OGR_SRSNode     *poWGS84;
    1280                 :         char            szValue[100];
    1281                 : 
    1282           27476 :         poWGS84 = new OGR_SRSNode( "TOWGS84" );
    1283                 : 
    1284          439616 :         for( int iCoeff = 0; iCoeff < 7; iCoeff++ )
    1285                 :         {
    1286          192332 :             sprintf( szValue, "%g", adfBursaTransform[iCoeff] );
    1287          192332 :             poWGS84->AddChild( new OGR_SRSNode( szValue ) );
    1288                 :         }
    1289                 : 
    1290           27476 :         poSRS->GetAttrNode( "DATUM" )->AddChild( poWGS84 );
    1291                 :     }
    1292                 : 
    1293           36204 :     poSRS->SetAuthority( "GEOGCS", "EPSG", nGeogCS );
    1294           36204 :     poSRS->SetAuthority( "DATUM", "EPSG", nDatumCode );
    1295           36204 :     poSRS->SetAuthority( "SPHEROID", "EPSG", nEllipsoidCode );
    1296           36204 :     poSRS->SetAuthority( "PRIMEM", "EPSG", nPMCode );
    1297                 : 
    1298           36204 :     if( nUOMAngle > 0 )
    1299           36204 :         poSRS->SetAuthority( "GEOGCS|UNIT", "EPSG", nUOMAngle );
    1300                 : 
    1301           36204 :     CPLFree( pszAngleName );
    1302           36204 :     CPLFree( pszDatumName );
    1303           36204 :     CPLFree( pszEllipsoidName );
    1304           36204 :     CPLFree( pszGeogCSName );
    1305           36204 :     CPLFree( pszPMName );
    1306                 : 
    1307                 : /* -------------------------------------------------------------------- */
    1308                 : /*      Set axes                                                        */
    1309                 : /* -------------------------------------------------------------------- */
    1310           36204 :     if( nCSC > 0 )
    1311                 :     {
    1312           36204 :         SetEPSGAxisInfo( poSRS, "GEOGCS", nCSC );
    1313           36204 :         CPLErrorReset();
    1314                 :     }
    1315                 : 
    1316           36204 :     return OGRERR_NONE;
    1317                 : }
    1318                 : 
    1319                 : /************************************************************************/
    1320                 : /*                           OGR_FetchParm()                            */
    1321                 : /*                                                                      */
    1322                 : /*      Fetch a parameter from the parm list, based on it's EPSG        */
    1323                 : /*      parameter code.                                                 */
    1324                 : /************************************************************************/
    1325                 : 
    1326          120372 : static double OGR_FetchParm( double *padfProjParms, int *panParmIds, 
    1327                 :                              int nTargetId, double dfFromGreenwich )
    1328                 : 
    1329                 : {
    1330                 :     int i;
    1331                 :     double dfResult;
    1332                 : 
    1333                 : /* -------------------------------------------------------------------- */
    1334                 : /*      Set default in meters/degrees.                                  */
    1335                 : /* -------------------------------------------------------------------- */
    1336          120372 :     switch( nTargetId )
    1337                 :     {
    1338                 :       case NatOriginScaleFactor:
    1339                 :       case InitialLineScaleFactor:
    1340                 :       case PseudoStdParallelScaleFactor:
    1341           18556 :         dfResult = 1.0;
    1342           18556 :         break;
    1343                 :         
    1344                 :       case AngleRectifiedToSkewedGrid:
    1345             158 :         dfResult = 90.0;
    1346             158 :         break;
    1347                 : 
    1348                 :       default:
    1349          101658 :         dfResult = 0.0;
    1350                 :     }
    1351                 : 
    1352                 : /* -------------------------------------------------------------------- */
    1353                 : /*      Try to find actual value in parameter list.                     */
    1354                 : /* -------------------------------------------------------------------- */
    1355          377295 :     for( i = 0; i < 7; i++ )
    1356                 :     {
    1357          376774 :         if( panParmIds[i] == nTargetId )
    1358                 :         {
    1359          119851 :             dfResult = padfProjParms[i];
    1360          119851 :             break;
    1361                 :         }
    1362                 :     }
    1363                 : 
    1364                 : /* -------------------------------------------------------------------- */
    1365                 : /*      EPSG longitudes are relative to greenwich.  The follow code     */
    1366                 : /*      could be used to make them relative to the prime meridian of    */
    1367                 : /*      the associated GCS if that was appropriate.  However, the       */
    1368                 : /*      SetNormProjParm() method expects longitudes relative to         */
    1369                 : /*      greenwich, so there is nothing for us to do.                    */
    1370                 : /* -------------------------------------------------------------------- */
    1371                 : #ifdef notdef
    1372                 :     switch( nTargetId )
    1373                 :     {
    1374                 :       case NatOriginLong:
    1375                 :       case ProjCenterLong:
    1376                 :       case FalseOriginLong:
    1377                 :       case SphericalOriginLong:
    1378                 :       case InitialLongitude:
    1379                 :         // Note that the EPSG values are already relative to greenwich.
    1380                 :         // This shift is really making it relative to the provided prime
    1381                 :         // meridian, so that when SetTM() and company the correction back
    1382                 :         // ends up back relative to greenwich.
    1383                 :         dfResult = dfResult + dfFromGreenwich;
    1384                 :         break;
    1385                 : 
    1386                 :       default:
    1387                 :         ;
    1388                 :     }
    1389                 : #endif
    1390                 : 
    1391          120372 :     return dfResult;
    1392                 : }
    1393                 : 
    1394                 : #define OGR_FP(x) OGR_FetchParm( adfProjParms, anParmIds, (x), \
    1395                 :                                  dfFromGreenwich )
    1396                 : 
    1397                 : /************************************************************************/
    1398                 : /*                           SetEPSGProjCS()                            */
    1399                 : /************************************************************************/
    1400                 : 
    1401           24168 : static OGRErr SetEPSGProjCS( OGRSpatialReference * poSRS, int nPCSCode )
    1402                 : 
    1403                 : {
    1404           24168 :     int         nGCSCode, nUOMAngleCode, nUOMLength, nTRFCode, nProjMethod=0;
    1405           24168 :     int         anParmIds[7], nCSC = 0;
    1406           24168 :     char        *pszPCSName = NULL, *pszUOMLengthName = NULL;
    1407                 :     double      adfProjParms[7], dfInMeters, dfFromGreenwich;
    1408                 :     OGRErr      nErr;
    1409                 :     OGR_SRSNode *poNode;
    1410                 : 
    1411           24168 :     if( !EPSGGetPCSInfo( nPCSCode, &pszPCSName, &nUOMLength, &nUOMAngleCode,
    1412                 :                          &nGCSCode, &nTRFCode, &nCSC ) )
    1413                 :     {
    1414             740 :         CPLFree(pszPCSName);
    1415             740 :         return OGRERR_UNSUPPORTED_SRS;
    1416                 :     }
    1417                 : 
    1418           23428 :     poSRS->SetNode( "PROJCS", pszPCSName );
    1419                 :     
    1420                 : /* -------------------------------------------------------------------- */
    1421                 : /*      Set GEOGCS.                                                     */
    1422                 : /* -------------------------------------------------------------------- */
    1423           23428 :     nErr = SetEPSGGeogCS( poSRS, nGCSCode );
    1424           23428 :     if( nErr != OGRERR_NONE )
    1425                 :     {
    1426              18 :         CPLFree(pszPCSName);
    1427              18 :         return nErr;
    1428                 :     }
    1429                 : 
    1430           23410 :     dfFromGreenwich = poSRS->GetPrimeMeridian();
    1431                 : 
    1432                 : /* -------------------------------------------------------------------- */
    1433                 : /*      Set linear units.                                               */
    1434                 : /* -------------------------------------------------------------------- */
    1435           23410 :     if( !EPSGGetUOMLengthInfo( nUOMLength, &pszUOMLengthName, &dfInMeters ) )
    1436                 :     {
    1437               0 :         CPLFree(pszPCSName);
    1438               0 :         return OGRERR_UNSUPPORTED_SRS;
    1439                 :     }
    1440                 : 
    1441           23410 :     poSRS->SetLinearUnits( pszUOMLengthName, dfInMeters );
    1442           23410 :     poSRS->SetAuthority( "PROJCS|UNIT", "EPSG", nUOMLength );
    1443                 : 
    1444           23410 :     CPLFree( pszUOMLengthName );
    1445           23410 :     CPLFree( pszPCSName );
    1446                 : 
    1447                 : /* -------------------------------------------------------------------- */
    1448                 : /*      Set projection and parameters.                                  */
    1449                 : /* -------------------------------------------------------------------- */
    1450           23410 :     if( !EPSGGetProjTRFInfo( nPCSCode, &nProjMethod, anParmIds, adfProjParms ))
    1451               0 :         return OGRERR_UNSUPPORTED_SRS;
    1452                 : 
    1453           23410 :     switch( nProjMethod )
    1454                 :     {
    1455                 :       case 9801:
    1456                 :       case 9817: /* really LCC near conformal */
    1457                 :         poSRS->SetLCC1SP( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1458                 :                           OGR_FP( NatOriginScaleFactor ), 
    1459             468 :                           OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1460             468 :         break;
    1461                 : 
    1462                 :       case 9802:
    1463                 :         poSRS->SetLCC( OGR_FP( StdParallel1Lat ), OGR_FP( StdParallel2Lat ),
    1464                 :                        OGR_FP( FalseOriginLat ), OGR_FP( FalseOriginLong ),
    1465                 :                        OGR_FP( FalseOriginEasting ), 
    1466            4006 :                        OGR_FP( FalseOriginNorthing ));
    1467            4006 :         break;
    1468                 : 
    1469                 :       case 9803:
    1470                 :         poSRS->SetLCCB( OGR_FP( StdParallel1Lat ), OGR_FP( StdParallel2Lat ),
    1471                 :                         OGR_FP( FalseOriginLat ), OGR_FP( FalseOriginLong ),
    1472                 :                         OGR_FP( FalseOriginEasting ), 
    1473               6 :                         OGR_FP( FalseOriginNorthing ));
    1474               6 :         break;
    1475                 : 
    1476                 :       case 9805:
    1477                 :         poSRS->SetMercator2SP( OGR_FP( StdParallel1Lat ),
    1478                 :                                OGR_FP( NatOriginLat ), OGR_FP(NatOriginLong),
    1479              12 :                                OGR_FP( FalseEasting ), OGR_FP(FalseNorthing) );
    1480                 : 
    1481              12 :         break;
    1482                 : 
    1483                 :       case 9804:
    1484                 :       case 9841: /* Mercator 1SP (Spherical) */
    1485                 :       case 1024: /* Google Mercator */
    1486                 :         poSRS->SetMercator( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1487                 :                             OGR_FP( NatOriginScaleFactor ), 
    1488             175 :                             OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1489                 : 
    1490             175 :         if( nProjMethod == 1024 || nProjMethod == 9841 ) // override hack for google mercator.
    1491                 :         {
    1492                 :             poSRS->SetExtension( "PROJCS", "PROJ4", 
    1493              87 :                                  "+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" );
    1494                 :         }
    1495             175 :         break;
    1496                 : 
    1497                 :       case 9806:
    1498                 :         poSRS->SetCS( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1499             126 :                             OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1500             126 :         break;
    1501                 : 
    1502                 :       case 9807:
    1503                 :         poSRS->SetTM( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1504                 :                       OGR_FP( NatOriginScaleFactor ), 
    1505           17265 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1506           17265 :         break;
    1507                 :         
    1508                 :       case 9808:
    1509                 :         poSRS->SetTMSO( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1510                 :                         OGR_FP( NatOriginScaleFactor ), 
    1511             174 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1512             174 :         break;
    1513                 :         
    1514                 :       case 9809:
    1515                 :         poSRS->SetOS( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1516                 :                       OGR_FP( NatOriginScaleFactor ), 
    1517             140 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1518             140 :         break;
    1519                 : 
    1520                 :       case 9810:
    1521                 :         poSRS->SetPS( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1522                 :                       OGR_FP( NatOriginScaleFactor ), 
    1523              36 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1524              36 :         break;
    1525                 : 
    1526                 :       case 9811:
    1527                 :         poSRS->SetNZMG( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1528              12 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1529              12 :         break;
    1530                 : 
    1531                 :       case 9812:
    1532                 :       case 9813:
    1533                 :         poSRS->SetHOM( OGR_FP( ProjCenterLat ), OGR_FP( ProjCenterLong ),
    1534                 :                        OGR_FP( Azimuth ), 
    1535                 :                        OGR_FP( AngleRectifiedToSkewedGrid ),
    1536                 :                        OGR_FP( InitialLineScaleFactor ),
    1537              78 :                        OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1538                 : 
    1539              78 :         poNode = poSRS->GetAttrNode( "PROJECTION" )->GetChild( 0 );
    1540              78 :         if( nProjMethod == 9813 )
    1541               6 :             poNode->SetValue( SRS_PT_LABORDE_OBLIQUE_MERCATOR );
    1542              78 :         break;
    1543                 : 
    1544                 :       case 9814:
    1545                 :         /* NOTE: This is no longer used!  Swiss Oblique Mercator gets
    1546                 :         ** implemented using 9815 instead.  
    1547                 :         */
    1548                 :         poSRS->SetSOC( OGR_FP( ProjCenterLat ), OGR_FP( ProjCenterLong ),
    1549               0 :                        OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1550               0 :         break;
    1551                 : 
    1552                 :       case 9815:
    1553                 :         poSRS->SetHOMAC( OGR_FP( ProjCenterLat ), OGR_FP( ProjCenterLong ),
    1554                 :                          OGR_FP( Azimuth ), 
    1555                 :                          OGR_FP( AngleRectifiedToSkewedGrid ),
    1556                 :                          OGR_FP( InitialLineScaleFactor ),
    1557                 :                          OGR_FP( ProjCenterEasting ), 
    1558              80 :                          OGR_FP( ProjCenterNorthing ) );
    1559              80 :         break;
    1560                 : 
    1561                 :       case 9816:
    1562                 :         poSRS->SetTMG( OGR_FP( FalseOriginLat ), OGR_FP( FalseOriginLong ),
    1563                 :                        OGR_FP( FalseOriginEasting ), 
    1564               6 :                        OGR_FP( FalseOriginNorthing ) );
    1565               6 :         break;
    1566                 : 
    1567                 :       case 9818:
    1568                 :         poSRS->SetPolyconic( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1569              30 :                              OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1570              30 :         break;
    1571                 : 
    1572                 :       case 9819:
    1573                 :       {
    1574             140 :           double dfCenterLong = OGR_FP( ProjCenterLong );
    1575                 : 
    1576             140 :           if( dfCenterLong == 0.0 ) // See ticket #2559
    1577             140 :               dfCenterLong = OGR_FP( PolarLongOrigin );
    1578                 : 
    1579             140 :           double dfAzimuth = OGR_FP( CoLatConeAxis ); // See ticket #4223
    1580             140 :           if( dfAzimuth == 0.0 ) 
    1581               0 :               dfAzimuth = OGR_FP( Azimuth );
    1582                 : 
    1583                 :           poSRS->SetKrovak( OGR_FP( ProjCenterLat ), dfCenterLong,
    1584                 :                             dfAzimuth, 
    1585                 :                             OGR_FP( PseudoStdParallelLat ),
    1586                 :                             OGR_FP( PseudoStdParallelScaleFactor ),
    1587                 :                             OGR_FP( ProjCenterEasting ), 
    1588             140 :                             OGR_FP( ProjCenterNorthing ) );
    1589                 :       }
    1590             140 :       break;
    1591                 : 
    1592                 :       case 9820:
    1593                 :       case 1027: /* used by EPSG:2163, 3408, 3409, 3973 and 3974 */
    1594                 :         poSRS->SetLAEA( OGR_FP( NatOriginLat ), OGR_FP( NatOriginLong ),
    1595              78 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1596              78 :         break;
    1597                 : 
    1598                 :       case 9821: /* DEPREACTED : this is the spherical form, and really needs different
    1599                 :                     equations which give different results but PROJ.4 doesn't
    1600                 :                     seem to support the spherical form. */
    1601                 :         poSRS->SetLAEA( OGR_FP( SphericalOriginLat ),
    1602                 :                         OGR_FP( SphericalOriginLong ),
    1603               0 :                         OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1604               0 :         break;
    1605                 : 
    1606                 :       case 9822: /* Albers (Conic) Equal Area */
    1607                 :         poSRS->SetACEA( OGR_FP( StdParallel1Lat ), 
    1608                 :                         OGR_FP( StdParallel2Lat ), 
    1609                 :                         OGR_FP( FalseOriginLat ),
    1610                 :                         OGR_FP( FalseOriginLong ),
    1611                 :                         OGR_FP( FalseOriginEasting ),
    1612             152 :                         OGR_FP( FalseOriginNorthing ) );
    1613             152 :         break;
    1614                 : 
    1615                 :       case 9823: /* Equidistant Cylindrical / Plate Carre / Equirectangular */
    1616                 :       case 1028:
    1617                 :       case 1029:
    1618                 :         poSRS->SetEquirectangular( OGR_FP( NatOriginLat ),
    1619                 :                                    OGR_FP( NatOriginLong ), 
    1620              30 :                                    0.0, 0.0 );
    1621              30 :         break;
    1622                 : 
    1623                 :       case 9829: /* Polar Stereographic (Variant B) */
    1624                 :         poSRS->SetPS( OGR_FP( PolarLatStdParallel ), OGR_FP(PolarLongOrigin),
    1625                 :                       1.0,
    1626             168 :                       OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1627             168 :         break;
    1628                 : 
    1629                 :       case 9834: /* Lambert Cylindrical Equal Area (Spherical) bug #2659 */
    1630                 :         poSRS->SetCEA( OGR_FP( StdParallel1Lat ), OGR_FP( NatOriginLong ), 
    1631              18 :                        OGR_FP( FalseEasting ), OGR_FP( FalseNorthing ) );
    1632              18 :         break;
    1633                 : 
    1634                 :       default:
    1635                 :         CPLDebug( "EPSG", "No WKT support for projection method %d.",
    1636             210 :                   nProjMethod );
    1637             210 :         return OGRERR_UNSUPPORTED_SRS;
    1638                 :     }
    1639                 : 
    1640                 : /* -------------------------------------------------------------------- */
    1641                 : /*      Set overall PCS authority code.                                 */
    1642                 : /* -------------------------------------------------------------------- */
    1643           23200 :     poSRS->SetAuthority( "PROJCS", "EPSG", nPCSCode );
    1644                 : 
    1645                 : /* -------------------------------------------------------------------- */
    1646                 : /*      Set axes                                                        */
    1647                 : /* -------------------------------------------------------------------- */
    1648           23200 :     if( nCSC > 0 )
    1649                 :     {
    1650           23200 :         SetEPSGAxisInfo( poSRS, "PROJCS", nCSC );
    1651           23200 :         CPLErrorReset();
    1652                 :     }
    1653                 : 
    1654           23200 :     return OGRERR_NONE;
    1655                 : }
    1656                 : 
    1657                 : /************************************************************************/
    1658                 : /*                           SetEPSGVertCS()                            */
    1659                 : /************************************************************************/
    1660                 : 
    1661             974 : static OGRErr SetEPSGVertCS( OGRSpatialReference * poSRS, int nVertCSCode )
    1662                 : 
    1663                 : {
    1664                 : /* -------------------------------------------------------------------- */
    1665                 : /*      Fetch record from the vertcs.csv or override file.              */
    1666                 : /* -------------------------------------------------------------------- */
    1667                 :     char        **papszRecord;
    1668                 :     char        szSearchKey[24];
    1669                 :     const char  *pszFilename;
    1670                 :     
    1671             974 :     pszFilename = CSVFilename( "vertcs.override.csv" );
    1672             974 :     sprintf( szSearchKey, "%d", nVertCSCode );
    1673                 :     papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
    1674             974 :                                      szSearchKey, CC_Integer );
    1675                 : 
    1676             974 :     if( papszRecord == NULL )
    1677                 :     {
    1678             970 :         pszFilename = CSVFilename( "vertcs.csv" );
    1679                 :         papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
    1680             970 :                                          szSearchKey, CC_Integer );
    1681                 :         
    1682                 :     }
    1683                 : 
    1684             974 :     if( papszRecord == NULL )
    1685             958 :         return OGRERR_UNSUPPORTED_SRS;
    1686                 : 
    1687                 : 
    1688                 : /* -------------------------------------------------------------------- */
    1689                 : /*      Setup the basic VERT_CS.                                        */
    1690                 : /* -------------------------------------------------------------------- */
    1691                 :     poSRS->SetVertCS( 
    1692                 :         CSLGetField( papszRecord,
    1693                 :                      CSVGetFileFieldId(pszFilename,
    1694                 :                                        "COORD_REF_SYS_NAME")),
    1695                 :         CSLGetField( papszRecord,
    1696                 :                      CSVGetFileFieldId(pszFilename,
    1697              16 :                                        "DATUM_NAME")) );
    1698                 : /* -------------------------------------------------------------------- */
    1699                 : /*      Setup the VERT_DATUM node.                                      */
    1700                 : /* -------------------------------------------------------------------- */
    1701                 :     poSRS->SetAuthority( "VERT_CS|VERT_DATUM", "EPSG",
    1702                 :                          atoi(CSLGetField( papszRecord,
    1703                 :                                            CSVGetFileFieldId(pszFilename,
    1704              16 :                                                              "DATUM_CODE"))) );
    1705                 : 
    1706                 : /* -------------------------------------------------------------------- */
    1707                 : /*      Should we add a geoidgrids extension node?                      */
    1708                 : /* -------------------------------------------------------------------- */
    1709                 :     const char *pszMethod = 
    1710                 :         CSLGetField( papszRecord, 
    1711              16 :                      CSVGetFileFieldId(pszFilename,"COORD_OP_METHOD_CODE_1"));
    1712              16 :     if( pszMethod && EQUAL(pszMethod,"9665") )
    1713                 :     {
    1714                 :         const char *pszParm11 = 
    1715                 :             CSLGetField( papszRecord, 
    1716               4 :                          CSVGetFileFieldId(pszFilename,"PARM_1_1"));
    1717                 : 
    1718               4 :         poSRS->SetExtension( "VERT_CS|VERT_DATUM", "PROJ4_GRIDS", pszParm11 );
    1719                 :     }
    1720                 :     
    1721                 : /* -------------------------------------------------------------------- */
    1722                 : /*      Set linear units.                                               */
    1723                 : /* -------------------------------------------------------------------- */
    1724              16 :     char *pszUOMLengthName = NULL;
    1725                 :     double dfInMeters;
    1726                 :     int nUOM_CODE = atoi(CSLGetField( papszRecord,
    1727                 :                                       CSVGetFileFieldId(pszFilename,
    1728              16 :                                                         "UOM_CODE")));
    1729                 : 
    1730              16 :     if( !EPSGGetUOMLengthInfo( nUOM_CODE, &pszUOMLengthName, &dfInMeters ) )
    1731                 :     {
    1732                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1733               0 :                   "Failed to lookup UOM CODE %d", nUOM_CODE );
    1734                 :     }
    1735                 :     else
    1736                 :     {
    1737              16 :         poSRS->SetTargetLinearUnits( "VERT_CS", pszUOMLengthName, dfInMeters );
    1738              16 :         poSRS->SetAuthority( "VERT_CS|UNIT", "EPSG", nUOM_CODE );
    1739                 : 
    1740              16 :         CPLFree( pszUOMLengthName );
    1741                 :     }
    1742                 : 
    1743                 : /* -------------------------------------------------------------------- */
    1744                 : /*      Set overall authority code.                                     */
    1745                 : /* -------------------------------------------------------------------- */
    1746              16 :     poSRS->SetAuthority( "VERT_CS", "EPSG", nVertCSCode );
    1747                 : 
    1748              16 :     return OGRERR_NONE;
    1749                 : }
    1750                 : 
    1751                 : /************************************************************************/
    1752                 : /*                           SetEPSGCompdCS()                           */
    1753                 : /************************************************************************/
    1754                 : 
    1755             958 : static OGRErr SetEPSGCompdCS( OGRSpatialReference * poSRS, int nCCSCode )
    1756                 : 
    1757                 : {
    1758                 : /* -------------------------------------------------------------------- */
    1759                 : /*      Fetch record from the compdcs.csv or override file.             */
    1760                 : /* -------------------------------------------------------------------- */
    1761             958 :     char        **papszRecord = NULL;
    1762                 :     char        szSearchKey[24];
    1763                 :     const char  *pszFilename;
    1764                 :     
    1765             958 :     sprintf( szSearchKey, "%d", nCCSCode );
    1766                 : 
    1767                 : // So far no override file needed.    
    1768                 : //    pszFilename = CSVFilename( "compdcs.override.csv" );
    1769                 : //    papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
    1770                 : //                                     szSearchKey, CC_Integer );
    1771                 : 
    1772                 :     //if( papszRecord == NULL )
    1773                 :     {
    1774             958 :         pszFilename = CSVFilename( "compdcs.csv" );
    1775                 :         papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
    1776             958 :                                          szSearchKey, CC_Integer );
    1777                 :         
    1778                 :     }
    1779                 : 
    1780             958 :     if( papszRecord == NULL )
    1781             950 :         return OGRERR_UNSUPPORTED_SRS;
    1782                 : 
    1783                 : /* -------------------------------------------------------------------- */
    1784                 : /*      Fetch subinformation now before anything messes with the        */
    1785                 : /*      last loaded record.                                             */
    1786                 : /* -------------------------------------------------------------------- */
    1787                 :     int nPCSCode = atoi(CSLGetField( papszRecord,
    1788                 :                                      CSVGetFileFieldId(pszFilename,
    1789               8 :                                                        "CMPD_HORIZCRS_CODE")));
    1790                 :     int nVertCSCode = atoi(CSLGetField( papszRecord,
    1791                 :                                         CSVGetFileFieldId(pszFilename,
    1792               8 :                                                           "CMPD_VERTCRS_CODE")));
    1793                 : 
    1794                 : /* -------------------------------------------------------------------- */
    1795                 : /*      Set the COMPD_CS node with a name.                              */
    1796                 : /* -------------------------------------------------------------------- */
    1797                 :     poSRS->SetNode( "COMPD_CS", 
    1798                 :                     CSLGetField( papszRecord,
    1799                 :                                  CSVGetFileFieldId(pszFilename,
    1800               8 :                                                    "COORD_REF_SYS_NAME")) );
    1801                 : 
    1802                 : /* -------------------------------------------------------------------- */
    1803                 : /*      Lookup the the projected coordinate system.  Can the            */
    1804                 : /*      horizontal CRS be a GCS?                                        */
    1805                 : /* -------------------------------------------------------------------- */
    1806               8 :     OGRSpatialReference oPCS;
    1807                 :     OGRErr eErr;
    1808                 : 
    1809               8 :     eErr = SetEPSGProjCS( &oPCS, nPCSCode );
    1810               8 :     if( eErr != OGRERR_NONE )
    1811                 :     {
    1812                 :         // perhaps it is a GCS?
    1813               2 :         eErr = SetEPSGGeogCS( &oPCS, nPCSCode );
    1814                 :     }
    1815                 : 
    1816               8 :     if( eErr != OGRERR_NONE )
    1817                 :     {
    1818               0 :         return eErr;
    1819                 :     }
    1820                 : 
    1821                 :     poSRS->GetRoot()->AddChild( 
    1822               8 :         oPCS.GetRoot()->Clone() );
    1823                 : 
    1824                 : /* -------------------------------------------------------------------- */
    1825                 : /*      Lookup the VertCS.                                              */
    1826                 : /* -------------------------------------------------------------------- */
    1827               8 :     OGRSpatialReference oVertCS;
    1828               8 :     eErr = SetEPSGVertCS( &oVertCS, nVertCSCode );
    1829               8 :     if( eErr != OGRERR_NONE )
    1830               0 :         return eErr;
    1831                 : 
    1832                 :     poSRS->GetRoot()->AddChild( 
    1833               8 :         oVertCS.GetRoot()->Clone() );
    1834                 : 
    1835                 : /* -------------------------------------------------------------------- */
    1836                 : /*      Set overall authority code.                                     */
    1837                 : /* -------------------------------------------------------------------- */
    1838               8 :     poSRS->SetAuthority( "COMPD_CS", "EPSG", nCCSCode );
    1839                 : 
    1840               8 :     return OGRERR_NONE;
    1841                 : }
    1842                 : 
    1843                 : /************************************************************************/
    1844                 : /*                           SetEPSGGeocCS()                            */
    1845                 : /************************************************************************/
    1846                 : 
    1847             950 : static OGRErr SetEPSGGeocCS( OGRSpatialReference * poSRS, int nGCSCode )
    1848                 : 
    1849                 : {
    1850                 : /* -------------------------------------------------------------------- */
    1851                 : /*      Fetch record from the geoccs.csv or override file.              */
    1852                 : /* -------------------------------------------------------------------- */
    1853             950 :     char        **papszRecord = NULL;
    1854                 :     char        szSearchKey[24];
    1855                 :     const char  *pszFilename;
    1856                 :     
    1857             950 :     sprintf( szSearchKey, "%d", nGCSCode );
    1858                 : 
    1859                 : // So far no override file needed.    
    1860                 : //    pszFilename = CSVFilename( "compdcs.override.csv" );
    1861                 : //    papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
    1862                 : //                                     szSearchKey, CC_Integer );
    1863                 : 
    1864                 :     //if( papszRecord == NULL )
    1865                 :     {
    1866             950 :         pszFilename = CSVFilename( "geoccs.csv" );
    1867                 :         papszRecord = CSVScanFileByName( pszFilename, "COORD_REF_SYS_CODE",
    1868             950 :                                          szSearchKey, CC_Integer );
    1869                 :         
    1870                 :     }
    1871                 : 
    1872             950 :     if( papszRecord == NULL )
    1873             946 :         return OGRERR_UNSUPPORTED_SRS;
    1874                 : 
    1875                 : /* -------------------------------------------------------------------- */
    1876                 : /*      Set the GEOCCS node with a name.                                */
    1877                 : /* -------------------------------------------------------------------- */
    1878               4 :     poSRS->Clear();
    1879                 :     poSRS->SetGeocCS( CSLGetField( papszRecord,
    1880                 :                                    CSVGetFileFieldId(pszFilename,
    1881               4 :                                                      "COORD_REF_SYS_NAME")) );
    1882                 : 
    1883                 : /* -------------------------------------------------------------------- */
    1884                 : /*      Get datum related information.                                  */
    1885                 : /* -------------------------------------------------------------------- */
    1886                 :     int nDatumCode, nEllipsoidCode, nPMCode;
    1887                 :     char *pszDatumName;
    1888                 :     
    1889                 :     nDatumCode = atoi(CSLGetField( papszRecord,
    1890                 :                                    CSVGetFileFieldId(pszFilename,
    1891               4 :                                                      "DATUM_CODE")));
    1892                 :     
    1893                 :     pszDatumName = 
    1894                 :         CPLStrdup( CSLGetField( papszRecord,
    1895               4 :                                 CSVGetFileFieldId(pszFilename,"DATUM_NAME") ) );
    1896               4 :     OGREPSGDatumNameMassage( &pszDatumName );
    1897                 : 
    1898                 : 
    1899                 :     nEllipsoidCode = atoi(CSLGetField( papszRecord,
    1900                 :                                    CSVGetFileFieldId(pszFilename,
    1901               4 :                                                      "ELLIPSOID_CODE")));
    1902                 :     
    1903                 :     nPMCode = atoi(CSLGetField( papszRecord,
    1904                 :                                 CSVGetFileFieldId(pszFilename,
    1905               4 :                                                   "PRIME_MERIDIAN_CODE")));
    1906                 :     
    1907                 : /* -------------------------------------------------------------------- */
    1908                 : /*      Get prime meridian information.                                 */
    1909                 : /* -------------------------------------------------------------------- */
    1910               4 :     char *pszPMName = NULL;
    1911               4 :     double dfPMOffset = 0.0;
    1912                 : 
    1913               4 :     if( !EPSGGetPMInfo( nPMCode, &pszPMName, &dfPMOffset ) )
    1914                 :     {
    1915               0 :         CPLFree( pszDatumName );
    1916               0 :         return OGRERR_UNSUPPORTED_SRS;
    1917                 :     }
    1918                 : 
    1919                 : /* -------------------------------------------------------------------- */
    1920                 : /*      Get the ellipsoid information.                                  */
    1921                 : /* -------------------------------------------------------------------- */
    1922               4 :     char *pszEllipsoidName = NULL;
    1923                 :     double dfSemiMajor, dfInvFlattening; 
    1924                 : 
    1925               4 :     if( OSRGetEllipsoidInfo( nEllipsoidCode, &pszEllipsoidName, 
    1926                 :                              &dfSemiMajor, &dfInvFlattening ) != OGRERR_NONE )
    1927                 :     {
    1928               0 :         CPLFree( pszDatumName );
    1929               0 :         CPLFree( pszPMName );
    1930               0 :         return OGRERR_UNSUPPORTED_SRS;
    1931                 :     }
    1932                 : 
    1933                 : /* -------------------------------------------------------------------- */
    1934                 : /*      Setup the spheroid.                                             */
    1935                 : /* -------------------------------------------------------------------- */
    1936                 :     char                szValue[128];
    1937                 : 
    1938               4 :     OGR_SRSNode *poSpheroid = new OGR_SRSNode( "SPHEROID" );
    1939               8 :     poSpheroid->AddChild( new OGR_SRSNode( pszEllipsoidName ) );
    1940                 : 
    1941               4 :     OGRPrintDouble( szValue, dfSemiMajor );
    1942               8 :     poSpheroid->AddChild( new OGR_SRSNode(szValue) );
    1943                 : 
    1944               4 :     OGRPrintDouble( szValue, dfInvFlattening );
    1945               8 :     poSpheroid->AddChild( new OGR_SRSNode(szValue) );
    1946                 : 
    1947               4 :     CPLFree( pszEllipsoidName );
    1948                 : 
    1949                 : /* -------------------------------------------------------------------- */
    1950                 : /*      Setup the Datum.                                                */
    1951                 : /* -------------------------------------------------------------------- */
    1952               8 :     OGR_SRSNode *poDatum = new OGR_SRSNode( "DATUM" );
    1953               8 :     poDatum->AddChild( new OGR_SRSNode(pszDatumName) );
    1954               4 :     poDatum->AddChild( poSpheroid );
    1955                 : 
    1956               4 :     poSRS->GetRoot()->AddChild( poDatum );
    1957                 : 
    1958               4 :     CPLFree( pszDatumName );
    1959                 : 
    1960                 : /* -------------------------------------------------------------------- */
    1961                 : /*      Setup the prime meridian.                                       */
    1962                 : /* -------------------------------------------------------------------- */
    1963               4 :     if( dfPMOffset == 0.0 )
    1964               4 :         strcpy( szValue, "0" );
    1965                 :     else
    1966               0 :         OGRPrintDouble( szValue, dfPMOffset );
    1967                 :     
    1968               4 :     OGR_SRSNode *poPM = new OGR_SRSNode( "PRIMEM" );
    1969               8 :     poPM->AddChild( new OGR_SRSNode( pszPMName ) );
    1970               8 :     poPM->AddChild( new OGR_SRSNode( szValue ) );
    1971                 : 
    1972               4 :     poSRS->GetRoot()->AddChild( poPM );
    1973                 : 
    1974               4 :     CPLFree( pszPMName );
    1975                 : 
    1976                 : /* -------------------------------------------------------------------- */
    1977                 : /*      Should we try to lookup a datum transform?                      */
    1978                 : /* -------------------------------------------------------------------- */
    1979                 : #ifdef notdef
    1980                 :     if( EPSGGetWGS84Transform( nGeogCS, adfBursaTransform ) )
    1981                 :     {
    1982                 :         OGR_SRSNode     *poWGS84;
    1983                 :         char            szValue[100];
    1984                 : 
    1985                 :         poWGS84 = new OGR_SRSNode( "TOWGS84" );
    1986                 : 
    1987                 :         for( int iCoeff = 0; iCoeff < 7; iCoeff++ )
    1988                 :         {
    1989                 :             sprintf( szValue, "%g", adfBursaTransform[iCoeff] );
    1990                 :             poWGS84->AddChild( new OGR_SRSNode( szValue ) );
    1991                 :         }
    1992                 : 
    1993                 :         poSRS->GetAttrNode( "DATUM" )->AddChild( poWGS84 );
    1994                 :     }
    1995                 : #endif
    1996                 : 
    1997                 : /* -------------------------------------------------------------------- */
    1998                 : /*      Set linear units.                                               */
    1999                 : /* -------------------------------------------------------------------- */
    2000               4 :     char *pszUOMLengthName = NULL;
    2001               4 :     double dfInMeters = 1.0;
    2002                 :     int nUOMLength = atoi(CSLGetField( papszRecord,
    2003                 :                                        CSVGetFileFieldId(pszFilename,
    2004               4 :                                                          "UOM_CODE")));
    2005                 :     
    2006               4 :     if( !EPSGGetUOMLengthInfo( nUOMLength, &pszUOMLengthName, &dfInMeters ) )
    2007                 :     {
    2008               0 :         return OGRERR_UNSUPPORTED_SRS;
    2009                 :     }
    2010                 : 
    2011               4 :     poSRS->SetLinearUnits( pszUOMLengthName, dfInMeters );
    2012               4 :     poSRS->SetAuthority( "GEOCCS|UNIT", "EPSG", nUOMLength );
    2013                 : 
    2014               4 :     CPLFree( pszUOMLengthName );
    2015                 : 
    2016                 : /* -------------------------------------------------------------------- */
    2017                 : /*      Set axes                                                        */
    2018                 : /* -------------------------------------------------------------------- */
    2019               4 :     OGR_SRSNode *poAxis = new OGR_SRSNode( "AXIS" );
    2020                 : 
    2021               8 :     poAxis->AddChild( new OGR_SRSNode( "Geocentric X" ) );
    2022               8 :     poAxis->AddChild( new OGR_SRSNode( OSRAxisEnumToName(OAO_Other) ) );
    2023                 : 
    2024               4 :     poSRS->GetRoot()->AddChild( poAxis );
    2025                 :     
    2026               8 :     poAxis = new OGR_SRSNode( "AXIS" );
    2027                 : 
    2028               8 :     poAxis->AddChild( new OGR_SRSNode( "Geocentric Y" ) );
    2029               8 :     poAxis->AddChild( new OGR_SRSNode( OSRAxisEnumToName(OAO_Other) ) );
    2030                 : 
    2031               4 :     poSRS->GetRoot()->AddChild( poAxis );
    2032                 :     
    2033               8 :     poAxis = new OGR_SRSNode( "AXIS" );
    2034                 : 
    2035               8 :     poAxis->AddChild( new OGR_SRSNode( "Geocentric Z" ) );
    2036               8 :     poAxis->AddChild( new OGR_SRSNode( OSRAxisEnumToName(OAO_North) ) );
    2037                 : 
    2038               4 :     poSRS->GetRoot()->AddChild( poAxis );
    2039                 : 
    2040                 : /* -------------------------------------------------------------------- */
    2041                 : /*      Set the authority codes.                                        */
    2042                 : /* -------------------------------------------------------------------- */
    2043               4 :     poSRS->SetAuthority( "DATUM", "EPSG", nDatumCode );
    2044               4 :     poSRS->SetAuthority( "SPHEROID", "EPSG", nEllipsoidCode );
    2045               4 :     poSRS->SetAuthority( "PRIMEM", "EPSG", nPMCode );
    2046                 : 
    2047                 : //    if( nUOMAngle > 0 )
    2048                 : //        poSRS->SetAuthority( "GEOGCS|UNIT", "EPSG", nUOMAngle );
    2049                 : 
    2050               4 :     poSRS->SetAuthority( "GEOCCS", "EPSG", nGCSCode );
    2051                 : 
    2052               4 :     return OGRERR_NONE;
    2053                 : }
    2054                 : 
    2055                 : /************************************************************************/
    2056                 : /*                           importFromEPSG()                           */
    2057                 : /************************************************************************/
    2058                 : 
    2059                 : /**
    2060                 :  * \brief Initialize SRS based on EPSG GCS or PCS code.
    2061                 :  *
    2062                 :  * This method will initialize the spatial reference based on the
    2063                 :  * passed in EPSG GCS or PCS code.  The coordinate system definitions
    2064                 :  * are normally read from the EPSG derived support files such as 
    2065                 :  * pcs.csv, gcs.csv, pcs.override.csv, gcs.override.csv and falling 
    2066                 :  * back to search for a PROJ.4 epsg init file or a definition in epsg.wkt. 
    2067                 :  *
    2068                 :  * These support files are normally searched for in /usr/local/share/gdal
    2069                 :  * or in the directory identified by the GDAL_DATA configuration option.
    2070                 :  * See CPLFindFile() for details.
    2071                 :  * 
    2072                 :  * This method is relatively expensive, and generally involves quite a bit
    2073                 :  * of text file scanning.  Reasonable efforts should be made to avoid calling
    2074                 :  * it many times for the same coordinate system. 
    2075                 :  * 
    2076                 :  * This method is similar to importFromEPSGA() except that EPSG preferred 
    2077                 :  * axis ordering will *not* be applied for geographic coordinate systems.
    2078                 :  * EPSG normally defines geographic coordinate systems to use lat/long 
    2079                 :  * contrary to typical GIS use). 
    2080                 :  *
    2081                 :  * This method is the same as the C function OSRImportFromEPSG().
    2082                 :  *
    2083                 :  * @param nCode a GCS or PCS code from the horizontal coordinate system table.
    2084                 :  * 
    2085                 :  * @return OGRERR_NONE on success, or an error code on failure.
    2086                 :  */
    2087                 : 
    2088           36194 : OGRErr OGRSpatialReference::importFromEPSG( int nCode )
    2089                 : 
    2090                 : {
    2091           36194 :     OGRErr eErr = importFromEPSGA( nCode );
    2092                 : 
    2093                 :     // Strip any GCS axis settings found.
    2094           36194 :     if( eErr == OGRERR_NONE )
    2095                 :     {
    2096           35402 :         OGR_SRSNode *poGEOGCS = GetAttrNode( "GEOGCS" );
    2097                 : 
    2098           35402 :         if( poGEOGCS != NULL )
    2099           35390 :             poGEOGCS->StripNodes( "AXIS" );
    2100                 :     }
    2101                 : 
    2102           36194 :     return eErr;
    2103                 : }
    2104                 : 
    2105                 : /************************************************************************/
    2106                 : /*                         OSRImportFromEPSG()                          */
    2107                 : /************************************************************************/
    2108                 : 
    2109                 : /**
    2110                 :  * \brief  Initialize SRS based on EPSG GCS or PCS code.
    2111                 :  *
    2112                 :  * This function is the same as OGRSpatialReference::importFromEPSG().
    2113                 :  */
    2114                 : 
    2115           17976 : OGRErr CPL_STDCALL OSRImportFromEPSG( OGRSpatialReferenceH hSRS, int nCode )
    2116                 : 
    2117                 : {
    2118           17976 :     VALIDATE_POINTER1( hSRS, "OSRImportFromEPSG", CE_Failure );
    2119                 : 
    2120           17976 :     return ((OGRSpatialReference *) hSRS)->importFromEPSG( nCode );
    2121                 : }
    2122                 : 
    2123                 : /************************************************************************/
    2124                 : /*                          importFromEPSGA()                           */
    2125                 : /************************************************************************/
    2126                 : 
    2127                 : /**
    2128                 :  * \brief Initialize SRS based on EPSG GCS or PCS code.
    2129                 :  *
    2130                 :  * This method will initialize the spatial reference based on the
    2131                 :  * passed in EPSG GCS or PCS code.  
    2132                 :  * 
    2133                 :  * This method is similar to importFromEPSG() except that EPSG preferred 
    2134                 :  * axis ordering *will* be applied for geographic coordinate systems.
    2135                 :  * EPSG normally defines geographic coordinate systems to use lat/long 
    2136                 :  * contrary to typical GIS use).  See OGRSpatialReference::importFromEPSG() 
    2137                 :  * for more details on operation of this method.
    2138                 :  *
    2139                 :  * This method is the same as the C function OSRImportFromEPSGA().
    2140                 :  *
    2141                 :  * @param nCode a GCS or PCS code from the horizontal coordinate system table.
    2142                 :  * 
    2143                 :  * @return OGRERR_NONE on success, or an error code on failure.
    2144                 :  */
    2145                 : 
    2146           36952 : OGRErr OGRSpatialReference::importFromEPSGA( int nCode )
    2147                 : 
    2148                 : {
    2149                 :     OGRErr  eErr;
    2150           36952 :     CPLLocaleC  oLocaleForcer;
    2151                 : 
    2152           36952 :     bNormInfoSet = FALSE;
    2153                 : 
    2154                 : /* -------------------------------------------------------------------- */
    2155                 : /*      Clear any existing definition.                                  */
    2156                 : /* -------------------------------------------------------------------- */
    2157           36952 :     if( GetRoot() != NULL )
    2158                 :     {
    2159            8422 :         delete poRoot;
    2160            8422 :         poRoot = NULL;
    2161                 :     }
    2162                 : 
    2163                 : /* -------------------------------------------------------------------- */
    2164                 : /*      Verify that we can find the required filename(s).               */
    2165                 : /* -------------------------------------------------------------------- */
    2166           36952 :     if( CSVScanFileByName( CSVFilename( "gcs.csv" ),
    2167                 :                            "COORD_REF_SYS_CODE", 
    2168                 :                            "4269", CC_Integer ) == NULL )
    2169                 :     {
    2170                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    2171                 :                   "Unable to open EPSG support file %s.\n"
    2172                 :                   "Try setting the GDAL_DATA environment variable to point to the\n"
    2173                 :                   "directory containing EPSG csv files.", 
    2174               0 :                   CSVFilename( "gcs.csv" ) );
    2175               0 :         return OGRERR_FAILURE;
    2176                 :     }
    2177                 : 
    2178                 : /* -------------------------------------------------------------------- */
    2179                 : /*      Try this as various sorts of objects till one works.            */
    2180                 : /* -------------------------------------------------------------------- */
    2181           36952 :     eErr = SetEPSGGeogCS( this, nCode );
    2182           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2183           24160 :         eErr = SetEPSGProjCS( this, nCode );
    2184           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2185             966 :         eErr = SetEPSGVertCS( this, nCode );
    2186           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2187             958 :         eErr = SetEPSGCompdCS( this, nCode );
    2188           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2189             950 :         eErr = SetEPSGGeocCS( this, nCode );
    2190                 : 
    2191                 : /* -------------------------------------------------------------------- */
    2192                 : /*      If we get it as an unsupported code, try looking it up in       */
    2193                 : /*      the epsg.wkt coordinate system dictionary.                      */
    2194                 : /* -------------------------------------------------------------------- */
    2195           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2196                 :     {
    2197                 :         char szCode[32];
    2198             946 :         sprintf( szCode, "%d", nCode );
    2199             946 :         eErr = importFromDict( "epsg.wkt", szCode );
    2200                 :     }
    2201                 : 
    2202                 : /* -------------------------------------------------------------------- */
    2203                 : /*      If we get it as an unsupported code, try looking it up in       */
    2204                 : /*      the PROJ.4 support file(s).                                     */
    2205                 : /* -------------------------------------------------------------------- */
    2206           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2207                 :     {
    2208                 :         char szWrkDefn[100];
    2209                 :         char *pszNormalized;
    2210                 : 
    2211             792 :         sprintf( szWrkDefn, "+init=epsg:%d", nCode );
    2212                 :         
    2213             792 :         pszNormalized = OCTProj4Normalize( szWrkDefn );
    2214                 : 
    2215             792 :         if( strstr(pszNormalized,"proj=") != NULL )
    2216               0 :             eErr = importFromProj4( pszNormalized );
    2217                 :         
    2218             792 :         CPLFree( pszNormalized );
    2219                 :     }
    2220                 : 
    2221                 : /* -------------------------------------------------------------------- */
    2222                 : /*      Push in authority information if we were successful, and it     */
    2223                 : /*      is not already present.                                         */
    2224                 : /* -------------------------------------------------------------------- */
    2225                 :     const char *pszAuthName;
    2226                 : 
    2227           36952 :     if( IsProjected() )
    2228           23438 :         pszAuthName = GetAuthorityName( "PROJCS" );
    2229                 :     else
    2230           13514 :         pszAuthName = GetAuthorityName( "GEOGCS" );
    2231                 : 
    2232                 : 
    2233           36952 :     if( eErr == OGRERR_NONE && pszAuthName == NULL )
    2234                 :     {
    2235              14 :         if( IsProjected() )
    2236               2 :             SetAuthority( "PROJCS", "EPSG", nCode );
    2237              12 :         else if( IsGeographic() )
    2238               0 :             SetAuthority( "GEOGCS", "EPSG", nCode );
    2239                 :     }
    2240                 : 
    2241                 : /* -------------------------------------------------------------------- */
    2242                 : /*      Otherwise officially issue an error message.                    */
    2243                 : /* -------------------------------------------------------------------- */
    2244           36952 :     if( eErr == OGRERR_UNSUPPORTED_SRS )
    2245                 :     {
    2246                 :         CPLError( CE_Failure, CPLE_NotSupported,
    2247                 :                   "EPSG PCS/GCS code %d not found in EPSG support files.  Is this a valid\nEPSG coordinate system?", 
    2248             792 :                   nCode );
    2249                 :     }
    2250                 : 
    2251                 : /* -------------------------------------------------------------------- */
    2252                 : /*      To the extent possible, we want to return the results in as     */
    2253                 : /*      close to standard OGC format as possible, so we fixup the       */
    2254                 : /*      ordering.                                                       */
    2255                 : /* -------------------------------------------------------------------- */
    2256           36952 :     if( eErr == OGRERR_NONE )
    2257                 :     {    
    2258           36160 :         eErr = FixupOrdering();
    2259                 :     }
    2260                 : 
    2261           36952 :     return eErr;
    2262                 : }
    2263                 : 
    2264                 : /************************************************************************/
    2265                 : /*                         OSRImportFromEPSGA()                         */
    2266                 : /************************************************************************/
    2267                 : 
    2268                 : /**
    2269                 :  * \brief  Initialize SRS based on EPSG GCS or PCS code.
    2270                 :  *
    2271                 :  * This function is the same as OGRSpatialReference::importFromEPSGA().
    2272                 :  */
    2273                 : 
    2274               6 : OGRErr CPL_STDCALL OSRImportFromEPSGA( OGRSpatialReferenceH hSRS, int nCode )
    2275                 : 
    2276                 : {
    2277               6 :     VALIDATE_POINTER1( hSRS, "OSRImportFromEPSGA", CE_Failure );
    2278                 : 
    2279               6 :     return ((OGRSpatialReference *) hSRS)->importFromEPSGA( nCode );
    2280                 : }
    2281                 : 
    2282                 : /************************************************************************/
    2283                 : /*                           SetStatePlane()                            */
    2284                 : /************************************************************************/
    2285                 : 
    2286                 : /**
    2287                 :  * \brief Set State Plane projection definition.
    2288                 :  *
    2289                 :  * This will attempt to generate a complete definition of a state plane
    2290                 :  * zone based on generating the entire SRS from the EPSG tables.  If the
    2291                 :  * EPSG tables are unavailable, it will produce a stubbed LOCAL_CS definition
    2292                 :  * and return OGRERR_FAILURE.
    2293                 :  *
    2294                 :  * This method is the same as the C function OSRSetStatePlaneWithUnits().
    2295                 :  *
    2296                 :  * @param nZone State plane zone number, in the USGS numbering scheme (as
    2297                 :  * dinstinct from the Arc/Info and Erdas numbering scheme. 
    2298                 :  *
    2299                 :  * @param bNAD83 TRUE if the NAD83 zone definition should be used or FALSE
    2300                 :  * if the NAD27 zone definition should be used.  
    2301                 :  *
    2302                 :  * @param pszOverrideUnitName Linear unit name to apply overriding the 
    2303                 :  * legal definition for this zone.
    2304                 :  *
    2305                 :  * @param dfOverrideUnit Linear unit conversion factor to apply overriding
    2306                 :  * the legal definition for this zone. 
    2307                 :  * 
    2308                 :  * @return OGRERR_NONE on success, or OGRERR_FAILURE on failure, mostly likely
    2309                 :  * due to the EPSG tables not being accessable. 
    2310                 :  */
    2311                 : 
    2312              14 : OGRErr OGRSpatialReference::SetStatePlane( int nZone, int bNAD83,
    2313                 :                                            const char *pszOverrideUnitName,
    2314                 :                                            double dfOverrideUnit )
    2315                 : 
    2316                 : {
    2317                 :     int         nAdjustedId;
    2318                 :     int         nPCSCode;
    2319                 :     char        szID[32];
    2320                 : 
    2321                 : /* -------------------------------------------------------------------- */
    2322                 : /*      Get the index id from stateplane.csv.                           */
    2323                 : /* -------------------------------------------------------------------- */
    2324              14 :     if( bNAD83 )
    2325              12 :         nAdjustedId = nZone;
    2326                 :     else
    2327               2 :         nAdjustedId = nZone + 10000;
    2328                 : 
    2329                 : /* -------------------------------------------------------------------- */
    2330                 : /*      Turn this into a PCS code.  We assume there will only be one    */
    2331                 : /*      PCS corresponding to each Proj_ code since the proj code        */
    2332                 : /*      already effectively indicates NAD27 or NAD83.                   */
    2333                 : /* -------------------------------------------------------------------- */
    2334              14 :     sprintf( szID, "%d", nAdjustedId );
    2335                 :     nPCSCode =
    2336                 :         atoi( CSVGetField( CSVFilename( "stateplane.csv" ),
    2337                 :                            "ID", szID, CC_Integer,
    2338              14 :                            "EPSG_PCS_CODE" ) );
    2339              14 :     if( nPCSCode < 1 )
    2340                 :     {
    2341                 :         char    szName[128];
    2342                 :         static int bFailureReported = FALSE;
    2343                 : 
    2344               0 :         if( !bFailureReported )
    2345                 :         {
    2346               0 :             bFailureReported = TRUE;
    2347                 :             CPLError( CE_Warning, CPLE_OpenFailed, 
    2348                 :                       "Unable to find state plane zone in stateplane.csv,\n"
    2349                 :                       "likely because the GDAL data files cannot be found.  Using\n"
    2350               0 :                       "incomplete definition of state plane zone.\n" );
    2351                 :         }
    2352                 : 
    2353               0 :         Clear();
    2354               0 :         if( bNAD83 )
    2355                 :         {
    2356               0 :             sprintf( szName, "State Plane Zone %d / NAD83", nZone );
    2357               0 :             SetLocalCS( szName );
    2358               0 :             SetLinearUnits( SRS_UL_METER, 1.0 );
    2359                 :         }
    2360                 :         else
    2361                 :         {
    2362               0 :             sprintf( szName, "State Plane Zone %d / NAD27", nZone );
    2363               0 :             SetLocalCS( szName );
    2364               0 :             SetLinearUnits( SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV) );
    2365                 :         }
    2366                 : 
    2367               0 :         return OGRERR_FAILURE;
    2368                 :     }
    2369                 : 
    2370                 : /* -------------------------------------------------------------------- */
    2371                 : /*      Define based on a full EPSG definition of the zone.             */
    2372                 : /* -------------------------------------------------------------------- */
    2373              14 :     OGRErr eErr = importFromEPSG( nPCSCode );
    2374                 : 
    2375              14 :     if( eErr != OGRERR_NONE )
    2376               0 :         return eErr;
    2377                 : 
    2378                 : /* -------------------------------------------------------------------- */
    2379                 : /*      Apply units override if required.                               */
    2380                 : /*                                                                      */
    2381                 : /*      We will need to adjust the linear projection parameter to       */
    2382                 : /*      match the provided units, and clear the authority code.         */
    2383                 : /* -------------------------------------------------------------------- */
    2384              14 :     if( dfOverrideUnit != 0.0 
    2385                 :         && fabs(dfOverrideUnit - GetLinearUnits()) > 0.0000000001 )
    2386                 :     {
    2387               2 :         double dfFalseEasting = GetNormProjParm( SRS_PP_FALSE_EASTING );
    2388               2 :         double dfFalseNorthing= GetNormProjParm( SRS_PP_FALSE_NORTHING);
    2389                 :         OGR_SRSNode *poPROJCS;
    2390                 : 
    2391               2 :         SetLinearUnits( pszOverrideUnitName, dfOverrideUnit );
    2392                 :         
    2393               2 :         SetNormProjParm( SRS_PP_FALSE_EASTING, dfFalseEasting );
    2394               2 :         SetNormProjParm( SRS_PP_FALSE_NORTHING, dfFalseNorthing );
    2395                 : 
    2396               2 :         poPROJCS = GetAttrNode( "PROJCS" );
    2397               2 :         if( poPROJCS != NULL && poPROJCS->FindChild( "AUTHORITY" ) != -1 )
    2398                 :         {
    2399               2 :             poPROJCS->DestroyChild( poPROJCS->FindChild( "AUTHORITY" ) );
    2400                 :         }
    2401                 :     }
    2402                 : 
    2403              14 :     return OGRERR_NONE;
    2404                 : }
    2405                 : 
    2406                 : /************************************************************************/
    2407                 : /*                          OSRSetStatePlane()                          */
    2408                 : /************************************************************************/
    2409                 : 
    2410                 : /**
    2411                 :  * \brief Set State Plane projection definition.
    2412                 :  *
    2413                 :  * This function is the same as OGRSpatialReference::SetStatePlane().
    2414                 :  */ 
    2415                 :  
    2416               0 : OGRErr OSRSetStatePlane( OGRSpatialReferenceH hSRS, int nZone, int bNAD83 )
    2417                 : 
    2418                 : {
    2419               0 :     VALIDATE_POINTER1( hSRS, "OSRSetStatePlane", CE_Failure );
    2420                 : 
    2421               0 :     return ((OGRSpatialReference *) hSRS)->SetStatePlane( nZone, bNAD83 );
    2422                 : }
    2423                 : 
    2424                 : /************************************************************************/
    2425                 : /*                     OSRSetStatePlaneWithUnits()                      */
    2426                 : /************************************************************************/
    2427                 : 
    2428                 : /**
    2429                 :  * \brief Set State Plane projection definition.
    2430                 :  *
    2431                 :  * This function is the same as OGRSpatialReference::SetStatePlane().
    2432                 :  */ 
    2433                 :  
    2434               4 : OGRErr OSRSetStatePlaneWithUnits( OGRSpatialReferenceH hSRS, 
    2435                 :                                   int nZone, int bNAD83,
    2436                 :                                   const char *pszOverrideUnitName,
    2437                 :                                   double dfOverrideUnit )
    2438                 : 
    2439                 : {
    2440               4 :     VALIDATE_POINTER1( hSRS, "OSRSetStatePlaneWithUnits", CE_Failure );
    2441                 : 
    2442                 :     return ((OGRSpatialReference *) hSRS)->SetStatePlane( nZone, bNAD83,
    2443                 :                                                           pszOverrideUnitName,
    2444               4 :                                                           dfOverrideUnit );
    2445                 : }
    2446                 : 
    2447                 : /************************************************************************/
    2448                 : /*                           GetEPSGGeogCS()                            */
    2449                 : /*                                                                      */
    2450                 : /*      Try to establish what the EPSG code for this coordinate         */
    2451                 : /*      systems GEOGCS might be.  Returns -1 if no reasonable guess     */
    2452                 : /*      can be made.                                                    */
    2453                 : /*                                                                      */
    2454                 : /*      TODO: We really need to do some name lookups.                   */
    2455                 : /************************************************************************/
    2456                 : 
    2457             290 : int OGRSpatialReference::GetEPSGGeogCS()
    2458                 : 
    2459                 : {
    2460             290 :     const char *pszAuthName = GetAuthorityName( "GEOGCS" );
    2461                 : 
    2462                 : /* -------------------------------------------------------------------- */
    2463                 : /*      Do we already have it?                                          */
    2464                 : /* -------------------------------------------------------------------- */
    2465             290 :     if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
    2466             142 :         return atoi(GetAuthorityCode( "GEOGCS" ));
    2467                 : 
    2468                 : /* -------------------------------------------------------------------- */
    2469                 : /*      Get the datum and geogcs names.                                 */
    2470                 : /* -------------------------------------------------------------------- */
    2471             148 :     const char *pszGEOGCS = GetAttrValue( "GEOGCS" );
    2472             148 :     const char *pszDatum = GetAttrValue( "DATUM" );
    2473                 : 
    2474                 :     // We can only operate on coordinate systems with a geogcs.
    2475             148 :     if( pszGEOGCS == NULL || pszDatum == NULL )
    2476               0 :         return -1;
    2477                 : 
    2478                 : /* -------------------------------------------------------------------- */
    2479                 : /*      Is this a "well known" geographic coordinate system?            */
    2480                 : /* -------------------------------------------------------------------- */
    2481                 :     int bWGS, bNAD;
    2482                 : 
    2483                 :     bWGS = strstr(pszGEOGCS,"WGS") != NULL
    2484                 :         || strstr(pszDatum, "WGS")
    2485                 :         || strstr(pszGEOGCS,"World Geodetic System")
    2486                 :         || strstr(pszGEOGCS,"World_Geodetic_System")
    2487                 :         || strstr(pszDatum, "World Geodetic System")
    2488             148 :         || strstr(pszDatum, "World_Geodetic_System"); 
    2489                 : 
    2490                 :     bNAD = strstr(pszGEOGCS,"NAD") != NULL
    2491                 :         || strstr(pszDatum, "NAD")
    2492                 :         || strstr(pszGEOGCS,"North American")
    2493                 :         || strstr(pszGEOGCS,"North_American")
    2494                 :         || strstr(pszDatum, "North American")
    2495             148 :         || strstr(pszDatum, "North_American"); 
    2496                 : 
    2497             148 :     if( bWGS && (strstr(pszGEOGCS,"84") || strstr(pszDatum,"84")) )
    2498              96 :         return 4326;
    2499                 : 
    2500              52 :     if( bWGS && (strstr(pszGEOGCS,"72") || strstr(pszDatum,"72")) )
    2501               0 :         return 4322;
    2502                 : 
    2503              52 :     if( bNAD && (strstr(pszGEOGCS,"83") || strstr(pszDatum,"83")) )
    2504              10 :         return 4269;
    2505                 : 
    2506              42 :     if( bNAD && (strstr(pszGEOGCS,"27") || strstr(pszDatum,"27")) )
    2507               2 :         return 4267;
    2508                 : 
    2509                 : /* -------------------------------------------------------------------- */
    2510                 : /*      If we know the datum, associate the most likely GCS with        */
    2511                 : /*      it.                                                             */
    2512                 : /* -------------------------------------------------------------------- */
    2513              40 :     pszAuthName = GetAuthorityName( "GEOGCS|DATUM" );
    2514                 : 
    2515              40 :     if( pszAuthName != NULL 
    2516                 :         && EQUAL(pszAuthName,"epsg") 
    2517                 :         && GetPrimeMeridian() == 0.0 )
    2518                 :     {
    2519               6 :         int nDatum = atoi(GetAuthorityCode("GEOGCS|DATUM"));
    2520                 :         
    2521               6 :         if( nDatum >= 6000 && nDatum <= 6999 )
    2522               6 :             return nDatum - 2000;
    2523                 :     }
    2524                 : 
    2525              34 :     return -1;
    2526                 : }
    2527                 : 
    2528                 : /************************************************************************/
    2529                 : /*                          AutoIdentifyEPSG()                          */
    2530                 : /************************************************************************/
    2531                 : 
    2532                 : /**
    2533                 :  * \brief Set EPSG authority info if possible.
    2534                 :  *
    2535                 :  * This method inspects a WKT definition, and adds EPSG authority nodes
    2536                 :  * where an aspect of the coordinate system can be easily and safely 
    2537                 :  * corresponded with an EPSG identifier.  In practice, this method will 
    2538                 :  * evolve over time.  In theory it can add authority nodes for any object
    2539                 :  * (ie. spheroid, datum, GEOGCS, units, and PROJCS) that could have an 
    2540                 :  * authority node.  Mostly this is useful to inserting appropriate 
    2541                 :  * PROJCS codes for common formulations (like UTM n WGS84). 
    2542                 :  *
    2543                 :  * If it success the OGRSpatialReference is updated in place, and the 
    2544                 :  * method return OGRERR_NONE.  If the method fails to identify the 
    2545                 :  * general coordinate system OGRERR_UNSUPPORTED_SRS is returned but no 
    2546                 :  * error message is posted via CPLError(). 
    2547                 :  *
    2548                 :  * This method is the same as the C function OSRAutoIdentifyEPSG().
    2549                 :  *
    2550                 :  * @return OGRERR_NONE or OGRERR_UNSUPPORTED_SRS.
    2551                 :  */
    2552                 : 
    2553             104 : OGRErr OGRSpatialReference::AutoIdentifyEPSG()
    2554                 : 
    2555                 : {
    2556                 : /* -------------------------------------------------------------------- */
    2557                 : /*      Do we have a GEOGCS node, but no authority?  If so, try         */
    2558                 : /*      guessing it.                                                    */
    2559                 : /* -------------------------------------------------------------------- */
    2560             104 :     if( (IsProjected() || IsGeographic()) 
    2561                 :         && GetAuthorityCode( "GEOGCS" ) == NULL )
    2562                 :     {
    2563              54 :         int nGCS = GetEPSGGeogCS();
    2564              54 :         if( nGCS != -1 )
    2565              20 :             SetAuthority( "GEOGCS", "EPSG", nGCS );
    2566                 :     }
    2567                 : 
    2568                 : /* -------------------------------------------------------------------- */
    2569                 : /*      Is this a UTM coordinate system with a common GEOGCS?           */
    2570                 : /* -------------------------------------------------------------------- */
    2571                 :     int nZone, bNorth;
    2572             104 :     if( (nZone = GetUTMZone( &bNorth )) != 0 
    2573                 :         && GetAuthorityCode( "PROJCS") == NULL )
    2574                 :     {
    2575                 :         const char *pszAuthName, *pszAuthCode;
    2576                 : 
    2577              72 :         pszAuthName = GetAuthorityName( "PROJCS|GEOGCS" );
    2578              72 :         pszAuthCode = GetAuthorityCode( "PROJCS|GEOGCS" );
    2579                 : 
    2580              72 :         if( pszAuthName == NULL ||  pszAuthCode == NULL )
    2581                 :         {
    2582                 :             /* don't exactly recognise datum */
    2583                 :         }
    2584              50 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4326 )
    2585                 :         { // WGS84
    2586               0 :             if( bNorth ) 
    2587               0 :                 SetAuthority( "PROJCS", "EPSG", 32600 + nZone );
    2588                 :             else
    2589               0 :                 SetAuthority( "PROJCS", "EPSG", 32700 + nZone );
    2590                 :         }
    2591             100 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4267 
    2592                 :                  && nZone >= 3 && nZone <= 22 && bNorth )
    2593              50 :             SetAuthority( "PROJCS", "EPSG", 26700 + nZone ); // NAD27
    2594               0 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4269
    2595                 :                  && nZone >= 3 && nZone <= 23 && bNorth )
    2596               0 :             SetAuthority( "PROJCS", "EPSG", 26900 + nZone ); // NAD83
    2597               0 :         else if( EQUAL(pszAuthName,"EPSG") && atoi(pszAuthCode) == 4322 )
    2598                 :         { // WGS72
    2599               0 :             if( bNorth ) 
    2600               0 :                 SetAuthority( "PROJCS", "EPSG", 32200 + nZone );
    2601                 :             else
    2602               0 :                 SetAuthority( "PROJCS", "EPSG", 32300 + nZone );
    2603                 :         }
    2604                 :     }
    2605                 : 
    2606                 : /* -------------------------------------------------------------------- */
    2607                 : /*      Return.                                                         */
    2608                 : /* -------------------------------------------------------------------- */
    2609             104 :     if( IsProjected() && GetAuthorityCode("PROJCS") != NULL )
    2610              50 :         return OGRERR_NONE;
    2611              54 :     else if( IsGeographic() && GetAuthorityCode("GEOGCS") != NULL )
    2612               4 :         return OGRERR_NONE;
    2613                 :     else
    2614              50 :         return OGRERR_UNSUPPORTED_SRS;
    2615                 : }
    2616                 : 
    2617                 : /************************************************************************/
    2618                 : /*                        OSRAutoIdentifyEPSG()                         */
    2619                 : /************************************************************************/
    2620                 : 
    2621                 : /**
    2622                 :  * \brief Set EPSG authority info if possible.
    2623                 :  *
    2624                 :  * This function is the same as OGRSpatialReference::AutoIdentifyEPSG().
    2625                 :  */ 
    2626                 :  
    2627               0 : OGRErr OSRAutoIdentifyEPSG( OGRSpatialReferenceH hSRS )
    2628                 : 
    2629                 : {
    2630               0 :     VALIDATE_POINTER1( hSRS, "OSRAutoIdentifyEPSG", CE_Failure );
    2631                 : 
    2632               0 :     return ((OGRSpatialReference *) hSRS)->AutoIdentifyEPSG();
    2633                 : }
    2634                 : 
    2635                 : /************************************************************************/
    2636                 : /*                        EPSGTreatsAsLatLong()                         */
    2637                 : /************************************************************************/
    2638                 : 
    2639                 : /**
    2640                 :  * \brief This method returns TRUE if EPSG feels this geographic coordinate
    2641                 :  * system should be treated as having lat/long coordinate ordering.
    2642                 :  *
    2643                 :  * Currently this returns TRUE for all geographic coordinate systems
    2644                 :  * with an EPSG code set, and AXIS values set defining it as lat, long.
    2645                 :  * Note that coordinate systems with an EPSG code and no axis settings
    2646                 :  * will be assumed to not be lat/long.  
    2647                 :  *
    2648                 :  * FALSE will be returned for all coordinate systems that are not geographic,
    2649                 :  * or that do not have an EPSG code set. 
    2650                 :  *
    2651                 :  * This method is the same as the C function OSREPSGTreatsAsLatLong().
    2652                 :  *
    2653                 :  * @return TRUE or FALSE. 
    2654                 :  */ 
    2655                 : 
    2656             424 : int OGRSpatialReference::EPSGTreatsAsLatLong()
    2657                 : 
    2658                 : {
    2659             424 :     if( !IsGeographic() )
    2660              42 :         return FALSE;
    2661                 : 
    2662             382 :     const char *pszAuth = GetAuthorityName( "GEOGCS" );
    2663                 : 
    2664             382 :     if( pszAuth == NULL || !EQUAL(pszAuth,"EPSG") )
    2665               0 :         return FALSE;
    2666                 : 
    2667             382 :     OGR_SRSNode *poFirstAxis = GetAttrNode( "GEOGCS|AXIS" );
    2668                 : 
    2669             382 :     if( poFirstAxis == NULL )
    2670              34 :         return FALSE;
    2671                 : 
    2672             348 :     if( poFirstAxis->GetChildCount() >= 2 
    2673                 :         && EQUAL(poFirstAxis->GetChild(1)->GetValue(),"NORTH") )
    2674             348 :         return TRUE;
    2675                 : 
    2676               0 :     return FALSE;
    2677                 : }
    2678                 : 
    2679                 : /************************************************************************/
    2680                 : /*                       OSREPSGTreatsAsLatLong()                       */
    2681                 : /************************************************************************/
    2682                 : 
    2683                 : /**
    2684                 :  * \brief This function returns TRUE if EPSG feels this geographic coordinate
    2685                 :  * system should be treated as having lat/long coordinate ordering.
    2686                 :  *
    2687                 :  * This function is the same as OGRSpatialReference::OSREPSGTreatsAsLatLong().
    2688                 :  */ 
    2689                 :  
    2690               8 : int OSREPSGTreatsAsLatLong( OGRSpatialReferenceH hSRS )
    2691                 : 
    2692                 : {
    2693               8 :     VALIDATE_POINTER1( hSRS, "OSREPSGTreatsAsLatLong", CE_Failure );
    2694                 : 
    2695               8 :     return ((OGRSpatialReference *) hSRS)->EPSGTreatsAsLatLong();
    2696                 : }
    2697                 : 

Generated by: LCOV version 1.7