Some background on OpenGIS coordinate systems and services can be found in the Simple Features for COM, and Spatial Reference Systems Abstract Model documents available from the Open Geospatial Consortium. The GeoTIFF Projections Transform List may also be of assistance in understanding formulations of projections in WKT. The EPSG Geodesy web page is also a useful resource.
A Geographic coordinate system contains information on the datum (which implies an spheroid described by a semi-major axis, and inverse flattening), prime meridian(normally Greenwich), and an angular units type which is normally degrees. The following code initializes a geographic coordinate system on supplying all this information along with a user visible name for the geographic coordinate system.
OGRSpatialReference oSRS; oSRS.SetGeogCS( "My geographic coordinate system", "WGS_1984", "My WGS84 Spheroid", SRS_WGS84_SEMIMAJOR, SRS_WGS84_INVFLATTENING, "Greenwich", 0.0, "degree", SRS_UA_DEGREE_CONV );
Of these values, the names "My geographic coordinate system", "My WGS84 Spheroid", "Greenwich" and "degree" are not keys, but are used for display to the user. However, the datum name "WGS_1984" is used as a key to identify the datum, and there are rules on what values can be used. NOTE: Prepare writeup somewhere on valid datums!
The OGRSpatialReference has built in support for a few well known coordinate systems, which include "NAD27", "NAD83", "WGS72" and "WGS84" which can be defined in a single call to SetWellKnownGeogCS().
oSRS.SetWellKnownGeogCS( "WGS84" );
Furthermore, any geographic coordinate system in the EPSG database can be set by it's GCS code number if the EPSG database is available.
oSRS.SetWellKnownGeogCS( "EPSG:4326" );
For serializization, and transmission of projection definitions to other packages, the OpenGIS Well Known Text format for coordinate systems is used. An OGRSpatialReference can be initialized from well known text, or converted back into well known text.
char *pszWKT = NULL; oSRS.SetWellKnownGeogCS( "WGS84" ); oSRS.exportToWkt( &pszWKT ); printf( "%s\n", pszWKT );
gives something like:
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG",7030]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG",6326]], PRIMEM["Greenwich",0,AUTHORITY["EPSG",8901]],UNIT["DMSH",0.0174532925199433, AUTHORITY["EPSG",9108]],AXIS["Lat",NORTH],AXIS["Long",EAST],AUTHORITY["EPSG", 4326]]
or in more readable form:
GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG",7030]], TOWGS84[0,0,0,0,0,0,0], AUTHORITY["EPSG",6326]], PRIMEM["Greenwich",0,AUTHORITY["EPSG",8901]], UNIT["DMSH",0.0174532925199433,AUTHORITY["EPSG",9108]], AXIS["Lat",NORTH], AXIS["Long",EAST], AUTHORITY["EPSG",4326]]
The OGRSpatialReference::importFromWkt() method can be used to set an OGRSpatialReference from a WKT coordinate system definition.
OGRSpatialReference oSRS; oSRS.SetProjCS( "UTM 17 (WGS84) in northern hemisphere." ); oSRS.SetWellKnownGeogCS( "WGS84" ); oSRS.SetUTM( 17, TRUE );
Calling SetProjCS() sets a user name for the projected coordinate system and establishes that the system is projected. The SetWellKnownGeogCS() associates a geographic coordinate system, and the SetUTM() call sets detailed projection transformation parameters. At this time the above order is important in order to create a valid definition, but in the future the object will automatically reorder the internal representation as needed to remain valid. For now be careful of the order of steps defining an OGRSpatialReference!
The above definition would give a WKT version that looks something like the following. Note that the UTM 17 was expanded into the details transverse mercator definition of the UTM zone.
PROJCS["UTM 17 (WGS84) in northern hemisphere.", GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG",7030]], TOWGS84[0,0,0,0,0,0,0], AUTHORITY["EPSG",6326]], PRIMEM["Greenwich",0,AUTHORITY["EPSG",8901]], UNIT["DMSH",0.0174532925199433,AUTHORITY["EPSG",9108]], AXIS["Lat",NORTH], AXIS["Long",EAST], AUTHORITY["EPSG",4326]], PROJECTION["Transverse_Mercator"], PARAMETER["latitude_of_origin",0], PARAMETER["central_meridian",-81], PARAMETER["scale_factor",0.9996], PARAMETER["false_easting",500000], PARAMETER["false_northing",0]]
There are methods for many projection methods including SetTM() (Transverse Mercator), SetLCC() (Lambert Conformal Conic), and SetMercator().
The following code (from ogr_srs_proj4.cpp) demonstrates use of GetAttrValue() to get the projection, and GetProjParm() to get projection parameters. The GetAttrValue() method searches for the first "value" node associated with the named entry in the WKT text representation. The define'ed constants for projection parameters (such as SRS_PP_CENTRAL_MERIDIAN) should be used when fetching projection parameter with GetProjParm(). The code for the Set methods of the various projections in ogrspatialreference.cpp can be consulted to find which parameters apply to which projections.
const char *pszProjection = poSRS->GetAttrValue("PROJECTION"); if( pszProjection == NULL ) { if( poSRS->IsGeographic() ) sprintf( szProj4+strlen(szProj4), "+proj=longlat " ); else sprintf( szProj4+strlen(szProj4), "unknown " ); } else if( EQUAL(pszProjection,SRS_PT_CYLINDRICAL_EQUAL_AREA) ) { sprintf( szProj4+strlen(szProj4), "+proj=cea +lon_0=%.9f +lat_ts=%.9f +x_0=%.3f +y_0=%.3f ", poSRS->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0), poSRS->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0), poSRS->GetProjParm(SRS_PP_FALSE_EASTING,0.0), poSRS->GetProjParm(SRS_PP_FALSE_NORTHING,0.0) ); } ...
OGRSpatialReference oSourceSRS, oTargetSRS; OGRCoordinateTransformation *poCT; double x, y; oSourceSRS.importFromEPSG( atoi(papszArgv[i+1]) ); oTargetSRS.importFromEPSG( atoi(papszArgv[i+2]) ); poCT = OGRCreateCoordinateTransformation( &oSourceSRS, &oTargetSRS ); x = atof( papszArgv[i+3] ); y = atof( papszArgv[i+4] ); if( poCT == NULL || !poCT->Transform( 1, &x, &y ) ) printf( "Transformation failed.\n" ); else printf( "(%f,%f) -> (%f,%f)\n", atof( papszArgv[i+3] ), atof( papszArgv[i+4] ), x, y );
There are a couple of points at which transformations can fail. First, OGRCreateCoordinateTransformation() may fail, generally because the internals recognise that no transformation between the indicated systems can be established. This might be due to use of a projection not supported by the internal PROJ.4 library, differing datums for which no relationship is known, or one of the coordinate systems being inadequately defined. If OGRCreateCoordinateTransformation() fails it will return a NULL.
The OGRCoordinateTransformation::Transform() method itself can also fail. This may be as a delayed result of one of the above problems, or as a result of an operation being numerically undefined for one or more of the passed in points. The Transform() function will return TRUE on success, or FALSE if any of the points fail to transform. The point array is left in an indeterminate state on error.
Though not shown above, the coordinate transformation service can take 3D points, and will adjust elevations for elevation differents in spheroids, and datums. At some point in the future shifts between different vertical datums may also be applied. If no Z is passed, it is assume that the point is on the geoide.
The following example shows how to conveniently create a lat/long coordinate system using the same geographic coordinate system as a projected coordinate system, and using that to transform between projected coordinates and lat/long.
OGRSpatialReference oUTM, *poLatLong; OGRCoordinateTransformation *poTransform; oUTM.SetProjCS("UTM 17 / WGS84"); oUTM.SetWellKnownGeogCS( "WGS84" ); oUTM.SetUTM( 17 ); poLatLong = oUTM.CloneGeogCS(); poTransform = OGRCreateCoordinateTransformation( &oUTM, poLatLong ); if( poTransform == NULL ) { ... } ... if( !poTransform->Transform( nPoints, x, y, z ) ) ...
typedef void *OGRSpatialReferenceH; typedef void *OGRCoordinateTransformationH; OGRSpatialReferenceH OSRNewSpatialReference( const char * ); void OSRDestroySpatialReference( OGRSpatialReferenceH ); int OSRReference( OGRSpatialReferenceH ); int OSRDereference( OGRSpatialReferenceH ); OGRErr OSRImportFromEPSG( OGRSpatialReferenceH, int ); OGRErr OSRImportFromWkt( OGRSpatialReferenceH, char ** ); OGRErr OSRExportToWkt( OGRSpatialReferenceH, char ** ); OGRErr OSRSetAttrValue( OGRSpatialReferenceH hSRS, const char * pszNodePath, const char * pszNewNodeValue ); const char *OSRGetAttrValue( OGRSpatialReferenceH hSRS, const char * pszName, int iChild); OGRErr OSRSetLinearUnits( OGRSpatialReferenceH, const char *, double ); double OSRGetLinearUnits( OGRSpatialReferenceH, char ** ); int OSRIsGeographic( OGRSpatialReferenceH ); int OSRIsProjected( OGRSpatialReferenceH ); int OSRIsSameGeogCS( OGRSpatialReferenceH, OGRSpatialReferenceH ); int OSRIsSame( OGRSpatialReferenceH, OGRSpatialReferenceH ); OGRErr OSRSetProjCS( OGRSpatialReferenceH hSRS, const char * pszName ); OGRErr OSRSetWellKnownGeogCS( OGRSpatialReferenceH hSRS, const char * pszName ); OGRErr OSRSetGeogCS( OGRSpatialReferenceH hSRS, const char * pszGeogName, const char * pszDatumName, const char * pszEllipsoidName, double dfSemiMajor, double dfInvFlattening, const char * pszPMName , double dfPMOffset , const char * pszUnits, double dfConvertToRadians ); double OSRGetSemiMajor( OGRSpatialReferenceH, OGRErr * ); double OSRGetSemiMinor( OGRSpatialReferenceH, OGRErr * ); double OSRGetInvFlattening( OGRSpatialReferenceH, OGRErr * ); OGRErr OSRSetAuthority( OGRSpatialReferenceH hSRS, const char * pszTargetKey, const char * pszAuthority, int nCode ); OGRErr OSRSetProjParm( OGRSpatialReferenceH, const char *, double ); double OSRGetProjParm( OGRSpatialReferenceH hSRS, const char * pszParmName, double dfDefault, OGRErr * ); OGRErr OSRSetUTM( OGRSpatialReferenceH hSRS, int nZone, int bNorth ); int OSRGetUTMZone( OGRSpatialReferenceH hSRS, int *pbNorth ); OGRCoordinateTransformationH OCTNewCoordinateTransformation( OGRSpatialReferenceH hSourceSRS, OGRSpatialReferenceH hTargetSRS ); void OCTDestroyCoordinateTransformation( OGRCoordinateTransformationH ); int OCTTransform( OGRCoordinateTransformationH hCT, int nCount, double *x, double *y, double *z );
class osr.SpatialReference def __init__(self,obj=None): def ImportFromWkt( self, wkt ): def ExportToWkt(self): def ImportFromEPSG(self,code): def IsGeographic(self): def IsProjected(self): def GetAttrValue(self, name, child = 0): def SetAttrValue(self, name, value): def SetWellKnownGeogCS(self, name): def SetProjCS(self, name = "unnamed" ): def IsSameGeogCS(self, other): def IsSame(self, other): def SetLinearUnits(self, units_name, to_meters ): def SetUTM(self, zone, is_north = 1): class CoordinateTransformation: def __init__(self,source,target): def TransformPoint(self, x, y, z = 0): def TransformPoints(self, points):