LSSTApplications  19.0.0-10-g920eed2,19.0.0-11-g48a0200+2,19.0.0-18-gfc4e62b+17,19.0.0-2-g3b2f90d+2,19.0.0-2-gd671419+5,19.0.0-20-g5a5a17ab+15,19.0.0-21-g2644856+18,19.0.0-23-g84eeccb+6,19.0.0-24-g878c510+5,19.0.0-25-g6c8df7140,19.0.0-25-gb330496+5,19.0.0-3-g2b32d65+5,19.0.0-3-g8227491+16,19.0.0-3-g9c54d0d+16,19.0.0-3-gca68e65+12,19.0.0-3-gcfc5f51+5,19.0.0-3-ge110943+15,19.0.0-3-ge74d124,19.0.0-3-gfe04aa6+16,19.0.0-30-g9c3fd16+6,19.0.0-4-g06f5963+5,19.0.0-4-g3d16501+18,19.0.0-4-g4a9c019+5,19.0.0-4-g5a8b323,19.0.0-4-g66397f0+1,19.0.0-4-g8278b9b+1,19.0.0-4-g8557e14,19.0.0-4-g8964aba+17,19.0.0-4-ge404a01+16,19.0.0-5-g40f3a5a,19.0.0-5-g4db63b3,19.0.0-5-gfb03ce7+17,19.0.0-6-gbaebbfb+16,19.0.0-61-gec4c6e08+6,19.0.0-7-g039c0b5+16,19.0.0-7-gbea9075+4,19.0.0-7-gc567de5+17,19.0.0-70-g334bf3e+1,19.0.0-9-g463f923+16,b.20.0.x-g5487ab2134,v20.0.0.rc1
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)
251 
252  ANGLE_OPUP_TYPE(-=, double)
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)
lsst::geom::degrees
constexpr AngleUnit degrees
constant with units of degrees
Definition: Angle.h:109
lsst::geom::isAngle
constexpr bool isAngle(T) noexcept
Allow a user to check if they have an angle.
Definition: Angle.h:380
lsst::geom::Angle::separation
Angle separation(Angle const &other) const noexcept
The signed difference between two Angles.
Definition: Angle.h:449
lsst::geom::radToDeg
constexpr double radToDeg(double x) noexcept
Definition: Angle.h:52
lsst::geom::masToRad
constexpr double masToRad(double x) noexcept
Definition: Angle.h:56
lsst::geom::PI
constexpr double PI
The ratio of a circle's circumference to diameter.
Definition: Angle.h:39
lsst::geom::Angle::wrapCtr
Angle wrapCtr() const noexcept
Wrap this angle to the range [-π, π).
Definition: Angle.h:412
lsst::geom::Angle::wrap
Angle wrap() const noexcept
Wrap this angle to the range [0, 2π).
Definition: Angle.h:403
ANGLE_OP
#define ANGLE_OP(OP)
Definition: Angle.h:287
lsst::geom::arcseconds
constexpr AngleUnit arcseconds
constant with units of arcseconds
Definition: Angle.h:112
ANGLE_OP_TYPE
#define ANGLE_OP_TYPE(OP, TYPE)
Definition: Angle.h:294
lsst::geom::Angle::asArcminutes
constexpr double asArcminutes() const noexcept
Return an Angle's value in arcminutes.
Definition: Angle.h:175
lsst::geom::ONE_OVER_PI
constexpr double ONE_OVER_PI
Definition: Angle.h:42
lsst::geom::Angle::Angle
constexpr Angle(double val, AngleUnit units=radians) noexcept
Construct an Angle with the specified value (interpreted in the given units).
Definition: Angle.h:136
lsst::geom::operator-
constexpr Angle operator-(Angle a, Angle d) noexcept
Difference of two angles.
Definition: Angle.h:314
lsst::geom::Angle::Angle
constexpr Angle() noexcept
Construct the zero angle.
Definition: Angle.h:139
val
ImageT val
Definition: CR.cc:146
angle
table::Key< double > angle
Definition: FunctionLibrary.cc:22
std::hash< lsst::geom::Angle >::operator()
size_t operator()(argument_type const &x) const noexcept
Definition: Angle.h:466
lsst::geom::radToArcsec
constexpr double radToArcsec(double x) noexcept
Definition: Angle.h:53
lsst::geom::AngleUnit::operator*
constexpr friend 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
lsst::geom::hours
constexpr AngleUnit hours
constant with units of hours
Definition: Angle.h:110
lsst::geom::Angle::asRadians
constexpr double asRadians() const noexcept
Return an Angle's value in radians.
Definition: Angle.h:166
std::is_arithmetic
lsst::geom::Angle::Angle
constexpr Angle(Angle &&other) noexcept=default
Move constructor.
lsst::afw::table::Angle
lsst::geom::Angle Angle
Definition: misc.h:33
std::ostream
STL class.
lsst::geom::Angle::hash_value
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Angle.h:278
x
double x
Definition: ChebyshevBoundedField.cc:277
other
ItemVariant const * other
Definition: Schema.cc:56
lsst::geom::milliarcseconds
constexpr AngleUnit milliarcseconds
constant with units of milliarcseconds
Definition: Angle.h:115
lsst::geom::TWOPI
constexpr double TWOPI
Definition: Angle.h:40
lsst::geom::AngleUnit::operator==
constexpr bool operator==(AngleUnit const &rhs) const noexcept
Test if two units are the same.
Definition: Angle.h:104
lsst::geom::operator*
constexpr Angle operator*(Angle a, Angle d) noexcept
Product of two angles.
Definition: Angle.h:322
lsst::geom::Angle::operator=
Angle & operator=(Angle const &other) noexcept=default
Copy assignment.
lsst::geom::INVSQRTPI
double const INVSQRTPI
Definition: Angle.h:45
lsst::geom::radToMas
constexpr double radToMas(double x) noexcept
Definition: Angle.h:54
lsst::geom::AngleUnit::hash_value
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Angle.h:98
lsst::geom::Angle::operator=
Angle & operator=(Angle &&other) noexcept=default
Move assignment.
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
lsst::geom::operator<<
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
Definition: AffineTransform.cc:72
lsst::geom::degToRad
constexpr double degToRad(double x) noexcept
Definition: Angle.h:51
lsst::geom::Angle::asAngularUnits
constexpr double asAngularUnits(AngleUnit const &units) const noexcept
Return an Angle's value in the specified units.
Definition: Angle.h:163
lsst::geom::arcminutes
constexpr AngleUnit arcminutes
constant with units of arcminutes
Definition: Angle.h:111
lsst::geom
Definition: geomOperators.dox:4
lsst::geom::Angle::~Angle
~Angle()=default
lsst::geom::Angle::Angle
constexpr Angle(Angle const &other) noexcept=default
Copy constructor.
lsst::geom::ROOT2
constexpr double ROOT2
Definition: Angle.h:46
std::fmod
T fmod(T... args)
a
table::Key< int > a
Definition: TransmissionCurve.cc:466
lsst::geom::operator/
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition: Angle.h:349
std
STL namespace.
lsst::geom::Angle::asHours
constexpr double asHours() const noexcept
Return an Angle's value in hours.
Definition: Angle.h:172
lsst::geom::AngleUnit
A class used to convert scalar POD types such as double to Angle.
Definition: Angle.h:70
lsst::geom::Angle
A class representing an angle.
Definition: Angle.h:127
lsst::geom::radians
constexpr AngleUnit radians
constant with units of radians
Definition: Angle.h:108
lsst::geom::Angle::asDegrees
constexpr double asDegrees() const noexcept
Return an Angle's value in degrees.
Definition: Angle.h:169
std::size_t
std::hash< lsst::geom::AngleUnit >::operator()
size_t operator()(argument_type const &x) const noexcept
Definition: Angle.h:459
ANGLE_COMP
#define ANGLE_COMP(OP)
Definition: Angle.h:259
lsst::geom::Angle::wrapNear
Angle wrapNear(Angle const &refAng) const noexcept
Wrap this angle to a value x such that -π ≤ x - refAng ≤ π, approximately.
Definition: Angle.h:431
lsst::geom::SQRTPI
double const SQRTPI
Definition: Angle.h:44
lsst::geom::Angle::asMilliarcseconds
constexpr double asMilliarcseconds() const noexcept
Return an Angle's value in milliarcseconds.
Definition: Angle.h:181
lsst::geom::Angle::asArcseconds
constexpr double asArcseconds() const noexcept
Return an Angle's value in arcseconds.
Definition: Angle.h:178
lsst::geom::HALFPI
constexpr double HALFPI
Definition: Angle.h:41
lsst::geom::AngleUnit::AngleUnit
constexpr AngleUnit(double val)
Define a new angle unit.
Definition: Angle.h:85
ANGLE_OPUP_TYPE
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition: Angle.h:235
lsst::geom::arcsecToRad
constexpr double arcsecToRad(double x) noexcept
Definition: Angle.h:55
std::hash
std::is_base_of