UNCLASSIFIED

GeographicTranslator
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Macros
DatumLibraryImplementation.cpp
Go to the documentation of this file.
1 // CLASSIFICATION: UNCLASSIFIED
2 
3 /***************************************************************************/
4 /* RSC IDENTIFIER: Datum Library Implementation
5  *
6  * ABSTRACT
7  *
8  * This component provides datum shifts for a large collection of local
9  * datums, WGS72, and WGS84. A particular datum can be accessed by using its
10  * standard 5-letter code to find its index in the datum table. The index
11  * can then be used to retrieve the name, type, ellipsoid code, and datum
12  * shift parameters, and to perform shifts to or from that datum.
13  *
14  * By sequentially retrieving all of the datum codes and/or names, a menu
15  * of the available datums can be constructed. The index values resulting
16  * from selections from this menu can then be used to access the parameters
17  * of the selected datum, or to perform datum shifts involving that datum.
18  *
19  * This component supports both 3-parameter local datums, for which only X,
20  * Y, and Z translations relative to WGS 84 have been defined, and
21  * 7-parameter local datums, for which X, Y, and Z rotations, and a scale
22  * factor, are also defined. It also includes entries for WGS 84 (with an
23  * index of 0), and WGS 72 (with an index of 1), but no shift parameter
24  * values are defined for these.
25  *
26  * This component provides datum shift functions for both geocentric and
27  * geodetic coordinates. WGS84 is used as an intermediate state when
28  * shifting from one local datum to another. When geodetic coordinates are
29  * given Molodensky's method is used, except near the poles where the 3-step
30  * step method is used instead. Specific algorithms are used for shifting
31  * between WGS72 and WGS84.
32  *
33  * This component depends on two data files, named 3_param.dat and
34  * 7_param.dat, which contain the datum parameter values. Copies of these
35  * files must be located in the directory specified by the value of the
36  * environment variable "MSPCCS_DATA", if defined, or else in the current
37  * directory whenever a program containing this component is executed.
38  *
39  * Additional datums can be added to these files, either manually or using
40  * the Create_Datum function. However, if a large number of datums are
41  * added, the datum table array sizes in this component will have to be
42  * increased.
43  *
44  * This component depends on two other components: the Ellipsoid component
45  * for access to ellipsoid parameters; and the Geocentric component for
46  * conversions between geodetic and geocentric coordinates.
47  *
48  * ERROR HANDLING
49  *
50  * This component checks for input file errors and input parameter errors.
51  * If an invalid value is found, the error code is combined with the current
52  * error code using the bitwise or. This combining allows multiple error
53  * codes to be returned. The possible error codes are:
54  *
55  * DATUM_NO_ERROR : No errors occurred in function
56  * DATUM_NOT_INITIALIZED_ERROR : Datum module has not been initialized
57  * DATUM_7PARAM_FILE_OPEN_ERROR : 7 parameter file opening error
58  * DATUM_7PARAM_FILE_PARSING_ERROR : 7 parameter file structure error
59  * DATUM_3PARAM_FILE_OPEN_ERROR : 3 parameter file opening error
60  * DATUM_3PARAM_FILE_PARSING_ERROR : 3 parameter file structure error
61  * DATUM_INVALID_INDEX_ERROR : Index out of valid range (less than one
62  * or more than Number_of_Datums)
63  * DATUM_INVALID_SRC_INDEX_ERROR : Source datum index invalid
64  * DATUM_INVALID_DEST_INDEX_ERROR : Destination datum index invalid
65  * DATUM_INVALID_CODE_ERROR : Datum code not found in table
66  * DATUM_LAT_ERROR : Latitude out of valid range (-90 to 90)
67  * DATUM_LON_ERROR : Longitude out of valid range (-180 to
68  * 360)
69  * DATUM_SIGMA_ERROR : Standard error values must be positive
70  * (or -1 if unknown)
71  * DATUM_DOMAIN_ERROR : Domain of validity not well defined
72  * DATUM_ELLIPSE_ERROR : Error in ellipsoid module
73  * DATUM_NOT_USERDEF_ERROR : Datum code is not user defined - cannot
74  * be deleted
75  *
76  *
77  * REUSE NOTES
78  *
79  * Datum is intended for reuse by any application that needs access to
80  * datum shift parameters relative to WGS 84.
81  *
82  *
83  * REFERENCES
84  *
85  * Further information on Datum can be found in the Reuse Manual.
86  *
87  * Datum originated from : U.S. Army Topographic Engineering Center (USATEC)
88  * Geospatial Information Division (GID)
89  * 7701 Telegraph Road
90  * Alexandria, VA 22310-3864
91  *
92  * LICENSES
93  *
94  * None apply to this component.
95  *
96  * RESTRICTIONS
97  *
98  * Datum has no restrictions.
99  *
100  * ENVIRONMENT
101  *
102  * Datum was tested and certified in the following environments:
103  *
104  * 1. Solaris 2.5 with GCC 2.8.1
105  * 2. MS Windows 95 with MS Visual C++ 6
106  *
107  * MODIFICATIONS
108  *
109  * Date Description
110  * ---- -----------
111  * 03/30/97 Original Code
112  * 05/28/99 Added user-definable datums (for JMTK)
113  * Added datum domain of validity checking (for JMTK)
114  * Added datum shift accuracy calculation (for JMTK)
115  * 06/27/06 Moved data files to data directory
116  * 03-14-07 Original C++ Code
117  * 03-21-08 Added check for west, east longitude values > 180
118  * 06-11-10 S. Gillis, BAEts26724, Fixed memory error problem
119  * when MSPCCS_DATA is not set
120  * 07-07-10 K.Lam, BAEts27269, Replace C functions in threads.h
121  * with C++ methods in classes CCSThreadMutex
122  * 05/17/11 T. Thompson, BAEts27393, let user know when problem
123  * is due to undefined MSPCCS_DATA
124  * 07/13/12 K.Lam, BAEts29544, fixed problem with create datum
125  * 07/17/12 S.Gillis,MSP_00029561,Fixed problem with deleting datum
126  * 08/13/12 S. Gillis, MSP_00029654, Added lat/lon to define7ParamDatum
127  * 10/02/17 M. Thakkar : LSC-13195 : Fixed array out of bounds error (DATUM_CODE_LENGTH)
128  */
129 
130 
131 /***************************************************************************/
132 /*
133  * INCLUDES
134  */
135 
136 #include <math.h>
137 #include <stdio.h>
138 #include <stdlib.h>
139 #include <ctype.h>
142 #include "EllipsoidParameters.h"
143 #include "SevenParameterDatum.h"
144 #include "ThreeParameterDatum.h"
145 #include "Geocentric.h"
146 #include "Datum.h"
147 #include "CartesianCoordinates.h"
148 #include "GeodeticCoordinates.h"
150 #include "ErrorMessages.h"
151 #include "Accuracy.h"
152 #include "CCSThreadMutex.h"
153 #include "CCSThreadLock.h"
154 
155 /*
156  * math.h - standard C mathematics library
157  * EllipsoidLibrary.h - used to get ellipsoid parameters
158  * SevenParameterDatum.h - creates a 7 parameter datum
159  * ThreeParameterDatum.h - creates a 3 parameter datum
160  * Geocentric.h - converts between geodetic and geocentric coordinates
161  * Datum.h - used to store individual datum information
162  * DatumLibraryImplementation.h - for error ehecking and error codes
163  * CCSThreadMutex.h - used for thread safety
164  * CCSThreadLock.h - used for thread safety
165  * CartesianCoordinates.h - defines cartesian coordinates
166  * GeodeticCoordinates.h - defines geodetic coordinates
167  * CoordinateConversionException.h - Exception handler
168  * ErrorMessages.h - Contains exception messages
169  */
170 
171 
172 using namespace MSP::CCS;
173 using MSP::CCSThreadMutex;
174 using MSP::CCSThreadLock;
175 
176 /***************************************************************************/
177 /*
178  * DEFINES
179  */
180 
181 const double SECONDS_PER_RADIAN = 206264.8062471; /* Seconds in a radian */
182 const double PI = 3.14159265358979323e0;
183 const double PI_OVER_2 = (PI / 2.0);
184 const double PI_OVER_180 = (PI / 180.0);
185 const double _180_OVER_PI = (180.0 / PI);
186 const double TWO_PI = (2.0 * PI);
187 const double MIN_LAT = (-PI/2.0);
188 const double MAX_LAT = (+PI/2.0);
189 const double MIN_LON = -PI;
190 const double MAX_LON = (2.0 * PI);
191 const int DATUM_CODE_LENGTH = 7;
192 const int DATUM_NAME_LENGTH = 33;
193 const int ELLIPSOID_CODE_LENGTH = 3;
194 const int MAX_WGS = 2;
195 const double MOLODENSKY_MAX = (89.75 * PI_OVER_180); /* Polar limit */
196 const int FILENAME_LENGTH = 128;
197 const char *WGS84_Datum_Code = "WGE";
198 const char *WGS72_Datum_Code = "WGC";
199 
200 
201 /************************************************************************/
202 /* LOCAL FUNCTIONS
203  *
204  */
205 
207  const double a,
208  const double da,
209  const double f,
210  const double df,
211  const double dx,
212  const double dy,
213  const double dz,
214  const double sourceLongitude,
215  const double sourceLatitude,
216  const double sourceHeight )
217 {
218 /*
219  * The function molodenskyShift shifts geodetic coordinates
220  * using the Molodensky method.
221  *
222  * a : Semi-major axis of source ellipsoid in meters (input)
223  * da : Destination a minus source a (input)
224  * f : Flattening of source ellipsoid (input)
225  * df : Destination f minus source f (input)
226  * dx : X coordinate shift in meters (input)
227  * dy : Y coordinate shift in meters (input)
228  * dz : Z coordinate shift in meters (input)
229  * sourceLongitude : Longitude in radians (input)
230  * sourceLatitude : Latitude in radians. (input)
231  * sourceHeight : Height in meters. (input)
232  * targetLongitude : Calculated longitude in radians. (output)
233  * targetLatitude : Calculated latitude in radians. (output)
234  * targetHeight : Calculated height in meters. (output)
235  */
236 
237  double tLon_in; /* temp longitude */
238  double e2; /* Intermediate calculations for dp, dl */
239  double ep2; /* Intermediate calculations for dp, dl */
240  double sin_Lat; /* sin(Latitude_1) */
241  double sin2_Lat; /* (sin(Latitude_1))^2 */
242  double sin_Lon; /* sin(Longitude_1) */
243  double cos_Lat; /* cos(Latitude_1) */
244  double cos_Lon; /* cos(Longitude_1) */
245  double w2; /* Intermediate calculations for dp, dl */
246  double w; /* Intermediate calculations for dp, dl */
247  double w3; /* Intermediate calculations for dp, dl */
248  double m; /* Intermediate calculations for dp, dl */
249  double n; /* Intermediate calculations for dp, dl */
250  double dp; /* Delta phi */
251  double dp1; /* Delta phi calculations */
252  double dp2; /* Delta phi calculations */
253  double dp3; /* Delta phi calculations */
254  double dl; /* Delta lambda */
255  double dh; /* Delta height */
256  double dh1; /* Delta height calculations */
257  double dh2; /* Delta height calculations */
258 
259  if (sourceLongitude > PI)
260  tLon_in = sourceLongitude - TWO_PI;
261  else
262  tLon_in = sourceLongitude;
263 
264  e2 = 2 * f - f * f;
265  ep2 = e2 / (1 - e2);
266  sin_Lat = sin(sourceLatitude);
267  cos_Lat = cos(sourceLatitude);
268  sin_Lon = sin(tLon_in);
269  cos_Lon = cos(tLon_in);
270  sin2_Lat = sin_Lat * sin_Lat;
271  w2 = 1.0 - e2 * sin2_Lat;
272  w = sqrt(w2);
273  w3 = w * w2;
274  m = (a * (1.0 - e2)) / w3;
275  n = a / w;
276  dp1 = cos_Lat * dz - sin_Lat * cos_Lon * dx - sin_Lat * sin_Lon * dy;
277  dp2 = ((e2 * sin_Lat * cos_Lat) / w) * da;
278  dp3 = sin_Lat * cos_Lat * (2.0 * n + ep2 * m * sin2_Lat) * (1.0 - f) * df;
279  dp = (dp1 + dp2 + dp3) / (m + sourceHeight);
280  dl = (-sin_Lon * dx + cos_Lon * dy) / ((n + sourceHeight) * cos_Lat);
281  dh1 = (cos_Lat * cos_Lon * dx) + (cos_Lat * sin_Lon * dy) + (sin_Lat * dz);
282  dh2 = -(w * da) + ((a * (1 - f)) / w) * sin2_Lat * df;
283  dh = dh1 + dh2;
284 
285  double targetLatitude = sourceLatitude + dp;
286  double targetLongitude = sourceLongitude + dl;
287  double targetHeight = sourceHeight + dh;
288 
289  if (targetLongitude > TWO_PI)
290  targetLongitude -= TWO_PI;
291  if (targetLongitude < (- PI))
292  targetLongitude += TWO_PI;
293 
294  return new GeodeticCoordinates(
295  CoordinateType::geodetic, targetLongitude, targetLatitude, targetHeight );
296 }
297 
298 
299 /************************************************************************/
300 /* FUNCTIONS
301  *
302  */
303 
304 /* This class is a safeguard to make sure the singleton gets deleted
305  * when the application exits
306  */
307 namespace MSP
308 {
309  namespace CCS
310  {
312  {
313  public:
314 
316  {
317  CCSThreadLock lock(&DatumLibraryImplementation::mutex);
318  DatumLibraryImplementation::deleteInstance();
319  }
320 
322  }
323 }
324 
325 // Make this class a singleton, so the data files are only initialized once
326 CCSThreadMutex DatumLibraryImplementation::mutex;
327 DatumLibraryImplementation* DatumLibraryImplementation::instance = 0;
328 int DatumLibraryImplementation::instanceCount = 0;
329 
330 
332 {
333  CCSThreadLock lock(&mutex);
334  if( instance == 0 )
335  instance = new DatumLibraryImplementation;
336 
337  instanceCount++;
338 
339  return instance;
340 }
341 
342 
344 {
345 /*
346  * The function removeInstance removes this DatumLibraryImplementation
347  * instance from the total number of instances.
348  */
349  CCSThreadLock lock(&mutex);
350  if( --instanceCount < 1 )
351  {
352  deleteInstance();
353  }
354 }
355 
356 
357 void DatumLibraryImplementation::deleteInstance()
358 {
359 /*
360  * Delete the singleton.
361  */
362 
363  if( instance != 0 )
364  {
365  delete instance;
366  instance = 0;
367  }
368 }
369 
370 
372  _ellipsoidLibraryImplementation( 0 ),
373  datum3ParamCount( 0 ),
374  datum7ParamCount( 0 )
375 {
376  loadDatums();
377 }
378 
379 
381  const DatumLibraryImplementation &dl )
382 {
383  int size = dl.datumList.size();
384  for( int i = 0; i < size; i++ )
385  {
386  switch( dl.datumList[i]->datumType() )
387  {
389  datumList.push_back( new ThreeParameterDatum(
390  *( ( ThreeParameterDatum* )( dl.datumList[i] ) ) ) );
391  break;
393  datumList.push_back( new SevenParameterDatum(
394  *( ( SevenParameterDatum* )( dl.datumList[i] ) ) ) );
395  break;
398  datumList.push_back( new Datum( *( dl.datumList[i] ) ) );
399  break;
400  }
401  }
402 
403  _ellipsoidLibraryImplementation = dl._ellipsoidLibraryImplementation;
404  datum3ParamCount = dl.datum3ParamCount;
405  datum7ParamCount = dl.datum7ParamCount;
406 }
407 
408 
410 {
411  std::vector<Datum*>::iterator iter = datumList.begin();
412  while( iter != datumList.end() )
413  {
414  delete( *iter );
415  iter++;
416  }
417  datumList.clear();
418 
419  _ellipsoidLibraryImplementation = 0;
420 }
421 
422 
424  const DatumLibraryImplementation &dl )
425 {
426  if ( &dl == this )
427  return *this;
428 
429  int size = dl.datumList.size();
430  for( int i = 0; i < size; i++ )
431  {
432  switch( dl.datumList[i]->datumType() )
433  {
435  datumList.push_back( new ThreeParameterDatum(
436  *( ( ThreeParameterDatum* )( dl.datumList[i] ) ) ) );
437  break;
439  datumList.push_back( new SevenParameterDatum(
440  *( ( SevenParameterDatum* )( dl.datumList[i] ) ) ) );
441  break;
444  datumList.push_back( new Datum( *( dl.datumList[i] ) ) );
445  break;
446  }
447  }
448 
449  _ellipsoidLibraryImplementation = dl._ellipsoidLibraryImplementation;
450  datum3ParamCount = dl.datum3ParamCount;
451  datum7ParamCount = dl.datum7ParamCount;
452 
453  return *this;
454 }
455 
456 
458  const char *code,
459  const char *name,
460  const char *ellipsoidCode,
461  double deltaX,
462  double deltaY,
463  double deltaZ,
464  double sigmaX,
465  double sigmaY,
466  double sigmaZ,
467  double westLongitude,
468  double eastLongitude,
469  double southLatitude,
470  double northLatitude )
471 {
472 /*
473  * The function define3ParamDatum creates a new local 3-parameter datum with the
474  * specified code, name, and axes. If the datum table has not been initialized,
475  * the specified code is already in use, or a new version of the 3-param.dat
476  * file cannot be created, an exception is thrown.
477  * Note that the indexes of all datums in the datum table may be
478  * changed by this function.
479  *
480  * code : 5-letter new datum code. (input)
481  * name : Name of the new datum (input)
482  * ellipsoidCode : 2-letter code for the associated ellipsoid (input)
483  * deltaX : X translation to WGS84 in meters (input)
484  * deltaY : Y translation to WGS84 in meters (input)
485  * deltaZ : Z translation to WGS84 in meters (input)
486  * sigmaX : Standard error in X in meters (input)
487  * sigmaY : Standard error in Y in meters (input)
488  * sigmaZ : Standard error in Z in meters (input)
489  * westLongitude : Western edge of validity rectangle in radians (input)
490  * eastLongitude : Eastern edge of validity rectangle in radians (input)
491  * southLatitude : Southern edge of validity rectangle in radians(input)
492  * northLatitude : Northern edge of validity rectangle in radians(input)
493  */
494 
495  char datum_Code[DATUM_CODE_LENGTH];
496  long index = 0;
497  long ellipsoid_index = 0;
498  long code_length = 0;
499  char *PathName = NULL;
500  FILE *fp_3param = NULL;
501 
502  if (!(((sigmaX > 0.0) || (sigmaX == -1.0)) &&
503  ((sigmaY > 0.0) || (sigmaY == -1.0)) &&
504  ((sigmaZ > 0.0) || (sigmaZ == -1.0))))
506 
507  if ((southLatitude < MIN_LAT) || (southLatitude > MAX_LAT))
509  if ((westLongitude < MIN_LON) || (westLongitude > MAX_LON))
511  if ((northLatitude < MIN_LAT) || (northLatitude > MAX_LAT))
513  if ((eastLongitude < MIN_LON) || (eastLongitude > MAX_LON))
515  if (southLatitude >= northLatitude)
517  if((westLongitude >= eastLongitude) &&
518  (westLongitude >= 0 && westLongitude < 180) &&
519  (eastLongitude >= 0 && eastLongitude < 180))
521 
522  // assume the datum code is new
523  bool isNewDatumCode = true;
524  try
525  {
526  // check if datum code exists
527  datumIndex( code, &index );
528  // get here if datum code is found in current datum table
529  isNewDatumCode = false;
530  }
532  {
533  // the datum code is new, keep going
534  }
535 
536  // the datum code exists in current datum table, throw an error
537  if ( !isNewDatumCode )
539 
540  code_length = strlen( code );
541 
542  if( code_length > ( DATUM_CODE_LENGTH-1 ) )
544 
545  if( _ellipsoidLibraryImplementation )
546  {
547  _ellipsoidLibraryImplementation->ellipsoidIndex(
548  ellipsoidCode, &ellipsoid_index );
549  }
550  else
552 
553 
554  strcpy( datum_Code, code );
555  /* Convert code to upper case */
556  for( long i = 0; i < code_length; i++ )
557  datum_Code[i] = ( char )toupper( datum_Code[i] );
558 
559  int numDatums = datumList.size();
560  datumList.push_back( new ThreeParameterDatum(
561  numDatums, ( char* )datum_Code, ( char* )ellipsoidCode,
562  ( char* )name, DatumType::threeParamDatum, deltaX, deltaY, deltaZ,
563  westLongitude, eastLongitude, southLatitude, northLatitude, sigmaX,
564  sigmaY, sigmaZ, true ) );
565  datum3ParamCount++;
566 
567  write3ParamFile();
568 }
569 
570 
572  const char *code,
573  const char *name,
574  const char *ellipsoidCode,
575  double deltaX,
576  double deltaY,
577  double deltaZ,
578  double rotationX,
579  double rotationY,
580  double rotationZ,
581  double scale,
582  double westLongitude,
583  double eastLongitude,
584  double southLatitude,
585  double northLatitude )
586 {
587 /*
588  * The function define7ParamDatum creates a new local 7-parameter datum with the
589  * specified code, name, and axes. If the datum table has not been initialized,
590  * the specified code is already in use, or a new version of the 7-param.dat
591  * file cannot be created, an exception is thrown.
592  * Note that the indexes of all datums in the datum table may be
593  * changed by this function.
594  *
595  * code : 5-letter new datum code. (input)
596  * name : Name of the new datum (input)
597  * ellipsoidCode : 2-letter code for the associated ellipsoid (input)
598  * deltaX : X translation to WGS84 in meters (input)
599  * deltaY : Y translation to WGS84 in meters (input)
600  * deltaZ : Z translation to WGS84 in meters (input)
601  * rotationX : X rotation to WGS84 in arc seconds (input)
602  * rotationY : Y rotation to WGS84 in arc seconds (input)
603  * rotationZ : Z rotation to WGS84 in arc seconds (input)
604  * scale : Scale factor (input)
605  * westLongitude : Western edge of validity rectangle in radians (input)
606  * eastLongitude : Eastern edge of validity rectangle in radians (input)
607  * southLatitude : Southern edge of validity rectangle in radians(input)
608  * northLatitude : Northern edge of validity rectangle in radians(input)
609  */
610 
611  char datum_Code[DATUM_CODE_LENGTH];
612  long index = 0;
613  long ellipsoid_index = 0;
614  long code_length = 0;
615  char *PathName = NULL;
616  FILE *fp_7param = NULL;
617 
618  if ((rotationX < -60.0) || (rotationX > 60.0))
620  if ((rotationY < -60.0) || (rotationY > 60.0))
622  if ((rotationZ < -60.0) || (rotationZ > 60.0))
624 
625  if ((scale < -0.001) || (scale > 0.001))
627 
628  // assume the datum code is new
629  bool isNewDatumCode = true;
630  try
631  {
632  // check if datum code exists
633  datumIndex( code, &index );
634  // get here if datum code is found in current datum table
635  isNewDatumCode = false;
636  }
638  {
639  // the datum code is new, keep going
640  }
641 
642  // the datum code exists in current datum table, throw an error
643  if ( !isNewDatumCode )
645 
646  code_length = strlen( code );
647  if( code_length > ( DATUM_CODE_LENGTH-1 ) )
649 
650  if( _ellipsoidLibraryImplementation )
651  {
652  _ellipsoidLibraryImplementation->ellipsoidIndex(
653  ellipsoidCode, &ellipsoid_index );
654  }
655  else
657 
658  long i;
659  strcpy( datum_Code, code );
660  /* Convert code to upper case */
661  for( i = 0; i < code_length; i++ )
662  datum_Code[i] = ( char )toupper( datum_Code[i] );
663 
664  datumList.insert( datumList.begin() + MAX_WGS + datum7ParamCount,
665  new SevenParameterDatum( datum7ParamCount, ( char* )datum_Code,
666  ( char* )ellipsoidCode, ( char* )name, DatumType::sevenParamDatum,
667  deltaX, deltaY, deltaZ,
668  westLongitude, eastLongitude, southLatitude, northLatitude,
669  rotationX / SECONDS_PER_RADIAN,
670  rotationY / SECONDS_PER_RADIAN, rotationZ / SECONDS_PER_RADIAN,
671  scale, true ) );
672  datum7ParamCount++;
673 
674  write7ParamFile();
675 }
676 
677 
679 {
680 /*
681  * The function removeDatum deletes a local (3-parameter) datum with the
682  * specified code. If the datum table has not been initialized or a new
683  * version of the 3-param.dat file cannot be created, an exception is thrown,
684  * Note that the indexes of all datums
685  * in the datum table may be changed by this function.
686  *
687  * code : 5-letter datum code. (input)
688  *
689  */
690 
691  char *PathName = NULL;
692  FILE *fp_3param = NULL;
693  FILE *fp_7param = NULL;
694  long index = 0;
695  bool delete_3param_datum = true;
696 
697  datumIndex( code, &index );
698 
699  if( datumList[index]->datumType() == DatumType::threeParamDatum )
700  {
701  if( !( ( ThreeParameterDatum* )datumList[index] )->userDefined() )
703  }
704  else if( datumList[index]->datumType() == DatumType::sevenParamDatum )
705  {
706  delete_3param_datum = false;
707  if( !( ( SevenParameterDatum* )datumList[index] )->userDefined() )
709  }
710  else
712 
713  datumList.erase( datumList.begin() + index );
714 
715  if( !delete_3param_datum )
716  {
717  datum7ParamCount--;
718 
719  write7ParamFile();
720  }
721  else if( delete_3param_datum )
722  {
723  datum3ParamCount--;
724 
725  write3ParamFile();
726  }
727 }
728 
729 
731 {
732 /*
733  * The function datumCount returns the number of Datums in the table
734  * if the table was initialized without error.
735  *
736  * count : number of datums in the datum table (output)
737  */
738 
739  *count = datumList.size();
740 }
741 
742 
743 void DatumLibraryImplementation::datumIndex( const char *code, long *index )
744 {
745 /*
746  * The function datumIndex returns the index of the datum with the
747  * specified code.
748  *
749  * code : The datum code being searched for. (input)
750  * index : The index of the datum in the table with the (output)
751  * specified code.
752  */
753 
754  char temp_code[DATUM_CODE_LENGTH];
755  long length;
756  long pos = 0;
757  long i = 0;
758 
759  *index = 0;
760 
761  if( !code )
763 
764  length = strlen( code );
765  if ( length > ( DATUM_CODE_LENGTH-1 ) )
767  else
768  {
769  strcpy( temp_code, code );
770 
771  /* Convert to upper case */
772  for( i=0; i < length; i++ )
773  temp_code[i] = ( char )toupper( temp_code[i] );
774 
775  /* Strip blank spaces */
776  while( pos < length )
777  {
778  if( isspace( temp_code[pos] ) )
779  {
780  for( i=pos; i < length; i++ )
781  temp_code[i] = temp_code[i+1];
782  length -= 1;
783  }
784  else
785  pos += 1;
786  }
787 
788  int numDatums = datumList.size();
789  /* Search for code */
790  i = 0;
791  while( i < numDatums && strcmp( temp_code, datumList[i]->code() ) )
792  {
793  i++;
794  }
795  if( i == numDatums || strcmp( temp_code, datumList[i]->code() ) )
797  else
798  *index = i;
799  }
800 }
801 
802 
803 void DatumLibraryImplementation::datumCode( const long index, char *code )
804 {
805 /*
806  * The function datumCode returns the 5-letter code of the datum
807  * referenced by index.
808  *
809  * index : The index of a given datum in the datum table. (input)
810  * code : The datum Code of the datum referenced by Index. (output)
811  */
812 
813  if( index < 0 || index >= datumList.size() )
815  else
816  strcpy( code, datumList[index]->code() );
817 }
818 
819 
820 void DatumLibraryImplementation::datumName( const long index, char *name )
821 {
822 /*
823  * The function datumName returns the name of the datum referenced by
824  * index.
825  *
826  * index : The index of a given datum in the datum table. (input)
827  * name : The datum Name of the datum referenced by Index. (output)
828  */
829 
830  if( index < 0 || index >= datumList.size() )
832  else
833  strcpy( name, datumList[index]->name() );
834 }
835 
836 
838  const long index, char *code )
839 {
840 /*
841  * The function datumEllipsoidCode returns the 2-letter ellipsoid code
842  * for the ellipsoid associated with the datum referenced by index.
843  *
844  * index : The index of a given datum in the datum table. (input)
845  * code : The ellipsoid code for the ellipsoid associated with (output)
846  * the datum referenced by index.
847  */
848 
849  if( index < 0 || index >= datumList.size() )
851  else
852  strcpy( code, datumList[index]->ellipsoidCode() );
853 }
854 
855 
857  const long index,
858  double *sigmaX,
859  double *sigmaY,
860  double *sigmaZ )
861 {
862 /*
863  * The function datumStandardErrors returns the standard errors in X,Y, & Z
864  * for the datum referenced by index.
865  *
866  * index : The index of a given datum in the datum table (input)
867  * sigma_X : Standard error in X in meters (output)
868  * sigma_Y : Standard error in Y in meters (output)
869  * sigma_Z : Standard error in Z in meters (output)
870  */
871 
872  if( index < 0 || index >= datumList.size() )
874  else
875  {
876  Datum* datum = datumList[index];
877 
878  if( datum->datumType() == DatumType::threeParamDatum )
879  {
880  ThreeParameterDatum* threeParameterDatum = ( ThreeParameterDatum* )datum;
881  *sigmaX = threeParameterDatum->sigmaX();
882  *sigmaY = threeParameterDatum->sigmaY();
883  *sigmaZ = threeParameterDatum->sigmaZ();
884  }
885  else
887  }
888 }
889 
890 
892  const long index,
893  double *rotationX,
894  double *rotationY,
895  double *rotationZ,
896  double *scaleFactor )
897 {
898 /*
899  * The function datumSevenParameters returns parameter values,
900  * used only by a seven parameter datum,
901  * for the datum referenced by index.
902  *
903  * index : The index of a given datum in the datum table. (input)
904  * rotationX : X rotation in radians (output)
905  * rotationY : Y rotation in radians (output)
906  * rotationZ : Z rotation in radians (output)
907  * scaleFactor : Scale factor (output)
908  */
909 
910  if( index < 0 || index >= datumList.size() )
912  else
913  {
914  Datum* datum = datumList[index];
915 
916  if( datum->datumType() == DatumType::sevenParamDatum )
917  {
918  SevenParameterDatum* sevenParameterDatum = ( SevenParameterDatum* )datum;
919 
920  *rotationX = sevenParameterDatum->rotationX();
921  *rotationY = sevenParameterDatum->rotationY();
922  *rotationZ = sevenParameterDatum->rotationZ();
923  *scaleFactor = sevenParameterDatum->scaleFactor();
924  }
925  else
927  }
928 }
929 
930 
932  const long index,
933  double *deltaX,
934  double *deltaY,
935  double *deltaZ )
936 {
937 /*
938  * The function datumTranslationValues returns the translation values
939  * for the datum referenced by index.
940  *
941  * index : The index of a given datum in the datum table. (input)
942  * deltaX : X translation in meters (output)
943  * deltaY : Y translation in meters (output)
944  * deltaZ : Z translation in meters (output)
945  */
946 
947  if( index < 0 || index >= datumList.size() )
949  else
950  {
951  Datum* datum = datumList[index];
952 
953  *deltaX = datum->deltaX();
954  *deltaY = datum->deltaY();
955  *deltaZ = datum->deltaZ();
956  }
957 }
958 
959 
961  const long sourceIndex,
962  const long targetIndex,
963  double longitude,
964  double latitude,
965  Accuracy* sourceAccuracy,
966  Precision::Enum precision )
967 {
968  double sinlat = sin( latitude );
969  double coslat = cos( latitude );
970  double sinlon = sin( longitude );
971  double coslon = cos( longitude );
972  double sigma_delta_lat;
973  double sigma_delta_lon;
974  double sigma_delta_height;
975  double sx, sy, sz;
976  double ce90_in = -1.0;
977  double le90_in = -1.0;
978  double se90_in = -1.0;
979  double ce90_out = -1.0;
980  double le90_out = -1.0;
981  double se90_out = -1.0;
982  double circularError90 = sourceAccuracy->circularError90();
983  double linearError90 = sourceAccuracy->linearError90();
984  double sphericalError90 = sourceAccuracy->sphericalError90();
985 
986  int numDatums = datumList.size();
987 
988  if( ( sourceIndex < 0 ) || ( sourceIndex >= numDatums ) )
990  if( ( targetIndex < 0 ) || ( targetIndex >= numDatums ) )
992  if( ( latitude < ( -90 * PI_OVER_180 ) ) ||
993  ( latitude > ( 90 * PI_OVER_180 ) ) )
995  if( ( longitude < ( -PI ) ) || ( longitude > TWO_PI ) )
997 
998  if( sourceIndex == targetIndex )
999  { /* Just copy */
1000  circularError90 = circularError90;
1001  linearError90 = linearError90;
1002  sphericalError90 = sphericalError90;
1003  }
1004  else
1005  {
1006  Datum* sourceDatum = datumList[sourceIndex];
1007  Datum* targetDatum = datumList[targetIndex];
1008 
1009  /* calculate input datum errors */
1010  switch( sourceDatum->datumType() )
1011  {
1012  case DatumType::wgs84Datum:
1013  case DatumType::wgs72Datum:
1015  {
1016  ce90_in = 0.0;
1017  le90_in = 0.0;
1018  se90_in = 0.0;
1019  break;
1020  }
1022  {
1023  ThreeParameterDatum* sourceThreeParameterDatum =
1024  ( ThreeParameterDatum* )sourceDatum;
1025 
1026  if( ( sourceThreeParameterDatum->sigmaX() < 0 )
1027  || ( sourceThreeParameterDatum->sigmaY() < 0 )
1028  || ( sourceThreeParameterDatum->sigmaZ() < 0 ) )
1029  {
1030  ce90_in = -1.0;
1031  le90_in = -1.0;
1032  se90_in = -1.0;
1033  }
1034  else
1035  {
1036  sx = sourceThreeParameterDatum->sigmaX() * sinlat * coslon;
1037  sy = sourceThreeParameterDatum->sigmaY() * sinlat * sinlon;
1038  sz = sourceThreeParameterDatum->sigmaZ() * coslat;
1039  sigma_delta_lat = sqrt( ( sx * sx ) + ( sy * sy ) + ( sz * sz ) );
1040 
1041  sx = sourceThreeParameterDatum->sigmaX() * sinlon;
1042  sy = sourceThreeParameterDatum->sigmaY() * coslon;
1043  sigma_delta_lon = sqrt( ( sx * sx ) + ( sy * sy ) );
1044 
1045  sx = sourceThreeParameterDatum->sigmaX() * coslat * coslon;
1046  sy = sourceThreeParameterDatum->sigmaY() * coslat * sinlon;
1047  sz = sourceThreeParameterDatum->sigmaZ() * sinlat;
1048  sigma_delta_height = sqrt( ( sx * sx ) + ( sy * sy ) + ( sz * sz ) );
1049 
1050  ce90_in = 2.146 * ( sigma_delta_lat + sigma_delta_lon ) / 2.0;
1051  le90_in = 1.6449 * sigma_delta_height;
1052  se90_in = 2.5003 *
1053  ( sourceThreeParameterDatum->sigmaX() +
1054  sourceThreeParameterDatum->sigmaY() +
1055  sourceThreeParameterDatum->sigmaZ() ) / 3.0;
1056  }
1057  break;
1058  }
1059  }
1060 
1061  /* calculate output datum errors */
1062  switch( targetDatum->datumType() )
1063  {
1064  case DatumType::wgs84Datum:
1065  case DatumType::wgs72Datum:
1067  {
1068  ce90_out = 0.0;
1069  le90_out = 0.0;
1070  se90_out = 0.0;
1071  break;
1072  }
1074  {
1075  ThreeParameterDatum* targetThreeParameterDatum =
1076  ( ThreeParameterDatum* )targetDatum;
1077  if ((targetThreeParameterDatum->sigmaX() < 0)
1078  ||(targetThreeParameterDatum->sigmaY() < 0)
1079  ||(targetThreeParameterDatum->sigmaZ() < 0))
1080  {
1081  ce90_out = -1.0;
1082  le90_out = -1.0;
1083  se90_out = -1.0;
1084  }
1085  else
1086  {
1087  sx = targetThreeParameterDatum->sigmaX() * sinlat * coslon;
1088  sy = targetThreeParameterDatum->sigmaY() * sinlat * sinlon;
1089  sz = targetThreeParameterDatum->sigmaZ() * coslat;
1090  sigma_delta_lat = sqrt((sx * sx) + (sy * sy) + (sz * sz));
1091 
1092  sx = targetThreeParameterDatum->sigmaX() * sinlon;
1093  sy = targetThreeParameterDatum->sigmaY() * coslon;
1094  sigma_delta_lon = sqrt( ( sx * sx ) + ( sy * sy ) );
1095 
1096  sx = targetThreeParameterDatum->sigmaX() * coslat * coslon;
1097  sy = targetThreeParameterDatum->sigmaY() * coslat * sinlon;
1098  sz = targetThreeParameterDatum->sigmaZ() * sinlat;
1099  sigma_delta_height = sqrt( ( sx * sx ) + ( sy * sy ) + ( sz * sz ) );
1100 
1101  ce90_out = 2.146 * ( sigma_delta_lat + sigma_delta_lon ) / 2.0;
1102  le90_out = 1.6449 * sigma_delta_height;
1103  se90_out = 2.5003 *
1104  ( targetThreeParameterDatum->sigmaX() +
1105  targetThreeParameterDatum->sigmaY() +
1106  targetThreeParameterDatum->sigmaZ() ) / 3.0;
1107  }
1108  break;
1109  }
1110  }
1111 
1112  /* combine errors */
1113  if( ( circularError90 < 0.0 ) || ( ce90_in < 0.0 ) || ( ce90_out < 0.0 ) )
1114  {
1115  circularError90 = -1.0;
1116  linearError90 = -1.0;
1117  sphericalError90 = -1.0;
1118  }
1119  else
1120  {
1121  circularError90 = sqrt( ( circularError90 * circularError90 ) +
1122  ( ce90_in * ce90_in ) + ( ce90_out * ce90_out ) );
1123  if( circularError90 < 1.0 )
1124  {
1125  circularError90 = 1.0;
1126  }
1127 
1128  if( ( linearError90 < 0.0 ) || ( le90_in < 0.0 ) || ( le90_out < 0.0 ) )
1129  {
1130  linearError90 = -1.0;
1131  sphericalError90 = -1.0;
1132  }
1133  else
1134  {
1135  linearError90 = sqrt( ( linearError90 * linearError90 ) +
1136  ( le90_in * le90_in ) + ( le90_out * le90_out ) );
1137  if( linearError90 < 1.0 )
1138  {
1139  linearError90 = 1.0;
1140  }
1141 
1142  if( ( sphericalError90 < 0.0 )
1143  || ( se90_in < 0.0 )
1144  || ( se90_out < 0.0 ) )
1145  sphericalError90 = -1.0;
1146  else
1147  {
1148  sphericalError90 = sqrt(
1149  ( sphericalError90 * sphericalError90 ) +
1150  ( se90_in * se90_in ) + ( se90_out * se90_out ) );
1151  if( sphericalError90 < 1.0 )
1152  {
1153  sphericalError90 = 1.0;
1154  }
1155  }
1156  }
1157  }
1158  }
1159 
1160  // Correct for limited precision of input/output coordinate.
1161 
1162  // sigma for uniform distribution due to rounding.
1163  double sigma = Precision::toMeters( precision ) / sqrt( 12.0 );
1164 
1165  // For linear error
1166  if( linearError90 > 0.0 )
1167  {
1168  double lePrec = 1.6449 * sigma;
1169  linearError90 = sqrt(
1170  linearError90 * linearError90 + lePrec * lePrec);
1171  }
1172 
1173  // For circular error
1174  if( circularError90 > 0.0 )
1175  {
1176  double cePrec = 2.146 * sigma;
1177  circularError90 = sqrt(
1178  circularError90 * circularError90 + cePrec * cePrec);
1179  }
1180 
1181  // For spherical error
1182  if( sphericalError90 > 0.0 )
1183  {
1184  // Assume sigma in all directions
1185  double sePrec = 2.5003 * sigma;
1186  sphericalError90 = sqrt(
1187  sphericalError90 * sphericalError90 + sePrec * sePrec );
1188  }
1189 
1190  return new Accuracy( circularError90, linearError90, sphericalError90 );
1191 }
1192 
1193 
1195  const long index, long *result )
1196 {
1197 /*
1198  * The function datumUserDefined checks whether or not the specified datum is
1199  * user defined. It returns 1 if the datum is user defined, and returns
1200  * 0 otherwise. If index is valid DATUM_NO_ERROR is returned, otherwise
1201  * DATUM_INVALID_INDEX_ERROR is returned.
1202  *
1203  * index : Index of a given datum in the datum table (input)
1204  * result : Indicates whether specified datum is user defined (1)
1205  * or not (0) (output)
1206  */
1207 
1208  *result = false;
1209 
1210  if( index < 0 || index >= datumList.size() )
1212  else
1213  {
1214  Datum* datum = datumList[index];
1215 
1216  if( datum->datumType() == DatumType::threeParamDatum )
1217  {
1218  ThreeParameterDatum* threeParameterDatum = ( ThreeParameterDatum* )datum;
1219 
1220  if( threeParameterDatum->userDefined() )
1221  *result = true;
1222  }
1223  else if( datum->datumType() == DatumType::sevenParamDatum )
1224  {
1225  SevenParameterDatum* sevenParamDatum = ( SevenParameterDatum* )datum;
1226 
1227  if( sevenParamDatum->userDefined() )
1228  *result = true;
1229  }
1230  else
1232  }
1233 }
1234 
1235 
1236 bool DatumLibraryImplementation::datumUsesEllipsoid( const char *ellipsoidCode )
1237 {
1238 /*
1239  * The function datumUsesEllipsoid returns 1 if the ellipsoid is in use by a
1240  * user defined datum. Otherwise, 0 is returned.
1241  *
1242  * ellipsoidCode : The ellipsoid code being searched for. (input)
1243  */
1244 
1245  char temp_code[DATUM_CODE_LENGTH];
1246  long length;
1247  long pos = 0;
1248  long i = 0;
1249  bool ellipsoid_in_use = false;
1250 
1251  length = strlen( ellipsoidCode );
1252  if( length <= ( ELLIPSOID_CODE_LENGTH-1 ) )
1253  {
1254  strcpy( temp_code, ellipsoidCode );
1255 
1256  /* Convert to upper case */
1257  for( i=0;i<length;i++ )
1258  temp_code[i] = ( char )toupper( temp_code[i] );
1259 
1260  /* Strip blank spaces */
1261  while( pos < length )
1262  {
1263  if( isspace( temp_code[pos] ) )
1264  {
1265  for( i=pos; i<length; i++ )
1266  temp_code[i] = temp_code[i+1];
1267  length -= 1;
1268  }
1269  else
1270  pos += 1;
1271  }
1272 
1273  /* Search for code */
1274  i = 0;
1275  int numDatums = datumList.size();
1276  while( ( i < numDatums ) && ( !ellipsoid_in_use ) )
1277  {
1278  if( strcmp( temp_code, datumList[i]->ellipsoidCode() ) == 0 )
1279  ellipsoid_in_use = true;
1280  i++;
1281  }
1282  }
1283 
1284  return ellipsoid_in_use;
1285 }
1286 
1287 
1289  const long index,
1290  double *westLongitude,
1291  double *eastLongitude,
1292  double *southLatitude,
1293  double *northLatitude )
1294 {
1295 /*
1296  * The function datumValidRectangle returns the edges of the validity
1297  * rectangle for the datum referenced by index.
1298  *
1299  * index : The index of a given datum in the datum table (input)
1300  * westLongitude : Western edge of validity rectangle in radians (output)
1301  * eastLongitude : Eastern edge of validity rectangle in radians (output)
1302  * southLatitude : Southern edge of validity rectangle in radians (output)
1303  * northLatitude : Northern edge of validity rectangle in radians (output)
1304  *
1305  */
1306 
1307  if( index < 0 && index >= datumList.size() )
1309  else
1310  {
1311  *westLongitude = datumList[index]->westLongitude();
1312  *eastLongitude = datumList[index]->eastLongitude();
1313  *southLatitude = datumList[index]->southLatitude();
1314  *northLatitude = datumList[index]->northLatitude();
1315  }
1316 }
1317 
1318 
1320  const long sourceIndex,
1321  const double sourceX,
1322  const double sourceY,
1323  const double sourceZ,
1324  const long targetIndex )
1325 {
1326 /*
1327  * The function geocentricDatumShift shifts a geocentric coordinate (X, Y, Z in meters) relative
1328  * to the source datum to geocentric coordinate (X, Y, Z in meters) relative
1329  * to the destination datum.
1330  *
1331  * sourceIndex : Index of source datum (input)
1332  * sourceX : X coordinate relative to source datum (input)
1333  * sourceY : Y coordinate relative to source datum (input)
1334  * sourceZ : Z coordinate relative to source datum (input)
1335  * targetIndex : Index of destination datum (input)
1336  * targetX : X coordinate relative to destination datum (output)
1337  * targetY : Y coordinate relative to destination datum (output)
1338  * targetZ : Z coordinate relative to destination datum (output)
1339  *
1340  */
1341 
1342  int numDatums = datumList.size();
1343 
1344  if( ( sourceIndex < 0 ) || ( sourceIndex >= numDatums ) )
1346  if( ( targetIndex < 0 ) || ( targetIndex >= numDatums ) )
1348 
1349  if( sourceIndex == targetIndex )
1350  {
1351  return new CartesianCoordinates(
1352  CoordinateType::geocentric, sourceX, sourceY, sourceZ );
1353  }
1354  else
1355  {
1356  CartesianCoordinates* wgs84CartesianCoordinates = geocentricShiftToWGS84(
1357  sourceIndex, sourceX, sourceY, sourceZ );
1358 
1359  CartesianCoordinates* targetCartesianCoordinates = geocentricShiftFromWGS84(
1360  wgs84CartesianCoordinates->x(), wgs84CartesianCoordinates->y(),
1361  wgs84CartesianCoordinates->z(), targetIndex );
1362 
1363  delete wgs84CartesianCoordinates;
1364 
1365  return targetCartesianCoordinates;
1366  }
1367 }
1368 
1369 
1371  const double WGS84X,
1372  const double WGS84Y,
1373  const double WGS84Z,
1374  const long targetIndex )
1375 {
1376 /*
1377  * The function geocentricShiftFromWGS84 shifts a geocentric coordinate (X, Y, Z in meters) relative
1378  * to WGS84 to a geocentric coordinate (X, Y, Z in meters) relative to the
1379  * local datum referenced by index.
1380  *
1381  * WGS84X : X coordinate relative to WGS84 (input)
1382  * WGS84Y : Y coordinate relative to WGS84 (input)
1383  * WGS84Z : Z coordinate relative to WGS84 (input)
1384  * targetIndex : Index of destination datum (input)
1385  * targetX : X coordinate relative to the destination datum (output)
1386  * targetY : Y coordinate relative to the destination datum (output)
1387  * targetZ : Z coordinate relative to the destination datum (output)
1388  */
1389 
1390  int numDatums = datumList.size();
1391 
1392  if( ( targetIndex < 0 ) || ( targetIndex >= numDatums ) )
1394 
1395  Datum* localDatum = datumList[targetIndex];
1396  switch( localDatum->datumType() )
1397  {
1398  case DatumType::wgs72Datum:
1399  {
1400  CartesianCoordinates* wgs72CartesianCoordinates =
1401  geocentricShiftWGS84ToWGS72( WGS84X, WGS84Y, WGS84Z );
1402 
1403  return wgs72CartesianCoordinates;
1404  }
1405  case DatumType::wgs84Datum:
1406  {
1407  return new CartesianCoordinates(
1408  CoordinateType::geocentric, WGS84X, WGS84Y, WGS84Z );
1409  }
1411  {
1412  SevenParameterDatum* sevenParameterDatum =
1413  ( SevenParameterDatum* )localDatum;
1414 
1415  double targetX = WGS84X - sevenParameterDatum->deltaX() - sevenParameterDatum->rotationZ() * WGS84Y
1416  + sevenParameterDatum->rotationY() * WGS84Z - sevenParameterDatum->scaleFactor() * WGS84X;
1417 
1418  double targetY = WGS84Y - sevenParameterDatum->deltaY() + sevenParameterDatum->rotationZ() * WGS84X
1419  - sevenParameterDatum->rotationX() * WGS84Z - sevenParameterDatum->scaleFactor() * WGS84Y;
1420 
1421  double targetZ = WGS84Z - sevenParameterDatum->deltaZ() - sevenParameterDatum->rotationY() * WGS84X
1422  + sevenParameterDatum->rotationX() * WGS84Y - sevenParameterDatum->scaleFactor() * WGS84Z;
1423 
1424  return new CartesianCoordinates( CoordinateType::geocentric, targetX, targetY, targetZ );
1425  }
1427  {
1428  ThreeParameterDatum* threeParameterDatum = ( ThreeParameterDatum* )localDatum;
1429 
1430  double targetX = WGS84X - threeParameterDatum->deltaX();
1431  double targetY = WGS84Y - threeParameterDatum->deltaY();
1432  double targetZ = WGS84Z - threeParameterDatum->deltaZ();
1433 
1434  return new CartesianCoordinates( CoordinateType::geocentric, targetX, targetY, targetZ );
1435  }
1436  default:
1438  }
1439 }
1440 
1441 
1443  const long sourceIndex,
1444  const double sourceX,
1445  const double sourceY,
1446  const double sourceZ )
1447 {
1448 /*
1449  * The function geocentricShiftToWGS84 shifts a geocentric coordinate (X, Y, Z in meters) relative
1450  * to the datum referenced by index to a geocentric coordinate (X, Y, Z in
1451  * meters) relative to WGS84.
1452  *
1453  * sourceIndex : Index of source datum (input)
1454  * sourceX : X coordinate relative to the source datum (input)
1455  * sourceY : Y coordinate relative to the source datum (input)
1456  * sourceZ : Z coordinate relative to the source datum (input)
1457  * WGS84X : X coordinate relative to WGS84 (output)
1458  * WGS84Y : Y coordinate relative to WGS84 (output)
1459  * WGS84Z : Z coordinate relative to WGS84 (output)
1460  */
1461 
1462  int numDatums = datumList.size();
1463 
1464  if( ( sourceIndex < 0 ) || (sourceIndex > numDatums ) )
1466 
1467  Datum* localDatum = datumList[sourceIndex];
1468  switch( localDatum->datumType() )
1469  {
1470  case DatumType::wgs72Datum:
1471  {
1472  CartesianCoordinates* wgs84CartesianCoordinates =
1473  geocentricShiftWGS72ToWGS84( sourceX, sourceY, sourceZ );
1474 
1475  return wgs84CartesianCoordinates;
1476  }
1477  case DatumType::wgs84Datum:
1478  {
1479  return new CartesianCoordinates( CoordinateType::geocentric, sourceX, sourceY, sourceZ );
1480  }
1482  {
1483  SevenParameterDatum* sevenParameterDatum = ( SevenParameterDatum* )localDatum;
1484 
1485  double wgs84X = sourceX + sevenParameterDatum->deltaX() + sevenParameterDatum->rotationZ() * sourceY
1486  - sevenParameterDatum->rotationY() * sourceZ + sevenParameterDatum->scaleFactor() * sourceX;
1487 
1488  double wgs84Y = sourceY + sevenParameterDatum->deltaY() - sevenParameterDatum->rotationZ() * sourceX
1489  + sevenParameterDatum->rotationX() * sourceZ + sevenParameterDatum->scaleFactor() * sourceY;
1490 
1491  double wgs84Z = sourceZ + sevenParameterDatum->deltaZ() + sevenParameterDatum->rotationY() * sourceX
1492  - sevenParameterDatum->rotationX() * sourceY + sevenParameterDatum->scaleFactor() * sourceZ;
1493 
1494  return new CartesianCoordinates( CoordinateType::geocentric, wgs84X, wgs84Y, wgs84Z );
1495  }
1497  {
1498  ThreeParameterDatum* threeParameterDatum = ( ThreeParameterDatum* )localDatum;
1499 
1500  double wgs84X = sourceX + threeParameterDatum->deltaX();
1501  double wgs84Y = sourceY + threeParameterDatum->deltaY();
1502  double wgs84Z = sourceZ + threeParameterDatum->deltaZ();
1503 
1504  return new CartesianCoordinates( CoordinateType::geocentric, wgs84X, wgs84Y, wgs84Z );
1505  }
1506  default:
1508  }
1509 }
1510 
1511 
1513  const long sourceIndex,
1514  const GeodeticCoordinates* sourceCoordinates,
1515  const long targetIndex )
1516 {
1517 /*
1518  * The function geodeticDatumShift shifts geodetic coordinates (latitude, longitude in radians
1519  * and height in meters) relative to the source datum to geodetic coordinates
1520  * (latitude, longitude in radians and height in meters) relative to the
1521  * destination datum.
1522  *
1523  * sourceIndex : Index of source datum (input)
1524  * sourceLongitude : Longitude in radians relative to source datum (input)
1525  * sourceLatitude : Latitude in radians relative to source datum (input)
1526  * sourceHeight : Height in meters relative to source datum (input)
1527  * targetIndex : Index of destination datum (input)
1528  * targetLongitude : Longitude in radians relative to destination datum(output)
1529  * targetLatitude : Latitude in radians relative to destination datum (output)
1530  * targetHeight : Height in meters relative to destination datum (output)
1531  */
1532 
1533  long E_Index;
1534  double a;
1535  double f;
1536 
1537  double sourceLongitude = sourceCoordinates->longitude();
1538  double sourceLatitude = sourceCoordinates->latitude();
1539  double sourceHeight = sourceCoordinates->height();
1540 
1541  int numDatums = datumList.size();
1542 
1543  if( sourceIndex < 0 || sourceIndex >= numDatums )
1545  if( targetIndex < 0 || targetIndex >= numDatums )
1547 
1548  if(( sourceLatitude < ( -90 * PI_OVER_180 ) ) ||
1549  ( sourceLatitude > ( 90 * PI_OVER_180 ) ) )
1551  if( ( sourceLongitude < ( -PI )) || ( sourceLongitude > TWO_PI ) )
1553 
1554  Datum* sourceDatum = datumList[sourceIndex];
1555  Datum* targetDatum = datumList[targetIndex];
1556 
1557  if ( sourceIndex == targetIndex )
1558  { /* Just copy */
1559  return new GeodeticCoordinates(
1560  CoordinateType::geodetic, sourceLongitude, sourceLatitude, sourceHeight);
1561  }
1562  else
1563  {
1564  if( _ellipsoidLibraryImplementation )
1565  {
1566  if( sourceDatum->datumType() == DatumType::sevenParamDatum )
1567  {
1568  _ellipsoidLibraryImplementation->ellipsoidIndex(
1569  sourceDatum->ellipsoidCode(), &E_Index );
1570  _ellipsoidLibraryImplementation->ellipsoidParameters( E_Index, &a, &f );
1571 
1572  Geocentric geocentricFromGeodetic( a, f );
1573 
1574  CartesianCoordinates* sourceCartesianCoordinates =
1575  geocentricFromGeodetic.convertFromGeodetic( sourceCoordinates );
1576 
1577  if( targetDatum->datumType() == DatumType::sevenParamDatum )
1578  { /* Use 3-step method for both stages */
1579  CartesianCoordinates* targetCartesianCoordinates = geocentricDatumShift(
1580  sourceIndex,
1581  sourceCartesianCoordinates->x(),
1582  sourceCartesianCoordinates->y(),
1583  sourceCartesianCoordinates->z(), targetIndex );
1584 
1585  _ellipsoidLibraryImplementation->ellipsoidIndex(
1586  targetDatum->ellipsoidCode(), &E_Index );
1587  _ellipsoidLibraryImplementation->ellipsoidParameters( E_Index, &a, &f );
1588 
1589  Geocentric geocentricToGeodetic( a, f );
1590  GeodeticCoordinates* targetGeodeticCoordinates =
1591  geocentricToGeodetic.convertToGeodetic( targetCartesianCoordinates );
1592 
1593  delete targetCartesianCoordinates;
1594  delete sourceCartesianCoordinates;
1595 
1596  return targetGeodeticCoordinates;
1597  }
1598  else
1599  { /* Use 3-step method for 1st stage, Molodensky if possible for 2nd stage */
1600  CartesianCoordinates* wgs84CartesianCoordinates = geocentricShiftToWGS84(
1601  sourceIndex, sourceCartesianCoordinates->x(),
1602  sourceCartesianCoordinates->y(), sourceCartesianCoordinates->z() );
1603 
1604  long wgs84EllipsoidIndex;
1605  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
1606  _ellipsoidLibraryImplementation->ellipsoidParameters(
1607  wgs84EllipsoidIndex, &a, &f );
1608 
1609  Geocentric geocentricToGeodetic( a, f );
1610  GeodeticCoordinates* wgs84GeodeticCoordinates =
1611  geocentricToGeodetic.convertToGeodetic( wgs84CartesianCoordinates );
1612 
1613  GeodeticCoordinates* targetGeodeticCoordinates =
1614  geodeticShiftFromWGS84( wgs84GeodeticCoordinates, targetIndex );
1615 
1616  delete wgs84GeodeticCoordinates;
1617  delete wgs84CartesianCoordinates;
1618 
1619  return targetGeodeticCoordinates;
1620  }
1621  }
1622  else if( targetDatum->datumType() == DatumType::sevenParamDatum )
1623  { /* Use Molodensky if possible for 1st stage, 3-step method for 2nd stage */
1624  GeodeticCoordinates* wgs84GeodeticCoordinates = geodeticShiftToWGS84(
1625  sourceIndex, sourceCoordinates );
1626 
1627  long wgs84EllipsoidIndex;
1628  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
1629  _ellipsoidLibraryImplementation->ellipsoidParameters(
1630  wgs84EllipsoidIndex, &a, &f );
1631 
1632  Geocentric geocentricFromGeodetic( a, f );
1633  CartesianCoordinates* wgs84CartesianCoordinates =
1634  geocentricFromGeodetic.convertFromGeodetic( wgs84GeodeticCoordinates );
1635 
1636  CartesianCoordinates* targetCartesianCoordinates =
1638  wgs84CartesianCoordinates->x(),
1639  wgs84CartesianCoordinates->y(),
1640  wgs84CartesianCoordinates->z(), targetIndex );
1641 
1642  _ellipsoidLibraryImplementation->ellipsoidIndex(
1643  targetDatum->ellipsoidCode(), &E_Index );
1644  _ellipsoidLibraryImplementation->ellipsoidParameters( E_Index, &a, &f );
1645 
1646  Geocentric geocentricToGeodetic( a, f );
1647  GeodeticCoordinates* targetGeodeticCoordinates =
1648  geocentricToGeodetic.convertToGeodetic( targetCartesianCoordinates );
1649 
1650  delete targetCartesianCoordinates;
1651  delete wgs84CartesianCoordinates;
1652  delete wgs84GeodeticCoordinates;
1653 
1654  return targetGeodeticCoordinates;
1655  }
1656  else
1657  { /* Use Molodensky if possible for both stages */
1658  GeodeticCoordinates* wgs84GeodeticCoordinates = geodeticShiftToWGS84(
1659  sourceIndex, sourceCoordinates );
1660 
1661  GeodeticCoordinates* targetGeodeticCoordinates = geodeticShiftFromWGS84(
1662  wgs84GeodeticCoordinates, targetIndex );
1663 
1664  delete wgs84GeodeticCoordinates;
1665 
1666  return targetGeodeticCoordinates;
1667  }
1668  }
1669  else
1671  }
1672 }
1673 
1674 
1676  const GeodeticCoordinates* sourceCoordinates, const long targetIndex )
1677 {
1678 /*
1679  * The function geodeticShiftFromWGS84 shifts geodetic coordinates relative to WGS84
1680  * to geodetic coordinates relative to a given local datum.
1681  *
1682  * WGS84Longitude : Longitude in radians relative to WGS84 (input)
1683  * WGS84Latitude : Latitude in radians relative to WGS84 (input)
1684  * WGS84Height : Height in meters relative to WGS84 (input)
1685  * targetIndex : Index of destination datum (input)
1686  * targetLongitude : Longitude (rad) relative to destination datum (output)
1687  * targetLatitude : Latitude (rad) relative to destination datum (output)
1688  * targetHeight : Height in meters relative to destination datum (output)
1689  *
1690  */
1691 
1692  double WGS84_a; /* Semi-major axis of WGS84 ellipsoid in meters */
1693  double WGS84_f; /* Flattening of WGS84 ellisoid */
1694  double a; /* Semi-major axis of ellipsoid in meters */
1695  double da; /* Difference in semi-major axes */
1696  double f; /* Flattening of ellipsoid */
1697  double df; /* Difference in flattening */
1698  double dx;
1699  double dy;
1700  double dz;
1701  long E_Index;
1702 
1703  double WGS84Longitude = sourceCoordinates->longitude();
1704  double WGS84Latitude = sourceCoordinates->latitude();
1705  double WGS84Height = sourceCoordinates->height();
1706 
1707  if( ( targetIndex < 0) || (targetIndex >= datumList.size() ) )
1709  if(( WGS84Latitude < ( -90 * PI_OVER_180 ) ) ||
1710  ( WGS84Latitude > ( 90 * PI_OVER_180 ) ) )
1712  if( ( WGS84Longitude < ( -PI ) ) || ( WGS84Longitude > TWO_PI ) )
1714 
1715  Datum* localDatum = datumList[targetIndex];
1716  switch( localDatum->datumType() )
1717  {
1718  case DatumType::wgs72Datum:
1719  {
1720  GeodeticCoordinates* targetGeodeticCoordinates = geodeticShiftWGS84ToWGS72( WGS84Longitude, WGS84Latitude, WGS84Height );
1721  return targetGeodeticCoordinates;
1722  }
1723  case DatumType::wgs84Datum:
1724  {
1725  return new GeodeticCoordinates( CoordinateType::geodetic, WGS84Longitude, WGS84Latitude, WGS84Height );
1726  }
1729  {
1730  if( _ellipsoidLibraryImplementation )
1731  {
1732  _ellipsoidLibraryImplementation->ellipsoidIndex( localDatum->ellipsoidCode(), &E_Index );
1733  _ellipsoidLibraryImplementation->ellipsoidParameters( E_Index, &a, &f );
1734 
1735  long wgs84EllipsoidIndex;
1736  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
1737  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &WGS84_a, &WGS84_f );
1738 
1739  if( ( localDatum->datumType() == DatumType::sevenParamDatum ) ||
1740  ( WGS84Latitude < ( -MOLODENSKY_MAX ) ) ||
1741  ( WGS84Latitude > MOLODENSKY_MAX ) )
1742  { /* Use 3-step method */
1743  Geocentric geocentricFromGeodetic( WGS84_a, WGS84_f );
1744  CartesianCoordinates* wgs84CartesianCoordinates = geocentricFromGeodetic.convertFromGeodetic( sourceCoordinates );
1745 
1746  CartesianCoordinates* localCartesianCoordinates = geocentricShiftFromWGS84( wgs84CartesianCoordinates->x(), wgs84CartesianCoordinates->y(),
1747  wgs84CartesianCoordinates->z(), targetIndex );
1748 
1749  Geocentric geocentricToGeodetic( a, f );
1750  GeodeticCoordinates* targetGeodeticCoordinates = geocentricToGeodetic.convertToGeodetic( localCartesianCoordinates );
1751 
1752  delete localCartesianCoordinates;
1753  delete wgs84CartesianCoordinates;
1754 
1755  return targetGeodeticCoordinates;
1756  }
1757  else
1758  { /* Use Molodensky's method */
1759  da = a - WGS84_a;
1760  df = f - WGS84_f;
1761  dx = -( localDatum->deltaX() );
1762  dy = -( localDatum->deltaY() );
1763  dz = -( localDatum->deltaZ() );
1764 
1765  GeodeticCoordinates* targetGeodeticCoordinates = molodenskyShift( WGS84_a, da, WGS84_f, df, dx, dy, dz,
1766  WGS84Longitude, WGS84Latitude, WGS84Height );
1767 
1768  return targetGeodeticCoordinates;
1769  }
1770  }
1771  }
1772  default:
1774  }
1775 }
1776 
1777 
1779 {
1780 /*
1781  * The function geodeticShiftToWGS84 shifts geodetic coordinates relative to a given source datum
1782  * to geodetic coordinates relative to WGS84.
1783  *
1784  * sourceIndex : Index of source datum (input)
1785  * sourceLongitude : Longitude in radians relative to source datum (input)
1786  * sourceLatitude : Latitude in radians relative to source datum (input)
1787  * sourceHeight : Height in meters relative to source datum (input)
1788  * WGS84Longitude : Longitude in radians relative to WGS84 (output)
1789  * WGS84Latitude : Latitude in radians relative to WGS84 (output)
1790  * WGS84Height : Height in meters relative to WGS84 (output)
1791  *
1792  */
1793 
1794  double WGS84_a; /* Semi-major axis of WGS84 ellipsoid in meters */
1795  double WGS84_f; /* Flattening of WGS84 ellisoid */
1796  double a; /* Semi-major axis of ellipsoid in meters */
1797  double da; /* Difference in semi-major axes */
1798  double f; /* Flattening of ellipsoid */
1799  double df; /* Difference in flattening */
1800  double dx;
1801  double dy;
1802  double dz;
1803  long E_Index;
1804 
1805  double sourceLongitude = sourceCoordinates->longitude();
1806  double sourceLatitude = sourceCoordinates->latitude();
1807  double sourceHeight = sourceCoordinates->height();
1808 
1809  if( ( sourceIndex < 0 ) || ( sourceIndex >= datumList.size() ) )
1811  if(( sourceLatitude < ( -90 * PI_OVER_180 ) ) ||
1812  ( sourceLatitude > ( 90 * PI_OVER_180 ) ) )
1814  if( ( sourceLongitude < ( -PI ) ) || ( sourceLongitude > TWO_PI ) )
1816 
1817  Datum* localDatum = datumList[sourceIndex];
1818  switch( localDatum->datumType() )
1819  {
1820  case DatumType::wgs72Datum:
1821  { /* Special case for WGS72 */
1822  return geodeticShiftWGS72ToWGS84( sourceLongitude, sourceLatitude, sourceHeight );
1823  }
1824  case DatumType::wgs84Datum:
1825  { /* Just copy */
1826  return new GeodeticCoordinates(CoordinateType::geodetic, sourceLongitude, sourceLatitude, sourceHeight);
1827  }
1830  {
1831  if( _ellipsoidLibraryImplementation )
1832  {
1833  _ellipsoidLibraryImplementation->ellipsoidIndex( localDatum->ellipsoidCode(), &E_Index );
1834  _ellipsoidLibraryImplementation->ellipsoidParameters( E_Index, &a, &f );
1835 
1836  if( ( localDatum->datumType() == DatumType::sevenParamDatum ) ||
1837  ( sourceLatitude < (-MOLODENSKY_MAX ) ) ||
1838  ( sourceLatitude > MOLODENSKY_MAX ) )
1839  { /* Use 3-step method */
1840  Geocentric geocentricFromGeodetic( a, f );
1841  CartesianCoordinates* localCartesianCoordinates =
1842  geocentricFromGeodetic.convertFromGeodetic( sourceCoordinates );
1843 
1844  CartesianCoordinates* wgs84CartesianCoordinates = geocentricShiftToWGS84( sourceIndex, localCartesianCoordinates->x(), localCartesianCoordinates->y(), localCartesianCoordinates->z() );
1845 
1846  long wgs84EllipsoidIndex;
1847  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
1848  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &WGS84_a, &WGS84_f );
1849 
1850  Geocentric geocentricToGeodetic( WGS84_a, WGS84_f );
1851  GeodeticCoordinates* wgs84GeodeticCoordinates = geocentricToGeodetic.convertToGeodetic( wgs84CartesianCoordinates );
1852 
1853  delete wgs84CartesianCoordinates;
1854  delete localCartesianCoordinates;
1855 
1856  return wgs84GeodeticCoordinates;
1857  }
1858  else
1859  { /* Use Molodensky's method */
1860  long wgs84EllipsoidIndex;
1861  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
1862  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &WGS84_a, &WGS84_f );
1863 
1864  da = WGS84_a - a;
1865  df = WGS84_f - f;
1866  dx = localDatum->deltaX();
1867  dy = localDatum->deltaY();
1868  dz = localDatum->deltaZ();
1869 
1870  GeodeticCoordinates* wgs84GeodeticCoordinates = molodenskyShift( a, da, f, df, dx, dy, dz, sourceLongitude, sourceLatitude, sourceHeight );
1871 
1872  return wgs84GeodeticCoordinates;
1873  }
1874  }
1875  }
1876  default:
1878  }
1879 }
1880 
1881 
1883  const long index,
1884  DatumType::Enum *datumType )
1885 {
1886 /*
1887  * The function retrieveDatumType returns the type of the datum referenced by
1888  * index.
1889  *
1890  * index : The index of a given datum in the datum table. (input)
1891  * datumType : The type of datum referenced by index. (output)
1892  *
1893  */
1894 
1895  if( index < 0 || index >= datumList.size() )
1897  else
1898  *datumType = datumList[index]->datumType();
1899 }
1900 
1901 
1903  const long index,
1904  double longitude,
1905  double latitude,
1906  long *result )
1907 {
1908 /*
1909  * The function validDatum checks whether or not the specified location is within the
1910  * validity rectangle for the specified datum. It returns zero if the specified
1911  * location is NOT within the validity rectangle, and returns 1 otherwise.
1912  *
1913  * index : The index of a given datum in the datum table (input)
1914  * latitude : Latitude of the location to be checked in radians (input)
1915  * longitude : Longitude of the location to be checked in radians (input)
1916  * result : Indicates whether location is inside (1) or outside (0)
1917  * of the validity rectangle of the specified datum (output)
1918  */
1919  *result = 0;
1920 
1921  if( ( index < 0 ) || ( index >= datumList.size() ) )
1923  if( ( latitude < MIN_LAT ) || ( latitude > MAX_LAT ) )
1925  if( ( longitude < MIN_LON ) || ( longitude > MAX_LON ) )
1927 
1928  Datum* datum = datumList[index];
1929 
1930  double west_longitude = datum->westLongitude();
1931  double east_longitude = datum->eastLongitude();
1932 
1933  /* The west and east longitudes may be in the range 0 to 360
1934  or -180 to 180, longitude is always in the -180 to 180 range
1935  Figure out which range west and east longitudes are in.
1936  If west and east are in the -180 to 180 range and west > east, put them in the 0 to 360 range and adjust longitude if
1937  necessary.
1938  If west and east are in the 0 to 360 range and west > east, put them in the -180 to 180 range. If west < east, adjust
1939  longitude to the 0 to 360 range
1940  */
1941  if( ( west_longitude < 0 ) || ( east_longitude < 0 ) )
1942  {
1943  if( west_longitude > east_longitude )
1944  {
1945  if( west_longitude < 0 )
1946  west_longitude += TWO_PI;
1947  if( east_longitude < 0 )
1948  east_longitude += TWO_PI;
1949  if( longitude < 0 )
1950  longitude += TWO_PI;
1951  }
1952  }
1953  else if( ( west_longitude > PI ) || ( east_longitude > PI ) )
1954  {
1955  if( west_longitude > east_longitude )
1956  {
1957  if( west_longitude > PI )
1958  west_longitude -= TWO_PI;
1959  if( east_longitude > PI )
1960  east_longitude -= TWO_PI;
1961  }
1962  else
1963  {
1964  if( longitude < 0 )
1965  longitude += TWO_PI;
1966  }
1967  }
1968 
1969  if( ( datum->southLatitude() <= latitude ) &&
1970  ( latitude <= datum->northLatitude() ) &&
1971  ( west_longitude <= longitude ) &&
1972  ( longitude <= east_longitude ) )
1973  {
1974  *result = 1;
1975  }
1976  else
1977  {
1978  *result = 0;
1979  }
1980 }
1981 
1982 
1984  EllipsoidLibraryImplementation* __ellipsoidLibraryImplementation )
1985 {
1986 /*
1987  * The function setEllipsoidLibraryImplementation sets the ellipsoid library information
1988  * which is needed to create datums and calculate datum shifts.
1989  *
1990  * __ellipsoidLibraryImplementation : Ellipsoid library implementation(input)
1991  *
1992  */
1993 
1994  _ellipsoidLibraryImplementation = __ellipsoidLibraryImplementation;
1995 }
1996 
1997 
1998 /************************************************************************/
1999 /* PRIVATE FUNCTIONS
2000  *
2001  */
2002 
2003 void DatumLibraryImplementation::loadDatums()
2004 {
2005 /*
2006  * The function loadDatums creates the datum table from two external
2007  * files. If an error occurs, the initialization stops and an error code is
2008  * returned. This function must be called before any of the other functions
2009  * in this component.
2010  */
2011 
2012  long index = 0, i = 0;
2013  char *PathName = NULL;
2014  char* FileName7 = 0;
2015  FILE *fp_7param = NULL;
2016  FILE *fp_3param = NULL;
2017  char* FileName3 = 0;
2018  const int file_name_length = 23;
2019 
2020  CCSThreadLock lock(&mutex);
2021 
2022  /* Check the environment for a user provided path, else current directory; */
2023  /* Build a File Name, including specified or default path: */
2024 
2025 #ifdef NDK_BUILD
2026  PathName = "/data/data/com.baesystems.msp.geotrans/lib/";
2027  FileName7 = new char[ 80 ];
2028  strcpy( FileName7, PathName );
2029  strcat( FileName7, "lib7paramdat.so" );
2030 #else
2031  PathName = getenv( "MSPCCS_DATA" );
2032  if (PathName != NULL)
2033  {
2034  FileName7 = new char[ strlen( PathName ) + 13 ];
2035  strcpy( FileName7, PathName );
2036  strcat( FileName7, "/" );
2037  }
2038  else
2039  {
2040  FileName7 = new char[ file_name_length ];
2041  strcpy( FileName7, "../../data/" );
2042  }
2043  strcat( FileName7, "7_param.dat" );
2044 #endif
2045 
2046  /* Open the File READONLY, or Return Error Condition: */
2047 
2048  if (( fp_7param = fopen( FileName7, "r" ) ) == NULL)
2049  {
2050  delete [] FileName7;
2051  FileName7 = 0;
2052 
2053  char message[256] = "";
2054  if (NULL == PathName)
2055  {
2056  strcpy( message, "Environment variable undefined: MSPCCS_DATA." );
2057  }
2058  else
2059  {
2060  strcpy( message, ErrorMessages::datumFileOpenError );
2061  strcat( message, ": 7_param.dat\n" );
2062  }
2063  throw CoordinateConversionException( message );
2064  }
2065 
2066  /* Open the File READONLY, or Return Error Condition: */
2067 
2068  /* WGS84 datum entry */
2069  datumList.push_back( new Datum(
2070  index, "WGE", "WE", "World Geodetic System 1984", DatumType::wgs84Datum,
2071  0.0, 0.0, 0.0, -PI, +PI, -PI / 2.0, +PI / 2.0, false ) );
2072  index ++;
2073 
2074 
2075  /* WGS72 datum entry */
2076  datumList.push_back( new Datum(
2077  index, "WGC", "WD", "World Geodetic System 1972", DatumType::wgs72Datum,
2078  0.0, 0.0, 0.0, -PI, +PI, -PI / 2.0, +PI / 2.0, false ) );
2079 
2080  index ++;
2081 
2082  datum7ParamCount = 0;
2083  /* build 7-parameter datum table entries */
2084  while ( !feof(fp_7param ) )
2085  {
2086  char code[DATUM_CODE_LENGTH];
2087 
2088  bool userDefined = false;
2089 
2090  if (fscanf(fp_7param, "%s ", code) <= 0)
2091  {
2092  fclose( fp_7param );
2094  }
2095  else
2096  {
2097  if( code[0] == '*' )
2098  {
2099  userDefined = true;
2100  for( int i = 0; i < DATUM_CODE_LENGTH - 1; i++ )
2101  code[i] = code[i+1];
2102 
2103  code[DATUM_CODE_LENGTH-1] = '\0';
2104  }
2105  }
2106 
2107  char name[DATUM_NAME_LENGTH];
2108  if (fscanf(fp_7param, "\"%32[^\"]\"", name) <= 0)
2109  name[0] = '\0';
2110 
2111  char ellipsoidCode[ELLIPSOID_CODE_LENGTH];
2112  double deltaX;
2113  double deltaY;
2114  double deltaZ;
2115  double rotationX;
2116  double rotationY;
2117  double rotationZ;
2118  double scaleFactor;
2119 
2120  if( fscanf( fp_7param, " %s %lf %lf %lf %lf %lf %lf %lf ",
2121  ellipsoidCode, &deltaX, &deltaY, &deltaZ,
2122  &rotationX, &rotationY, &rotationZ, &scaleFactor ) <= 0 )
2123  {
2124  fclose( fp_7param );
2126  }
2127  else
2128  { /* convert from degrees to radians */
2129 
2130  rotationX /= SECONDS_PER_RADIAN;
2131  rotationY /= SECONDS_PER_RADIAN;
2132  rotationZ /= SECONDS_PER_RADIAN;
2133 
2134  datumList.push_back( new SevenParameterDatum(
2135  index, code, ellipsoidCode, name, DatumType::sevenParamDatum,
2136  deltaX, deltaY, deltaZ, -PI, +PI, -PI / 2.0, +PI / 2.0,
2137  rotationX, rotationY, rotationZ, scaleFactor, userDefined ) );
2138  }
2139  index++;
2140  datum7ParamCount++;
2141  }
2142  fclose( fp_7param );
2143 
2144 #ifdef NDK_BUILD
2145  PathName = "/data/data/com.baesystems.msp.geotrans/lib/";
2146  FileName3 = new char[ 80 ];
2147  strcpy( FileName3, PathName );
2148  strcat( FileName3, "lib3paramdat.so" );
2149 #else
2150  if (PathName != NULL)
2151  {
2152  FileName3 = new char[ strlen( PathName ) + 13 ];
2153  strcpy( FileName3, PathName );
2154  strcat( FileName3, "/" );
2155  }
2156  else
2157  {
2158  FileName3 = new char[ file_name_length ];
2159  strcpy( FileName3, "../../data/" );
2160  }
2161  strcat( FileName3, "3_param.dat" );
2162 #endif
2163 
2164  if (( fp_3param = fopen( FileName3, "r" ) ) == NULL)
2165  {
2166  delete [] FileName7;
2167  FileName7 = 0;
2168  delete [] FileName3;
2169  FileName3 = 0;
2170 
2171  char message[256] = "";
2172  strcpy( message, ErrorMessages::datumFileOpenError );
2173  strcat( message, ": 3_param.dat\n" );
2174  throw CoordinateConversionException( message );
2175  }
2176 
2177  datum3ParamCount = 0;
2178 
2179  /* build 3-parameter datum table entries */
2180  while( !feof( fp_3param ) )
2181  {
2182  char code[DATUM_CODE_LENGTH];
2183 
2184  bool userDefined = false;
2185 
2186  if( fscanf( fp_3param, "%s ", code ) <= 0 )
2187  {
2188  fclose( fp_3param );
2190  }
2191  else
2192  {
2193  if( code[0] == '*' )
2194  {
2195  userDefined = true;
2196  for( int i = 0; i < DATUM_CODE_LENGTH - 1; i++ )
2197  code[i] = code[i+1];
2198 
2199  code[DATUM_CODE_LENGTH-1] = '\0';
2200  }
2201  }
2202 
2203  char name[DATUM_NAME_LENGTH];
2204  if( fscanf( fp_3param, "\"%32[^\"]\"", name) <= 0 )
2205  name[0] = '\0';
2206 
2207  char ellipsoidCode[ELLIPSOID_CODE_LENGTH];
2208  double deltaX;
2209  double deltaY;
2210  double deltaZ;
2211  double sigmaX;
2212  double sigmaY;
2213  double sigmaZ;
2214  double eastLongitude;
2215  double westLongitude;
2216  double northLatitude;
2217  double southLatitude;
2218 
2219  if( fscanf( fp_3param, " %s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf ",
2220  ellipsoidCode, &deltaX, &sigmaX, &deltaY, &sigmaY, &deltaZ, &sigmaZ,
2221  &southLatitude, &northLatitude, &westLongitude, &eastLongitude ) <= 0 )
2222  {
2223  fclose( fp_3param );
2225  }
2226  else
2227  {
2228  southLatitude *= PI_OVER_180;
2229  northLatitude *= PI_OVER_180;
2230  westLongitude *= PI_OVER_180;
2231  eastLongitude *= PI_OVER_180;
2232 
2233  datumList.push_back( new ThreeParameterDatum(
2234  index, code, ellipsoidCode, name, DatumType::threeParamDatum,
2235  deltaX, deltaY, deltaZ, westLongitude, eastLongitude,
2236  southLatitude, northLatitude, sigmaX, sigmaY, sigmaZ,
2237  userDefined ) );
2238  }
2239 
2240  index++;
2241  datum3ParamCount++;
2242  }
2243  fclose( fp_3param );
2244 
2245  delete [] FileName7;
2246  FileName7 = 0;
2247  delete [] FileName3;
2248  FileName3 = 0;
2249 }
2250 
2251 
2252 void DatumLibraryImplementation::write3ParamFile()
2253 {
2254 /*
2255  * The function write3ParamFile writes the 3 parameter datums in the datum list
2256  * to the 3_param.dat file.
2257  */
2258 
2259  char datum_name[DATUM_NAME_LENGTH+2];
2260  char *PathName = NULL;
2261  char FileName[FILENAME_LENGTH];
2262  FILE *fp_3param = NULL;
2263 
2264  CCSThreadLock lock(&mutex);
2265 
2266  /*output updated 3-parameter datum table*/
2267  PathName = getenv( "MSPCCS_DATA" );
2268  if (PathName != NULL)
2269  {
2270  strcpy( FileName, PathName );
2271  strcat( FileName, "/" );
2272  }
2273  else
2274  {
2275  strcpy( FileName, "../../data/" );
2276  }
2277  strcat( FileName, "3_param.dat" );
2278 
2279  if ((fp_3param = fopen(FileName, "w")) == NULL)
2280  { /* fatal error */
2281  char message[256] = "";
2282  if (NULL == PathName)
2283  {
2284  strcpy( message, "Environment variable undefined: MSPCCS_DATA." );
2285  }
2286  else
2287  {
2288  strcpy( message, ErrorMessages::datumFileOpenError );
2289  strcat( message, ": 3_param.dat\n" );
2290  }
2291  throw CoordinateConversionException( message );
2292  }
2293 
2294  /* write file */
2295  long index = MAX_WGS + datum7ParamCount;
2296  int size = datumList.size();
2297  while( index < size )
2298  {
2299  ThreeParameterDatum* _3parameterDatum = ( ThreeParameterDatum* )datumList[index];
2300  if( _3parameterDatum )
2301  {
2302  strcpy( datum_name, "\"" );
2303  strcat( datum_name, datumList[index]->name());
2304  strcat( datum_name, "\"" );
2305  if( _3parameterDatum->userDefined() )
2306  fprintf( fp_3param, "*");
2307 
2308  fprintf( fp_3param, "%-6s %-33s%-2s %4.0f %4.0f %4.0f %4.0f %5.0f %4.0f %4.0f %4.0f %4.0f %4.0f \n",
2309  _3parameterDatum->code(),
2310  datum_name,
2311  _3parameterDatum->ellipsoidCode(),
2312  _3parameterDatum->deltaX(),
2313  _3parameterDatum->sigmaX(),
2314  _3parameterDatum->deltaY(),
2315  _3parameterDatum->sigmaY(),
2316  _3parameterDatum->deltaZ(),
2317  _3parameterDatum->sigmaZ(),
2318  ( _3parameterDatum->southLatitude() * _180_OVER_PI ),
2319  ( _3parameterDatum->northLatitude() * _180_OVER_PI ),
2320  ( _3parameterDatum->westLongitude() * _180_OVER_PI ),
2321  ( _3parameterDatum->eastLongitude() * _180_OVER_PI ) );
2322  }
2323 
2324  index++;
2325  }
2326 
2327  fclose( fp_3param );
2328 
2329 }
2330 
2331 
2332 void DatumLibraryImplementation::write7ParamFile()
2333 {
2334 /*
2335  * The function write3ParamFile writes the 7 parameter datums in the datum list
2336  * to the 7_param.dat file.
2337  */
2338 
2339  char datum_name[DATUM_NAME_LENGTH+2];
2340  char *PathName = NULL;
2341  char FileName[FILENAME_LENGTH];
2342  FILE *fp_7param = NULL;
2343 
2344  CCSThreadLock lock(&mutex);
2345 
2346  /*output updated 7-parameter datum table*/
2347  PathName = getenv( "MSPCCS_DATA" );
2348  if (PathName != NULL)
2349  {
2350  strcpy( FileName, PathName );
2351  strcat( FileName, "/" );
2352  }
2353  else
2354  {
2355  strcpy( FileName, "../../data/" );
2356  }
2357  strcat( FileName, "7_param.dat" );
2358 
2359  if ((fp_7param = fopen(FileName, "w")) == NULL)
2360  { /* fatal error */
2361  char message[256] = "";
2362  if (NULL == PathName)
2363  {
2364  strcpy( message, "Environment variable undefined: MSPCCS_DATA." );
2365  }
2366  else
2367  {
2368  strcpy( message, ErrorMessages::datumFileOpenError );
2369  strcat( message, ": 7_param.dat\n" );
2370  }
2371  throw CoordinateConversionException( message );
2372  }
2373 
2374  /* write file */
2375  long index = MAX_WGS;
2376  int endIndex = datum7ParamCount + MAX_WGS;
2377  while( index < endIndex )
2378  {
2379  SevenParameterDatum* _7parameterDatum = ( SevenParameterDatum* )datumList[index];
2380  if( _7parameterDatum )
2381  {
2382  strcpy( datum_name, "\"" );
2383  strcat( datum_name, datumList[index]->name());
2384  strcat( datum_name, "\"" );
2385  if( _7parameterDatum->userDefined() )
2386  fprintf( fp_7param, "*");
2387 
2388  fprintf( fp_7param, "%-6s %-33s%-2s %4.0f %4.0f %4.0f % 4.3f % 4.3f % 4.3f % 4.10f \n",
2389  _7parameterDatum->code(),
2390  datum_name,
2391  _7parameterDatum->ellipsoidCode(),
2392  _7parameterDatum->deltaX(),
2393  _7parameterDatum->deltaY(),
2394  _7parameterDatum->deltaZ(),
2395  _7parameterDatum->rotationX() * SECONDS_PER_RADIAN,
2396  _7parameterDatum->rotationY() * SECONDS_PER_RADIAN,
2397  _7parameterDatum->rotationZ() * SECONDS_PER_RADIAN,
2398  _7parameterDatum->scaleFactor() );
2399  }
2400 
2401  index++;
2402  }
2403 
2404  fclose( fp_7param );
2405 }
2406 
2407 
2408 GeodeticCoordinates* DatumLibraryImplementation::geodeticShiftWGS84ToWGS72( const double WGS84Longitude, const double WGS84Latitude, const double WGS84Height )
2409 {
2410 /*
2411  * The function geodeticShiftWGS84ToWGS72 shifts a geodetic coordinate (latitude, longitude in radians
2412  * and height in meters) relative to WGS84 to a geodetic coordinate
2413  * (latitude, longitude in radians and height in meters) relative to WGS72.
2414  *
2415  * WGS84Longitude : Longitude in radians relative to WGS84 (input)
2416  * WGS84Latitude : Latitude in radians relative to WGS84 (input)
2417  * WGS84Height : Height in meters relative to WGS84 (input)
2418  * WGS72Longitude : Longitude in radians relative to WGS72 (output)
2419  * WGS72Latitude : Latitude in radians relative to WGS72 (output)
2420  * WGS72Height : Height in meters relative to WGS72 (output)
2421  */
2422 
2423  double Delta_Lat;
2424  double Delta_Lon;
2425  double Delta_Hgt;
2426  double WGS84_a; /* Semi-major axis of WGS84 ellipsoid */
2427  double WGS84_f; /* Flattening of WGS84 ellipsoid */
2428  double WGS72_a; /* Semi-major axis of WGS72 ellipsoid */
2429  double WGS72_f; /* Flattening of WGS72 ellipsoid */
2430  double da; /* WGS72_a - WGS84_a */
2431  double df; /* WGS72_f - WGS84_f */
2432  double Q;
2433  double sin_Lat;
2434  double sin2_Lat;
2435 
2436  long wgs84EllipsoidIndex;
2437  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
2438  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &WGS84_a, &WGS84_f );
2439 
2440  long wgs72EllipsoidIndex;
2441  _ellipsoidLibraryImplementation->ellipsoidIndex( "WD", &wgs72EllipsoidIndex );
2442  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs72EllipsoidIndex, &WGS72_a, &WGS72_f );
2443 
2444  da = WGS72_a - WGS84_a;
2445  df = WGS72_f - WGS84_f;
2446  Q = PI / 648000;
2447  sin_Lat = sin(WGS84Latitude);
2448  sin2_Lat = sin_Lat * sin_Lat;
2449 
2450  Delta_Lat = (-4.5 * cos(WGS84Latitude)) / (WGS84_a*Q)
2451  + (df * sin(2*WGS84Latitude)) / Q;
2452  Delta_Lat /= SECONDS_PER_RADIAN;
2453  Delta_Lon = -0.554 / SECONDS_PER_RADIAN;
2454  Delta_Hgt = -4.5 * sin_Lat + WGS84_a * df * sin2_Lat - da - 1.4;
2455 
2456  double wgs72Latitude = WGS84Latitude + Delta_Lat;
2457  double wgs72Longitude = WGS84Longitude + Delta_Lon;
2458  double wgs72Height = WGS84Height + Delta_Hgt;
2459 
2460  if (wgs72Latitude > PI_OVER_2)
2461  wgs72Latitude = PI_OVER_2 - (wgs72Latitude - PI_OVER_2);
2462  else if (wgs72Latitude < -PI_OVER_2)
2463  wgs72Latitude = -PI_OVER_2 - (wgs72Latitude + PI_OVER_2);
2464 
2465  if (wgs72Longitude > PI)
2466  wgs72Longitude -= TWO_PI;
2467  if (wgs72Longitude < -PI)
2468  wgs72Longitude += TWO_PI;
2469 
2470  return new GeodeticCoordinates(CoordinateType::geodetic, wgs72Longitude, wgs72Latitude, wgs72Height);
2471 }
2472 
2473 
2474 GeodeticCoordinates* DatumLibraryImplementation::geodeticShiftWGS72ToWGS84( const double WGS72Longitude, const double WGS72Latitude, const double WGS72Height )
2475 {
2476 /*
2477  * The function geodeticShiftWGS72ToWGS84 shifts a geodetic coordinate (latitude, longitude in radians
2478  * and height in meters) relative to WGS72 to a geodetic coordinate
2479  * (latitude, longitude in radians and height in meters) relative to WGS84.
2480  *
2481  * WGS72Longitude : Longitude in radians relative to WGS72 (input)
2482  * WGS72Latitude : Latitude in radians relative to WGS72 (input)
2483  * WGS72Height : Height in meters relative to WGS72 (input)
2484  * WGS84Longitude : Longitude in radians relative to WGS84 (output)
2485  * WGS84Latitude : Latitude in radians relative to WGS84 (output)
2486  * WGS84Height : Height in meters relative to WGS84 (output)
2487  */
2488 
2489  double Delta_Lat;
2490  double Delta_Lon;
2491  double Delta_Hgt;
2492  double WGS84_a; /* Semi-major axis of WGS84 ellipsoid */
2493  double WGS84_f; /* Flattening of WGS84 ellipsoid */
2494  double WGS72_a; /* Semi-major axis of WGS72 ellipsoid */
2495  double WGS72_f; /* Flattening of WGS72 ellipsoid */
2496  double da; /* WGS84_a - WGS72_a */
2497  double df; /* WGS84_f - WGS72_f */
2498  double Q;
2499  double sin_Lat;
2500  double sin2_Lat;
2501 
2502  long wgs84EllipsoidIndex;
2503  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
2504  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &WGS84_a, &WGS84_f );
2505 
2506  long wgs72EllipsoidIndex;
2507  _ellipsoidLibraryImplementation->ellipsoidIndex( "WD", &wgs72EllipsoidIndex );
2508  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs72EllipsoidIndex, &WGS72_a, &WGS72_f );
2509 
2510  da = WGS84_a - WGS72_a;
2511  df = WGS84_f - WGS72_f;
2512  Q = PI / 648000;
2513  sin_Lat = sin(WGS72Latitude);
2514  sin2_Lat = sin_Lat * sin_Lat;
2515 
2516  Delta_Lat = (4.5 * cos(WGS72Latitude)) / (WGS72_a*Q) + (df * sin(2*WGS72Latitude)) / Q;
2517  Delta_Lat /= SECONDS_PER_RADIAN;
2518  Delta_Lon = 0.554 / SECONDS_PER_RADIAN;
2519  Delta_Hgt = 4.5 * sin_Lat + WGS72_a * df * sin2_Lat - da + 1.4;
2520 
2521  double wgs84Latitude = WGS72Latitude + Delta_Lat;
2522  double wgs84Longitude = WGS72Longitude + Delta_Lon;
2523  double wgs84Height = WGS72Height + Delta_Hgt;
2524 
2525  if (wgs84Latitude > PI_OVER_2)
2526  wgs84Latitude = PI_OVER_2 - (wgs84Latitude - PI_OVER_2);
2527  else if (wgs84Latitude < -PI_OVER_2)
2528  wgs84Latitude = -PI_OVER_2 - (wgs84Latitude + PI_OVER_2);
2529 
2530  if (wgs84Longitude > PI)
2531  wgs84Longitude -= TWO_PI;
2532  if (wgs84Longitude < -PI)
2533  wgs84Longitude += TWO_PI;
2534 
2535  return new GeodeticCoordinates(CoordinateType::geodetic, wgs84Longitude, wgs84Latitude, wgs84Height);
2536 }
2537 
2538 
2539 CartesianCoordinates* DatumLibraryImplementation::geocentricShiftWGS84ToWGS72( const double X_WGS84, const double Y_WGS84, const double Z_WGS84 )
2540 {
2541 /*
2542  * The function geocentricShiftWGS84ToWGS72 shifts a geocentric coordinate (X, Y, Z in meters) relative
2543  * to WGS84 to a geocentric coordinate (X, Y, Z in meters) relative to WGS72.
2544  *
2545  * X_WGS84 : X coordinate relative to WGS84 (input)
2546  * Y_WGS84 : Y coordinate relative to WGS84 (input)
2547  * Z_WGS84 : Z coordinate relative to WGS84 (input)
2548  * X : X coordinate relative to WGS72 (output)
2549  * Y : Y coordinate relative to WGS72 (output)
2550  * Z : Z coordinate relative to WGS72 (output)
2551  */
2552 
2553  double a_72; /* Semi-major axis in meters of WGS72 ellipsoid */
2554  double f_72; /* Flattening of WGS72 ellipsoid */
2555  double a_84; /* Semi-major axis in meters of WGS84 ellipsoid */
2556  double f_84; /* Flattening of WGS84 ellipsoid */
2557 
2558  /* Set WGS84 ellipsoid params */
2559  long wgs84EllipsoidIndex;
2560  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
2561  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &a_84, &f_84 );
2562 
2563  Geocentric geocentric84( a_84, f_84 );
2564 
2565  CartesianCoordinates cart( CoordinateType::geocentric, X_WGS84, Y_WGS84, Z_WGS84 );
2566  GeodeticCoordinates* wgs84GeodeticCoordinates = geocentric84.convertToGeodetic( &cart );
2567 
2568  GeodeticCoordinates* wgs72GeodeticCoordinates = geodeticShiftWGS84ToWGS72( wgs84GeodeticCoordinates->longitude(), wgs84GeodeticCoordinates->latitude(), wgs84GeodeticCoordinates->height() );
2569 
2570  /* Set WGS72 ellipsoid params */
2571  long wgs72EllipsoidIndex;
2572  _ellipsoidLibraryImplementation->ellipsoidIndex( "WD", &wgs72EllipsoidIndex );
2573  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs72EllipsoidIndex, &a_72, &f_72 );
2574 
2575  Geocentric geocentric72( a_72, f_72 );
2576 
2577  CartesianCoordinates* wgs72GeocentricCoordinates = geocentric72.convertFromGeodetic( wgs72GeodeticCoordinates );
2578 
2579  delete wgs72GeodeticCoordinates;
2580  delete wgs84GeodeticCoordinates;
2581 
2582  return wgs72GeocentricCoordinates;
2583 }
2584 
2585 
2586 CartesianCoordinates* DatumLibraryImplementation::geocentricShiftWGS72ToWGS84( const double X, const double Y, const double Z )
2587 {
2588 /*
2589  * The function geocentricShiftWGS72ToWGS84 shifts a geocentric coordinate (X, Y, Z in meters) relative
2590  * to WGS72 to a geocentric coordinate (X, Y, Z in meters) relative to WGS84.
2591  *
2592  * X : X coordinate relative to WGS72 (input)
2593  * Y : Y coordinate relative to WGS72 (input)
2594  * Z : Z coordinate relative to WGS72 (input)
2595  * X_WGS84 : X coordinate relative to WGS84 (output)
2596  * Y_WGS84 : Y coordinate relative to WGS84 (output)
2597  * Z_WGS84 : Z coordinate relative to WGS84 (output)
2598  */
2599 
2600  double a_72; /* Semi-major axis in meters of WGS72 ellipsoid */
2601  double f_72; /* Flattening of WGS72 ellipsoid */
2602  double a_84; /* Semi-major axis in meters of WGS84 ellipsoid */
2603  double f_84; /* Flattening of WGS84 ellipsoid */
2604 
2605  /* Set WGS72 ellipsoid params */
2606  long wgs72EllipsoidIndex;
2607  _ellipsoidLibraryImplementation->ellipsoidIndex( "WD", &wgs72EllipsoidIndex );
2608  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs72EllipsoidIndex, &a_72, &f_72 );
2609 
2610  Geocentric geocentric72( a_72, f_72 );
2612  GeodeticCoordinates* wgs72GeodeticCoordinates = geocentric72.convertToGeodetic( &cart );
2613 
2614  GeodeticCoordinates* wgs84GeodeticCoordinates = geodeticShiftWGS72ToWGS84( wgs72GeodeticCoordinates->longitude(), wgs72GeodeticCoordinates->latitude(), wgs72GeodeticCoordinates->height() );
2615 
2616  /* Set WGS84 ellipsoid params */
2617  long wgs84EllipsoidIndex;
2618  _ellipsoidLibraryImplementation->ellipsoidIndex( "WE", &wgs84EllipsoidIndex );
2619  _ellipsoidLibraryImplementation->ellipsoidParameters( wgs84EllipsoidIndex, &a_84, &f_84 );
2620 
2621  Geocentric geocentric84( a_84, f_84 );
2622  CartesianCoordinates* wgs84GeocentricCoordinates = geocentric84.convertFromGeodetic( wgs84GeodeticCoordinates );
2623 
2624  delete wgs84GeodeticCoordinates;
2625  delete wgs72GeodeticCoordinates;
2626 
2627  return wgs84GeocentricCoordinates;
2628 }
2629 
2630 
2631 // CLASSIFICATION: UNCLASSIFIED
static const char * datumRotation
Definition: ErrorMessages.h:37
double linearError90()
Definition: Accuracy.cpp:86
static const char * datumDomain
Definition: ErrorMessages.h:36
CartesianCoordinates * geocentricDatumShift(const long sourceIndex, const double sourceX, const double sourceY, const double sourceZ, const long targetIndex)
void datumStandardErrors(const long index, double *sigmaX, double *sigmaY, double *sigmaZ)
void datumName(const long index, char *name)
void datumSevenParameters(const long index, double *rotationX, double *rotationY, double *rotationZ, double *scaleFactor)
CartesianCoordinates * geocentricShiftFromWGS84(const double WGS84X, const double WGS84Y, const double WGS84Z, const long targetIndex)
char * ellipsoidCode() const
Definition: Datum.cpp:101
#define PI_OVER_2
Definition: MGRS.cpp:165
GeodeticCoordinates * geodeticShiftToWGS84(const long sourceIndex, const GeodeticCoordinates *sourceCoordinates)
static const char * datumFileParseError
Definition: ErrorMessages.h:35
void datumIndex(const char *code, long *index)
void datumUserDefined(const long index, long *result)
const char * WGS84_Datum_Code
const int FILENAME_LENGTH
void retrieveDatumType(const long index, DatumType::Enum *datumType)
double deltaX() const
Definition: Datum.cpp:119
static const char * datumType
Definition: ErrorMessages.h:39
static const char * datumFileOpenError
Definition: ErrorMessages.h:33
double southLatitude() const
Definition: Datum.cpp:149
static const char * notUserDefined
Definition: ErrorMessages.h:42
double northLatitude() const
Definition: Datum.cpp:155
double circularError90()
Definition: Accuracy.cpp:80
GeodeticCoordinates * geodeticShiftFromWGS84(const GeodeticCoordinates *sourceCoordinates, const long targetIndex)
CartesianCoordinates * geocentricShiftToWGS84(const long sourceIndex, const double sourceX, const double sourceY, const double sourceZ)
bool datumUsesEllipsoid(const char *ellipsoidCode)
const double MOLODENSKY_MAX
static const char * longitude
Definition: ErrorMessages.h:76
void datumEllipsoidCode(const long index, char *code)
DatumType::Enum datumType() const
Definition: Datum.cpp:113
void define7ParamDatum(const char *code, const char *name, const char *ellipsoidCode, double deltaX, double deltaY, double deltaZ, double rotationX, double rotationY, double rotationZ, double scale, double westLongitude, double eastLongitude, double southLatitude, double northLatitude)
const double MIN_LON
MSP::CCS::GeodeticCoordinates * convertToGeodetic(MSP::CCS::CartesianCoordinates *cartesianCoordinates)
Definition: Geocentric.cpp:235
double deltaZ() const
Definition: Datum.cpp:131
double deltaY() const
Definition: Datum.cpp:125
void datumTranslationValues(const long index, double *deltaX, double *deltaY, double *deltaZ)
static const char * datumSigma
Definition: ErrorMessages.h:38
double eastLongitude() const
Definition: Datum.cpp:143
static const char * latitude
Definition: ErrorMessages.h:75
bool userDefined() const
Definition: Datum.cpp:161
#define MAX_LAT
Definition: UTM.cpp:117
void ellipsoidParameters(const long index, double *a, double *f)
char * code() const
Definition: Datum.cpp:95
static DatumLibraryImplementation * getInstance()
const double MAX_LON
DatumLibraryImplementation & operator=(const DatumLibraryImplementation &d)
#define PI
Definition: MGRS.cpp:164
static const char * invalidIndex
Definition: ErrorMessages.h:99
MSP::CCS::CartesianCoordinates * convertFromGeodetic(const MSP::CCS::GeodeticCoordinates *geodeticCoordinates)
Definition: Geocentric.cpp:186
const int MAX_WGS
Accuracy * datumShiftError(const long sourceIndex, const long targetIndex, double longitude, double latitude, Accuracy *sourceAccuracy, Precision::Enum precision)
static const char * scaleFactor
Definition: ErrorMessages.h:52
void validDatum(const long index, double longitude, double latitude, long *result)
const double SECONDS_PER_RADIAN
const double _180_OVER_PI
#define PI_OVER_180
Definition: MGRS.cpp:166
static const char * invalidDatumCode
Definition: ErrorMessages.h:40
void define3ParamDatum(const char *code, const char *name, const char *ellipsoidCode, double deltaX, double deltaY, double deltaZ, double sigmaX, double sigmaY, double sigmaZ, double westLongitude, double eastLongitude, double southLatitude, double northLatitude)
const double TWO_PI
static const char * ellipse
Definition: ErrorMessages.h:30
class MSP::CCS::DatumLibraryImplementationCleaner datumLibraryImplementationCleanerInstance
double sphericalError90()
Definition: Accuracy.cpp:92
#define MIN_LAT
Definition: UTM.cpp:116
double westLongitude() const
Definition: Datum.cpp:137
const int ELLIPSOID_CODE_LENGTH
void datumValidRectangle(const long index, double *westLongitude, double *eastLongitude, double *southLatitude, double *northLatitude)
GeodeticCoordinates * geodeticDatumShift(const long sourceIndex, const GeodeticCoordinates *sourceCoordinates, const long targetIndex)
void datumCode(const long index, char *code)
const char * WGS72_Datum_Code
void setEllipsoidLibraryImplementation(EllipsoidLibraryImplementation *__ellipsoidLibraryImplementation)
static double toMeters(const Enum &prec)
Definition: Precision.h:54
GeodeticCoordinates * molodenskyShift(const double a, const double da, const double f, const double df, const double dx, const double dy, const double dz, const double sourceLongitude, const double sourceLatitude, const double sourceHeight)