Isis 3 Programmer Reference
TransverseMercator.cpp
Go to the documentation of this file.
1 
23 #include "TransverseMercator.h"
24 
25 #include <cmath>
26 #include <cfloat>
27 
28 #include "Constants.h"
29 #include "IException.h"
30 #include "TProjection.h"
31 #include "Pvl.h"
32 #include "PvlGroup.h"
33 #include "PvlKeyword.h"
34 
35 using namespace std;
36 namespace Isis {
55  TransverseMercator::TransverseMercator(Pvl &label, bool allowDefaults) :
56  TProjection::TProjection(label) {
57  try {
58  // Try to read the mapping group
59  PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
60 
61  // Compute and write the default center longitude if allowed and
62  // necessary
63  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) {
64  double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0;
65  mapGroup += PvlKeyword("CenterLongitude", toString(lon));
66  }
67 
68  // Compute and write the default center latitude if allowed and
69  // necessary
70  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) {
71  double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0;
72  mapGroup += PvlKeyword("CenterLatitude", toString(lat));
73  }
74 
75  // Get the center longitude & latitude
76  m_centerLongitude = mapGroup["CenterLongitude"];
77  m_centerLatitude = mapGroup["CenterLatitude"];
78 
79  // make sure the center latitude value is valid
80  if (fabs(m_centerLatitude) >= 90.0) {
81  string msg = "Invalid Center Latitude Value. Must be between -90 and 90";
83  }
84 
85  // make sure the center longitude value is valid
86  if (fabs(m_centerLongitude) > 360.0) {
87  string msg = "Invalid Center Longitude Value. Must be between -360 and 360";
89  }
90 
91  // convert latitude to planetographic if it is planetocentric
92  if (IsPlanetocentric()) {
94  }
95 
96  // convert to radians and adjust for longitude direction
98  m_centerLatitude *= PI / 180.0;
99  m_centerLongitude *= PI / 180.0;
100 
101  // Compute other necessary variables. See Snyder, page 61
103  m_esp = m_eccsq;
104  m_e0 = 1.0 - 0.25 * m_eccsq * (1.0 + m_eccsq / 16.0 * (3.0 + 1.25 * m_eccsq));
105  m_e1 = 0.375 * m_eccsq * (1.0 + 0.25 * m_eccsq * (1.0 + 0.468750 * m_eccsq));
106  m_e2 = 0.058593750 * m_eccsq * m_eccsq * (1.0 + 0.750 * m_eccsq);
107  m_e3 = m_eccsq * m_eccsq * m_eccsq * (35.0 / 3072.0);
109  m_e2 * sin(4.0 * m_centerLatitude) - m_e3 * sin(6.0 * m_centerLatitude));
110 
111  // Set flag for sphere or ellipsiod
112  m_sph = true; // Sphere
113  if (Eccentricity() >= .00001) {
114  m_sph = false; // Ellipsoid
115  m_esp = m_eccsq / (1.0 - m_eccsq);
116  }
117 
118  // Get the scale factor
119  if ((allowDefaults) && (!mapGroup.hasKeyword("ScaleFactor"))) {
120  mapGroup += PvlKeyword("ScaleFactor", toString(1.0));
121  }
122  m_scalefactor = mapGroup["ScaleFactor"];
123  }
124  catch(IException &e) {
125  string message = "Invalid label group [Mapping]";
126  throw IException(e, IException::Io, message, _FILEINFO_);
127  }
128  }
129 
132  }
133 
143  if (!Projection::operator==(proj)) return false;
144  // dont do the below it is a recusive plunge
145  // if (Projection::operator!=(proj)) return false;
146  TransverseMercator *trans = (TransverseMercator *) &proj;
147  if ((trans->m_centerLongitude != m_centerLongitude) ||
148  (trans->m_centerLatitude != m_centerLatitude)) return false;
149  return true;
150  }
151 
157  QString TransverseMercator::Name() const {
158  return "TransverseMercator";
159  }
160 
167  QString TransverseMercator::Version() const {
168  return "1.0";
169  }
170 
183  bool TransverseMercator::SetGround(const double lat, const double lon) {
184  // Get longitude & fix direction
185  m_longitude = lon;
187 
188  double cLonDeg = m_centerLongitude * 180.0 / PI;
189  double deltaLon = m_longitude - cLonDeg;
190  while(deltaLon < -360.0) deltaLon += 360.0;
191  while(deltaLon > 360.0) deltaLon -= 360.0;
192  double deltaLonRads = deltaLon * PI / 180.0;
193 
194  // Now convert latitude to radians & clean up ... it must be planetographic
195  m_latitude = lat;
196  double latRadians = m_latitude * PI / 180.0;
197  if (IsPlanetocentric()) {
198  latRadians = ToPlanetographic(m_latitude) * PI / 180.0;
199  }
200 
201  // distance along the meridian fromthe Equator to the latitude phi
202  // see equation (3-21) on pages 61, 17.
203  double M = m_equatorialRadius * (m_e0 * latRadians
204  - m_e1 * sin(2.0 * latRadians)
205  + m_e2 * sin(4.0 * latRadians)
206  - m_e3 * sin(6.0 * latRadians));
207 
208  // Declare variables
209  const double epsilon = 1.0e-10;
210 
211  // Sphere Conversion
212  double x, y;
213  if (m_sph) {
214  double cosphi = cos(latRadians);
215  double b = cosphi * sin(deltaLonRads);
216 
217  // Point projects to infinity
218  if (fabs(fabs(b) - 1.0) <= epsilon) {
219  m_good = false;
220  return m_good;
221  }
222  x = 0.5 * m_equatorialRadius * m_scalefactor * log((1.0 + b) / (1.0 - b));
223 
224  // If arcosine argument is too close to 1, con=0.0 because arcosine(1)=0
225  double con = cosphi * cos(deltaLonRads) / sqrt(1.0 - b * b);
226  if (fabs(con) > 1.0) {
227  con = 0.0;
228  }
229  else {
230  con = acos(con);
231  }
232  if (m_latitude < 0.0) con = -con;
234  }
235 
236  // Ellipsoid Conversion
237  else {
238  if (fabs(HALFPI - fabs(latRadians)) < epsilon) {
239  x = 0.0;
240  y = m_scalefactor * (M - m_ml0);
241  }
242  else {
243  // Define Snyder's variables for ellipsoidal projections, page61
244  double sinphi = sin(latRadians);
245  double cosphi = cos(latRadians);
246  double A = cosphi * deltaLonRads; // see equation (8-15), page 61
247  double Asquared = A * A;
248  double C = m_esp * cosphi * cosphi; // see equation (8-14), page 61
249  double tanphi = tan(latRadians);
250  double T = tanphi * tanphi; // see equation (8-13), page 61
251  double N = m_equatorialRadius / sqrt(1.0 - m_eccsq * sinphi * sinphi);
252  // see equation (4-20), page 61
253 
254  x = m_scalefactor * N * A
255  * (1.0 + Asquared / 6.0 * (1.0 - T + C + Asquared / 20.0
256  *(5.0 - 18.0*T + T*T + 72.0*C - 58.0*m_esp)));
257  y = m_scalefactor
258  * (M - m_ml0 + N*tanphi*(Asquared * (0.5 + Asquared / 24.0 *
259  (5.0 - T + 9.0*C + 4.0*C*C + Asquared / 30.0
260  *(61.0 - 58.0*T + T*T + 600.0*C - 330.0*m_esp)))));
261  }
262  }
263 
264  SetComputedXY(x, y);
265  m_good = true;
266  return m_good;
267  }
268 
282  bool TransverseMercator::SetCoordinate(const double x, const double y) {
283  // Save the coordinate
284  SetXY(x, y);
285 
286  // Declare & Initialize variables
287  double f, g, h, temp, con, phi, dphi, sinphi, cosphi, tanphi;
288  double c, cs, t, ts, n, rp, d, ds;
289  const double epsilon = 1.0e-10;
290 
291  // Sphere Conversion
292  if (m_sph) {
293  f = exp(GetX() / (m_equatorialRadius * m_scalefactor));
294  g = 0.5 * (f - 1.0 / f);
296  h = cos(temp);
297  con = sqrt((1.0 - h * h) / (1.0 + g * g));
298  if (con > 1.0) con = 1.0;
299  if (con < -1.0) con = -1.0;
300  m_latitude = asin(con);
301  if (temp < 0.0) m_latitude = -m_latitude;
303  if (g != 0.0 || h != 0.0) {
304  m_longitude = atan2(g, h) + m_centerLongitude;
305  }
306  }
307 
308  // Ellipsoid Conversion
309  else if (!m_sph) {
310  con = (m_ml0 + GetY() / m_scalefactor) / m_equatorialRadius;
311  phi = con;
312  for (int i = 1; i < 7; i++) {
313  dphi = ((con + m_e1 * sin(2.0 * phi) - m_e2 * sin(4.0 * phi)
314  + m_e3 * sin(6.0 * phi)) / m_e0) - phi;
315  phi += dphi;
316  if (fabs(dphi) <= epsilon) break;
317  }
318 
319  // Didn't converge
320  if (fabs(dphi) > epsilon) {
321  m_good = false;
322  return m_good;
323  }
324  if (fabs(phi) >= HALFPI) {
325  if (GetY() >= 0.0) m_latitude = fabs(HALFPI);
326  if (GetY() < 0.0) m_latitude = - fabs(HALFPI);
328  }
329  else {
330  sinphi = sin(phi);
331  cosphi = cos(phi);
332  tanphi = tan(phi);
333  c = m_esp * cosphi * cosphi;
334  cs = c * c;
335  t = tanphi * tanphi;
336  ts = t * t;
337  con = 1.0 - m_eccsq * sinphi * sinphi;
338  n = m_equatorialRadius / sqrt(con);
339  rp = n * (1.0 - m_eccsq) / con;
340  d = GetX() / (n * m_scalefactor);
341  ds = d * d;
342  m_latitude = phi - (n * tanphi * ds / rp) * (0.5 - ds /
343  24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 *
344  m_esp - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c +
345  45.0 * ts - 252.0 * m_esp - 3.0 * cs)));
346 
347 
348  // Latitude cannot be greater than + or - halfpi radians (or 90 degrees)
349  if (fabs(m_latitude) > HALFPI) {
350  m_good = false;
351  return m_good;
352  }
354  + (d * (1.0 - ds / 6.0 *
355  (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c +
356  28.0 * t - 3.0 * cs + 8.0 * m_esp + 24.0 * ts))) / cosphi);
357  }
358  }
359 
360  // Convert to Degrees
361  m_latitude *= 180.0 / PI;
362  m_longitude *= 180.0 / PI;
363 
364  // Cleanup the longitude
366  // These need to be done for circular type projections
369 
370  // Cleanup the latitude
372 
373  m_good = true;
374  return m_good;
375  }
376 
400  bool TransverseMercator::XYRange(double &minX, double &maxX,
401  double &minY, double &maxY) {
402  // Check the corners of the lat/lon range
407 
408  // convert center latitude to degrees & test
409  double clat = m_centerLatitude * 180.0 / PI;
410 
411  if (clat > m_minimumLatitude &&
412  clat < m_maximumLatitude) {
415  }
416 
417  // convert center longitude to degrees & test
418  double clon = m_centerLongitude * 180.0 / PI;
419  if (clon > m_minimumLongitude &&
420  clon < m_maximumLongitude) {
423  }
424 
425  // Make sure everything is ordered
426  if (m_minimumX >= m_maximumX) return false;
427  if (m_minimumY >= m_maximumY) return false;
428 
429  // Return X/Y min/maxs
430  minX = m_minimumX;
431  maxX = m_maximumX;
432  minY = m_minimumY;
433  maxY = m_maximumY;
434  return true;
435  }
436 
437 
444  PvlGroup mapping = TProjection::Mapping();
445 
446  mapping += m_mappingGrp["CenterLatitude"];
447  mapping += m_mappingGrp["CenterLongitude"];
448  mapping += m_mappingGrp["ScaleFactor"];
449 
450  return mapping;
451  }
452 
460 
461  mapping += m_mappingGrp["CenterLatitude"];
462 
463  return mapping;
464  }
465 
473 
474  mapping += m_mappingGrp["CenterLongitude"];
475 
476  return mapping;
477  }
478 } // end namespace isis
479 
495  bool allowDefaults) {
496  return new Isis::TransverseMercator(lab, allowDefaults);
497 }
498 
499 
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
bool m_sph
Flag set to true if sphere, and false if ellipsiod.
const double PI
The mathematical constant PI.
Definition: Constants.h:56
Longitude values increase in the westerly direction.
Definition: TProjection.h:241
Base class for Map TProjections.
Definition: TProjection.h:182
double m_e3
Eccentricity Constant: e3 = 35e^6/3072 estimates the value e3 = 35e^6/3072 + ...
QString Version() const
Returns the version of the map projection.
const double HALFPI
The mathematical constant PI/2.
Definition: Constants.h:57
Namespace for the standard library.
double m_scalefactor
Scale Factor for the projection.
Search child objects.
Definition: PvlObject.h:170
double GetX() const
Calculates the unrotated form of current x value.
Definition: Projection.cpp:833
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...
double m_minimumX
The data elements m_minimumX, m_minimumY, m_maximumX, and m_maximumY are convience data elements when...
Definition: Projection.h:333
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:226
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:171
void SetComputedXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:795
double m_latitude
This contains the currently set latitude value.
Definition: TProjection.h:332
virtual PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
double m_maximumY
See minimumX description.
Definition: Projection.h:344
double m_longitude
This contains the currently set longitude value.
Definition: TProjection.h:334
Isis::Projection * TransverseMercatorPlugin(Isis::Pvl &lab, bool allowDefaults)
This is the function that is called in order to instantiate a TransverseMercator object.
bool IsPlanetocentric() const
This indicates if the latitude type is planetocentric (as opposed to planetographic).
double m_maximumLongitude
Contains the maximum longitude for the entire ground range.
Definition: TProjection.h:376
double m_eccsq
Eccentricity Squared.
double m_minimumLatitude
Contains the minimum latitude for the entire ground range.
Definition: TProjection.h:370
QString Name() const
Returns the name of the map projection, "TransverseMercator".
double m_maximumLatitude
Contains the maximum latitude for the entire ground range.
Definition: TProjection.h:372
Base class for Map Projections.
Definition: Projection.h:171
double m_minimumY
See minimumX description.
Definition: Projection.h:343
double m_e2
Eccentricity Constant: e2 = 15e^4/256 * (1 + 3e^2/4)) estimates the value e2 = 15e^4/256 + 45e^6/1024...
double Eccentricity() const
This returns the eccentricity of the target,.
double m_equatorialRadius
Polar radius of the target.
Definition: TProjection.h:351
int m_longitudeDomain
This integer is either 180 or 360 and is read from the labels.
Definition: TProjection.h:347
static double To180Domain(const double lon)
This method converts a longitude into the -180 to 180 domain.
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
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...
A single keyword-value pair.
Definition: PvlKeyword.h:98
bool SetGround(const double lat, const double lon)
This method is used to set the latitude/longitude (assumed to be of the correct LatitudeType, LongitudeDirection, and LongitudeDomain.
TransverseMercator Map Projection.
Container for cube-like labels.
Definition: Pvl.h:135
double ToPlanetographic(const double lat) const
This method converts a planetocentric latitude to a planetographic latitude.
virtual PvlGroup Mapping()
This function returns the keywords that this projection uses.
bool m_good
Indicates if the contents of m_x, m_y, m_latitude, and m_longitude are valid.
Definition: Projection.h:316
static double To360Domain(const double lon)
This method converts a longitude into the 0 to 360 domain.
double m_ml0
Distance along the meridian from the equator to the center latitude.
double m_centerLongitude
The center longitude for the map projection.
LongitudeDirection m_longitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
Definition: TProjection.h:340
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
double m_centerLatitude
The center latitude for the map projection.
PvlGroup Mapping()
This function returns the keywords that this projection uses.
double GetY() const
Calculates the unrotated form of the current y value.
Definition: Projection.cpp:844
double ToPlanetocentric(const double lat) const
This method converts a planetographic latitude to a planetocentric latitude.
double m_esp
Snyder&#39;s (e&#39;)^2 variable from equation (8-12) on page.
virtual PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
void SetXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:819
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
void XYRangeCheck(const double latitude, const double longitude)
This convience function is established to assist in the development of the XYRange virtual method...
double m_minimumLongitude
Contains the minimum longitude for the entire ground range.
Definition: TProjection.h:374
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...
double m_maximumX
See minimumX description.
Definition: Projection.h:342
~TransverseMercator()
Destroys the TransverseMercator object.
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition: Projection.h:345
bool operator==(const Projection &proj)
Compares two Projection objects to see if they are equal.