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
20namespace 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
65
66 m_equatorialRadius = NULL;
67 m_polarRadius = NULL;
68
69 m_errors = errors;
70
71 setPlanetocentric(latitude.radians(), Radians);
72 }
73
74
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
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}
Defines an angle and provides unit conversions.
Definition Angle.h:45
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
Definition Angle.cpp:95
Angle()
Constructs a blank angle object which needs a value to be set in order to do any calculations.
Definition Angle.cpp:23
virtual void setAngle(const double &angle, const Units &unit)
Set angle value in desired units.
Definition Angle.cpp:323
double radians() const
Convert an angle to a double.
Definition Angle.h:226
virtual double angle(const Units &unit) const
Return angle value in desired units.
Definition Angle.cpp:289
Units
The set of usable angle measurement units.
Definition Angle.h:49
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Definition Angle.h:63
virtual QString toString(bool includeUnits=true) const
Get the angle in human-readable form.
Definition Angle.cpp:243
Distance measurement, usually in meters.
Definition Distance.h:34
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
This class is designed to encapsulate the concept of a Latitude.
Definition Latitude.h:51
void setPlanetographic(double latitude, Angle::Units units=Angle::Radians)
Set the latitude given a value in the Planetographic coordinate system.
Definition Latitude.cpp:360
Distance * m_equatorialRadius
Used for converting to Planetographic, this is the radius of the target on the equatorial plane.
Definition Latitude.h:166
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
~Latitude()
This cleans up the Latitude class.
Definition Latitude.cpp:260
Latitude add(Angle angleToAdd, PvlGroup mapping)
Adds an angle to this latitude.
Definition Latitude.cpp:503
ErrorChecking
Some user-configurable error checking parameters.
Definition Latitude.h:71
@ AllowPastPole
Don't throw an exception if a latitude beyond -90/90 is found.
Definition Latitude.h:75
CoordinateType
These are the latitude coordinate systems.
Definition Latitude.h:85
@ Planetocentric
This is the universal (and default) latitude coordinate system.
Definition Latitude.h:91
@ Planetographic
This is a secondary coordinate system for latitudes.
Definition Latitude.h:103
bool inRange(Latitude min, Latitude max) const
Checks if this latitude value is within the given range.
Definition Latitude.cpp:439
void setErrorChecking(ErrorChecking errors)
Set the error checking status.
Definition Latitude.cpp:420
Distance * m_polarRadius
Used for converting to Planetographic, this is the radius of the target perpendicular to the equatori...
Definition Latitude.h:171
double planetographic(Angle::Units units=Angle::Radians) const
Get the latitude in the planetographic coordinate system.
Definition Latitude.cpp:315
Latitude()
Create a blank Latitude object without Planetographic support.
Definition Latitude.cpp:25
double planetocentric(Angle::Units units=Angle::Radians) const
Get the latitude in the planetocentric (universal) coordinate system.
Definition Latitude.cpp:282
ErrorChecking m_errors
This contains which exceptions should not be thrown.
Definition Latitude.h:174
void setPlanetocentric(double latitude, Angle::Units units=Angle::Radians)
Set the latitude given a value in the Planetocentric coordinate system.
Definition Latitude.cpp:293
ErrorChecking errorChecking() const
Get the error checking status.
Definition Latitude.cpp:407
virtual void setAngle(const double &angle, const Angle::Units &units)
Same as planetocentric.
Definition Latitude.cpp:583
Contains multiple PvlContainers.
Definition PvlGroup.h:41
static PvlGroup radiiGroup(QString target)
Creates a Pvl Group with keywords TargetName, EquitorialRadius, and PolarRadius.
Definition Target.cpp:428
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
bool IsSpecial(const double d)
Returns if the input pixel is special.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149