LSSTApplications  12.1-5-gbdcc3ab+2,15.0+14,15.0+30,15.0-1-g19261fa+21,15.0-1-g417ea41,15.0-1-g60afb23+30,15.0-1-g615e0bb+22,15.0-1-g788a293+30,15.0-1-ga91101e+30,15.0-1-gae1598d+13,15.0-1-gd076f1f+28,15.0-1-gdf18595+5,15.0-12-g3681e7a+8,15.0-12-g7952b551+2,15.0-16-g6f0eb036+3,15.0-17-g076ea75+3,15.0-2-g100d730+23,15.0-2-g8aea5f4+1,15.0-2-gf38729e+25,15.0-2-gf60f3cf,15.0-3-g707930d+3,15.0-3-g9103c06+12,15.0-30-g9378914ca+1,15.0-4-g9ee0f43+3,15.0-4-gf6f1c6c+3,15.0-4-gf906033+2,15.0-5-g23e394c+18,15.0-5-g4be42a9+4,15.0-5-gae1eaf0+3,15.0-6-g09241ba+6,15.0-6-g69628aa+4,15.0-6-g81517ef+3,15.0-6-gc1213af+3,15.0-6-gfa9b38f+8,15.0-7-ged79c87+3,15.0-8-g13fca11+3,15.0-8-g67a62d3+5,15.0-8-gcf05001+5,15.0-9-g1e7c341+2,w.2018.25
LSSTDataManagementBasePackage
Angle.h
Go to the documentation of this file.
1 /*
2  * Developed for the LSST Data Management System.
3  * This product includes software developed by the LSST Project
4  * (https://www.lsst.org).
5  * See the COPYRIGHT file at the top-level directory of this distribution
6  * for details of code ownership.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 #ifndef LSST_GEOM_ANGLE_H
22 #define LSST_GEOM_ANGLE_H
23 
24 #include <cmath>
25 #include <iostream>
26 #include <type_traits>
27 
28 #include "boost/math/constants/constants.hpp"
29 
30 namespace lsst {
31 namespace geom {
32 
33 /*
34  * None of C99, C++98, and C++11 define M_PI, so we'll do it ourselves
35  */
36 #pragma clang diagnostic push
37 #pragma clang diagnostic ignored "-Wunused-variable"
38 double constexpr PI = boost::math::constants::pi<double>();
40 double constexpr TWOPI = boost::math::constants::pi<double>() * 2.0;
41 double constexpr HALFPI = boost::math::constants::pi<double>() * 0.5;
42 double constexpr ONE_OVER_PI = 1.0 / boost::math::constants::pi<double>();
43 // sqrt is not a constexpr on OS X
44 double const SQRTPI = sqrt(boost::math::constants::pi<double>());
45 double const INVSQRTPI = 1.0 / sqrt(boost::math::constants::pi<double>());
46 double constexpr ROOT2 = boost::math::constants::root_two<double>(); // sqrt(2)
47 #pragma clang diagnostic pop
48 
49 // These shouldn't be necessary if the Angle class is used, but sometimes you just need
50 // them. Better to define them once here than have *180/PI throughout the code...
51 inline constexpr double degToRad(double x) noexcept { return x * PI / 180.; }
52 inline constexpr double radToDeg(double x) noexcept { return x * 180. / PI; }
53 inline constexpr double radToArcsec(double x) noexcept { return x * 3600. * 180. / PI; }
54 inline constexpr double radToMas(double x) noexcept { return x * 1000. * 3600. * 180. / PI; }
55 inline constexpr double arcsecToRad(double x) noexcept { return (x / 3600.) * PI / 180.; }
56 inline constexpr double masToRad(double x) noexcept { return (x / (1000. * 3600.)) * PI / 180.; }
57 
58 class Angle;
70 class AngleUnit final {
71  friend class Angle;
72  template <typename T>
73  friend constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept;
74 
75 public:
83  // Current implementation does not throw exceptions, but somebody may want
84  // to add input validation later
85  explicit constexpr AngleUnit(double val) : _val(val) {}
86 
95  constexpr bool operator==(AngleUnit const& rhs) const noexcept;
96 
97 private:
98  double _val;
99 };
100 
101 inline constexpr bool AngleUnit::operator==(AngleUnit const& rhs) const noexcept {
102  return (_val == rhs._val);
103 }
104 
105 AngleUnit constexpr radians = AngleUnit(1.0);
106 AngleUnit constexpr degrees = AngleUnit(PI / 180.0);
107 AngleUnit constexpr hours = AngleUnit(PI * 15.0 / 180.0);
108 AngleUnit constexpr arcminutes = AngleUnit(PI / 60 / 180.0);
109 AngleUnit constexpr arcseconds = AngleUnit(PI / 180.0 / 3600.0);
110 
120 class Angle final {
121  friend class AngleUnit;
122 
123 public:
129  explicit constexpr Angle(double val, AngleUnit units = radians) noexcept : _val(val * units._val) {}
130 
132  constexpr Angle() noexcept : _val(0) {}
133 
135  constexpr Angle(Angle const& other) noexcept = default;
136 
138  constexpr Angle(Angle&& other) noexcept = default;
139 
141  Angle& operator=(Angle const& other) noexcept = default;
142 
144  Angle& operator=(Angle&& other) noexcept = default;
145 
146  ~Angle() = default;
147 
149  constexpr operator double() const noexcept { return _val; }
150 
156  constexpr double asAngularUnits(AngleUnit const& units) const noexcept { return _val / units._val; }
157 
159  constexpr double asRadians() const noexcept { return asAngularUnits(radians); }
160 
162  constexpr double asDegrees() const noexcept { return asAngularUnits(degrees); }
163 
165  constexpr double asHours() const noexcept { return asAngularUnits(hours); }
166 
168  constexpr double asArcminutes() const noexcept { return asAngularUnits(arcminutes); }
169 
171  constexpr double asArcseconds() const noexcept { return asAngularUnits(arcseconds); }
172 
185  Angle wrap() const noexcept;
186 
199  Angle wrapCtr() const noexcept;
200 
213  Angle wrapNear(Angle const& refAng) const noexcept;
214 
223  Angle separation(Angle const& other) const noexcept;
224 
225 #define ANGLE_OPUP_TYPE(OP, TYPE) \
226  Angle& operator OP(TYPE const& d) noexcept { \
227  _val OP d; \
228  return *this; \
229  }
230 
232  ANGLE_OPUP_TYPE(*=, double)
236 
237  ANGLE_OPUP_TYPE(+=, double)
239  ANGLE_OPUP_TYPE(+=, int)
241 
242  ANGLE_OPUP_TYPE(-=, double)
244  ANGLE_OPUP_TYPE(-=, int)
246 
247 #undef ANGLE_OPUP_TYPE
248 
249 #define ANGLE_COMP(OP) \
250  constexpr bool operator OP(const Angle& rhs) const noexcept { return _val OP rhs._val; }
251 
253  ANGLE_COMP(==)
257 
258  ANGLE_COMP(<=)
264 
265 #undef ANGLE_COMP
266 
267 private:
268  double _val;
269 };
270 
271 /*
272  * Operators for Angles.
273  */
274 #define ANGLE_OP(OP) \
275  inline constexpr Angle operator OP(Angle a, Angle d) noexcept { \
276  return Angle(static_cast<double>(a) OP static_cast<double>(d)); \
277  }
278 
279 // We need both int and double versions to avoid ambiguous overloading due to
280 // implicit conversion of Angle to double
281 #define ANGLE_OP_TYPE(OP, TYPE) \
282  inline constexpr Angle operator OP(Angle a, TYPE d) noexcept { \
283  return Angle(static_cast<double>(a) OP d); \
284  } \
285  \
286  inline constexpr Angle operator OP(TYPE d, Angle a) noexcept { \
287  return Angle(d OP static_cast<double>(a)); \
288  }
289 
311 
316 ANGLE_OP_TYPE(*, double)
319 
320 #undef ANGLE_OP
321 #undef ANGLE_OP_TYPE
322 
328 inline constexpr Angle operator-(Angle angle) { return Angle(-static_cast<double>(angle)); }
329 
330 // Apparently @relatesalso doesn't work with grouping
336 inline constexpr Angle operator/(Angle a, int d) noexcept { return Angle(static_cast<double>(a) / d); }
337 
343 inline constexpr Angle operator/(Angle a, double d) noexcept { return Angle(static_cast<double>(a) / d); }
344 
345 // Division is different. Don't allow division by an Angle
346 template <typename T>
347 constexpr double operator/(T const lhs, Angle rhs) noexcept = delete;
348 
364 
366 template <typename T>
367 inline constexpr bool isAngle(T) noexcept {
369 };
370 
381 template <typename T>
382 inline constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept {
383  static_assert(std::is_arithmetic<T>::value,
384  "Only numeric types may be multiplied by an AngleUnit to create an Angle!");
385  return Angle(lhs * rhs._val);
386 }
387 
388 // Inline method definitions, placed last in order to benefit from Angle's full API
389 
390 inline Angle Angle::wrap() const noexcept {
391  double wrapped = std::fmod(_val, TWOPI);
392  // wrapped is in the range (-TWOPI, TWOPI)
393  if (wrapped < 0.0) wrapped += TWOPI;
394  // if wrapped is small enough, adding 2 pi gives 2 pi
395  if (wrapped >= TWOPI) wrapped = 0.0;
396  return wrapped * radians;
397 }
398 
399 inline Angle Angle::wrapCtr() const noexcept {
400  double wrapped = std::fmod(_val, TWOPI);
401  // wrapped is in the range [-TWOPI, TWOPI]
402  if (wrapped < -PI) {
403  wrapped += TWOPI;
404  if (wrapped >= PI) {
405  // handle roundoff error, however unlikely
406  wrapped = -PI;
407  }
408  } else if (wrapped >= PI) {
409  wrapped -= TWOPI;
410  if (wrapped < -PI) {
411  // handle roundoff error, however unlikely
412  wrapped = -PI;
413  }
414  }
415  return wrapped * radians;
416 }
417 
418 inline Angle Angle::wrapNear(Angle const& refAng) const noexcept {
419  // compute (this - refAng).wrapCtr() + refAng
420  // which is correct except for roundoff error at the edges
421  double const refAngRad = refAng.asRadians();
422  double wrapped = (*this - refAng).wrapCtr().asRadians() + refAngRad;
423 
424  // roundoff can cause slightly out-of-range values; fix those as bast we can;
425  // note that both conditionals are wanted, since either or both may execute
426  // (though if/else could be used if the lower limit was squishy for radians)
427  if (wrapped - refAngRad >= PI) {
428  wrapped -= TWOPI;
429  }
430  if (wrapped - refAngRad < -PI) {
431  wrapped += TWOPI;
432  }
433  return wrapped * radians;
434 }
435 
436 inline Angle Angle::separation(Angle const& other) const noexcept { return (*this - other).wrapCtr(); }
437 
438 } // namespace geom
439 } // namespace lsst
440 
441 #endif // if !defined(LSST_GEOM_ANGLE_H)
constexpr double asAngularUnits(AngleUnit const &units) const noexcept
Return an Angle&#39;s value in the specified units.
Definition: Angle.h:156
AngleUnit constexpr arcminutes
constant with units of arcminutes
Definition: Angle.h:108
constexpr double asRadians() const noexcept
Return an Angle&#39;s value in radians.
Definition: Angle.h:159
#define ANGLE_COMP(OP)
Definition: Angle.h:249
friend class Angle
Definition: Angle.h:71
constexpr double asDegrees() const noexcept
Return an Angle&#39;s value in degrees.
Definition: Angle.h:162
double constexpr TWOPI
Definition: Angle.h:40
AngleUnit constexpr hours
constant with units of hours
Definition: Angle.h:107
constexpr double radToDeg(double x) noexcept
Definition: Angle.h:52
T fmod(T... args)
table::Key< int > a
Angle separation(Angle const &other) const noexcept
The signed difference between two Angles.
Definition: Angle.h:436
ImageT val
Definition: CR.cc:146
def wrap(ctrl)
Definition: wrap.py:250
AngleUnit constexpr radians
constant with units of radians
Definition: Angle.h:105
A class representing an angle.
Definition: Angle.h:120
Angle wrapCtr() const noexcept
Wrap this angle to the range [-π, π).
Definition: Angle.h:399
constexpr double radToArcsec(double x) noexcept
Definition: Angle.h:53
double constexpr ONE_OVER_PI
Definition: Angle.h:42
constexpr Angle operator-(Angle a, Angle d) noexcept
Difference of two angles.
Definition: Angle.h:301
AngleUnit constexpr degrees
constant with units of degrees
Definition: Angle.h:106
A base class for image defects.
Definition: cameraGeom.dox:3
constexpr double asHours() const noexcept
Return an Angle&#39;s value in hours.
Definition: Angle.h:165
AngleUnit constexpr arcseconds
constant with units of arcseconds
Definition: Angle.h:109
constexpr Angle() noexcept
Construct the zero angle.
Definition: Angle.h:132
constexpr double degToRad(double x) noexcept
Definition: Angle.h:51
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
#define ANGLE_OP(OP)
Definition: Angle.h:274
solver_t * s
constexpr double asArcseconds() const noexcept
Return an Angle&#39;s value in arcseconds.
Definition: Angle.h:171
double x
constexpr Angle(double val, AngleUnit units=radians) noexcept
Construct an Angle with the specified value (interpreted in the given units).
Definition: Angle.h:129
Angle wrapNear(Angle const &refAng) const noexcept
Wrap this angle to a value x such that -π ≤ x - refAng ≤ π, approximately.
Definition: Angle.h:418
double const INVSQRTPI
Definition: Angle.h:45
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition: Angle.h:336
constexpr bool operator==(AngleUnit const &rhs) const noexcept
Test if two units are the same.
Definition: Angle.h:101
double constexpr HALFPI
Definition: Angle.h:41
friend constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept
Use AngleUnit to convert a POD (e.g. int, double) to an Angle; e.g. 180*degrees.
Definition: Angle.h:382
constexpr double radToMas(double x) noexcept
Definition: Angle.h:54
double const SQRTPI
Definition: Angle.h:44
ItemVariant const * other
Definition: Schema.cc:55
constexpr double asArcminutes() const noexcept
Return an Angle&#39;s value in arcminutes.
Definition: Angle.h:168
constexpr AngleUnit(double val)
Define a new angle unit.
Definition: Angle.h:85
Angle wrap() const noexcept
Wrap this angle to the range [0, 2π).
Definition: Angle.h:390
constexpr bool isAngle(T) noexcept
Allow a user to check if they have an angle.
Definition: Angle.h:367
constexpr double masToRad(double x) noexcept
Definition: Angle.h:56
constexpr double arcsecToRad(double x) noexcept
Definition: Angle.h:55
STL class.
double constexpr ROOT2
Definition: Angle.h:46
#define ANGLE_OP_TYPE(OP, TYPE)
Definition: Angle.h:281
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition: Angle.h:225
double constexpr PI
The ratio of a circle&#39;s circumference to diameter.
Definition: Angle.h:39
A class used to convert scalar POD types such as double to Angle.
Definition: Angle.h:70