Isis 3 Programmer Reference
LambertConformal.cpp
Go to the documentation of this file.
1 
23 #include "LambertConformal.h"
24 
25 #include <cmath>
26 #include <cfloat>
27 
28 #include "Constants.h"
29 #include "IException.h"
30 #include "IString.h"
31 #include "Projection.h"
32 #include "Pvl.h"
33 #include "PvlGroup.h"
34 #include "PvlKeyword.h"
35 
36 using namespace std;
37 namespace Isis {
57  LambertConformal::LambertConformal(Pvl &label, bool allowDefaults) :
58  TProjection::TProjection(label) {
59  try {
60  // Try to read the mapping group
61  PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
62 
63  // Compute and write the default center longitude if allowed and
64  // necessary
65  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) {
66  double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0;
67  mapGroup += PvlKeyword("CenterLongitude", toString(lon));
68  }
69 
70  // Compute and write the default center latitude if allowed and
71  // necessary
72  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) {
73  double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0;
74  mapGroup += PvlKeyword("CenterLatitude", toString(lat));
75  }
76 
77  // Get the center longitude & latitude
78  m_centerLongitude = mapGroup["CenterLongitude"];
79  m_centerLatitude = mapGroup["CenterLatitude"];
80  if (IsPlanetocentric()) {
82  }
83 
84  // Test to make sure center longitude is valid
85  if (fabs(m_centerLongitude) > 360.0) {
86  IString message = "Central Longitude [" + IString(m_centerLongitude);
87  message += "] must be between -360 and 360";
88  throw IException(IException::Unknown, message, _FILEINFO_);
89  }
90 
91  // convert to radians, adjust for longitude direction
92  m_centerLongitude *= PI / 180.0;
94 
95  // Get the standard parallels & convert them to ographic
96  m_par1 = mapGroup["FirstStandardParallel"];
97  if (IsPlanetocentric()) {
99  }
100  m_par2 = mapGroup["SecondStandardParallel"];
101  if (IsPlanetocentric()) {
103  }
104 
105  // Test to make sure standard parallels are valid
106  if (fabs(m_par1) > 90.0 || fabs(m_par2) > 90.0) {
107  QString message = "Standard Parallels must between -90 and 90";
108  throw IException(IException::Unknown, message, _FILEINFO_);
109  }
110  if (fabs(m_par1 + m_par2) < DBL_EPSILON) {
111  QString message = "Standard Parallels cannot be symmetric to the equator";
112  throw IException(IException::Unknown, message, _FILEINFO_);
113  }
114  // Removed because this test only works for northern hemisphere
115  // Just reorder the parallels so p1 is at the larger radius of the two
116  //if (m_par1 > m_par2) {
117  // QString message = "Standard Parallels must be ordered";
118  // throw IException::Message(IException::Projection,message,_FILEINFO_);
119  //}
120 
121  // Reorder the parallels so p1 is closer to the equator than p2
122  // Therefore p2 is nearest the apex of the cone
123  if (fabs(m_par1) > fabs(m_par2)) {
124  double tmp = m_par2;
125  m_par2 = m_par1;
126  m_par1 = tmp;
127  }
128 
129  // Test to make sure center latitude is valid
130  // The pole opposite the apex can not be used as the clat (i.e., origin of
131  // the projection) it projects to infinity
132  // Given: p2 is closer to the apex than p1, and p2 must be on the same
133  // side of the equator as the apex (due to the reording of p1 and p2 above)
134  // Test for cone pointed south "v"
135  if ((m_par2 < 0.0) && (fabs(90.0 - m_centerLatitude) < DBL_EPSILON)) {
136  IString message = "Center Latitude [" + IString(m_centerLatitude);
137  message += "] is not valid, it projects to infinity "
138  "for standard parallels [";
139  message += IString(m_par1) + "," + IString(m_par2) + "]";
140  throw IException(IException::Unknown, message, _FILEINFO_);
141  }
142  // Test for cone pointed north "^"
143  else if ((m_par2 > 0.0) && (fabs(-90.0 - m_centerLatitude) < DBL_EPSILON)) {
144  IString message = "Center Latitude [" + IString(m_centerLatitude);
145  message += "] is not valid, it projects to infinity "
146  "for standard parallels [";
147  message += IString(m_par1) + "," + IString(m_par2) + "]";
148  throw IException(IException::Unknown, message, _FILEINFO_);
149  }
150  // convert clat to radians
151  m_centerLatitude *= PI / 180.0;
152 
153  // Convert standard parallels to radians
154  m_par1 *= PI / 180.0;
155  m_par2 *= PI / 180.0;
156 
157  // Compute the Snyder's m and t values for the standard parallels and the
158  // center latitude
159  double sinpar1 = sin(m_par1);
160  double cospar1 = cos(m_par1);
161  double m1 = mCompute(sinpar1, cospar1);
162  double t1 = tCompute(m_par1, sinpar1);
163 
164  double sinpar2 = sin(m_par2);
165  double cospar2 = cos(m_par2);
166  double m2 = mCompute(sinpar2, cospar2);
167  double t2 = tCompute(m_par2, sinpar2);
168 
169  double sinclat = sin(m_centerLatitude);
170  double tclat = tCompute(m_centerLatitude, sinclat);
171 
172  // Calculate Snyder's n, f, and rho
173  if (fabs(m_par1 - m_par2) >= DBL_EPSILON) {
174  m_n = log(m1 / m2) / log(t1 / t2);
175  }
176  else {
177  m_n = sinpar1;
178  }
179  m_f = m1 / (m_n * pow(t1, m_n));
180  m_rho = m_equatorialRadius * m_f * pow(tclat, m_n);
181  }
182  catch(IException &e) {
183  QString message = "Invalid label group [Mapping]";
184  throw IException(e, IException::Io, message, _FILEINFO_);
185  }
186  }
187 
190  }
191 
201  if (!Projection::operator==(proj)) return false;
202  // dont do the below it is a recusive plunge
203  // if (Projection::operator!=(proj)) return false;
204  LambertConformal *lamb = (LambertConformal *) &proj;
205  if ((lamb->m_centerLongitude != m_centerLongitude) ||
206  (lamb->m_centerLatitude != m_centerLatitude)) return false;
207  return true;
208  }
209 
215  QString LambertConformal::Name() const {
216  return "LambertConformal";
217  }
218 
225  QString LambertConformal::Version() const {
226  return "1.0";
227  }
228 
236  if (m_par1 > m_par2) return m_par2 * 180.0 / PI;
237  else return m_par1 * 180.0 / PI;
238  }
239 
252  bool LambertConformal::SetGround(const double lat, const double lon) {
253  // Convert longitude to radians & clean up
254  m_longitude = lon;
255  double lonRadians = lon * PI / 180.0;
256  if (m_longitudeDirection == PositiveWest) lonRadians *= -1.0;
257 
258  // Now convert latitude to radians & clean up ... it must be planetographic
259  m_latitude = lat;
260  double latRadians = lat;
261  if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians);
262  latRadians *= PI / 180.0;
263 
264  // Check for special cases & calculate rh, theta, and snyder t
265  double rh;
266  if (fabs(fabs(latRadians) - HALFPI) < DBL_EPSILON) {
267  // Lat/Lon point cannot be projected
268  if (latRadians *m_n <= 0.0) {
269  m_good = false;
270  return m_good;
271  }
272  else rh = 0.0;
273  }
274  else {
275  double sinlat = sin(latRadians);
276  // Lat/Lon point cannot be projected
277  double t = tCompute(latRadians, sinlat);
278  rh = m_equatorialRadius * m_f * pow(t, m_n);
279  }
280  double theta = m_n * (lonRadians - m_centerLongitude);
281 
282  // Compute the coordinate
283  double x = rh * sin(theta);
284  double y = m_rho - rh * cos(theta);
285  SetComputedXY(x, y);
286 
287  m_good = true;
288  return m_good;
289  }
290 
304  bool LambertConformal::SetCoordinate(const double x, const double y) {
305  // Save the coordinate
306  SetXY(x, y);
307 
308  // Get the sign of Snyder's n
309  double sign;
310  if (m_n >= 0) sign = 1.0;
311  else sign = -1.0;
312 
313  double temp = m_rho - GetY();
314  double rh = sign * sqrt(GetX() * GetX() + temp * temp);
315 
316  double theta;
317  if (rh != 0) theta = atan2(sign * GetX(), sign * temp);
318  else theta = 0.0;
319 
320  // Compute latitude and longitude
321  if (rh != 0 || m_n > 0) {
322  double t = pow(rh / (m_equatorialRadius * m_f), 1.0 / m_n);
323  m_latitude = phi2Compute(t);
324  }
325  else m_latitude = -HALFPI;
326  m_longitude = theta / m_n + m_centerLongitude;
327 
328 
329  // Convert to degrees
330  m_latitude *= 180.0 / PI;
331  m_longitude *= 180.0 / PI;
332 
333  // Cleanup the longitude
335  // These need to be done for circular type projections
336  // m_longitude = To360Domain (m_longitude);
337  // if (m_longitudeDomain == 180) m_longitude = To180Domain(m_longitude);
338 
339  // Cleanup the latitude
341 
342  m_good = true;
343  return m_good;
344  }
345 
377  bool LambertConformal::XYRange(double &minX, double &maxX,
378  double &minY, double &maxY) {
379 
380  // Test the four corners
385 
386  // Decide which pole the apex of the cone is above
387  // Remember p1 is now closest to the equator and p2 is closest to one of the
388  // poles
389  bool north_hemi = true;
390  // Stuart Sides 2008-08-15
391  // This test was removed because the reordering of p1 and p2 in the
392  // constructor made it incorrect
393  //if (fabs(m_par1) > fabs(m_par2)) north_hemi = false;
394  if (m_par2 < 0.0) north_hemi = false;
395  if ((m_par1 == m_par2) && (m_par1 < 0.0)) north_hemi = false;
396 
397  double cLonDeg = m_centerLongitude * 180.0 / PI;
398 
399  // This is needed because the SetGround class applies the PositiveWest
400  // adjustment which was already done in the constructor.
401  if (m_longitudeDirection == PositiveWest) cLonDeg = cLonDeg * -1.0;
402 
403  double pole_north, min_lat_north, max_lat_north, londiff;
404  // North Pole
405  if (north_hemi) {
406  m_latitude = 90.0;
407  m_longitude = cLonDeg;
408 
409  //Unable to project at the pole
411  m_good = false;
412  return m_good;
413  }
414 
415  pole_north = YCoord();
417 
418  //Unable to project at the pole
420  m_good = false;
421  return m_good;
422  }
423 
424  min_lat_north = YCoord();
425  double y = min_lat_north + 2.0 * (pole_north - min_lat_north);
426 
427  //Unable to project opposite the center longitude
428  if (!SetCoordinate(XCoord(), y)) {
429  m_good = false;
430  return m_good;
431  }
432 
433  londiff = fabs(cLonDeg - m_longitude) / 2.0;
434  m_longitude = cLonDeg - londiff;
435  for (int i = 0; i < 3; i++) {
440  }
441  m_longitude += londiff;
442  }
443 
444  }
445  // South Pole
446  else {
447  m_latitude = -90.0;
448  m_longitude = cLonDeg;
449 
450  //Unable to project at the pole
452  m_good = false;
453  return m_good;
454  }
455 
456  pole_north = YCoord();
458 
459  //Unable to project at the pole
461  m_good = false;
462  return m_good;
463  }
464 
465  max_lat_north = YCoord();
466  double y = max_lat_north - 2.0 * (max_lat_north - pole_north);
467 
468  //Unable to project opposite the center longitude
469  if (!SetCoordinate(XCoord(), y)) {
470  m_good = false;
471  return m_good;
472  }
473 
474  londiff = fabs(cLonDeg - m_longitude) / 2.0;
475  m_longitude = cLonDeg - londiff;
476  for (int i = 0; i < 3; i++) {
481  }
482  m_longitude += londiff;
483  }
484  }
485 
486  // Make sure everything is ordered
487  if (m_minimumX >= m_maximumX) return false;
488  if (m_minimumY >= m_maximumY) return false;
489 
490  // Return X/Y min/maxs
491  minX = m_minimumX;
492  maxX = m_maximumX;
493  minY = m_minimumY;
494  maxY = m_maximumY;
495  return true;
496  }
497 
498 
505  PvlGroup mapping = TProjection::Mapping();
506 
507  mapping += m_mappingGrp["CenterLatitude"];
508  mapping += m_mappingGrp["CenterLongitude"];
509  mapping += m_mappingGrp["FirstStandardParallel"];
510  mapping += m_mappingGrp["SecondStandardParallel"];
511 
512  return mapping;
513  }
514 
522 
523  mapping += m_mappingGrp["CenterLatitude"];
524  mapping += m_mappingGrp["FirstStandardParallel"];
525  mapping += m_mappingGrp["SecondStandardParallel"];
526 
527  return mapping;
528  }
529 
537 
538  mapping += m_mappingGrp["CenterLongitude"];
539 
540  return mapping;
541  }
542 } // end namespace isis
543 
558  bool allowDefaults) {
559  return new Isis::LambertConformal(lab, allowDefaults);
560 }
561 
double m_par1
The first standard parallel.
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
double m_centerLongitude
The center longitude for the map projection.
QString Version() const
Returns the version of the map projection.
double mCompute(const double sinphi, const double cosphi) const
A convience method to compute Snyder&#39;s m equation (14-15) for a given latitude, . ...
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
double tCompute(const double phi, const double sinphi) const
A convience method to compute Snyder&#39;s t equation (15-9) for a given latitude, .
Isis::Projection * LambertConformalPlugin(Isis::Pvl &lab, bool allowDefaults)
This is the function that is called in order to instantiate a LambertConformal object.
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
const double HALFPI
The mathematical constant PI/2.
Definition: Constants.h:57
Namespace for the standard library.
double m_f
Snyder&#39;s f variable.
Search child objects.
Definition: PvlObject.h:170
double GetX() const
Calculates the unrotated form of current x value.
Definition: Projection.cpp:833
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround, or SetWorld returned with success.
Definition: Projection.cpp:402
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
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_par2
The second standard parallel.
double m_minimumLatitude
Contains the minimum latitude for the entire ground range.
Definition: TProjection.h:370
~LambertConformal()
Destroys the LambertConformal object.
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.
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_equatorialRadius
Polar radius of the target.
Definition: TProjection.h:351
double m_rho
Snyder&#39;s rho variable.
QString Name() const
Returns the name of the map projection, "LambertConformal".
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
A single keyword-value pair.
Definition: PvlKeyword.h:98
bool operator==(const Projection &proj)
Compares two Projection objects to see if they are equal.
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:134
double YCoord() const
This returns the projection Y provided SetGround, SetCoordinate, SetUniversalGround, or SetWorld returned with success.
Definition: Projection.cpp:415
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.
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 phi2Compute(const double t) const
A convience method to compute latitude angle phi2 given small t, from Syder&#39;s recursive equation (7-9...
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
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Lambert Conformal 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
PvlGroup Mapping()
This function returns the keywords that this projection uses.
Adds specific functionality to C++ strings.
Definition: IString.h:181
double TrueScaleLatitude() const
Returns the latitude of true scale (in the case of LambertConformal it is the smaller of the two stan...
double m_n
Snyder&#39;s n variable.
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
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.
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
void XYRangeCheck(const double latitude, const double longitude)
This convience function is established to assist in the development of the XYRange virtual method...
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
double m_minimumLongitude
Contains the minimum longitude for the entire ground range.
Definition: TProjection.h:374
double m_centerLatitude
The center latitude for the map projection.
double m_maximumX
See minimumX description.
Definition: Projection.h:342
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition: Projection.h:345