GeoTrans_ToGlobalDirection function

Applies To: Implementing a custom GeoTransformer

Performs coordinates transformation used in the process chain that computes global ground (real world) coordinates, in reference to a chosen coordinate system. In this document, we will refer to the direction of this transformation as ToGlobal (also know as “image to ground”). Our convention on defining, for example, a correction is that we correct towards global ground coordinates, which means this function will 'correct'.

GeoTransCore component will forward this call to your implementation whenever coordinates must be transformed by your custom GeoTransformer, and is supposed to invert, when possible, the transformation performed by GeoTrans_FromGlobalDirection function.

[C]

BOOL __stdcall GeoTrans_ToGlobalDirection(

HGeoTrans hInstance, // handle of GeoTransformer instance

GeoTransData * outData, // pointer to output package

const GeoTransData * inData // pointer to input package

);

[C++]

extern "C" BOOL __stdcall GeoTrans_ToGlobalDirection(

HGeoTrans hInstance, // handle of GeoTransformer instance

GeoTransData& outData, // output package

const GeoTransData& inData // input package

);

Arguments

[in] hInstance

Custom GeoTransformer instance handle. This handle specifies which instance should be used when transforming given coordinates. The given handle value may point to any type of GeoTransformer supported by your implementation. Refer to the documentation of Instance_Create function for details about a handle to a GeoTransformer instance.

HGeoTrans type is defined as a HANDLE in GeoTransCreation namespace.

Note: It is not required to test against NULL the value of the handle, since GeoTransCore component ensures its validity.

[in,out] outData

An output package that returns the transformed coordinates. Please refer to GeoTransData structure’s documentation for details of a package self-descriptive content.

Note: Do not assume that both input and output packages have the same type. Testing their validity and compatibility should be considered. You may choose to support only a restricted set of package types (lets say, only 3D arrays), but your implementation should not make any assumptions about their types (not even based on human logic, like receiving 3 points in the input package means 3 points can be returned in the output package).

Important: Do not change the type of the output package! Also, if applicable, array dimension must not be changed! The only data that may be changed in this structure represents coordinates. All other members are given by calling components to describe the required output format, as it was previously allocated.

[in] inData

A read-only input package that contains coordinates to be transformed. The package is self-descriptive through its dwType member, as documented in GeoTransData structure.

Return Value

Return FALSE when outData package does not contain expected transformed coordinates. Setting an error code with SetLastError function will identify the reason(s) for failure. When the transformation was successful, but some warning(s) should be signaled, set an appropriate code but return TRUE.

Reporting errors and warnings: To learn how to provide descriptions for your custom error and warning codes, please see Error_FormatMessage function documentation. GTM_Errors_Warnings namespace enumerates some recommended codes and descriptions to be supported, from which the following would be set by this function:

Constant

Description

err_data_general

Cannot transform in this direction.

err_data_invalid_in

Invalid input data.

err_data_invalid_out

Invalid output data.

err_data_type_in

Unsupported input data type.

err_data_type_out

Unsupported output data type.

err_data_types_size

Input and output data types are incompatible.

err_data_types_dif

Input and output must have the same data type.

err_data_pnts_dif

Input and output arrays must have same size.

Remarks

When the transformation that you’re implementing is invertible only under certain circumstances, then its reverse transformation may be quite an expensive process. Even when not supported, the ToGlobal transformation could be substituted by an iterative algorithm available in GeoTransCore component which tries to approximate the inverse of a supported FromGlobal transformation. For example, when implementing projections onto a 2D plane, one could choose to support a transformation of object-coordinates (lets say an image point) paired with the 2D plane elevation (ground Z). Obviously, the resulting output coordinates will depend on given elevation, which will remain unchanged. In conclusion, depending on the purpose of your custom GeoTransformer, this function may require special input coordinates, an expensive processing, or may not be possible to implement.

There are quite a few considerations when implementing this function, but probably the most important of all is that both input and output packages may point to the same buffer of coordinates. Thus, it is essential that your implementation makes a copy of an input coordinate before writing the corresponding output coordinate in case that original value still needs to be used in the computation. Following sample code shows the undesired behavior of replacing the input data when shares the same memory with the output data:

[C / C++]

#include <windows.h>

#include <math.h>

#define M_PI 3.14159265358979323846

 

void Rotate2dPoints(double angleDegrees,const double * inPoints,double * outPoints,size_t noPoints) {

double angleRadians = angleDegrees * M_PI / 180;

register int idx = noPoints;

while (idx) { --idx;

outPoints[2*idx] = cos(angleRadians) * inPoints[2*idx] - sin(angleRadians) * inPoints[2*idx+1];

/* at this point, value of inPoints[2*idx] is also changed */

outPoints[2*idx+1] = sin(angleRadians) * inPoints[2*idx] + cos(angleRadians) * inPoints[2*idx+1];

}

}

