Isis 3 Programmer Reference
LambertAzimuthalEqualArea.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "LambertAzimuthalEqualArea.h"
8 
9 #include <cmath>
10 #include <cfloat>
11 
12 #include <iostream>
13 #include <iomanip>
14 
15 #include "Constants.h"
16 #include "IException.h"
17 #include "IString.h"
18 #include "TProjection.h"
19 #include "Pvl.h"
20 #include "PvlGroup.h"
21 #include "PvlKeyword.h"
22 #include "SpecialPixel.h"
23 
24 using namespace std;
25 namespace Isis {
62  LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(
63  Pvl &label,
64  bool allowDefaults) :
65  TProjection::TProjection(label) {
66  try {
67  // This algorithm can be found in the USGS Professional Paper 1395
68  // Map Projections--A Working Manual by John P. Snyder
69 
70  // Try to read the mapping group
71  PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse);
72 
73  // Compute and write the default center longitude if allowed and
74  // necessary
75  if (!mapGroup.hasKeyword("CenterLongitude")) {
76  if (allowDefaults) {
77  double centerLon = (MinimumLongitude() + MaximumLongitude()) / 2.0;
78  mapGroup += PvlKeyword("CenterLongitude", toString(centerLon), "Degrees");
79  }
80  else {
81  QString message = "Cannot project using Lambert Azimuthal equal-area";
82  message += " without [CenterLongitude] value. Keyword does not exist";
83  message += " in labels and defaults are not allowed.";
84  throw IException(IException::Unknown, message, _FILEINFO_);
85  }
86  }
87 
88  // Compute and write the default center latitude if allowed and
89  // necessary
90  if (!mapGroup.hasKeyword("CenterLatitude")) {
91  if (allowDefaults) {
92  double centerLat = (MinimumLatitude() + MaximumLatitude()) / 2.0;
93  mapGroup += PvlKeyword("CenterLatitude", toString(centerLat), "Degrees");
94  }
95  else {
96  QString message = "Cannot project using Lambert Azimuthal equal-area";
97  message += " without [CenterLatitude] value. Keyword does not exist";
98  message += " in labels and defaults are not allowed.";
99  throw IException(IException::Unknown, message, _FILEINFO_);
100  }
101  }
102 
103  // Get the center longitude & latitude
104  double centerLongitude = mapGroup["CenterLongitude"];
105  double centerLatitude = mapGroup["CenterLatitude"];
106 
107  if (fabs(MinimumLongitude() - centerLongitude) > 360.0 ||
108  fabs(MaximumLongitude() - centerLongitude) > 360.0) {
109  IString message = "[MinimumLongitude,MaximumLongitude] range of [";
110  message += IString(MinimumLongitude())+","+IString(MaximumLongitude());
111  message += "] is invalid. No more than 360 degrees from the "
112  "CenterLongitude [" + IString(centerLongitude) + "] is allowed.";
113  throw IException(IException::Unknown, message, _FILEINFO_);
114  }
115 
116  if (MaximumLongitude() - MinimumLongitude() > 360.0) {
117  IString message = "[MinimumLongitude,MaximumLongitude] range of ["
118  + IString(MinimumLongitude()) + ","
119  + IString(MaximumLongitude()) + "] is invalid. "
120  "No more than 360 degree range width is allowed.";
121  throw IException(IException::Unknown, message, _FILEINFO_);
122  }
123 
124  // initialize member variables
125  init(centerLatitude, centerLongitude);
126  }
127  catch(IException &e) {
128  IString message = "Invalid label group [Mapping]";
129  throw IException(e, IException::Unknown, message, _FILEINFO_);
130  }
131  }
132 
140  LambertAzimuthalEqualArea::~LambertAzimuthalEqualArea() {
141  }
142 
155  bool LambertAzimuthalEqualArea::operator== (const Projection &proj) {
156  if (!Projection::operator==(proj)) return false;
157  // don't do the below it is a recursive plunge
158  // if (Projection::operator!=(proj)) return false;
159  LambertAzimuthalEqualArea *lama = (LambertAzimuthalEqualArea *) &proj;
160  if ((lama->m_phi1 != m_phi1) ||
161  (lama->m_lambda0 != m_lambda0) ||
162  (lama->m_a != m_a) ||
163  (lama->m_e != m_e)) return false;
164  // all other data members calculated using m_lambda0, m_phi1, m_a and m_e.
165  return true;
166  }
167 
177  QString LambertAzimuthalEqualArea::Name() const {
178  return "LambertAzimuthalEqualArea";
179  }
180 
186  QString LambertAzimuthalEqualArea::Version() const {
187  return "1.0";
188  }
189 
205  //Snyder pg.
206  // no distortion at center of projection (centerLatitude, centerLongitude)
207  return m_phi1 * 180.0 / PI;
208  }
209 
210 
232  void LambertAzimuthalEqualArea::init(double centerLatitude,
233  double centerLongitude) {
234  // Initialize miscellaneous protected data elements
235  m_good = false;
236 
237  m_minimumX = DBL_MAX;
238  m_maximumX = -DBL_MAX;
239  m_minimumY = DBL_MAX;
240  m_maximumY = -DBL_MAX;
241 
242  // Test to make sure center longitude is valid
243  if (fabs(centerLongitude) > 360.0) {
244  IString message = "CenterLongitude [" + IString(centerLongitude);
245  message += "] is outside the range of [-360, 360]";
246  throw IException(IException::Unknown, message, _FILEINFO_);
247  }
248 
249  // Test to make sure center lat is valid
250  if (fabs(centerLatitude) > 90.0) {
251  IString message = "CenterLatitude [" + IString(centerLatitude);
252  message += "] is outside the range of [-90, 90]";
253  throw IException(IException::Unknown, message, _FILEINFO_);
254  }
255 
256  // We need to convert to planetographic since phi is geographic latitude
257  // (see phi and phi1 - Snyder pg ix)
258  if (IsPlanetocentric()) {
259  centerLatitude = ToPlanetographic(centerLatitude);
260  }
261 
262  // adjust for positive east longitude direction
263  // (see lambda and lambda0 - Snyder pg ix)
265  centerLongitude = -1.0*centerLongitude;
266  }
267 
268  // Descriptions of the variables a, e, lambda0, and phi1
269  // can be found in Snyder text on pgs viii-ix, pg 187
270  m_a = EquatorialRadius();
271  m_e = Eccentricity(); // e = sqrt(1 - (PolarRadius/EqRadius)^2)
272  // must be 0 <= e < 1
273 
274  // Snyder variables used for spherical projection
275  m_lambda0 = centerLongitude*PI / 180.0; // convert to radians
276  m_phi1 = centerLatitude*PI / 180.0; // convert to radians
277  m_sinPhi1 = sin(m_phi1);
278  m_cosPhi1 = cos(m_phi1);
279 
280  // flags for determinining which formulas to use
281  m_spherical = false;
282  m_northPolarAspect = false;
283  m_southPolarAspect = false;
284  m_equatorialAspect = false;
285 
286  if (qFuzzyCompare(0.0, m_e)) {
287  m_e = 0.0;
288  m_spherical = true;
289  }
290  if (qFuzzyCompare(HALFPI, m_phi1)) {
291  m_phi1 = HALFPI;
292  m_northPolarAspect = true;
293  }
294  if (qFuzzyCompare(-HALFPI, m_phi1)) {
295  m_phi1 = -HALFPI;
296  m_southPolarAspect = true;
297  }
298  if (qFuzzyCompare(0.0, m_phi1)) {
299  m_phi1 = 0.0;
300  m_equatorialAspect = true;
301  }
302 
303  // Snyder ellipsoid variables will not be used
304  m_qp = Null;
305  m_q1 = Null;
306  m_m1 = Null;
307  m_beta1 = Null;
308  m_sinBeta1 = Null;
309  m_cosBeta1 = Null;
310  m_Rq = Null;
311  m_D = Null;
312 
313  // other Snyder variables
314  m_h = Null;
315  m_k = Null;
316 
317  // if eccentricity = 0, we are projecting a sphere.
318  if (!m_spherical) {
319  // Calculate Snyder ellipsoid variables
320  initEllipsoid();
321  }
322 
323  // Check if the antipodal point is in the lat/lon ranges.
324  //
325  // We can only allow this if we have a polar projection.
326  // Otherwise, we cannot SetGround() for the antipodal point since it is
327  // projected as a circle, not a single point with (x,y) value.
328  //
329  // The antipodal point is defined by the coordinates
330  // (-centerLat, centerLon-180) or (-centerLat, centerLon+180)
332  if (-centerLatitude >= MinimumLatitude()
333  && -centerLatitude <= MaximumLatitude()
334  && ( (MinimumLongitude() <= centerLongitude - 180 &&
335  MaximumLongitude() >= centerLongitude - 180)
336  || (MinimumLongitude() <= centerLongitude + 180 &&
337  MaximumLongitude() >= centerLongitude + 180) ) ) {
338  IString message = "Invalid latitude and/or longitude range. ";
339  message += "Non-polar Lambert Azimuthal equal-area "
340  "projections can not project the antipodal point on "
341  "the body.";
342  throw IException(IException::Unknown, message, _FILEINFO_);
343  }
344  }
345  }
346 
354  void LambertAzimuthalEqualArea::initEllipsoid() {
355  m_spherical = false;
356 
357  // Decided not to use qCompute method here to reduce chance of roundoff
358  // error since q for polar simplifies
359  // m_qp = qCompute(1.0); //q for polar, sin(phi) = sin(pi/2) = 1.0
360  m_qp = 1 - (1 - m_e * m_e) / (2 * m_e) * log( (1 - m_e) / (1 + m_e) );
361  // Snyder eqn (3-12) pg 187, use phi = pi/2 (polar)
362  // Note: We know that qp is well defined since 0 < e < 1, thus
363  // 1+e != 0 (no 0 denominator) and (1-e)/(1+e) > 0 (log domain)
365  // we only need to compute these variables for oblique projections
366 
367  m_q1 = qCompute(m_sinPhi1); // Snyder eqn (3-12) pg 187, use phi = phi1
368  m_m1 = mCompute(m_sinPhi1, m_cosPhi1); // Snyder eqn (14-15) pg 187,
369  //use phi = phi1, thus m1 = cosPhi1/sqrt(1-eSinPhi1*eSinPhi1)
370  m_beta1 = asin(m_q1 / m_qp); // Snyder eqn (3-11) pg 187, use q = q1
371  // Note: We can show mathematically that beta1 is well defined
372  // First, since 0 < eccentricity < 1, we have (1-e)/(1+e) < 1
373  // Thus, ln((1-e)/(1+e)) < 0 and so qp > 1 (no 0 denominator)
374  // Next, verify the domain for arcsine, -1 <= q1/qp <= 1
375  // Since not polar, |phi1| < 90, and since ellipsoid 0 < e < 1
376  // Then |sinPhi1| < 1, so e|sinPhi1| < e
377  // So, 1 < (1+e|sinPhi1|)/(1-e|sinPhi1|) < (1+e)/(1-e).
378  // 0 < ln[(1+e|sinPhi1|)/(1-e|sinPhi1|)] < ln[(1+e)/(1-e)]
379  // Note that (1-e^2)/(2e) > 0 and recall -ln(x) = ln(1/x)
380  // So |q1| = |sinPhi1 - (1-e^2)/(2e)ln[(1-eSinPhi1)/(1+eSinPhi1)]|
381  // = |sinPhi1 + (1-e^2)/(2e)ln[(1+eSinPhi1)/(1-eSinPhi1)]|
382  // <= |sinPhi1| + |(1-e^2)/(2e)ln[(1+eSinPhi1)/(1-eSinPhi1)]|
383  // = |sinPhi1| +(1-e^2)/(2e) |ln[(1+eSinPhi1)/(1-eSinPhi1)]|
384  // < 1 + (1-e^2)/(2e) |ln[(1+eSinPhi1)/(1-eSinPhi1)]|
385  // <= 1 + (1-e^2)/(2e) ln[(1+e|SinPhi1|)/(1-e|SinPhi1|)]
386  // < 1 + (1-e^2)/(2e) ln[(1+e)/(1-e)]
387  // = 1 - (1-e^2)/(2e)ln[(1-e)/(1+e)]
388  // = qp
389  m_sinBeta1 = sin(m_beta1);
390  m_cosBeta1 = cos(m_beta1);
391  m_Rq = m_a * sqrt(m_qp / 2); // Snyder eqn (3-13) pg 16, 187
392  // Note: We know Rq is well defined since qp > 1 (see m_beta1)
393  m_D = m_a * m_m1 / (m_Rq * m_cosBeta1); // Snyder eqn (24-20) pg 187
394  // Note: We know D is well-defined since
395  // cosBeta1 = 0 implies beta1 = +/-pi/2,
396  // which in turn implies q1 = +/-qp
397  // This should only happen if polar aspect,
398  // Furthermore, Rq = 0 is impossible since a > 0 and q > 1
399  }
400  }
401 
421  bool LambertAzimuthalEqualArea::SetGround(const double lat,
422  const double lon) {
423  // when lat/lon is Null or lat is "beyond" the poles, we can't set ground
424  if (fabs(lat) - 90.0 > DBL_EPSILON || lat == Null || lon == Null) {
425  if (!qFuzzyCompare(90.0, fabs(lat))) {
426  m_good = false;
427  return m_good;
428  }
429  }
430 
431  m_longitude = lon;
432  m_latitude = lat;
433 
434  // assign input values to Snyder's phi and lambda variables
435  // convert to radians, positive east longitude, planetographic
436  double phi = lat * PI / 180.0;
437  double lambda = lon * PI / 180.0;
438 
439  // when lat just barely beyond pole, set equal to pole
440  if (lat > 90.0 && qFuzzyCompare(90.0, lat)) {
441  phi = HALFPI;
442  }
443  if (lat < -90.0 && qFuzzyCompare(-90.0, lat)) {
444  phi = -HALFPI;
445  }
446 
447  if (m_longitudeDirection == PositiveWest) lambda *= -1.0;
448  if (IsPlanetocentric()) phi = ToPlanetographic(phi);
449 
450  if (!m_spherical) return setGroundEllipsoid(phi, lambda);
451 
452  // calculate the following once to reduce computations
453  double sinPhi = sin(phi);
454  double cosPhi = cos(phi);
455  double sinLambdaDiff = sin(lambda - m_lambda0);
456  double cosLambdaDiff = cos(lambda - m_lambda0);
457 
458  // Use the variables defined above to compute the x,y coordinate
459  double x,y;
460 
461  // In this case, Spherical Radius = Equitorial Radius,
462  // so Snyder's R = Snyder's a variable pg ix
463  double R = m_a;
464  if (m_northPolarAspect ) {
465  double sinQuarterPiMinusHalfPhi = sin(PI/4-phi/2);
466  x = 2*R*sinQuarterPiMinusHalfPhi*sinLambdaDiff; //Snyder eqn (24-3) pg 186
467  y = -2*R*sinQuarterPiMinusHalfPhi*cosLambdaDiff;//Snyder eqn (24-4) pg 186
468  m_h = cos(PI/4-phi/2); // Snyder eqn (24-6) pg 186
469  m_k = 1/m_h; // Snyder eqn (24-5) and (24-6) pg 186
470  // - recall sec(theta) = 1/cos(theta)
471  }
472  else if (m_southPolarAspect ) {
473  double cosQuarterPiMinusHalfPhi = cos(PI/4-phi/2);
474  x = 2*R*cosQuarterPiMinusHalfPhi*sinLambdaDiff; //Snyder eqn (24-8) pg 186
475  y = 2*R*cosQuarterPiMinusHalfPhi*cosLambdaDiff; //Snyder eqn (24-9) pg 186
476  m_h = sin(PI/4-phi/2); // Snyder eqn (24-11) pg 186
477  m_k = 1/m_h; // Snyder eqn (24-10) and (24-11) pg 186
478  }
479  else { // spherical oblique aspect (this includes equatorial)
480 
481  // Check if (phi, lambda) is the antipodal point (point diametrically
482  // opposite the center point of projection)
483  if (qFuzzyCompare(-m_phi1, phi) // phi = -phi1
484  && fabs(fmod(lambda-m_lambda0, PI)) < DBL_EPSILON //lambda-lambda0=k*PI
485  && fabs(fmod(lambda-m_lambda0, 2*PI)) > DBL_EPSILON) { // k is odd
486  // We don't allow this for oblique aspect projections. This point,
487  // at the opposite side of the planet, is projected as a circle of
488  // radius 2R - we can't return a unique (x,y) value.
489  m_good = false;
490  return m_good;
491  }
492 
493  // First, be sure that the denominator will not be zero
494  double trigTerms;
495  if (m_equatorialAspect) {
496  // If m_phi1 == 0, the general case below cancels alegbraically
497  // to the following equations, however, the simplified equations
498  // are used here to reduce chance of roundoff errors
499  // -- Snyder eq (24-14) pg 186
500  trigTerms = cosPhi*cosLambdaDiff;
501  }
502  else {
503  // general case for oblique projections -- Snyder eq (24-2) pg 185
504  double sinProduct = m_sinPhi1 * sinPhi;
505  double cosProduct = m_cosPhi1 * cosPhi * cosLambdaDiff;
506  trigTerms = sinProduct + cosProduct;
507  }
508  // make sure when we add 1 to trigTerms that we are not near zero
509  if (qFuzzyCompare(-1.0, trigTerms)) {
510  m_good = false;
511  return m_good;
512  }
513  double denominator = 1 + trigTerms;
514  double kprime = sqrt(2/denominator); // Snyder eqn (24-2) or (24-14) pg 185-186
515  x = R*kprime*cosPhi*sinLambdaDiff; // Snyder eqn (22-4) pg 185
516  if (m_equatorialAspect) {
517  // If m_phi1 == 0, the general case below cancels alegbraically
518  // to the following, however, use the simplified equations for y
519  // to reduce the likelihood of roundoff errors
520  // -- Snyder eq (24-13) pg 186
521  y = R*kprime*sinPhi;
522  }
523  else { // spherical general oblique aspect -- Snyder eqn (22-5) pg 185
524  y = R*kprime*(m_cosPhi1*sinPhi - m_sinPhi1*cosPhi*cosLambdaDiff);
525  }
526  // these are the relative scale factors for oblique aspect
527  m_k = kprime;
528  m_h = 1/m_k;
529  }
530 
531  SetComputedXY(x, y); // sets m_x = x and m_y = y and handles rotation
532  m_good = true;
533  return m_good;
534  }
535 
550  bool LambertAzimuthalEqualArea::setGroundEllipsoid(double phi,
551  double lambda) {
552  // calculate the following once to reduce computations
553  double sinPhi = sin(phi);
554  double cosPhi = cos(phi);
555  double sinLambdaDiff = sin(lambda - m_lambda0);
556  double cosLambdaDiff = cos(lambda - m_lambda0);
557 
558  // Use the variables passed in to compute the x,y coordinate
559  double x,y;
560 
561  // projecting an ellipsoid
562  double q = qCompute(sinPhi); //q for given lat
563  if (qFuzzyCompare(PI/2, phi)) {
564  q = m_qp; // reduce roundoff error
565  }
566  if (qFuzzyCompare(-PI/2, phi)) {
567  q = -m_qp; // reduce roundoff error
568  }
569  // q = (1-e^2)*(sinphi/(1-e^2sinphi^2))-1/(2e)*log((1-esinphi)/(1+esinphi)))
570 
571  double m = mCompute(sinPhi, cosPhi); // m = cosPhi/sqrt(1-eSinPhi*eSinPhi)
572  if (m_northPolarAspect) {
573  double rho = m_a* sqrt(m_qp - q); // Snyder eqn (24-23) pg 188
574  // Note: Rho is well defined (qp >= q) as shown in initEllipsoid()
575  x = rho * sinLambdaDiff; // Snyder eqn (21-30) pg 188
576  y = -1.0 * rho * cosLambdaDiff; // Snyder eqn (21-31) pg 188
577  if (qFuzzyCompare(m_phi1, phi)) {
578  m_k = 1; // Since True scale at clat/clon - see Snyder page 190, table 29
579  }
580  else{
581  m_k = rho / (m_a * m); // Snyder eqn (21-32) pg 188
582  }
583  m_h = 1 / m_k; // Snyder paragraph after eqn (24-23) pg 188
584 
585  }
586  else if (m_southPolarAspect) {
587  double rho = m_a* sqrt(m_qp + q); // Snyder eqn (24-25) pg 188
588  // Note: Rho is well defined (qp >= -q) as shown in initEllipsoid()
589  x = rho * sinLambdaDiff; // Snyder eqn (21-30) pg 188
590  y = rho * cosLambdaDiff; // Snyder eqn (24-24) pg 188
591  if (qFuzzyCompare(m_phi1, phi)) {
592  m_k = 1; // Since True scale at clat/clon - see Snyder page 190, table 29
593  }
594  else{
595  m_k = rho / (m_a * m); // Snyder eqn (21-32) pg 188
596  }
597  m_h = 1 / m_k;
598  }
599  else { // ellipsoidal oblique aspect
600  // following comment is impossible -- see initEllipsoid(), |q1| > |qp|
601  // if (fabs(q) > fabs(m_qp)) {
602  // m_good = false;
603  // return m_good;
604  // }
605  double beta = asin( q/m_qp); // Snyder eqn (3-11) pg 187
606  // Note: beta is well defined- see initEllipsoid() m_beta1
607 
608  // calculate the following once to reduce computations when defining
609  // Snyder's variable B
610  double sinBeta = sin(beta);
611  double cosBeta = cos(beta);
612 
613  if (m_equatorialAspect) {
614  // If phi1 == 0, the general case below cancels alegbraically to
615  // the following equations, however, the simplified equations are
616  // used here to reduce chance of roundoff errors
617  double trigTerm = cosBeta*cosLambdaDiff;
618  if (qFuzzyCompare(-1, trigTerm)) { // avoid divide by zero & possible roundoff errors
619  // This happens when trying to project the antipodal point.
620  // lambda = lambda0 +/- 180 and beta = 0 (that is, phi = 0)
621  // Thus denominator = 1 + (1)(-1) = 0
622  // We don't allow this for equatorial aspect projections. This point,
623  // at the opposite side of the planet, is projected as a circle of
624  // radius 2R - we can't return a unique (x,y) value.
625  m_good = false;
626  return m_good;
627  }
628  double denominator = 1 + trigTerm;
629  x = m_a * cosBeta * sinLambdaDiff * sqrt(2/denominator);
630  // Snyder eqn (24-21) pg 187
631  y = (m_Rq*m_Rq/m_a) * sinBeta * sqrt(2/denominator);
632  // Snyder eqn (24-22) pg 187
633  // Note: Clearly 1 + cosBeta*cosLambdaDiff >= 0
634  // 1 + cosBeta*cosLambdaDiff = 0 implies 2 cases
635  // 1) cosBeta = 1 and cosLambdaDiff = -1
636  // So, beta = 0 and lambdaDiff = 180
637  // Then, q = 0, which implies phi = 0 = phi1
638  // this only happens when projecting opposite side of equator
639  // 2) cosBeta = -1 and cosLambdaDiff = 1
640  // So, beta = 180 impossible since beta is defined by asin
641  // (range of asin is -90 to 90)
642  // Then, q = 0, which implies phi = 0 = phi1
643  // this only happens when projecting opposite side of equator
644  // Therefore x and y are well defined
645  }
646  else { // ellipsoidal General oblique aspect
647  double sinProduct = m_sinBeta1 * sinBeta;
648  double cosProduct = m_cosBeta1 * cosBeta * cosLambdaDiff;
649  double trigTerms = sinProduct + cosProduct;
650  if (qFuzzyCompare(-1, trigTerms)) { // avoid divide by zero & possible roundoff errors
651  // This happens when trying to project the antipodal point.
652  // lambda = lambda0 + 180 and beta = -beta1 (that is, phi = -phi1)
653  // Then, by odd symmetry of sine function, sinBeta = -sinBeta1,
654  // by even symmetry of cosine, cosBeta = cosBeta1
655  // and cosLambdaDiff = cos(180) = -1
656  // Thus denominator = 1 - sin^2(beta) - cos^2(beta) = 1-1 = 0
657  // We don't allow this for oblique aspect projections. This point,
658  // at the opposite side of the planet, is projected as a circle of
659  // radius 2R - we can't return a unique (x,y) value.
660  m_good = false;
661  return m_good;
662  }
663  double denominator = 1 + trigTerms;
664  double kprime = sqrt(2/denominator); // Snyder eqn (24-2) page 185
665  double B = m_Rq * kprime; // Snyder eqns (24-19) pg 187
666 
667  x = B * m_D * cosBeta*sinLambdaDiff; // Snyder eqn (24-17) pg 187
668  y = (B/m_D) * (m_cosBeta1*sinBeta - m_sinBeta1*cosBeta*cosLambdaDiff);
669  // Snyder eqn (24-18) pg 187
670  // Note: y is well defined since D = 0 implies a = 0 or m1 = 0
671  // we know a > 0,
672  // so m1 = 0 would imply cosPhi1 = 0, thus phi1 = +/- 90
673  // but this calculation is not used for polar aspect,
674  // so y doesn't have zero denominator
675  }
676  // There are no ellipsoidal values for the scale factors h and k unless
677  // using the polar aspects, Snyder pg 26.
678  }
679  SetComputedXY(x, y); // sets m_x = x and m_y = y and handles rotation
680 
681  m_good = true;
682  return m_good;
683  }
684 
704  bool LambertAzimuthalEqualArea::SetCoordinate(const double x,
705  const double y) {
706  if (x == Null || y == Null) {
707  m_good = false;
708  return m_good;
709  }
710  // Save the coordinate
711  SetXY(x, y);
712 
713  // 2012-06-11
714  // Uncomment following line if ellipsoid projection is implemented
715  if (!m_spherical) return setCoordinateEllipsoid(x,y);
716 
717  double phi; // latitude value to be calculated
718  double lambda; // longitude value to be calculated
719 
720  // Spherical Radius = Equatorial Radius, so
721  // Snyder's R = Snyder's a variable pg ix
722  double R = m_a;
723 
724  double rho = sqrt(x*x+y*y); // Snyder eqn (20-18) pg 187
725  if (rho < DBL_EPSILON) { // this implies (x,y) = (0,0),
726  // so project to center lat/lon values
727  phi = m_phi1;
728  lambda = m_lambda0;
729  }
730  else {
731  if (fabs(rho/(2*R)) > 1 + DBL_EPSILON) {// given (x,y) point is off planet
732  // projection if distance from
733  // origin (rho) is greater than
734  // 2*radius of sphere
735  m_good = false;
736  return m_good;
737  }
738  else if (fabs(rho/(2*R)) > 1) { // if ratio is slightly larger than 1
739  // due to rounding error, then fix so we
740  // can take the arcsin
741  rho = 2*R;
742  }
743  double c = 2*asin(rho/(2*R)); // c is angular distance,
744  //Snyder eqn (24-16) pg 187
745  double sinC = sin(c);
746  double cosC = cos(c);
747 
748  // verify the following is in the domain of the arcsin function
749  if (fabs(cosC*m_sinPhi1+y*sinC*m_cosPhi1/rho) > 1) {
750  m_good = false;
751  return m_good;
752  }
753  phi = asin(cosC*m_sinPhi1+y*sinC*m_cosPhi1/rho);//Snyder eq (20-14) pg 186
754  if (m_northPolarAspect ) { // spherical north polar aspect
755  lambda = m_lambda0 + atan2(x,-y); // Snyder eqn (20-16) pg 187,
756  // need to use atan2 to correct for
757  // quadrant - see pg 150
758  }
759  else if (m_southPolarAspect ) { // spherical north polar aspect
760  lambda = m_lambda0 + atan2(x,y); // Snyder eqn (20-17) pg 187, 150
761  }
762  else { // spherical oblique aspect
763  double denominator = rho*m_cosPhi1*cosC - y*m_sinPhi1*sinC;
764  // atan2 well defined for denominator = 0
765  // if numerator is also 0, returns 0
766  lambda = m_lambda0 + atan2(x * sinC, denominator);
767  // Snyder eqn (20-15) pg 186
768  }
769  }
770 
771  m_latitude = phi * 180.0 / PI;
772  m_longitude = lambda * 180.0 / PI;
773 
774  // Cleanup the longitude
776  m_longitude *= -1.0;
777  }
778 
779  if (m_longitudeDomain == 180) {
781  }
782  else {
783  // Do this because longitudeDirection could cause (-360,0)
785  }
786 
787  // Cleanup the latitude
788  if (IsPlanetocentric()) {
790  }
791 
792  m_good = true;
793  return m_good;
794  }
795 
813  bool LambertAzimuthalEqualArea::setCoordinateEllipsoid(const double x,
814  const double y) {
815  double phi; // latitude value to be calculated
816  double lambda; // longitude value to be calculated
817 
818  // ellipsoidal projection
819  double q;
820  // for polar aspects
821  double rho = sqrt(x*x+y*y); // Snyder eqn (20-18) pg 190
822  if (m_northPolarAspect ) { // ellipsoidal north polar aspect
823  q = m_qp - (rho*rho/(m_a*m_a)); // Snyder eqn (24-31) pg 190
824  lambda = m_lambda0 + atan2(x,-y); // Snyder eqn (20-16) pgs 190, 150
825  }
826  else if (m_southPolarAspect ) { // ellipsoidal south polar aspect
827  q = -1.0*(m_qp - (rho*rho/(m_a*m_a))); // Snyder eqn (24-31) pg 190
828  lambda = m_lambda0 + atan2(x,y); // Snyder eqn (20-17) pg 190, 150
829  }
830  else {// ellipsoidal oblique aspect
831  double xD = x/m_D; // m_D = 0 implies polar aspect
832  // (see setGroundEllipsoid() general oblique case
833  double Dy = m_D*y;
834  double rho = sqrt((xD*xD)+(Dy*Dy)); // Snyder eqn (24-28) pg 189
835  if (fabs(rho) > fabs(2*m_Rq)) {
836  m_good = false;
837  return m_good;
838  }
839  double Ce = 2*asin(rho/(2*m_Rq)); // Snyder eqn (24-29) pg 189
840  // TYPO IN TEXT, parentheses required
841  // around denominator (see usage pg 335)
842  // Note: Ce well defined since Rq = 0 is impossible (a > 0 and q > 1)
843  double sinCe = sin(Ce);
844  double cosCe = cos(Ce);
845 
846  if (rho < DBL_EPSILON) { // pg 189, first line appears to be typo in text,
847  // below is our interpretation.
848  // if rho = 0, then x=0 and (D=0 or y=0), so it
849  // makes sense that lambda = lambda0 in this case.
850  q = m_qp * m_sinBeta1;
851  lambda = m_lambda0;
852  }
853  else {
854  q = m_qp * (cosCe * m_sinBeta1 + m_D * y * sinCe * m_cosBeta1 / rho);
855  // Snyder eqn (24-27) pg 188
856  double numerator = x * sinCe;
857  double denominator = m_D * rho * m_cosBeta1 * cosCe
858  - m_D * m_D * y * m_sinBeta1 * sinCe;
859  // atan2 well defined for denominator = 0
860  // if numerator is also 0, returns 0
861  lambda = m_lambda0 + atan2(numerator, denominator);
862  // Snyder eqn (24-26) pg 188
863  }
864  }
865 
866  if (qFuzzyCompare(fabs(q), fabs(m_qp))) {
867  phi = copysign(HALFPI,q);// Snyder eqn (14-20) pg 189,
868  //(see definition of qp on pg 187)
869  }
870  else {
871  if (fabs(q) > 2) {
872  // verify that q/2 is in the domain of arcsin
873  m_good = false;
874  return m_good;
875  }
876  phi = asin(q/2); // Snyder pg 189 above (14-20) describes iteration
877  // process and initial value for phi
878  double phiOld = phi;
879  bool converge = false;
880  double tolerance = 1e-10; // tolerance same as Projection::phi2Compute()
881  // should we attempt to relate tolerance to pixel resolution ???
882  int maximumIterations = 100;
883  int i = 0;
884  while (!converge) {
885  i++;
886  // calculate values to reduce calculations:
887  double sinPhi = sin(phi);
888  double eSinPhi = m_e*sinPhi;
889  double cosPhi = cos(phi);
890  double squareESinPhi = eSinPhi*eSinPhi;
891  double oneMinusSquareESinPhi = 1 - squareESinPhi;
892  // find next iteration of phi
893  phi += oneMinusSquareESinPhi*oneMinusSquareESinPhi / (2 * cosPhi)
894  * (q / (1 - m_e * m_e)
895  - sinPhi / (oneMinusSquareESinPhi)
896  + log( (1 - eSinPhi) / (1 + eSinPhi) ) / (2 * m_e));
897  //eqn (3-16) pg 188
898  if (fabs(phiOld - phi) < tolerance) {
899  converge = true;
900  }
901  if (i > maximumIterations) {
902  m_good = false;
903  return m_good;
904  }
905  phiOld = phi;
906  }
907  }
908  m_latitude = phi * 180.0 / PI;
909  m_longitude = lambda * 180.0 / PI;
910 
911  // Cleanup the longitude
913  m_longitude *= -1.0;
914  }
915 
916  if (m_longitudeDomain == 180) {
918  }
919  else {
920  // Do this because longitudeDirection could cause (-360,0)
922  }
923 
924  // Cleanup the latitude
925  if (IsPlanetocentric()) {
927  }
928 
929  m_good = true;
930  return m_good;
931  }
932 
971  bool LambertAzimuthalEqualArea::XYRange(double &minX, double &maxX,
972  double &minY, double &maxY) {
973  // Global Polar projection
974  if ((m_northPolarAspect && qFuzzyCompare(-90.0, MinimumLatitude()))
975  || (m_southPolarAspect && qFuzzyCompare(90.0, MaximumLatitude()))) {
976  // for polar aspect projections, the antipodal point is the opposite pole.
977  // if it is included in lat range, the bounding circle will exist, no
978  // matter the longitude range.
979  double eRad = EquatorialRadius();
980  double pRad = PolarRadius();
981  double maxCoordValue = 0;
982 
983  if (m_spherical) {
984  maxCoordValue = 2*EquatorialRadius();
985  }
986  else {
987  maxCoordValue = sqrt(2*eRad*eRad
988  + pRad*pRad*log((1+m_e)/(1-m_e))/m_e);
989  }
990  m_minimumX = -maxCoordValue;
991  m_maximumX = maxCoordValue;
992  m_minimumY = -maxCoordValue;
993  m_maximumY = maxCoordValue;
994  }
995  // Polar projection, not including antipodal point
997  return xyRangeLambertAzimuthalPolar(minX, maxX, minY, maxY);
998  }
999  // Oblique projection
1000  else { // oblique cases (includes equatorial aspect)
1001  if (xyRangeOblique(minX, maxX, minY, maxY)) {
1002  // Make sure that the calculations didn't go beyond the accepatable x,y
1003  // values. As far as we know, the x, y values should not exceed
1004  // 2*LocalRadius(-phi)
1005  double maxCoordValue = 2*LocalRadius(-m_phi1*180/PI);
1006  if (m_minimumX < -maxCoordValue) m_minimumX = -maxCoordValue;
1007  if (m_maximumX > maxCoordValue) m_maximumX = maxCoordValue;
1008  if (m_minimumX < -maxCoordValue) m_minimumX = -maxCoordValue;
1009  if (m_maximumY > maxCoordValue) m_maximumY = maxCoordValue;
1010  }
1011  else {
1012  return false;
1013  }
1014  }
1015 
1016  // If we haven't already returned, we have a Global Polar projection or an
1017  // Oblique projection that did not fail xyRangeOblique
1018 
1019  // Make sure everything is ordered
1020  if (m_minimumX >= m_maximumX) return false;
1021  if (m_minimumY >= m_maximumY) return false;
1022 
1023  // Return X/Y min/maxs
1024  minX = m_minimumX;
1025  maxX = m_maximumX;
1026  minY = m_minimumY;
1027  maxY = m_maximumY;
1028  return true;
1029  }
1030 
1067  bool LambertAzimuthalEqualArea::xyRangeLambertAzimuthalPolar(double &minX,
1068  double &maxX,
1069  double &minY,
1070  double &maxY) {
1071  // Test the four combinations of min/max lat/lon
1076 
1077  double centerLonDeg = m_lambda0 * 180.0 / PI;
1078  if (m_longitudeDirection == PositiveWest) centerLonDeg = centerLonDeg * -1.0;
1079 
1080  // Since this projection is Polar aspect, 4 longitudes will lie
1081  // directly on the horizontal and vertical axes of the
1082  // projection.
1083  // test combinations with each of these longitudes:
1084  //
1085  // down (negative vertical axis) - center long for north polar
1086  // up (positive vertical axis) - center long for south polar
1087  // left (negative horizontal axis)
1088  // right (positive horizontal axis)
1089  //
1090  for (double lon = centerLonDeg; lon < centerLonDeg + 360; lon += 90) {
1091  checkLongitude(lon);
1092  }
1093 
1094  // Make sure everything is ordered
1095  if (m_minimumX >= m_maximumX) return false;
1096  if (m_minimumY >= m_maximumY) return false;
1097 
1098  // Return X/Y min/maxs
1099  minX = m_minimumX;
1100  maxX = m_maximumX;
1101  minY = m_minimumY;
1102  maxY = m_maximumY;
1103  return true;
1104  }
1105 
1123  void LambertAzimuthalEqualArea::checkLongitude(double longitude) {
1124 
1125  double centerLatDeg = m_phi1 * 180.0 / PI;
1126 
1127  double innerLatitude, outerLatitude;
1128  if (m_northPolarAspect) {
1129  innerLatitude = MaximumLatitude();
1130  outerLatitude = MinimumLatitude();
1131  }
1132  else if (m_southPolarAspect) {
1133  innerLatitude = MinimumLatitude();
1134  outerLatitude = MaximumLatitude();
1135  }
1136  else {
1137  IString message = "checkLongitude() should only be called for a "
1138  "polar aspect projection. CenterLatitude is [";
1139  message = message + IString(centerLatDeg) + "] degrees.";
1140  throw IException(IException::Programmer, message, _FILEINFO_);
1141  }
1142 
1143  // Check whether longitude is in the min/max longitude range
1144  bool thisLongitudeInMinMaxRange = false;
1145  if (MaximumLongitude() - MinimumLongitude() == 360) {
1146  thisLongitudeInMinMaxRange = true;
1147  }
1148  double adjustedLon = To360Domain(longitude);
1149  double adjustedMinLon = To360Domain(MinimumLongitude());
1150  double adjustedMaxLon = To360Domain(MaximumLongitude());
1151 
1152  if (adjustedMinLon > adjustedMaxLon) {
1153  if (adjustedLon > adjustedMinLon) {
1154  adjustedLon -= 360;
1155  }
1156  adjustedMinLon -= 360;
1157  }
1158  // if lon value for this axis is between min lon and max lon
1159  if (adjustedMinLon <= adjustedLon
1160  && adjustedLon <= adjustedMaxLon) {
1161  thisLongitudeInMinMaxRange = true;
1162  }
1163  else {
1164  thisLongitudeInMinMaxRange = false;
1165  }
1166 
1167  if (thisLongitudeInMinMaxRange) {
1168  // any shape that includes this longitude
1169  XYRangeCheck(outerLatitude, longitude);
1170  }
1171  else {
1172  // determine which boundary value (minlon or maxlon)
1173  // is closer to given longitude
1174  double distToMinLon = fabs(adjustedMinLon - adjustedLon);
1175  double distToMaxLon = fabs(adjustedMaxLon - adjustedLon);
1176 
1177  if (distToMinLon >= 180 ) {
1178  distToMinLon = fabs(360 - distToMinLon);
1179  }
1180  if (distToMaxLon >= 180 ) {
1181  distToMaxLon = fabs(360 - distToMaxLon);
1182  }
1183 
1184  double nearestBoundary = 0;
1185  if (distToMinLon < distToMaxLon) {
1186  nearestBoundary = MinimumLongitude();
1187  }
1188  else {
1189  nearestBoundary = MaximumLongitude();
1190  }
1191 
1192  // shapes that come within 90 degrees of the given longitude
1193  if (distToMinLon <= 90 + DBL_EPSILON
1194  || distToMaxLon <= 90 + DBL_EPSILON) {
1195  XYRangeCheck(outerLatitude, nearestBoundary);
1196  }
1197  // shapes more than 90 degrees from the longitude that include the origin
1198  else if (qFuzzyCompare(MaximumLatitude(), centerLatDeg)) {
1199  XYRangeCheck(centerLatDeg,longitude);
1200  }
1201  // shapes more than 90 degrees from the longitude without the origin
1202  else {
1203  XYRangeCheck(innerLatitude, nearestBoundary);
1204  }
1205  }
1206  return;
1207  }
1208 
1237  PvlGroup mapping = TProjection::Mapping();
1238 
1239  mapping += m_mappingGrp["CenterLatitude"];
1240  mapping += m_mappingGrp["CenterLongitude"];
1241 
1242  return mapping;
1243  }
1244 
1263  PvlGroup mapping = TProjection::MappingLatitudes();
1264 
1265  mapping += m_mappingGrp["CenterLatitude"];
1266 
1267  return mapping;
1268  }
1269 
1288  PvlGroup mapping = TProjection::MappingLongitudes();
1289 
1290  mapping += m_mappingGrp["CenterLongitude"];
1291 
1292  return mapping;
1293  }
1294 
1295  // There are no ellipsoidal values for the scale factors h and k unless
1296  // using the polar aspects, Snyder pg 26.
1297 
1298  // These methods are not currently used in other Projection classes. However,
1299  // if similar methods are implemented for other projections, we should create
1300  // a virtual prototype in the parent Projection. Currently since they do not
1301  // exist in Projection, we can not call them if ProjectionFactory was used to
1302  // create the object.
1317  double LambertAzimuthalEqualArea::relativeScaleFactorLongitude() const {
1318  validateRelativeScaleFactor();
1319  return m_h;
1320  };
1321 
1336  double LambertAzimuthalEqualArea::relativeScaleFactorLatitude() const {
1337  validateRelativeScaleFactor();
1338  return m_k;
1339  }
1340 
1363  void LambertAzimuthalEqualArea::validateRelativeScaleFactor() const {
1364  if (!m_good) {
1365  IString message = "Projection failed or ground and coordinates have not "
1366  "been set. Relative scale factor can not be computed.";
1367  throw IException(IException::Unknown, message, _FILEINFO_);
1368  }
1370  IString message = "For ellipsidal bodies, relative scale factor can only "
1371  "be computed for polar aspect projections.";
1372  throw IException(IException::Unknown, message, _FILEINFO_);
1373  }
1374  if (m_northPolarAspect && qFuzzyCompare(-90.0, m_latitude)) {
1375  IString message = "Relative scale factor can not be computed for north "
1376  "polar aspect projection when ground is set to "
1377  "latitude -90.";
1378  throw IException(IException::Unknown, message, _FILEINFO_);
1379  }
1380  if (m_southPolarAspect && qFuzzyCompare(90.0, m_latitude)) {
1381  IString message = "Relative scale factor can not be computed for south "
1382  "polar aspect projection when ground is set to "
1383  "latitude 90.";
1384  throw IException(IException::Unknown, message, _FILEINFO_);
1385  }
1386  if (m_k == Null || m_h == Null) {
1387  IString message = "Relative scale factor can not be computed.";
1388  throw IException(IException::Unknown, message, _FILEINFO_);
1389  }
1390  }
1391 
1392 } // end namespace isis
1393 
1411 extern "C" Isis::Projection *LambertAzimuthalEqualAreaPlugin(Isis::Pvl &lab,
1412  bool allowDefaults) {
1413  return new Isis::LambertAzimuthalEqualArea(lab, allowDefaults);
1414 }
1415 
Isis::LambertAzimuthalEqualArea::m_qp
double m_qp
Snyder's q variable from equation (3-12) on page 187, computed for the north pole,...
Definition: LambertAzimuthalEqualArea.h:154
Isis::LambertAzimuthalEqualArea::m_e
double m_e
Eccentricity of the ellipsoid.
Definition: LambertAzimuthalEqualArea.h:139
Isis::HALFPI
const double HALFPI
The mathematical constant PI/2.
Definition: Constants.h:41
Isis::LambertAzimuthalEqualArea::m_lambda0
double m_lambda0
The center longitude for the map projection measured positive east, in radians.
Definition: LambertAzimuthalEqualArea.h:141
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::TProjection::m_latitude
double m_latitude
This contains the currently set latitude value.
Definition: TProjection.h:316
Isis::LambertAzimuthalEqualArea::m_equatorialAspect
bool m_equatorialAspect
Indicates whether this is a equatorial aspect projection.
Definition: LambertAzimuthalEqualArea.h:133
Isis::LambertAzimuthalEqualArea::m_sinBeta1
double m_sinBeta1
The sine of m_beta1.
Definition: LambertAzimuthalEqualArea.h:165
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::LambertAzimuthalEqualArea
Lambert Azimuthal Equal Area Map Projection.
Definition: LambertAzimuthalEqualArea.h:91
Isis::TProjection::m_longitudeDirection
LongitudeDirection m_longitudeDirection
An enumerated type indicating the LongitudeDirection read from the labels.
Definition: TProjection.h:324
Isis::LambertAzimuthalEqualArea::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...
Isis::TProjection::PositiveWest
@ PositiveWest
Longitude values increase in the westerly direction.
Definition: TProjection.h:225
Isis::TProjection::MinimumLongitude
virtual double MinimumLongitude() const
This returns the minimum longitude of the area of interest.
Definition: TProjection.cpp:732
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::LambertAzimuthalEqualArea::TrueScaleLatitude
double TrueScaleLatitude() const
This method returns the latitude of true scale.
Isis::LambertAzimuthalEqualArea::m_h
double m_h
Relative scale factor along a meridian of longitude.
Definition: LambertAzimuthalEqualArea.h:174
Isis::TProjection::xyRangeOblique
bool xyRangeOblique(double &minX, double &maxX, double &minY, double &maxY)
This method is used to find the XY range for oblique aspect projections (non-polar projections) by "w...
Definition: TProjection.cpp:1195
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::TProjection::ToPlanetocentric
double ToPlanetocentric(const double lat) const
This method converts a planetographic latitude to a planetocentric latitude.
Definition: TProjection.cpp:418
Isis::LambertAzimuthalEqualArea::m_Rq
double m_Rq
The radius of the sphere having the same surface area as the ellipsoid.
Definition: LambertAzimuthalEqualArea.h:167
Isis::LambertAzimuthalEqualArea::m_southPolarAspect
bool m_southPolarAspect
Indicates whether this is a south polar aspect projection.
Definition: LambertAzimuthalEqualArea.h:131
Isis::LambertAzimuthalEqualArea::m_m1
double m_m1
Snyder's m variable from equation (14-15) on page 187, computed from the center latitude,...
Definition: LambertAzimuthalEqualArea.h:159
Isis::LambertAzimuthalEqualArea::Name
QString Name() const
This method returns the name of the map projection.
Isis::LambertAzimuthalEqualArea::m_a
double m_a
Equitorial Radius of the ellipsoid.
Definition: LambertAzimuthalEqualArea.h:137
Isis::TProjection::MaximumLatitude
virtual double MaximumLatitude() const
This returns the maximum latitude of the area of interest.
Definition: TProjection.cpp:721
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::TProjection::EquatorialRadius
double EquatorialRadius() const
This returns the equatorial radius of the target.
Definition: TProjection.cpp:277
Isis::LambertAzimuthalEqualArea::m_spherical
bool m_spherical
Indicates whether the body to be projected is spherical.
Definition: LambertAzimuthalEqualArea.h:127
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::LambertAzimuthalEqualArea::m_k
double m_k
Relative scale factor along a parallel of latitude.
Definition: LambertAzimuthalEqualArea.h:175
Isis::Projection::m_mappingGrp
PvlGroup m_mappingGrp
Mapping group that created this projection.
Definition: Projection.h:329
Isis::PvlObject::Traverse
@ Traverse
Search child objects.
Definition: PvlObject.h:158
Isis::LambertAzimuthalEqualArea::m_sinPhi1
double m_sinPhi1
The sine of the center latitude.
Definition: LambertAzimuthalEqualArea.h:149
Isis::LambertAzimuthalEqualArea::operator==
bool operator==(const Projection &proj)
This method determines whether two map projection objects are equal by comparing the equatorial radiu...
Isis::TProjection::qCompute
double qCompute(const double sinPhi) const
A convience method to compute Snyder's q equation (3-12) for a given latitude, .
Definition: TProjection.cpp:1770
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::LambertAzimuthalEqualArea::Version
QString Version() const
This method returns the Version of the map projection.
Isis::TProjection::PolarRadius
double PolarRadius() const
This returns the polar radius of the target.
Definition: TProjection.cpp:287
Isis::LambertAzimuthalEqualArea::m_northPolarAspect
bool m_northPolarAspect
Indicates whether this is a north polar aspect projection.
Definition: LambertAzimuthalEqualArea.h:129
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::LambertAzimuthalEqualArea::m_cosPhi1
double m_cosPhi1
The cosine of the center latitude.
Definition: LambertAzimuthalEqualArea.h:150
Isis::LambertAzimuthalEqualArea::m_phi1
double m_phi1
The center latitude for the map projection, in radians.
Definition: LambertAzimuthalEqualArea.h:147
Isis::LambertAzimuthalEqualArea::MappingLongitudes
PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Isis::LambertAzimuthalEqualArea::MappingLatitudes
PvlGroup MappingLatitudes()
This function returns the latitude keywords that this projection uses.
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::LambertAzimuthalEqualArea::m_beta1
double m_beta1
The authalaic latitude.
Definition: LambertAzimuthalEqualArea.h:162
Isis::Null
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:95
Isis::TProjection::MaximumLongitude
virtual double MaximumLongitude() const
This returns the maximum longitude of the area of interest.
Definition: TProjection.cpp:743
Isis::TProjection::MappingLongitudes
virtual PvlGroup MappingLongitudes()
This function returns the longitude keywords that this projection uses.
Definition: TProjection.cpp:1739
Isis::LambertAzimuthalEqualArea::m_q1
double m_q1
Snyder's q variable from equation (3-12) on page 187, computed for the center latitude,...
Definition: LambertAzimuthalEqualArea.h:156
Isis::TProjection::LocalRadius
double LocalRadius() const
This method returns the local radius in meters at the current latitude position.
Definition: TProjection.cpp:353
Isis::Projection::SetComputedXY
void SetComputedXY(double x, double y)
This protected method is a helper for derived classes.
Definition: Projection.cpp:780
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
std
Namespace for the standard library.
Isis::LambertAzimuthalEqualArea::m_D
double m_D
Value used to correct scale in all directions at the center of the projection.
Definition: LambertAzimuthalEqualArea.h:170
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::LambertAzimuthalEqualArea::SetCoordinate
bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
Isis::TProjection::MinimumLatitude
virtual double MinimumLatitude() const
This returns the minimum latitude of the area of interest.
Definition: TProjection.cpp:710
Isis::TProjection::Mapping
virtual PvlGroup Mapping()
This function returns the keywords that this projection uses.
Definition: TProjection.cpp:1698
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::LambertAzimuthalEqualArea::Mapping
PvlGroup Mapping()
This function returns the keywords that this projection uses.
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::LambertAzimuthalEqualArea::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,...
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::LambertAzimuthalEqualArea::m_cosBeta1
double m_cosBeta1
The cosine of m_beta1.
Definition: LambertAzimuthalEqualArea.h:166
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16