LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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"
39 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;
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)
double x
table::Key< double > angle
table::Key< int > a
A class representing an angle.
Definition: Angle.h:127
Angle wrapCtr() const noexcept
Wrap this angle to the range [-π, π).
Definition: Angle.h:412
constexpr Angle(Angle const &other) noexcept=default
Copy constructor.
constexpr double asRadians() const noexcept
Return an Angle's value in radians.
Definition: Angle.h:166
constexpr double asHours() const noexcept
Return an Angle's value in hours.
Definition: Angle.h:172
Angle separation(Angle const &other) const noexcept
The signed difference between two Angles.
Definition: Angle.h:449
constexpr Angle(double val, AngleUnit units=radians) noexcept
Construct an Angle with the specified value (interpreted in the given units).
Definition: Angle.h:136
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Angle.h:278
constexpr Angle() noexcept
Construct the zero angle.
Definition: Angle.h:139
constexpr Angle operator/(Angle a, double d) noexcept
Ratio of an angle and a scalar.
Definition: Angle.h:356
constexpr double asDegrees() const noexcept
Return an Angle's value in degrees.
Definition: Angle.h:169
constexpr double asMilliarcseconds() const noexcept
Return an Angle's value in milliarcseconds.
Definition: Angle.h:181
constexpr double asArcseconds() const noexcept
Return an Angle's value in arcseconds.
Definition: Angle.h:178
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition: Angle.h:349
Angle & operator=(Angle &&other) noexcept=default
Move assignment.
Angle wrapNear(Angle const &refAng) const noexcept
Wrap this angle to a value x such that -π ≤ x - refAng ≤ π, approximately.
Definition: Angle.h:431
Angle wrap() const noexcept
Wrap this angle to the range [0, 2π).
Definition: Angle.h:403
constexpr Angle operator-(Angle angle)
An angle in the opposite sense.
Definition: Angle.h:341
Angle & operator=(Angle const &other) noexcept=default
Copy assignment.
constexpr Angle(Angle &&other) noexcept=default
Move constructor.
constexpr double asAngularUnits(AngleUnit const &units) const noexcept
Return an Angle's value in the specified units.
Definition: Angle.h:163
constexpr double asArcminutes() const noexcept
Return an Angle's value in arcminutes.
Definition: Angle.h:175
A class used to convert scalar POD types such as double to Angle.
Definition: Angle.h:70
constexpr AngleUnit(double val)
Define a new angle unit.
Definition: Angle.h:85
constexpr bool operator==(AngleUnit const &rhs) const noexcept
Test if two units are the same.
Definition: Angle.h:104
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Angle.h:98
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
T fmod(T... args)
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition: Angle.h:235
#define ANGLE_OP_TYPE(OP, TYPE)
Definition: Angle.h:294
#define ANGLE_OP(OP)
Definition: Angle.h:287
#define ANGLE_COMP(OP)
Definition: Angle.h:259
class[[deprecated("Removed with no replacement (but see lsst::afw::image::TransmissionCurve). Will be " "removed after v22.")]] FilterProperty final
Describe the properties of a Filter (e.g.
Definition: Filter.h:53
lsst::geom::Angle Angle
Definition: misc.h:33
constexpr Angle operator*(Angle a, Angle d) noexcept
Product of two angles.
Definition: Angle.h:322
double const SQRTPI
Definition: Angle.h:44
constexpr double arcsecToRad(double x) noexcept
Definition: Angle.h:55
double const INVSQRTPI
Definition: Angle.h:45
constexpr double radToMas(double x) noexcept
Definition: Angle.h:54
constexpr double PI
The ratio of a circle's circumference to diameter.
Definition: Angle.h:39
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition: Angle.h:349
constexpr AngleUnit arcseconds
constant with units of arcseconds
Definition: Angle.h:112
constexpr double HALFPI
Definition: Angle.h:41
constexpr AngleUnit degrees
constant with units of degrees
Definition: Angle.h:109
constexpr double radToDeg(double x) noexcept
Definition: Angle.h:52
constexpr double masToRad(double x) noexcept
Definition: Angle.h:56
constexpr double radToArcsec(double x) noexcept
Definition: Angle.h:53
constexpr double TWOPI
Definition: Angle.h:40
constexpr AngleUnit hours
constant with units of hours
Definition: Angle.h:110
constexpr AngleUnit milliarcseconds
constant with units of milliarcseconds
Definition: Angle.h:115
constexpr double degToRad(double x) noexcept
Definition: Angle.h:51
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
constexpr double ONE_OVER_PI
Definition: Angle.h:42
constexpr double ROOT2
Definition: Angle.h:46
constexpr AngleUnit radians
constant with units of radians
Definition: Angle.h:108
constexpr bool isAngle(T) noexcept
Allow a user to check if they have an angle.
Definition: Angle.h:380
constexpr AngleUnit arcminutes
constant with units of arcminutes
Definition: Angle.h:111
A base class for image defects.
STL namespace.
ImageT val
Definition: CR.cc:146
size_t operator()(argument_type const &x) const noexcept
Definition: Angle.h:466
size_t operator()(argument_type const &x) const noexcept
Definition: Angle.h:459