~ubuntu-branches/debian/sid/gdal/sid

« back to all changes in this revision

Viewing changes to ogr/ogrspatialreference.cpp

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2012-05-07 15:04:42 UTC
  • mfrom: (5.5.16 experimental)
  • Revision ID: package-import@ubuntu.com-20120507150442-2eks97loeh6rq005
Tags: 1.9.0-1
* Ready for sid, starting transition.
* All symfiles updated to latest builds.
* Added dh_numpy call in debian/rules to depend on numpy ABI.
* Policy bumped to 3.9.3, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id: ogrspatialreference.cpp 20132 2010-07-25 10:15:39Z chaitanya $
 
2
 * $Id: ogrspatialreference.cpp 22974 2011-08-24 18:37:09Z rouault $
3
3
 *
4
4
 * Project:  OpenGIS Simple Features Reference Implementation
5
5
 * Purpose:  The OGRSpatialReference class.
33
33
#include "cpl_http.h"
34
34
#include "cpl_atomic_ops.h"
35
35
 
36
 
CPL_CVSID("$Id: ogrspatialreference.cpp 20132 2010-07-25 10:15:39Z chaitanya $");
 
36
CPL_CVSID("$Id: ogrspatialreference.cpp 22974 2011-08-24 18:37:09Z rouault $");
37
37
 
38
38
// The current opinion is that WKT longitudes like central meridian
39
39
// should be relative to greenwich, not the prime meridian in use. 
45
45
/*                           OGRPrintDouble()                           */
46
46
/************************************************************************/
47
47
 
48
 
static void OGRPrintDouble( char * pszStrBuf, double dfValue )
 
48
void OGRPrintDouble( char * pszStrBuf, double dfValue )
49
49
 
50
50
{
51
51
    sprintf( pszStrBuf, "%.16g", dfValue );
428
428
    papszPathTokens = CSLTokenizeStringComplex(pszNodePath, "|", TRUE, FALSE);
429
429
 
430
430
    if( CSLCount( papszPathTokens ) < 1 )
 
431
    {
 
432
        CSLDestroy(papszPathTokens);
431
433
        return NULL;
 
434
    }
432
435
 
433
436
    poNode = GetRoot();
434
437
    for( int i = 0; poNode != NULL && papszPathTokens[i] != NULL; i++ )
701
704
 
702
705
    poRoot = new OGR_SRSNode();
703
706
 
704
 
    return poRoot->importFromWkt( ppszInput );
 
707
    OGRErr eErr = poRoot->importFromWkt( ppszInput ); 
 
708
    if (eErr != OGRERR_NONE)
 
709
        return eErr;
 
710
 
 
711
/* -------------------------------------------------------------------- */
 
712
/*      The following seems to try and detect and unconsumed            */
 
713
/*      VERTCS[] coordinate system definition (ESRI style) and to       */
 
714
/*      import and attach it to the existing root.  Likely we will      */
 
715
/*      need to extend this somewhat to bring it into an acceptable     */
 
716
/*      OGRSpatialReference organization at some point.                 */
 
717
/* -------------------------------------------------------------------- */
 
718
    if (strlen(*ppszInput) > 0 && strstr(*ppszInput, "VERTCS"))
 
719
    {
 
720
        if(((*ppszInput)[0]) == ',')
 
721
            (*ppszInput)++;
 
722
        OGR_SRSNode *poNewChild = new OGR_SRSNode();
 
723
        poRoot->AddChild( poNewChild );
 
724
        return poNewChild->importFromWkt( ppszInput );
 
725
    }
 
726
 
 
727
    return eErr;
705
728
}
706
729
 
707
730
/************************************************************************/
877
900
    if( poCS->FindChild( "UNIT" ) >= 0 )
878
901
    {
879
902
        poUnits = poCS->GetChild( poCS->FindChild( "UNIT" ) );
 
903
        if (poUnits->GetChildCount() < 2)
 
904
            return OGRERR_FAILURE;
880
905
        poUnits->GetChild(0)->SetValue( pszUnitsName );
881
906
        poUnits->GetChild(1)->SetValue( szValue );
882
907
    }
1058
1083
    return ((OGRSpatialReference *) hSRS)->
1059
1084
        SetLinearUnitsAndUpdateParameters( pszUnits, dfInMeters );
1060
1085
}
 
1086
 
1061
1087
/************************************************************************/
1062
1088
/*                           SetLinearUnits()                           */
1063
1089
/************************************************************************/
1066
1092
 * \brief Set the linear units for the projection.
1067
1093
 *
1068
1094
 * This method creates a UNIT subnode with the specified values as a
1069
 
 * child of the PROJCS or LOCAL_CS node. 
 
1095
 * child of the PROJCS, GEOCCS or LOCAL_CS node. 
1070
1096
 *
1071
1097
 * This method does the same as the C function OSRSetLinearUnits(). 
1072
1098
 *
1085
1111
                                            double dfInMeters )
1086
1112
 
1087
1113
{
1088
 
    OGR_SRSNode *poCS;
1089
 
    OGR_SRSNode *poUnits;
1090
 
    char        szValue[128];
1091
 
 
1092
 
    bNormInfoSet = FALSE;
1093
 
 
1094
 
    poCS = GetAttrNode( "PROJCS" );
1095
 
    if( poCS == NULL )
1096
 
        poCS = GetAttrNode( "LOCAL_CS" );
1097
 
 
1098
 
    if( poCS == NULL )
1099
 
        return OGRERR_FAILURE;
1100
 
 
1101
 
    if( dfInMeters == (int) dfInMeters )
1102
 
        sprintf( szValue, "%d", (int) dfInMeters );
1103
 
    else
1104
 
        OGRPrintDouble( szValue, dfInMeters );
1105
 
 
1106
 
    if( poCS->FindChild( "UNIT" ) >= 0 )
1107
 
    {
1108
 
        poUnits = poCS->GetChild( poCS->FindChild( "UNIT" ) );
1109
 
        poUnits->GetChild(0)->SetValue( pszUnitsName );
1110
 
        poUnits->GetChild(1)->SetValue( szValue );
1111
 
        if( poUnits->FindChild( "AUTHORITY" ) != -1 )
1112
 
            poUnits->DestroyChild( poUnits->FindChild( "AUTHORITY" ) );
1113
 
    }
1114
 
    else
1115
 
    {
1116
 
        poUnits = new OGR_SRSNode( "UNIT" );
1117
 
        poUnits->AddChild( new OGR_SRSNode( pszUnitsName ) );
1118
 
        poUnits->AddChild( new OGR_SRSNode( szValue ) );
1119
 
        
1120
 
        poCS->AddChild( poUnits );
1121
 
    }
1122
 
 
1123
 
    return OGRERR_NONE;
 
1114
    return SetTargetLinearUnits( NULL, pszUnitsName, dfInMeters );
1124
1115
}
1125
1116
 
1126
1117
/************************************************************************/
1143
1134
}
1144
1135
 
1145
1136
/************************************************************************/
 
1137
/*                        SetTargetLinearUnits()                        */
 
1138
/************************************************************************/
 
1139
 
 
1140
/**
 
1141
 * \brief Set the linear units for the projection.
 
1142
 *
 
1143
 * This method creates a UNIT subnode with the specified values as a
 
1144
 * child of the target node. 
 
1145
 *
 
1146
 * This method does the same as the C function OSRSetTargetLinearUnits(). 
 
1147
 *
 
1148
 * @param pszTargetKey the keyword to set the linear units for.  ie. "PROJCS" or "VERT_CS"
 
1149
 *
 
1150
 * @param pszUnitsName the units name to be used.  Some preferred units
 
1151
 * names can be found in ogr_srs_api.h such as SRS_UL_METER, SRS_UL_FOOT 
 
1152
 * and SRS_UL_US_FOOT. 
 
1153
 *
 
1154
 * @param dfInMeters the value to multiple by a length in the indicated
 
1155
 * units to transform to meters.  Some standard conversion factors can
 
1156
 * be found in ogr_srs_api.h. 
 
1157
 *
 
1158
 * @return OGRERR_NONE on success.
 
1159
 *
 
1160
 * @since OGR 1.9.0
 
1161
 */
 
1162
 
 
1163
OGRErr OGRSpatialReference::SetTargetLinearUnits( const char *pszTargetKey,
 
1164
                                                  const char * pszUnitsName,
 
1165
                                                  double dfInMeters )
 
