LSSTApplications  11.0-24-g0a022a1,15.0+13,15.0+9,15.0-1-g19261fa+5,15.0-1-g1eca518+15,15.0-1-g60afb23+12,15.0-1-g615e0bb+4,15.0-1-g6668b0b+5,15.0-1-g788a293+12,15.0-1-ga91101e+12,15.0-1-gae1598d+8,15.0-1-gc45031d+15,15.0-1-gd076f1f+12,15.0-1-gdf18595+2,15.0-1-gf4f1c34+8,15.0-2-g100d730+5,15.0-2-g18f3f21+5,15.0-2-g35685a8+6,15.0-2-gf38729e+5,15.0-21-g91b8abf62,15.0-3-g150fc43+14,15.0-3-g6f085af+5,15.0-3-g707930d,15.0-3-g9103c06+8,15.0-3-ga03b4ca+16,15.0-3-gaec6799+5,15.0-3-gb7a597c+12,15.0-3-ge6a6747+5,15.0-4-g45f767a+8,15.0-4-g654b129+10,15.0-4-gf5d1e39,15.0-4-gff20472+15,15.0-5-ga70c291+5,15.0-6-g9a9df217+5,15.0-7-gab4c137+6,15.0-7-gab79a70c+4
LSSTDataManagementBasePackage
Angle.h
Go to the documentation of this file.
1 #if !defined(LSST_AFW_GEOM_ANGLE_H)
2 #define LSST_AFW_GEOM_ANGLE_H
3 
4 #include <iostream>
5 #include <type_traits>
6 
7 #include <cmath>
8 
9 #include "boost/math/constants/constants.hpp"
10 
11 namespace lsst {
12 namespace afw {
13 namespace geom {
14 
15 /*
16  * None of C99, C++98, and C++11 define M_PI, so we'll do it ourselves
17  */
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wunused-variable"
20 double constexpr PI = boost::math::constants::pi<double>();
22 double constexpr TWOPI = boost::math::constants::pi<double>() * 2.0;
23 double constexpr HALFPI = boost::math::constants::pi<double>() * 0.5;
24 double constexpr ONE_OVER_PI = 1.0 / boost::math::constants::pi<double>();
25 // sqrt is not a constexpr on OS X
26 double const SQRTPI = sqrt(boost::math::constants::pi<double>());
27 double const INVSQRTPI = 1.0 / sqrt(boost::math::constants::pi<double>());
28 double constexpr ROOT2 = boost::math::constants::root_two<double>(); // sqrt(2)
29 #pragma clang diagnostic pop
30 
31 // These shouldn't be necessary if the Angle class is used, but sometimes you just need
32 // them. Better to define them once here than have *180/PI throughout the code...
33 inline constexpr double degToRad(double x) noexcept { return x * PI / 180.; }
34 inline constexpr double radToDeg(double x) noexcept { return x * 180. / PI; }
35 inline constexpr double radToArcsec(double x) noexcept { return x * 3600. * 180. / PI; }
36 inline constexpr double radToMas(double x) noexcept { return x * 1000. * 3600. * 180. / PI; }
37 inline constexpr double arcsecToRad(double x) noexcept { return (x / 3600.) * PI / 180.; }
38 inline constexpr double masToRad(double x) noexcept { return (x / (1000. * 3600.)) * PI / 180.; }
39 
40 class Angle;
52 class AngleUnit final {
53  friend class Angle;
54  template <typename T>
55  friend constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept;
56 
57 public:
65  // Current implementation does not throw exceptions, but somebody may want
66  // to add input validation later
67  explicit constexpr AngleUnit(double val) : _val(val) {}
68 
77  constexpr bool operator==(AngleUnit const& rhs) const noexcept;
78 
79 private:
80  double _val;
81 };
82 
83 inline constexpr bool AngleUnit::operator==(AngleUnit const& rhs) const noexcept {
84  return (_val == rhs._val);
85 }
86 
87 AngleUnit constexpr radians = AngleUnit(1.0);
88 AngleUnit constexpr degrees = AngleUnit(PI / 180.0);
89 AngleUnit constexpr hours = AngleUnit(PI * 15.0 / 180.0);
90 AngleUnit constexpr arcminutes = AngleUnit(PI / 60 / 180.0);
91 AngleUnit constexpr arcseconds = AngleUnit(PI / 180.0 / 3600.0);
92 
102 class Angle final {
103  friend class AngleUnit;
104 
105 public:
111  explicit constexpr Angle(double val, AngleUnit units = radians) noexcept : _val(val* units._val) {}
112 
114  constexpr Angle() noexcept : _val(0) {}
115 
117  constexpr Angle(Angle const& other) noexcept = default;
118 
120  constexpr Angle(Angle&& other) noexcept = default;
121 
123  Angle& operator=(Angle const& other) noexcept = default;
124 
126  Angle& operator=(Angle&& other) noexcept = default;
127 
128  ~Angle() = default;
129 
131  constexpr operator double() const noexcept { return _val; }
132 
138  constexpr double asAngularUnits(AngleUnit const& units) const noexcept { return _val / units._val; }
139 
141  constexpr double asRadians() const noexcept { return asAngularUnits(radians); }
142 
144  constexpr double asDegrees() const noexcept { return asAngularUnits(degrees); }
145 
147  constexpr double asHours() const noexcept { return asAngularUnits(hours); }
148 
150  constexpr double asArcminutes() const noexcept { return asAngularUnits(arcminutes); }
151 
153  constexpr double asArcseconds() const noexcept { return asAngularUnits(arcseconds); }
154 
167  Angle wrap() const noexcept;
168 
181  Angle wrapCtr() const noexcept;
182 
195  Angle wrapNear(Angle const& refAng) const noexcept;
196 
205  Angle separation(Angle const& other) const noexcept;
206 
207 #define ANGLE_OPUP_TYPE(OP, TYPE) \
208  Angle& operator OP(TYPE const& d) noexcept { \
209  _val OP d; \
210  return *this; \
211  }
212 
214  ANGLE_OPUP_TYPE(*=, double)
218 
219  ANGLE_OPUP_TYPE(+=, double)
221  ANGLE_OPUP_TYPE(+=, int)
223 
224  ANGLE_OPUP_TYPE(-=, double)
226  ANGLE_OPUP_TYPE(-=, int)
228 
229 #undef ANGLE_OPUP_TYPE
230 
231 #define ANGLE_COMP(OP) \
232  constexpr bool operator OP(const Angle& rhs) const noexcept { return _val OP rhs._val; }
233 
235  ANGLE_COMP(==)
239 
240  ANGLE_COMP(<=)
246 
247 #undef ANGLE_COMP
248 
249 private:
250  double _val;
251 };
252 
253 /*
254  * Operators for Angles.
255  */
256 #define ANGLE_OP(OP) \
257  inline constexpr Angle operator OP(Angle a, Angle d) noexcept { \
258  return Angle(static_cast<double>(a) OP static_cast<double>(d)); \
259  }
260 
261 // We need both int and double versions to avoid ambiguous overloading due to
262 // implicit conversion of Angle to double
263 #define ANGLE_OP_TYPE(OP, TYPE) \
264  inline constexpr Angle operator OP(Angle a, TYPE d) noexcept { \
265  return Angle(static_cast<double>(a) OP d); \
266  } \
267  \
268  inline constexpr Angle operator OP(TYPE d, Angle a) noexcept { \
269  return Angle(d OP static_cast<double>(a)); \
270  }
271 
293 
298 ANGLE_OP_TYPE(*, double)
301 
302 #undef ANGLE_OP
303 #undef ANGLE_OP_TYPE
304 
310 inline constexpr Angle operator-(Angle angle) { return Angle(-static_cast<double>(angle)); }
311 
312 // Apparently @relatesalso doesn't work with grouping
318 inline constexpr Angle operator/(Angle a, int d) noexcept { return Angle(static_cast<double>(a) / d); }
319 
325 inline constexpr Angle operator/(Angle a, double d) noexcept { return Angle(static_cast<double>(a) / d); }
326 
327 // Division is different. Don't allow division by an Angle
328 template <typename T>
329 constexpr double operator/(T const lhs, Angle rhs) noexcept = delete;
330 
346 
348 template <typename T>
349 inline constexpr bool isAngle(T) noexcept {
351 };
352 
363 template <typename T>
364 inline constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept {
365  static_assert(std::is_arithmetic<T>::value,
366  "Only numeric types may be multiplied by an AngleUnit to create an Angle!");
367  return Angle(lhs * rhs._val);
368 }
369 
370 // Inline method definitions, placed last in order to benefit from Angle's full API
371 
372 inline Angle Angle::wrap() const noexcept {
373  double wrapped = std::fmod(_val, TWOPI);
374  // wrapped is in the range (-TWOPI, TWOPI)
375  if (wrapped < 0.0) wrapped += TWOPI;
376  // if wrapped is small enough, adding 2 pi gives 2 pi
377  if (wrapped >= TWOPI) wrapped = 0.0;
378  return wrapped * radians;
379 }
380 
381 inline Angle Angle::wrapCtr() const noexcept {
382  double wrapped = std::fmod(_val, TWOPI);
383  // wrapped is in the range [-TWOPI, TWOPI]
384  if (wrapped < -PI) {
385  wrapped += TWOPI;
386  if (wrapped >= PI) {
387  // handle roundoff error, however unlikely
388  wrapped = -PI;
389  }
390  } else if (wrapped >= PI) {
391  wrapped -= TWOPI;
392  if (wrapped < -PI) {
393  // handle roundoff error, however unlikely
394  wrapped = -PI;
395  }
396  }
397  return wrapped * radians;
398 }
399 
400 inline Angle Angle::wrapNear(Angle const& refAng) const noexcept {
401  // compute (this - refAng).wrapCtr() + refAng
402  // which is correct except for roundoff error at the edges
403  double const refAngRad = refAng.asRadians();
404  double wrapped = (*this - refAng).wrapCtr().asRadians() + refAngRad;
405 
406  // roundoff can cause slightly out-of-range values; fix those as bast we can;
407  // note that both conditionals are wanted, since either or both may execute
408  // (though if/else could be used if the lower limit was squishy for radians)
409  if (wrapped - refAngRad >= PI) {
410  wrapped -= TWOPI;
411  }
412  if (wrapped - refAngRad < -PI) {
413  wrapped += TWOPI;
414  }
415  return wrapped * radians;
416 }
417 
418 inline Angle Angle::separation(Angle const& other) const noexcept { return (*this - other).wrapCtr(); }
419 }
420 }
421 }
422 #endif // if !defined(LSST_AFW_GEOM_ANGLE_H)
constexpr bool isAngle(T) noexcept
Allow a user to check if they have an angle.
Definition: Angle.h:349
AngleUnit constexpr arcminutes
constant with units of arcminutes
Definition: Angle.h:90
friend class Angle
Definition: Angle.h:53
std::ostream & operator<<(std::ostream &os, lsst::afw::geom::AffineTransform const &transform)
double constexpr HALFPI
Definition: Angle.h:23
Angle wrapNear(Angle const &refAng) const noexcept
Wrap this angle to a value x such that -π ≤ x - refAng ≤ π, approximately.
Definition: Angle.h:400
constexpr double masToRad(double x) noexcept
Definition: Angle.h:38
AngleUnit constexpr radians
constant with units of radians
Definition: Angle.h:87
double const INVSQRTPI
Definition: Angle.h:27
AngleUnit constexpr degrees
constant with units of degrees
Definition: Angle.h:88
T fmod(T... args)
table::Key< int > a
ImageT val
Definition: CR.cc:158
table::Key< double > angle
constexpr double asArcseconds() const noexcept
Return an Angle&#39;s value in arcseconds.
Definition: Angle.h:153
def wrap(ctrl)
Definition: wrap.py:250
A class used to convert scalar POD types such as double to Angle.
Definition: Angle.h:52
double constexpr ONE_OVER_PI
Definition: Angle.h:24
#define ANGLE_COMP(OP)
Definition: Angle.h:231
double constexpr PI
The ratio of a circle&#39;s circumference to diameter.
Definition: Angle.h:21
constexpr Angle(double val, AngleUnit units=radians) noexcept
Construct an Angle with the specified value (interpreted in the given units).
Definition: Angle.h:111
constexpr double asArcminutes() const noexcept
Return an Angle&#39;s value in arcminutes.
Definition: Angle.h:150
A class representing an angle.
Definition: Angle.h:102
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition: Angle.h:318
A base class for image defects.
Definition: cameraGeom.dox:3
Angle wrap() const noexcept
Wrap this angle to the range [0, 2π).
Definition: Angle.h:372
constexpr AngleUnit(double val)
Define a new angle unit.
Definition: Angle.h:67
constexpr bool operator==(AngleUnit const &rhs) const noexcept
Test if two units are the same.
Definition: Angle.h:83
double constexpr ROOT2
Definition: Angle.h:28
Angle wrapCtr() const noexcept
Wrap this angle to the range [-π, π).
Definition: Angle.h:381
constexpr double asAngularUnits(AngleUnit const &units) const noexcept
Return an Angle&#39;s value in the specified units.
Definition: Angle.h:138
solver_t * s
AngleUnit constexpr hours
constant with units of hours
Definition: Angle.h:89
double x
#define ANGLE_OP(OP)
Definition: Angle.h:256
constexpr double degToRad(double x) noexcept
Definition: Angle.h:33
constexpr Angle() noexcept
Construct the zero angle.
Definition: Angle.h:114
AngleUnit constexpr arcseconds
constant with units of arcseconds
Definition: Angle.h:91
constexpr double radToArcsec(double x) noexcept
Definition: Angle.h:35
constexpr Angle operator-(Angle a, Angle d) noexcept
Difference of two angles.
Definition: Angle.h:283
constexpr double asRadians() const noexcept
Return an Angle&#39;s value in radians.
Definition: Angle.h:141
constexpr double radToDeg(double x) noexcept
Definition: Angle.h:34
ItemVariant const * other
Definition: Schema.cc:55
Angle separation(Angle const &other) const noexcept
The signed difference between two Angles.
Definition: Angle.h:418
constexpr double arcsecToRad(double x) noexcept
Definition: Angle.h:37
constexpr double asDegrees() const noexcept
Return an Angle&#39;s value in degrees.
Definition: Angle.h:144
constexpr double radToMas(double x) noexcept
Definition: Angle.h:36
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition: Angle.h:207
STL class.
double const SQRTPI
Definition: Angle.h:26
double constexpr TWOPI
Definition: Angle.h:22
#define ANGLE_OP_TYPE(OP, TYPE)
Definition: Angle.h:263
constexpr double asHours() const noexcept
Return an Angle&#39;s value in hours.
Definition: Angle.h:147
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:364