Test theta.u and quaternion multiplication.
#include <visp3/core/vpConfig.h>
#if defined(VISP_HAVE_CATCH2)
#include <visp3/core/vpThetaUVector.h>
#include <visp3/core/vpUniRand.h>
#include <catch_amalgamated.hpp>
#ifdef ENABLE_VISP_NAMESPACE
#endif
namespace
{
{
}
{
const double ctheta = std::cos(angle);
const double stheta = std::sin(angle);
const double ax = rng.
uniform(-1.0, 1.0);
const double ay = rng.
uniform(-1.0, 1.0);
const double az = rng.
uniform(-1.0, 1.0);
}
}
bool test(
const std::string &s,
const vpArray2D<double> &v,
const std::vector<double> &bench)
{
std::cout << s <<
"(" << v.
getRows() <<
"," << v.
getCols() <<
") = [" << v <<
"]" << std::endl;
if (bench.size() != v.
size()) {
std::cout << "Test fails: bad size wrt bench" << std::endl;
return false;
}
for (
unsigned int i = 0; i < v.
size(); i++) {
if (std::fabs(v.
data[i] - bench[i]) > std::fabs(v.
data[i]) * std::numeric_limits<double>::epsilon()) {
std::cout << "Test fails: bad content" << std::endl;
return false;
}
}
return true;
}
{
std::cout << s <<
"(" << v.
getRows() <<
"," << v.
getCols() <<
") = [" << v <<
"]" << std::endl;
std::cout << "Test fails: bad size wrt bench" << std::endl;
return false;
}
for (
unsigned int i = 0; i < v.
size(); i++) {
if (std::fabs(v.
data[i] - bench[i]) > std::fabs(v.
data[i]) * std::numeric_limits<double>::epsilon()) {
std::cout << "Test fails: bad content" << std::endl;
return false;
}
}
return true;
}
{
std::cout << s <<
"(" << v.
getRows() <<
"," << v.
getCols() <<
") = [" << v <<
"]" << std::endl;
for (
unsigned int i = 0; i < v.
size(); i++) {
if (std::fabs(v[i] - bench) > std::fabs(v[i]) * std::numeric_limits<double>::epsilon()) {
std::cout << "Test fails: bad content" << std::endl;
return false;
}
}
return true;
}
{
for (unsigned int i = 0; i < 4; i++) {
for (unsigned int j = 0; j < 4; j++) {
return false;
}
}
}
return true;
}
TEST_CASE("Common rotation operations", "[rotation]")
{
SECTION("Theta u initialization")
{
CHECK(test("r1", r1, bench1));
bench1.clear();
bench1 = r1.toStdVector();
CHECK(test("r1", r1, bench1));
r1.buildFrom(bench3);
CHECK(test("r1", r1, bench3));
CHECK(test("r2", r2, bench1));
CHECK(r2.
data != r1.data);
CHECK(test("r3", r3, bench1));
for (
unsigned int i = 0; i < r3.
size(); i++) {
CHECK(std::fabs(r3[i] - bench1[i]) < std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
}
CHECK(test("r4", r4, bench2));
CHECK(test("r5", r5, bench1));
}
SECTION("Rxyz initialization")
{
CHECK(test("r1", r1, bench1));
bench1.clear();
bench1 = r1.toStdVector();
CHECK(test("r1", r1, bench1));
r1.buildFrom(bench3);
CHECK(test("r1", r1, bench3));
CHECK(test("r2", r2, bench1));
CHECK(test("r3", r3, bench1));
for (
unsigned int i = 0; i < r3.
size(); i++) {
CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
}
CHECK(test("r4", r4, bench2));
CHECK(test("r5", r5, bench1));
}
SECTION("rzyx initialization")
{
CHECK(test("r1", r1, bench1));
bench1.clear();
bench1 = r1.toStdVector();
CHECK(test("r1", r1, bench1));
r1.buildFrom(bench3);
CHECK(test("r1", r1, bench3));
CHECK(test("r2", r2, bench1));
CHECK(test("r3", r3, bench1));
for (
unsigned int i = 0; i < r3.
size(); i++) {
CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
}
CHECK(test("r4", r4, bench2));
CHECK(test("r5", r5, bench1));
}
SECTION("rzyz initialiation")
{
CHECK(test("r1", r1, bench1));
bench1.clear();
bench1 = r1.toStdVector();
CHECK(test("r1", r1, bench1));
r1.buildFrom(bench3);
CHECK(test("r1", r1, bench3));
CHECK(test("r2", r2, bench1));
CHECK(test("r3", r3, bench1));
for (
unsigned int i = 0; i < r3.
size(); i++) {
CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
}
CHECK(test("r4", r4, bench2));
CHECK(test("r5", r5, bench1));
}
SECTION("Test quaternion initialization", "[quaternion]")
{
CHECK(test("r1", r1, bench1));
bench1.clear();
bench1 = r1.toStdVector();
CHECK(test("r1", r1, bench1));
r1.buildFrom(bench3);
CHECK(test("r1", r1, bench3));
CHECK(test("r2", r2, bench1));
CHECK(test("r3", r3, bench1));
for (
unsigned int i = 0; i < r3.
size(); i++) {
CHECK(std::fabs(r3[i] - bench1[i]) <= std::fabs(r3[i]) * std::numeric_limits<double>::epsilon());
}
CHECK(test("r4", r4, bench2));
CHECK(test("r5", r5, bench1));
}
SECTION("Conversions")
{
for (int i = -10; i < 10; i++) {
for (int j = -10; j < 10; j++) {
std::cout << "Initialization " << std::endl;
double theta;
std::cout <<
"theta=" <<
vpMath::deg(theta) << std::endl;
std::cout << "u=" << u << std::endl;
std::cout << "From vpThetaUVector to vpRotationMatrix " << std::endl;
std::cout << "Matrix R";
std::cout << R << std::endl;
std::cout << "From vpRotationMatrix to vpQuaternionVector " << std::endl;
CHECK(q.magnitude() == Catch::Approx(1.0).margin(1e-4));
std::cout << q << std::endl;
std::cout << "From vpQuaternionVector to vpRotationMatrix " << std::endl;
std::cout << "From vpRotationMatrix to vpRxyzVector " << std::endl;
std::cout << RxyzbuildR << std::endl;
std::cout << "From vpRxyzVector to vpThetaUVector " << std::endl;
std::cout << " use From vpRxyzVector to vpRotationMatrix " << std::endl;
std::cout << " use From vpRotationMatrix to vpThetaUVector " << std::endl;
std::cout << std::endl;
std::cout << "result : should equivalent to the first one " << std::endl;
double theta2;
std::cout <<
"theta=" <<
vpMath::deg(theta2) << std::endl;
std::cout << "u=" << u2 << std::endl;
CHECK(
vpMath::abs(theta2 - theta) < std::numeric_limits<double>::epsilon() * 1e10);
CHECK(
vpMath::abs(u[0] - u2[0]) < std::numeric_limits<double>::epsilon() * 1e10);
CHECK(
vpMath::abs(u[1] - u2[1]) < std::numeric_limits<double>::epsilon() * 1e10);
CHECK(
vpMath::abs(u[2] - u2[2]) < std::numeric_limits<double>::epsilon() * 1e10);
}
}
SECTION("Conversion from and to rzyz vector")
{
std::cout << "Initialization vpRzyzVector " << std::endl;
std::cout << rzyz << std::endl;
std::cout << "From vpRzyzVector to vpRotationMatrix " << std::endl;
std::cout << "From vpRotationMatrix to vpRzyzVector " << std::endl;
std::cout << rzyz_final << std::endl;
}
SECTION("Conversion from and to rzyx vector")
{
std::cout << "Initialization vpRzyxVector " << std::endl;
std::cout << rzyx << std::endl;
std::cout << "From vpRzyxVector to vpRotationMatrix " << std::endl;
std::cout << R << std::endl;
std::cout << "From vpRotationMatrix to vpRzyxVector " << std::endl;
bool ret = test(
"rzyx", rzyx_final,
vpColVector(rzyx));
if (ret == false) {
std::cout << "Rzyx vector differ. Test rotation matrix..." << std::endl;
if (R == RR) {
std::cout << "Rzyx vector differ but rotation matrix is valid" << std::endl;
ret = true;
}
}
CHECK(ret);
std::cout << rzyx_final << std::endl;
}
}
SECTION("Rotation matrix extraction from homogeneous matrix and multiplication")
{
_1_M_2_truth[0][0] = 0.9835;
_1_M_2_truth[0][1] = -0.0581;
_1_M_2_truth[0][2] = 0.1716;
_1_M_2_truth[0][3] = 0;
_1_M_2_truth[1][0] = -0.0489;
_1_M_2_truth[1][1] = -0.9972;
_1_M_2_truth[1][2] = -0.0571;
_1_M_2_truth[1][3] = 0;
_1_M_2_truth[2][0] = 0.1744;
_1_M_2_truth[2][1] = 0.0478;
_1_M_2_truth[2][2] = -0.9835;
_1_M_2_truth[2][3] = 0;
_2_M_3_[0][0] = 0.9835;
_2_M_3_[0][1] = -0.0581;
_2_M_3_[0][2] = 0.1716;
_2_M_3_[0][3] = 0.0072;
_2_M_3_[1][0] = -0.0489;
_2_M_3_[1][1] = -0.9972;
_2_M_3_[1][2] = -0.0571;
_2_M_3_[1][3] = 0.0352;
_2_M_3_[2][0] = 0.1744;
_2_M_3_[2][1] = 0.0478;
_2_M_3_[2][2] = -0.9835;
_2_M_3_[2][3] = 0.9470;
CHECK(test_matrix_equal(_1_M_3_, _1_M_3_truth));
}
}
TEST_CASE("Theta u multiplication", "[theta.u]")
{
const int nTrials = 100;
const uint64_t seed = 0x123456789;
for (int iter = 0; iter < nTrials; iter++) {
const double tolerance = 1e-9;
for (unsigned int i = 0; i < 3; i++) {
for (unsigned int j = 0; j < 3; j++) {
CHECK(c1Rc3_ref[i][j] == Catch::Approx(c1Rc3[i][j]).epsilon(0).margin(tolerance));
}
}
}
}
TEST_CASE("Quaternion multiplication", "[quaternion]")
{
const int nTrials = 100;
const uint64_t seed = 0x123456789;
for (int iter = 0; iter < nTrials; iter++) {
const double tolerance = 1e-9;
for (unsigned int i = 0; i < 3; i++) {
for (unsigned int j = 0; j < 3; j++) {
CHECK(c1Rc3_ref[i][j] == Catch::Approx(c1Rc3[i][j]).epsilon(0).margin(tolerance));
}
}
}
}
int main(int argc, char *argv[])
{
Catch::Session session;
session.applyCommandLine(argc, argv);
int numFailed = session.run();
return numFailed;
}
#else
#include <iostream>
int main() { return EXIT_SUCCESS; }
#endif
unsigned int getCols() const
Type * data
Address of the first element of the data array.
unsigned int size() const
Return the number of elements of the 2D array.
unsigned int getRows() const
Implementation of column vector and the associated operations.
vpColVector extract(unsigned int r, unsigned int colsize) const
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
static double rad(double deg)
static Type abs(const Type &x)
static bool equal(double x, double y, double threshold=0.001)
static double deg(double rad)
Implementation of a rotation vector as quaternion angle minimal representation.
void set(double x, double y, double z, double w)
Implementation of a rotation matrix and operations on such kind of matrices.
bool isARotationMatrix(double threshold=1e-6) const
vpRotationMatrix & buildFrom(const vpHomogeneousMatrix &M)
Implementation of a generic rotation vector.
Implementation of a rotation vector as Euler angle minimal representation.
Implementation of a rotation vector as Euler angle minimal representation.
vpRzyxVector & buildFrom(const vpRotationMatrix &R)
Implementation of a rotation vector as Euler angle minimal representation.
vpRzyzVector & buildFrom(const vpRotationMatrix &R)
Implementation of a rotation vector as axis-angle minimal representation.
void extract(double &theta, vpColVector &u) const
vpThetaUVector & buildFrom(const vpHomogeneousMatrix &M)
Class for generating random numbers with uniform probability density.
int uniform(int a, int b)