libcrn  3.9.5
A document image processing library
•All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNTrigonometry.h
Go to the documentation of this file.
1 /* Copyright 2006-2015 Yann LEYDIER, CoReNum, Université Paris Descartes
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNTrigonometry.h
19  * \author Yann LEYDIER
20  */
21 
22 #ifndef CRNTrigonometry_HEADER
23 #define CRNTrigonometry_HEADER
24 
25 #include <CRN.h>
26 #include <CRNException.h>
27 #include <cmath>
28 #include <vector>
29 
31 namespace crn
32 {
36  struct Radian
37  {
38  using type = double;
39  static constexpr type MAXVAL = 2.0 * M_PI;
40  static constexpr TypeInfo<type>::SumType VAL2PI = 2.0 * M_PI;
41  };
43  struct Degree
44  {
45  using type = double;
46  static constexpr type MAXVAL = 360;
47  static constexpr TypeInfo<type>::SumType VAL2PI = 360;
48  };
50  struct ByteAngle
51  {
52  using type = uint8_t;
53  static constexpr type MAXVAL = 255;
54  static constexpr TypeInfo<type>::SumType VAL2PI = 256;
55  };
56 
61  template<typename Unit> inline double Cosine(typename Unit::type angle) noexcept
62  {
63  return cos(angle * Radian::MAXVAL / Unit::MAXVAL);
64  }
65 
70  template<typename Unit> inline double Sine(typename Unit::type angle) noexcept
71  {
72  return sin(angle * Radian::MAXVAL / Unit::MAXVAL);
73  }
74 
79  template<typename Unit> inline double Tangent(typename Unit::type angle) noexcept
80  {
81  return tan(angle * Radian::MAXVAL / Unit::MAXVAL);
82  }
83 
88  template<> inline double Cosine<ByteAngle>(uint8_t angle) noexcept
89  {
90  static double costab[256];
91  static bool init = false;
92  if (!init)
93  {
94  init = true;
95  for (int tmp = 0; tmp < 256; ++tmp)
96  costab[tmp] = cos(tmp * Radian::MAXVAL / ByteAngle::MAXVAL);
97  }
98  return costab[angle];
99  }
100 
105  template<> inline double Sine<ByteAngle>(uint8_t angle) noexcept
106  {
107  static double sintab[256];
108  static bool init = false;
109  if (!init)
110  {
111  init = true;
112  for (int tmp = 0; tmp < 256; ++tmp)
113  sintab[tmp] = sin(tmp * Radian::MAXVAL / ByteAngle::MAXVAL);
114  }
115  return sintab[angle];
116  }
117 
122  template<> inline double Tangent<ByteAngle>(uint8_t angle) noexcept
123  {
124  static double tantab[256];
125  static bool init = false;
126  if (!init)
127  {
128  init = true;
129  for (int tmp = 0; tmp < 256; ++tmp)
130  tantab[tmp] = tan(tmp * Radian::MAXVAL / ByteAngle::MAXVAL);
131  }
132  return tantab[angle];
133  }
134 
139  template<typename Unit> struct Angle
140  {
141  using unit = Unit;
143  constexpr Angle() noexcept(std::is_nothrow_constructible<typename Unit::type>::value)
144  : value(0) { }
146  inline Angle(typename Unit::type val) noexcept(std::is_nothrow_constructible<typename Unit::type>::value)
147  : value(val)
148  {
150  while (tmp >= Unit::VAL2PI)
151  tmp -= typename TypeInfo<typename Unit::type>::SumType(Unit::VAL2PI);
152  while (tmp < 0)
153  tmp += Unit::VAL2PI;
154  value = typename Unit::type(tmp);
155  }
157  template<typename U> inline Angle(const Angle<U> &other) noexcept(
158  std::is_nothrow_constructible<typename U::type>::value &&
159  std::is_nothrow_constructible<typename TypeInfo<typename Unit::type>::SumType>::value)
160  : value(other.template Get<Unit>())
161  {
163  while (tmp >= Unit::VAL2PI)
164  tmp -= Unit::VAL2PI;
165  while (tmp < 0)
166  tmp += Unit::VAL2PI;
167  value = typename Unit::type(tmp);
168  }
169  Angle(const Angle&) = default;
170  Angle(Angle&&) = default;
171  Angle& operator=(const Angle&) = default;
172  Angle& operator=(Angle&&) = default;
173 
175  template<typename U> inline typename U::type Get() const noexcept(
176  std::is_nothrow_constructible<typename U::type>::value &&
177  std::is_nothrow_constructible<typename TypeInfo<typename Unit::type>::SumType>::value)
178  {
179  return typename U::type(((typename TypeInfo<typename Unit::type>::SumType)value * U::MAXVAL) / Unit::MAXVAL);
180  }
181 
183  inline Angle operator-() const noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value)
184  { Angle a(Unit::VAL2PI); return a -= *this; }
185 
187  inline const Angle& operator+=(typename Unit::type angle) noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value)
188  {
190  tmp += angle;
191  while (tmp >= Unit::VAL2PI)
192  tmp -= Unit::VAL2PI;
193  value = typename Unit::type(tmp);
194  return *this;
195  }
197  inline const Angle& operator+=(const Angle &other) noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value) { return this->operator+=(other.value); }
199  inline Angle operator+(const Angle &other) const noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value){ Angle a(*this); return a+= other; }
200 
202  inline const Angle& operator-=(typename Unit::type angle) noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value)
203  {
205  tmp -= angle;
206  while (tmp < 0)
207  tmp += Unit::VAL2PI;
208  value = typename Unit::type(tmp);
209  return *this;
210  }
212  inline const Angle& operator-=(const Angle &other) noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value)
213  { return this->operator-=(other.value); }
215  inline Angle operator-(const Angle &other) const noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value)
216  { Angle a(*this); return a -= other; }
217 
219  inline Angle& operator*=(double f) noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value)
220  {
221  auto tmp = double(value) * f;
222  while (tmp >= Unit::VAL2PI)
223  tmp -= Unit::VAL2PI;
224  while (tmp < 0)
225  tmp += Unit::VAL2PI;
226  value = typename Unit::type(tmp);
227  return *this;
228  }
230  inline Angle& operator*(double f) noexcept(std::is_nothrow_copy_assignable<typename Unit::type>::value) { auto a(*this); return a *= f; }
231 
233  inline bool operator==(const Angle &other) const noexcept { return value == other.value; }
234 
236  inline double Cos() const noexcept { return crn::Cosine<Unit>(value); }
238  inline double Sin() const noexcept { return crn::Sine<Unit>(value); }
240  inline double Tan() const noexcept { return crn::Tangent<Unit>(value); }
241 
243  static inline Angle Acos(double cosine) noexcept(std::is_nothrow_constructible<typename Unit::type>::value) { return Angle<Radian>(acos(cosine)); }
245  static inline Angle Asin(double sine) noexcept(std::is_nothrow_constructible<typename Unit::type>::value) { return Angle<Radian>(asin(sine)); }
247  static inline Angle Atan(double tangent) noexcept(std::is_nothrow_constructible<typename Unit::type>::value) { return Angle<Radian>(atan(tangent)); }
249  static inline Angle Atan(double y, double x) noexcept(std::is_nothrow_constructible<typename Unit::type>::value) { return Angle<Radian>(atan2(y, x)); }
250 
251  static constexpr Angle<Unit> LEFT() { return typename Unit::type(0); }
252  static constexpr Angle<Unit> RIGHT() { return typename Unit::type(Unit::MAXVAL / 2); }
253  static constexpr Angle<Unit> TOP() { return typename Unit::type(Unit::MAXVAL / 4); }
254  static constexpr Angle<Unit> BOTTOM() { return typename Unit::type((3 * (typename TypeInfo<typename Unit::type>::SumType)Unit::MAXVAL) / 4); }
256  typename Unit::type value;
257  };
258 
259  template<class ANGLE> using Unit = typename ANGLE::unit;
260 
262  template<typename Unit> inline Angle<Unit> operator+(const Angle<Unit> &a1, const Angle<Unit> &a2)
263  noexcept(
264  std::is_nothrow_constructible<typename Unit::type>::value &&
265  std::is_nothrow_copy_assignable<typename Unit::type>::value)
266  {
267  Angle<Unit> tmp(a1);
268  tmp += a2;
269  return tmp;
270  }
271 
273  template<typename Unit> inline Angle<Unit> operator-(const Angle<Unit> &a1, const Angle<Unit> &a2)
274  noexcept(
275  std::is_nothrow_constructible<typename Unit::type>::value &&
276  std::is_nothrow_copy_assignable<typename Unit::type>::value)
277  {
278  Angle<Unit> tmp(a1);
279  tmp -= a2;
280  return tmp;
281  }
282 
284  template<typename Unit> inline Angle<Unit> operator*(double f, const Angle<Unit> &a)
285  noexcept(
286  std::is_nothrow_constructible<typename Unit::type>::value &&
287  std::is_nothrow_copy_assignable<typename Unit::type>::value)
288  {
289  Angle<Unit> tmp(a);
290  return tmp *= f;
291  }
292 
293  namespace literals
294  {
295  inline Angle<Degree> operator"" _deg(long double val)
296  {
297  return Angle<Degree>{double(val)};
298  }
299  inline Angle<Radian> operator"" _rad(long double val)
300  {
301  return Angle<Radian>{double(val)};
302  }
303  inline Angle<ByteAngle> operator"" _ba(unsigned long long int val)
304  {
305  return Angle<ByteAngle>{uint8_t(val % 256)};
306  }
307  }
308 
310  template<class A> inline double Cos(const A &a) noexcept { return a.Cos(); }
312  inline double Cos(double a) noexcept { return cos(a); }
314  inline double Cos(uint8_t a) noexcept { return Cosine<ByteAngle>(a); }
316  template<class A> inline double Sin(const A &a) noexcept { return a.Sin(); }
318  inline double Sin(double a) noexcept { return sin(a); }
320  inline double Sin(uint8_t a) noexcept { return Sine<ByteAngle>(a); }
322  template<class A> inline double Tan(const A &a) noexcept { return a.Tan(); }
324  inline double Tan(double a) noexcept { return Tan(a); }
326  inline double Tan(uint8_t a) noexcept { return Tangent<ByteAngle>(a); }
328  template<class A> inline A Atan(double s, double c) noexcept { return A::Atan(s, c); }
330  template<> inline double Atan<double>(double s, double c) noexcept { return atan2(s, c); }
331 
341  template<typename Unit> inline typename Unit::type AngularDistance(const Angle<Unit> &a1, const Angle<Unit> &a2) noexcept(
342  std::is_nothrow_constructible<typename TypeInfo<typename Unit::type>::DiffType>::value &&
343  std::is_nothrow_copy_assignable<typename TypeInfo<typename Unit::type>::DiffType>::value &&
344  std::is_nothrow_constructible<typename Unit::type>::value)
345  {
346  // TODO what is the fastest? min(a-b, 2PI - (a-b)) or PI - abs(PI - abs(a-b))
348  if (dist > Unit::MAXVAL / 2)
349  dist = Unit::MAXVAL - dist;
350  return typename Unit::type(dist);
351  }
359  inline double AngularDistance(double a1, double a2) noexcept
360  {
361  const auto dist = Abs(a1 - a2);
362  return (dist > M_PI) ? (M_PI - dist) : dist;
363  }
364 
371  template<typename ITER> typename std::iterator_traits<ITER>::value_type AngularMean(ITER beg, ITER en)
372  {
373  using return_type = typename std::iterator_traits<ITER>::value_type;
374  if (beg == en)
375  throw ExceptionDomain("AngularMean(): empty set of angles.");
376  double s = 0, c = 0;
377  for (ITER it = beg; it != en; ++it)
378  {
379  s += Sin(*it);
380  c += Cos(*it);
381  }
382  return Atan<return_type>(s, c);
383  }
384 
391  template<typename ITER> ITER AngularMedian(ITER beg, ITER en)
392  {
393  if (beg == en)
394  throw ExceptionDomain("AngularMedian(): empty set of angles.");
395  auto mdist = std::vector<double>(std::distance(beg, en), 0.0);
396  auto cnt1 = size_t(0);
397  for (auto it1 = beg; it1 != en; ++cnt1, ++it1)
398  {
399  auto cnt2 = cnt1 + 1;
400  for (auto it2 = std::next(it1); it2 != en; ++cnt2, ++it2)
401  {
402  const auto d = AngularDistance(*it1, *it2);
403  mdist[cnt1] += d;
404  mdist[cnt2] += d;
405  }
406  }
407  return std::next(beg, std::min_element(mdist.begin(), mdist.end()) - mdist.begin());
408  }
409 
416  template<typename ITER> double AngularVariance(ITER beg, ITER en)
417  {
418  using angle_type = typename std::iterator_traits<ITER>::value_type;
419  if (beg == en)
420  throw ExceptionDomain("AngularVariance(): empty set of angles.");
421  angle_type mean(AngularMean(beg, en));
422  double acc = 0;
423  for (ITER it = beg; it != en; ++it)
424  {
425  acc += Sqr(AngularDistance<typename angle_type::unit>(mean, *it));
426  }
427  return acc / double(std::distance(beg, en));
428  }
429 
437  template<typename ITER> double AngularVariance(ITER beg, ITER en, typename std::iterator_traits<ITER>::value_type mean)
438  {
439  using angle_type = typename std::iterator_traits<ITER>::value_type;
440  if (beg == en)
441  throw ExceptionDomain("AngularVariance(): empty set of angles.");
442  double acc = 0;
443  for (ITER it = beg; it != en; ++it)
444  {
445  acc += Sqr(AngularDistance<typename angle_type::unit>(mean, *it));
446  }
447  return acc / double(std::distance(beg, en));
448  }
449 
456  template<typename ITER> double CircularVariance(ITER beg, ITER en)
457  {
458  if (beg == en)
459  throw ExceptionDomain("CircularVariance(): empty set of angles.");
460  auto c = 0.0, s = 0.0;
461  for (ITER it = beg; it != en; ++it)
462  {
463  c += it->Cos();
464  s += it->Sin();
465  }
466  auto n = double(std::distance(beg, en));
467  return 1.0 - sqrt(Sqr(c / n) + Sqr(s / n));
468  }
469 
476  template<typename ITER> double CircularStdDev(ITER beg, ITER en)
477  {
478  return sqrt(-2.0 * log(1.0 - CircularVariance(beg, en)));
479  }
480 
490  template<typename ITER> typename std::complex<double> TrigonometricMoment(ITER beg, ITER en, typename std::iterator_traits<ITER>::value_type refer, size_t p)
491  {
492  if (beg == en)
493  throw ExceptionDomain("TrigonometricMoment(): empty set of angles.");
494  if (p == 0)
495  throw ExceptionInvalidArgument("TrigonometricMoment(): null order.");
496  auto c = 0.0, s = 0.0;
497  for (auto it = beg; it != en; ++it)
498  {
499  c += Cos(double(p) * (*it - refer));
500  s += Sin(double(p) * (*it - refer));
501  }
502  const auto n = double(std::distance(beg, en));
503  c /= n;
504  s /= n;
505  return std::complex<double>(c, s);
506  }
507 
514  template<typename ITER> double AngularSkewness(ITER beg, ITER en)
515  {
516  if (beg == en)
517  throw ExceptionDomain("AngularSkewness(): empty set of angles.");
518  const auto m = AngularMean(beg, en);
519  const auto m1 = TrigonometricMoment(beg, en, m, 1);
520  const auto m2 = TrigonometricMoment(beg, en, m, 2);
521  return std::abs(m2) * Sin(Angle<Radian>(std::arg(m2)) - 2 * m) / pow(1 - std::abs(m1), 1.5);
522  }
523 
530  template<typename ITER> double AngularKurtosis(ITER beg, ITER en)
531  {
532  if (beg == en)
533  throw ExceptionDomain("AngularKurtosis(): empty set of angles.");
534  const auto m = AngularMean(beg, en);
535  const auto m1 = TrigonometricMoment(beg, en, m, 1);
536  const auto m2 = TrigonometricMoment(beg, en, m, 2);
537  return (std::abs(m2) * Cos(Angle<Radian>(std::arg(m2)) - 2 * m) - pow(std::abs(m1), 4)) / Sqr(1 - std::abs(m1));
538  }
539 
542 }
543 
544 #endif
545 
546 
Angle & operator*=(double f) noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Multiplies by a scalar.
typename TypeInfo< T >::SumType SumType
Definition: CRNType.h:185
BoolNotBoolDummy operator-(const BoolNotBoolDummy &, const BoolNotBoolDummy &)
Definition: CRNImage.h:124
Unit::type AngularDistance(const Angle< Unit > &a1, const Angle< Unit > &a2) noexcept(std::is_nothrow_constructible< typename TypeInfo< typename Unit::type >::DiffType >::value &&std::is_nothrow_copy_assignable< typename TypeInfo< typename Unit::type >::DiffType >::value &&std::is_nothrow_constructible< typename Unit::type >::value)
Distance between two angles.
const Angle & operator-=(typename Unit::type angle) noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Subtracts an angle.
Angle(typename Unit::type val) noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Constructor from a value.
double Sine< ByteAngle >(uint8_t angle) noexcept
Sine of a byte angle using a lookup table.
Angle(const Angle< U > &other) noexcept(std::is_nothrow_constructible< typename U::type >::value &&std::is_nothrow_constructible< typename TypeInfo< typename Unit::type >::SumType >::value)
Constructor from any other angle unit.
static constexpr Angle< Unit > RIGHT()
static Angle Asin(double sine) noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Computes arc sine.
Angle operator-(const Angle &other) const noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Subtracts an angle.
static constexpr type MAXVAL
double Tan() const noexcept
Computes tangent.
double Cos(const A &a) noexcept
Radian angle unit.
double Sine(typename Unit::type angle) noexcept
Sine of an angle.
static constexpr TypeInfo< type >::SumType VAL2PI
double Atan< double >(double s, double c) noexcept
decltype(std::declval< T >()-std::declval< T >()) DiffType
A safe type to compute a difference (e.g.: a signed type)
Definition: CRNType.h:181
const Angle & operator+=(const Angle &other) noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Adds an angle.
constexpr Angle() noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Null angle.
#define M_PI
Definition: CRNMath.h:38
static constexpr type MAXVAL
std::iterator_traits< ITER >::value_type AngularMean(ITER beg, ITER en)
Mean of a set of angles.
Angle operator-() const noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Negative of the angle.
A convenience class for angles units.
double Cosine(typename Unit::type angle) noexcept
Cosine of an angle.
ITER AngularMedian(ITER beg, ITER en)
Mean of a set of angles.
const Angle & operator+=(typename Unit::type angle) noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Adds an angle.
A generic domain error.
Definition: CRNException.h:83
BYTE angle unit.
const Angle & operator-=(const Angle &other) noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Subtracts an angle.
static constexpr TypeInfo< type >::SumType VAL2PI
U::type Get() const noexcept(std::is_nothrow_constructible< typename U::type >::value &&std::is_nothrow_constructible< typename TypeInfo< typename Unit::type >::SumType >::value)
Conversion to any other angle unit.
BoolNotBoolDummy operator*(const BoolNotBoolDummy &, const BoolNotBoolDummy &)
Definition: CRNImage.h:125
decltype(std::declval< T >()+std::declval< T >()) SumType
A safe type to compute a sum (e.g.: a larger integer type)
Definition: CRNType.h:179
BoolNotBoolDummy operator+(const BoolNotBoolDummy &, const BoolNotBoolDummy &)
Definition: CRNImage.h:123
constexpr SumType< T > Sqr(const T &v) noexcept(noexcept(v *v))
Returns the square of a value.
Definition: CRNMath.h:61
static constexpr Angle< Unit > LEFT()
bool operator==(const Angle &other) const noexcept
Comparison operator.
double AngularVariance(ITER beg, ITER en)
Variance of a set of angles.
double Tangent(typename Unit::type angle) noexcept
Tangent of an angle.
double Sin() const noexcept
Computes sine.
A Atan(double s, double c) noexcept
double CircularStdDev(ITER beg, ITER en)
Circular (pseudo) standard deviation of a set of angles.
double Cos() const noexcept
Computes cosine.
Angle operator+(const Angle &other) const noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Adds an angle.
static constexpr type MAXVAL
static constexpr TypeInfo< type >::SumType VAL2PI
double Tangent< ByteAngle >(uint8_t angle) noexcept
Tangent of a byte angle using a lookup table.
Unit::type value
void Abs(Image< T > &img, typename std::enable_if< std::is_arithmetic< T >::value >::type *dummy=nullptr) noexcept
Replaces each pixel by its absolute value.
Definition: CRNImageGray.h:47
double AngularKurtosis(ITER beg, ITER en)
Kurtosis of a set of angles.
double CircularVariance(ITER beg, ITER en)
Circular (pseudo) variance of a set of angles.
Degree angle unit.
double Sin(const A &a) noexcept
Angle & operator*(double f) noexcept(std::is_nothrow_copy_assignable< typename Unit::type >::value)
Multiplies by a scalar.
static constexpr Angle< Unit > BOTTOM()
double Tan(const A &a) noexcept
double Cosine< ByteAngle >(uint8_t angle) noexcept
Cosine of a byte angle using a lookup table.
double AngularSkewness(ITER beg, ITER en)
Skewness of a set of angles.
Angle & operator=(const Angle &)=default
typename ANGLE::unit Unit
static constexpr Angle< Unit > TOP()
static Angle Acos(double cosine) noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Computes arc cosine.
A class containing informations on a type.
Definition: CRNType.h:176
std::complex< double > TrigonometricMoment(ITER beg, ITER en, typename std::iterator_traits< ITER >::value_type refer, size_t p)
Trigonometric moment.
static Angle Atan(double y, double x) noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Computes arc tangent from coordinates.
Invalid argument error (e.g.: nullptr pointer)
Definition: CRNException.h:107
static Angle Atan(double tangent) noexcept(std::is_nothrow_constructible< typename Unit::type >::value)
Computes arc tangent.