LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
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 <limits>
5 #include <iostream>
6 #include <boost/math/constants/constants.hpp>
7 #include <cmath>
8 
9 namespace lsst { namespace afw { namespace geom {
10 
11 /************************************************************************************************************/
12 /*
13  * None of C99, C++98, and C++0x define M_PI, so we'll do it ourselves
14  */
15 #pragma clang diagnostic push
16 #pragma clang diagnostic ignored "-Wunused-variable"
17 double const PI = boost::math::constants::pi<double>();
18 double const TWOPI = boost::math::constants::pi<double>() * 2.0;
19 double const HALFPI = boost::math::constants::pi<double>() * 0.5;
20 double const ONE_OVER_PI = 1.0 / boost::math::constants::pi<double>();
21 double const SQRTPI = sqrt(boost::math::constants::pi<double>());
22 double const INVSQRTPI = 1.0/sqrt(boost::math::constants::pi<double>());
23 double const ROOT2 = boost::math::constants::root_two<double>(); // sqrt(2)
24 #pragma clang diagnostic pop
25 
26 // These shouldn't be necessary if the Angle class is used, but sometimes you just need
27 // them. Better to define them once here than have *180/PI throughout the code...
28 inline double degToRad(double x) {
29  return x * PI / 180.;
30 }
31 inline double radToDeg(double x) {
32  return x * 180. / PI;
33 }
34 inline double radToArcsec(double x) {
35  return x * 3600. * 180. / PI;
36 }
37 inline double radToMas(double x) {
38  return x * 1000. * 3600. * 180. / PI;
39 }
40 inline double arcsecToRad(double x) {
41  return (x / 3600.) * PI / 180.;
42 }
43 inline double masToRad(double x) {
44  return (x / (1000. * 3600.)) * PI / 180.;
45 }
46 
47 // NOTE, if you add things here, you must also add them to
48 // python/lsst/afw/geom/__init__.py
49 // (if you want them to accessible from python)
50 
51 #if 0 && !defined(M_PI) // a good idea, but with ramifications
52 # define M_PI ::lsst::afw::geom::PI
53 #endif
54 
55 /************************************************************************************************************/
56 
57 class Angle;
70 class AngleUnit {
71  friend class Angle;
72  template<typename T> friend const Angle operator *(T lhs, AngleUnit const rhs);
73 public:
74  explicit AngleUnit(double val) : _val(val) {}
75 
76  bool operator==(AngleUnit const &rhs) const;
77 private:
78  double _val;
79 };
80 
82  return (_val == rhs._val);
83 }
84 
85 // NOTE, if you add things here, remember to also add them to
86 // python/lsst/afw/geom/__init__.py
87 
88 // swig likes this way of initialising the constant, so don't mess with it;
89 // N.b. swig 1.3 doesn't like PI/(60*180)
90 AngleUnit const radians = AngleUnit(1.0);
91 AngleUnit const degrees = AngleUnit(PI/180.0); // constant with units of degrees
92 AngleUnit const hours = AngleUnit(PI*15.0/180.0); // constant with units of hours
93 AngleUnit const arcminutes = AngleUnit(PI/60/180.0); // constant with units of arcminutes
94 AngleUnit const arcseconds = AngleUnit(PI/180.0/3600.0); // constant with units of arcseconds
95 
96 /************************************************************************************************************/
103 class Angle {
104  friend class AngleUnit;
105 public:
107  explicit Angle(double val, AngleUnit units=radians) : _val(val*units._val) {}
108  Angle() : _val(0) {}
110  Angle(Angle const& other) : _val(other._val) {}
112  operator double() const { return _val; }
114  //operator float() const { return _val; }
115 
117  double asAngularUnits(AngleUnit const& units) const {
118  return _val/units._val;
119  }
121  double asRadians() const { return asAngularUnits(radians); }
123  double asDegrees() const { return asAngularUnits(degrees); }
125  double asHours() const { return asAngularUnits(hours); }
127  double asArcminutes() const { return asAngularUnits(arcminutes); }
129  double asArcseconds() const { return asAngularUnits(arcseconds); }
130 
131  double toUnitSphereDistanceSquared() const { return 2. * (1. - std::cos(asRadians())); }
132  // == 4.0 * pow(std::sin(0.5 * asRadians()), 2.0)
134  return (std::acos(1. - d2/2.)) * radians;
135  // == 2.0 * asin(0.5 * sqrt(d2))
136  }
137 
145  void wrap() {
146  _val = std::fmod(_val, TWOPI);
147  // _val is now in the range (-TWOPI, TWOPI)
148  if (_val < 0.0)
149  _val += TWOPI;
150  // if _val is small enough, adding 2 pi gives 2 pi
151  if (_val >= TWOPI)
152  _val = 0.0;
153  }
154 
161  void wrapCtr() {
162  _val = std::fmod(_val, TWOPI);
163  // _val is now in the range [-TWOPI, TWOPI]
164  if (_val < -PI) {
165  _val += TWOPI;
166  if (_val >= PI) {
167  // handle roundoff error, however unlikely
168  _val = -PI;
169  }
170  } else if (_val >= PI) {
171  _val -= TWOPI;
172  if (_val < -PI) {
173  // handle roundoff error, however unlikely
174  _val = -PI;
175  }
176  }
177  }
178 
185  void wrapNear(
186  Angle const & refAng
187  ) {
188  // compute this = (this - refAng).wrapCtr() + refAng
189  // which is correct except for roundoff error at the edges
190  double refAngRad = refAng.asRadians();
191  *this -= refAng;
192  wrapCtr();
193  _val += refAngRad;
194 
195  // roundoff can cause slightly out-of-range values; fix those
196  if (_val - refAngRad >= PI) {
197  _val -= TWOPI;
198  }
199  // maximum relative roundoff error for subtraction is 2 epsilon
200  if (_val - refAngRad < -PI) {
201  _val -= _val * 2.0 * std::numeric_limits<double>::epsilon();
202  }
203  }
204 
205 
206 #define ANGLE_OPUP_TYPE(OP, TYPE) \
207  Angle& operator OP(TYPE const& d) { \
208  _val OP d; \
209  return *this; \
210  }
211 
212 ANGLE_OPUP_TYPE(*=, double)
214 ANGLE_OPUP_TYPE(+=, double)
216 ANGLE_OPUP_TYPE(-=, double)
218 
219 #undef ANGLE_OPUP_TYPE
220 
221 #define ANGLE_COMP(OP) \
222  bool operator OP ( const Angle& rhs ) { \
223  return _val OP rhs._val; \
224  }
225 
232 
233 #undef ANGLE_COMP
234 
235 private:
236  double _val;
237 };
238 
239 Angle const NullAngle = Angle(-1000000., degrees);
240 
241 
242 /************************************************************************************************************/
243 /*
244  * Operators for Angles.
245  *
246  * N.b. We need both int and double versions to avoid ambiguous overloading due to implicit conversion of
247  * Angle to double
248  */
249 #define ANGLE_OP(OP) \
250  inline const Angle operator OP(Angle const a, Angle const d) { \
251  return Angle(static_cast<double>(a) OP static_cast<double>(d)); \
252  }
253 
254 #define ANGLE_OP_TYPE(OP, TYPE) \
255  inline const Angle operator OP(Angle const a, TYPE d) { \
256  return Angle(static_cast<double>(a) OP d); \
257  } \
258  \
259  inline const Angle operator OP(TYPE d, Angle const a) { \
260  return Angle(d OP static_cast<double>(a)); \
261  }
262 
266 ANGLE_OP_TYPE(*, double)
268 
269 #undef ANGLE_OP
270 #undef ANGLE_OP_TYPE
271 
272 // Division is different. Don't allow division by an Angle
273 inline const Angle operator /(Angle const a, int d) {
274  return Angle(static_cast<double>(a)/d);
275 }
276 
277 inline const Angle operator /(Angle const a, double d) {
278  return Angle(static_cast<double>(a)/d);
279 }
280 
281 template<typename T>
282  double operator /(T const lhs, Angle const rhs);
283 
284 /************************************************************************************************************/
288 template<typename T>
289 inline bool isAngle(T) {
290  return false;
291 };
292 
293 inline bool isAngle(Angle const&) {
294  return true;
295 };
296 
297 /************************************************************************************************************/
301 template<typename T>
302 inline
303 const Angle operator *(T lhs,
304  AngleUnit const rhs
305  ) {
306  static_assert(std::numeric_limits<T>::is_specialized,
307  "Only numeric types may be converted to Angles using degrees/radians!");
308  return Angle(lhs*rhs._val);
309 }
313 std::ostream& operator<<(std::ostream &s,
314  Angle const a
315  );
316 
317 }}}
318 #endif // if !defined(LSST_AFW_GEOM_ANGLE_H)
double asArcseconds() const
Return an Angle&#39;s value as a double in arcseconds.
Definition: Angle.h:129
const Angle operator/(Angle const a, int d)
Definition: Angle.h:273
double degToRad(double x)
Definition: Angle.h:28
Angle(Angle const &other)
Copy constructor.
Definition: Angle.h:110
AngleUnit const radians
constant with units of radians
Definition: Angle.h:90
std::ostream & operator<<(std::ostream &os, lsst::afw::geom::AffineTransform const &transform)
void wrapCtr()
Wrap this angle to the range [-pi, pi)
Definition: Angle.h:161
AngleUnit const hours
Definition: Angle.h:92
double const TWOPI
Definition: Angle.h:18
double const SQRTPI
Definition: Angle.h:21
A class used to convert scalar POD types such as double to Angle.
Definition: Angle.h:70
AngleUnit(double val)
Definition: Angle.h:74
double radToDeg(double x)
Definition: Angle.h:31
#define ANGLE_COMP(OP)
Definition: Angle.h:221
AngleUnit const degrees
Definition: Angle.h:91
const Angle operator*(Angle const a, Angle const d)
Definition: Angle.h:265
A class representing an Angle.
Definition: Angle.h:103
double radToArcsec(double x)
Definition: Angle.h:34
double asAngularUnits(AngleUnit const &units) const
Convert an Angle to a float in radians.
Definition: Angle.h:117
double toUnitSphereDistanceSquared() const
Definition: Angle.h:131
bool isAngle(T)
Allow a user to check if they have an angle (yes; they could do this themselves via trivial TMP) ...
Definition: Angle.h:289
void wrapNear(Angle const &refAng)
Wrap this angle such that pi &lt;= this - refAng &lt; pi.
Definition: Angle.h:185
double const ONE_OVER_PI
Definition: Angle.h:20
double x
#define ANGLE_OP(OP)
Definition: Angle.h:249
lsst::afw::geom::Angle Angle
Definition: misc.h:38
AngleUnit const arcminutes
Definition: Angle.h:93
Angle(double val, AngleUnit units=radians)
Construct an Angle with the specified value (interpreted in the given units)
Definition: Angle.h:107
double const HALFPI
Definition: Angle.h:19
AngleUnit const arcseconds
Definition: Angle.h:94
double const ROOT2
Definition: Angle.h:23
double arcsecToRad(double x)
Definition: Angle.h:40
double asRadians() const
Return an Angle&#39;s value as a double in radians.
Definition: Angle.h:121
double radToMas(double x)
Definition: Angle.h:37
double masToRad(double x)
Definition: Angle.h:43
double asDegrees() const
Return an Angle&#39;s value as a double in degrees.
Definition: Angle.h:123
double const PI
The ratio of a circle&#39;s circumference to diameter.
Definition: Angle.h:17
friend const Angle operator*(T lhs, AngleUnit const rhs)
Use AngleUnit to convert a POD (e.g.
Definition: Angle.h:303
static Angle fromUnitSphereDistanceSquared(double d2)
Definition: Angle.h:133
void wrap()
Wraps this angle to the range [0, 2 pi)
Definition: Angle.h:145
#define ANGLE_OPUP_TYPE(OP, TYPE)
Definition: Angle.h:206
ImageT val
Definition: CR.cc:159
double asHours() const
Return an Angle&#39;s value as a double in hours.
Definition: Angle.h:125
double const INVSQRTPI
Definition: Angle.h:22
double asArcminutes() const
Return an Angle&#39;s value as a double in arcminutes.
Definition: Angle.h:127
#define ANGLE_OP_TYPE(OP, TYPE)
Definition: Angle.h:254
Angle const NullAngle
Definition: Angle.h:239
bool operator==(AngleUnit const &rhs) const
Definition: Angle.h:81