1166
 
 
1167
{
 
1168
    OGR_SRSNode *poCS;
 
1169
    OGR_SRSNode *poUnits;
 
1170
    char        szValue[128];
 
1171
 
 
1172
    bNormInfoSet = FALSE;
 
1173
 
 
1174
    if( pszTargetKey == NULL )
 
1175
    {
 
1176
        poCS = GetAttrNode( "PROJCS" );
 
1177
 
 
1178
        if( poCS == NULL )
 
1179
            poCS = GetAttrNode( "LOCAL_CS" );
 
1180
        if( poCS == NULL )
 
1181
            poCS = GetAttrNode( "GEOCCS" );
 
1182
        if( poCS == NULL && IsVertical() )
 
1183
            poCS = GetAttrNode( "VERT_CS" );
 
1184
    }
 
1185
    else
 
1186
        poCS = GetAttrNode( pszTargetKey );
 
1187
 
 
1188
    if( poCS == NULL )
 
1189
        return OGRERR_FAILURE;
 
1190
 
 
1191
    if( dfInMeters == (int) dfInMeters )
 
1192
        sprintf( szValue, "%d", (int) dfInMeters );
 
1193
    else
 
1194
        OGRPrintDouble( szValue, dfInMeters );
 
1195
 
 
1196
    if( poCS->FindChild( "UNIT" ) >= 0 )
 
1197
    {
 
1198
        poUnits = poCS->GetChild( poCS->FindChild( "UNIT" ) );
 
1199
        if (poUnits->GetChildCount() < 2)
 
1200
            return OGRERR_FAILURE;
 
1201
        poUnits->GetChild(0)->SetValue( pszUnitsName );
 
1202
        poUnits->GetChild(1)->SetValue( szValue );
 
1203
        if( poUnits->FindChild( "AUTHORITY" ) != -1 )
 
1204
            poUnits->DestroyChild( poUnits->FindChild( "AUTHORITY" ) );
 
1205
    }
 
1206
    else
 
1207
    {
 
1208
        poUnits = new OGR_SRSNode( "UNIT" );
 
1209
        poUnits->AddChild( new OGR_SRSNode( pszUnitsName ) );
 
1210
        poUnits->AddChild( new OGR_SRSNode( szValue ) );
 
1211
        
 
1212
        poCS->AddChild( poUnits );
 
1213
    }
 
1214
 
 
1215
    return OGRERR_NONE;
 
1216
}
 
1217
 
 
1218
/************************************************************************/
 
1219
/*                         OSRSetLinearUnits()                          */
 
1220
/************************************************************************/
 
1221
 
 
1222
/**
 
1223
 * \brief Set the linear units for the target node.
 
1224
 *
 
1225
 * This function is the same as OGRSpatialReference::SetTargetLinearUnits()
 
1226
 *
 
1227
 * @since OGR 1.9.0
 
1228
 */
 
1229
OGRErr OSRSetTargetLinearUnits( OGRSpatialReferenceH hSRS, 
 
1230
                                const char *pszTargetKey,
 
1231
                                const char * pszUnits, double dfInMeters )
 
1232
 
 
1233
{
 
1234
    VALIDATE_POINTER1( hSRS, "OSRSetTargetLinearUnits", CE_Failure );
 
1235
 
 
1236
    return ((OGRSpatialReference *) hSRS)->
 
1237
        SetTargetLinearUnits( pszTargetKey, pszUnits, dfInMeters );
 
1238
}
 
1239
 
 
1240
/************************************************************************/
1146
1241
/*                           GetLinearUnits()                           */
1147
1242
/************************************************************************/
1148
1243
 
1150
1245
 * \brief Fetch linear projection units. 
1151
1246
 *
1152
1247
 * If no units are available, a value of "Meters" and 1.0 will be assumed.
1153
 
 * This method only checks directly under the PROJCS or LOCAL_CS node for 
1154
 
 * units.
 
1248
 * This method only checks directly under the PROJCS, GEOCCS or LOCAL_CS node 
 
1249
 * for units.
1155
1250
 *
1156
1251
 * This method does the same thing as the C function OSRGetLinearUnits()/
1157
1252
 *
1167
1262
double OGRSpatialReference::GetLinearUnits( char ** ppszName ) const
1168
1263
 
1169
1264
{
1170
 
    const OGR_SRSNode *poCS = GetAttrNode( "PROJCS" );
1171
 
 
1172
 
    if( poCS == NULL )
1173
 
        poCS = GetAttrNode( "LOCAL_CS" );
1174
 
 
1175
 
    if( ppszName != NULL )
1176
 
        *ppszName = (char*) "unknown";
1177
 
        
1178
 
    if( poCS == NULL )
1179
 
        return 1.0;
1180
 
 
1181
 
    for( int iChild = 0; iChild < poCS->GetChildCount(); iChild++ )
1182
 
    {
1183
 
        const OGR_SRSNode     *poChild = poCS->GetChild(iChild);
1184
 
        
1185
 
        if( EQUAL(poChild->GetValue(),"UNIT")
1186
 
            && poChild->GetChildCount() >= 2 )
1187
 
        {
1188
 
            if( ppszName != NULL )
1189
 
                *ppszName = (char *) poChild->GetChild(0)->GetValue();
1190
 
            
1191
 
            return CPLAtof( poChild->GetChild(1)->GetValue() );
1192
 
        }
1193
 
    }
1194
 
 
1195
 
    return 1.0;
 
1265
    return GetTargetLinearUnits( NULL, ppszName );
1196
1266
}
1197
1267
 
1198
1268
/************************************************************************/
1213
1283
}
1214
1284
 
1215
1285
/************************************************************************/
 
1286
/*                        GetTargetLinearUnits()                        */
 
1287
/************************************************************************/
 
1288
 
 
1289
/**
 
1290
 * \brief Fetch linear units for target. 
 
1291
 *
 
1292
 * If no units are available, a value of "Meters" and 1.0 will be assumed.
 
1293
 *
 
1294
 * This method does the same thing as the C function OSRGetTargetLinearUnits()/
 
1295
 *
 
1296
 * @param pszTargetKey the key to look on. ie. "PROJCS" or "VERT_CS".
 
1297
 * @param ppszName a pointer to be updated with the pointer to the 
 
1298
 * units name.  The returned value remains internal to the OGRSpatialReference
 
1299
 * and shouldn't be freed, or modified.  It may be invalidated on the next
 
1300
 * OGRSpatialReference call. 
 
1301
 *
 
1302
 * @return the value to multiply by linear distances to transform them to 
 
1303
 * meters.
 
1304
 *
 
1305
 * @since OGR 1.9.0
 
1306
 */
 
1307
 
 
1308
double OGRSpatialReference::GetTargetLinearUnits( const char *pszTargetKey,
 
1309
                                                  char ** ppszName ) const
 
1310
 
 
1311
{
 
1312
    const OGR_SRSNode *poCS;
 
1313
 
 
1314
    if( pszTargetKey == NULL )
 
1315
    {
 
1316
        poCS = GetAttrNode( "PROJCS" );
 
1317
 
 
1318
        if( poCS == NULL )
 
1319
            poCS = GetAttrNode( "LOCAL_CS" );
 
1320
        if( poCS == NULL )
 
1321
            poCS = GetAttrNode( "GEOCCS" );
 
1322
        if( poCS == NULL && IsVertical() )
 
1323
            poCS = GetAttrNode( "VERT_CS" );
 
1324
    }
 
1325
    else
 
1326
        poCS = GetAttrNode( pszTargetKey );
 
1327
 
 
1328
    if( ppszName != NULL )
 
1329
        *ppszName = (char*) "unknown";
 
1330
        
 
1331
    if( poCS == NULL )
 
1332
        return 1.0;
 
1333
 
 
1334
    for( int iChild = 0; iChild < poCS->GetChildCount(); iChild++ )
 
1335
    {
 
1336
        const OGR_SRSNode     *poChild = poCS->GetChild(iChild);
 
1337
        
 
1338
        if( EQUAL(poChild->GetValue(),"UNIT")
 
1339
            && poChild->GetChildCount() >= 2 )
 
1340
        {
 
1341
            if( ppszName != NULL )
 
1342
                *ppszName = (char *) poChild->GetChild(0)->GetValue();
 
1343
            
 
1344
            return CPLAtof( poChild->GetChild(1)->GetValue() );
 
1345
        }
 
1346
    }
 
1347
 
 
1348
    return 1.0;
 
1349
}
 
1350
 
 
1351
/************************************************************************/
 
1352
/*                      OSRGetTargetLinearUnits()                       */
 
1353
/************************************************************************/
 
1354
 
 
1355
/**
 
1356
 * \brief Fetch linear projection units. 
 
1357
 *
 
1358
 * This function is the same as OGRSpatialReference::GetTargetLinearUnits()
 
1359
 *
 
1360
 * @since OGR 1.9.0
 
1361
 */
 
1362
double OSRGetTargetLinearUnits( OGRSpatialReferenceH hSRS, 
 
1363
                                const char *pszTargetKey, 
 
1364
                                char ** ppszName )
 
1365
    
 
1366
{
 
1367
    VALIDATE_POINTER1( hSRS, "OSRGetTargetLinearUnits", 0 );
 
1368
 
 
1369
    return ((OGRSpatialReference *) hSRS)->GetTargetLinearUnits( pszTargetKey,
 
1370
                                                                 ppszName );
 
1371
}
 
1372
 
 
1373
/************************************************************************/
1216
1374
/*                          GetPrimeMeridian()                          */
1217
1375
/************************************************************************/
1218
1376
 
1332
1490
    bNormInfoSet = FALSE;
1333
1491
 
1334
1492
/* -------------------------------------------------------------------- */
 
1493
/*      For a geocentric coordinate system we want to set the datum     */
 
1494
/*      and ellipsoid based on the GEOGCS.  Create the GEOGCS in a      */
 
1495
/*      temporary srs and use the copy method which has special         */
 
1496
/*      handling for GEOCCS.                                            */
 
1497
/* -------------------------------------------------------------------- */
 
1498
    if( IsGeocentric() )
 
