Isis 3 Programmer Reference
TransverseMercator.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "TransverseMercator.h"
8 
9 #include <cmath>
10 #include <cfloat>
11 
12 #include "Constants.h"
13 #include "IException.h"
14 #include "TProjection.h"
15 #include "Pvl.h"
16 #include "PvlGroup.h"
17 #include "PvlKeyword.h"
18 
19 using namespace std;
20 namespace Isis {
39  TransverseMercator::TransverseMercator(Pvl &label, bool allowDefaults) :
40  TProjection::TProjection(label) {
41  try {
42  // Try to read the mapping group
43  PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
44 
45  // Compute and write the default center longitude if allowed and
46  // necessary
47  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) {
48  double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0;
49  mapGroup += PvlKeyword("CenterLongitude", toString(lon));
50  }
51 
52  // Compute and write the default center latitude if allowed and
53  // necessary
54  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) {
55  double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0;
56  mapGroup += PvlKeyword("CenterLatitude", toString(lat));
57  }
58 
59  // Get the center longitude & latitude
60  m_centerLongitude = mapGroup["CenterLongitude"];
61  m_centerLatitude = mapGroup["CenterLatitude"];
62 
63  // make sure the center latitude value is valid
64  if (fabs(m_centerLatitude) >= 90.0) {
65  string msg = "Invalid Center Latitude Value. Must be between -90 and 90";
66  throw IException(IException::Io, msg, _FILEINFO_);
67  }
68 
69  // make sure the center longitude value is valid
70  if (fabs(m_centerLongitude) > 360.0) {
71  string msg = "Invalid Center Longitude Value. Must be between -360 and 360";
72  throw IException(IException::Io, msg, _FILEINFO_);
73  }
74 
75  // convert latitude to planetographic if it is planetocentric
76  if (IsPlanetocentric()) {
78  }
79 
80  // convert to radians and adjust for longitude direction
82  m_centerLatitude *= PI / 180.0;
83  m_centerLongitude *= PI / 180.0;
84 
85  // Compute other necessary variables. See Snyder, page 61
87  m_esp = m_eccsq;
88  m_e0 = 1.0 - 0.25 * m_eccsq * (1.0 + m_eccsq / 16.0 * (3.0 + 1.25 * m_eccsq));
89  m_e1 = 0.375 * m_eccsq * (1.0 + 0.25 * m_eccsq * (1.0 + 0.468750 * m_eccsq));
90  m_e2 = 0.058593750 * m_eccsq * m_eccsq * (1.0 + 0.750 * m_eccsq);
91  m_e3 = m_eccsq * m_eccsq * m_eccsq * (35.0 / 3072.0);
93  m_e2 * sin(4.0 * m_centerLatitude) - m_e3 * sin(6.0 * m_centerLatitude));
94 
95  // Set flag for sphere or ellipsiod
96  m_sph = true; // Sphere
97  if (Eccentricity() >= .00001) {
98  m_sph = false; // Ellipsoid
99  m_esp = m_eccsq / (1.0 - m_eccsq);
100  }
101 
102  // Get the scale factor
103  if ((allowDefaults) && (!mapGroup.hasKeyword("ScaleFactor"))) {
104  mapGroup += PvlKeyword("ScaleFactor", toString(1.0));
105  }
106  m_scalefactor = mapGroup["ScaleFactor"];
107  }
108  catch(IException &e) {
109  string message = "Invalid label group [Mapping]";
110  throw IException(e, IException::Io, message, _FILEINFO_);
111  }
112  }
113 
116  }
117 
127  if (!Projection::operator==(proj)) return false;
128  // dont do the below it is a recusive plunge
129  // if (Projection::operator!=(proj)) return false;
130  TransverseMercator *trans = (TransverseMercator *) &proj;
131  if ((trans->m_centerLongitude != m_centerLongitude) ||
132  (trans->m_centerLatitude != m_centerLatitude)) return false;
133  return true;
134  }
135 
141  QString TransverseMercator::Name() const {
142  return "TransverseMercator";
143  }
144 
151  QString TransverseMercator::Version() const {
152  return "1.0";
153  }
154 
167  bool TransverseMercator::SetGround(const double lat, const double lon) {
168  // Get longitude & fix direction
169  m_longitude = lon;
171 
172  double cLonDeg = m_centerLongitude * 180.0 / PI;
173  double deltaLon = m_longitude - cLonDeg;
174  while(deltaLon < -360.0) deltaLon += 360.0;
175  while(deltaLon > 360.0) deltaLon -= 360.0;
176  double deltaLonRads = deltaLon * PI / 180.0;
177 
178  // Now convert latitude to radians & clean up ... it must be planetographic
179  m_latitude = lat;
180  double latRadians = m_latitude * PI / 180.0;
181  if (IsPlanetocentric()) {
182  latRadians = ToPlanetographic(m_latitude) * PI / 180.0;
183  }
184 
185  // distance along the meridian fromthe Equator to the latitude phi
186  // see equation (3-21) on pages 61, 17.
187  double M = m_equatorialRadius * (m_e0 * latRadians
188  - m_e1 * sin(2.0 * latRadians)
189  + m_e2 * sin(4.0 * latRadians)
190  - m_e3 * sin(6.0 * latRadians));
191 
192  // Declare variables
193  const double epsilon = 1.0e-10;
194 
195  // Sphere Conversion
196  double x, y;
197  if (m_sph) {
198  double cosphi = cos(latRadians);
199  double b = cosphi * sin(deltaLonRads);
200 
201  // Point projects to infinity
202  if (fabs(fabs(b) - 1.0) <= epsilon) {
203  m_good = false;
204  return m_good;
205  }
206  x = 0.5 * m_equatorialRadius * m_scalefactor * log((1.0 + b) / (1.0 - b));
207 
208  // If arcosine argument is too close to 1, con=0.0 because arcosine(1)=0
209  double con = cosphi * cos(deltaLonRads) / sqrt(1.0 - b * b);
210  if (fabs(con) > 1.0) {
211  con = 0.0;
212  }
213  else {
214  con = acos(con);
215  }
216  if (m_latitude < 0.0) con = -con;
218  }
219 
220  // Ellipsoid Conversion
221  else {
222  if (fabs(HALFPI - fabs(latRadians)) < epsilon) {
223  x = 0.0;
224  y = m_scalefactor * (M - m_ml0);
225  }
226  else {
227  // Define Snyder's variables for ellipsoidal projections, page61
228  double sinphi = sin(latRadians);
229  double cosphi = cos(latRadians);
230  double A = cosphi * deltaLonRads; // see equation (8-15), page 61
231  double Asquared = A * A;
232  double C = m_esp * cosphi * cosphi; // see equation (8-14), page 61
233  double tanphi = tan(latRadians);
234  double T = tanphi * tanphi; // see equation (8-13), page 61
235  double N = m_equatorialRadius / sqrt(1.0 - m_eccsq * sinphi * sinphi);
236  // see equation (4-20), page 61
237 
238  x = m_scalefactor * N * A
239  * (1.0 + Asquared / 6.0 * (1.0 - T + C + Asquared / 20.0
240  *(5.0 - 18.0*T + T*T + 72.0*C - 58.0*m_esp)));
241  y = m_scalefactor
242  * (M - m_ml0 + N*tanphi*(Asquared * (0.5 + Asquared / 24.0 *
243  (5.0 - T + 9.0*C + 4.0*C*C + Asquared / 30.0
244  *(61.0 - 58.0*T + T*T + 600.0*C - 330.0*m_esp)))));
245  }
246  }
247 
248  SetComputedXY(x, y);
249  m_good = true;
250  return m_good;
251  }
252 
266  bool TransverseMercator::SetCoordinate(const double x, const double y) {
267  // Save the coordinate
268  SetXY(x, y);
269 
270  // Declare & Initialize variables
271  double f, g, h, temp, con, phi, dphi, sinphi, cosphi, tanphi;
272  double c, cs, t, ts, n, rp, d, ds;
273  const double epsilon = 1.0e-10;
274 
275  // Sphere Conversion
276  if (m_sph) {
277  f = exp(GetX() / (m_equatorialRadius * m_scalefactor));
278  g = 0.5 * (f - 1.0 / f);
280  h = cos(temp);
281  con = sqrt((1.0 - h * h) / (1.0 + g * g));
282  if (con > 1.0) con = 1.0;
283  if (con < -1.0) con = -1.0;
284  m_latitude = asin(con);
285  if (temp < 0.0) m_latitude = -m_latitude;
287  if (g != 0.0 || h != 0.0) {
288  m_longitude = atan2(g, h) + m_centerLongitude;
289  }
290  }
291 
292  // Ellipsoid Conversion
293  else if (!m_sph) {
294  con = (m_ml0 + GetY() / m_scalefactor) / m_equatorialRadius;
295  phi = con;
296  for (int i = 1; i < 7; i++) {
297  dphi = ((con + m_e1 * sin(2.0 * phi) - m_e2 * sin(4.0 * phi)
298  + m_e3 * sin(6.0 * phi)) / m_e0) - phi;
299  phi += dphi;
300  if (fabs(dphi) <= epsilon) break;
301  }
302 
303  // Didn't converge
304  if (fabs(dphi) > epsilon) {
305  m_good = false;
306  return m_good;
307  }
308  if (fabs(phi) >= HALFPI) {
309  if (GetY() >= 0.0) m_latitude = fabs(HALFPI);
310  if (GetY() < 0.0) m_latitude = - fabs(HALFPI);
312  }
313  else {
314  sinphi = sin(phi);
315  cosphi = cos(phi);
316  tanphi = tan(phi);
317  c = m_esp * cosphi * cosphi;
318  cs = c * c;
319  t = tanphi * tanphi;
320  ts = t * t;
321  con = 1.0 - m_eccsq * sinphi * sinphi;
322  n = m_equatorialRadius / sqrt(con);
323  rp = n * (1.0 - m_eccsq) / con;
324  d = GetX() / (n * m_scalefactor);
325  ds = d * d;
326  m_latitude = phi - (n * tanphi * ds / rp) * (0.5 - ds /
327  24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 *
328  m_esp - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c +
329  45.0 * ts - 252.0 * m_esp - 3.0 * cs)));
330 
331 
332  // Latitude cannot be greater than + or - halfpi radians (or 90 degrees)
333  if (fabs(m_latitude) > HALFPI) {
334  m_good = false;
335  return m_good;
336  }
338  + (d * (1.0 - ds / 6.0 *
339  (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c +
340  28.0 * t - 3.0 * cs + 8.0 * m_esp + 24.0 * ts))) / cosphi);
341  }
342  }
343 
344  // Convert to Degrees
345  m_latitude *= 180.0 / PI;
346  m_longitude *= 180.0 / PI;
347 
348  // Cleanup the longitude
350  // These need to be done for circular type projections
353 
354  // Cleanup the latitude
356 
357  m_good = true;
358  return m_good;
359  }
360 
384  bool TransverseMercator::XYRange(double &minX, double &maxX,
385  double &minY, double &maxY) {
386  // Check the corners of the lat/lon range
391 
392  // convert center latitude to degrees & test
393  double clat = m_centerLatitude * 180.0 / PI;
394 
395  if (clat > m_minimumLatitude &&
396  clat < m_maximumLatitude) {
399  }
400 
401  // convert center longitude to degrees & test
402  double clon = m_centerLongitude * 180.0 / PI;
403  if (clon > m_minimumLongitude &&
404  clon < m_maximumLongitude) {
407  }
408 
409  // Make sure everything is ordered
410  if (m_minimumX >= m_maximumX) return false;
411  if (m_minimumY >= m_maximumY) return false;
412 
413  // Return X/Y min/maxs
414  minX = m_minimumX;
415  maxX = m_maximumX;
416  minY = m_minimumY;
417  maxY = m_maximumY;
418  return true;
419  }
420 
421 
428  PvlGroup mapping = TProjection::Mapping();
429 
430  mapping += m_mappingGrp["CenterLatitude"];
431  mapping += m_mappingGrp["CenterLongitude"];
432  mapping += m_mappingGrp["ScaleFactor"];
433 
434  return mapping;
435  }
436 
444 
445  mapping += m_mappingGrp["CenterLatitude"];
446 
447  return mapping;
448  }
449 
457 
458  mapping += m_mappingGrp["CenterLongitude"];
459 
460  return mapping;
461  }
462 } // end namespace isis
463 
478 extern "C" Isis::Projection *TransverseMercatorPlugin(Isis::Pvl &lab,
479  bool allowDefaults) {
480  return new Isis::TransverseMercator(lab, allowDefaults);
481 }
482 
483 
Isis::TProjection::m_maximumLatitude
double m_maximumLatitude
Contains the maximum latitude for the entire ground range.
Definition: TProjection.h:356
Isis::HALFPI
const double HALFPI
The mathematical constant PI/2.
Definition: Constants.h:41
Isis::TProjection::m_longitude
double m_longitude
This contains the currently set longitude value.
Definition: TProjection.h:318
Isis::TProjection::m_longitudeDomain
int m_longitudeDomain
This integer is either 180 or 360 and is read from the labels.
Definition: TProjection.h:331
Isis::PvlObject::findGroup
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:129
Isis::IException::Io
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:155
Isis::TProjection::m_minimumLongitude
double m_minimumLongitude
Contains the minimum longitude for the entire ground range.
Definition: TProjection.h:358
Isis::TProjection::m_latitude
double m_latitude
This contains the currently set latitude value.
Definition: TProjection.h:316
Isis::TransverseMercator::SetCoordinate
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
Definition: TransverseMercator.cpp:266
Isis::TransverseMercator::~TransverseMercator
~TransverseMercator()
Destroys the TransverseMercator object.
Definition: TransverseMercator.cpp:115
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::TransverseMercator::XYRange
bool XYRange(double &minX, double &maxX, double &minY, double &maxY)
This method is used to determine the x/y range which completely covers the area of interest specified...
Definition: TransverseMercator.cpp:384
Isis::TransverseMercator::m_e3
double m_e3
Eccentricity Constant: e3 = 35e^6/3072 estimates the value e3 = 35e^6/3072 + ...
Definition: TransverseMercator.h:94
Isis::TransverseMercator::m_sph
bool m_sph
Flag set to true if sphere, and false if ellipsiod.
Definition: TransverseMercator.h:98
Isis::TProjection::m_longitudeDirection
LongitudeDirection m_longitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
Definition: TProjection.h:324
Isis::TransverseMercator::Version
QString Version() const
Returns the version of the map projection.
Definition: TransverseMercator.cpp:151
Isis::TProjection::m_minimumLatitude
double m_minimumLatitude
Contains the minimum latitude for the entire ground range.
Definition: TProjection.h:354
Isis::TProjection::PositiveWest
@ PositiveWest
Longitude values increase in the westerly direction.
Definition: TProjection.h:225
Isis::Projection::m_minimumY
double m_minimumY
See minimumX description.
Definition: Projection.h:327
Isis::Projection::GetX
double GetX() const
Calculates the unrotated form of current x value.
Definition: Projection.cpp:818
Isis::PvlContainer::hasKeyword
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Definition: PvlContainer.cpp:159
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::TProjection::Eccentricity
double Eccentricity() const
This returns the eccentricity of the target,.
Definition: TProjection.cpp:304
Isis::Projection::SetXY
void SetXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:804
Isis::TransverseMercator::Name
QString Name() const
Returns the name of the map projection, "TransverseMercator".
Definition: TransverseMercator.cpp:141
Isis::TProjection::ToPlanetocentric
double ToPlanetocentric(const double lat) const
This method converts a planetographic latitude to a planetocentric latitude.
Definition: TProjection.cpp:418
Isis::TransverseMercator::m_scalefactor
double m_scalefactor
Scale Factor for the projection.
Definition: TransverseMercator.h:77
Isis::TProjection::XYRangeCheck
void XYRangeCheck(const double latitude, const double longitude)
This convience function is established to assist in the development of the XYRange virtual method.
Definition: TProjection.cpp:1062
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::Projection::m_mappingGrp
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition: Projection.h:329
Isis::Projection::GetY
double GetY() const
Calculates the unrotated form of the current y value.
Definition: Projection.cpp:829
Isis::PvlObject::Traverse
@ Traverse
Search child objects.
Definition: PvlObject.h:158
Isis::TransverseMercator::SetGround
bool SetGround(const double lat, const double lon)
This method is used to set the latitude/longitude (assumed to be of the correct LatitudeType,...
Definition: TransverseMercator.cpp:167
Isis::TransverseMercator::m_eccsq
double m_eccsq
Eccentricity Squared.
Definition: TransverseMercator.h:78
Isis::Projection::m_minimumX
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
Definition: Projection.h:317
Isis::PvlGroup
Contains multiple PvlContainers.
Definition: PvlGroup.h:41
Isis::TransverseMercator::m_e2
double m_e2
Eccentricity Constant: e2 = 15e^4/256 * (1 + 3e^2/4)) estimates the value e2 = 15e^4/256 + 45e^6/1024...
Definition: TransverseMercator.h:91
Isis::Projection::m_good
bool m_good
Indicates if the contents of m_x, m_y, m_latitude, and m_longitude are valid.
Definition: Projection.h:300
Isis::TProjection
Base class for Map TProjections.
Definition: TProjection.h:166
Isis::TransverseMercator
TransverseMercator Map Projection.
Definition: TransverseMercator.h:57
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::TransverseMercator::m_ml0
double m_ml0
Distance along the meridian from the equator to the center latitude.
Definition: TransverseMercator.h:96
Isis::TProjection::To180Domain
static double To180Domain(const double lon)
This method converts a longitude into the -180 to 180 domain.
Definition: TProjection.cpp:657
Isis::TransverseMercator::Mapping
PvlGroup Mapping()
This function returns the keywords that this projection uses.
Definition: TransverseMercator.cpp:427
Isis::TProjection::MappingLongitudes
virtual PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: TProjection.cpp:1739
Isis::TransverseMercator::m_e0
double m_e0
Eccentricity Constant: e0 = 1 - e^2/4 * (1 + 3e^2/16 * (3 + 5e^2/4)) estimates the value e0 = 1 - e^2...
Definition: TransverseMercator.h:83
Isis::Projection::SetComputedXY
void SetComputedXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:780
std
Namespace for the standard library.
Isis::TransverseMercator::m_centerLongitude
double m_centerLongitude
The center longitude for the map projection.
Definition: TransverseMercator.h:75
Isis::TransverseMercator::m_centerLatitude
double m_centerLatitude
The center latitude for the map projection.
Definition: TransverseMercator.h:76
Isis::TProjection::m_maximumLongitude
double m_maximumLongitude
Contains the maximum longitude for the entire ground range.
Definition: TProjection.h:360
Isis::TProjection::MappingLatitudes
virtual PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
Definition: TProjection.cpp:1723
Isis::TProjection::ToPlanetographic
double ToPlanetographic(const double lat) const
This method converts a planetocentric latitude to a planetographic latitude.
Definition: TProjection.cpp:463
Isis::TransverseMercator::m_esp
double m_esp
Snyder's (e')^2 variable from equation (8-12) on page.
Definition: TransverseMercator.h:79
Isis::TransverseMercator::MappingLatitudes
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
Definition: TransverseMercator.cpp:442
Isis::TProjection::Mapping
virtual PvlGroup Mapping()
This function returns the keywords that this projection uses.
Definition: TProjection.cpp:1698
Isis::TProjection::m_equatorialRadius
double m_equatorialRadius
Polar radius of the target.
Definition: TProjection.h:335
Isis::TProjection::To360Domain
static double To360Domain(const double lon)
This method converts a longitude into the 0 to 360 domain.
Definition: TProjection.cpp:675
Isis::TProjection::IsPlanetocentric
bool IsPlanetocentric() const
This indicates if the latitude type is planetocentric (as opposed to planetographic).
Definition: TProjection.cpp:392
Isis::Projection::m_maximumY
double m_maximumY
See minimumX description.
Definition: Projection.h:328
Isis::Projection
Base class for Map Projections.
Definition: Projection.h:155
Isis::Projection::m_maximumX
double m_maximumX
See minimumX description.
Definition: Projection.h:326
Isis::TransverseMercator::operator==
bool operator==(const Projection &proj)
Compares two Projection objects to see if they are equal.
Definition: TransverseMercator.cpp:126
Isis::TransverseMercator::MappingLongitudes
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: TransverseMercator.cpp:455
Isis::TransverseMercator::m_e1
double m_e1
Eccentricity Constant: e1 = 3e^2/8 * (1.0 + e^2/4 * (1.0 + 15e^2/32)) estimates the value e1 = 3e^2/8...
Definition: TransverseMercator.h:87
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16