Lesson 8: Performing a Three-Dimensional Coordinate Transformation

In addition to the two-dimensional coordinate transformations described in lesson 7, the CoordTransform object is also capable of performing three-dimensional coordinate transformations.  Such a transformation can be performed when both the source and target coordinate systems have a valid VerticalReference.

Since all of the definitions we will be using reside in the DataSourceComponent, we will start by creating and loading a DataSourceComponent.  For more information about the DataSourceComponent object, see Lesson 4.

[VB]

Dim gcDataSource As New DataSourceComponent

gcDataSource.LoadFile("c:\\bmg\\GeoCalcNET\\data\\geocalc.xml")

 

[C#]

DataSourceComponent gcDataSource = new DataSourceComponent();

gcDataSource.LoadFile("c:\\bmg\\GeoCalcNET\\data\\geocalc.xml");

 

Creating a CoordTransform

Performing a three-dimensional coordinate transformation is very similar to performing a two-dimensional coordinate transformation.  As before, we must start by constructing a CoordTransform object, which will facilitate this transformation.  In order to construct a CoordTransform, we will need to retrieve some CoordSys definitions and some VerticalReferences from the DataSourceComponent.  Since we want this to be a non-trivial lesson, let's pick some interesting objects.  First, we want two different types of CoordSys objects, a ProjectedCoordSys and a GeodeticCoordSys.  Second, we want to select CoordSys objects that use different HorizontalDatums so that we will need to use some DatumShifts.  Finally, we should select two different VerticalReferences so that we need to perform a vertical transformation.  These objects will suffice for this lesson:

[VB]

Dim source As GeodeticCoordSys

source = gcDataSource.GetGeodeticCoordSys("BMG", "SIRGAS_GEODETIC")

Dim sourceVR As VerticalReference

sourceVR = gcDataSource.GetVerticalReference("BMG", "CVD_GEOCOL04")

source.VertReference = sourceVR

Dim target As ProjectedCoordSys

target = gcDataSource.GetProjectedCoordSys("BMG", "UTM-18N")

Dim targetVR As VerticalReference

targetVR = gcDataSource.GetVerticalReference("BMG", "ELLIPSOID_HEIGHT")

target.InnerGeodetic.VertReference = targetVR

 

[C#]

GeodeticCoordSys source = gcDataSource.GetGeodeticCoordSys("BMG", "SIRGAS_GEODETIC");

VerticalReference sourceVR = gcDataSource.GetVerticalReference("BMG", "CVD_GEOCOL04");

source.VertReference = sourceVR;

ProjectedCoordSys target = gcDataSource.GetProjectedCoordSys("BMG", "UTM-18N");

VerticalReference targetVR = gcDataSource.GetVerticalReference("BMG", "ELLIPSOID_HEIGHT");

target.InnerGeodetic.VertReference = targetVR;

Here we have select the Sirgas GeodeticCoordSys with the Colombia Geoid Model of 2004 VerticalReference as our source coordinate system, and the UTM 18N ProjectedCoordSys with the ellipsoid height VerticalReference as our target coordinate system.  So we are now ready to construct our CoordTransform:

[VB]

Dim ct As New CoordTransform(source, target)

 

[C#]

CoordTransform ct = new CoordTransform(source, target);

 

Selecting DatumShifts

Since our source and target coordinate systems use different HorizontalDatums, we will need to perform one or more DatumShifts.  There are multiple ways to find the DatumShifts needed for a CoordTransform, and Lesson 6 describes these methods.  For the purpose of this lesson, we will just retrieve a single DatumShift from the DataSourceComponent and put it into our CoordTransform::DatumShifts collection:

[VB]

Dim ds As DatumShift = gcDataSource.GetDatumShift("BMG", "SIRGAS_to_WGS84")

ds = ct.DatumShifts.AddBack(ds)

 

[C#]

DatumShift ds = gcDataSource.GetDatumShift("BMG", "SIRGAS_to_WGS84");

ds = ct.DatumShifts.AddBack(ds);

It is also possible to intentionally not use a DatumShift by not populating the DatumShifts property.  Users should be aware that some coordinate shift may occur when shifting between ProjectedCoordSys' even though no DatumShift is being used.  This can be occur if the source and target HorizontalDatums use different Ellipsoids.

 

Initializing a Vertical Transform

Since our source and target coordinate systems use different VerticalReferences, we will need to perform a vertical transformation.  This requires that we call the CoordTransform::InitializeVerticalTransform method before we try to transform any points with this CoordTransform.

Most of the HeightModels and VerticalDatums supported by GeoCalc require additional data files that were not installed with GeoCalc.  All of these files can be obtained free of charge from our website.  A description of the files needed by each HeightModel and VerticalDatum, as well as a link through which they can be downloaded, can be found on the description page for each HeightModel and each VerticalDatum.  For the transformation described in this lesson, we will require the files for the Colombia Geoid Model of 2004.  Without these files, the InitializeVerticalTransform method will throw a GeoCalcException.

Now that we have the necessary files, we can call the InitializeVerticalTransform method:

[VB]

Try

    If Not ct.InitializeVerticalTransform Then

        MessageBox.Show("Unable to InitializeVerticalTransform")

    End If

Catch ex As GeoCalcException

    MessageBox.Show(ex.ToString())

End Try

 

[C#]

try

{

if(! ct.InitializeVerticalTransform())

{

MessageBox.Show("Unable to InitializeVerticalTransform");

}

}

catch(GeoCalcException ex)

{

MessageBox.Show(ex.ToString());

}

The InitializeVerticalTransform method may throw a GeoCalcException with an ErrorCode of IllegalVerticalTransform.  This indicates that GeoCalc is not capable of performing the requested vertical transformation.  There could be several reasons for this, but the most common cause of this exception is that one of our VerticalReferences uses a HeightModel that uses a HorizontalDatum that is not used by either the source or target CoordSys.  However, if you have set things up in the same way as is done in this lesson, you should not receive this exception (nor should you receive any GeoCalcException for that matter).

 

Transforming Points

Our CoordTransform is now set up and ready to perform a three dimensional coordinate transformation.  As with the two-dimensional transformation as described in Lesson 7, we have the option of transforming either a single point or a list of points.  Here we will only transform a single point.  If you would like to transform many points at once, please see the section 'Transforming a Collection of Points' in Lesson 7.  The method of transforming multiple three-dimensional points is the same as the method for transforming multiple two-dimensional points.

We must take care when selecting a point to transform, because the Colombia Geoid Model of 2004 is only defined from 5 to 15 north latitude and from 66 to 80 west longitude.  If we try to transform a point outside of that area, we will receive a GeoCalcException.  Here is the GeodeticPoint we will transform, along with the expected value of the resulting ProjectedPoint:

 

Sirgas Geodetic

 

 

UTM 18N

Latitude

10 Degrees

 

North

1105578.58919244 Meters

Longitude

-76 Degrees

 

East

390399.22748554 Meters

Height

123 Meters

 

Height

120.75025305 Meters

Here is how we perform the transformation:

[VB]

Dim inPt As CoordPoint = ct.SourceCoordSys.PointStyle.Clone()

Dim outPt As CoordPoint = ct.TargetCoordSys.PointStyle.Clone()

inPt.SetInUnits(-76, 10, 123)

Try

    If Not ct.ConvertAhead(inPt, outPt) Then

        MessageBox.Show("ConvertAhead failed")

    End If

Catch ex As GeoCalcException

    MessageBox.Show(ex.ToString())

End Try

Dim lon As Double

Dim lat As Double

Dim height As Double

outPt.GetInUnits(lon, lat, height)

 

[C#]

CoordPoint inPt = (CoordPoint)ct.SourceCoordSys.PointStyle.Clone();

CoordPoint outPt = (CoordPoint)ct.TargetCoordSys.PointStyle.Clone();

inPt.SetInUnits(-76, 10, 123);

try

{

if(! ct.ConvertAhead(inPt, outPt))

{

MessageBox.Show("ConvertAhead failed");

}

}

catch(GeoCalcException ex)

{

MessageBox.Show(ex.ToString());

}

double lon = 0;

double lat = 0;

double height = 0;

outPt.GetInUnits(ref lon, ref lat, ref height);

The values of east, north, and height should now match the corresponding values shown above.  

 

Clean Up

Finally, we must clean up after ourselves and free the memory that was allocated in this lesson using the Dispose method:

[VB]

ct.Dispose()

source.Dispose()

sourceVR.Dispose()

target.Dispose()

targetVR.Dispose()

ds.Dispose()

inPt.Dispose()

outPt.Dispose()

 

[C#]

ct.Dispose();

source.Dispose();

sourceVR.Dispose();

target.Dispose();

targetVR.Dispose();

ds.Dispose();

inPt.Dispose();

outPt.Dispose();