1499
    {
 
1500
        OGRSpatialReference oGCS;
 
1501
 
 
1502
        oGCS.SetGeogCS( pszGeogName, pszDatumName, pszSpheroidName,
 
1503
                        dfSemiMajor, dfInvFlattening, 
 
1504
                        pszPMName, dfPMOffset, 
 
1505
                        pszAngularUnits, dfConvertToRadians );
 
1506
        return CopyGeogCSFrom( &oGCS );
 
1507
    }        
 
1508
 
 
1509
/* -------------------------------------------------------------------- */
1335
1510
/*      Do we already have a GEOGCS?  If so, blow it away so it can     */
1336
1511
/*      be properly replaced.                                           */
1337
1512
/* -------------------------------------------------------------------- */
1338
1513
    if( GetAttrNode( "GEOGCS" ) != NULL )
1339
1514
    {
1340
 
        OGR_SRSNode *poPROJCS;
 
1515
        OGR_SRSNode *poCS;
1341
1516
 
1342
1517
        if( EQUAL(GetRoot()->GetValue(),"GEOGCS") )
1343
1518
            Clear();
1344
 
        else if( (poPROJCS = GetAttrNode( "PROJCS" )) != NULL
1345
 
                 && poPROJCS->FindChild( "GEOGCS" ) != -1 )
1346
 
            poPROJCS->DestroyChild( poPROJCS->FindChild( "GEOGCS" ) );
 
1519
        else if( (poCS = GetAttrNode( "PROJCS" )) != NULL
 
1520
                 && poCS->FindChild( "GEOGCS" ) != -1 )
 
1521
            poCS->DestroyChild( poCS->FindChild( "GEOGCS" ) );
1347
1522
        else
1348
1523
            return OGRERR_FAILURE;
1349
1524
    }
1532
1707
/* -------------------------------------------------------------------- */
1533
1708
    char        *pszWKT = NULL;
1534
1709
 
1535
 
    if( EQUAL(pszName, "WGS84") || EQUAL(pszName,"CRS84") )
 
1710
    if( EQUAL(pszName, "WGS84") || EQUAL(pszName,"CRS84") || EQUAL(pszName,"CRS:84") )
1536
1711
        pszWKT = (char* ) SRS_WKT_WGS84;
1537
1712
 
1538
1713
    else if( EQUAL(pszName, "WGS72") )
1539
1714
        pszWKT = (char* ) "GEOGCS[\"WGS 72\",DATUM[\"WGS_1972\",SPHEROID[\"WGS 72\",6378135,298.26,AUTHORITY[\"EPSG\",\"7043\"]],TOWGS84[0,0,4.5,0,0,0.554,0.2263],AUTHORITY[\"EPSG\",\"6322\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AUTHORITY[\"EPSG\",\"4322\"]]";
1540
1715
 
1541
 
    else if( EQUAL(pszName, "NAD27") || EQUAL(pszName, "CRS27") )
1542
 
        pszWKT = (char* ) "GEOGCS[\"NAD27\",DATUM[\"North_American_Datum_1927\",SPHEROID[\"Clarke 1866\",6378206.4,294.978698213898,AUTHORITY[\"EPSG\",\"7008\"]],TOWGS84[-3,142,183,0,0,0,0],AUTHORITY[\"EPSG\",\"6267\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AUTHORITY[\"EPSG\",\"4267\"]]";
 
1716
    else if( EQUAL(pszName, "NAD27") || EQUAL(pszName, "CRS27") || EQUAL(pszName,"CRS:27") )
 
1717
        pszWKT = (char* ) "GEOGCS[\"NAD27\",DATUM[\"North_American_Datum_1927\",SPHEROID[\"Clarke 1866\",6378206.4,294.978698213898,AUTHORITY[\"EPSG\",\"7008\"]],AUTHORITY[\"EPSG\",\"6267\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AUTHORITY[\"EPSG\",\"4267\"]]";
1543
1718
        
1544
 
    else if( EQUAL(pszName, "NAD83") || EQUAL(pszName,"CRS83") )
 
1719
    else if( EQUAL(pszName, "NAD83") || EQUAL(pszName,"CRS83") || EQUAL(pszName,"CRS:83") )
1545
1720
        pszWKT = (char* ) "GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6269\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AUTHORITY[\"EPSG\",\"4269\"]]";
1546
1721
 
1547
1722
    else
1603
1778
    bNormInfoSet = FALSE;
1604
1779
 
1605
1780
/* -------------------------------------------------------------------- */
 
1781
/*      Handle geocentric coordinate systems specially.  We just        */
 
1782
/*      want to copy the DATUM and PRIMEM nodes.                        */
 
1783
/* -------------------------------------------------------------------- */
 
1784
    if( IsGeocentric() )
 
1785
    {
 
1786
        if( GetRoot()->FindChild( "DATUM" ) != -1 )
 
1787
            GetRoot()->DestroyChild( GetRoot()->FindChild( "DATUM" ) );
 
1788
        if( GetRoot()->FindChild( "PRIMEM" ) != -1 )
 
1789
            GetRoot()->DestroyChild( GetRoot()->FindChild( "PRIMEM" ) );
 
1790
 
 
1791
        const OGR_SRSNode *poDatum = poSrcSRS->GetAttrNode( "DATUM" );
 
1792
        const OGR_SRSNode *poPrimeM = poSrcSRS->GetAttrNode( "PRIMEM" );
 
1793
 
 
1794
        if( poDatum == NULL || poPrimeM == NULL )
 
1795
            return OGRERR_FAILURE;
 
1796
        
 
1797
        poRoot->InsertChild( poDatum->Clone(), 1 );
 
1798
        poRoot->InsertChild( poPrimeM->Clone(), 2 );
 
1799
 
 
1800
        return OGRERR_NONE;
 
1801
        
 
1802
    }
 
1803
 
 
1804
/* -------------------------------------------------------------------- */
1606
1805
/*      Do we already have a GEOGCS?  If so, blow it away so it can     */
1607
1806
/*      be properly replaced.                                           */
1608
1807
/* -------------------------------------------------------------------- */
1680
1879
 * WGS84 or WGS72. 
1681
1880
 * <li> WKT (directly or in a file) in ESRI format should be prefixed with
1682
1881
 * ESRI:: to trigger an automatic morphFromESRI().
 
1882
 * <li> "IGNF:xxx" - "+init=IGNF:xxx" passed on to importFromProj4().
1683
1883
 * </ol>
1684
1884
 *
1685
1885
 * It is expected that this method will be extended in the future to support
1717
1917
/* -------------------------------------------------------------------- */
1718
1918
    if( EQUALN(pszDefinition,"PROJCS",6)
1719
1919
        || EQUALN(pszDefinition,"GEOGCS",6)
1720
 
        || EQUALN(pszDefinition,"COMPD_CS",6)
 
1920
        || EQUALN(pszDefinition,"COMPD_CS",8)
 
1921
        || EQUALN(pszDefinition,"GEOCCS",6)
 
1922
        || EQUALN(pszDefinition,"VERT_CS",7)
1721
1923
        || EQUALN(pszDefinition,"LOCAL_CS",8) )
1722
1924
    {
1723
1925
        err = importFromWkt( (char **) &pszDefinition );
1727
1929
        return err;
1728
1930
    }
1729
1931
 
1730
 
    if( EQUALN(pszDefinition,"EPSG:",5) )
1731
 
        return importFromEPSG( atoi(pszDefinition+5) );
1732
 
 
1733
 
    if( EQUALN(pszDefinition,"EPSGA:",6) )
1734
 
        return importFromEPSGA( atoi(pszDefinition+6) );
1735
 
 
1736
 
    if( EQUALN(pszDefinition,"urn:ogc:def:crs:",16) 
1737
 
        || EQUALN(pszDefinition,"urn:x-ogc:def:crs:",18) )
 
1932
    if( EQUALN(pszDefinition,"EPSG:",5) 
 
1933
        || EQUALN(pszDefinition,"EPSGA:",6) )
 
1934
    {
 
1935
        OGRErr eStatus; 
 
1936
 
 
1937
        if( EQUALN(pszDefinition,"EPSG:",5) )
 
1938
            eStatus = importFromEPSG( atoi(pszDefinition+5) );
 
1939
        
 
1940
        else /* if( EQUALN(pszDefinition,"EPSGA:",6) ) */
 
1941
            eStatus = importFromEPSGA( atoi(pszDefinition+6) );
 
1942
        
 
1943
        // Do we want to turn this into a compound definition
 
1944
        // with a vertical datum?
 
1945
        if( eStatus == OGRERR_NONE && strchr( pszDefinition, '+' ) != NULL )
 
1946
        {
 
1947
            OGRSpatialReference oVertSRS;
 
1948
 
 
1949
            eStatus = oVertSRS.importFromEPSG( 
 
1950
                atoi(strchr(pszDefinition,'+')+1) );
 
1951
            if( eStatus == OGRERR_NONE )
 
1952
            {
 
1953
                OGR_SRSNode *poHorizSRS = GetRoot()->Clone();
 
1954
 
 
1955
                Clear();
 
1956
 
 
1957
                CPLString osName = poHorizSRS->GetChild(0)->GetValue();
 
1958
                osName += " + ";
 
1959
                osName += oVertSRS.GetRoot()->GetValue();
 
1960
 
 
1961
                SetNode( "COMPD_CS", osName );
 
1962
                GetRoot()->AddChild( poHorizSRS );
 
1963
                GetRoot()->AddChild( oVertSRS.GetRoot()->Clone() );
 
1964
            }
 
1965
            
 
1966
            return eStatus;
 
1967
        }
 
1968
        else
 
1969
            return eStatus;
 
1970
    }
 
