Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
catchMathUtils.cpp
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 * Test additional math functions such as lon-lat generator or look-at function.
32 */
33
39#include <visp3/core/vpConfig.h>
40
41#if defined(VISP_HAVE_CATCH2)
42
43#include <visp3/core/vpHomogeneousMatrix.h>
44#include <visp3/core/vpMath.h>
45
46#include <catch_amalgamated.hpp>
47
48// #define VERBOSE
49// #define DEBUG
50
51#ifdef DEBUG
52#include <visp3/core/vpIoTools.h>
53#endif
54
55#ifdef ENABLE_VISP_NAMESPACE
56using namespace VISP_NAMESPACE_NAME;
57#endif
58
59TEST_CASE("Lon-Lat generator", "[math_lonlat]")
60{
61 const int lonStart = 0, lonEnd = 360, nlon = 20;
62 const int latStart = 0, latEnd = 90, nLat = 10;
63 std::vector<double> longitudes = vpMath::linspace(lonStart, lonEnd, nlon);
64 std::vector<double> latitudes = vpMath::linspace(latStart, latEnd, nLat);
65 const double radius = 5;
66
67 std::vector<std::pair<double, double> > lonlatVec;
68 lonlatVec.reserve(longitudes.size() * latitudes.size());
69 for (auto lon : longitudes) {
70 for (auto lat : latitudes) {
71 lonlatVec.emplace_back(lon, lat);
72 }
73 }
74
75 SECTION("NED")
76 {
77 std::vector<vpHomogeneousMatrix> ecef_M_ned_vec =
79 for (const auto &ecef_M_ned : ecef_M_ned_vec) {
80#ifdef VERBOSE
81 std::cout << "Lon-Lat ecef_M_ned:\n" << ecef_M_ned << std::endl;
82#endif
83 CHECK(ecef_M_ned.isValid());
84 CHECK(ecef_M_ned.getRotationMatrix().isARotationMatrix());
85 CHECK(vpMath::equal(ecef_M_ned.getTranslationVector().sumSquare(), radius * radius));
86 }
87
88#ifdef DEBUG
89 vpHomogeneousMatrix ned_M_cv;
90 ned_M_cv[0][0] = 0;
91 ned_M_cv[0][1] = -1;
92 ned_M_cv[1][0] = 1;
93 ned_M_cv[1][1] = 0;
94 const std::string folder = "NED/lon-lat/";
96 int i = 0;
97 for (const auto &ecef_M_ned : ecef_M_ned_vec) {
98 std::string filename = vpIoTools::formatString(folder + "ecef_M_cv_%04d.txt", ++i);
99 std::ofstream file(filename);
100 if (file.is_open()) {
101 (ecef_M_ned * ned_M_cv).save(file);
102 }
103 }
104#endif
105 }
106
107 SECTION("ENU")
108 {
109 std::vector<vpHomogeneousMatrix> ecef_M_enu_vec =
111 for (const auto &ecef_M_enu : ecef_M_enu_vec) {
112#ifdef VERBOSE
113 std::cout << "Lon-Lat ecef_M_enu:\n" << ecef_M_enu << std::endl;
114#endif
115 CHECK(ecef_M_enu.isValid());
116 CHECK(ecef_M_enu.getRotationMatrix().isARotationMatrix());
117 CHECK(vpMath::equal(ecef_M_enu.getTranslationVector().sumSquare(), radius * radius));
118
119#ifdef DEBUG
120 vpHomogeneousMatrix enu_M_cv;
121 enu_M_cv[1][1] = -1;
122 enu_M_cv[2][2] = -1;
123 const std::string folder = "ENU/lon-lat/";
125 int i = 0;
126 for (const auto &ecef_M_enu : ecef_M_enu_vec) {
127 std::string filename = vpIoTools::formatString(folder + "ecef_M_cv_%04d.txt", ++i);
128 std::ofstream file(filename);
129 if (file.is_open()) {
130 (ecef_M_enu * enu_M_cv).save(file);
131 }
132 }
133#endif
134 }
135 }
136}
137
138TEST_CASE("Equidistributed sphere point", "[math_equi_sphere_pts]")
139{
140 const unsigned int maxPoints = 200;
141 std::vector<std::pair<double, double> > lonlatVec = vpMath::computeRegularPointsOnSphere(maxPoints);
142 const double radius = 5;
143
144 SECTION("NED")
145 {
146 std::vector<vpHomogeneousMatrix> ecef_M_ned_vec =
148 CHECK(!ecef_M_ned_vec.empty());
149 for (const auto &ecef_M_ned : ecef_M_ned_vec) {
150#ifdef VERBOSE
151 std::cout << "Equidistributed ecef_M_ned:\n" << ecef_M_ned << std::endl;
152#endif
153 CHECK(ecef_M_ned.isValid());
154 CHECK(ecef_M_ned.getRotationMatrix().isARotationMatrix());
155 CHECK(vpMath::equal(ecef_M_ned.getTranslationVector().sumSquare(), radius * radius));
156 }
157
158#ifdef DEBUG
159 vpHomogeneousMatrix ned_M_cv;
160 ned_M_cv[0][0] = 0;
161 ned_M_cv[0][1] = -1;
162 ned_M_cv[1][0] = 1;
163 ned_M_cv[1][1] = 0;
164 const std::string folder = "NED/equi/";
166 int i = 0;
167 for (const auto &ecef_M_ned : ecef_M_ned_vec) {
168 std::string filename = = vpIoTools::formatString(folder + "ecef_M_cv_%04d.txt", ++i);
169 std::ofstream file(filename);
170 if (file.is_open()) {
171 (ecef_M_ned * ned_M_cv).save(file);
172 }
173 }
174#endif
175 }
176
177 SECTION("ENU")
178 {
179 std::vector<vpHomogeneousMatrix> ecef_M_enu_vec =
181 CHECK(!ecef_M_enu_vec.empty());
182 for (const auto &ecef_M_enu : ecef_M_enu_vec) {
183#ifdef VERBOSE
184 std::cout << "Equidistributed ecef_M_enu:\n" << ecef_M_enu << std::endl;
185#endif
186 CHECK(ecef_M_enu.isValid());
187 CHECK(ecef_M_enu.getRotationMatrix().isARotationMatrix());
188 CHECK(vpMath::equal(ecef_M_enu.getTranslationVector().sumSquare(), radius * radius));
189 }
190
191#ifdef DEBUG
192 vpHomogeneousMatrix enu_M_cv;
193 enu_M_cv[1][1] = -1;
194 enu_M_cv[2][2] = -1;
195 const std::string folder = "ENU/equi/";
197 int i = 0;
198 for (const auto &ecef_M_enu : ecef_M_enu_vec) {
199 std::stringstream buffer;
200 std::string filename = vpIoTools::formatString(folder + "ecef_M_cv_%04d.txt", ++i);
201 std::ofstream file(filename);
202 if (file.is_open()) {
203 (ecef_M_enu * enu_M_cv).save(file);
204 }
205 }
206#endif
207 }
208}
209
210TEST_CASE("Look-at", "[math_look_at]")
211{
212 // Set camera to an arbitrary pose (only translation)
213 vpColVector from_blender = { 8.867762565612793, -1.1965436935424805, 2.1211400032043457 };
214 // Transformation from OpenGL to Blender frame
215 vpHomogeneousMatrix blender_M_gl;
216 blender_M_gl[0][0] = 0;
217 blender_M_gl[0][2] = 1;
218 blender_M_gl[1][0] = 1;
219 blender_M_gl[1][1] = 0;
220 blender_M_gl[2][1] = 1;
221 blender_M_gl[2][2] = 0;
222
223 // From is the current camera pose expressed in the OpenGL coordinate system
224 vpColVector from = (blender_M_gl.getRotationMatrix().t() * from_blender);
225 // To is the desired point toward the camera must look
226 vpColVector to = { 0, 0, 0 };
227 // Up is an arbitrary vector
228 vpColVector up = { 0, 1, 0 };
229
230 // Compute the look-at transformation
231 vpHomogeneousMatrix gl_M_cam = vpMath::lookAt(from, to, up);
232 std::cout << "\ngl_M_cam:\n" << gl_M_cam << std::endl;
233
234 // Transformation from the computer vision frame to the Blender camera frame
235 vpHomogeneousMatrix cam_M_cv;
236 cam_M_cv[1][1] = -1;
237 cam_M_cv[2][2] = -1;
238 // Transformation from the computer vision frame to the Blender frame
239 vpHomogeneousMatrix bl_M_cv = blender_M_gl * gl_M_cam * cam_M_cv;
240 std::cout << "\nbl_M_cv:\n" << bl_M_cv << std::endl;
241
242 // Ground truth using Blender look-at
243 vpHomogeneousMatrix bl_M_cv_gt = vpHomogeneousMatrix({ 0.13372008502483368, 0.22858507931232452, -0.9642965197563171,
244 8.867762565612793, 0.9910191297531128, -0.030843468382954597,
245 0.13011434674263, -1.1965436935424805, -5.4016709327697754e-08,
246 -0.9730352163314819, -0.23065657913684845, 2.121140241622925 });
247 std::cout << "\nbl_M_cv_gt:\n" << bl_M_cv_gt << std::endl;
248
249 const double tolerance = 1e-6;
250 for (unsigned int i = 0; i < 3; i++) {
251 for (unsigned int j = 0; j < 4; j++) {
252 CHECK(vpMath::equal(bl_M_cv[i][j], bl_M_cv_gt[i][j], tolerance));
253 }
254 }
255}
256
257int main(int argc, char *argv[])
258{
259 Catch::Session session;
260 session.applyCommandLine(argc, argv);
261 int numFailed = session.run();
262 return numFailed;
263}
264#else
265#include <iostream>
266
267int main() { return EXIT_SUCCESS; }
268#endif
Implementation of column vector and the associated operations.
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
static std::string formatString(const std::string &name, unsigned int val)
static void makeDirectory(const std::string &dirname)
static std::vector< double > linspace(T start_in, T end_in, unsigned int num_in)
Definition vpMath.h:336
static std::vector< vpHomogeneousMatrix > getLocalTangentPlaneTransformations(const std::vector< std::pair< double, double > > &lonlatVec, double radius, LongLattToHomogeneous func)
Definition vpMath.cpp:674
static vpHomogeneousMatrix lookAt(const vpColVector &from, const vpColVector &to, vpColVector tmp)
Definition vpMath.cpp:710
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:470
static vpHomogeneousMatrix enu2ecef(double lonDeg, double latDeg, double radius)
Definition vpMath.cpp:583
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