OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimMercatorProjection.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 // Copyright (C) 2000 ImageLinks Inc.
3 //
4 // License: See top LICENSE.txt file.
5 //
6 // Author: Garrett Potts
7 //
8 // Description:
9 //
10 // Calls Geotrans Mercator projection code.
11 //*******************************************************************
12 // $Id: ossimMercatorProjection.cpp 17815 2010-08-03 13:23:14Z dburken $
13 
14 #include <math.h>
17 
18 RTTI_DEF1(ossimMercatorProjection, "ossimMercatorProjection", ossimMapProjection)
19 /***************************************************************************/
20 /*
21  * DEFINES
22  */
23 
24 #define PI 3.14159265358979323e0 /* PI */
25 #define PI_OVER_2 ( PI / 2.0e0)
26 //#define MAX_LAT ( (PI * 89.5) / 180.0 ) /* 89.5 degrees in radians */
27 #define MAX_LAT ( (PI * 89.99) / 180.0 ) /* 89.99 degrees in radians */
28 
29 #define MERC_NO_ERROR 0x0000
30 #define MERC_LAT_ERROR 0x0001
31 #define MERC_LON_ERROR 0x0002
32 #define MERC_EASTING_ERROR 0x0004
33 #define MERC_NORTHING_ERROR 0x0008
34 #define MERC_ORIGIN_LAT_ERROR 0x0010
35 #define MERC_CENT_MER_ERROR 0x0020
36 #define MERC_A_ERROR 0x0040
37 #define MERC_B_ERROR 0x0080
38 #define MERC_A_LESS_B_ERROR 0x0100
39 
41  const ossimGpt& origin)
42  :ossimMapProjection(ellipsoid, origin)
43 {
44  setDefaults();
45  update();
46 }
47 
49  const ossimGpt& origin,
50  double falseEasting,
51  double falseNorthing,
52  double scaleFactor)
53  :ossimMapProjection(ellipsoid, origin)
54 {
55  setDefaults();
56  Merc_False_Easting = falseEasting;
57  Merc_False_Northing = falseNorthing;
58  Merc_Scale_Factor = scaleFactor;
59 
60  update();
61 }
62 
64 {
65 
68  theOrigin.latr(),
69  theOrigin.lonr(),
73 
76 
78 }
79 
81 {
82  Merc_False_Easting = falseEasting;
83  update();
84 }
85 
87 {
88  Merc_False_Northing = falseNorthing;
89  update();
90 }
91 
93 {
94  Merc_Scale_Factor = scaleFactor;
95  update();
96 }
97 
99  double falseNorthing)
100 {
101  Merc_False_Easting = falseEasting;
102  Merc_False_Northing = falseNorthing;
103  update();
104 }
105 
106 void ossimMercatorProjection::setParameters(double falseEasting,
107  double falseNorthing,
108  double scaleFactor)
109 {
110  Merc_False_Easting = falseEasting;
111  Merc_False_Northing = falseNorthing;
112  Merc_Scale_Factor = scaleFactor;
113 
114  update();
115 }
116 
118 {
119  Merc_False_Easting = 0.0;
120  Merc_False_Northing = 0.0;
121  Merc_Delta_Easting = 20237883.0;
122  Merc_Delta_Northing = 23421740.0;
123  Merc_Scale_Factor = 1.0;
124 }
125 
127 {
128  double lat = 0.0;
129  double lon = 0.0;
130 
131  if(theSphericalFlag)
132  {
133  double shift = M_PI * 6378137.0;
134  lon = (eastingNorthing.x / shift) * 180.0;
135  lat = (eastingNorthing.y / shift) * 180.0;
136 
137  lat = 180 / M_PI * (2 * atan( exp( lat * M_PI / 180.0)) - M_PI / 2.0);
138  }
139  else
140  {
141  Convert_Mercator_To_Geodetic(eastingNorthing.x,
142  eastingNorthing.y,
143  &lat,
144  &lon);
145  lat = ossim::radiansToDegrees(lat);
146  lon = ossim::radiansToDegrees(lon);
147  }
148 
149 
150 
151  return ossimGpt(lat, lon, 0.0, theDatum);
152 }
153 
155 {
156  double easting = 0.0;
157  double northing = 0.0;
158  ossimGpt gpt = latLon;
159  ossimDpt result;
160  if (theDatum)
161  {
162  if (theDatum->code() != latLon.datum()->code())
163  {
164  gpt.changeDatum(theDatum); // Shift to our datum.
165  }
166  }
167  if(theSphericalFlag)
168  {
169  double lat = latLon.latd();
170  double lon = latLon.lond();
171  double shift = M_PI * Merc_a;
172  easting = lon * shift / 180.0;
173  northing = log( tan((90 + lat) * M_PI / 360.0 )) / (M_PI / 180.0);
174 
175  northing = northing * shift / 180.0;
176  result = ossimDpt(easting, northing);
177  }
178  else
179  {
180  long errorCode = Convert_Geodetic_To_Mercator(gpt.latr(),
181  gpt.lonr(),
182  &easting,
183  &northing);
184  if(errorCode!=MERC_NO_ERROR)
185  {
186  result.makeNan();
187  }
188  else
189  {
190  result = ossimDpt(easting, northing);
191  }
192  }
193 
194 
195  return result;
196 }
197 
198 
199 bool ossimMercatorProjection::saveState(ossimKeywordlist& kwl, const char* prefix) const
200 {
201  kwl.add(prefix,
204  true);
205 
206  return ossimMapProjection::saveState(kwl, prefix);
207 }
208 
210  const char* prefix)
211 {
212  bool flag = ossimMapProjection::loadState(kwl, prefix);
213 
214  const char* type = kwl.find(prefix, ossimKeywordNames::TYPE_KW);
215  const char* scaleFactor = kwl.find(prefix, ossimKeywordNames::SCALE_FACTOR_KW);
216 
217  setDefaults();
218 
220  {
223 
224  if(scaleFactor)
225  {
226  Merc_Scale_Factor = ossimString(scaleFactor).toDouble();
227  }
228  }
229  update();
230 
231  return flag;
232 }
233 
234 
235 /***************************************************************************/
236 /*
237  * FUNCTIONS
238  */
239 
240 
242  double f,
243  double Origin_Latitude,
244  double Central_Meridian,
245  double False_Easting,
246  double False_Northing,
247  double *Scale_Factor)
248 { /* BEGIN Set_Mercator_Parameters */
249 /*
250  * The function Set_Mercator_Parameters receives the ellipsoid parameters and
251  * Mercator projection parameters as inputs, and sets the corresponding state
252  * variables. It calculates and returns the scale factor. If any errors
253  * occur, the error code(s) are returned by the function, otherwise Merc_NO_ERROR
254  * is returned.
255  *
256  * a : Semi-major axis of ellipsoid, in meters (input)
257  * f : Flattening of ellipsoid (input)
258  * Origin_Latitude : Latitude in radians at which the (input)
259  * point scale factor is 1.0
260  * Central_Meridian : Longitude in radians at the center of (input)
261  * the projection
262  * False_Easting : A coordinate value in meters assigned to the
263  * central meridian of the projection. (input)
264  * False_Northing : A coordinate value in meters assigned to the
265  * origin latitude of the projection (input)
266  * Scale_Factor : Multiplier which reduces distances in the
267  * projection to the actual distance on the
268  * ellipsoid (output)
269  */
270 
271  double es2; /* Eccentricity squared of ellipsoid to the second power */
272  double es3; /* Eccentricity squared of ellipsoid to the third power */
273  double es4; /* Eccentricity squared of ellipsoid to the fourth power */
274  double sin_olat; /* sin(Origin_Latitude), temp variable */
275 // double inv_f = 1 / f;
276  long Error_Code = MERC_NO_ERROR;
277 
279 
280 // if (a <= 0.0)
281 // { /* Semi-major axis must be greater than zero */
282 // Error_Code |= MERC_A_ERROR;
283 // }
284 // if ((inv_f < 250) || (inv_f > 350))
285 // { /* Inverse flattening must be between 250 and 350 */
286 // Error_Code |= MERC_INV_F_ERROR;
287 // }
288 // if ((Origin_Latitude < -MAX_LAT) || (Origin_Latitude > MAX_LAT))
289 // { /* origin latitude out of range */
290 // Error_Code |= MERC_ORIGIN_LAT_ERROR;
291 // }
292 // if ((Central_Meridian < -PI) || (Central_Meridian > (2*PI)))
293 // { /* origin longitude out of range */
294 // Error_Code |= MERC_CENT_MER_ERROR;
295 // }
296  if (!Error_Code)
297  { /* no errors */
298  Merc_a = a;
299  Merc_f = f;
300  Merc_Origin_Lat = Origin_Latitude;
301 // if (Central_Meridian > PI)
302 // Central_Meridian -= (2*PI);
303  Merc_Origin_Long = Central_Meridian;
304  Merc_False_Northing = False_Northing;
305  Merc_False_Easting = False_Easting;
306  Merc_es = 2 * Merc_f - Merc_f * Merc_f;
307  Merc_e = sqrt(Merc_es);
308  sin_olat = sin(Origin_Latitude);
309  Merc_Scale_Factor = 1.0 / ( sqrt(1.e0 - Merc_es * sin_olat * sin_olat)
310  / cos(Origin_Latitude) );
311  es2 = Merc_es * Merc_es;
312  es3 = es2 * Merc_es;
313  es4 = es3 * Merc_es;
314  Merc_ab = Merc_es / 2.e0 + 5.e0 * es2 / 24.e0 + es3 / 12.e0
315  + 13.e0 * es4 / 360.e0;
316  Merc_bb = 7.e0 * es2 / 48.e0 + 29.e0 * es3 / 240.e0
317  + 811.e0 * es4 / 11520.e0;
318  Merc_cb = 7.e0 * es3 / 120.e0 + 81.e0 * es4 / 1120.e0;
319  Merc_db = 4279.e0 * es4 / 161280.e0;
320  *Scale_Factor = Merc_Scale_Factor;
323  if (Merc_Delta_Easting < 0)
325  Merc_Delta_Easting *= 1.01;
327  Merc_Delta_Northing *= 1.01;
329  } /* END OF if(!Error_Code) */
330  return (Error_Code);
331 } /* END OF Set_Mercator_Parameters */
332 
333 
335  double *f,
336  double *Origin_Latitude,
337  double *Central_Meridian,
338  double *False_Easting,
339  double *False_Northing,
340  double *Scale_Factor)const
341 { /* BEGIN Get_Mercator_Parameters */
342 /*
343  * The function Get_Mercator_Parameters returns the current ellipsoid
344  * parameters, Mercator projection parameters, and scale factor.
345  *
346  * a : Semi-major axis of ellipsoid, in meters (output)
347  * f : Flattening of ellipsoid (output)
348  * Origin_Latitude : Latitude in radians at which the (output)
349  * point scale factor is 1.0
350  * Central_Meridian : Longitude in radians at the center of (output)
351  * the projection
352  * False_Easting : A coordinate value in meters assigned to the
353  * central meridian of the projection. (output)
354  * False_Northing : A coordinate value in meters assigned to the
355  * origin latitude of the projection (output)
356  * Scale_Factor : Multiplier which reduces distances in the
357  * projection to the actual distance on the
358  * ellipsoid (output)
359  */
360 
361  *a = Merc_a;
362  *f = Merc_f;
363  *Origin_Latitude = Merc_Origin_Lat;
364  *Central_Meridian = Merc_Origin_Long;
365  *False_Easting = Merc_False_Easting;
366  *False_Northing = Merc_False_Northing;
367  *Scale_Factor = Merc_Scale_Factor;
368 
369  return;
370 } /* END OF Get_Mercator_Parameters */
371 
372 
374  double Longitude,
375  double *Easting,
376  double *Northing)const
377 { /* BEGIN Convert_Geodetic_To_Mercator */
378  long Error_Code = MERC_NO_ERROR;
379 /*
380  * The function Convert_Geodetic_To_Mercator converts geodetic (latitude and
381  * longitude) coordinates to Mercator projection (easting and northing)
382  * coordinates, according to the current ellipsoid and Mercator projection
383  * parameters. If any errors occur, the error code(s) are returned by the
384  * function, otherwise MERC_NO_ERROR is returned.
385  *
386  * Latitude : Latitude (phi) in radians (input)
387  * Longitude : Longitude (lambda) in radians (input)
388  * Easting : Easting (X) in meters (output)
389  * Northing : Northing (Y) in meters (output)
390  */
391 
392  double ctanz2; /* Cotangent of z/2 - z - Isometric colatitude */
393  double e_x_sinlat; /* e * sin(Latitude) */
394  double Delta_Long; /* Difference in origin longitude and longitude */
395  double tan_temp;
396  double pow_temp;
397 
398 
399  if ((Latitude < -MAX_LAT) || (Latitude > MAX_LAT))
400  { /* Latitude out of range */
401  Error_Code |= MERC_LAT_ERROR;
402  }
403 // if ((Longitude < -PI) || (Longitude > (2*PI)))
404 // { /* Longitude out of range */
405 // Error_Code |= MERC_LON_ERROR;
406 // }
407  if (!Error_Code)
408  { /* no errors */
409  if (Longitude > PI)
410  Longitude -= (2*PI);
411  e_x_sinlat = Merc_e * sin(Latitude);
412  tan_temp = tan(PI / 4.e0 + Latitude / 2.e0);
413  pow_temp = pow( ((1.e0 - e_x_sinlat) / (1.e0 + e_x_sinlat)),
414  (Merc_e / 2.e0) );
415  ctanz2 = tan_temp * pow_temp;
416  *Northing = Merc_Scale_Factor * Merc_a * log(ctanz2) + Merc_False_Northing;
417  Delta_Long = Longitude - Merc_Origin_Long;
418 // if (Delta_Long > PI)
419 // Delta_Long -= (2 * PI);
420 // if (Delta_Long < -PI)
421 // Delta_Long += (2 * PI);
422  *Easting = Merc_Scale_Factor * Merc_a * Delta_Long
424  }
425 
426  return (Error_Code);
427 } /* END OF Convert_Geodetic_To_Mercator */
428 
429 
431  double Northing,
432  double *Latitude,
433  double *Longitude)const
434 { /* BEGIN Convert_Mercator_To_Geodetic */
435 /*
436  * The function Convert_Mercator_To_Geodetic converts Mercator projection
437  * (easting and northing) coordinates to geodetic (latitude and longitude)
438  * coordinates, according to the current ellipsoid and Mercator projection
439  * coordinates. If any errors occur, the error code(s) are returned by the
440  * function, otherwise MERC_NO_ERROR is returned.
441  *
442  * Easting : Easting (X) in meters (input)
443  * Northing : Northing (Y) in meters (input)
444  * Latitude : Latitude (phi) in radians (output)
445  * Longitude : Longitude (lambda) in radians (output)
446  */
447 
448  double dx; /* Delta easting - Difference in easting (easting-FE) */
449  double dy; /* Delta northing - Difference in northing (northing-FN) */
450  double xphi; /* Isometric latitude */
451  long Error_Code = MERC_NO_ERROR;
452 
453 #if 0
454  if(theSphericalFlag)
455  {
456  *Latitude = M_PI*.5 - 2.0 * atan(exp(-Easting / Merc_a));
457  *Longitude = Easting/Merc_a;
458 
459  return Error_Code;
460  }
461 #endif
462 // if ((Easting < (Merc_False_Easting - Merc_Delta_Easting))
463 // || (Easting > (Merc_False_Easting + Merc_Delta_Easting)))
464 // { /* Easting out of range */
465 // Error_Code |= MERC_EASTING_ERROR;
466 // }
467 // if ((Northing < (Merc_False_Northing - Merc_Delta_Northing))
468 // || (Northing > (Merc_False_Northing + Merc_Delta_Northing)))
469 // { /* Northing out of range */
470 // Error_Code |= MERC_NORTHING_ERROR;
471 // }
472  if (!Error_Code)
473  { /* no errors */
474  dy = Northing - Merc_False_Northing;
475  dx = Easting - Merc_False_Easting;
476  *Longitude = Merc_Origin_Long + dx / (Merc_Scale_Factor * Merc_a);
477  xphi = PI / 2.e0
478  - 2.e0 * atan(1.e0 / exp(dy / (Merc_Scale_Factor * Merc_a)));
479  *Latitude = xphi + Merc_ab * sin(2.e0 * xphi) + Merc_bb * sin(4.e0 * xphi)
480  + Merc_cb * sin(6.e0 * xphi) + Merc_db * sin(8.e0 * xphi);
481 // if (*Longitude > PI)
482 // *Longitude -= (2 * PI);
483 // if (*Longitude < -PI)
484 // *Longitude += (2 * PI);
485  }
486  return (Error_Code);
487 } /* END OF Convert_Mercator_To_Geodetic */
488 
489 //*************************************************************************************************
491 //*************************************************************************************************
493 {
494  if (!ossimMapProjection::operator==(proj))
495  return false;
496 
497  const ossimMercatorProjection* p = dynamic_cast<const ossimMercatorProjection*>(&proj);
498  if (!p) return false;
499 
501 
502  return true;
503 }
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
double lond() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:97
#define MAX_LAT
Represents serializable keyword/value map.
const char * find(const char *key) const
bool almostEqual(T x, T y, T tolerance=FLT_EPSILON)
Definition: ossimCommon.h:53
double y
Definition: ossimDpt.h:165
virtual const ossimString & code() const
Definition: ossimDatum.h:57
#define MERC_NO_ERROR
double latd() const
Will convert the radian measure to degrees.
Definition: ossimGpt.h:87
void Get_Mercator_Parameters(double *a, double *f, double *Origin_Latitude, double *Central_Meridian, double *False_Easting, double *False_Northing, double *Scale_Factor) const
void setParameters(double falseEasting, double falseNorthing, double scaleFactor)
static const char * TYPE_KW
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
void changeDatum(const ossimDatum *datum)
This will actually perform a shift.
Definition: ossimGpt.cpp:316
virtual bool operator==(const ossimProjection &projection) const
Returns TRUE if principal parameters are within epsilon tolerance.
long Set_Mercator_Parameters(double a, double f, double Origin_Latitude, double Central_Meridian, double False_Easting, double False_Northing, double *Scale_Factor)
#define STATIC_TYPE_NAME(T)
Definition: ossimRtti.h:325
const ossimDatum * datum() const
datum().
Definition: ossimGpt.h:196
double radiansToDegrees(double x)
Definition: ossimCommon.h:257
virtual ossimDpt forward(const ossimGpt &latLon) const
All map projections will convert the world coordinate to an easting northing (Meters).
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
#define M_PI
void setScaleFactor(double scaleFactor)
long Convert_Geodetic_To_Mercator(double Latitude, double Longitude, double *Easting, double *Northing) const
const double & getA() const
double lonr() const
Returns the longitude in radian measure.
Definition: ossimGpt.h:76
double toDouble() const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
void setFalseEastingNorthing(double falseEasting, double falseNorthing)
double x
Definition: ossimDpt.h:164
#define PI
double latr() const
latr().
Definition: ossimGpt.h:66
void setFalseNorthing(double falseNorthing)
void setFalseEasting(double falseEasting)
const double & getFlattening() const
ossimEllipsoid theEllipsoid
This method verifies that the projection parameters match the current pcs code.
long Convert_Mercator_To_Geodetic(double Easting, double Northing, double *Latitude, double *Longitude) const
static const char * SCALE_FACTOR_KW
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
ossimDpt theFalseEastingNorthing
Hold the false easting northing.
virtual ossimGpt inverse(const ossimDpt &eastingNorthing) const
Will take a point in meters and convert it to ground.
ossimMercatorProjection(const ossimEllipsoid &ellipsoid=ossimEllipsoid(), const ossimGpt &origin=ossimGpt())
void makeNan()
Definition: ossimDpt.h:65
#define MERC_LAT_ERROR
const ossimDatum * theDatum
This is only set if we want to have built in datum shifting.