1971
 
 
1972
    if( EQUALN(pszDefinition,"urn:ogc:def:crs:",16)
 
1973
        || EQUALN(pszDefinition,"urn:ogc:def:crs,crs:",20)
 
1974
        || EQUALN(pszDefinition,"urn:x-ogc:def:crs:",18)
 
1975
        || EQUALN(pszDefinition,"urn:opengis:crs:",16)
 
1976
        || EQUALN(pszDefinition,"urn:opengis:def:crs:",20))
1738
1977
        return importFromURN( pszDefinition );
1739
1978
 
1740
1979
    if( EQUALN(pszDefinition,"AUTO:",5) )
1743
1982
    if( EQUALN(pszDefinition,"OGC:",4) )  // WMS/WCS OGC codes like OGC:CRS84
1744
1983
        return SetWellKnownGeogCS( pszDefinition+4 );
1745
1984
 
 
1985
    if( EQUALN(pszDefinition,"CRS:",4) )
 
1986
        return SetWellKnownGeogCS( pszDefinition );
 
1987
 
1746
1988
    if( EQUALN(pszDefinition,"DICT:",5) 
1747
1989
        && strstr(pszDefinition,",") )
1748
1990
    {
1773
2015
             || strstr(pszDefinition,"+init") != NULL )
1774
2016
        return importFromProj4( pszDefinition );
1775
2017
 
 
2018
    if( EQUALN(pszDefinition,"IGNF:", 5) )
 
2019
    {
 
2020
        char* pszProj4Str = (char*) CPLMalloc(6 + strlen(pszDefinition) + 1);
 
2021
        strcpy(pszProj4Str, "+init=");
 
2022
        strcat(pszProj4Str, pszDefinition);
 
2023
        err = importFromProj4( pszProj4Str );
 
2024
        CPLFree(pszProj4Str);
 
2025
 
 
2026
        return err;
 
2027
    }
 
2028
 
1776
2029
    if( EQUALN(pszDefinition,"http://",7) )
1777
2030
    {
1778
2031
        return importFromUrl (pszDefinition);
1779
2032
    }
 
2033
 
 
2034
    if( EQUAL(pszDefinition,"osgb:BNG") )
 
2035
    {
 
2036
        return importFromEPSG(27700);
 
2037
    }
 
2038
 
1780
2039
/* -------------------------------------------------------------------- */
1781
2040
/*      Try to open it as a file.                                       */
1782
2041
/* -------------------------------------------------------------------- */
1961
2220
}
1962
2221
 
1963
2222
/************************************************************************/
1964
 
/*                           importFromURN()                            */
1965
 
/*                                                                      */
1966
 
/*      See OGC recommendation paper 06-023r1 or later for details.     */
 
2223
/*                         importFromURNPart()                          */
1967
2224
/************************************************************************/
1968
 
 
1969
 
/**
1970
 
 * \brief Initialize from OGC URN. 
1971
 
 *
1972
 
 * Initializes this spatial reference from a coordinate system defined
1973
 
 * by an OGC URN prefixed with "urn:ogc:def:crs:" per recommendation 
1974
 
 * paper 06-023r1.  Currently EPSG and OGC authority values are supported, 
1975
 
 * including OGC auto codes, but not including CRS1 or CRS88 (NAVD88). 
1976
 
 *
1977
 
 * This method is also support through SetFromUserInput() which can
1978
 
 * normally be used for URNs.
1979
 
 * 
1980
 
 * @param pszURN the urn string. 
1981
 
 *
1982
 
 * @return OGRERR_NONE on success or an error code.
1983
 
 */
1984
 
 
1985
 
OGRErr OGRSpatialReference::importFromURN( const char *pszURN )
1986
 
 
 
2225
OGRErr OGRSpatialReference::importFromURNPart(const char* pszAuthority,
 
2226
                                              const char* pszCode,
 
2227
                                              const char* pszURN)
