Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMath.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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
39
40#include <cmath>
41#include <functional>
42#include <numeric>
43#include <stdint.h>
44#include <cassert>
45#include <ctype.h>
46
47#include <visp3/core/vpException.h>
48#include <visp3/core/vpMath.h>
49#include <visp3/core/vpMatrix.h>
50
51#if defined(VISP_HAVE_FUNC__FINITE)
52#include <float.h>
53#endif
54
56#if !(defined(VISP_HAVE_FUNC_ISNAN) || defined(VISP_HAVE_FUNC_STD_ISNAN)) || \
57 !(defined(VISP_HAVE_FUNC_ISINF) || defined(VISP_HAVE_FUNC_STD_ISINF)) || \
58 !(defined(VISP_HAVE_FUNC_ISFINITE) || defined(VISP_HAVE_FUNC_STD_ISFINITE) || defined(VISP_HAVE_FUNC__FINITE))
59#if defined _MSC_VER || defined __BORLANDC__
60typedef __int64 int64;
61typedef unsigned __int64 uint64;
62#else
63typedef int64_t int64;
64typedef uint64_t uint64;
65#endif
66
67#ifndef DOXYGEN_SHOULD_SKIP_THIS
68typedef union Vp64suf
69{
70 // int64 i; //Unused variable, should be harmless to comment it
71 uint64 u;
72 double f;
73} Vp64suf;
74
75typedef union Vp32suf
76{
77 // int i; //Unused variable, should be harmless to comment it
78 unsigned u;
79 float f;
80} Vp32suf;
81#endif
82#endif
83
84void emitWarning(const std::string &message);
85
86void emitWarning(const std::string &message)
87{
88 std::cerr << "\033[0;31m";
89 std::cerr << message << std::endl;
90 std::cerr << "\033[0m";
91}
92
93const double vpMath::ang_min_sinc = 1.0e-8;
94const double vpMath::ang_min_mc = 2.5e-4;
95
101bool vpMath::isNaN(double value)
102{
103#if defined(VISP_HAVE_FAST_MATH)
104 emitWarning("isNaN: You are testing whether a double value is a number, but are compiling with fast math options enabled. This function may return an incorrect result.");
105#endif
106#if defined(VISP_HAVE_FUNC_STD_ISNAN)
107 return std::isnan(value);
108#elif defined(VISP_HAVE_FUNC_ISNAN)
109 return isnan(value);
110#elif defined(VISP_HAVE_FUNC__ISNAN)
111 return (_isnan(value) != 0);
112#else
113 // Taken from OpenCV source code CvIsNan()
114 Vp64suf ieee754;
115 ieee754.f = value;
116 return ((static_cast<unsigned int>(ieee754.u >> 32) & 0x7fffffff) + ((static_cast<unsigned int>(ieee754.u) != 0) > 0x7ff00000) != 0;
117#endif
118}
119
125bool vpMath::isNaN(float value)
126{
127#if defined(VISP_HAVE_FAST_MATH)
128 emitWarning("isNaN: You are testing whether a float value is a number, but are compiling with fast math options enabled. This function may return an incorrect result.");
129#endif
130#if defined(VISP_HAVE_FUNC_STD_ISNAN)
131 return std::isnan(value);
132#elif defined(VISP_HAVE_FUNC_ISNAN)
133 return isnan(value);
134#elif defined(VISP_HAVE_FUNC__ISNAN)
135 return (_isnan(value) != 0);
136#else
137 // Taken from OpenCV source code CvIsNan()
138 Vp32suf ieee754;
139 ieee754.f = value;
140 return ((static_cast<unsigned int>(ieee754.u) & 0x7fffffff) > 0x7f800000;
141#endif
142}
143
151bool vpMath::isInf(double value)
152{
153#if defined(VISP_HAVE_FAST_MATH)
154 emitWarning("isInf: You are testing whether a double value is infinite, but are compiling with fast math options enabled. This function may return an incorrect result.");
155#endif
156#if defined(VISP_HAVE_FUNC_STD_ISINF)
157 return std::isinf(value);
158#elif defined(VISP_HAVE_FUNC_ISINF)
159 return isinf(value);
160#else
161 // Taken from OpenCV source code CvIsInf()
162 Vp64suf ieee754;
163 ieee754.f = value;
164 return (static_cast<unsigned int>(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && (static_cast<unsigned int>(ieee754.u) == 0;
165#endif
166}
167
175bool vpMath::isInf(float value)
176{
177#if defined(VISP_HAVE_FAST_MATH)
178 emitWarning("isInf: You are testing whether a float value is infinite, but are compiling with fast math options enabled. This function may return an incorrect result.");
179#endif
180#if defined(VISP_HAVE_FUNC_STD_ISINF)
181 return std::isinf(value);
182#elif defined(VISP_HAVE_FUNC_ISINF)
183 return isinf(value);
184#else
185 // Taken from OpenCV source code CvIsInf()
186 Vp32suf ieee754;
187 ieee754.f = value;
188 return ((static_cast<unsigned int>(ieee754.u) & 0x7fffffff) == 0x7f800000;
189#endif
190}
191
198bool vpMath::isFinite(double value)
199{
200#if defined(VISP_HAVE_FUNC_STD_ISFINITE)
201 return std::isfinite(value);
202#elif defined(VISP_HAVE_FUNC_ISFINITE)
203 return isfinite(value);
204#elif defined(VISP_HAVE_FUNC__FINITE)
205 return _finite(value);
206#else
207 return !vpMath::isInf(value) && !vpMath::isNaN(value);
208#endif
209}
210
217bool vpMath::isFinite(float value)
218{
219#if defined(VISP_HAVE_FUNC_STD_ISFINITE)
220 return std::isfinite(value);
221#elif defined(VISP_HAVE_FUNC_ISFINITE)
222 return isfinite(value);
223#elif defined(VISP_HAVE_FUNC__FINITE)
224 return _finitef(value);
225#else
226 return !vpMath::isInf(value) && !vpMath::isNaN(value);
227#endif
228}
229
235bool vpMath::isNumber(const std::string &str)
236{
237 size_t str_size = str.size();
238 for (size_t i = 0; i < str_size; ++i) {
239 if (isdigit(str[i]) == false) {
240 return false;
241 }
242 }
243 return true;
244}
245
254double vpMath::mcosc(double cosx, double x)
255{
256 if (fabs(x) < ang_min_mc) {
257 return 0.5 - x * x / 24.0;
258 }
259 else {
260 return ((1.0 - cosx) / x / x);
261 }
262}
263
272double vpMath::msinc(double sinx, double x)
273{
274 if (fabs(x) < ang_min_mc) {
275 return (1. / 6.0 - x * x / 120.0);
276 }
277 else {
278 return ((1.0 - (sinx / x)) / x / x);
279 }
280}
281
289double vpMath::sinc(double x)
290{
291 if (fabs(x) < ang_min_sinc) {
292 return 1.0 - x * x / 6.0;
293 }
294 else {
295 return sin(x) / x;
296 }
297}
298
306double vpMath::sinc(double sinx, double x)
307{
308 if (fabs(x) < ang_min_sinc) {
309 return 1.0 - x * x / 6.0;
310 }
311 else {
312 return (sinx / x);
313 }
314}
315
323double vpMath::getMean(const std::vector<double> &v)
324{
325 if (v.empty()) {
326 throw vpException(vpException::notInitialized, "Empty vector !");
327 }
328
329 size_t size = v.size();
330
331 double sum = std::accumulate(v.begin(), v.end(), 0.0);
332
333 return sum / (static_cast<double>(size));
334}
335
343double vpMath::getMedian(const std::vector<double> &v)
344{
345 if (v.empty()) {
346 throw vpException(vpException::notInitialized, "Empty vector !");
347 }
348 const size_t val_2 = 2;
349 std::vector<double> v_copy = v;
350 size_t size = v_copy.size();
351
352 size_t n = size / 2;
353 std::nth_element(v_copy.begin(), v_copy.begin() + n, v_copy.end());
354 double val_n = v_copy[n];
355
356 if ((size % val_2) == 1) {
357 return val_n;
358 }
359 else {
360 std::nth_element(v_copy.begin(), v_copy.begin() + (n - 1), v_copy.end());
361 return 0.5 * (val_n + v_copy[n - 1]);
362 }
363}
364
374double vpMath::getStdev(const std::vector<double> &v, bool useBesselCorrection)
375{
376 if (v.empty()) {
377 throw vpException(vpException::notInitialized, "Empty vector !");
378 }
379
380 double mean = getMean(v);
381
382 std::vector<double> diff(v.size());
383#if VISP_CXX_STANDARD > VISP_CXX_STANDARD_98
384 std::transform(v.begin(), v.end(), diff.begin(), std::bind(std::minus<double>(), std::placeholders::_1, mean));
385#else
386 std::transform(v.begin(), v.end(), diff.begin(), std::bind2nd(std::minus<double>(), mean));
387#endif
388
389 double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
390 double divisor = static_cast<double> (v.size());
391 if (useBesselCorrection && (v.size() > 1)) {
392 divisor = divisor - 1;
393 }
394
395 return std::sqrt(sq_sum / divisor);
396}
397
411double vpMath::lineFitting(const std::vector<vpImagePoint> &imPts, double &a, double &b, double &c)
412{
413 const unsigned int val_3 = 3;
414 if (imPts.size() < val_3) {
415 throw vpException(vpException::dimensionError, "Number of image points must be greater or equal to 3.");
416 }
417
418 double x_mean = 0, y_mean = 0;
419 size_t imPts_size = imPts.size();
420 for (size_t i = 0; i < imPts_size; ++i) {
421 const vpImagePoint &imPt = imPts[i];
422 x_mean += imPt.get_u();
423 y_mean += imPt.get_v();
424 }
425 x_mean /= imPts.size();
426 y_mean /= imPts.size();
427
428 vpMatrix AtA(2, 2, 0.0);
429 imPts_size = imPts.size();
430 for (size_t i = 0; i < imPts_size; ++i) {
431 const vpImagePoint &imPt = imPts[i];
432 AtA[0][0] += (imPt.get_u() - x_mean) * (imPt.get_u() - x_mean);
433 AtA[0][1] += (imPt.get_u() - x_mean) * (imPt.get_v() - y_mean);
434 AtA[1][1] += (imPt.get_v() - y_mean) * (imPt.get_v() - y_mean);
435 }
436 AtA[1][0] = AtA[0][1];
437
438 vpColVector eigenvalues;
439 vpMatrix eigenvectors;
440 AtA.eigenValues(eigenvalues, eigenvectors);
441
442 a = eigenvectors[0][0];
443 b = eigenvectors[1][0];
444 c = (a * x_mean) + (b * y_mean);
445
446 double error = 0;
447 imPts_size = imPts.size();
448 for (size_t i = 0; i < imPts_size; ++i) {
449 double x0 = imPts[i].get_u();
450 double y0 = imPts[i].get_v();
451
452 error += std::fabs((a * x0) + ((b * y0) - c));
453 }
454
455 return error / imPts.size();
456}
457
468int vpMath::modulo(int a, int n) { return ((a % n) + n) % n; }
469
479unsigned int vpMath::modulo(unsigned int a, unsigned int n) { return ((a % n) + n) % n; }
480
519vpHomogeneousMatrix vpMath::ned2ecef(double lonDeg, double latDeg, double radius)
520{
521 double lon = vpMath::rad(lonDeg);
522 double lat = vpMath::rad(latDeg);
523 const unsigned int index_0 = 0;
524 const unsigned int index_1 = 1;
525 const unsigned int index_2 = 2;
526 const unsigned int index_3 = 3;
527 vpHomogeneousMatrix ecef_M_ned;
528 ecef_M_ned[index_0][index_0] = -sin(lat) * cos(lon);
529 ecef_M_ned[index_0][index_1] = -sin(lon);
530 ecef_M_ned[index_0][index_2] = -cos(lat) * cos(lon);
531 ecef_M_ned[index_0][index_3] = radius * cos(lon) * cos(lat);
532 ecef_M_ned[index_1][index_0] = -sin(lat) * sin(lon);
533 ecef_M_ned[index_1][index_1] = cos(lon);
534 ecef_M_ned[index_1][index_2] = -cos(lat) * sin(lon);
535 ecef_M_ned[index_1][index_3] = radius * sin(lon) * cos(lat);
536 ecef_M_ned[index_2][index_0] = cos(lat);
537 ecef_M_ned[index_2][index_1] = 0;
538 ecef_M_ned[index_2][index_2] = -sin(lat);
539 ecef_M_ned[index_2][index_3] = radius * sin(lat);
540
541 return ecef_M_ned;
542}
543
583vpHomogeneousMatrix vpMath::enu2ecef(double lonDeg, double latDeg, double radius)
584{
585 double lon = vpMath::rad(lonDeg);
586 double lat = vpMath::rad(latDeg);
587 const unsigned int index_0 = 0;
588 const unsigned int index_1 = 1;
589 const unsigned int index_2 = 2;
590 const unsigned int index_3 = 3;
591
592 vpHomogeneousMatrix ecef_M_enu;
593 ecef_M_enu[index_0][index_0] = -sin(lon);
594 ecef_M_enu[index_0][index_1] = -sin(lat) * cos(lon);
595 ecef_M_enu[index_0][index_2] = cos(lat) * cos(lon);
596 ecef_M_enu[index_0][index_3] = radius * cos(lon) * cos(lat);
597 ecef_M_enu[index_1][index_0] = cos(lon);
598 ecef_M_enu[index_1][index_1] = -sin(lat) * sin(lon);
599 ecef_M_enu[index_1][index_2] = cos(lat) * sin(lon);
600 ecef_M_enu[index_1][index_3] = radius * sin(lon) * cos(lat);
601 ecef_M_enu[index_2][index_0] = 0;
602 ecef_M_enu[index_2][index_1] = cos(lat);
603 ecef_M_enu[index_2][index_2] = sin(lat);
604 ecef_M_enu[index_2][index_3] = radius * sin(lat);
605
606 return ecef_M_enu;
607}
608
623std::vector<std::pair<double, double> > vpMath::computeRegularPointsOnSphere(unsigned int maxPoints)
624{
625 assert(maxPoints > 0);
626
627 double a = (4.0 * M_PI) / maxPoints;
628 double d = sqrt(a);
629 int m_theta = static_cast<int>(round(M_PI / d));
630 double d_theta = M_PI / m_theta;
631 double d_phi = a / d_theta;
632
633 std::vector<std::pair<double, double> > lonlat_vec;
634#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
635 lonlat_vec.reserve(static_cast<unsigned int>(std::sqrt(maxPoints)));
636#else
637 lonlat_vec.reserve(static_cast<unsigned int>(std::sqrt(static_cast<double>(maxPoints))));
638#endif
639
640 for (int m = 0; m < m_theta; ++m) {
641 double theta = (M_PI * (m + 0.5)) / m_theta;
642 int m_phi = static_cast<int>(round((2.0 * M_PI * sin(theta)) / d_phi));
643
644 for (int n = 0; n < m_phi; ++n) {
645 double phi = (2.0 * M_PI * n) / m_phi;
646 double lon = phi;
647 double lat = M_PI_2 - theta;
648 lonlat_vec.push_back(std::make_pair(deg(lon), deg(lat)));
649 }
650 }
651
652 return lonlat_vec;
653}
654
674std::vector<vpHomogeneousMatrix> vpMath::getLocalTangentPlaneTransformations(const std::vector<std::pair<double, double> > &lonlatVec, double radius,
676{
677 std::vector<vpHomogeneousMatrix> ecef_M_local_vec;
678 ecef_M_local_vec.reserve(lonlatVec.size());
679 size_t lonlatVec_size = lonlatVec.size();
680 for (size_t i = 0; i < lonlatVec_size; ++i) {
681 double lonDeg = lonlatVec[i].first;
682 double latDeg = lonlatVec[i].second;
683
684 vpHomogeneousMatrix ecef_M_local = toECEF(lonDeg, latDeg, radius);
685 ecef_M_local_vec.push_back(ecef_M_local);
686 }
687 return ecef_M_local_vec;
688}
689
711{
712 assert(from.size() == 3);
713 assert(to.size() == 3);
714 assert(tmp.size() == 3);
715 vpColVector forward = (from - to).normalize();
716 vpColVector right = vpColVector::crossProd(tmp.normalize(), forward).normalize();
717 vpColVector up = vpColVector::crossProd(forward, right).normalize();
718 const unsigned int index_0 = 0;
719 const unsigned int index_1 = 1;
720 const unsigned int index_2 = 2;
721 const unsigned int index_3 = 3;
722
724 wMc[index_0][index_0] = right[index_0];
725 wMc[index_0][index_1] = up[index_0];
726 wMc[index_0][index_2] = forward[index_0];
727 wMc[index_0][index_3] = from[index_0];
728 wMc[index_1][index_0] = right[index_1];
729 wMc[index_1][index_1] = up[index_1];
730 wMc[index_1][index_2] = forward[index_1];
731 wMc[index_1][index_3] = from[index_1];
732 wMc[index_2][index_0] = right[index_2];
733 wMc[index_2][index_1] = up[index_2];
734 wMc[index_2][index_2] = forward[index_2];
735 wMc[index_2][index_3] = from[index_2];
736
737 return wMc;
738}
739
747{
748 const unsigned int val_4 = 4;
749 if (r.size() == val_4) {
750 throw(vpException(vpException::fatalError, "Cannot convert angles of a quaternion vector in degrees!"));
751 }
752 vpColVector r_deg(r.size());
753 unsigned int r_size = r.size();
754 for (unsigned int i = 0; i < r_size; ++i) {
755 r_deg[i] = vpMath::deg(r[i]);
756 }
757 return r_deg;
758}
759
767{
768 vpColVector r_deg(r.size());
769 unsigned int r_size = r.size();
770 for (unsigned int i = 0; i < r_size; ++i) {
771 r_deg[i] = vpMath::deg(r[i]);
772 }
773 return r_deg;
774}
775
783{
784 vpColVector r_rad(r.size());
785 unsigned int r_size = r.size();
786 for (unsigned int i = 0; i < r_size; ++i) {
787 r_rad[i] = vpMath::rad(r[i]);
788 }
789 return r_rad;
790}
791
798{
799 vpHomogeneousMatrix ned_M_enu;
800 const unsigned int index_0 = 0;
801 const unsigned int index_1 = 1;
802 const unsigned int index_2 = 2;
803 ned_M_enu[index_0][index_0] = 0;
804 ned_M_enu[index_0][index_1] = 1;
805 ned_M_enu[index_1][index_0] = 1;
806 ned_M_enu[index_1][index_1] = 0;
807 ned_M_enu[index_2][index_2] = -1;
808
809 vpHomogeneousMatrix ned_M = ned_M_enu * enu_M;
810 return ned_M;
811}
812END_VISP_NAMESPACE
unsigned int size() const
Return the number of elements of the 2D array.
Definition vpArray2D.h:435
Implementation of column vector and the associated operations.
vpColVector & normalize()
static vpColVector crossProd(const vpColVector &a, const vpColVector &b)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ notInitialized
Used to indicate that a parameter is not initialized.
Definition vpException.h:74
@ dimensionError
Bad dimension.
Definition vpException.h:71
@ fatalError
Fatal error.
Definition vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double get_u() const
double get_v() const
static double msinc(double sinx, double x)
Definition vpMath.cpp:272
static bool isNaN(double value)
Definition vpMath.cpp:101
static double rad(double deg)
Definition vpMath.h:129
static double getMedian(const std::vector< double > &v)
Definition vpMath.cpp:343
static double sinc(double x)
Definition vpMath.cpp:289
static std::vector< vpHomogeneousMatrix > getLocalTangentPlaneTransformations(const std::vector< std::pair< double, double > > &lonlatVec, double radius, LongLattToHomogeneous func)
Definition vpMath.cpp:674
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
Definition vpMath.cpp:374
static vpHomogeneousMatrix lookAt(const vpColVector &from, const vpColVector &to, vpColVector tmp)
Definition vpMath.cpp:710
vpHomogeneousMatrix(* LongLattToHomogeneous)(double lonDeg, double latDeg, double radius)
Definition vpMath.h:364
static vpHomogeneousMatrix enu2ecef(double lonDeg, double latDeg, double radius)
Definition vpMath.cpp:583
static double lineFitting(const std::vector< vpImagePoint > &imPts, double &a, double &b, double &c)
Definition vpMath.cpp:411
static int round(double x)
Definition vpMath.h:413
static bool isFinite(double value)
Definition vpMath.cpp:198
static double getMean(const std::vector< double > &v)
Definition vpMath.cpp:323
static bool isInf(double value)
Definition vpMath.cpp:151
static vpHomogeneousMatrix enu2ned(const vpHomogeneousMatrix &enu_M)
Definition vpMath.cpp:797
static double mcosc(double cosx, double x)
Definition vpMath.cpp:254
static double deg(double rad)
Definition vpMath.h:119
static bool isNumber(const std::string &str)
Definition vpMath.cpp:235
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 std::vector< std::pair< double, double > > computeRegularPointsOnSphere(unsigned int maxPoints)
Definition vpMath.cpp:623
static vpHomogeneousMatrix ned2ecef(double lonDeg, double latDeg, double radius)
Definition vpMath.cpp:519
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
vpColVector eigenValues() const
Implementation of a generic rotation vector.