Isis 3 Programmer Reference
Longitude.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "Longitude.h"
8 
9 #include <cmath>
10 
11 #include <QtCore>
12 #include <QDebug>
13 
14 #include "Constants.h"
15 #include "IException.h"
16 #include "IString.h"
17 #include "PvlGroup.h"
18 #include "SpecialPixel.h"
19 
20 namespace Isis {
26  }
27 
28 
39  Longitude::Longitude(double longitude, PvlGroup mapping,
40  Angle::Units longitudeUnits) :
41  Angle(longitude, longitudeUnits) {
42  if(mapping["LongitudeDomain"][0] == "360") {
44  }
45  else if(mapping["LongitudeDomain"][0] == "180") {
47  }
48  else {
49  IString msg = "Longitude domain [" +
50  IString(mapping["LongitudeDomain"][0]) + "] not recognized";
51  throw IException(IException::Programmer, msg, _FILEINFO_);
52  }
53 
54  if(mapping["LongitudeDirection"][0] == "PositiveEast") {
55  setPositiveEast(longitude, longitudeUnits);
56  }
57  else if(mapping["LongitudeDirection"][0] == "PositiveWest") {
58  setPositiveWest(longitude, longitudeUnits);
59  }
60  else {
61  IString msg = "Longitude direction [" +
62  IString(mapping["LongitudeDirection"][0]) + "] not recognized";
63  throw IException(IException::Programmer, msg, _FILEINFO_);
64  }
65  }
66 
67 
77  Direction lonDir, Domain lonDomain) :
78  Angle(longitude) {
79  m_currentDomain = lonDomain;
80 
81  if(lonDir == PositiveEast) {
82  setPositiveEast(longitude.radians(), Radians);
83  }
84  else if(lonDir == PositiveWest) {
85  setPositiveWest(longitude.radians(), Radians);
86  }
87  else {
88  IString msg = "Longitude direction [" + IString(lonDir) + "] not valid";
89  throw IException(IException::Programmer, msg, _FILEINFO_);
90  }
91  }
92 
93 
103  Longitude::Longitude(double longitude, Angle::Units longitudeUnits,
104  Direction lonDir, Domain lonDomain) :
105  Angle(longitude, longitudeUnits) {
106  m_currentDomain = lonDomain;
107 
108  if(lonDir == PositiveEast) {
109  setPositiveEast(longitude, longitudeUnits);
110  }
111  else if(lonDir == PositiveWest) {
112  setPositiveWest(longitude, longitudeUnits);
113  }
114  else {
115  IString msg = "Longitude direction [" + IString(lonDir) + "] not valid";
116  throw IException(IException::Programmer, msg, _FILEINFO_);
117  }
118  }
119 
120 
126  Longitude::Longitude(const Longitude &longitudeToCopy)
127  : Angle(longitudeToCopy) {
128  m_currentDomain = longitudeToCopy.m_currentDomain;
129  }
130 
131 
136  }
137 
138 
146  double Longitude::positiveEast(Angle::Units units) const {
147  return angle(units);
148  }
149 
150 
158  double Longitude::positiveWest(Angle::Units units) const {
159  double longitude = angle(units);
160 
161  if (!IsSpecial(longitude)) {
162  if(m_currentDomain == Domain360) {
163  double wrapPoint = unitWrapValue(units);
164  double halfWrap = wrapPoint / 2.0;
165 
166  int numPlanetWraps = qFloor(longitude / wrapPoint);
167 
168  // If the input is 360, then we want numPlanetWraps == 0. Compare the input to the border
169  // case (wraps * wrapPoint == longitude) and bring the number of wraps down if it's true.
170  // If it's false, then the rounding already took care of this border case.
171  if (numPlanetWraps != 0 && qFuzzyCompare(numPlanetWraps * wrapPoint, longitude)) {
172  if (numPlanetWraps > 0)
173  numPlanetWraps--;
174  else
175  numPlanetWraps++;
176  }
177 
178  longitude -= numPlanetWraps * wrapPoint;
179  longitude = -(longitude - halfWrap) + halfWrap;
180  longitude -= numPlanetWraps * wrapPoint;
181  }
182  else {
183  // 180 domain is just a negation in this conversion,
184  // no more work needs done
185  longitude = -1 * longitude;
186  }
187  }
188 
189  return longitude;
190  }
191 
192 
199  void Longitude::setPositiveEast(double longitude, Angle::Units units) {
200  setAngle(longitude, units);
201  }
202 
203 
210  void Longitude::setPositiveWest(double longitude, Angle::Units units) {
211  if(!IsSpecial(longitude)) {
212  if(m_currentDomain == Domain360) {
213  // Same as positiveWest
214  double wrapPoint = unitWrapValue(units);
215  double halfWrap = wrapPoint / 2.0;
216 
217  int numPlanetWraps = qFloor(longitude / wrapPoint);
218 
219  // If the input is 360, then we want numPlanetWraps == 0. Compare the input to the border
220  // case (wraps * wrapPoint == longitude) and bring the number of wraps down if it's true.
221  // If it's false, then the rounding already took care of this border case.
222  if (numPlanetWraps != 0 && qFuzzyCompare(numPlanetWraps * wrapPoint, longitude)) {
223  if (numPlanetWraps > 0)
224  numPlanetWraps--;
225  else
226  numPlanetWraps++;
227  }
228 
229 
230  longitude -= numPlanetWraps * wrapPoint;
231  longitude = -(longitude - halfWrap) + halfWrap;
232  longitude -= numPlanetWraps * wrapPoint;
233  }
234  else {
235  // 180 domain is just a negation in this conversion,
236  // no more work needs done
237  longitude = -1 * longitude;
238  }
239  }
240 
241  setAngle(longitude, units);
242  }
243 
244 
252  Longitude& Longitude::operator=(const Longitude & longitudeToCopy) {
253  if(this == &longitudeToCopy) return *this;
254 
255  m_currentDomain = longitudeToCopy.m_currentDomain;
256  setPositiveEast(longitudeToCopy.positiveEast());
257 
258  return *this;
259  }
260 
261 
268  if(!isValid()) return Longitude();
269 
270  double resultantLongitude = angle(Angle::Degrees);
271 
272  // Bring the number in the 0 to 360 range
273  if (qFuzzyCompare(degrees(), 360.0)) {
274  resultantLongitude = 360.0;
275  }
276  else {
277  resultantLongitude -= 360 * qFloor(resultantLongitude / 360);
278  }
279 
280  return Longitude(resultantLongitude, Angle::Degrees);
281  }
282 
283 
290  if(!isValid()) return Longitude();
291 
292  Longitude forced = force360Domain();
293 
294  if(forced.degrees() > 180.0)
295  forced -= Angle(360.0, Angle::Degrees);
296 
297  return forced;
298  }
299 
300 
319  bool Longitude::inRange(Longitude min, Longitude max) const {
320  bool result = false;
321 
322  QList< QPair<Longitude, Longitude> > ranges = to360Range(min, max);
323 
324  Longitude thisLon = force360Domain();
325 
327  foreach (range, ranges) {
328  if (thisLon >= range.first && thisLon <= range.second) {
329  result = true;
330  }
331 
332  double thisLonRadians = thisLon.radians();
333  double rangeStartRadians = range.first.radians();
334  double rangeEndRadians = range.second.radians();
335  // Check equality on edges of range
336  if (qFuzzyCompare(thisLonRadians, rangeStartRadians) ||
337  qFuzzyCompare(thisLonRadians, rangeEndRadians)) {
338  result = true;
339  }
340 
341  // Be very careful at the 0-360 boundary
342  if ((qFuzzyCompare(thisLonRadians, 0.0) || qFuzzyCompare(thisLonRadians, 2.0 * PI)) &&
343  (qFuzzyCompare(rangeStartRadians, 0.0) ||
344  qFuzzyCompare(rangeEndRadians, 2.0 * PI))) {
345  result = true;
346  }
347  }
348 
349  return result;
350  }
351 
365 
367 
368  if (startLon.isValid() && endLon.isValid() && startLon < endLon) {
369 
370  int multiplier = floor(startLon / fullRotation());
371 
372  startLon -= multiplier * fullRotation();
373  endLon -= multiplier * fullRotation();
374 
375  if (endLon > fullRotation()) {
376 
377  Longitude startLon2(0, Angle::Degrees);
378  Longitude endLon2(endLon - fullRotation());
379 
380  if (endLon2 < startLon) {
381  range.append(qMakePair(startLon2, endLon2));
382  }
383  else {
384  startLon = Longitude(0, Angle::Degrees);
385  }
386  endLon = Longitude(360, Angle::Degrees);
387  }
388  startLon = Longitude((Angle)startLon);
389  endLon = Longitude((Angle)endLon);
390 
391  range.append(qMakePair(startLon, endLon));
392  }
393  return range;
394  }
395 }
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::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
QList
This is free and unencumbered software released into the public domain.
Definition: BoxcarCachingAlgorithm.h:13
Isis::Longitude::positiveWest
double positiveWest(Angle::Units units=Angle::Radians) const
Get the longitude in the PositiveWest coordinate system.
Definition: Longitude.cpp:158
Isis::Longitude::positiveEast
double positiveEast(Angle::Units units=Angle::Radians) const
Get the longitude in the PositiveEast coordinate system.
Definition: Longitude.cpp:146
Isis::Longitude::operator=
Longitude & operator=(const Longitude &longitudeToCopy)
Same as positiveEast.
Definition: Longitude.cpp:252
Isis::Longitude::Domain180
@ Domain180
As the longitude increases the actual position is more west.
Definition: Longitude.h:66
Isis::Longitude::Domain360
@ Domain360
As the longitude increases the actual position is more east.
Definition: Longitude.h:64
Isis::Angle::unitWrapValue
double unitWrapValue(const Units &unit) const
Return wrap value in desired units.
Definition: Angle.cpp:266
Isis::Longitude::force180Domain
Longitude force180Domain() const
This returns a longitude that is constricted to -180 to 180 degrees.
Definition: Longitude.cpp:289
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::Longitude::setPositiveEast
void setPositiveEast(double longitude, Angle::Units units=Angle::Radians)
Set the longitude given a value in the PositiveEast longitude system.
Definition: Longitude.cpp:199
Isis::Longitude
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:40
Isis::Longitude::m_currentDomain
Domain m_currentDomain
This is necessary for converting to PositiveWest and back.
Definition: Longitude.h:111
Isis::Longitude::~Longitude
~Longitude()
This cleans up the Longitude class.
Definition: Longitude.cpp:135
Isis::PvlGroup
Contains multiple PvlContainers.
Definition: PvlGroup.h:41
Isis::Longitude::setPositiveWest
void setPositiveWest(double longitude, Angle::Units units=Angle::Radians)
Set the longitude given a value in the PositiveWest longitude system.
Definition: Longitude.cpp:210
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::Longitude::Direction
Direction
Possible longitude directions: Is a positive longitude towards east or towards west?
Definition: Longitude.h:46
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::Longitude::to360Range
static QList< QPair< Longitude, Longitude > > to360Range(Longitude startLon, Longitude endLon)
Calculates where the longitude range is in 0-360.
Definition: Longitude.cpp:364
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
QPair
This is free and unencumbered software released into the public domain.
Definition: CubeIoHandler.h:23
Isis::Angle::fullRotation
static Angle fullRotation()
Makes an angle to represent a full rotation (0-360 or 0-2pi).
Definition: Angle.cpp:106
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::Longitude::PositiveWest
@ PositiveWest
As the longitude increases the actual position is more west.
Definition: Longitude.h:50
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::Longitude::Domain
Domain
Use LongitudeDomain360 if 0-360 is the primary range of the longitude values with 180 being the 'cent...
Definition: Longitude.h:62
Isis::Longitude::Longitude
Longitude()
Create a blank Longitude object with 0-360 domain.
Definition: Longitude.cpp:24
Isis::Longitude::force360Domain
Longitude force360Domain() const
This returns a longitude that is constricted to 0-360 degrees.
Definition: Longitude.cpp:267
Isis::Longitude::PositiveEast
@ PositiveEast
As the longitude increases the actual position is more east.
Definition: Longitude.h:48
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::Longitude::inRange
bool inRange(Longitude min, Longitude max) const
Checks if this longitude value is within the given range.
Definition: Longitude.cpp:319
Isis::Angle::radians
double radians() const
Convert an angle to a double.
Definition: Angle.h:226