1987
2228
{
1988
 
    const char *pszCur = pszURN + 16;
1989
 
 
1990
 
    if( EQUALN(pszURN,"urn:ogc:def:crs:",16) )
1991
 
        pszCur = pszURN + 16;
1992
 
    else if( EQUALN(pszURN,"urn:x-ogc:def:crs:",18) )
1993
 
        pszCur = pszURN + 18;
1994
 
    else
1995
 
    {
1996
 
        CPLError( CE_Failure, CPLE_AppDefined, 
1997
 
                  "URN %s not a supported format.", pszURN );
1998
 
        return OGRERR_FAILURE;
1999
 
    }
2000
 
 
2001
 
/* -------------------------------------------------------------------- */
2002
 
/*      Clear any existing definition.                                  */
2003
 
/* -------------------------------------------------------------------- */
2004
 
    if( GetRoot() != NULL )
2005
 
    {
2006
 
        delete poRoot;
2007
 
        poRoot = NULL;
2008
 
    }
2009
 
 
2010
 
/* -------------------------------------------------------------------- */
2011
 
/*      Find code (ignoring version) out of string like:                */
2012
 
/*                                                                      */
2013
 
/*      authority:version:code                                          */
2014
 
/* -------------------------------------------------------------------- */
2015
 
    const char *pszAuthority = pszCur;
2016
 
 
2017
 
    // skip authority
2018
 
    while( *pszCur != ':' && *pszCur )
2019
 
        pszCur++;
2020
 
    if( *pszCur == ':' )
2021
 
        pszCur++;
2022
 
 
2023
 
    // skip version
2024
 
    while( *pszCur != ':' && *pszCur )
2025
 
        pszCur++;
2026
 
    if( *pszCur == ':' )
2027
 
        pszCur++;
2028
 
 
2029
 
    const char *pszCode = pszCur;
2030
2229
 
2031
2230
/* -------------------------------------------------------------------- */
2032
2231
/*      Is this an EPSG code? Note that we import it with EPSG          */
2046
2245
/* -------------------------------------------------------------------- */
2047
2246
    if( !EQUALN(pszAuthority,"OGC:",4) )
2048
2247
    {
2049
 
        CPLError( CE_Failure, CPLE_AppDefined, 
2050
 
                  "URN %s has unrecognised authority.", 
 
2248
        CPLError( CE_Failure, CPLE_AppDefined,
 
2249
                  "URN %s has unrecognised authority.",
2051
2250
                  pszURN );
2052
2251
        return OGRERR_FAILURE;
2053
2252
    }
2085
2284
/* -------------------------------------------------------------------- */
2086
2285
/*      Not a recognise OGC item.                                       */
2087
2286
/* -------------------------------------------------------------------- */
2088
 
    CPLError( CE_Failure, CPLE_AppDefined, 
2089
 
              "URN %s value not supported.", 
 
2287
    CPLError( CE_Failure, CPLE_AppDefined,
 
2288
              "URN %s value not supported.",
2090
2289
              pszURN );
2091
2290
 
2092
2291
    return OGRERR_FAILURE;
2093
2292
}
2094
2293
 
2095
2294
/************************************************************************/
 
2295
/*                           importFromURN()                            */
 
2296
/*                                                                      */
 
2297
/*      See OGC recommendation paper 06-023r1 or later for details.     */
 
2298
/************************************************************************/
 
2299
 
 
2300
/**
 
2301
 * \brief Initialize from OGC URN. 
 
2302
 *
 
2303
 * Initializes this spatial reference from a coordinate system defined
 
2304
 * by an OGC URN prefixed with "urn:ogc:def:crs:" per recommendation 
 
2305
 * paper 06-023r1.  Currently EPSG and OGC authority values are supported, 
 
2306
 * including OGC auto codes, but not including CRS1 or CRS88 (NAVD88). 
 
2307
 *
 
2308
 * This method is also support through SetFromUserInput() which can
 
2309
 * normally be used for URNs.
 
2310
 * 
 
2311
 * @param pszURN the urn string. 
 
2312
 *
 
2313
 * @return OGRERR_NONE on success or an error code.
 
2314
 */
 
2315
 
 
2316
OGRErr OGRSpatialReference::importFromURN( const char *pszURN )
 
2317
 
 
2318
{
 
2319
    const char *pszCur;
 
2320
 
 
2321
    if( EQUALN(pszURN,"urn:ogc:def:crs:",16) )
 
2322
        pszCur = pszURN + 16;
 
2323
    else if( EQUALN(pszURN,"urn:ogc:def:crs,crs:",20) )
 
2324
        pszCur = pszURN + 20;
 
2325
    else if( EQUALN(pszURN,"urn:x-ogc:def:crs:",18) )
 
2326
        pszCur = pszURN + 18;
 
2327
    else if( EQUALN(pszURN,"urn:opengis:crs:",16) )
 
2328
        pszCur = pszURN + 16;
 
2329
    else if( EQUALN(pszURN,"urn:opengis:def:crs:",20) )
 
2330
        pszCur = pszURN + 20;
 
2331
    else
 
2332
    {
 
2333
        CPLError( CE_Failure, CPLE_AppDefined, 
 
2334
                  "URN %s not a supported format.", pszURN );
 
2335
        return OGRERR_FAILURE;
 
2336
    }
 
2337
 
 
2338
/* -------------------------------------------------------------------- */
 
2339
/*      Clear any existing definition.                                  */
 
2340
/* -------------------------------------------------------------------- */
 
2341
    if( GetRoot() != NULL )
 
2342
    {
 
2343
        delete poRoot;
 
2344
        poRoot = NULL;
 
2345
    }
 
2346
 
 
2347
/* -------------------------------------------------------------------- */
 
2348
/*      Find code (ignoring version) out of string like:                */
 
2349
/*                                                                      */
 
2350
/*      authority:[version]:code                                        */
 
2351
/* -------------------------------------------------------------------- */
 
2352
    const char *pszAuthority = pszCur;
 
2353
 
 
2354
    // skip authority
 
2355
    while( *pszCur != ':' && *pszCur )
 
2356
        pszCur++;
 
2357
    if( *pszCur == ':' )
 
2358
        pszCur++;
 
2359
 
 
2360
    // skip version
 
2361
    const char* pszBeforeVersion = pszCur;
 
2362
    while( *pszCur != ':' && *pszCur )
 
2363
        pszCur++;
 
2364
    if( *pszCur == ':' )
 
2365
        pszCur++;
 
2366
    else
 
2367
        /* We come here in the case, the content to parse is authority:code (instead of authority::code) */
 
2368
        /* which is probably illegal according to http://www.opengeospatial.org/ogcUrnPolicy */
 
2369
        /* but such content is found for example in what is returned by GeoServer */
 
2370
        pszCur = pszBeforeVersion;
 
2371
 
 
2372
    const char *pszCode = pszCur;
 
2373
 
 
2374
    const char* pszComma = strchr(pszCur, ',');
 
2375
    if (pszComma == NULL)
 
2376
        return importFromURNPart(pszAuthority, pszCode, pszURN);
 
2377
 
 
2378
 
 
2379
    /* There's a second part with the vertical SRS */
 
2380
    pszCur = pszComma + 1;
 
2381
    if (strncmp(pszCur, "crs:", 4) != 0)
 
2382
    {
 
2383
        CPLError( CE_Failure, CPLE_AppDefined,
 
2384
                  "URN %s not a supported format.", pszURN );
 
2385
        return OGRERR_FAILURE;
 
2386
    }
 
2387
 
 
2388
    pszCur += 4;
 
2389
 
 
2390
    char* pszFirstCode = CPLStrdup(pszCode);
 
2391
    pszFirstCode[pszComma - pszCode] = '\0';
 
2392
    OGRErr eStatus = importFromURNPart(pszAuthority, pszFirstCode, pszURN);
 
2393
    CPLFree(pszFirstCode);
 
2394
 
 
2395
    // Do we want to turn this into a compound definition
 
2396
    // with a vertical datum?
 
2397
    if( eStatus == OGRERR_NONE )
 
2398
    {
 
2399
        OGRSpatialReference oVertSRS;
 
2400
 
 
2401
    /* -------------------------------------------------------------------- */
 
2402
    /*      Find code (ignoring version) out of string like:                */
 
2403
    /*                                                                      */
 
2404
    /*      authority:[version]:code                                        */
 
2405
    /* -------------------------------------------------------------------- */
 
2406
        pszAuthority = pszCur;
 
2407
 
 
2408
        // skip authority
 
2409
        while( *pszCur != ':' && *pszCur )
 
2410
            pszCur++;
 
2411
        if( *pszCur == ':' )
 
2412
            pszCur++;
 
2413
 
 
2414
        // skip version
 
2415
        pszBeforeVersion = pszCur;
 
2416
        while( *pszCur != ':' && *pszCur )
 
2417
            pszCur++;
 
2418
        if( *pszCur == ':' )
 
2419
            pszCur++;
 
2420
        else
 
2421
            pszCur = pszBeforeVersion;
 
2422
 
 
2423
        pszCode = pszCur;
 
2424
 
 
2425
        eStatus = oVertSRS.importFromURNPart(pszAuthority, pszCode, pszURN);
 
2426
        if( eStatus == OGRERR_NONE )
 
2427
        {
 
2428
            OGR_SRSNode *poHorizSRS = GetRoot()->Clone();
 
2429
 
 
2430
            Clear();
 
2431
 
 
2432
            CPLString osName = poHorizSRS->GetChild(0)->GetValue();
 
2433
            osName += " + ";
 
2434
            osName += oVertSRS.GetRoot()->GetValue();
 
2435
 
 
2436
            SetNode( "COMPD_CS", osName );
 
2437
            GetRoot()->AddChild( poHorizSRS );
 
2438
            GetRoot()->AddChild( oVertSRS.GetRoot()->Clone() );
 
2439
        }
 
2440
 
 
2441
        return eStatus;
 
2442
    }
 
2443
    else
 
2444
        return eStatus;
 
2445
}
 
2446
 
 
2447
/************************************************************************/
2096
2448
/*                         importFromWMSAUTO()                          */
2097
2449
/************************************************************************/
2098
2450
 
2395
2747
 *
2396
2748
 * This method is the same as the C function OSRSetLocalCS(). 
2397
2749
 *
2398
 
 * This method is will ensure a LOCAL_CS node is created as the root, 
 
2750
 * This method will ensure a LOCAL_CS node is created as the root,
2399
2751
 * and set the provided name on it.  It must be used before SetLinearUnits().
2400
2752
 *
2401
2753
 * @param pszName the user visible name to assign.  Not used as a key.
2441
2793
}
2442
2794
 
2443
2795
/************************************************************************/
 
2796
/*                             SetGeocCS()                              */
 
2797
/************************************************************************/
 
2798
 
 
2799
/**
 
2800
 * \brief Set the user visible GEOCCS name.
 
2801
 *
 
2802
 * This method is the same as the C function OSRSetGeocCS(). 
 
2803
 
 
2804
 * This method will ensure a GEOCCS node is created as the root,
 
2805
 * and set the provided name on it.  If used on a GEOGCS coordinate system, 
 
2806
 * the DATUM and PRIMEM nodes from the GEOGCS will be tarnsferred over to 
 
2807
 * the GEOGCS. 
 
2808
 *
 
2809
 * @param pszName the user visible name to assign.  Not used as a key.
 
2810
 * 
 
2811
 * @return OGRERR_NONE on success.
 
2812
 *
 
2813
 * @since OGR 1.9.0
 
2814
 */
 
2815
 
 
2816
OGRErr OGRSpatialReference::SetGeocCS( const char * pszName )
 
2817
 
 
2818
{
 
2819
    OGR_SRSNode *poGeogCS = NULL;
 
2820
    OGR_SRSNode *poGeocCS = GetAttrNode( "GEOCCS" );
 
2821
 
 
2822
    if( poRoot != NULL && EQUAL(poRoot->GetValue(),"GEOGCS") )
 
2823
    {
 
2824
        poGeogCS = poRoot;
 
2825
        poRoot = NULL;
 
2826
    }
 
2827
 
 
2828
    if( poGeocCS == NULL && GetRoot() != NULL )
 
2829
    {
 
2830
        CPLDebug( "OGR", 
 
2831
                  "OGRSpatialReference::SetGeocCS(%s) failed.\n"
 
2832
               "It appears an incompatible root node (%s) already exists.\n",
 
2833
                  pszName, GetRoot()->GetValue() );
 
2834
        return OGRERR_FAILURE;
 
2835
    }
 
2836
 
 
2837
    SetNode( "GEOCCS", pszName );
 
2838
 
 
2839
    if( poGeogCS != NULL )
 
2840
    {
 
2841
        OGR_SRSNode *poDatum = poGeogCS->GetNode( "DATUM" );
 
2842
        OGR_SRSNode *poPRIMEM = poGeogCS->GetNode( "PRIMEM" );
 
2843
        if ( poDatum != NULL && poPRIMEM != NULL )
 
2844
        {
 
2845
            poRoot->InsertChild( poDatum->Clone(), 1 );
 
2846
            poRoot->InsertChild( poPRIMEM->Clone(), 2 );
 
2847
        }
 
2848
        delete poGeogCS;
 
2849
    }
 
2850
 
 
2851
    return OGRERR_NONE;
 
2852
}
 
2853
 
 
2854
/************************************************************************/
 
2855
/*                            OSRSetGeocCS()                            */
 
2856
/************************************************************************/
 
2857
 
 
2858
/**
 
2859
 * \brief Set the user visible PROJCS name.
 
2860
 *
 
2861
 * This function is the same as OGRSpatialReference::SetGeocCS()
 
2862
 *
 
2863
 * @since OGR 1.9.0
 
2864
 */
 
2865
OGRErr OSRSetGeocCS( OGRSpatialReferenceH hSRS, const char * pszName )
 
2866
 
 
2867
{
 
2868
    VALIDATE_POINTER1( hSRS, "OSRSetGeocCS", CE_Failure );
 
2869
 
 
2870
    return ((OGRSpatialReference *) hSRS)->SetGeocCS( pszName );
 
2871
}
 
2872
 
 
2873
/************************************************************************/
 
2874
/*                             SetVertCS()                              */
 
2875
/************************************************************************/
 
2876
 
 
2877
/**
 
2878
 * \brief Set the user visible VERT_CS name.
 
2879
 *
 
2880
 * This method is the same as the C function OSRSetVertCS(). 
 
2881
 
 
2882
 * This method will ensure a VERT_CS node is created if needed.  If the
 
2883
 * existing coordinate system is GEOGCS or PROJCS rooted, then it will be
 
2884
 * turned into a COMPD_CS.
 
2885
 *
 
2886
 * @param pszVertCSName the user visible name of the vertical coordinate
 
2887
 * system. Not used as a key.
 
2888
 *  
 
2889
 * @param pszVertDatumName the user visible name of the vertical datum.  It
 
2890
 * is helpful if this matches the EPSG name.
 
2891
 * 
 
2892
 * @param nVertDatumType the OGC vertical datum type, usually 2005. 
 
2893
 * 
 
2894
 * @return OGRERR_NONE on success.
 
2895
 *
 
2896
 * @since OGR 1.9.0
 
2897
 */
 
2898
 
 
2899
OGRErr OGRSpatialReference::SetVertCS( const char * pszVertCSName,
 
2900
                                       const char * pszVertDatumName,
 
2901
                                       int nVertDatumType )
 
2902
 
 
2903
{
 
2904
/* -------------------------------------------------------------------- */
 
2905
/*      Handle the case where we want to make a compound coordinate     */
 
2906
/*      system.                                                         */
 
2907
/* -------------------------------------------------------------------- */
 
2908
    if( IsProjected() || IsGeographic() )
 
2909
    {
 
2910
        OGR_SRSNode *poNewRoot = new OGR_SRSNode( "COMPD_CS" );
 
2911
        poNewRoot->AddChild( poRoot );
 
2912
        poRoot = poNewRoot;
 
2913
    }
 
2914
 
 
2915
    else if( GetAttrNode( "VERT_CS" ) == NULL )
 
2916
        Clear();
 
2917
 
 
2918
/* -------------------------------------------------------------------- */
 
2919
/*      If we already have a VERT_CS, wipe and recreate the root        */
 
2920
/*      otherwise create the VERT_CS now.                               */
 
2921
/* -------------------------------------------------------------------- */
 
2922
    OGR_SRSNode *poVertCS = GetAttrNode( "VERT_CS" );
 
2923
    
 
2924
    if( poVertCS != NULL )
 
2925
    {
 
2926
        poVertCS->ClearChildren();
 
2927
    }
 
2928
    else
 
2929
    {
 
2930
        poVertCS = new OGR_SRSNode( "VERT_CS" );
 
2931
        if( poRoot != NULL && EQUAL(poRoot->GetValue(),"COMPD_CS") )
 
2932
        {
 
2933
            poRoot->AddChild( poVertCS );
 
2934
        }
 
2935
        else
 
2936
            SetRoot( poVertCS );
 
2937
    }
 
2938
 
 
2939
/* -------------------------------------------------------------------- */
 
2940
/*      Set the name, datumname, and type.                              */
 
2941
/* -------------------------------------------------------------------- */
 
2942
    OGR_SRSNode *poVertDatum;
 
2943
 
 
2944
    poVertCS->AddChild( new OGR_SRSNode( pszVertCSName ) );
 
2945
    
 
2946
    poVertDatum = new OGR_SRSNode( "VERT_DATUM" );
 
2947
    poVertCS->AddChild( poVertDatum );
 
2948
        
 
2949
    poVertDatum->AddChild( new OGR_SRSNode( pszVertDatumName ) );
 
2950
 
 
2951
    CPLString osVertDatumType;
 
2952
    osVertDatumType.Printf( "%d", nVertDatumType );
 
2953
    poVertDatum->AddChild( new OGR_SRSNode( osVertDatumType ) );
 
2954
 
 
2955
    // add default axis node.
 
2956
    OGR_SRSNode *poAxis = new OGR_SRSNode( "AXIS" );
 
2957
 
 
2958
    poAxis->AddChild( new OGR_SRSNode( "Up" ) );
 
2959
    poAxis->AddChild( new OGR_SRSNode( "UP" ) );
 
2960
 
 
2961
    poVertCS->AddChild( poAxis );
 
2962
 
 
2963
    return OGRERR_NONE;
 
2964
}
 
2965
 
 
2966
/************************************************************************/
 
2967
/*                            OSRSetVertCS()                            */
 
2968
/************************************************************************/
 
2969
 
 
2970
/**
 
2971
 * \brief Setup the vertical coordinate system.
 
2972
 *
 
2973
 * This function is the same as OGRSpatialReference::SetVertCS()
 
2974
 *
 
2975
 * @since OGR 1.9.0
 
2976
 */
 
2977
OGRErr OSRSetVertCS( OGRSpatialReferenceH hSRS,
 
2978
                     const char * pszVertCSName,
 
2979
                     const char * pszVertDatumName,
 
2980
                     int nVertDatumType )
 
2981
 
 
2982
{
 
2983
    VALIDATE_POINTER1( hSRS, "OSRSetVertCS", CE_Failure );
 
2984
 
 
2985
    return ((OGRSpatialReference *) hSRS)->SetVertCS( pszVertCSName,
 
2986
                                                      pszVertDatumName,
 
2987
                                                      nVertDatumType );
 
2988
}
 
2989
 
 
2990
/************************************************************************/
 
2991
/*                           SetCompoundCS()                            */
 
2992
/************************************************************************/
 
2993
 
 
2994
/**
 
2995
 * \brief Setup a compound coordinate system.
 
2996
 *
 
2997
 * This method is the same as the C function OSRSetCompoundCS(). 
 
2998
 
 
2999
 * This method is replace the current SRS with a COMPD_CS coordinate system
 
3000
 * consisting of the passed in horizontal and vertical coordinate systems.
 
3001
 *
 
3002
 * @param pszName the name of the compound coordinate system. 
 
3003
 * 
 
3004
 * @param poHorizSRS the horizontal SRS (PROJCS or GEOGCS).
 
3005
 *  
 
3006
 * @param poVertSRS the vertical SRS (VERT_CS).
 
3007
 * 
 
3008
 * @return OGRERR_NONE on success.
 
3009
 */
 
3010
 
 
3011
OGRErr 
 
3012
OGRSpatialReference::SetCompoundCS( const char *pszName,
 
3013
                                    const OGRSpatialReference *poHorizSRS,
 
3014
                                    const OGRSpatialReference *poVertSRS )
 
3015
 
 
3016
{
 
3017
/* -------------------------------------------------------------------- */
 
3018
/*      Verify these are legal horizontal and vertical coordinate       */
 
3019
/*      systems.                                                        */
 
3020
/* -------------------------------------------------------------------- */
 
3021
    if( !poVertSRS->IsVertical() ) 
 
3022
    {
 
3023
        CPLError( CE_Failure, CPLE_AppDefined, 
 
3024
                  "SetCompoundCS() fails, vertical component is not VERT_CS." );
 
3025
        return OGRERR_FAILURE;
 
3026
    }
 
3027
    if( !poHorizSRS->IsProjected() 
 
3028
        && !poHorizSRS->IsGeographic() )
 
3029
    {
 
3030
        CPLError( CE_Failure, CPLE_AppDefined, 
 
3031
                  "SetCompoundCS() fails, horizontal component is not PROJCS or GEOGCS." );
 
3032
        return OGRERR_FAILURE;
 
3033
    }
 
3034
 
 
3035
/* -------------------------------------------------------------------- */
 
3036
/*      Replace with compound srs.                                      */
 
3037
/* -------------------------------------------------------------------- */
 
3038
    Clear();
 
3039
 
 
3040
    poRoot = new OGR_SRSNode( "COMPD_CS" );
 
3041
    poRoot->AddChild( new OGR_SRSNode( pszName ) );
 
3042
    poRoot->AddChild( poHorizSRS->GetRoot()->Clone() );
 
3043
    poRoot->AddChild( poVertSRS->GetRoot()->Clone() );
 
3044
    
 
3045
    return OGRERR_NONE;
 
3046
}
 
3047
 
 
3048
/************************************************************************/
 
3049
/*                          OSRSetCompoundCS()                          */
 
3050
/************************************************************************/
 
3051
 
 
3052
/**
 
3053
 * \brief Setup a compound coordinate system.
 
3054
 *
 
3055
 * This function is the same as OGRSpatialReference::SetCompoundCS()
 
3056
 */
 
3057
OGRErr OSRSetCompoundCS( OGRSpatialReferenceH hSRS,
 
3058
                         const char *pszName,
 
3059
                         OGRSpatialReferenceH hHorizSRS,
 
3060
                         OGRSpatialReferenceH hVertSRS )
 
3061
 
 
3062
{
 
3063
    VALIDATE_POINTER1( hSRS, "OSRSetCompoundCS", CE_Failure );
 
3064
    VALIDATE_POINTER1( hHorizSRS, "OSRSetCompoundCS", CE_Failure );
 
3065
    VALIDATE_POINTER1( hVertSRS, "OSRSetCompoundCS", CE_Failure );
 
3066
 
 
3067
    return ((OGRSpatialReference *) hSRS)->
 
3068
        SetCompoundCS( pszName,
 
3069
                       (OGRSpatialReference *) hHorizSRS,
 
3070
                       (OGRSpatialReference *) hVertSRS );
 
3071
}
 
3072
 
 
3073
/************************************************************************/
2444
3074
/*                             SetProjCS()                              */
2445
3075
/************************************************************************/
2446
3076
 
2449
3079
 *
2450
3080
 * This method is the same as the C function OSRSetProjCS(). 
2451
3081
 *
2452
 
 * This method is will ensure a PROJCS node is created as the root, 
 
3082
 * This method will ensure a PROJCS node is created as the root,
2453
3083
 * and set the provided name on it.  If used on a GEOGCS coordinate system, 
2454
3084
 * the GEOGCS node will be demoted to be a child of the new PROJCS root.
2455
3085
 *
3601
4231
}
3602
4232
 
