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
20namespace Isis {
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
137
138
147 return angle(units);
148 }
149
150
159 double longitude = angle(units);
160
161 if (!IsSpecial(longitude)) {
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)) {
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
320 bool result = false;
321
322 QList< QPair<Longitude, Longitude> > ranges = to360Range(min, max);
323
324 Longitude thisLon = force360Domain();
325
326 QPair<Longitude, Longitude> range;
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
364 QList< QPair<Longitude, Longitude> > Longitude::to360Range(Longitude startLon, Longitude endLon) {
365
366 QList< QPair<Longitude, Longitude> > range;
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}
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 unitWrapValue(const Units &unit) const
Return wrap value in desired units.
Definition Angle.cpp:266
double degrees() const
Get the angle in units of Degrees.
Definition Angle.h:232
static Angle fullRotation()
Makes an angle to represent a full rotation (0-360 or 0-2pi).
Definition Angle.cpp:106
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
Isis exception class.
Definition IException.h:91
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Adds specific functionality to C++ strings.
Definition IString.h:165
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
double positiveWest(Angle::Units units=Angle::Radians) const
Get the longitude in the PositiveWest coordinate system.
void setPositiveEast(double longitude, Angle::Units units=Angle::Radians)
Set the longitude given a value in the PositiveEast longitude system.
Direction
Possible longitude directions: Is a positive longitude towards east or towards west?
Definition Longitude.h:46
@ PositiveWest
As the longitude increases the actual position is more west.
Definition Longitude.h:50
@ PositiveEast
As the longitude increases the actual position is more east.
Definition Longitude.h:48
void setPositiveWest(double longitude, Angle::Units units=Angle::Radians)
Set the longitude given a value in the PositiveWest longitude system.
Longitude()
Create a blank Longitude object with 0-360 domain.
Definition Longitude.cpp:24
~Longitude()
This cleans up the Longitude class.
Domain
Use LongitudeDomain360 if 0-360 is the primary range of the longitude values with 180 being the 'cent...
Definition Longitude.h:62
@ Domain180
As the longitude increases the actual position is more west.
Definition Longitude.h:66
@ Domain360
As the longitude increases the actual position is more east.
Definition Longitude.h:64
Longitude force180Domain() const
This returns a longitude that is constricted to -180 to 180 degrees.
static QList< QPair< Longitude, Longitude > > to360Range(Longitude startLon, Longitude endLon)
Calculates where the longitude range is in 0-360.
Longitude force360Domain() const
This returns a longitude that is constricted to 0-360 degrees.
Domain m_currentDomain
This is necessary for converting to PositiveWest and back.
Definition Longitude.h:111
double positiveEast(Angle::Units units=Angle::Radians) const
Get the longitude in the PositiveEast coordinate system.
Longitude & operator=(const Longitude &longitudeToCopy)
Same as positiveEast.
bool inRange(Longitude min, Longitude max) const
Checks if this longitude value is within the given range.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
bool IsSpecial(const double d)
Returns if the input pixel is special.
const double PI
The mathematical constant PI.
Definition Constants.h:40