int main(int ,char ** ,char ** ) {

double points[4] = {0};

points[0] = points[3] = 1.0;

Rotate2dPoints(60.0,points,points,2);

return 0;

}

When checking the type of I / O packages given as parameters, only the least significant byte defines the structure of the package (bits 8-31 are reserved for geo-interpretation). This means you should compare only the first byte of dwType member (use dwType & 0xFF) of the GeoTransData structure against the enumerated values defined in GeoTransDataTypes namespace. For your implementation to remain compatible with later versions of the GeoTransCore component, do not try to process undefined package types. Simply set an error code that describes an unsupported argument type and return FALSE.

Multi-threading: Concurrent calls from different threads will expect this implementation to be thread safe.

Exception handling: Careful interpretation of the I / O packages represent the most important task in avoiding exceptions.

Requirements

Platform

32 bit Windows OS

Environment

ANSI C / C++ Standard compliant

API

__stdcall calling convention; by name, undecorated "C" export

Unicode support

SBCS (ASCII) only

Dependency

kernel32.dll

Reference

kernel32.lib

Include

windows.h

Example

This sample was depicted from an implementation of a 2D affine transformation (please note that it completely ignores Z values):

[C++]

#define ERR_TDP_INVALID(dwFlags,trans_only)\

if (dwFlags & trans_only) {\

SetLastError(err_data_general);\

return FALSE;\

}\

if (!inData.as) {\

SetLastError(err_data_invalid_in);\

return FALSE;\

}\

if (!outData.as) {\

SetLastError(err_data_invalid_out);\

return FALSE;\

}

#define ERR_TDP_UNSUPPORTED(mask,condition)\

if ((inData.dwType mask) condition) {\

SetLastError(err_data_type_in);\

return FALSE;\

}\

if ((outData.dwType mask) condition) {\

SetLastError(err_data_type_out);\

return FALSE;\

}

#define ERR_TDP_INCOMPATIBLE()\

if ((inData.dwType & 0x6) != (outData.dwType & 0x6)) {\

SetLastError(err_data_types_size);\

return FALSE;\

}

#define ERR_TDP_SIZE()\

if (inData.as->MPoints2D.pntNo != outData.as->MPoints2D.pntNo) {\

SetLastError(err_data_pnts_dif);\

return FALSE;\

}

 

#define GEOTRANS_AFFINE(tp,ip,op)\

double x;\

x = (tp.A1 * ip.X) + (tp.A2 * ip.Y) + tp.A0;\

op.Y = (tp.B1 * ip.X) + (tp.B2 * ip.Y) + tp.B0;\

op.X = x;

 

BOOL __stdcall Affine::GeoTrans_ToGlobalDirection(

GeoTransData& outData,

const GeoTransData& inData

) {

ERR_TDP_INVALID(dwFlags,trans_toGlobal_only);

ERR_TDP_UNSUPPORTED(&0xFC,>0);

ERR_TDP_INCOMPATIBLE();

if (inData.dwType & 0x2) { // arrays given

ERR_TDP_SIZE();

int iStride = 3-(inData.dwType & 0x1); // Stride2D=2;Stride3D=3

int oStride = 3-(outData.dwType & 0x1); // Stride2D=2;Stride3D=3

register int idx = inData.as->MPoints2D.pntNo; // same offset in MPoints3D ;)

double * iXYs = (double*)inData.as->MPoints2D.XYs; // same offset in MPoints3D ;)

double * oXYs = (double*)outData.as->MPoints2D.XYs; // same offset in MPoints3D ;)

while (idx) { --idx;

GEOTRANS_AFFINE(tg,(*(VERTEX2D*)iXYs),(*(VERTEX2D*)oXYs));

iXYs += iStride;

oXYs += oStride;

}

return TRUE;

}

VERTEX2D& ip = *&inData.as->Point2D;

VERTEX2D& op = *&outData.as->Point2D;

GEOTRANS_AFFINE(tg,ip,op);

return TRUE;

}

 

extern "C" BOOL __stdcall GeoTrans_ToGlobalDirection(

HGeoTrans hInstance,

GeoTransData& outData,

const GeoTransData& inData

) {

return ((Affine*)hInstance)->GeoTrans_FromGlobalDirection(outData,inData);

}

For a detailed example on how to implement this function, please see Custom GeoTransformer VC++ Sample.

Related Topics

See also: Instance_Create, Instance_Discard, GeoTrans_FromGlobalDirection, Error_FormatMessage, GeoTransCreation, GTM_Errors_Warnings, GeoTransDataTypes, GeoTransData