3603
4233
/************************************************************************/
 
4234
/*                              SetIGH()                                */
 
4235
/************************************************************************/
 
4236
 
 
4237
OGRErr OGRSpatialReference::SetIGH()
 
4238
 
 
4239
{
 
4240
    SetProjection( SRS_PT_IGH );
 
4241
 
 
4242
    return OGRERR_NONE;
 
4243
}
 
4244
 
 
4245
/************************************************************************/
 
4246
/*                              OSRSetIGH()                             */
 
4247
/************************************************************************/
 
4248
 
 
4249
OGRErr OSRSetIGH( OGRSpatialReferenceH hSRS )
 
4250
 
 
4251
{
 
4252
    VALIDATE_POINTER1( hSRS, "OSRSetIGH", CE_Failure );
 
4253
 
 
4254
    return ((OGRSpatialReference *) hSRS)->SetIGH();
 
4255
}
 
4256
 
 
4257
/************************************************************************/
3604
4258
/*                              SetGEOS()                               */
3605
4259
/************************************************************************/
3606
4260
 
4668
5322
 *
4669
5323
 * This is the same as the C function OSRGetUTMZone().
4670
5324
 *
 
5325
 * In SWIG bindings (Python, Java, etc) the GetUTMZone() method returns a 
 
5326
 * zone which is negative in the southern hemisphere instead of having the 
 
