Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpMath.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Simple mathematical function not available in the C math library (math.h).
32  */
33 
40 #ifndef VP_MATH_H
41 #define VP_MATH_H
42 
43 #include <visp3/core/vpConfig.h>
44 
45 #include <algorithm>
46 #include <climits>
47 #include <limits>
48 #if defined(_WIN32)
49 // Define _USE_MATH_DEFINES before including <math.h> to expose these macro
50 // definitions for common math constants. These are placed under an #ifdef
51 // since these commonly-defined names are not part of the C or C++ standards
52 #ifndef _USE_MATH_DEFINES
53 #define _USE_MATH_DEFINES
54 #endif
55 #endif
56 #include <math.h>
57 #include <vector>
58 
59 #if defined(VISP_HAVE_FUNC_ISNAN) || defined(VISP_HAVE_FUNC_STD_ISNAN) || defined(VISP_HAVE_FUNC_ISINF) || \
60  defined(VISP_HAVE_FUNC_STD_ISINF) || defined(VISP_HAVE_FUNC_STD_ROUND)
61 #include <cmath>
62 #endif
63 
64 #if defined(_WIN32) // Not defined in Microsoft math.h
65 
66 #ifndef M_PI
67 #define M_PI 3.14159265358979323846
68 #endif
69 
70 #ifndef M_PI_2
71 #define M_PI_2 (M_PI / 2.0)
72 #endif
73 
74 #ifndef M_PI_4
75 #define M_PI_4 (M_PI / 4.0)
76 #endif
77 
78 #endif
79 
80 #ifndef M_PI_FLOAT
81 #define M_PI_FLOAT 3.14159265358979323846f
82 #endif
83 
84 #ifndef M_PI_2_FLOAT
85 #define M_PI_2_FLOAT (M_PI_FLOAT / 2.0f)
86 #endif
87 
88 #ifndef M_PI_4_FLOAT
89 #define M_PI_4_FLOAT (M_PI_FLOAT / 4.0f)
90 #endif
91 
92 #include <visp3/core/vpException.h>
93 #include <visp3/core/vpImagePoint.h>
94 
96 
97 class vpPoint;
99 class vpColVector;
100 class vpRotationVector;
101 class vpRxyzVector;
102 class vpTranslationVector;
103 
110 class VISP_EXPORT vpMath
111 {
112 public:
119  static inline double deg(double rad) { return (rad * 180.0) / M_PI; }
120 
121  static vpColVector deg(const vpRotationVector &r);
122  static vpColVector deg(const vpColVector &r);
123 
129  static inline double rad(double deg) { return (deg * M_PI) / 180.0; }
130 
131  static vpColVector rad(const vpColVector &r);
132 
139  static float getAngleBetweenMinPiAndPi(const float &theta)
140  {
141  float theta1 = theta;
142  if (theta1 > M_PI_FLOAT) {
143  theta1 -= 2.0f * M_PI_FLOAT;
144  }
145  else if (theta1 <= -M_PI_FLOAT) {
146  theta1 += 2.0f * M_PI_FLOAT;
147  }
148  return theta1;
149  }
150 
157  static double getAngleBetweenMinPiAndPi(const double &theta)
158  {
159  double theta1 = theta;
160  if (theta1 > M_PI) {
161  theta1 -= 2.0 * M_PI;
162  }
163  else if (theta1 < -M_PI) {
164  theta1 += 2.0 * M_PI;
165  }
166  return theta1;
167  }
168 
177  static float modulo(const float &value, const float &modulo)
178  {
179  float quotient = std::floor(value / modulo);
180  float rest = value - (quotient * modulo);
181  return rest;
182  }
183 
192  static double modulo(const double &value, const double &modulo)
193  {
194  double quotient = std::floor(value / modulo);
195  double rest = value - (quotient * modulo);
196  return rest;
197  }
198 
203  static inline double sqr(double x) { return x * x; }
204 
205  // factorial of x
206  static inline double fact(unsigned int x);
207 
208  // combinaison
209  static inline long double comb(unsigned int n, unsigned int p);
210 
218  template <typename T> static inline T clamp(const T &v, const T &lower, const T &upper)
219  {
220  // Check if std:c++17 or higher.
221  // Here we cannot use (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17) when ViSP
222  // is used as a 3rdparty. See issue #1274
223 #if ((__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
224  return std::clamp(v, lower, upper);
225 #else
226  if (upper < lower) {
227  throw vpException(vpException::badValue, "clamp: lower bound is greater than upper bound");
228  }
229  return (v < lower) ? lower : (upper < v) ? upper : v;
230 #endif
231  }
232 
233  // round x to the nearest integer
234  static inline int round(double x);
235 
236  // return the sign of x (+-1)
237  static inline int sign(double x);
238 
239  // test if a number equals 0 (with threshold value)
240  static inline bool nul(double x, double threshold = 0.001);
241 
242  // test if two numbers are equals (with a user defined threshold)
243  static inline bool equal(double x, double y, double threshold = 0.001);
244 
245  // test if a number is greater than another (with a user defined threshold)
246  static inline bool greater(double x, double y, double threshold = 0.001);
247 
254  template <class Type> static Type maximum(const Type &a, const Type &b) { return (a > b) ? a : b; }
255 
262  template <class Type> static Type minimum(const Type &a, const Type &b) { return (a < b) ? a : b; }
263 
269  template <class Type> static Type abs(const Type &x) { return (x < 0) ? -x : x; }
270 
271  // sinus cardinal
272  static double sinc(double x);
273  static double sinc(double sinx, double x);
274  static double mcosc(double cosx, double x);
275  static double msinc(double sinx, double x);
276 
277  // sigmoid
278  static inline double sigmoid(double x, double x0 = 0., double x1 = 1., double n = 12.);
279 
286  template <class Type> static void swap(Type &a, Type &b)
287  {
288  Type tmp = b;
289  b = a;
290  a = tmp;
291  }
292 
293  static bool isNaN(double value);
294  static bool isNaN(float value);
295  static bool isInf(double value);
296  static bool isInf(float value);
297  static bool isFinite(double value);
298  static bool isFinite(float value);
299  static bool isNumber(const std::string &str);
300 
301  static double lineFitting(const std::vector<vpImagePoint> &imPts, double &a, double &b, double &c);
302 
303  template <typename Tp> static inline Tp saturate(unsigned char v) { return Tp(v); }
304  template <typename Tp> static inline Tp saturate(char v) { return Tp(v); }
305  template <typename Tp> static inline Tp saturate(unsigned short v) { return Tp(v); }
306  template <typename Tp> static inline Tp saturate(short v) { return Tp(v); }
307  template <typename Tp> static inline Tp saturate(unsigned v) { return Tp(v); }
308  template <typename Tp> static inline Tp saturate(int v) { return Tp(v); }
309  template <typename Tp> static inline Tp saturate(float v) { return Tp(v); }
310  template <typename Tp> static inline Tp saturate(double v) { return Tp(v); }
311 
312  static double getMean(const std::vector<double> &v);
313  static double getMedian(const std::vector<double> &v);
314  static double getStdev(const std::vector<double> &v, bool useBesselCorrection = false);
315 
316  static int modulo(int a, int n);
317 
318  static vpHomogeneousMatrix ned2ecef(double lonDeg, double latDeg, double radius);
319  static vpHomogeneousMatrix enu2ecef(double lonDeg, double latDeg, double radius);
320  static vpHomogeneousMatrix enu2ned(const vpHomogeneousMatrix &enu_M);
321 
332  template <typename T> static std::vector<double> linspace(T start_in, T end_in, unsigned int num_in)
333  {
334  std::vector<double> linspaced;
335 
336  double start = static_cast<double>(start_in);
337  double end = static_cast<double>(end_in);
338  double num = static_cast<double>(num_in);
339 
340  if (std::fabs(num) < std::numeric_limits<double>::epsilon()) {
341  return linspaced;
342  }
343  if (std::fabs(num - 1) < std::numeric_limits<double>::epsilon()) {
344  linspaced.push_back(start);
345  return linspaced;
346  }
347 
348  double delta = (end - start) / (num - 1);
349 
350  for (int i = 0; i < (num - 1); ++i) {
351  linspaced.push_back(start + (delta * i));
352  }
353  linspaced.push_back(end); // I want to ensure that start and end
354  // are exactly the same as the input
355  return linspaced;
356  }
357 
358  static std::vector<std::pair<double, double> > computeRegularPointsOnSphere(unsigned int maxPoints);
359 
360  typedef vpHomogeneousMatrix(*LongLattToHomogeneous)(double lonDeg, double latDeg, double radius);
361  static std::vector<vpHomogeneousMatrix>
362  getLocalTangentPlaneTransformations(const std::vector<std::pair<double, double> > &lonlatVec, double radius,
363  LongLattToHomogeneous func);
364 
365  static vpHomogeneousMatrix lookAt(const vpColVector &from, const vpColVector &to, vpColVector tmp);
366 
367 private:
368  static const double ang_min_sinc;
369  static const double ang_min_mc;
370 };
371 
372 // Begining of the inline functions definition
373 
378 double vpMath::fact(unsigned int x)
379 {
380  if ((x == 1) || (x == 0)) {
381  return 1;
382  }
383  return x * fact(x - 1);
384 }
385 
394 long double vpMath::comb(unsigned int n, unsigned int p)
395 {
396  if (n == p) {
397  return 1;
398  }
399  return fact(n) / (fact(n - p) * fact(p));
400 }
401 
409 int vpMath::round(double x)
410 {
411 #if defined(VISP_HAVE_FUNC_STD_ROUND)
412  return static_cast<int>(std::round(x));
413 #elif defined(VISP_HAVE_FUNC_ROUND)
414  //:: to design the global namespace and avoid to call recursively
415  // vpMath::round
416  return static_cast<int>(::round(x));
417 #else
418  return (x > 0.0) ? (static_cast<int>(floor(x + 0.5))) : (static_cast<int>(ceil(x - 0.5)));
419 #endif
420 }
421 
428 int vpMath::sign(double x)
429 {
430  if (fabs(x) < std::numeric_limits<double>::epsilon()) {
431  return 0;
432  }
433  else {
434  if (x < 0) {
435  return -1;
436  }
437  else {
438  return 1;
439  }
440  }
441 }
442 
449 bool vpMath::nul(double x, double threshold) { return (fabs(x) < threshold); }
450 
458 bool vpMath::equal(double x, double y, double threshold) { return (nul(x - y, threshold)); }
459 
467 bool vpMath::greater(double x, double y, double threshold) { return (x > (y - threshold)); }
468 
480 double vpMath::sigmoid(double x, double x0, double x1, double n)
481 {
482  if (x < x0) {
483  return 0.;
484  }
485  else if (x > x1) {
486  return 1.;
487  }
488  double l0 = 1. / (1. + exp(0.5 * n));
489  double l1 = 1. / (1. + exp(-0.5 * n));
490  return ((1. / (1. + exp(-n * (((x - x0) / (x1 - x0)) - 0.5)))) - l0) / (l1 - l0);
491 }
492 
493 // unsigned char
494 template <> inline unsigned char vpMath::saturate<unsigned char>(char v)
495 {
496  // On big endian arch like powerpc, char implementation is unsigned
497  // with CHAR_MIN=0, CHAR_MAX=255 and SCHAR_MIN=-128, SCHAR_MAX=127
498  // leading to (int)(char -127) = 129.
499  // On little endian arch, CHAR_MIN=-127 and CHAR_MAX=128 leading to
500  // (int)(char -127) = -127.
501  if (std::numeric_limits<char>::is_signed) {
502  return static_cast<unsigned char>(std::max<int>(static_cast<int>(v), 0));
503  }
504  else {
505  return static_cast<unsigned char>(static_cast<unsigned int>(v) > SCHAR_MAX ? 0 : v);
506  }
507 }
508 
509 template <> inline unsigned char vpMath::saturate<unsigned char>(unsigned short v)
510 {
511  return static_cast<unsigned char>(std::min<unsigned int>(static_cast<unsigned int>(v), static_cast<unsigned int>(UCHAR_MAX)));
512 }
513 
514 template <> inline unsigned char vpMath::saturate<unsigned char>(int v)
515 {
516  return static_cast<unsigned char>(static_cast<unsigned int>(v) <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0);
517 }
518 
519 template <> inline unsigned char vpMath::saturate<unsigned char>(short v)
520 {
521  return saturate<unsigned char>(static_cast<int>(v));
522 }
523 
524 template <> inline unsigned char vpMath::saturate<unsigned char>(unsigned int v)
525 {
526  return static_cast<unsigned char>(std::min<unsigned int>(v, static_cast<unsigned int>(UCHAR_MAX)));
527 }
528 
529 template <> inline unsigned char vpMath::saturate<unsigned char>(float v)
530 {
531  int iv = vpMath::round(static_cast<double>(v));
532  return saturate<unsigned char>(iv);
533 }
534 
535 template <> inline unsigned char vpMath::saturate<unsigned char>(double v)
536 {
537  int iv = vpMath::round(v);
538  return saturate<unsigned char>(iv);
539 }
540 
541 // char
542 template <> inline char vpMath::saturate<char>(unsigned char v)
543 {
544  return static_cast<char>(std::min<int>(static_cast<int>(v), SCHAR_MAX));
545 }
546 
547 template <> inline char vpMath::saturate<char>(unsigned short v)
548 {
549  return static_cast<char>(std::min<unsigned int>(static_cast<unsigned int>(v), static_cast<unsigned int>(SCHAR_MAX)));
550 }
551 
552 template <> inline char vpMath::saturate<char>(int v)
553 {
554  return static_cast<char>(static_cast<unsigned int>(v - SCHAR_MIN) <= static_cast<unsigned int>(UCHAR_MAX) ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN);
555 }
556 
557 template <> inline char vpMath::saturate<char>(short v)
558 {
559  return saturate<char>(static_cast<int>(v));
560 }
561 
562 template <> inline char vpMath::saturate<char>(unsigned int v)
563 {
564  return static_cast<char>(std::min<unsigned int>(v, static_cast<unsigned int>(SCHAR_MAX)));
565 }
566 
567 template <> inline char vpMath::saturate<char>(float v)
568 {
569  int iv = vpMath::round(v);
570  return saturate<char>(iv);
571 }
572 
573 template <> inline char vpMath::saturate<char>(double v)
574 {
575  int iv = vpMath::round(v);
576  return saturate<char>(iv);
577 }
578 
579 // unsigned short
580 template <> inline unsigned short vpMath::saturate<unsigned short>(char v)
581 {
582  // On big endian arch like powerpc, char implementation is unsigned
583  // with CHAR_MIN=0, CHAR_MAX=255 and SCHAR_MIN=-128, SCHAR_MAX=127
584  // leading to (int)(char -127) = 129.
585  // On little endian arch, CHAR_MIN=-127 and CHAR_MAX=128 leading to
586  // (int)(char -127) = -127.
587  if (std::numeric_limits<char>::is_signed) {
588  return static_cast<unsigned short>(std::max<int>(static_cast<int>(v), 0));
589  }
590  else {
591  return static_cast<unsigned short>(static_cast<unsigned int>(v) > SCHAR_MAX ? 0 : v);
592  }
593 }
594 
595 template <> inline unsigned short vpMath::saturate<unsigned short>(short v)
596 {
597  return static_cast<unsigned short>(std::max<int>(static_cast<int>(v), 0));
598 }
599 
600 template <> inline unsigned short vpMath::saturate<unsigned short>(int v)
601 {
602  return static_cast<unsigned short>(static_cast<unsigned int>(v) <= static_cast<unsigned int>(USHRT_MAX) ? v : v > 0 ? USHRT_MAX : 0);
603 }
604 
605 template <> inline unsigned short vpMath::saturate<unsigned short>(unsigned int v)
606 {
607  return static_cast<unsigned short>(std::min<unsigned int>(v, static_cast<unsigned int>(USHRT_MAX)));
608 }
609 
610 template <> inline unsigned short vpMath::saturate<unsigned short>(float v)
611 {
612  int iv = vpMath::round(static_cast<double>(v));
613  return vpMath::saturate<unsigned short>(iv);
614 }
615 
616 template <> inline unsigned short vpMath::saturate<unsigned short>(double v)
617 {
618  int iv = vpMath::round(v);
619  return vpMath::saturate<unsigned short>(iv);
620 }
621 
622 // short
623 template <> inline short vpMath::saturate<short>(unsigned short v)
624 {
625  return static_cast<short>(std::min<int>(static_cast<int>(v), SHRT_MAX));
626 }
627 template <> inline short vpMath::saturate<short>(int v)
628 {
629  return static_cast<short>(static_cast<unsigned int>(v - SHRT_MIN) <= static_cast<unsigned int>(USHRT_MAX) ? v : v > 0 ? SHRT_MAX : SHRT_MIN);
630 }
631 template <> inline short vpMath::saturate<short>(unsigned int v)
632 {
633  return static_cast<short>(std::min<unsigned int>(v, static_cast<unsigned int>(SHRT_MAX)));
634 }
635 template <> inline short vpMath::saturate<short>(float v)
636 {
637  int iv = vpMath::round(static_cast<double>(v));
638  return vpMath::saturate<short>(iv);
639 }
640 template <> inline short vpMath::saturate<short>(double v)
641 {
642  int iv = vpMath::round(v);
643  return vpMath::saturate<short>(iv);
644 }
645 
646 // int
647 template <> inline int vpMath::saturate<int>(float v)
648 {
649  return vpMath::round(static_cast<double>(v));
650 }
651 
652 template <> inline int vpMath::saturate<int>(double v)
653 {
654  return vpMath::round(v);
655 }
656 
657 // unsigned int
658 // (Comment from OpenCV) we intentionally do not clip negative numbers, to
659 // make -1 become 0xffffffff etc.
660 template <> inline unsigned int vpMath::saturate<unsigned int>(float v)
661 {
662  return static_cast<unsigned int>(vpMath::round(static_cast<double>(v)));
663 }
664 
665 template <> inline unsigned int vpMath::saturate<unsigned int>(double v)
666 {
667  return static_cast<unsigned int>(vpMath::round(v));
668 }
669 END_VISP_NAMESPACE
670 #endif
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
Implementation of an homogeneous matrix and operations on such kind of matrices.
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
Definition: vpMath.h:111
static Tp saturate(double v)
Definition: vpMath.h:310
static Tp saturate(char v)
Definition: vpMath.h:304
static void swap(Type &a, Type &b)
Definition: vpMath.h:286
static Tp saturate(unsigned char v)
Definition: vpMath.h:303
static float getAngleBetweenMinPiAndPi(const float &theta)
Definition: vpMath.h:139
static Tp saturate(unsigned v)
Definition: vpMath.h:307
static double fact(unsigned int x)
Definition: vpMath.h:378
static double rad(double deg)
Definition: vpMath.h:129
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:254
static double sqr(double x)
Definition: vpMath.h:203
static Tp saturate(int v)
Definition: vpMath.h:308
static bool greater(double x, double y, double threshold=0.001)
Definition: vpMath.h:467
static Type abs(const Type &x)
Definition: vpMath.h:269
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:458
static double sigmoid(double x, double x0=0., double x1=1., double n=12.)
Definition: vpMath.h:480
static T clamp(const T &v, const T &lower, const T &upper)
Definition: vpMath.h:218
static bool nul(double x, double threshold=0.001)
Definition: vpMath.h:449
static int round(double x)
Definition: vpMath.h:409
static Type minimum(const Type &a, const Type &b)
Definition: vpMath.h:262
static Tp saturate(float v)
Definition: vpMath.h:309
static int sign(double x)
Definition: vpMath.h:428
static double modulo(const double &value, const double &modulo)
Gives the rest of value divided by modulo when the quotient can only be an integer.
Definition: vpMath.h:192
static long double comb(unsigned int n, unsigned int p)
Definition: vpMath.h:394
static double deg(double rad)
Definition: vpMath.h:119
static float modulo(const float &value, const float &modulo)
Gives the rest of value divided by modulo when the quotient can only be an integer.
Definition: vpMath.h:177
static Tp saturate(unsigned short v)
Definition: vpMath.h:305
static double getAngleBetweenMinPiAndPi(const double &theta)
Definition: vpMath.h:157
static Tp saturate(short v)
Definition: vpMath.h:306
static std::vector< double > linspace(T start_in, T end_in, unsigned int num_in)
Definition: vpMath.h:332
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition: vpPoint.h:79
Implementation of a generic rotation vector.
Implementation of a rotation vector as Euler angle minimal representation.
Definition: vpRxyzVector.h:183
Class that consider the case of a translation vector.