LSSTApplications  18.0.0+47,18.0.0+97,19.0.0,19.0.0+1,19.0.0+2,19.0.0+6,19.0.0+7,19.0.0+8,19.0.0-1-g20d9b18+3,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+3,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+6,19.0.0-1-g8c57eb9+3,19.0.0-1-gb5175dc+6,19.0.0-1-gd7f3e1b+6,19.0.0-1-gdc0e4a7+6,19.0.0-1-ge272bc4+3,19.0.0-1-gf46fa72+2,19.0.0-2-g0d9f9cd+6,19.0.0-2-g3d9e4fb2+6,19.0.0-2-g72d3ad5+1,19.0.0-2-gd955cfd+6,19.0.0-2-gdbc0a5a+3,19.0.0-3-g2d13df8,19.0.0-3-g87c0a3903,19.0.0-4-g725f80e+2,19.0.0-4-g80b229a+1,19.0.0-7-gf796fef9+7,19.0.0-8-g608b899+3,w.2019.50
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 
98  std::size_t hash_value() const noexcept { return std::hash<double>()(_val); }
99 
100 private:
101  double _val;
102 };
103 
104 inline constexpr bool AngleUnit::operator==(AngleUnit const& rhs) const noexcept {
105  return (_val == rhs._val);
106 }
107 
108 AngleUnit constexpr radians = AngleUnit(1.0);
109 AngleUnit constexpr degrees = AngleUnit(PI / 180.0);
110 AngleUnit constexpr hours = AngleUnit(PI * 15.0 / 180.0);
111 AngleUnit constexpr arcminutes = AngleUnit(PI / 60 / 180.0);
112 AngleUnit constexpr arcseconds = AngleUnit(PI / 180.0 / 3600.0);
113 // Note: if we use PI / 180.0 / 3.6e6 then 60*60*180*1000*lsst.geom.milliarcseconds
114 // does not test exactly equal to 180*lsst.geom.degrees
116  AngleUnit(PI / (180.0 * 3.6e6));
117 
127 class Angle final {
128  friend class AngleUnit;
129 
130 public:
136  explicit constexpr Angle(double val, AngleUnit units = radians) noexcept : _val(val * units._val) {}
137 
139  constexpr Angle() noexcept : _val(0) {}
140 
142  constexpr Angle(Angle const& other) noexcept = default;
143 
145  constexpr Angle(Angle&& other) noexcept = default;
146 
148  Angle& operator=(Angle const& other) noexcept = default;
149 
151  Angle& operator=(Angle&& other) noexcept = default;
152 
153  ~Angle() = default;
154 
156  constexpr operator double() const noexcept { return _val; }
157 
163  constexpr double asAngularUnits(AngleUnit const& units) const noexcept { return _val / units._val; }
164 
166  constexpr double asRadians() const noexcept { return asAngularUnits(radians); }
167 
169  constexpr double asDegrees() const noexcept { return asAngularUnits(degrees); }
170 
172  constexpr double asHours() const noexcept { return asAngularUnits(hours); }
173 
175  constexpr double asArcminutes() const noexcept { return asAngularUnits(arcminutes); }
176 
178  constexpr double asArcseconds() const noexcept { return asAngularUnits(arcseconds); }
179 
181  constexpr double asMilliarcseconds() const noexcept { return asAngularUnits(milliarcseconds); }
182 
195  Angle wrap() const noexcept;
196 
209  Angle wrapCtr() const noexcept;
210 
223  Angle wrapNear(Angle const& refAng) const noexcept;
224 
233  Angle separation(Angle const& other) const noexcept;
234 
235 #define ANGLE_OPUP_TYPE(OP, TYPE) \
236  Angle& operator OP(TYPE const& d) noexcept { \
237  _val OP d; \
238  return *this; \
239  }
240 
242  ANGLE_OPUP_TYPE(*=, double)
246 
247  ANGLE_OPUP_TYPE(+=, double)
249  ANGLE_OPUP_TYPE(+=, int)
251 
252  ANGLE_OPUP_TYPE(-=, double)
254  ANGLE_OPUP_TYPE(-=, int)
256 
257 #undef ANGLE_OPUP_TYPE
258 
259 #define ANGLE_COMP(OP) \
260  constexpr bool operator OP(const Angle& rhs) const noexcept { return _val OP rhs._val; }
261 
263  ANGLE_COMP(==)
267 
268  ANGLE_COMP(<=)
274 
275 #undef ANGLE_COMP
276 
278  std::size_t hash_value() const noexcept { return std::hash<double>()(_val); }
279 
280 private:
281  double _val;
282 };
283 
284 /*
285  * Operators for Angles.
286  */
287 #define ANGLE_OP(OP) \
288  inline constexpr Angle operator OP(Angle a, Angle d) noexcept { \
289  return Angle(static_cast<double>(a) OP static_cast<double>(d)); \
290  }
291 
292 // We need both int and double versions to avoid ambiguous overloading due to
293 // implicit conversion of Angle to double
294 #define ANGLE_OP_TYPE(OP, TYPE) \
295  inline constexpr Angle operator OP(Angle a, TYPE d) noexcept { \
296  return Angle(static_cast<double>(a) OP d); \
297  } \
298  \
299  inline constexpr Angle operator OP(TYPE d, Angle a) noexcept { \
300  return Angle(d OP static_cast<double>(a)); \
301  }
302 
324 
329 ANGLE_OP_TYPE(*, double)
332 
333 #undef ANGLE_OP
334 #undef ANGLE_OP_TYPE
335 
341 inline constexpr Angle operator-(Angle angle) { return Angle(-static_cast<double>(angle)); }
342 
343 // Apparently @relatesalso doesn't work with grouping
349 inline constexpr Angle operator/(Angle a, int d) noexcept { return Angle(static_cast<double>(a) / d); }
350 
356 inline constexpr Angle operator/(Angle a, double d) noexcept { return Angle(static_cast<double>(a) / d); }
357 
358 // Division is different. Don't allow division by an Angle
359 template <typename T>
360 constexpr double operator/(T const lhs, Angle rhs) noexcept = delete;
361 
377 
379 template <typename T>
380 inline constexpr bool isAngle(T) noexcept {
382 };
383 
394 template <typename T>
395 inline constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept {
396  static_assert(std::is_arithmetic<T>::value,
397  "Only numeric types may be multiplied by an AngleUnit to create an Angle!");
398  return Angle(lhs * rhs._val);
399 }
400 
401 // Inline method definitions, placed last in order to benefit from Angle's full API
402 
403 inline Angle Angle::wrap() const noexcept {
404  double wrapped = std::fmod(_val, TWOPI);
405  // wrapped is in the range (-TWOPI, TWOPI)
406  if (wrapped < 0.0) wrapped += TWOPI;
407  // if wrapped is small enough, adding 2 pi gives 2 pi
408  if (wrapped >= TWOPI) wrapped = 0.0;
409  return wrapped * radians;
410 }
411 
412 inline Angle Angle::wrapCtr() const noexcept {
413  double wrapped = std::fmod(_val, TWOPI);
414  // wrapped is in the range [-TWOPI, TWOPI]
415  if (wrapped < -PI) {
416  wrapped += TWOPI;
417  if (wrapped >= PI) {
418  // handle roundoff error, however unlikely
419  wrapped = -PI;
420  }
421  } else if (wrapped >= PI) {
422  wrapped -= TWOPI;
423  if (wrapped < -PI) {
424  // handle roundoff error, however unlikely
425  wrapped = -PI;
426  }
427  }
428  return wrapped * radians;
429 }
430 
431 inline Angle Angle::wrapNear(Angle const& refAng) const noexcept {
432  // compute (this - refAng).wrapCtr() + refAng
433  // which is correct except for roundoff error at the edges
434  double const refAngRad = refAng.asRadians();
435  double wrapped = (*this - refAng).wrapCtr().asRadians() + refAngRad;
436 
437  // roundoff can cause slightly out-of-range values; fix those as bast we can;
438  // note that both conditionals are wanted, since either or both may execute
439  // (though if/else could be used if the lower limit was squishy for radians)
440  if (wrapped - refAngRad >= PI) {
441  wrapped -= TWOPI;
442  }
443  if (wrapped - refAngRad < -PI) {
444  wrapped += TWOPI;
445  }
446  return wrapped * radians;
447 }
448 
449 inline Angle Angle::separation(Angle const& other) const noexcept { return (*this - other).wrapCtr(); }
450 
451 } // namespace geom
452 } // namespace lsst
453 
454 namespace std {
455 template <>
459  size_t operator()(argument_type const& x) const noexcept { return x.hash_value(); }
460 };
461 
462 template <>
466  size_t operator()(argument_type const& x) const noexcept { return x.hash_value(); }
467 };
468 } // namespace std
469 
470 #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:163
AngleUnit constexpr arcminutes
constant with units of arcminutes
Definition: Angle.h:111
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Angle.h:278
constexpr double asRadians() const noexcept
Return an Angle&#39;s value in radians.
Definition: Angle.h:166
friend class Angle
Definition: Angle.h:71
constexpr double asDegrees() const noexcept
Return an Angle&#39;s value in degrees.
Definition: Angle.h:169
double constexpr TWOPI
Definition: Angle.h:40
AngleUnit constexpr hours
constant with units of hours
Definition: Angle.h:110
constexpr double radToDeg(double x) noexcept
Definition: Angle.h:52
T fmod(T... args)
table::Key< int > a
STL namespace.
Angle separation(Angle const &other) const noexcept
The signed difference between two Angles.
Definition: Angle.h:449
ImageT val
Definition: CR.cc:146
ItemVariant const * other
Definition: Schema.cc:56
AngleUnit constexpr radians
constant with units of radians
Definition: Angle.h:108
A class representing an angle.
Definition: Angle.h:127
Angle wrapCtr() const noexcept
Wrap this angle to the range [-π, π).
Definition: Angle.h:412
size_t operator()(argument_type const &x) const noexcept
Definition: Angle.h:459
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:314
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition: Angle.h:235
AngleUnit constexpr degrees
constant with units of degrees
Definition: Angle.h:109
A base class for image defects.
constexpr double asHours() const noexcept
Return an Angle&#39;s value in hours.
Definition: Angle.h:172
AngleUnit constexpr arcseconds
constant with units of arcseconds
Definition: Angle.h:112
constexpr Angle() noexcept
Construct the zero angle.
Definition: Angle.h:139
constexpr double degToRad(double x) noexcept
Definition: Angle.h:51
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
constexpr double asArcseconds() const noexcept
Return an Angle&#39;s value in arcseconds.
Definition: Angle.h:178
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:136
Angle wrapNear(Angle const &refAng) const noexcept
Wrap this angle to a value x such that -π ≤ x - refAng ≤ π, approximately.
Definition: Angle.h:431
constexpr double asMilliarcseconds() const noexcept
Return an Angle&#39;s value in milliarcseconds.
Definition: Angle.h:181
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:349
#define ANGLE_OP(OP)
Definition: Angle.h:287
constexpr bool operator==(AngleUnit const &rhs) const noexcept
Test if two units are the same.
Definition: Angle.h:104
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:395
def wrap(ctrl)
Definition: wrap.py:302
#define ANGLE_OP_TYPE(OP, TYPE)
Definition: Angle.h:294
constexpr double radToMas(double x) noexcept
Definition: Angle.h:54
double const SQRTPI
Definition: Angle.h:44
constexpr double asArcminutes() const noexcept
Return an Angle&#39;s value in arcminutes.
Definition: Angle.h:175
constexpr AngleUnit(double val)
Define a new angle unit.
Definition: Angle.h:85
lsst::geom::Angle Angle
Definition: misc.h:33
Angle wrap() const noexcept
Wrap this angle to the range [0, 2π).
Definition: Angle.h:403
AngleUnit constexpr milliarcseconds
constant with units of milliarcseconds
Definition: Angle.h:115
constexpr bool isAngle(T) noexcept
Allow a user to check if they have an angle.
Definition: Angle.h:380
constexpr double masToRad(double x) noexcept
Definition: Angle.h:56
constexpr double arcsecToRad(double x) noexcept
Definition: Angle.h:55
size_t operator()(argument_type const &x) const noexcept
Definition: Angle.h:466
STL class.
double constexpr ROOT2
Definition: Angle.h:46
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Angle.h:98
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
#define ANGLE_COMP(OP)
Definition: Angle.h:259