Coordinate transformation is what GeoCalc was built to do. This lesson and the next lesson provide a description of precisely how to convert coordinates from one coordinate system to another. This lesson covers the most common kind of coordinate transformation performed by GeoCalc - one in which no vertical data is considered.
Since all of the definitions we will be using reside in the DataSource, we will start by creating and loading a DataSource. For more information about the DataSource object, see Lesson 4.
Dim gcDataSource As New DataSource
gcDataSource.LoadFile ("c:\bmg\GeoCalcCOM\data\geocalc.xml")
var
gcDataSource : DataSource;
begin
gcDataSource := CoDataSource.Create;
gcDataSource.LoadFile('c:\bmg\GeoCalcCOM\data\geocalc.xml');
The CoordTransform object facilitates the transformation of points from one coordinate system to another. It requires two ICoordSys objects, one of which corresponds to the SourceCoordSys property, and the other of which corresponds to the TargetCoordSys property. The SourceCoordSys represents the coordinate system from which points will be transformed, and the TargetCoordSys represents the coordinate system to which points will be transformed. If you think of the CoordTransform as a mathematical function that acts upon ICoordPoints, then the SourceCoordSys is the domain of the function and the TargetCoordSys is the codomain of the function.
So the first step in creating our CoordTransform will be to get a couple ICoordSys objects. It does not matter what type the ICoordSys objects are, or if they use the same HorizontalDatum; the CoordTransform can facilitate a transformation between any two ICoordSys objects. To make things interesting, let's use two ICoordSys objects that are different types, one ProjectedCoordSys and one GeodeticCoordSys. Let's also select ICoordSys objects that use different HorizontalDatums, so that we will need to perform some DatumShifts. For this example, we will perform a transformation from the US State Plane 27 Maine East ProjectedCoordSys and the WGS84 GeodeticCoordSys. First, we will need to retrieve these objects from the DataSource:
Dim source As ICoordSys
Set source = gcDataSource.GetProjectedCoordSys("BMG", "ME-27E")
Dim target As ICoordSys
Set target = gcDataSource.GetGeodeticCoordSys("BMG", "WGS84_coordinate_system")
var
source : ICoordSys;
target : ICoordSys;
begin
source := gcDataSource.GetProjectedCoordSys('BMG', 'ME-27E');
target := gcDataSource.GetGeodeticCoordSys('BMG', 'WGS84_coordinate_system');
Now that we have these objects, we can use them to construct a new CoordTransform:
Dim ct As New CoordTransform
ct.SourceCoordSys = source
ct.TargetCoordSys = target
var
ct : CoordTransform;
begin
ct := CoCoordTransform.Create;
ct.SourceCoordSys := source;
ct.TargetCoordSys := target;
We now have a CoordTransform that we will use to convert between two different coordinate systems. However, we are not quite ready to transform any points yet. Since our source and target coordinate systems use different HorizontalDatums, we will need to perform one or more DatumShifts. Given any two HorizontalDatums, there are probably multiple DatumShift combinations that will shift between the HorizontalDatums. The CoordTransform object will not make any assumptions about how you wish to perform a DatumShift; you must explicitly specify all of the DatumShifts.
The CoordTransform::DatumShifts property holds a DatumShiftCollection that holds all of the DatumShifts used by the CoordTransform. In many cases, a single DatumShift will be sufficient for a CoordTransform. However, the GeoCalc data source does not contain each type of DatumShift for each pair of HorizontalDatums. In some cases, it is necessary to use multiple DatumShifts to shift from one HorizontalDatum to another.
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 DataSource and put it into our CoordTransform::DatumShifts collection:
Dim ds As DatumShift
Set ds = gcDataSource.GetDatumShift("BMG", "NAD27-EAST US_to_WGS84")
Set ds = ct.DatumShifts.InsertBack(ds)
var
ds : DatumShift;
begin
ds := gcDataSource.GetDatumShift('BMG', 'NAD27-EAST US_to_WGS84');
ds := ct.DatumShifts.InsertBack(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.
Our CoordTransform is now ready to transform a point. In order to do this, we will first need some ICoordPoints and some coordinate values. We can get the ICoordPoints we need by cloning the PointStyle objects on our source and target ICoordSys objects:
Dim inPt As ICoordPoint
Dim outPt As ICoordPoint
Dim temp As ICloneable
Set temp = ct.SourceCoordSys.PointStyle
Set inPt = temp.Clone
Set temp = ct.TargetCoordSys.PointStyle
Set outPt = temp.Clone
var
inPt : ICoordPoint;
outPt : ICoordPoint;
begin
(ct.SourceCoordSys.PointStyle as ICloneable).Clone(IInterface(inPt));
(ct.TargetCoordSys.PointStyle as ICloneable).Clone(IInterface(outPt));
Now inPt is an instance of a ProjectedPoint, and outPt is an instance of a GeodeticPoint. Our inPt is the point that we will transform, and outPt is the point that will hold the result of the transformation. Let's set the North coordinate to 1200 US feet, and let's set the East coordinate to -250 US feet. This can be accomplished with this line of code:
inPt.SetInUnits -250, 1200
inPt.SetInUnits(-250, 1200, 0);
To transform inPt, we need to call the ConvertAhead method:
ct.ConvertAhead inPt, outPt
ct.ConvertAhead(inPt, outPt);
Assuming that ConvertAhead succeeded in transforming our point, outPt will now hold the result. We can get the coordinate values for outPt like this:
Dim lon As Double
Dim lat As Double
Dim height As Double
outPt.GetInUnits lon, lat, height
var
lon : double;
lat : double;
height : double;
begin
outPt.GetInUnits(lon, lat, height);
The coordinate values for ourPt are lat = 43.82089062 and lon = -70.39491858. Please note that deviating from the steps outlined in this lesson may cause different output values than are shown here. Specifically, if you used a different method for selecting DatumShifts and selected some different DatumShifts, then the output values would not match those shown above.
In many cases, it is convenient to transform many points at once, and GeoCalc provides this functionality. The CoordTransform::ConvertListAhead method will transform all of the ICoordPoints in a CoordPointCollection. In order to use this method, we must first construct two CoordPointCollections: one to hold our input points and one to hold the output points.
Dim inCPC As New CoordPointCollection
Dim outCPC As New CoordPointCollection
inCPC.PointStyle = ct.SourceCoordSys.PointStyle
outCPC.PointStyle = ct.TargetCoordSys.PointStyle
var
inCPC : CoordPointCollection;
outCPC : CoordPointCollection;
begin
inCPC := CoCoordPointCollection.Create;
outCPC := CoCoordPointCollection.Create;
inCPC.PointStyle := ct.SourceCoordSys.PointStyle;
outCPC.PointStyle := ct.TargetCoordSys.PointStyle;
Next, we put some points that we wish to convert into the input CoordPointCollection:
Dim inPt As ICoordPoint
Dim outPt As ICoordPoint
Dim temp As ICloneable
Set temp = ct.SourceCoordSys.PointStyle
Set inPt = temp.Clone
Set temp = ct.TargetCoordSys.PointStyle
Set outPt = temp.Clone
inPt.SetInUnits -250, 1200
inCPC.AddPoint inPt
inPt.SetInUnits 0, 0
inCPC.AddPoint inPt
var
inPt : ICoordPoint;
outPt : ICoordPoint;
begin
(ct.SourceCoordSys.PointStyle as ICloneable).Clone(IInterface(inPt));
(ct.TargetCoordSys.PointStyle as ICloneable).Clone(IInterface(outPt));
inPt.SetInUnits(-250, 1200, 0);
inCPC.AddPoint(inPt);
inPt.SetInUnits(0, 0, 0);
inCPC.AddPoint(inPt);
Finally, we call the ConvertListAhead method to send our points through the CoordTransform:
ct.ConvertListAhead inCPC, outCPC
ct.ConvertListAhead(inCPC, outCPC);
If you have set up everything in the same way as described in this lesson, then both of these points will be successfully converted.