LSST Applications g011c388f00+c533e7e796,g0265f82a02+71b8ded0d6,g16a3bce237+71b8ded0d6,g2079a07aa2+b9108c1c87,g2bbee38e9b+71b8ded0d6,g337abbeb29+71b8ded0d6,g3ddfee87b4+efeeb9cceb,g44050f54f7+816a004954,g4cf46543a9+ac9bf1619d,g50ff169b8f+8309cf5058,g52b1c1532d+43dac7135f,g858d7b2824+816a004954,g8a8a8dda67+43dac7135f,g99855d9996+36230435de,g9cb17f706c+56afb287bb,g9ddcbc5298+389b8f2b7e,ga1e77700b3+4bafba478f,ga8c6da7877+9a92598c84,gae46bcf261+71b8ded0d6,gb0e22166c9+713927f999,gb700894bec+0b6c79d923,gb8350603e9+a03320826c,gba4ed39666+e464e2e6f0,gbeb006f7da+8cd302297b,gc86a011abf+816a004954,gcf0d15dbbd+efeeb9cceb,gd0e876f1fb+efeeb9cceb,gd162630629+3eacc90e0c,gd44f2fa1a7+82b768a15d,gd8a3c24633+eaa4ad6639,gdaeeff99f8+6b435c3f92,ge2eec9bf53+fad368631c,ge79ae78c31+71b8ded0d6,gee10cc3b42+43dac7135f,gf1cff7945b+816a004954,w.2024.08
LSST Data Management Base Package
Loading...
Searching...
No Matches
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 "lsst/sphgeom/Angle.h"
29#include "boost/math/constants/constants.hpp"
30
31namespace lsst {
32namespace geom {
33
34/*
35 * None of C99, C++98, and C++11 define M_PI, so we'll do it ourselves
36 */
37#pragma clang diagnostic push
38#pragma clang diagnostic ignored "-Wunused-variable"
40double constexpr PI = boost::math::constants::pi<double>();
41double constexpr TWOPI = boost::math::constants::pi<double>() * 2.0;
42double constexpr HALFPI = boost::math::constants::pi<double>() * 0.5;
43double constexpr ONE_OVER_PI = 1.0 / boost::math::constants::pi<double>();
44// sqrt is not a constexpr on OS X
45double const SQRTPI = sqrt(boost::math::constants::pi<double>());
46double const INVSQRTPI = 1.0 / sqrt(boost::math::constants::pi<double>());
47double constexpr ROOT2 = boost::math::constants::root_two<double>(); // sqrt(2)
48#pragma clang diagnostic pop
49
50// These shouldn't be necessary if the Angle class is used, but sometimes you just need
51// them. Better to define them once here than have *180/PI throughout the code...
52inline constexpr double degToRad(double x) noexcept { return x * PI / 180.; }
53inline constexpr double radToDeg(double x) noexcept { return x * 180. / PI; }
54inline constexpr double radToArcsec(double x) noexcept { return x * 3600. * 180. / PI; }
55inline constexpr double radToMas(double x) noexcept { return x * 1000. * 3600. * 180. / PI; }
56inline constexpr double arcsecToRad(double x) noexcept { return (x / 3600.) * PI / 180.; }
57inline constexpr double masToRad(double x) noexcept { return (x / (1000. * 3600.)) * PI / 180.; }
58
59class Angle;
71class AngleUnit final {
72 friend class Angle;
73 template <typename T>
74 friend constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept;
75
76public:
84 // Current implementation does not throw exceptions, but somebody may want
85 // to add input validation later
86 explicit constexpr AngleUnit(double val) : _val(val) {}
87
96 constexpr bool operator==(AngleUnit const& rhs) const noexcept;
97
99 std::size_t hash_value() const noexcept { return std::hash<double>()(_val); }
100
101private:
102 double _val;
103};
104
105inline constexpr bool AngleUnit::operator==(AngleUnit const& rhs) const noexcept {
106 return (_val == rhs._val);
107}
108
109AngleUnit constexpr radians = AngleUnit(1.0);
110AngleUnit constexpr degrees = AngleUnit(PI / 180.0);
111AngleUnit constexpr hours = AngleUnit(PI * 15.0 / 180.0);
112AngleUnit constexpr arcminutes = AngleUnit(PI / 60 / 180.0);
113AngleUnit constexpr arcseconds = AngleUnit(PI / 180.0 / 3600.0);
114// Note: if we use PI / 180.0 / 3.6e6 then 60*60*180*1000*lsst.geom.milliarcseconds
115// does not test exactly equal to 180*lsst.geom.degrees
117 AngleUnit(PI / (180.0 * 3.6e6));
118
128class Angle final {
129 friend class AngleUnit;
130
131public:
137 explicit constexpr Angle(double val, AngleUnit units = radians) noexcept : _val(val * units._val) {}
138
140 constexpr Angle() noexcept : _val(0) {}
141
143 explicit Angle(sphgeom::Angle const & sgAngle) noexcept : Angle(sgAngle.asRadians()) {}
144
146 constexpr Angle(Angle const& other) noexcept = default;
147
149 constexpr Angle(Angle&& other) noexcept = default;
150
152 Angle& operator=(Angle const& other) noexcept = default;
153
155 Angle& operator=(Angle&& other) noexcept = default;
156
157 ~Angle() = default;
158
160 constexpr operator double() const noexcept { return _val; }
161
163 operator sphgeom::Angle() const noexcept { return sphgeom::Angle::fromRadians(_val); }
164
170 constexpr double asAngularUnits(AngleUnit const& units) const noexcept { return _val / units._val; }
171
173 constexpr double asRadians() const noexcept { return asAngularUnits(radians); }
174
176 constexpr double asDegrees() const noexcept { return asAngularUnits(degrees); }
177
179 constexpr double asHours() const noexcept { return asAngularUnits(hours); }
180
182 constexpr double asArcminutes() const noexcept { return asAngularUnits(arcminutes); }
183
185 constexpr double asArcseconds() const noexcept { return asAngularUnits(arcseconds); }
186
188 constexpr double asMilliarcseconds() const noexcept { return asAngularUnits(milliarcseconds); }
189
202 Angle wrap() const noexcept;
203
216 Angle wrapCtr() const noexcept;
217
230 Angle wrapNear(Angle const& refAng) const noexcept;
231
240 Angle separation(Angle const& other) const noexcept;
241
242#define ANGLE_OPUP_TYPE(OP, TYPE) \
243 Angle& operator OP(TYPE const& d) noexcept { \
244 _val OP d; \
245 return *this; \
246 }
247
249
250 ANGLE_OPUP_TYPE(*=, double)
253
254
255 ANGLE_OPUP_TYPE(+=, double)
258
259
260 ANGLE_OPUP_TYPE(-=, double)
263
264#undef ANGLE_OPUP_TYPE
265
266#define ANGLE_COMP(OP) \
267 constexpr bool operator OP(const Angle& rhs) const noexcept { return _val OP rhs._val; }
268
270
274
275
281
282#undef ANGLE_COMP
283
285 std::size_t hash_value() const noexcept { return std::hash<double>()(_val); }
286
287private:
288 double _val;
289};
290
291/*
292 * Operators for Angles.
293 */
294#define ANGLE_OP(OP) \
295 inline constexpr Angle operator OP(Angle a, Angle d) noexcept { \
296 return Angle(static_cast<double>(a) OP static_cast<double>(d)); \
297 }
298
299// We need both int and double versions to avoid ambiguous overloading due to
300// implicit conversion of Angle to double
301#define ANGLE_OP_TYPE(OP, TYPE) \
302 inline constexpr Angle operator OP(Angle a, TYPE d) noexcept { \
303 return Angle(static_cast<double>(a) OP d); \
304 } \
305 \
306 inline constexpr Angle operator OP(TYPE d, Angle a) noexcept { \
307 return Angle(d OP static_cast<double>(a)); \
308 }
309
331
339
340#undef ANGLE_OP
341#undef ANGLE_OP_TYPE
342
348inline constexpr Angle operator-(Angle angle) { return Angle(-static_cast<double>(angle)); }
349
350// Apparently @relatesalso doesn't work with grouping
356inline constexpr Angle operator/(Angle a, int d) noexcept { return Angle(static_cast<double>(a) / d); }
357
363inline constexpr Angle operator/(Angle a, double d) noexcept { return Angle(static_cast<double>(a) / d); }
364
365// Division is different. Don't allow division by an Angle
366template <typename T>
367constexpr double operator/(T const lhs, Angle rhs) noexcept = delete;
368
384
386template <typename T>
387inline constexpr bool isAngle(T) noexcept {
389};
390
401template <typename T>
402inline constexpr Angle operator*(T lhs, AngleUnit rhs) noexcept {
403 static_assert(std::is_arithmetic<T>::value,
404 "Only numeric types may be multiplied by an AngleUnit to create an Angle!");
405 return Angle(lhs * rhs._val);
406}
407
408// Inline method definitions, placed last in order to benefit from Angle's full API
409
410inline Angle Angle::wrap() const noexcept {
411 double wrapped = std::fmod(_val, TWOPI);
412 // wrapped is in the range (-TWOPI, TWOPI)
413 if (wrapped < 0.0) wrapped += TWOPI;
414 // if wrapped is small enough, adding 2 pi gives 2 pi
415 if (wrapped >= TWOPI) wrapped = 0.0;
416 return wrapped * radians;
417}
418
419inline Angle Angle::wrapCtr() const noexcept {
420 double wrapped = std::fmod(_val, TWOPI);
421 // wrapped is in the range [-TWOPI, TWOPI]
422 if (wrapped < -PI) {
423 wrapped += TWOPI;
424 if (wrapped >= PI) {
425 // handle roundoff error, however unlikely
426 wrapped = -PI;
427 }
428 } else if (wrapped >= PI) {
429 wrapped -= TWOPI;
430 if (wrapped < -PI) {
431 // handle roundoff error, however unlikely
432 wrapped = -PI;
433 }
434 }
435 return wrapped * radians;
436}
437
438inline Angle Angle::wrapNear(Angle const& refAng) const noexcept {
439 // compute (this - refAng).wrapCtr() + refAng
440 // which is correct except for roundoff error at the edges
441 double const refAngRad = refAng.asRadians();
442 double wrapped = (*this - refAng).wrapCtr().asRadians() + refAngRad;
443
444 // roundoff can cause slightly out-of-range values; fix those as bast we can;
445 // note that both conditionals are wanted, since either or both may execute
446 // (though if/else could be used if the lower limit was squishy for radians)
447 if (wrapped - refAngRad >= PI) {
448 wrapped -= TWOPI;
449 }
450 if (wrapped - refAngRad < -PI) {
451 wrapped += TWOPI;
452 }
453 return wrapped * radians;
454}
455
456inline Angle Angle::separation(Angle const& other) const noexcept { return (*this - other).wrapCtr(); }
457
458} // namespace geom
459} // namespace lsst
460
461namespace std {
462template <>
463struct hash<lsst::geom::AngleUnit> {
464 using argument_type = lsst::geom::AngleUnit;
465 using result_type = size_t;
466 size_t operator()(argument_type const& x) const noexcept { return x.hash_value(); }
467};
468
469template <>
470struct hash<lsst::geom::Angle> {
471 using argument_type = lsst::geom::Angle;
472 using result_type = size_t;
473 size_t operator()(argument_type const& x) const noexcept { return x.hash_value(); }
474};
475} // namespace std
476
477#endif // if !defined(LSST_GEOM_ANGLE_H)
table::Key< double > angle
table::Key< int > a
A class representing an angle.
Definition Angle.h:128
Angle wrapCtr() const noexcept
Wrap this angle to the range [-π, π).
Definition Angle.h:419
constexpr Angle(Angle const &other) noexcept=default
Copy constructor.
constexpr double asRadians() const noexcept
Return an Angle's value in radians.
Definition Angle.h:173
constexpr double asHours() const noexcept
Return an Angle's value in hours.
Definition Angle.h:179
Angle separation(Angle const &other) const noexcept
The signed difference between two Angles.
Definition Angle.h:456
constexpr Angle(double val, AngleUnit units=radians) noexcept
Construct an Angle with the specified value (interpreted in the given units).
Definition Angle.h:137
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition Angle.h:285
constexpr Angle() noexcept
Construct the zero angle.
Definition Angle.h:140
constexpr Angle operator/(Angle a, double d) noexcept
Ratio of an angle and a scalar.
Definition Angle.h:363
constexpr double asDegrees() const noexcept
Return an Angle's value in degrees.
Definition Angle.h:176
constexpr double asMilliarcseconds() const noexcept
Return an Angle's value in milliarcseconds.
Definition Angle.h:188
constexpr double asArcseconds() const noexcept
Return an Angle's value in arcseconds.
Definition Angle.h:185
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition Angle.h:356
Angle wrapNear(Angle const &refAng) const noexcept
Wrap this angle to a value x such that -π ≤ x - refAng ≤ π, approximately.
Definition Angle.h:438
Angle & operator=(Angle const &other) noexcept=default
Copy assignment.
Angle & operator=(Angle &&other) noexcept=default
Move assignment.
Angle wrap() const noexcept
Wrap this angle to the range [0, 2π).
Definition Angle.h:410
constexpr Angle operator-(Angle angle)
An angle in the opposite sense.
Definition Angle.h:348
constexpr Angle(Angle &&other) noexcept=default
Move constructor.
Angle(sphgeom::Angle const &sgAngle) noexcept
Convert from a sphgeom::Angle instance.
Definition Angle.h:143
constexpr double asAngularUnits(AngleUnit const &units) const noexcept
Return an Angle's value in the specified units.
Definition Angle.h:170
constexpr double asArcminutes() const noexcept
Return an Angle's value in arcminutes.
Definition Angle.h:182
A class used to convert scalar POD types such as double to Angle.
Definition Angle.h:71
constexpr AngleUnit(double val)
Define a new angle unit.
Definition Angle.h:86
constexpr bool operator==(AngleUnit const &rhs) const noexcept
Test if two units are the same.
Definition Angle.h:105
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:402
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition Angle.h:99
Angle represents an angle in radians.
Definition Angle.h:50
static Angle fromRadians(double a)
Definition Angle.h:58
T fmod(T... args)
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition Angle.h:242
#define ANGLE_OP_TYPE(OP, TYPE)
Definition Angle.h:301
#define ANGLE_OP(OP)
Definition Angle.h:294
#define ANGLE_COMP(OP)
Definition Angle.h:266
constexpr Angle operator*(Angle a, Angle d) noexcept
Product of two angles.
Definition Angle.h:329
double const SQRTPI
Definition Angle.h:45
constexpr double arcsecToRad(double x) noexcept
Definition Angle.h:56
double constexpr HALFPI
Definition Angle.h:42
double const INVSQRTPI
Definition Angle.h:46
double constexpr ROOT2
Definition Angle.h:47
AngleUnit constexpr milliarcseconds
constant with units of milliarcseconds
Definition Angle.h:116
constexpr double radToMas(double x) noexcept
Definition Angle.h:55
double constexpr ONE_OVER_PI
Definition Angle.h:43
constexpr Angle operator/(Angle a, int d) noexcept
Ratio of an angle and a scalar.
Definition Angle.h:356
AngleUnit constexpr degrees
constant with units of degrees
Definition Angle.h:110
AngleUnit constexpr arcseconds
constant with units of arcseconds
Definition Angle.h:113
double constexpr TWOPI
Definition Angle.h:41
constexpr double radToDeg(double x) noexcept
Definition Angle.h:53
constexpr double masToRad(double x) noexcept
Definition Angle.h:57
constexpr double radToArcsec(double x) noexcept
Definition Angle.h:54
AngleUnit constexpr arcminutes
constant with units of arcminutes
Definition Angle.h:112
AngleUnit constexpr radians
constant with units of radians
Definition Angle.h:109
constexpr double degToRad(double x) noexcept
Definition Angle.h:52
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
double constexpr PI
The ratio of a circle's circumference to diameter.
Definition Angle.h:40
constexpr bool isAngle(T) noexcept
Allow a user to check if they have an angle.
Definition Angle.h:387
AngleUnit constexpr hours
constant with units of hours
Definition Angle.h:111
STL namespace.
T operator()(T... args)
This file declares a class for representing angles.
ImageT val
Definition CR.cc:146