Visual Servoing Platform  version 3.6.1 under development (2024-11-21)
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 
95 BEGIN_VISP_NAMESPACE
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  static unsigned int modulo(unsigned int a, unsigned int n);
318 
319  static vpHomogeneousMatrix ned2ecef(double lonDeg, double latDeg, double radius);
320  static vpHomogeneousMatrix enu2ecef(double lonDeg, double latDeg, double radius);
321  static vpHomogeneousMatrix enu2ned(const vpHomogeneousMatrix &enu_M);
322 
333  template <typename T> static std::vector<double> linspace(T start_in, T end_in, unsigned int num_in)
334  {
335  std::vector<double> linspaced;
336 
337  double start = static_cast<double>(start_in);
338  double end = static_cast<double>(end_in);
339  double num = static_cast<double>(num_in);
340 
341  if (std::fabs(num) < std::numeric_limits<double>::epsilon()) {
342  return linspaced;
343  }
344  if (std::fabs(num - 1) < std::numeric_limits<double>::epsilon()) {
345  linspaced.push_back(start);
346  return linspaced;
347  }
348 
349  double delta = (end - start) / (num - 1);
350 
351  for (int i = 0; i < (num - 1); ++i) {
352  linspaced.push_back(start + (delta * i));
353  }
354  linspaced.push_back(end); // I want to ensure that start and end
355  // are exactly the same as the input
356  return linspaced;
357  }
358 
359  static std::vector<std::pair<double, double> > computeRegularPointsOnSphere(unsigned int maxPoints);
360 
361  typedef vpHomogeneousMatrix(*LongLattToHomogeneous)(double lonDeg, double latDeg, double radius);
362  static std::vector<vpHomogeneousMatrix>
363  getLocalTangentPlaneTransformations(const std::vector<std::pair<double, double> > &lonlatVec, double radius,
364  LongLattToHomogeneous func);
365 
366  static vpHomogeneousMatrix lookAt(const vpColVector &from, const vpColVector &to, vpColVector tmp);
367 
368 private:
369  static const double ang_min_sinc;
370  static const double ang_min_mc;
371 };
372 
373 // Begining of the inline functions definition
374 
379 double vpMath::fact(unsigned int x)
380 {
381  if ((x == 1) || (x == 0)) {
382  return 1;
383  }
384  return x * fact(x - 1);
385 }
386 
395 long double vpMath::comb(unsigned int n, unsigned int p)
396 {
397  if (n == p) {
398  return 1;
399  }
400  return fact(n) / (fact(n - p) * fact(p));
401 }
402 
410 int vpMath::round(double x)
411 {
412 #if defined(VISP_HAVE_FUNC_STD_ROUND)
413  return static_cast<int>(std::round(x));
414 #elif defined(VISP_HAVE_FUNC_ROUND)
415  //:: to design the global namespace and avoid to call recursively
416  // vpMath::round
417  return static_cast<int>(::round(x));
418 #else
419  return (x > 0.0) ? (static_cast<int>(floor(x + 0.5))) : (static_cast<int>(ceil(x - 0.5)));
420 #endif
421 }
422 
429 int vpMath::sign(double x)
430 {
431  if (fabs(x) < std::numeric_limits<double>::epsilon()) {
432  return 0;
433  }
434  else {
435  if (x < 0) {
436  return -1;
437  }
438  else {
439  return 1;
440  }
441  }
442 }
443 
450 bool vpMath::nul(double x, double threshold) { return (fabs(x) < threshold); }
451 
459 bool vpMath::equal(double x, double y, double threshold) { return (nul(x - y, threshold)); }
460 
468 bool vpMath::greater(double x, double y, double threshold) { return (x > (y - threshold)); }
469 
481 double vpMath::sigmoid(double x, double x0, double x1, double n)
482 {
483  if (x < x0) {
484  return 0.;
485  }
486  else if (x > x1) {
487  return 1.;
488  }
489  double l0 = 1. / (1. + exp(0.5 * n));
490  double l1 = 1. / (1. + exp(-0.5 * n));
491  return ((1. / (1. + exp(-n * (((x - x0) / (x1 - x0)) - 0.5)))) - l0) / (l1 - l0);
492 }
493 
494 // unsigned char
495 template <> inline unsigned char vpMath::saturate<unsigned char>(char v)
496 {
497  // On big endian arch like powerpc, char implementation is unsigned
498  // with CHAR_MIN=0, CHAR_MAX=255 and SCHAR_MIN=-128, SCHAR_MAX=127
499  // leading to (int)(char -127) = 129.
500  // On little endian arch, CHAR_MIN=-127 and CHAR_MAX=128 leading to
501  // (int)(char -127) = -127.
502  if (std::numeric_limits<char>::is_signed) {
503  return static_cast<unsigned char>(std::max<int>(static_cast<int>(v), 0));
504  }
505  else {
506  return static_cast<unsigned char>(static_cast<unsigned int>(v) > SCHAR_MAX ? 0 : v);
507  }
508 }
509 
510 template <> inline unsigned char vpMath::saturate<unsigned char>(unsigned short v)
511 {
512  return static_cast<unsigned char>(std::min<unsigned int>(static_cast<unsigned int>(v), static_cast<unsigned int>(UCHAR_MAX)));
513 }
514 
515 template <> inline unsigned char vpMath::saturate<unsigned char>(int v)
516 {
517  return static_cast<unsigned char>(static_cast<unsigned int>(v) <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0);
518 }
519 
520 template <> inline unsigned char vpMath::saturate<unsigned char>(short v)
521 {
522  return saturate<unsigned char>(static_cast<int>(v));
523 }
524 
525 template <> inline unsigned char vpMath::saturate<unsigned char>(unsigned int v)
526 {
527  return static_cast<unsigned char>(std::min<unsigned int>(v, static_cast<unsigned int>(UCHAR_MAX)));
528 }
529 
530 template <> inline unsigned char vpMath::saturate<unsigned char>(float v)
531 {
532  int iv = vpMath::round(static_cast<double>(v));
533  return saturate<unsigned char>(iv);
534 }
535 
536 template <> inline unsigned char vpMath::saturate<unsigned char>(double v)
537 {
538  int iv = vpMath::round(v);
539  return saturate<unsigned char>(iv);
540 }
541 
542 // char
543 template <> inline char vpMath::saturate<char>(unsigned char v)
544 {
545  return static_cast<char>(std::min<int>(static_cast<int>(v), SCHAR_MAX));
546 }
547 
548 template <> inline char vpMath::saturate<char>(unsigned short v)
549 {
550  return static_cast<char>(std::min<unsigned int>(static_cast<unsigned int>(v), static_cast<unsigned int>(SCHAR_MAX)));
551 }
552 
553 template <> inline char vpMath::saturate<char>(int v)
554 {
555  return static_cast<char>(static_cast<unsigned int>(v - SCHAR_MIN) <= static_cast<unsigned int>(UCHAR_MAX) ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN);
556 }
557 
558 template <> inline char vpMath::saturate<char>(short v)
559 {
560  return saturate<char>(static_cast<int>(v));
561 }
562 
563 template <> inline char vpMath::saturate<char>(unsigned int v)
564 {
565  return static_cast<char>(std::min<unsigned int>(v, static_cast<unsigned int>(SCHAR_MAX)));
566 }
567 
568 template <> inline char vpMath::saturate<char>(float v)
569 {
570  int iv = vpMath::round(v);
571  return saturate<char>(iv);
572 }
573 
574 template <> inline char vpMath::saturate<char>(double v)
575 {
576  int iv = vpMath::round(v);
577  return saturate<char>(iv);
578 }
579 
580 // unsigned short
581 template <> inline unsigned short vpMath::saturate<unsigned short>(char v)
582 {
583  // On big endian arch like powerpc, char implementation is unsigned
584  // with CHAR_MIN=0, CHAR_MAX=255 and SCHAR_MIN=-128, SCHAR_MAX=127
585  // leading to (int)(char -127) = 129.
586  // On little endian arch, CHAR_MIN=-127 and CHAR_MAX=128 leading to
587  // (int)(char -127) = -127.
588  if (std::numeric_limits<char>::is_signed) {
589  return static_cast<unsigned short>(std::max<int>(static_cast<int>(v), 0));
590  }
591  else {
592  return static_cast<unsigned short>(static_cast<unsigned int>(v) > SCHAR_MAX ? 0 : v);
593  }
594 }
595 
596 template <> inline unsigned short vpMath::saturate<unsigned short>(short v)
597 {
598  return static_cast<unsigned short>(std::max<int>(static_cast<int>(v), 0));
599 }
600 
601 template <> inline unsigned short vpMath::saturate<unsigned short>(int v)
602 {
603  return static_cast<unsigned short>(static_cast<unsigned int>(v) <= static_cast<unsigned int>(USHRT_MAX) ? v : v > 0 ? USHRT_MAX : 0);
604 }
605 
606 template <> inline unsigned short vpMath::saturate<unsigned short>(unsigned int v)
607 {
608  return static_cast<unsigned short>(std::min<unsigned int>(v, static_cast<unsigned int>(USHRT_MAX)));
609 }
610 
611 template <> inline unsigned short vpMath::saturate<unsigned short>(float v)
612 {
613  int iv = vpMath::round(static_cast<double>(v));
614  return vpMath::saturate<unsigned short>(iv);
615 }
616 
617 template <> inline unsigned short vpMath::saturate<unsigned short>(double v)
618 {
619  int iv = vpMath::round(v);
620  return vpMath::saturate<unsigned short>(iv);
621 }
622 
623 // short
624 template <> inline short vpMath::saturate<short>(unsigned short v)
625 {
626  return static_cast<short>(std::min<int>(static_cast<int>(v), SHRT_MAX));
627 }
628 template <> inline short vpMath::saturate<short>(int v)
629 {
630  return static_cast<short>(static_cast<unsigned int>(v - SHRT_MIN) <= static_cast<unsigned int>(USHRT_MAX) ? v : v > 0 ? SHRT_MAX : SHRT_MIN);
631 }
632 template <> inline short vpMath::saturate<short>(unsigned int v)
633 {
634  return static_cast<short>(std::min<unsigned int>(v, static_cast<unsigned int>(SHRT_MAX)));
635 }
636 template <> inline short vpMath::saturate<short>(float v)
637 {
638  int iv = vpMath::round(static_cast<double>(v));
639  return vpMath::saturate<short>(iv);
640 }
641 template <> inline short vpMath::saturate<short>(double v)
642 {
643  int iv = vpMath::round(v);
644  return vpMath::saturate<short>(iv);
645 }
646 
647 // int
648 template <> inline int vpMath::saturate<int>(float v)
649 {
650  return vpMath::round(static_cast<double>(v));
651 }
652 
653 template <> inline int vpMath::saturate<int>(double v)
654 {
655  return vpMath::round(v);
656 }
657 
658 // unsigned int
659 // (Comment from OpenCV) we intentionally do not clip negative numbers, to
660 // make -1 become 0xffffffff etc.
661 template <> inline unsigned int vpMath::saturate<unsigned int>(float v)
662 {
663  return static_cast<unsigned int>(vpMath::round(static_cast<double>(v)));
664 }
665 
666 template <> inline unsigned int vpMath::saturate<unsigned int>(double v)
667 {
668  return static_cast<unsigned int>(vpMath::round(v));
669 }
670 END_VISP_NAMESPACE
671 #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:379
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:468
static Type abs(const Type &x)
Definition: vpMath.h:269
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:459
static double sigmoid(double x, double x0=0., double x1=1., double n=12.)
Definition: vpMath.h:481
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:450
static int round(double x)
Definition: vpMath.h:410
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:429
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:395
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:333
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.