UNCLASSIFIED

GeographicTranslator
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Macros
Eckert6.cpp
Go to the documentation of this file.
1 // CLASSIFICATION: UNCLASSIFIED
2 
3 /***************************************************************************/
4 /* RSC IDENTIFIER: ECKERT6
5  *
6  * ABSTRACT
7  *
8  * This component provides conversions between Geodetic coordinates
9  * (latitude and longitude in radians) and Eckert VI projection coordinates
10  * (easting and northing in meters). This projection employs a spherical
11  * Earth model. The spherical radius used is the radius of the sphere
12  * having the same area as the ellipsoid.
13  *
14  * ERROR HANDLING
15  *
16  * This component checks parameters for valid values. If an invalid value
17  * is found, the error code is combined with the current error code using
18  * the bitwise or. This combining allows multiple error codes to be
19  * returned. The possible error codes are:
20  *
21  * ECK6_NO_ERROR : No errors occurred in function
22  * ECK6_LAT_ERROR : Latitude outside of valid range
23  * (-90 to 90 degrees)
24  * ECK6_LON_ERROR : Longitude outside of valid range
25  * (-180 to 360 degrees)
26  * ECK6_EASTING_ERROR : Easting outside of valid range
27  * (False_Easting +/- ~18,000,000 m,
28  * depending on ellipsoid parameters)
29  * ECK6_NORTHING_ERROR : Northing outside of valid range
30  * (False_Northing +/- 0 to ~8,000,000 m,
31  * depending on ellipsoid parameters)
32  * ECK6_CENT_MER_ERROR : Central meridian outside of valid range
33  * (-180 to 360 degrees)
34  * ECK6_A_ERROR : Semi-major axis less than or equal to zero
35  * ECK6_INV_F_ERROR : Inverse flattening outside of valid range
36  * (250 to 350)
37  *
38  * REUSE NOTES
39  *
40  * ECKERT6 is intended for reuse by any application that performs a
41  * Eckert VI projection or its inverse.
42  *
43  * REFERENCES
44  *
45  * Further information on ECKERT6 can be found in the Reuse Manual.
46  *
47  * ECKERT6 originated from : U.S. Army Topographic Engineering Center
48  * Geospatial Information Division
49  * 7701 Telegraph Road
50  * Alexandria, VA 22310-3864
51  *
52  * LICENSES
53  *
54  * None apply to this component.
55  *
56  * RESTRICTIONS
57  *
58  * ECKERT6 has no restrictions.
59  *
60  * ENVIRONMENT
61  *
62  * ECKERT6 was tested and certified in the following environments:
63  *
64  * 1. Solaris 2.5 with GCC 2.8.1
65  * 2. MS Windows 95 with MS Visual C++ 6
66  *
67  * MODIFICATIONS
68  *
69  * Date Description
70  * ---- -----------
71  * 04-16-99 Original Code
72  * 03-06-07 Original C++ Code
73  *
74  */
75 
76 
77 /***************************************************************************/
78 /*
79  * INCLUDES
80  */
81 
82 #include <math.h>
83 #include "Eckert6.h"
86 #include "GeodeticCoordinates.h"
88 #include "ErrorMessages.h"
89 
90 /*
91  * math.h - Is needed to call the math functions (sqrt, pow, exp, log,
92  * sin, cos, tan, and atan).
93  * Eckert6.h - Is for prototype error checking.
94  * MapProjectionCoordinates.h - defines map projection coordinates
95  * GeodeticCoordinates.h - defines geodetic coordinates
96  * CoordinateConversionException.h - Exception handler
97  * ErrorMessages.h - Contains exception messages
98  */
99 
100 
101 using namespace MSP::CCS;
102 
103 
104 /***************************************************************************/
105 /* DEFINES
106  *
107  */
108 
109 const double PI = 3.14159265358979323e0; /* PI */
110 const double PI_OVER_2 = ( PI / 2.0);
111 const double MAX_LAT = ( (PI * 90) / 180.0 ); /* 90 degrees in radians */
112 const double TWO_PI = (2.0 * PI);
113 const double one_PLUS_PI_OVER_2 = (1.0 + PI / 2.0);
114 
115 
116 /************************************************************************/
117 /* FUNCTIONS
118  *
119  */
120 
121 Eckert6::Eckert6( double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double falseEasting, double falseNorthing ) :
123  es2( 0.0066943799901413800 ),
124  es4( 4.4814723452405e-005 ),
125  es6( 3.0000678794350e-007 ),
126  Ra_Over_Sqrt_Two_Plus_PI( 2809695.5356062 ),
127  Inv_Ra_Over_Sqrt_Two_Plus_PI( 3.5591044913137e-007 ),
128  Eck6_Origin_Long( 0.0 ),
129  Eck6_False_Easting( 0.0 ),
130  Eck6_False_Northing( 0.0 ),
131  Eck6_Delta_Northing( 8826919.0 ),
132  Eck6_Max_Easting( 17653838.0 )
133 {
134 /*
135  * The constructor receives the ellipsoid parameters and
136  * Eckert VI projection parameters as inputs, and sets the corresponding state
137  * variables. If any errors occur, an exception is thrown with a description
138  * of the error.
139  *
140  * ellipsoidSemiMajorAxis : Semi-major axis of ellipsoid, in meters (input)
141  * ellipsoidFlattening : Flattening of ellipsoid (input)
142  * centralMeridian : Longitude in radians at the center of (input)
143  * the projection
144  * falseEasting : A coordinate value in meters assigned to the
145  * central meridian of the projection. (input)
146  * falseNorthing : A coordinate value in meters assigned to the
147  * origin latitude of the projection (input)
148  */
149 
150  double Ra; /* Spherical radius */
151  double inv_f = 1 / ellipsoidFlattening;
152 
153  if (ellipsoidSemiMajorAxis <= 0.0)
154  { /* Semi-major axis must be greater than zero */
156  }
157  if ((inv_f < 250) || (inv_f > 350))
158  { /* Inverse flattening must be between 250 and 350 */
160  }
161  if ((centralMeridian < -PI) || (centralMeridian > TWO_PI))
162  { /* origin longitude out of range */
164  }
165 
166  semiMajorAxis = ellipsoidSemiMajorAxis;
167  flattening = ellipsoidFlattening;
168 
169  es2 = 2 * flattening - flattening * flattening;
170  es4 = es2 * es2;
171  es6 = es4 * es2;
172  /* spherical radius */
173  Ra = semiMajorAxis *
174  (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0 * es6 /3024.0);
175  Ra_Over_Sqrt_Two_Plus_PI = Ra / (sqrt(2.0 + PI));
176  Inv_Ra_Over_Sqrt_Two_Plus_PI = 1 / Ra_Over_Sqrt_Two_Plus_PI;
177  if (centralMeridian > PI)
178  centralMeridian -= TWO_PI;
179  Eck6_Origin_Long = centralMeridian;
180  Eck6_False_Easting = falseEasting;
181  Eck6_False_Northing = falseNorthing;
182  if (Eck6_Origin_Long > 0)
183  {
184  Eck6_Max_Easting = 17555761.0;
185  Eck6_Min_Easting = -17653839.0;
186  }
187  else if (Eck6_Origin_Long < 0)
188  {
189  Eck6_Max_Easting = 17653838.0;
190  Eck6_Min_Easting = -17555761.0;
191  }
192  else
193  {
194  Eck6_Max_Easting = 17653838.0;
195  Eck6_Min_Easting = -17653838.0;
196  }
197 }
198 
199 
201 {
204  es2 = e.es2;
205  es4 = e.es4;
206  es6 = e.es6;
207  Ra_Over_Sqrt_Two_Plus_PI = e.Ra_Over_Sqrt_Two_Plus_PI;
208  Inv_Ra_Over_Sqrt_Two_Plus_PI = e.Inv_Ra_Over_Sqrt_Two_Plus_PI;
209  Eck6_Origin_Long = e.Eck6_Origin_Long;
210  Eck6_False_Easting = e.Eck6_False_Easting;
211  Eck6_False_Northing = e.Eck6_False_Northing;
212  Eck6_Delta_Northing = e.Eck6_Delta_Northing;
213  Eck6_Max_Easting = e.Eck6_Max_Easting;
214 }
215 
216 
218 {
219 }
220 
221 
223 {
224  if( this != &e )
225  {
228  es2 = e.es2;
229  es4 = e.es4;
230  es6 = e.es6;
231  Ra_Over_Sqrt_Two_Plus_PI = e.Ra_Over_Sqrt_Two_Plus_PI;
232  Inv_Ra_Over_Sqrt_Two_Plus_PI = e.Inv_Ra_Over_Sqrt_Two_Plus_PI;
233  Eck6_Origin_Long = e.Eck6_Origin_Long;
234  Eck6_False_Easting = e.Eck6_False_Easting;
235  Eck6_False_Northing = e.Eck6_False_Northing;
236  Eck6_Delta_Northing = e.Eck6_Delta_Northing;
237  Eck6_Max_Easting = e.Eck6_Max_Easting;
238  }
239 
240  return *this;
241 }
242 
243 
245 {
246 /*
247  * The function getParameters returns the current ellipsoid
248  * parameters and Eckert VI projection parameters.
249  *
250  * ellipsoidSemiMajorAxis : Semi-major axis of ellipsoid, in meters (output)
251  * ellipsoidFlattening : Flattening of ellipsoid (output)
252  * centralMeridian : Longitude in radians at the center of (output)
253  * the projection
254  * falseEasting : A coordinate value in meters assigned to the
255  * central meridian of the projection. (output)
256  * falseNorthing : A coordinate value in meters assigned to the
257  * origin latitude of the projection (output)
258  */
259 
260  return new MapProjection3Parameters(
262  Eck6_Origin_Long, Eck6_False_Easting, Eck6_False_Northing );
263 }
264 
265 
267  MSP::CCS::GeodeticCoordinates* geodeticCoordinates )
268 {
269 /*
270  * The function convertFromGeodetic converts geodetic (latitude and
271  * longitude) coordinates to Eckert VI projection (easting and northing)
272  * coordinates, according to the current ellipsoid and Eckert VI projection
273  * parameters. If any errors occur, an exception is thrown with a description
274  * of the error.
275  *
276  * longitude : Longitude (lambda) in radians (input)
277  * latitude : Latitude (phi) in radians (input)
278  * easting : Easting (X) in meters (output)
279  * northing : Northing (Y) in meters (output)
280  */
281 
282  double dlam; /* Longitude - Central Meridan */
283  double delta_theta = 1.0;
284  double dt_tolerance = 4.85e-10; /* approximately 1/1000th of
285  an arc second or 1/10th meter */
286  int count = 60;
287 
288  double longitude = geodeticCoordinates->longitude();
289  double latitude = geodeticCoordinates->latitude();
290  double slat = sin(latitude);
291  double theta = latitude;
292 
293  if ((latitude < -PI_OVER_2) || (latitude > PI_OVER_2))
294  { /* Latitude out of range */
296  }
297  if ((longitude < -PI) || (longitude > TWO_PI))
298  { /* Longitude out of range */
300  }
301 
302  dlam = longitude - Eck6_Origin_Long;
303  if (dlam > PI)
304  {
305  dlam -= TWO_PI;
306  }
307  if (dlam < -PI)
308  {
309  dlam += TWO_PI;
310  }
311  while (fabs(delta_theta) > dt_tolerance && count)
312  {
313  delta_theta = -(theta + sin(theta) - one_PLUS_PI_OVER_2 *
314  slat) / (1.0 + cos(theta));
315  theta += delta_theta;
316  count --;
317  }
318 
319  if(!count)
321 
322  double easting =
323  Ra_Over_Sqrt_Two_Plus_PI * dlam * (1.0 + cos(theta)) + Eck6_False_Easting;
324  double northing = 2.0 * Ra_Over_Sqrt_Two_Plus_PI * theta + Eck6_False_Northing;
325 
326  return new MapProjectionCoordinates(
327  CoordinateType::eckert6, easting, northing );
328 }
329 
330 
332  MSP::CCS::MapProjectionCoordinates* mapProjectionCoordinates )
333 {
334 /*
335  * The function convertToGeodetic converts Eckert VI projection
336  * (easting and northing) coordinates to geodetic (latitude and longitude)
337  * coordinates, according to the current ellipsoid and Eckert VI projection
338  * coordinates. If any errors occur, an exception is thrown with a description
339  * of the error.
340  *
341  * easting : Easting (X) in meters (input)
342  * northing : Northing (Y) in meters (input)
343  * longitude : Longitude (lambda) in radians (output)
344  * latitude : Latitude (phi) in radians (output)
345  */
346 
347  double dx, dy;
348  double theta;
349  double i;
350  double longitude, latitude;
351 
352  double easting = mapProjectionCoordinates->easting();
353  double northing = mapProjectionCoordinates->northing();
354 
355  if ((easting < (Eck6_False_Easting + Eck6_Min_Easting))
356  || (easting > (Eck6_False_Easting + Eck6_Max_Easting)))
357  { /* Easting out of range */
359  }
360  if ((northing < (Eck6_False_Northing - Eck6_Delta_Northing))
361  || (northing > (Eck6_False_Northing + Eck6_Delta_Northing)))
362  { /* Northing out of range */
364  }
365 
366  dy = northing - Eck6_False_Northing;
367  dx = easting - Eck6_False_Easting;
368  theta = Inv_Ra_Over_Sqrt_Two_Plus_PI * dy / 2.0;
369  i = (theta + sin(theta)) / one_PLUS_PI_OVER_2;
370  if (i > 1.0)
371  latitude = MAX_LAT;
372  else if (i < -1.0)
373  latitude = -MAX_LAT;
374  else
375  latitude = asin(i);
376  longitude =
377  Eck6_Origin_Long + Inv_Ra_Over_Sqrt_Two_Plus_PI * dx / (1 + cos(theta));
378 
379  if (latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */
380  latitude = PI_OVER_2;
381  else if (latitude < -PI_OVER_2)
382  latitude = -PI_OVER_2;
383 
384  if (longitude > PI)
385  longitude -= TWO_PI;
386  if (longitude < -PI)
387  longitude += TWO_PI;
388 
389  if (longitude > PI) /* force distorted values to 180, -180 degrees */
390  longitude = PI;
391  else if (longitude < -PI)
392  longitude = -PI;
393 
394  return new GeodeticCoordinates(
395  CoordinateType::geodetic, longitude, latitude );
396 }
397 
398 
399 
400 // CLASSIFICATION: UNCLASSIFIED