5327
 * pbNorth flag used in the C and C++ interface.
 
5328
 *
4671
5329
 * @param pbNorth pointer to in to set to TRUE if northern hemisphere, or
4672
5330
 * FALSE if southern. 
4673
5331
 * 
4703
5361
 
4704
5362
    double      dfCentralMeridian = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 
4705
5363
                                                     0.0);
4706
 
    double      dfZone = (dfCentralMeridian+183) / 6.0 + 0.000000001;
 
5364
    double      dfZone = ( dfCentralMeridian + 186.0 ) / 6.0;
4707
5365
 
4708
 
    if( ABS(dfZone - (int) dfZone) > 0.00001
 
5366
    if( ABS(dfZone - (int) dfZone - 0.5 ) > 0.00001
4709
5367
        || dfCentralMeridian < -177.00001
4710
5368
        || dfCentralMeridian > 177.000001 )
4711
5369
        return 0;
5026
5684
 * portion remains (normally PROJCS, GEOGCS or LOCAL_CS). 
5027
5685
 *
5028
5686
 * If this is not a compound coordinate system then nothing is changed.
 
5687
 *
 
5688
 * @since OGR 1.8.0
5029
5689
 */
5030
5690
 
5031
5691
OGRErr OGRSpatialReference::StripVertical()
5111
5771
}
5112
5772
 
5113
5773
/************************************************************************/
 
5774
/*                             IsCompound()                             */
 
5775
/************************************************************************/
 
5776
 
 
5777
/**
 
5778
 * \brief Check if coordinate system is compound.
 
5779
 *
 
5780
 * This method is the same as the C function OSRIsCompound().
 
5781
 *
 
5782
 * @return TRUE if this is rooted with a COMPD_CS node.
 
5783
 */
 
5784
 
 
5785
int OGRSpatialReference::IsCompound() const
 
5786
 
 
5787
{
 
5788
    if( poRoot == NULL )
 
5789
        return FALSE;
 
5790
 
 
5791
    return EQUAL(poRoot->GetValue(),"COMPD_CS");
 
5792
}
 
5793
 
 
5794
/************************************************************************/
 
5795
/*                           OSRIsCompound()                            */
 
5796
/************************************************************************/
 
5797
 
 
5798
/** 
 
5799
 * \brief Check if the coordinate system is compound.
 
5800
 *
 
5801
 * This function is the same as OGRSpatialReference::IsCompound().
 
5802
 */
 
5803
int OSRIsCompound( OGRSpatialReferenceH hSRS ) 
 
5804
 
 
5805
{
 
5806
    VALIDATE_POINTER1( hSRS, "OSRIsCompound", 0 );
 
5807
 
 
5808
    return ((OGRSpatialReference *) hSRS)->IsCompound();
 
5809
}
 
5810
 
 
5811
/************************************************************************/
5114
5812
/*                            IsProjected()                             */
5115
5813
/************************************************************************/
5116
5814
 
5154
5852
}
5155
5853
 
5156
5854
/************************************************************************/
 
5855
/*                            IsGeocentric()                            */
 
5856
/************************************************************************/
 
5857
 
 
5858
/**
 
5859
 * \brief Check if geocentric coordinate system.
 
5860
 *
 
5861
 * This method is the same as the C function OSRIsGeocentric().
 
5862
 *
 
5863
 * @return TRUE if this contains a GEOCCS node indicating a it is a 
 
5864
 * geocentric coordinate system.
 
5865
 *
 
5866
 * @since OGR 1.9.0
 
5867
 */
 
5868
 
 
5869
int OGRSpatialReference::IsGeocentric() const
 
5870
 
 
5871
{
 
5872
    if( poRoot == NULL )
 
5873
        return FALSE;
 
5874
 
 
5875
    if( EQUAL(poRoot->GetValue(),"GEOCCS") )
 
5876
        return TRUE;
 
5877
    else 
 
5878
        return FALSE;
 
5879
}
 
5880
 
 
5881
/************************************************************************/
 
5882
/*                           OSRIsGeocentric()                          */
 
5883
/************************************************************************/
 
5884
/** 
 
5885
 * \brief Check if geocentric coordinate system.
 
5886
 *
 
5887
 * This function is the same as OGRSpatialReference::IsGeocentric().
 
5888
 *
 
5889
 * @since OGR 1.9.0
 
5890
 */
 
5891
int OSRIsGeocentric( OGRSpatialReferenceH hSRS ) 
 
5892
 
 
5893
{
 
5894
    VALIDATE_POINTER1( hSRS, "OSRIsGeocentric", 0 );
 
5895
 
 
5896
    return ((OGRSpatialReference *) hSRS)->IsGeocentric();
 
5897
}
 
5898
 
 
5899
/************************************************************************/
5157
5900
/*                            IsGeographic()                            */
5158
5901
/************************************************************************/
5159
5902
 
5236
5979
}
5237
5980
 
5238
5981
/************************************************************************/
 
5982
/*                            IsVertical()                              */
 
5983
/************************************************************************/
 
5984
 
 
5985
/**
 
5986
 * \brief Check if vertical coordinate system.
 
5987
 *
 
5988
 * This method is the same as the C function OSRIsVertical().
 
5989
 *
 
5990
 * @return TRUE if this contains a VERT_CS node indicating a it is a 
 
5991
 * vertical coordinate system.
 
5992
 *
 
5993
 * @since OGR 1.8.0
 
5994
 */
 
5995
 
 
5996
int OGRSpatialReference::IsVertical() const
 
5997
 
 
5998
{
 
5999
    if( poRoot == NULL )
 
6000
        return FALSE;
 
6001
 
 
6002
    if( EQUAL(poRoot->GetValue(),"VERT_CS") )
 
6003
        return TRUE;
 
6004
    else if( EQUAL(poRoot->GetValue(),"COMPD_CS") )
 
6005
        return GetAttrNode( "VERT_CS" ) != NULL;
 
6006
    else 
 
6007
        return FALSE;
 
6008
}
 
6009
 
 
6010
/************************************************************************/
 
6011
/*                           OSRIsVertical()                            */
 
6012
/************************************************************************/
 
6013
/** 
 
6014
 * \brief Check if vertical coordinate system.
 
6015
 *
 
6016
 * This function is the same as OGRSpatialReference::IsVertical().
 
6017
 *
 
6018
 * @since OGR 1.8.0
 
6019
 */
 
6020
int OSRIsVertical( OGRSpatialReferenceH hSRS ) 
 
6021
 
 
6022
{
 
6023
    VALIDATE_POINTER1( hSRS, "OSRIsVertical", 0 );
 
6024
 
 
6025
    return ((OGRSpatialReference *) hSRS)->IsVertical();
 
6026
}
 
6027
 
 
6028
/************************************************************************/
5239
6029
/*                            CloneGeogCS()                             */
5240
6030
/************************************************************************/
5241
6031
 
5250
6040
    const OGR_SRSNode *poGeogCS;
