Isis 3 Programmer Reference
Latitude.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "Latitude.h"
8 
9 #include <cmath>
10 
11 #include "Constants.h"
12 #include "Distance.h"
13 #include "IException.h"
14 #include "IString.h"
15 #include "PvlGroup.h"
16 #include "QString"
17 #include "SpecialPixel.h"
18 #include "Target.h"
19 
20 namespace Isis {
21 
26 
27  m_equatorialRadius = NULL;
28  m_polarRadius = NULL;
29 
31  }
32 
33 
45  Latitude::Latitude(double latitude, Angle::Units latitudeUnits,
46  ErrorChecking errors) : Angle() {
47 
48  m_equatorialRadius = NULL;
49  m_polarRadius = NULL;
50 
51  m_errors = errors;
52 
53  setPlanetocentric(latitude, latitudeUnits);
54  }
55 
56 
64  Latitude::Latitude(Angle latitude, ErrorChecking errors) : Angle() {
65 
66  m_equatorialRadius = NULL;
67  m_polarRadius = NULL;
68 
69  m_errors = errors;
70 
71  setPlanetocentric(latitude.radians(), Radians);
72  }
73 
74 
90  Latitude::Latitude(Angle latitude, PvlGroup mapping,
91  ErrorChecking errors) : Angle(latitude) {
92 
93  m_equatorialRadius = NULL;
94  m_polarRadius = NULL;
95 
96  if (mapping.hasKeyword("EquatorialRadius") && mapping.hasKeyword("PolarRadius")) {
97  m_equatorialRadius = new Distance(toDouble(mapping["EquatorialRadius"][0]),
99  m_polarRadius = new Distance(toDouble(mapping["PolarRadius"][0]),
101  }
102  else {
103  try {
104  PvlGroup radiiGrp = Target::radiiGroup(mapping["TargetName"][0]);
105  m_equatorialRadius = new Distance(toDouble(radiiGrp["EquatorialRadius"][0]),
107  m_polarRadius = new Distance(toDouble(radiiGrp["PolarRadius"][0]),
109  }
110  catch (IException &e) {
111  QString msg = "Unable to create Latitude object from given mapping group.";
112  throw IException(e, IException::Unknown, msg, _FILEINFO_);
113  }
114  }
115 
116  m_errors = errors;
117 
118  if (mapping["LatitudeType"][0] == "Planetographic") {
119  setPlanetographic(latitude.radians(), Radians);
120  }
121  else if (mapping["LatitudeType"][0] == "Planetocentric") {
122  setPlanetocentric(latitude.radians(), Radians);
123  }
124  else {
125  QString msg = "Latitude type [" + mapping["LatitudeType"][0] +
126  "] is not recognized";
127  throw IException(IException::Programmer, msg, _FILEINFO_);
128  }
129  }
130 
131 
148  Latitude::Latitude(double latitude,
149  PvlGroup mapping,
150  Angle::Units latitudeUnits,
151  ErrorChecking errors) : Angle(latitude, latitudeUnits) {
152 
153  m_equatorialRadius = NULL;
154  m_polarRadius = NULL;
155 
156  if (mapping.hasKeyword("EquatorialRadius") && mapping.hasKeyword("PolarRadius")) {
157  m_equatorialRadius = new Distance(toDouble(mapping["EquatorialRadius"][0]),
159  m_polarRadius = new Distance(toDouble(mapping["PolarRadius"][0]),
161  }
162  else {
163  try {
164  PvlGroup radiiGrp = Target::radiiGroup(mapping["TargetName"][0]);
165  m_equatorialRadius = new Distance(toDouble(radiiGrp["EquatorialRadius"][0]),
167  m_polarRadius = new Distance(toDouble(radiiGrp["PolarRadius"][0]),
169  }
170  catch (IException &e) {
171  QString msg = "Unable to create Latitude object from given mapping group.";
172  throw IException(e, IException::Unknown, msg, _FILEINFO_);
173  }
174  }
175 
176  m_errors = errors;
177 
178  if (mapping["LatitudeType"][0] == "Planetographic") {
179  setPlanetographic(latitude, latitudeUnits);
180  }
181  else if (mapping["LatitudeType"][0] == "Planetocentric") {
182  setPlanetocentric(latitude, latitudeUnits);
183  }
184  else {
185  QString msg = "Latitude type [" + mapping["LatitudeType"][0] +
186  "] is not recognized";
187  throw IException(IException::Programmer, msg, _FILEINFO_);
188  }
189  }
190 
191 
208  Latitude::Latitude(double latitude,
209  Distance equatorialRadius, Distance polarRadius,
210  CoordinateType latType,
211  Angle::Units latitudeUnits,
212  ErrorChecking errors) : Angle(latitude, latitudeUnits) {
213 
214  m_equatorialRadius = NULL;
215  m_polarRadius = NULL;
216 
217  m_equatorialRadius = new Distance(equatorialRadius);
218  m_polarRadius = new Distance(polarRadius);
219 
220  m_errors = errors;
221 
222  if (latType == Planetocentric) {
223  setPlanetocentric(latitude, latitudeUnits);
224  }
225  else if (latType == Planetographic) {
226  setPlanetographic(latitude, latitudeUnits);
227  }
228  else {
229  QString msg = "Enumeration value [" + toString(latType) + "] is not a valid CoordinateType";
230  throw IException(IException::Programmer, msg, _FILEINFO_);
231  }
232  }
233 
234 
240  Latitude::Latitude(const Latitude &latitudeToCopy) : Angle(latitudeToCopy) {
241 
242  m_equatorialRadius = NULL;
243  m_polarRadius = NULL;
244 
245  m_errors = latitudeToCopy.m_errors;
246 
247  if (latitudeToCopy.m_equatorialRadius) {
248  m_equatorialRadius = new Distance(*latitudeToCopy.m_equatorialRadius);
249  }
250 
251  if (latitudeToCopy.m_polarRadius) {
252  m_polarRadius = new Distance(*latitudeToCopy.m_polarRadius);
253  }
254  }
255 
256 
261  if (m_equatorialRadius) {
262  delete m_equatorialRadius;
263  m_equatorialRadius = NULL;
264  }
265 
266  if (m_polarRadius) {
267  delete m_polarRadius;
268  m_polarRadius = NULL;
269  }
270  }
271 
272 
283  return angle(units);
284  }
285 
286 
293  void Latitude::setPlanetocentric(double latitude, Angle::Units units) {
294  setAngle(latitude, units);
295  }
296 
297 
316 
317  if (m_equatorialRadius == NULL || m_polarRadius == NULL) {
318  QString msg = "Latitude [" + toString(true) + "] cannot "
319  "be converted to Planetographic without the planetary radii, please "
320  "use the other Latitude constructor.";
321  throw IException(IException::Programmer, msg, _FILEINFO_);
322  }
323 
324  if (*this > Angle(90.0, Angle::Degrees) ||
325  *this < Angle(-90.0, Angle::Degrees)) {
326  QString msg = "Latitudes outside of the -90/90 range cannot be converted "
327  "between Planetographic and Planetocentric";
328  throw IException(IException::Programmer, msg, _FILEINFO_);
329  }
330 
331  if (!isValid()) {
332  QString msg = "Invalid planetographic latitudes are not currently "
333  "supported";
334  throw IException(IException::Programmer, msg, _FILEINFO_);
335  }
336 
337  double ographicLatitude = atan(tan(radians()) *
340 
341  // This theoretically should just be an angle, but make it a Latitude so
342  // we can access angle
343  return Latitude(ographicLatitude, Angle::Radians).angle(units);
344  }
345 
346 
360  void Latitude::setPlanetographic(double latitude, Angle::Units units) {
361 
362  if (m_equatorialRadius == NULL || m_polarRadius == NULL) {
363  QString msg = "Latitude [" + Isis::toString(latitude) + " degrees] cannot be "
364  "converted to Planetocentic without the planetary radii, please use "
365  "the other Latitude constructor.";
366  throw IException(IException::Programmer, msg, _FILEINFO_);
367  }
368 
369  Angle inputAngle(latitude, units);
370 
371  if (inputAngle > Angle(90.0, Angle::Degrees) ||
372  inputAngle < Angle(-90.0, Angle::Degrees)) {
373  QString msg = "Latitudes outside of the -90/90 range cannot be converted "
374  "between Planetographic and Planetocentric";
375  throw IException(IException::Programmer, msg, _FILEINFO_);
376  }
377 
378  // Since the Angle constructor handles special pixels, we will never get to this line of code
379  // when passing in a special pixel.
380  // Left this here just in case the functionality in Angle changes.
381  if (IsSpecial(latitude)) {
382  QString msg = "Invalid planetographic latitudes are not currently "
383  "supported";
384  throw IException(IException::Programmer, msg, _FILEINFO_);
385  }
386 
387  double ocentricLatitude = atan(tan(inputAngle.radians()) *
390 
391  // Sometimes the trig functions return the negative of the expected value at the pole.
392  if ((ocentricLatitude > 0) != (inputAngle.radians() > 0)) {
393  ocentricLatitude *= -1;
394  }
395 
396  setAngle(ocentricLatitude, Angle::Radians);
397  }
398 
399 
408  return m_errors;
409  }
410 
411 
421  m_errors = errors;
422  }
423 
424 
439  bool Latitude::inRange(Latitude min, Latitude max) const {
440 
441  // Validity check on the range
442  if (min > max) {
443  QString msg = "Minimum latitude [" + min.toString(true) +
444  "] is greater than maximum latitude [" +
445  max.toString(true) + "]";
446  throw IException(IException::User, msg, _FILEINFO_);
447  }
448 
449  // Provide a little wriggle room for precision problems
450  Angle epsilon(DBL_EPSILON, Angle::Degrees);
451  Latitude adjustedMin = min - epsilon;
452  Latitude adjustedMax = max + epsilon;
453 
454  // Is this latitude between the min and the max
455  return *this >= adjustedMin && *this <= adjustedMax;
456  }
457 
458 
467  Latitude& Latitude::operator=(const Latitude & latitudeToCopy) {
468 
469  if (this == &latitudeToCopy) return *this;
470 
471  m_equatorialRadius = NULL;
472  m_polarRadius = NULL;
473 
474  m_errors = latitudeToCopy.m_errors;
475 
476  if (latitudeToCopy.m_equatorialRadius) {
477  m_equatorialRadius = new Distance(*latitudeToCopy.m_equatorialRadius);
478  }
479 
480  if (latitudeToCopy.m_polarRadius) {
481  m_polarRadius = new Distance(*latitudeToCopy.m_polarRadius);
482  }
483 
484  setPlanetocentric(latitudeToCopy.planetocentric());
485 
486  return *this;
487  }
488 
489 
503  Latitude Latitude::add(Angle angleToAdd, PvlGroup mapping) {
504 
505  CoordinateType latType;
506 
507  Distance equatorialRadius;
508  Distance polarRadius;
509  if (mapping.hasKeyword("EquatorialRadius") && mapping.hasKeyword("PolarRadius")) {
510  equatorialRadius = Distance(toDouble(mapping["EquatorialRadius"][0]),
512  polarRadius = Distance(toDouble(mapping["PolarRadius"][0]),
514  }
515  else {
516  try {
517  PvlGroup radiiGrp = Target::radiiGroup(mapping["TargetName"][0]);
518  equatorialRadius = Distance(toDouble(radiiGrp["EquatorialRadius"][0]),
520  polarRadius = Distance(toDouble(radiiGrp["PolarRadius"][0]),
522  }
523  catch (IException &e) {
524  QString msg = "Unable to add angle to Latitude object from given mapping group.";
525  throw IException(e, IException::Unknown, msg, _FILEINFO_);
526  }
527  }
528 
529  if (mapping["LatitudeType"][0] == "Planetocentric")
530  latType = Planetocentric;
531  else if (mapping["LatitudeType"][0] == "Planetographic")
532  latType = Planetographic;
533  else {
534  QString msg = "Latitude type [" + mapping["LatitudeType"][0] + "] is not recognized";
535  throw IException(IException::Programmer, msg, _FILEINFO_);
536  }
537 
538  return add(angleToAdd, equatorialRadius, polarRadius, latType);
539  }
540 
541 
553  Distance equatorialRadius,
554  Distance polarRadius,
555  CoordinateType latType) {
556  Latitude result;
557 
558  switch (latType) {
559  case Planetocentric:
560  result = Latitude(planetocentric() + angleToAdd.radians(), equatorialRadius, polarRadius,
561  latType, Radians, m_errors);
562  break;
563 
564  case Planetographic:
565  result = Latitude(planetographic() + angleToAdd.radians(), equatorialRadius, polarRadius,
566  latType, Radians, m_errors);
567  break;
568  }
569 
570  return result;
571  }
572 
573 
583  void Latitude::setAngle(const double &angle,
584  const Angle::Units &units) {
585 
586  // Check for passing 90 degrees if that error checking is on
588  Angle tmpAngle(angle, units);
589  if (tmpAngle > Angle(90, Angle::Degrees) ||
590  tmpAngle < Angle(-90, Angle::Degrees)) {
591  QString msg = "Latitudes past 90 degrees are not valid. The latitude ["
592  + Isis::toString(tmpAngle.degrees(), 8) + "] is not allowed";
593  throw IException(IException::Programmer, msg, _FILEINFO_);
594  }
595  }
596  Angle::setAngle(angle, units);
597  }
598 }
Isis::Target::radiiGroup
static PvlGroup radiiGroup(QString target)
Creates a Pvl Group with keywords TargetName, EquitorialRadius, and PolarRadius.
Definition: Target.cpp:403
Isis::Angle::Degrees
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition: Angle.h:56
Isis::Angle::toString
virtual QString toString(bool includeUnits=true) const
Get the angle in human-readable form.
Definition: Angle.cpp:243
Isis::Latitude
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:51
Isis::Latitude::add
Latitude add(Angle angleToAdd, PvlGroup mapping)
Adds an angle to this latitude.
Definition: Latitude.cpp:503
Isis::Latitude::m_polarRadius
Distance * m_polarRadius
Used for converting to Planetographic, this is the radius of the target perpendicular to the equatori...
Definition: Latitude.h:171
Isis::Latitude::planetographic
double planetographic(Angle::Units units=Angle::Radians) const
Get the latitude in the planetographic coordinate system.
Definition: Latitude.cpp:315
Isis::IException::Unknown
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:118
Isis::PvlContainer::hasKeyword
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Definition: PvlContainer.cpp:159
Isis::Latitude::~Latitude
~Latitude()
This cleans up the Latitude class.
Definition: Latitude.cpp:260
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::Latitude::Planetographic
@ Planetographic
This is a secondary coordinate system for latitudes.
Definition: Latitude.h:103
Isis::Distance
Distance measurement, usually in meters.
Definition: Distance.h:34
Isis::Latitude::ErrorChecking
ErrorChecking
Some user-configurable error checking parameters.
Definition: Latitude.h:71
Isis::Latitude::setErrorChecking
void setErrorChecking(ErrorChecking errors)
Set the error checking status.
Definition: Latitude.cpp:420
Isis::Latitude::setPlanetographic
void setPlanetographic(double latitude, Angle::Units units=Angle::Radians)
Set the latitude given a value in the Planetographic coordinate system.
Definition: Latitude.cpp:360
Isis::Latitude::setPlanetocentric
void setPlanetocentric(double latitude, Angle::Units units=Angle::Radians)
Set the latitude given a value in the Planetocentric coordinate system.
Definition: Latitude.cpp:293
Isis::Distance::Meters
@ Meters
The distance is being specified in meters.
Definition: Distance.h:43
Isis::Latitude::setAngle
virtual void setAngle(const double &angle, const Angle::Units &units)
Same as planetocentric.
Definition: Latitude.cpp:583
Isis::PvlGroup
Contains multiple PvlContainers.
Definition: PvlGroup.h:41
Isis::Latitude::Planetocentric
@ Planetocentric
This is the universal (and default) latitude coordinate system.
Definition: Latitude.h:91
Isis::Latitude::m_equatorialRadius
Distance * m_equatorialRadius
Used for converting to Planetographic, this is the radius of the target on the equatorial plane.
Definition: Latitude.h:166
Isis::Latitude::operator=
Latitude & operator=(const Latitude &latitudeToCopy)
This assigns another latitude to this one - making this latitude an exact duplicate of the other.
Definition: Latitude.cpp:467
Isis::Angle::Units
Units
The set of usable angle measurement units.
Definition: Angle.h:49
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Angle
Defines an angle and provides unit conversions.
Definition: Angle.h:45
Isis::Latitude::Latitude
Latitude()
Create a blank Latitude object without Planetographic support.
Definition: Latitude.cpp:25
Isis::Latitude::m_errors
ErrorChecking m_errors
This contains which exceptions should not be thrown.
Definition: Latitude.h:174
Isis::Latitude::AllowPastPole
@ AllowPastPole
Don't throw an exception if a latitude beyond -90/90 is found.
Definition: Latitude.h:75
Isis::toDouble
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:149
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::Angle::isValid
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
Definition: Angle.cpp:95
Isis::Angle::Angle
Angle()
Constructs a blank angle object which needs a value to be set in order to do any calculations.
Definition: Angle.cpp:23
Isis::Latitude::planetocentric
double planetocentric(Angle::Units units=Angle::Radians) const
Get the latitude in the planetocentric (universal) coordinate system.
Definition: Latitude.cpp:282
Isis::Angle::degrees
double degrees() const
Get the angle in units of Degrees.
Definition: Angle.h:232
Isis::Angle::setAngle
virtual void setAngle(const double &angle, const Units &unit)
Set angle value in desired units.
Definition: Angle.cpp:323
Isis::Latitude::inRange
bool inRange(Latitude min, Latitude max) const
Checks if this latitude value is within the given range.
Definition: Latitude.cpp:439
Isis::Latitude::errorChecking
ErrorChecking errorChecking() const
Get the error checking status.
Definition: Latitude.cpp:407
Isis::Latitude::CoordinateType
CoordinateType
These are the latitude coordinate systems.
Definition: Latitude.h:85
Isis::Angle::angle
virtual double angle(const Units &unit) const
Return angle value in desired units.
Definition: Angle.cpp:289
Isis::Angle::Radians
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Definition: Angle.h:63
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::IException::User
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition: IException.h:126
Isis::Angle::radians
double radians() const
Convert an angle to a double.
Definition: Angle.h:226