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 |
Cannot transform in this direction. |
|
Invalid input data. |
|
Invalid output data. |
|
Unsupported input data type. |
|
Unsupported output data type. |
|
Input and output data types are incompatible. |
|
Input and output must have the same data type. |
|
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