5251
6041
    OGRSpatialReference * poNewSRS;
5252
6042
 
 
6043
/* -------------------------------------------------------------------- */
 
6044
/*      We have to reconstruct the GEOGCS node for geocentric           */
 
6045
/*      coordinate systems.                                             */
 
6046
/* -------------------------------------------------------------------- */
 
6047
    if( IsGeocentric() )
 
6048
    {
 
6049
        const OGR_SRSNode *poDatum = GetAttrNode( "DATUM" );
 
6050
        const OGR_SRSNode *poPRIMEM = GetAttrNode( "PRIMEM" );
 
6051
        OGR_SRSNode *poGeogCS;
 
6052
        
 
6053
        if( poDatum == NULL || poPRIMEM == NULL )
 
6054
            return NULL;
 
6055
        
 
6056
        poGeogCS = new OGR_SRSNode( "GEOGCS" );
 
6057
        poGeogCS->AddChild( new OGR_SRSNode( "unnamed" ) );
 
6058
        poGeogCS->AddChild( poDatum->Clone() );
 
6059
        poGeogCS->AddChild( poPRIMEM->Clone() );
 
6060
 
 
6061
        poNewSRS = new OGRSpatialReference();
 
6062
        poNewSRS->SetRoot( poGeogCS );
 
6063
 
 
6064
        poNewSRS->SetAngularUnits( "degree", CPLAtof(SRS_UA_DEGREE_CONV) );
 
6065
 
 
6066
        return poNewSRS;
 
6067
    }
 
6068
 
 
6069
/* -------------------------------------------------------------------- */
 
6070
/*      For all others we just search the tree, and duplicate.          */
 
6071
/* -------------------------------------------------------------------- */
5253
6072
    poGeogCS = GetAttrNode( "GEOGCS" );
5254
6073
    if( poGeogCS == NULL )
5255
6074
        return NULL;
5308
6127
        return FALSE;
5309
6128
 
5310
6129
/* -------------------------------------------------------------------- */
 
6130
/*      Do the datum TOWGS84 values match if present?                   */
 
6131
/* -------------------------------------------------------------------- */
 
6132
    double adfTOWGS84[7], adfOtherTOWGS84[7];
 
6133
    int i;
 
6134
 
 
6135
    this->GetTOWGS84( adfTOWGS84, 7 );
 
6136
    poOther->GetTOWGS84( adfOtherTOWGS84, 7 );
 
6137
 
 
6138
    for( i = 0; i < 7; i++ )
 
6139
    {
 
6140
        if( fabs(adfTOWGS84[i] - adfOtherTOWGS84[i]) > 0.00001 )
 
6141
            return FALSE;
 
6142
    }
 
6143
 
 
6144
/* -------------------------------------------------------------------- */
5311
6145
/*      Do the prime meridians match?  If missing assume a value of zero.*/
5312
6146
/* -------------------------------------------------------------------- */
5313
6147
    pszThisValue = this->GetAttrValue( "PRIMEM", 1 );
5374
6208
}
5375
6209
 
5376
6210
/************************************************************************/
 
6211
/*                            IsSameVertCS()                            */
 
6212
/************************************************************************/
 
6213
 
 
6214
/**
 
6215
 * \brief Do the VertCS'es match?
 
6216
 *
 
6217
 * This method is the same as the C function OSRIsSameVertCS().
 
6218
 *
 
6219
 * @param poOther the SRS being compared against. 
 
6220
 *
 
6221
 * @return TRUE if they are the same or FALSE otherwise. 
 
6222
 */
 
6223
 
 
6224
int OGRSpatialReference::IsSameVertCS( const OGRSpatialReference *poOther ) const
 
6225
 
 
6226
{
 
6227
    const char *pszThisValue, *pszOtherValue;
 
6228
 
 
6229
/* -------------------------------------------------------------------- */
 
6230
/*      Does the datum name match?                                      */
 
6231
/* -------------------------------------------------------------------- */
 
6232
    pszThisValue = this->GetAttrValue( "VERT_DATUM" );
 
6233
    pszOtherValue = poOther->GetAttrValue( "VERT_DATUM" );
 
6234
 
 
6235
    if( pszThisValue == NULL || pszOtherValue == NULL 
 
6236
        || !EQUAL(pszThisValue, pszOtherValue) )
 
6237
        return FALSE;
 
6238
 
 
6239
/* -------------------------------------------------------------------- */
 
6240
/*      Do the units match?                                             */
 
6241
/* -------------------------------------------------------------------- */
 
6242
    pszThisValue = this->GetAttrValue( "VERT_CS|UNIT", 1 );
 
6243
    if( pszThisValue == NULL )
 
6244
        pszThisValue = "1.0";
 
6245
 
 
6246
    pszOtherValue = poOther->GetAttrValue( "VERT_CS|UNIT", 1 );
 
6247
    if( pszOtherValue == NULL )
 
6248
        pszOtherValue = "1.0";
 
6249
 
 
6250
    if( ABS(CPLAtof(pszOtherValue) - CPLAtof(pszThisValue)) > 0.00000001 )
 
6251
        return FALSE;
 
6252
 
 
6253
    return TRUE;
 
6254
}
 
6255
 
 
6256
/************************************************************************/
 
6257
/*                          OSRIsSameVertCS()                           */
 
6258
/************************************************************************/
 
6259
 
 
6260
/** 
 
6261
 * \brief Do the VertCS'es match?
 
6262
 *
 
6263
 * This function is the same as OGRSpatialReference::IsSameVertCS().
 
6264
 */
 
6265
int OSRIsSameVertCS( OGRSpatialReferenceH hSRS1, OGRSpatialReferenceH hSRS2 )
 
6266
 
 
6267
{
 
6268
    VALIDATE_POINTER1( hSRS1, "OSRIsSameVertCS", 0 );
 
6269
    VALIDATE_POINTER1( hSRS2, "OSRIsSameVertCS", 0 );
 
6270
 
 
6271
    return ((OGRSpatialReference *) hSRS1)->IsSameVertCS( 
 
6272
        (OGRSpatialReference *) hSRS2 );
 
6273
}
 
6274
 
 
6275
/************************************************************************/
5377
6276
/*                               IsSame()                               */
5378
6277
/************************************************************************/
5379
6278
 
5451
6350
        }
5452
6351
    }
5453
6352
 
 
6353
/* -------------------------------------------------------------------- */
 
6354
/*      Compare vertical coordinate system.                             */
 
6355
/* -------------------------------------------------------------------- */
 
6356
    if( IsVertical() && !IsSameVertCS( poOtherSRS ) )
 
6357
        return FALSE;
 
6358
 
5454
6359
    return TRUE;
5455
6360
}
5456
6361
 
5781
6686
 
5782
6687
{
5783
6688
/* -------------------------------------------------------------------- */
5784
 
/*      Ensure linear units defaulted to METER if missing for PROJCS    */
5785
 
/*      or LOCAL_CS.                                                    */
 
6689
/*      Ensure linear units defaulted to METER if missing for PROJCS,   */
 
6690
/*      GEOCCS or LOCAL_CS.                                             */
5786
6691
/* -------------------------------------------------------------------- */
5787
6692
    const OGR_SRSNode *poCS = GetAttrNode( "PROJCS" );
5788
6693
 
5789
6694
    if( poCS == NULL )
5790
6695
        poCS = GetAttrNode( "LOCAL_CS" );
5791
6696
 
 
6697
    if( poCS == NULL )
 
6698
        poCS = GetAttrNode( "GEOCCS" );
 
6699
 
5792
6700
    if( poCS != NULL && poCS->FindChild( "UNIT" ) == -1 )
5793
6701
        SetLinearUnits( SRS_UL_METER, 1.0 );
5794
6702
 
5983
6891
 
5984
6892
const char *
5985
6893
OGRSpatialReference::GetAxis( const char *pszTargetKey, int iAxis, 
5986
 
                              OGRAxisOrientation *peOrientation )
 
6894
                              OGRAxisOrientation *peOrientation ) const
5987
6895
 
5988
6896
{
5989
6897
    if( peOrientation != NULL )
6044
6952
            *peOrientation = OAO_South;
6045
6953
        else if( EQUAL(pszOrientation,"WEST") )
6046
6954
            *peOrientation = OAO_West;
 
6955
        else if( EQUAL(pszOrientation,"UP") )
 
6956
            *peOrientation = OAO_Up;
 
6957
        else if( EQUAL(pszOrientation,"DOWN") )
 
6958
            *peOrientation = OAO_Down;
 
6959
        else if( EQUAL(pszOrientation,"OTHER") )
 
6960
            *peOrientation = OAO_Other;
6047
6961
        else
6048
6962
        {
6049
6963
            CPLDebug( "OSR", "Unrecognised orientation value '%s'.",
6096
7010
        return "SOUTH";
6097
7011
    if( eOrientation == OAO_West )
6098
7012
        return "WEST";
 
7013
    if( eOrientation == OAO_Up )
 
7014
        return "UP";
 
7015
    if( eOrientation == OAO_Down )
 
7016
        return "DOWN";
 
7017
    if( eOrientation == OAO_Other )
 
7018
        return "OTHER";
6099
7019
 
6100
7020
    return "UNKNOWN";
6101
7021
}