Lesson 8: Performing a Three-Dimensional Coordinate Transformation

In addition to the two-dimensional coordinate transformations described in lesson 7, the ConcatenatedTransform object is also capable of performing three-dimensional coordinate transformations. Such a transformation can be performed when a vertical coordinate system has been added to both the source and target coordinate reference system collections, or when using a source and/or target horizontal coordinate system that is three-dimensional.

In order to compile the code samples provided in this lesson, it will be necessary to include the "WDataSource.h" header file.  

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.

DataSource * dataSource = 0;

dataSource = DataSource::CreateDataSource();

dataSource->LoadFile(BMG_T("C:\\bmg\\GeoCalcPBW\\data\\geodata.xml"), BMG_T("C:\\bmg\\GeoCalcPBW\\data\\geodata.xvw"), true, BMG_T("C:\\bmg\\GeoCalcPBW\\data\custom.xml"), 0, 0, 0);

 

Selecting CoordSys Definitions

Performing a three-dimensional coordinate transformation is very similar to performing a two-dimensional coordinate transformation. As before we must start by constructing a ConcatenatedTransform object which will facilitate this transformation. This construction begins with the retrieval of some CoordSys definitions from the DataSource. These systems will then be added the Source and Target coordinate systems contained within the ConcatenatedTransform. 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 GeodeticCoordSys definitions so that we will need to use some CoordTransforms. Finally we should select two different VerticalCoordSys definitions so that we need to perform a vertical transformation. The following objects will suffice for this lesson:

//You need the EGM 96 vertical datum file "WW15MGH.DAC" to run this transformation.

GeodeticCoordSys * source = 0;

source = dataSource->GetGeodeticCoordSys(BMG_T("EPSG"), BMG_T("4267"));

VerticalCoordSys * sourceVR = 0;

sourceVR = dataSource->GetVerticalCoordSys(BMG_T("EPSG"), BMG_T("5773"));

ProjectedCoordSys * target = 0;

target = dataSource->GetProjectedCoordSys(BMG_T("EPSG"), BMG_T("26919"));

VerticalCoordSys * targetVR = 0;

targetVR = dataSource->GetVerticalCoordSys(BMG_T("BMG"), BMG_T("ELLIPSOIDAL_HEIGHT_VERTICAL_COORD_SYS"));

Here we have selected the NAD27 GeodeticCoordSys with the EGM96 VerticalCoordSys as our source coordinate systems, and the UTM 19N ProjectedCoordSys with the ellipsoid height VerticalCoordSys as our target coordinate systems.

 

Selecting CoordTransforms

Since our source and target coordinate systems use different GeodeticCoordSys definitions, we will need to provide one or more CoordTransforms. There are multiple ways to find the CoordTransforms needed for a ConcatenatedTransform, and Lesson 6 describes these methods. For the purpose of this lesson, we will just retrieve a single HorizontalTransform and VerticalTransform from the DataSource.

Serializable * horizontalTransform = 0;

horizontalTransform = dataSource->GetCoordinateTransform(L"EPSG", L"1241");

 

VerticalTransform * verticalTransform = 0;

verticalTransform = dataSource->GetVerticalTransform(L"EPSG", L"10084");

 

Creating a ConcatenatedTransform

We now have a source horizontal and vertical coordinate system, a target horizontal coordinate system, and all of the CoordTransform objects required to go between the systems. We are now ready to construct our ConcatenatedTransform:

ConcatenatedTransform * concatTransform = 0;

concatTransform = ConcatenatedTransform::CreateConcatenatedTransform();

concatTransform->get_Sources().AddBack(*source);

concatTransform->get_Sources().AddBack(*sourceVR);

concatTransform->get_Targets().AddBack(*target);

concatTransform->get_Targets().AddBack(*targetVR);

concatTransform->get_Transforms().AddBack(*horizontalTransform);

       concatTransform->get_Transforms().AddBack(*verticalTransform);

It is also possible to intentionally not use a CoordTransform by not populating the Transforms property. This will cause errors during calculation, and should be avoided. Users should be aware that some coordinate shifting may occur when transforming data from one CoordSys to another, even when no CoordTransforms are required, if Projections are being applied.

Initializing a Point Transformer

Now that our ConcatenatedTransform is properly setup it’s time to create a PointTransformer.

Most of the VerticalTransforms supported by GeoCalc require additional data files that were not installed with GeoCalc. These files can be obtained free of charge from our website or by right clicking on their associated data source object in the DatasourcePicker and DatasourceEdito dialogs and selecting “Download Missing Files”.

Now that we have the necessary files, we can generate our PointTransformer.

GEOCALCPBW_NAMESPACE::PointTransformer * pTransformer = 0;

pTransformer = concatTransform->GeneratePointTransformer();

Transforming Points

Our PointTransformer is now set up and ready to perform a three dimensional coordinate transformation.

Here is how we perform the transformation:

CoordPoint * inPt = 0;

inPt = pTransformer->GetSourceCoordPoint();

CoordPoint * outPt = 0;

outPt = pTransformer->GetTargetCoordPoint();

inPt->set_InUnits(-69.00051903, 43.99991912, 50);

try

{

if(! pTransformer->ConvertSourceToTarget(*inPt, *outPt))

{

// ConvertAhead failed

return;

}

}

catch(GeoCalcException & ex)

{

if(ex.get_ErrorCode() == GeoCalcException::Code::InPointWrongType)

{

// Then inPt has the wrong ClassType

return;

}

else if(ex.get_ErrorCode() == GeoCalcException::Code::OutPointWrongType)

{

// Then outPt has the wrong ClassType

return;

}

else if(ex.get_ErrorCode() == GeoCalcException::Code::InPointOutOfBounds)

{

// Then inPt is not a valid point within the SourceCoordSys

return;

}

else if(ex.get_ErrorCode() == GeoCalcException::Code::OutPointOutOfBounds)

{

// Then outPt is not a valid point within the TargetCoordSsy

return;

}

else if(ex.get_ErrorCode() == GeoCalcException::Code::FileNotFound)

{

//Then the file which one of the Transfroms it based on cannot be found.

return;

}

}

double east, north, height;

outPt->get_InUnits(east, north, height);

The values of East, North, and Height should now match the corresponding values shown above, placing us just 20 miles west of beautiful Isle Au Haut, Maine.  

Clean Up

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

if(concatTransform) Disposal::Dispose(concatTransform);

if(source) Disposal::Dispose(source);

if(sourceVR) Disposal::Dispose(sourceVR);

if(target) Disposal::Dispose(target);

if(targetVR) Disposal::Dispose(targetVR);

if(horizontalTransform) Disposal::Dispose(horizontalTransform);

if(verticalTransform) Disposal::Dispose(verticalTransform);

if(pTransformer) Disposal::Dispose(pTransformer);

if(inPt) Disposal::Dispose(inPt);

if(outPt) Disposal::Dispose(outPt);

if(dataSource) Disposal::Dispose(dataSource);