Isis 3 Programmer Reference
LambertConformal.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "LambertConformal.h"
8 
9 #include <cmath>
10 #include <cfloat>
11 
12 #include "Constants.h"
13 #include "IException.h"
14 #include "IString.h"
15 #include "Projection.h"
16 #include "Pvl.h"
17 #include "PvlGroup.h"
18 #include "PvlKeyword.h"
19 
20 using namespace std;
21 namespace Isis {
41  LambertConformal::LambertConformal(Pvl &label, bool allowDefaults) :
42  TProjection::TProjection(label) {
43  try {
44  // Try to read the mapping group
45  PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
46 
47  // Compute and write the default center longitude if allowed and
48  // necessary
49  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) {
50  double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0;
51  mapGroup += PvlKeyword("CenterLongitude", toString(lon));
52  }
53 
54  // Compute and write the default center latitude if allowed and
55  // necessary
56  if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) {
57  double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0;
58  mapGroup += PvlKeyword("CenterLatitude", toString(lat));
59  }
60 
61  // Get the center longitude & latitude
62  m_centerLongitude = mapGroup["CenterLongitude"];
63  m_centerLatitude = mapGroup["CenterLatitude"];
64  if (IsPlanetocentric()) {
66  }
67 
68  // Test to make sure center longitude is valid
69  if (fabs(m_centerLongitude) > 360.0) {
70  IString message = "Central Longitude [" + IString(m_centerLongitude);
71  message += "] must be between -360 and 360";
72  throw IException(IException::Unknown, message, _FILEINFO_);
73  }
74 
75  // convert to radians, adjust for longitude direction
76  m_centerLongitude *= PI / 180.0;
78 
79  // Get the standard parallels & convert them to ographic
80  m_par1 = mapGroup["FirstStandardParallel"];
81  if (IsPlanetocentric()) {
83  }
84  m_par2 = mapGroup["SecondStandardParallel"];
85  if (IsPlanetocentric()) {
87  }
88 
89  // Test to make sure standard parallels are valid
90  if (fabs(m_par1) > 90.0 || fabs(m_par2) > 90.0) {
91  QString message = "Standard Parallels must between -90 and 90";
92  throw IException(IException::Unknown, message, _FILEINFO_);
93  }
94  if (fabs(m_par1 + m_par2) < DBL_EPSILON) {
95  QString message = "Standard Parallels cannot be symmetric to the equator";
96  throw IException(IException::Unknown, message, _FILEINFO_);
97  }
98  // Removed because this test only works for northern hemisphere
99  // Just reorder the parallels so p1 is at the larger radius of the two
100  //if (m_par1 > m_par2) {
101  // QString message = "Standard Parallels must be ordered";
102  // throw IException::Message(IException::Projection,message,_FILEINFO_);
103  //}
104 
105  // Reorder the parallels so p1 is closer to the equator than p2
106  // Therefore p2 is nearest the apex of the cone
107  if (fabs(m_par1) > fabs(m_par2)) {
108  double tmp = m_par2;
109  m_par2 = m_par1;
110  m_par1 = tmp;
111  }
112 
113  // Test to make sure center latitude is valid
114  // The pole opposite the apex can not be used as the clat (i.e., origin of
115  // the projection) it projects to infinity
116  // Given: p2 is closer to the apex than p1, and p2 must be on the same
117  // side of the equator as the apex (due to the reording of p1 and p2 above)
118  // Test for cone pointed south "v"
119  if ((m_par2 < 0.0) && (fabs(90.0 - m_centerLatitude) < DBL_EPSILON)) {
120  IString message = "Center Latitude [" + IString(m_centerLatitude);
121  message += "] is not valid, it projects to infinity "
122  "for standard parallels [";
123  message += IString(m_par1) + "," + IString(m_par2) + "]";
124  throw IException(IException::Unknown, message, _FILEINFO_);
125  }
126  // Test for cone pointed north "^"
127  else if ((m_par2 > 0.0) && (fabs(-90.0 - m_centerLatitude) < DBL_EPSILON)) {
128  IString message = "Center Latitude [" + IString(m_centerLatitude);
129  message += "] is not valid, it projects to infinity "
130  "for standard parallels [";
131  message += IString(m_par1) + "," + IString(m_par2) + "]";
132  throw IException(IException::Unknown, message, _FILEINFO_);
133  }
134  // convert clat to radians
135  m_centerLatitude *= PI / 180.0;
136 
137  // Convert standard parallels to radians
138  m_par1 *= PI / 180.0;
139  m_par2 *= PI / 180.0;
140 
141  // Compute the Snyder's m and t values for the standard parallels and the
142  // center latitude
143  double sinpar1 = sin(m_par1);
144  double cospar1 = cos(m_par1);
145  double m1 = mCompute(sinpar1, cospar1);
146  double t1 = tCompute(m_par1, sinpar1);
147 
148  double sinpar2 = sin(m_par2);
149  double cospar2 = cos(m_par2);
150  double m2 = mCompute(sinpar2, cospar2);
151  double t2 = tCompute(m_par2, sinpar2);
152 
153  double sinclat = sin(m_centerLatitude);
154  double tclat = tCompute(m_centerLatitude, sinclat);
155 
156  // Calculate Snyder's n, f, and rho
157  if (fabs(m_par1 - m_par2) >= DBL_EPSILON) {
158  m_n = log(m1 / m2) / log(t1 / t2);
159  }
160  else {
161  m_n = sinpar1;
162  }
163  m_f = m1 / (m_n * pow(t1, m_n));
164  m_rho = m_equatorialRadius * m_f * pow(tclat, m_n);
165  }
166  catch(IException &e) {
167  QString message = "Invalid label group [Mapping]";
168  throw IException(e, IException::Io, message, _FILEINFO_);
169  }
170  }
171 
174  }
175 
185  if (!Projection::operator==(proj)) return false;
186  // dont do the below it is a recusive plunge
187  // if (Projection::operator!=(proj)) return false;
188  LambertConformal *lamb = (LambertConformal *) &proj;
189  if ((lamb->m_centerLongitude != m_centerLongitude) ||
190  (lamb->m_centerLatitude != m_centerLatitude)) return false;
191  return true;
192  }
193 
199  QString LambertConformal::Name() const {
200  return "LambertConformal";
201  }
202 
209  QString LambertConformal::Version() const {
210  return "1.0";
211  }
212 
220  if (m_par1 > m_par2) return m_par2 * 180.0 / PI;
221  else return m_par1 * 180.0 / PI;
222  }
223 
236  bool LambertConformal::SetGround(const double lat, const double lon) {
237  // Convert longitude to radians & clean up
238  m_longitude = lon;
239  double lonRadians = lon * PI / 180.0;
240  if (m_longitudeDirection == PositiveWest) lonRadians *= -1.0;
241 
242  // Now convert latitude to radians & clean up ... it must be planetographic
243  m_latitude = lat;
244  double latRadians = lat;
245  if (IsPlanetocentric()) latRadians = ToPlanetographic(latRadians);
246  latRadians *= PI / 180.0;
247 
248  // Check for special cases & calculate rh, theta, and snyder t
249  double rh;
250  if (fabs(fabs(latRadians) - HALFPI) < DBL_EPSILON) {
251  // Lat/Lon point cannot be projected
252  if (latRadians *m_n <= 0.0) {
253  m_good = false;
254  return m_good;
255  }
256  else rh = 0.0;
257  }
258  else {
259  double sinlat = sin(latRadians);
260  // Lat/Lon point cannot be projected
261  double t = tCompute(latRadians, sinlat);
262  rh = m_equatorialRadius * m_f * pow(t, m_n);
263  }
264  double theta = m_n * (lonRadians - m_centerLongitude);
265 
266  // Compute the coordinate
267  double x = rh * sin(theta);
268  double y = m_rho - rh * cos(theta);
269  SetComputedXY(x, y);
270 
271  m_good = true;
272  return m_good;
273  }
274 
288  bool LambertConformal::SetCoordinate(const double x, const double y) {
289  // Save the coordinate
290  SetXY(x, y);
291 
292  // Get the sign of Snyder's n
293  double sign;
294  if (m_n >= 0) sign = 1.0;
295  else sign = -1.0;
296 
297  double temp = m_rho - GetY();
298  double rh = sign * sqrt(GetX() * GetX() + temp * temp);
299 
300  double theta;
301  if (rh != 0) theta = atan2(sign * GetX(), sign * temp);
302  else theta = 0.0;
303 
304  // Compute latitude and longitude
305  if (rh != 0 || m_n > 0) {
306  double t = pow(rh / (m_equatorialRadius * m_f), 1.0 / m_n);
307  m_latitude = phi2Compute(t);
308  }
309  else m_latitude = -HALFPI;
310  m_longitude = theta / m_n + m_centerLongitude;
311 
312 
313  // Convert to degrees
314  m_latitude *= 180.0 / PI;
315  m_longitude *= 180.0 / PI;
316 
317  // Cleanup the longitude
319  // These need to be done for circular type projections
320  // m_longitude = To360Domain (m_longitude);
321  // if (m_longitudeDomain == 180) m_longitude = To180Domain(m_longitude);
322 
323  // Cleanup the latitude
325 
326  m_good = true;
327  return m_good;
328  }
329 
361  bool LambertConformal::XYRange(double &minX, double &maxX,
362  double &minY, double &maxY) {
363 
364  // Test the four corners
369 
370  // Decide which pole the apex of the cone is above
371  // Remember p1 is now closest to the equator and p2 is closest to one of the
372  // poles
373  bool north_hemi = true;
374  // Stuart Sides 2008-08-15
375  // This test was removed because the reordering of p1 and p2 in the
376  // constructor made it incorrect
377  //if (fabs(m_par1) > fabs(m_par2)) north_hemi = false;
378  if (m_par2 < 0.0) north_hemi = false;
379  if ((m_par1 == m_par2) && (m_par1 < 0.0)) north_hemi = false;
380 
381  double cLonDeg = m_centerLongitude * 180.0 / PI;
382 
383  // This is needed because the SetGround class applies the PositiveWest
384  // adjustment which was already done in the constructor.
385  if (m_longitudeDirection == PositiveWest) cLonDeg = cLonDeg * -1.0;
386 
387  double pole_north, min_lat_north, max_lat_north, londiff;
388  // North Pole
389  if (north_hemi) {
390  m_latitude = 90.0;
391  m_longitude = cLonDeg;
392 
393  //Unable to project at the pole
395  m_good = false;
396  return m_good;
397  }
398 
399  pole_north = YCoord();
401 
402  //Unable to project at the pole
404  m_good = false;
405  return m_good;
406  }
407 
408  min_lat_north = YCoord();
409  double y = min_lat_north + 2.0 * (pole_north - min_lat_north);
410 
411  //Unable to project opposite the center longitude
412  if (!SetCoordinate(XCoord(), y)) {
413  m_good = false;
414  return m_good;
415  }
416 
417  londiff = fabs(cLonDeg - m_longitude) / 2.0;
418  m_longitude = cLonDeg - londiff;
419  for (int i = 0; i < 3; i++) {
424  }
425  m_longitude += londiff;
426  }
427 
428  }
429  // South Pole
430  else {
431  m_latitude = -90.0;
432  m_longitude = cLonDeg;
433 
434  //Unable to project at the pole
436  m_good = false;
437  return m_good;
438  }
439 
440  pole_north = YCoord();
442 
443  //Unable to project at the pole
445  m_good = false;
446  return m_good;
447  }
448 
449  max_lat_north = YCoord();
450  double y = max_lat_north - 2.0 * (max_lat_north - pole_north);
451 
452  //Unable to project opposite the center longitude
453  if (!SetCoordinate(XCoord(), y)) {
454  m_good = false;
455  return m_good;
456  }
457 
458  londiff = fabs(cLonDeg - m_longitude) / 2.0;
459  m_longitude = cLonDeg - londiff;
460  for (int i = 0; i < 3; i++) {
465  }
466  m_longitude += londiff;
467  }
468  }
469 
470  // Make sure everything is ordered
471  if (m_minimumX >= m_maximumX) return false;
472  if (m_minimumY >= m_maximumY) return false;
473 
474  // Return X/Y min/maxs
475  minX = m_minimumX;
476  maxX = m_maximumX;
477  minY = m_minimumY;
478  maxY = m_maximumY;
479  return true;
480  }
481 
482 
489  PvlGroup mapping = TProjection::Mapping();
490 
491  mapping += m_mappingGrp["CenterLatitude"];
492  mapping += m_mappingGrp["CenterLongitude"];
493  mapping += m_mappingGrp["FirstStandardParallel"];
494  mapping += m_mappingGrp["SecondStandardParallel"];
495 
496  return mapping;
497  }
498 
506 
507  mapping += m_mappingGrp["CenterLatitude"];
508  mapping += m_mappingGrp["FirstStandardParallel"];
509  mapping += m_mappingGrp["SecondStandardParallel"];
510 
511  return mapping;
512  }
513 
521 
522  mapping += m_mappingGrp["CenterLongitude"];
523 
524  return mapping;
525  }
526 } // end namespace isis
527 
541 extern "C" Isis::Projection *LambertConformalPlugin(Isis::Pvl &lab,
542  bool allowDefaults) {
543  return new Isis::LambertConformal(lab, allowDefaults);
544 }
545 
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::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::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::TProjection::m_longitudeDirection
LongitudeDirection m_longitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
Definition: TProjection.h:324
Isis::TProjection::m_minimumLatitude
double m_minimumLatitude
Contains the minimum latitude for the entire ground range.
Definition: TProjection.h:354
Isis::LambertConformal::m_par1
double m_par1
The first standard parallel.
Definition: LambertConformal.h:81
Isis::TProjection::PositiveWest
@ PositiveWest
Longitude values increase in the westerly direction.
Definition: TProjection.h:225
Isis::IException::Unknown
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:118
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::LambertConformal::Version
QString Version() const
Returns the version of the map projection.
Definition: LambertConformal.cpp:209
Isis::LambertConformal::MappingLongitudes
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: LambertConformal.cpp:519
Isis::LambertConformal::Name
QString Name() const
Returns the name of the map projection, "LambertConformal".
Definition: LambertConformal.cpp:199
Isis::TProjection::tCompute
double tCompute(const double phi, const double sinphi) const
A convience method to compute Snyder's t equation (15-9) for a given latitude, .
Definition: TProjection.cpp:1870
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::Projection::SetXY
void SetXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:804
Isis::TProjection::ToPlanetocentric
double ToPlanetocentric(const double lat) const
This method converts a planetographic latitude to a planetocentric latitude.
Definition: TProjection.cpp:418
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::LambertConformal::operator==
bool operator==(const Projection &proj)
Compares two Projection objects to see if they are equal.
Definition: LambertConformal.cpp:184
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::LambertConformal::SetCoordinate
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
Definition: LambertConformal.cpp:288
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::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::LambertConformal::TrueScaleLatitude
double TrueScaleLatitude() const
Returns the latitude of true scale (in the case of LambertConformal it is the smaller of the two stan...
Definition: LambertConformal.cpp:219
Isis::TProjection
Base class for Map TProjections.
Definition: TProjection.h:166
Isis::LambertConformal::m_centerLongitude
double m_centerLongitude
The center longitude for the map projection.
Definition: LambertConformal.h:79
Isis::LambertConformal::~LambertConformal
~LambertConformal()
Destroys the LambertConformal object.
Definition: LambertConformal.cpp:173
Isis::LambertConformal::m_n
double m_n
Snyder's n variable.
Definition: LambertConformal.h:83
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::LambertConformal::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: LambertConformal.cpp:361
Isis::TProjection::MappingLongitudes
virtual PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: TProjection.cpp:1739
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::LambertConformal::MappingLatitudes
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
Definition: LambertConformal.cpp:504
Isis::LambertConformal::m_rho
double m_rho
Snyder's rho variable.
Definition: LambertConformal.h:85
Isis::LambertConformal
Lambert Conformal Map Projection.
Definition: LambertConformal.h:60
Isis::TProjection::m_maximumLongitude
double m_maximumLongitude
Contains the maximum longitude for the entire ground range.
Definition: TProjection.h:360
Isis::LambertConformal::m_f
double m_f
Snyder's f variable.
Definition: LambertConformal.h:84
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::LambertConformal::Mapping
PvlGroup Mapping()
This function returns the keywords that this projection uses.
Definition: LambertConformal.cpp:488
Isis::TProjection::phi2Compute
double phi2Compute(const double t) const
A convience method to compute latitude angle phi2 given small t, from Syder's recursive equation (7-9...
Definition: TProjection.cpp:1803
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::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::TProjection::IsPlanetocentric
bool IsPlanetocentric() const
This indicates if the latitude type is planetocentric (as opposed to planetographic).
Definition: TProjection.cpp:392
Isis::LambertConformal::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: LambertConformal.cpp:236
Isis::Projection::YCoord
double YCoord() const
This returns the projection Y provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:400
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::TProjection::mCompute
double mCompute(const double sinphi, const double cosphi) const
A convience method to compute Snyder's m equation (14-15) for a given latitude, .
Definition: TProjection.cpp:1847
Isis::Projection::XCoord
double XCoord() const
This returns the projection X provided SetGround, SetCoordinate, SetUniversalGround,...
Definition: Projection.cpp:387
Isis::LambertConformal::m_centerLatitude
double m_centerLatitude
The center latitude for the map projection.
Definition: LambertConformal.h:80
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::LambertConformal::m_par2
double m_par2
The second standard parallel.
Definition: LambertConformal.h:82