mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
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
36namespace mx
37{
38namespace math
39{
40
41/// Calculate the semi-latus rectum of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>
42/**
43 * \ingroup geo
44 */
45#define semilatrect( a, e ) \
46 ( e == 0.0 ? a : ( e == 1.0 ? 2. * a : ( e < 1. ? a * ( 1 - e * e ) : a * ( e * e - 1 ) ) ) )
47
48/// Calculate the focal parameter of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a>
49/**
50 * \ingroup geo
51 */
52#define focus( a, e ) \
53 ( 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
56/// focal parameter and the eccentricity
57/**
58 * \ingroup geo
59 */
60#define semimaj( p, e ) ( e == 1.0 ? 1e34 : ( e < 1 ? p * e / ( 1 - e * e ) : p * e / ( e * e - 1 ) ) )
61
62/// Calculate the eccentricity of a <a href="http://en.wikipedia.org/wiki/Conic_section">conic section</a> given the
63/// semi-major axis and the focal parameter
64/**
65 * \ingroup geo
66 */
67#define eccent( a, p ) \
68 ( a == 0.0 ? 1e34 \
69 : ( p >= 1e9 ? 0.0 \
70 : ( p > 0 ? ( -p / ( 2 * a ) + 0.5 * std::sqrt( p * p / ( a * a ) + 4 ) ) \
71 : ( p / ( 2 * a ) + 0.5 * std::sqrt( p * p / ( a * a ) + 4 ) ) ) ) )
72
73/// Type specifying angles in radians
74/**
75 */
76struct radians;
77
78/// Type specifying angles in degrees
79/**
80 */
81struct degrees;
82
83/// Type holding constants related to angle calculations in degrees
84template <typename degrad, typename realT>
85struct degradT;
86
87/// Type holding constants related to angle calculations in degrees
88/**
89 */
90template <typename _realT>
91struct degradT<degrees, _realT>
92{
93 typedef _realT realT;
94 static constexpr realT scale =
95 static_cast<realT>( 180 ) / pi<realT>(); // Scale factor to convert from radians to this unit.
96 static constexpr realT degrees = 1;
97 static constexpr realT radians = pi<realT>() / static_cast<realT>( 180 );
98 static constexpr realT full = static_cast<realT>( 360.0 );
99 static constexpr realT half = static_cast<realT>( 180.0 );
100};
101
102template <typename realT>
103using degreesT = degradT<degrees, realT>;
104
105/// Type holding constants related to angle calculations in radians
106/**
107 */
108template <typename _realT>
109struct degradT<radians, _realT>
110{
111 typedef _realT realT;
112 static constexpr realT scale = 1; // Scale factor to convert from radians to this unit.
113 static constexpr realT degrees = static_cast<realT>( 180 ) / pi<realT>();
114 static constexpr realT radians = 1;
115 static constexpr realT full = two_pi<realT>();
116 static constexpr realT half = pi<realT>();
117};
118
119template <typename realT>
120using radiansT = degradT<radians, realT>;
121
122/// Convert from degrees to radians
123/**
124 *
125 * \param q is the angle to convert
126 *
127 * \return the angle q converted to radians
128 *
129 *
130 * \ingroup geo
131 */
132template <typename realT>
133realT dtor( realT q )
134{
136}
137
138/// Convert from radians to degrees
139/**
140 *
141 * \param q is the angle to convert
142 *
143 * \return the angle q converted to degrees
144 *
145 * \ingroup geo
146 */
147template <typename realT>
148realT rtod( realT q )
149{
151}
152
153/// Calculate the angle modulo full-circle, normalizing to a positive value.
154/** The output will be betweeen 0 and 360 (or 0 and 2pi).
155 *
156 * \returns the value of q normalized to 0 <= q < 360[2pi]
157 *
158 * \tparam degrad controls whether this is in degrees (0, default) or radians (1)
159 * \tparam realT is the type in which to do arithmetic
160 *
161 * \ingroup geo
162 */
163template <class angleT>
164typename angleT::realT angleMod( typename angleT::realT q /**< [in] the angle */ )
165{
166 static_assert( std::is_floating_point<typename angleT::realT>::value,
167 "angleMod: angleT::realT must be floating point" );
168
169 q = fmod( q, angleT::full );
170
171 if( q < 0 )
172 q += angleT::full;
173
174 return q;
175}
176
177/// Calculate the difference between two angles, correctly across 0/360.
178/** Calculates \f$ dq = q2- q1 \f$, but accounts for crossing 0/360. This implies
179 * that \f$ dq \le 180 \f$.
180 *
181 *
182 * \returns the difference of q2 and q1
183 *
184 * \tparam angleT controls whether this is in degrees (0, default) or radians (1)
185 * \tparam realT is the type in which to do arithmetic
186 *
187 *
188 * \ingroup geo
189 */
190template <class angleT>
191typename angleT::realT angleDiff( typename angleT::realT q1, ///< [in] angle to subtract from q2.
192 typename angleT::realT q2 ///< [in] angle to subtract q1 from.
193)
194{
195 static_assert( std::is_floating_point<typename angleT::realT>::value, "angleDiff: realT must be floating point" );
196
197 typename angleT::realT dq = q2 - q1;
198
199 if( std::abs( dq ) > angleT::half )
200 {
201 if( dq < 0 )
202 {
203 dq = dq + static_cast<typename angleT::realT>( 2 ) * angleT::half;
204 }
205 else
206 {
207 dq = dq - static_cast<typename angleT::realT>( 2 ) * angleT::half;
208 }
209 }
210
211 return dq;
212}
213
214/// Calculate the mean of a set of angles, correctly across 0/360.
215/** Calculates the mean by decomposing into vectors and averaging the components. This accounts for crossing 0/360.
216 *
217 * \returns the mean angle
218 *
219 * \tparam angleT is the angle type, either radians<realT> or degrees<realT>. angleT::realT is the type in which to do
220 * arithmetic.
221 *
222 * \ingroup geo
223 */
224template <class angleT>
225typename angleT::realT
226angleMean( const std::vector<typename angleT::realT> &q /**< [in] vector of angles to average.*/ )
227{
228 static_assert( std::is_floating_point<typename angleT::realT>::value, "angleMean: realT must be floating point" );
229
230 typename angleT::realT s = 0;
231 typename angleT::realT c = 0;
232
233 for( int i = 0; i < q.size(); ++i )
234 {
235 s += sin( q[i] / angleT::scale );
236 c += cos( q[i] / angleT::scale );
237 }
238
239 s /= q.size();
240 c /= q.size();
241
242 return atan2( s, c ) * angleT::scale;
243}
244
245/// Make a vector of angles continuous, fixing the 0/360 crossing.
246/** The vector is modified so it is continuous.
247 *
248 *
249 * \tparam degrad controls whether angles are degrees (false) or radians (true)
250 * \tparam realT is the type in which to do arithmetic
251 *
252 * \ingroup geo
253 */
254template <int degrad = 0, typename realT>
255int continueAngles( std::vector<realT> &angles, ///< [in] the vector of angles
256 realT threshold = 0.75 ///< [in] [optional] the fraction of a full circle at which to consider a
257 ///< difference in angle discontinuous.
258)
259{
260 realT full;
261
262 if( degrad )
263 full = two_pi<realT>();
264 else
265 full = static_cast<realT>( 360 );
266
267 threshold *= full;
268
269 realT adj = 0;
270
271 if( fabs( angles[1] - angles[0] ) > threshold )
272 {
273 if( angles[1] > angles[0] )
274 adj = -full;
275 else
276 adj = full;
277
278 angles[1] += adj;
279 }
280
281 if( angles.size() == 2 )
282 return 0;
283
284 for( int i = 2; i < angles.size(); ++i )
285 {
286 angles[i] += adj;
287
288 if( fabs( angles[i] - angles[i - 1] ) > threshold )
289 {
290 if( angles[i] > angles[i - 1] )
291 adj += -full;
292 else
293 adj += full;
294
295 angles[i] += adj;
296 }
297 }
298
299 return 0;
300}
301
302/// Rotate a point about the origin.
303/** The rotation is counter-clockwise for positive angles.
304 *
305 * \tparam realT a real floating point type
306 *
307 * \ingroup geo
308 */
309template <typename realT>
310void rotatePoint( realT &x0, ///< [in.out] the x-coordinate of the point to rotate. On exit contains the rotated value.
311 realT &y0, ///< [in.out] the y-coordinate of the point to rotate. On exit contains the rotated value.
312 realT angle ///< [in] the angle by which to rotate [radians]
313)
314{
315 realT x1;
316 realT y1;
317
318 realT cq = cos( angle );
319 realT sq = sin( angle );
320
321 x1 = x0 * cq - y0 * sq;
322 y1 = x0 * sq + y0 * cq;
323
324 x0 = x1;
325 y0 = y1;
326}
327
328} // namespace math
329} // namespace mx
330
331#endif // math_geo_hpp
constexpr T pi()
Get the value of pi.
Definition constants.hpp:62
constexpr T two_pi()
Get the value of 2pi.
int continueAngles(std::vector< realT > &angles, realT threshold=0.75)
Make a vector of angles continuous, fixing the 0/360 crossing.
Definition geo.hpp:255
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:164
realT rtod(realT q)
Convert from radians to degrees.
Definition geo.hpp:148
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:226
realT dtor(realT q)
Convert from degrees to radians.
Definition geo.hpp:133
void rotatePoint(realT &x0, realT &y0, realT angle)
Rotate a point about the origin.
Definition geo.hpp:310
The mxlib c++ namespace.
Definition mxlib.hpp:37
Type holding constants related to angle calculations in degrees.
Definition geo.hpp:85