mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
geo.hpp
Go to the documentation of this file.
1 /** \file geo.hpp
2  * \author Jared R. Males
3  * \brief Utilities for working with angles
4  * \ingroup gen_math_files
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2015, 2016, 2017, 2018 Jared R. Males (jaredmales@gmail.com)
10 //
11 // This file is part of mxlib.
12 //
13 // mxlib is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // mxlib is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 //***********************************************************************//
26 
27 #ifndef math_geo_hpp
28 #define math_geo_hpp
29 
30 #include <vector>
31 
32 #include <cmath>
33 
34 #include "constants.hpp"
35 
36 
37 namespace mx
38 {
39 namespace math
40 {
41 
42 
43 ///Calculate the semi-latus rectum of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>
44 /**
45  * \ingroup geo
46  */
47 #define semilatrect(a,e) (e == 0.0 ? a : (e == 1.0 ? 2.*a : (e < 1. ? a*(1-e*e) : a*(e*e-1))))
48 
49 ///Calculate the focal parameter of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>
50 /**
51  * \ingroup geo
52  */
53 #define focus(a,e) (e == 0.0 ? 1e34 : (e == 1.0 ? 2.*a : (e < 1. ? a*(1-e*e)/e : a*(e*e-1)/e)))
54 
55 ///Calculate the semi-major axis of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>, given the focal parameter and the eccentricity
56 /**
57  * \ingroup geo
58  */
59 #define semimaj(p,e) (e == 1.0 ? 1e34 : (e < 1 ? p*e/(1-e*e) : p*e/(e*e-1) ))
60 
61 ///Calculate the eccentricity of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a> given the semi-major axis and the focal parameter
62 /**
63  * \ingroup geo
64  */
65 #define eccent(a, p) (a == 0.0 ? 1e34 : (p >= 1e9 ? 0.0 : (p>0 ? (-p/(2*a)+0.5*std::sqrt(p*p/(a*a) + 4)) : (p/(2*a)+0.5*std::sqrt(p*p/(a*a) + 4)) ) ))
66 
67 /// Type specifying angles in radians
68 /**
69  * \test Verify compilation and calculations of math::angleDiff \ref tests_math_geo_angleDiff "[test doc]"
70  */
71 struct radians;
72 
73 /// Type specifying angles in degrees
74 /**
75  * \test Verify compilation and calculations of math::angleDiff \ref tests_math_geo_angleDiff "[test doc]"
76  */
77 struct degrees;
78 
79 /// Type holding constants related to angle calculations in degrees
80 template<typename degrad, typename realT>
81 struct degradT;
82 
83 /// Type holding constants related to angle calculations in degrees
84 /**
85  * \test Verify compilation and calculations of math::angleDiff \ref tests_math_geo_angleDiff "[test doc]"
86  */
87 template<typename _realT>
88 struct degradT<degrees, _realT>
89 {
90  typedef _realT realT;
91  static constexpr realT scale = static_cast<realT>(180)/pi<realT>(); //Scale factor to convert from radians to this unit.
92  static constexpr realT degrees = 1;
93  static constexpr realT radians = pi<realT>()/static_cast<realT>(180);
94  static constexpr realT full = static_cast<realT>(360.0);
95  static constexpr realT half = static_cast<realT>(180.0);
96 };
97 
98 template<typename realT>
100 
101 /// Type holding constants related to angle calculations in radians
102 /**
103  * \test Verify compilation and calculations of math::angleDiff \ref tests_math_geo_angleDiff "[test doc]"
104  */
105 template<typename _realT>
106 struct degradT<radians, _realT>
107 {
108  typedef _realT realT;
109  static constexpr realT scale = 1; //Scale factor to convert from radians to this unit.
110  static constexpr realT degrees = static_cast<realT>(180)/pi<realT>();
111  static constexpr realT radians = 1;
112  static constexpr realT full = two_pi<realT>();
113  static constexpr realT half = pi<realT>();
114 };
115 
116 template<typename realT>
118 
119 
120 ///Convert from degrees to radians
121 /**
122  *
123  * \param q is the angle to convert
124  *
125  * \return the angle q converted to radians
126  *
127  * \test Verify compilation and calculations of math::angleDiff \ref tests_math_geo_angleDiff "[test doc]"
128  *
129  * \ingroup geo
130  */
131 template<typename realT>
132 realT dtor(realT q)
133 {
135 }
136 
137 ///Convert from radians to degrees
138 /**
139  *
140  * \param q is the angle to convert
141  *
142  * \return the angle q converted to degrees
143  *
144  * \ingroup geo
145  */
146 template<typename realT>
147 realT rtod(realT q)
148 {
150 }
151 
152 ///Calculate the angle modulo full-circle, normalizing to a positive value.
153 /** The output will be betweeen 0 and 360 (or 0 and 2pi).
154  *
155  * \returns the value of q normalized to 0 <= q < 360[2pi]
156  *
157  * \tparam degrad controls whether this is in degrees (0, default) or radians (1)
158  * \tparam realT is the type in which to do arithmetic
159  *
160  * \ingroup geo
161  */
162 template<class angleT>
163 typename angleT::realT angleMod(typename angleT::realT q /**< [in] the angle */)
164 {
165  static_assert(std::is_floating_point<typename angleT::realT>::value, "angleMod: angleT::realT must be floating point");
166 
167  q = fmod(q, angleT::full);
168 
169  if(q < 0) q += angleT::full;
170 
171  return q;
172 }
173 
174 
175 
176 ///Calculate the difference between two angles, correctly across 0/360.
177 /** Calculates \f$ dq = q2- q1 \f$, but accounts for crossing 0/360. This implies
178  * that \f$ dq \le 180 \f$.
179  *
180  *
181  * \returns the difference of q2 and q1
182  *
183  * \tparam degrad controls whether this is in degrees (0, default) or radians (1)
184  * \tparam realT is the type in which to do arithmetic
185  *
186  * \test Verify compilation and calculations of math::angleDiff \ref tests_math_geo_angleDiff "[test doc]"
187  *
188  * \ingroup geo
189  */
190 template<class angleT>
191 typename angleT::realT angleDiff( typename angleT::realT q1, ///< [in] angle to subtract from q2, in degrees.
192  typename angleT::realT q2 ///< [in] angle to subtract q1 from, in degrees.
193  )
194 {
195  //typedef typename degradT::realT realT;
196 
197  static_assert(std::is_floating_point<typename angleT::realT>::value, "angleDiff: realT must be floating point");
198 
199  typename angleT::realT dq = q2-q1;
200 
201  if(std::abs(dq) > angleT::half)
202  {
203  if(dq < 0)
204  {
205  dq = dq + static_cast<typename angleT::realT>(2)*angleT::half;
206  }
207  else
208  {
209  dq = dq - static_cast<typename angleT::realT>(2)*angleT::half;
210  }
211  }
212 
213  return dq;
214 }
215 
216 
217 ///Calculate the mean of a set of angles, correctly across 0/360.
218 /** Calculates the mean by decomposing into vectors and averaging the components. This accounts for crossing 0/360.
219  *
220  * \returns the mean angle
221  *
222  * \tparam angleT is the angle type, either radians<realT> or degrees<realT>. angleT::realT is the type in which to do arithmetic.
223  *
224  * \ingroup geo
225  */
226 template<class angleT>
227 typename angleT::realT angleMean( const std::vector<typename angleT::realT> & q /**< [in] vector of angles to average.*/)
228 {
229  static_assert(std::is_floating_point<typename angleT::realT>::value, "angleMean: realT must be floating point");
230 
231  typename angleT::realT s = 0;
232  typename angleT::realT c = 0;
233 
234  for(int i=0; i< q.size(); ++i)
235  {
236  s += sin( q[i]/angleT::scale);
237  c += cos( q[i]/angleT::scale );
238  }
239 
240  s /= q.size();
241  c /= q.size();
242 
243  return atan2(s,c)*angleT::scale ;
244 
245 }
246 
247 ///Make a vector of angles continuous, fixing the 0/360 crossing.
248 /** The vector is modified so it is continuous.
249  *
250  *
251  * \tparam degrad controls whether angles are degrees (false) or radians (true)
252  * \tparam realT is the type in which to do arithmetic
253  *
254  * \ingroup geo
255  */
256 template<int degrad = 0, typename realT>
257 int continueAngles( std::vector<realT> & angles, ///< [in] the vector of angles
258  realT threshold=0.75 ///< [in] [optional] the fraction of a full circle at which to consider a difference in angle discontinuous.
259  )
260 {
261  realT full;
262 
263  if(degrad) full = two_pi<realT>();
264  else full = static_cast<realT>(360);
265 
266  threshold*=full;
267 
268  realT adj = 0;
269 
270  if( fabs(angles[1] - angles[0]) > threshold)
271  {
272  if( angles[1] > angles[0]) adj = -full;
273  else adj = full;
274 
275  angles[1] += adj;
276  }
277 
278  if(angles.size() == 2) return 0;
279 
280  for(int i=2; i< angles.size(); ++i)
281  {
282  angles[i] += adj;
283 
284  if( fabs(angles[i] - angles[i-1]) > threshold)
285  {
286  if( angles[i] > angles[i-1]) adj += -full;
287  else adj += full;
288 
289  angles[i] += adj;
290  }
291  }
292 
293  return 0;
294 }
295 
296 /// Rotate a point about the origin.
297 /** The rotation is counter-clockwise for positive angles.
298  *
299  * \tparam realT a real floating point type
300  *
301  * \ingroup geo
302  */
303 template<typename realT>
304 void rotatePoint( realT & x0, ///< [in.out] the x-coordinate of the point to rotate. On exit contains the rotated value.
305  realT & y0, ///< [in.out] the y-coordinate of the point to rotate. On exit contains the rotated value.
306  realT angle ///< [in] the angle by which to rotate [radians]
307  )
308 {
309  realT x1;
310  realT y1;
311 
312  realT cq = cos(angle);
313  realT sq = sin(angle);
314 
315  x1 = x0*cq - y0*sq;
316  y1 = x0*sq + y0*cq;
317 
318  x0 = x1;
319  y0 = y1;
320 }
321 
322 } //namespaace math
323 } //namespace mx
324 
325 #endif //math_geo_hpp
constexpr units::realT c()
The speed of light.
Definition: constants.hpp:60
int continueAngles(std::vector< realT > &angles, realT threshold=0.75)
Make a vector of angles continuous, fixing the 0/360 crossing.
Definition: geo.hpp:257
angleT::realT angleDiff(typename angleT::realT q1, typename angleT::realT q2)
Calculate the difference between two angles, correctly across 0/360.
Definition: geo.hpp:191
angleT::realT angleMod(typename angleT::realT q)
Calculate the angle modulo full-circle, normalizing to a positive value.
Definition: geo.hpp:163
realT rtod(realT q)
Convert from radians to degrees.
Definition: geo.hpp:147
angleT::realT angleMean(const std::vector< typename angleT::realT > &q)
Calculate the mean of a set of angles, correctly across 0/360.
Definition: geo.hpp:227
realT dtor(realT q)
Convert from degrees to radians.
Definition: geo.hpp:132
void rotatePoint(realT &x0, realT &y0, realT angle)
Rotate a point about the origin.
Definition: geo.hpp:304
The mxlib c++ namespace.
Definition: mxError.hpp:107
Type holding constants related to angle calculations in degrees.
Definition: geo.hpp:81