10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer 20ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2010, 2011, 2012 Google Inc. All rights reserved. 30ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// http://code.google.com/p/ceres-solver/ 40ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 50ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Redistribution and use in source and binary forms, with or without 60ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// modification, are permitted provided that the following conditions are met: 70ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 80ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions of source code must retain the above copyright notice, 90ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// this list of conditions and the following disclaimer. 100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions in binary form must reproduce the above copyright notice, 110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// this list of conditions and the following disclaimer in the documentation 120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and/or other materials provided with the distribution. 130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Neither the name of Google Inc. nor the names of its contributors may be 140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// used to endorse or promote products derived from this software without 150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// specific prior written permission. 160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// POSSIBILITY OF SUCH DAMAGE. 280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// 290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: sameeragarwal@google.com (Sameer Agarwal) 300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <cmath> 320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <limits> 330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include <string> 340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/eigen.h" 350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/port.h" 360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/jet.h" 370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/rotation.h" 380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/stringprintf.h" 390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/test_util.h" 400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "glog/logging.h" 410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gmock/gmock.h" 420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "gtest/gtest.h" 430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres { 450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace internal { 460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongconst double kPi = 3.14159265358979323846; 480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongconst double kHalfSqrt2 = 0.707106781186547524401; 490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongdouble RandDouble() { 510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double r = rand(); 520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return r / RAND_MAX; 530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// A tolerance value for floating-point comparisons. 560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic double const kTolerance = numeric_limits<double>::epsilon() * 10; 570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 581d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling// Looser tolerance used for numerically unstable conversions. 590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic double const kLooseTolerance = 1e-9; 600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Use as: 620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double quaternion[4]; 630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// EXPECT_THAT(quaternion, IsNormalizedQuaternion()); 640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongMATCHER(IsNormalizedQuaternion, "") { 650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (arg == NULL) { 660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "Null quaternion"; 670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm2 = arg[0] * arg[0] + arg[1] * arg[1] + 710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong arg[2] * arg[2] + arg[3] * arg[3]; 720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (fabs(norm2 - 1.0) > kTolerance) { 730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "squared norm is " << norm2; 740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Use as: 810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double expected_quaternion[4]; 820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double actual_quaternion[4]; 830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// EXPECT_THAT(actual_quaternion, IsNearQuaternion(expected_quaternion)); 840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongMATCHER_P(IsNearQuaternion, expected, "") { 850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (arg == NULL) { 860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "Null quaternion"; 870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Quaternions are equivalent upto a sign change. So we will compare 910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // both signs before declaring failure. 920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong bool near = true; 930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 4; i++) { 940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (fabs(arg[i] - expected[i]) > kTolerance) { 950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong near = false; 960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong break; 970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (near) { 1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong near = true; 1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 4; i++) { 1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (fabs(arg[i] + expected[i]) > kTolerance) { 1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong near = false; 1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong break; 1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (near) { 1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "expected : " 1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << expected[0] << " " 1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << expected[1] << " " 1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << expected[2] << " " 1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << expected[3] << " " 1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << "actual : " 1220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << arg[0] << " " 1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << arg[1] << " " 1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << arg[2] << " " 1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << arg[3]; 1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Use as: 1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double expected_axis_angle[4]; 1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double actual_axis_angle[4]; 1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// EXPECT_THAT(actual_axis_angle, IsNearAngleAxis(expected_axis_angle)); 1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongMATCHER_P(IsNearAngleAxis, expected, "") { 1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (arg == NULL) { 1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "Null axis/angle"; 1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (fabs(arg[i] - expected[i]) > kTolerance) { 1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "component " << i << " should be " << expected[i]; 1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Use as: 1500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double matrix[9]; 1510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// EXPECT_THAT(matrix, IsOrthonormal()); 1520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongMATCHER(IsOrthonormal, "") { 1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (arg == NULL) { 1540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "Null matrix"; 1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int c1 = 0; c1 < 3; c1++) { 1590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int c2 = 0; c2 < 3; c2++) { 1600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double v = 0; 1610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 1620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong v += arg[i + 3 * c1] * arg[i + 3 * c2]; 1630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected = (c1 == c2) ? 1 : 0; 1650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (fabs(expected - v) > kTolerance) { 1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "Columns " << c1 << " and " << c2 1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " should have dot product " << expected 1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " but have " << v; 1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Use as: 1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double matrix1[9]; 1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// double matrix2[9]; 1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// EXPECT_THAT(matrix1, IsNear3x3Matrix(matrix2)); 1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongMATCHER_P(IsNear3x3Matrix, expected, "") { 1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (arg == NULL) { 1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "Null matrix"; 1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 9; i++) { 1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (fabs(arg[i] - expected[i]) > kTolerance) { 1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong *result_listener << "component " << i << " should be " << expected[i]; 1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 1950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 1960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a zero axis/angle to a quaternion. 1980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, ZeroAngleAxisToQuaternion) { 1990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { 0, 0, 0 }; 2000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 2010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[4] = { 1, 0, 0, 0 }; 2020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 2030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNormalizedQuaternion()); 2040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNearQuaternion(expected)); 2050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that exact conversion works for small angles. 2080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, SmallAngleAxisToQuaternion) { 2090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Small, finite value to test. 2100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = 1.0e-2; 2110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { theta, 0, 0 }; 2120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 2130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[4] = { cos(theta/2), sin(theta/2.0), 0, 0 }; 2140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 2150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNormalizedQuaternion()); 2160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNearQuaternion(expected)); 2170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that approximate conversion works for very small angles. 2200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, TinyAngleAxisToQuaternion) { 2210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Very small value that could potentially cause underflow. 2220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = pow(numeric_limits<double>::min(), 0.75); 2230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { theta, 0, 0 }; 2240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 2250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[4] = { cos(theta/2), sin(theta/2.0), 0, 0 }; 2260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 2270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNormalizedQuaternion()); 2280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNearQuaternion(expected)); 2290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a rotation by pi/2 around X to a quaternion. 2320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, XRotationToQuaternion) { 2330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { kPi / 2, 0, 0 }; 2340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 2350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[4] = { kHalfSqrt2, kHalfSqrt2, 0, 0 }; 2360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 2370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNormalizedQuaternion()); 2380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(quaternion, IsNearQuaternion(expected)); 2390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a unit quaternion to an axis angle. 2420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, UnitQuaternionToAngleAxis) { 2430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4] = { 1, 0, 0, 0 }; 2440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 2450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[3] = { 0, 0, 0 }; 2460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 2470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(axis_angle, IsNearAngleAxis(expected)); 2480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a quaternion that rotates by pi about the Y axis to an axis angle. 2510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, YRotationQuaternionToAngleAxis) { 2520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4] = { 0, 0, 1, 0 }; 2530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 2540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[3] = { 0, kPi, 0 }; 2550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 2560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(axis_angle, IsNearAngleAxis(expected)); 2570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a quaternion that rotates by pi/3 about the Z axis to an axis 2600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// angle. 2610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, ZRotationQuaternionToAngleAxis) { 2620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4] = { sqrt(3) / 2, 0, 0, 0.5 }; 2630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 2640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[3] = { 0, 0, kPi / 3 }; 2650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 2660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(axis_angle, IsNearAngleAxis(expected)); 2670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that exact conversion works for small angles. 2700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, SmallQuaternionToAngleAxis) { 2710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Small, finite value to test. 2720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = 1.0e-2; 2730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4] = { cos(theta/2), sin(theta/2.0), 0, 0 }; 2740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 2750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[3] = { theta, 0, 0 }; 2760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 2770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(axis_angle, IsNearAngleAxis(expected)); 2780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that approximate conversion works for very small angles. 2810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, TinyQuaternionToAngleAxis) { 2820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Very small value that could potentially cause underflow. 2830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = pow(numeric_limits<double>::min(), 0.75); 2840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4] = { cos(theta/2), sin(theta/2.0), 0, 0 }; 2850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 2860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[3] = { theta, 0, 0 }; 2870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 2880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(axis_angle, IsNearAngleAxis(expected)); 2890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 2900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, QuaternionToAngleAxisAngleIsLessThanPi) { 2920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 2930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double angle_axis[3]; 2940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double half_theta = 0.75 * kPi; 2960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 2970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong quaternion[0] = cos(half_theta); 2980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong quaternion[1] = 1.0 * sin(half_theta); 2990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong quaternion[2] = 0.0; 3000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong quaternion[3] = 0.0; 3010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, angle_axis); 3020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double angle = sqrt(angle_axis[0] * angle_axis[0] + 3030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis[1] * angle_axis[1] + 3040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis[2] * angle_axis[2]); 3050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_LE(angle, kPi); 3060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 3070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic const int kNumTrials = 10000; 3090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Takes a bunch of random axis/angle values, converts them to quaternions, 3110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and back again. 3120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, AngleAxisToQuaterionAndBack) { 3130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong srand(5); 3140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < kNumTrials; i++) { 3150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 3160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make an axis by choosing three random numbers in [-1, 1) and 3170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // normalizing. 3180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm = 0; 3190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 3200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong axis_angle[i] = RandDouble() * 2 - 1; 3210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm += axis_angle[i] * axis_angle[i]; 3220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 3230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm = sqrt(norm); 3240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Angle in [-pi, pi). 3260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = kPi * 2 * RandDouble() - kPi; 3270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 3280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong axis_angle[i] = axis_angle[i] * theta / norm; 3290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 3300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 3320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double round_trip[3]; 3330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // We use ASSERTs here because if there's one failure, there are 3340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // probably many and spewing a million failures doesn't make anyone's 3350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // day. 3360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 3370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_THAT(quaternion, IsNormalizedQuaternion()); 3380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, round_trip); 3390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_THAT(round_trip, IsNearAngleAxis(axis_angle)); 3400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 3410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 3420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Takes a bunch of random quaternions, converts them to axis/angle, 3440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// and back again. 3450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, QuaterionToAngleAxisAndBack) { 3460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong srand(5); 3470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < kNumTrials; i++) { 3480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double quaternion[4]; 3490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Choose four random numbers in [-1, 1) and normalize. 3500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm = 0; 3510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 4; i++) { 3520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong quaternion[i] = RandDouble() * 2 - 1; 3530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm += quaternion[i] * quaternion[i]; 3540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 3550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm = sqrt(norm); 3560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 4; i++) { 3580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong quaternion[i] = quaternion[i] / norm; 3590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 3600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 3620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double round_trip[4]; 3630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 3640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, round_trip); 3650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_THAT(round_trip, IsNormalizedQuaternion()); 3660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_THAT(round_trip, IsNearQuaternion(quaternion)); 3670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 3680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 3690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a zero axis/angle to a rotation matrix. 3710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, ZeroAngleAxisToRotationMatrix) { 3720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { 0, 0, 0 }; 3730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 3740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; 3750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, matrix); 3760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsOrthonormal()); 3770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsNear3x3Matrix(expected)); 3780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 3790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, NearZeroAngleAxisToRotationMatrix) { 3810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { 1e-24, 2e-24, 3e-24 }; 3820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 3830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; 3840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, matrix); 3850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsOrthonormal()); 3860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsNear3x3Matrix(expected)); 3870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 3880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 3890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms a rotation by pi/2 around X to a rotation matrix and back. 3900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, XRotationToRotationMatrix) { 3910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { kPi / 2, 0, 0 }; 3920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 3930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // The rotation matrices are stored column-major. 3940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[9] = { 1, 0, 0, 0, 0, 1, 0, -1, 0 }; 3950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, matrix); 3960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsOrthonormal()); 3970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsNear3x3Matrix(expected)); 3980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double round_trip[3]; 3990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong RotationMatrixToAngleAxis(matrix, round_trip); 4000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(round_trip, IsNearAngleAxis(axis_angle)); 4010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 4020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms an axis angle that rotates by pi about the Y axis to a 4040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// rotation matrix and back. 4050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, YRotationToRotationMatrix) { 4060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { 0, kPi, 0 }; 4070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 4080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[9] = { -1, 0, 0, 0, 1, 0, 0, 0, -1 }; 4090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, matrix); 4100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsOrthonormal()); 4110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsNear3x3Matrix(expected)); 4120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double round_trip[3]; 4140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong RotationMatrixToAngleAxis(matrix, round_trip); 4150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(round_trip, IsNearAngleAxis(axis_angle)); 4160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 4170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, NearPiAngleAxisRoundTrip) { 4190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double in_axis_angle[3]; 4200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 4210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double out_axis_angle[3]; 4220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong srand(5); 4240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < kNumTrials; i++) { 4250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make an axis by choosing three random numbers in [-1, 1) and 4260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // normalizing. 4270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm = 0; 4280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 4290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong in_axis_angle[i] = RandDouble() * 2 - 1; 4300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm += in_axis_angle[i] * in_axis_angle[i]; 4310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm = sqrt(norm); 4330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Angle in [pi - kMaxSmallAngle, pi). 4350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double kMaxSmallAngle = 1e-2; 4360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = kPi - kMaxSmallAngle * RandDouble(); 4370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 4390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong in_axis_angle[i] *= (theta / norm); 4400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(in_axis_angle, matrix); 4420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong RotationMatrixToAngleAxis(matrix, out_axis_angle); 4430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i) { 4450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_NEAR(out_axis_angle[i], in_axis_angle[i], kLooseTolerance); 4460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 4490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, AtPiAngleAxisRoundTrip) { 4510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // A rotation of kPi about the X axis; 4520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong static const double kMatrix[3][3] = { 4530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong {1.0, 0.0, 0.0}, 4540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong {0.0, -1.0, 0.0}, 4550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong {0.0, 0.0, -1.0} 4560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 4570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double in_matrix[9]; 4590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Fill it from kMatrix in col-major order. 4600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0, k = 0; j < 3; ++j) { 4610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i, ++k) { 4620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong in_matrix[k] = kMatrix[i][j]; 4630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double expected_axis_angle[3] = { kPi, 0, 0 }; 4670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double out_matrix[9]; 4690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 4700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong RotationMatrixToAngleAxis(in_matrix, axis_angle); 4710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, out_matrix); 4720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(INFO) << "AngleAxis = " << axis_angle[0] << " " << axis_angle[1] 4740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << axis_angle[2]; 4750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(INFO) << "Expected AngleAxis = " << kPi << " 0 0"; 4760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double out_rowmajor[3][3]; 4770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0, k = 0; j < 3; ++j) { 4780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i, ++k) { 4790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong out_rowmajor[i][j] = out_matrix[k]; 4800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(INFO) << "Rotation:"; 4830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(INFO) << "EXPECTED | ACTUAL"; 4840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i) { 4850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong string line; 4860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < 3; ++j) { 4870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong StringAppendF(&line, "%g ", kMatrix[i][j]); 4880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong line += " | "; 4900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < 3; ++j) { 4910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong StringAppendF(&line, "%g ", out_rowmajor[i][j]); 4920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(INFO) << line; 4940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 4950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 4960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(axis_angle, IsNearAngleAxis(expected_axis_angle)); 4970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(out_matrix, IsNear3x3Matrix(in_matrix)); 4980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 4990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transforms an axis angle that rotates by pi/3 about the Z axis to a 5010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// rotation matrix. 5020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, ZRotationToRotationMatrix) { 5030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = { 0, 0, kPi / 3 }; 5040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 5050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // This is laid-out row-major on the screen but is actually stored 5060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // column-major. 5070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double expected[9] = { 0.5, sqrt(3) / 2, 0, // Column 1 5080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong -sqrt(3) / 2, 0.5, 0, // Column 2 5090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 0, 0, 1 }; // Column 3 5100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, matrix); 5110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsOrthonormal()); 5120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(matrix, IsNear3x3Matrix(expected)); 5130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double round_trip[3]; 5140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong RotationMatrixToAngleAxis(matrix, round_trip); 5150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(round_trip, IsNearAngleAxis(axis_angle)); 5160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 5170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Takes a bunch of random axis/angle values, converts them to rotation 5190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// matrices, and back again. 5200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, AngleAxisToRotationMatrixAndBack) { 5210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong srand(5); 5220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < kNumTrials; i++) { 5230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3]; 5240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Make an axis by choosing three random numbers in [-1, 1) and 5250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // normalizing. 5260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm = 0; 5270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 5280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong axis_angle[i] = RandDouble() * 2 - 1; 5290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm += axis_angle[i] * axis_angle[i]; 5300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm = sqrt(norm); 5320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Angle in [-pi, pi). 5340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = kPi * 2 * RandDouble() - kPi; 5350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; i++) { 5360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong axis_angle[i] = axis_angle[i] * theta / norm; 5370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double matrix[9]; 5400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double round_trip[3]; 5410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(axis_angle, matrix); 5420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_THAT(matrix, IsOrthonormal()); 5430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong RotationMatrixToAngleAxis(matrix, round_trip); 5440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i) { 5460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_NEAR(round_trip[i], axis_angle[i], kLooseTolerance); 5470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 5500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Transposes a 3x3 matrix. 5520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic void Transpose3x3(double m[9]) { 5530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::swap(m[1], m[3]); 5540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::swap(m[2], m[6]); 5550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong std::swap(m[5], m[7]); 5560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 5570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Convert Euler angles from radians to degrees. 5590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic void ToDegrees(double ea[3]) { 5600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i) 5610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ea[i] *= 180.0 / kPi; 5620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 5630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Compare the 3x3 rotation matrices produced by the axis-angle 5650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// rotation 'aa' and the Euler angle rotation 'ea' (in radians). 5660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic void CompareEulerToAngleAxis(double aa[3], double ea[3]) { 5670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double aa_matrix[9]; 5680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(aa, aa_matrix); 5690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong Transpose3x3(aa_matrix); // Column to row major order. 5700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ea_matrix[9]; 5720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ToDegrees(ea); // Radians to degrees. 5730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const int kRowStride = 3; 5740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EulerAnglesToRotationMatrix(ea, kRowStride, ea_matrix); 5750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(aa_matrix, IsOrthonormal()); 5770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(ea_matrix, IsOrthonormal()); 5780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(ea_matrix, IsNear3x3Matrix(aa_matrix)); 5790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 5800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 5810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test with rotation axis along the x/y/z axes. 5820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Also test zero rotation. 5830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(EulerAnglesToRotationMatrix, OnAxis) { 5840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong int n_tests = 0; 5850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (double x = -1.0; x <= 1.0; x += 1.0) { 5860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (double y = -1.0; y <= 1.0; y += 1.0) { 5870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (double z = -1.0; z <= 1.0; z += 1.0) { 5880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if ((x != 0) + (y != 0) + (z != 0) > 1) 5890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong continue; 5900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double axis_angle[3] = {x, y, z}; 5910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double euler_angles[3] = {x, y, z}; 5920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CompareEulerToAngleAxis(axis_angle, euler_angles); 5930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ++n_tests; 5940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 5970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong CHECK_EQ(7, n_tests); 5980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 5990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that a random rotation produces an orthonormal rotation 6010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// matrix. 6020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(EulerAnglesToRotationMatrix, IsOrthonormal) { 6030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong srand(5); 6040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int trial = 0; trial < kNumTrials; ++trial) { 6050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ea[3]; 6060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 3; ++i) 6070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ea[i] = 360.0 * (RandDouble() * 2.0 - 1.0); 6080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ea_matrix[9]; 6090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ToDegrees(ea); // Radians to degrees. 6100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EulerAnglesToRotationMatrix(ea, 3, ea_matrix); 6110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_THAT(ea_matrix, IsOrthonormal()); 6120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 6140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Tests using Jets for specific behavior involving auto differentiation 6160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// near singularity points. 6170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtypedef Jet<double, 3> J3; 6190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtypedef Jet<double, 4> J4; 6200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongJ3 MakeJ3(double a, double v0, double v1, double v2) { 6220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 j; 6230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.a = a; 6240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[0] = v0; 6250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[1] = v1; 6260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[2] = v2; 6270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return j; 6280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 6290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongJ4 MakeJ4(double a, double v0, double v1, double v2, double v3) { 6310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 j; 6320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.a = a; 6330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[0] = v0; 6340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[1] = v1; 6350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[2] = v2; 6360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong j.v[3] = v3; 6370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return j; 6380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 6390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongbool IsClose(double x, double y) { 6420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_FALSE(IsNaN(x)); 6430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_FALSE(IsNaN(y)); 6440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double absdiff = fabs(x - y); 6450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (x == 0 || y == 0) { 6460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return absdiff <= kTolerance; 6470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double reldiff = absdiff / max(fabs(x), fabs(y)); 6490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return reldiff <= kTolerance; 6500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 6510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtemplate <int N> 6530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongbool IsClose(const Jet<double, N> &x, const Jet<double, N> &y) { 6540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (IsClose(x.a, y.a)) { 6550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < N; i++) { 6560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (!IsClose(x.v[i], y.v[i])) { 6570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return false; 6580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong return true; 6620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 6630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtemplate <int M, int N> 6650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid ExpectJetArraysClose(const Jet<double, N> *x, const Jet<double, N> *y) { 6660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < M; i++) { 6670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong if (!IsClose(x[i], y[i])) { 6680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(ERROR) << "Jet " << i << "/" << M << " not equal"; 6690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(ERROR) << "x[" << i << "]: " << x[i]; 6700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(ERROR) << "y[" << i << "]: " << y[i]; 6710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong Jet<double, N> d, zero; 6720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong d.a = y[i].a - x[i].a; 6730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < N; j++) { 6740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong d.v[j] = y[i].v[j] - x[i].v[j]; 6750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong LOG(ERROR) << "diff: " << d; 6770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_TRUE(IsClose(x[i], y[i])); 6780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 6800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 6810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Log-10 of a value well below machine precision. 6830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic const int kSmallTinyCutoff = 6840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong static_cast<int>(2 * log(numeric_limits<double>::epsilon())/log(10.0)); 6850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Log-10 of a value just below values representable by double. 6870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongstatic const int kTinyZeroLimit = 6880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong static_cast<int>(1 + log(numeric_limits<double>::min())/log(10.0)); 6890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 6900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that exact conversion works for small angles when jets are used. 6910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, SmallAngleAxisToQuaternionForJets) { 6920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Examine small x rotations that are still large enough 6930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // to be well within the range represented by doubles. 6940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = -2; i >= kSmallTinyCutoff; i--) { 6950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = pow(10.0, i); 6960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 axis_angle[3] = { J3(theta, 0), J3(0, 1), J3(0, 2) }; 6970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 quaternion[4]; 6980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 expected[4] = { 6990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(cos(theta/2), -sin(theta/2)/2, 0, 0), 7000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(sin(theta/2), cos(theta/2)/2, 0, 0), 7010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0, sin(theta/2)/theta, 0), 7020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0, 0, sin(theta/2)/theta), 7030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 7040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 7050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectJetArraysClose<4, 3>(quaternion, expected); 7060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 7070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 7080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 7090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 7100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that conversion works for very small angles when jets are used. 7110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, TinyAngleAxisToQuaternionForJets) { 7120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Examine tiny x rotations that extend all the way to where 7130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // underflow occurs. 7140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = kSmallTinyCutoff; i >= kTinyZeroLimit; i--) { 7150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = pow(10.0, i); 7160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 axis_angle[3] = { J3(theta, 0), J3(0, 1), J3(0, 2) }; 7170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 quaternion[4]; 7180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // To avoid loss of precision in the test itself, 7190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // a finite expansion is used here, which will 7200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // be exact up to machine precision for the test values used. 7210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 expected[4] = { 7220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(1.0, 0, 0, 0), 7230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0.5, 0, 0), 7240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0, 0.5, 0), 7250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0, 0, 0.5), 7260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 7270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 7280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectJetArraysClose<4, 3>(quaternion, expected); 7290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 7300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 7310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 7320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that derivatives are correct for zero rotation. 7330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, ZeroAngleAxisToQuaternionForJets) { 7340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 axis_angle[3] = { J3(0, 0), J3(0, 1), J3(0, 2) }; 7350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 quaternion[4]; 7360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J3 expected[4] = { 7370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(1.0, 0, 0, 0), 7380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0.5, 0, 0), 7390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0, 0.5, 0), 7400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ3(0, 0, 0, 0.5), 7410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 7420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToQuaternion(axis_angle, quaternion); 7430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectJetArraysClose<4, 3>(quaternion, expected); 7440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 7450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 7460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that exact conversion works for small angles. 7470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, SmallQuaternionToAngleAxisForJets) { 7480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Examine small x rotations that are still large enough 7490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // to be well within the range represented by doubles. 7500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = -2; i >= kSmallTinyCutoff; i--) { 7510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = pow(10.0, i); 7520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double s = sin(theta); 7530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double c = cos(theta); 7540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 quaternion[4] = { J4(c, 0), J4(s, 1), J4(0, 2), J4(0, 3) }; 7550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 axis_angle[3]; 7560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 expected[3] = { 7570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(s, -2*theta, 2*theta*c, 0, 0), 7580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 0, 2*theta/s, 0), 7590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 0, 0, 2*theta/s), 7600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 7610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 7620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectJetArraysClose<3, 4>(axis_angle, expected); 7630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 7640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 7650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 7660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that conversion works for very small angles. 7670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, TinyQuaternionToAngleAxisForJets) { 7680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Examine tiny x rotations that extend all the way to where 7690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // underflow occurs. 7700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = kSmallTinyCutoff; i >= kTinyZeroLimit; i--) { 7710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = pow(10.0, i); 7720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double s = sin(theta); 7730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double c = cos(theta); 7740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 quaternion[4] = { J4(c, 0), J4(s, 1), J4(0, 2), J4(0, 3) }; 7750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 axis_angle[3]; 7760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // To avoid loss of precision in the test itself, 7770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // a finite expansion is used here, which will 7780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // be exact up to machine precision for the test values used. 7790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 expected[3] = { 7800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(theta, -2*theta, 2.0, 0, 0), 7810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 0, 2.0, 0), 7820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 0, 0, 2.0), 7830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 7840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 7850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectJetArraysClose<3, 4>(axis_angle, expected); 7860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 7870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 7880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 7890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Test that conversion works for no rotation. 7900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Rotation, ZeroQuaternionToAngleAxisForJets) { 7910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 quaternion[4] = { J4(1, 0), J4(0, 1), J4(0, 2), J4(0, 3) }; 7920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 axis_angle[3]; 7930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong J4 expected[3] = { 7940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 2.0, 0, 0), 7950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 0, 2.0, 0), 7960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong MakeJ4(0, 0, 0, 0, 2.0), 7970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 7980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToAngleAxis(quaternion, axis_angle); 7990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectJetArraysClose<3, 4>(axis_angle, expected); 8000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 8010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Quaternion, RotatePointGivesSameAnswerAsRotationByMatrixCanned) { 8030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Canned data generated in octave. 8040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double const q[4] = { 8050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong +0.1956830471754074, 8060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong -0.0150618562474847, 8070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong +0.7634572982788086, 8080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong -0.3019454777240753, 8090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 8100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double const Q[3][3] = { // Scaled rotation matrix. 8110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { -0.6355194033477252, 0.0951730541682254, 0.3078870197911186 }, 8120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { -0.1411693904792992, 0.5297609702153905, -0.4551502574482019 }, 8130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { -0.2896955822708862, -0.4669396571547050, -0.4536309793389248 }, 8140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 8150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double const R[3][3] = { // With unit rows and columns. 8160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { -0.8918859164053080, 0.1335655625725649, 0.4320876677394745 }, 8170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { -0.1981166751680096, 0.7434648665444399, -0.6387564287225856 }, 8180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong { -0.4065578619806013, -0.6553016349046693, -0.6366242786393164 }, 8190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 8200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Compute R from q and compare to known answer. 8220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double Rq[3][3]; 8230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToScaledRotation<double>(q, Rq[0]); 8240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectArraysClose(9, Q[0], Rq[0], kTolerance); 8250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Now do the same but compute R with normalization. 8270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToRotation<double>(q, Rq[0]); 8280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectArraysClose(9, R[0], Rq[0], kTolerance); 8290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 8300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Quaternion, RotatePointGivesSameAnswerAsRotationByMatrix) { 8330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong // Rotation defined by a unit quaternion. 8340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double const q[4] = { 8350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 0.2318160216097109, 8360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong -0.0178430356832060, 8370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 0.9044300776717159, 8380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong -0.3576998641394597, 8390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 8400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double const p[3] = { 8410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong +0.11, 8420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong -13.15, 8430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 1.17, 8440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong }; 8450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double R[3 * 3]; 8470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionToRotation(q, R); 8480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double result1[3]; 8500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong UnitQuaternionRotatePoint(q, p, result1); 8510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double result2[3]; 8530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong VectorRef(result2, 3) = ConstMatrixRef(R, 3, 3)* ConstVectorRef(p, 3); 8540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ExpectArraysClose(3, result1, result2, kTolerance); 8550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 8560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Verify that (a * b) * c == a * (b * c). 8590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(Quaternion, MultiplicationIsAssociative) { 8600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double a[4]; 8610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double b[4]; 8620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double c[4]; 8630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 4; ++i) { 8640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong a[i] = 2 * RandDouble() - 1; 8650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong b[i] = 2 * RandDouble() - 1; 8660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong c[i] = 2 * RandDouble() - 1; 8670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 8680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ab[4]; 8700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double ab_c[4]; 8710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionProduct(a, b, ab); 8720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionProduct(ab, c, ab_c); 8730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double bc[4]; 8750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double a_bc[4]; 8760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionProduct(b, c, bc); 8770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong QuaternionProduct(a, bc, a_bc); 8780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_NEAR(ab_c[0], a_bc[0], kTolerance); 8800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_NEAR(ab_c[1], a_bc[1], kTolerance); 8810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_NEAR(ab_c[2], a_bc[2], kTolerance); 8820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong ASSERT_NEAR(ab_c[3], a_bc[3], kTolerance); 8830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 8840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(AngleAxis, RotatePointGivesSameAnswerAsRotationMatrix) { 8870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double angle_axis[3]; 8880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double R[9]; 8890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double p[3]; 8900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double angle_axis_rotated_p[3]; 8910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double rotation_matrix_rotated_p[3]; 8920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 8930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 10000; ++i) { 8940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = (2.0 * i * 0.0011 - 1.0) * kPi; 8950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int j = 0; j < 50; ++j) { 8960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm2 = 0.0; 8970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int k = 0; k < 3; ++k) { 8980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis[k] = 2.0 * RandDouble() - 1.0; 8990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong p[k] = 2.0 * RandDouble() - 1.0; 9000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm2 = angle_axis[k] * angle_axis[k]; 9010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double inv_norm = theta / sqrt(norm2); 9040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int k = 0; k < 3; ++k) { 9050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis[k] *= inv_norm; 9060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(angle_axis, R); 9090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong rotation_matrix_rotated_p[0] = R[0] * p[0] + R[3] * p[1] + R[6] * p[2]; 9100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong rotation_matrix_rotated_p[1] = R[1] * p[0] + R[4] * p[1] + R[7] * p[2]; 9110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong rotation_matrix_rotated_p[2] = R[2] * p[0] + R[5] * p[1] + R[8] * p[2]; 9120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisRotatePoint(angle_axis, p, angle_axis_rotated_p); 9140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int k = 0; k < 3; ++k) { 9150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_NEAR(rotation_matrix_rotated_p[k], 9160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis_rotated_p[k], 9170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong kTolerance) << "p: " << p[0] 9180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << p[1] 9190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << p[2] 9200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " angle_axis: " << angle_axis[0] 9210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << angle_axis[1] 9220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << angle_axis[2]; 9230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 9270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus KongTEST(AngleAxis, NearZeroRotatePointGivesSameAnswerAsRotationMatrix) { 9290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double angle_axis[3]; 9300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double R[9]; 9310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double p[3]; 9320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double angle_axis_rotated_p[3]; 9330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double rotation_matrix_rotated_p[3]; 9340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int i = 0; i < 10000; ++i) { 9360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double norm2 = 0.0; 9370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int k = 0; k < 3; ++k) { 9380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis[k] = 2.0 * RandDouble() - 1.0; 9390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong p[k] = 2.0 * RandDouble() - 1.0; 9400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong norm2 = angle_axis[k] * angle_axis[k]; 9410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong double theta = (2.0 * i * 0.0001 - 1.0) * 1e-16; 9440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong const double inv_norm = theta / sqrt(norm2); 9450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int k = 0; k < 3; ++k) { 9460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis[k] *= inv_norm; 9470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisToRotationMatrix(angle_axis, R); 9500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong rotation_matrix_rotated_p[0] = R[0] * p[0] + R[3] * p[1] + R[6] * p[2]; 9510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong rotation_matrix_rotated_p[1] = R[1] * p[0] + R[4] * p[1] + R[7] * p[2]; 9520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong rotation_matrix_rotated_p[2] = R[2] * p[0] + R[5] * p[1] + R[8] * p[2]; 9530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong AngleAxisRotatePoint(angle_axis, p, angle_axis_rotated_p); 9550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong for (int k = 0; k < 3; ++k) { 9560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong EXPECT_NEAR(rotation_matrix_rotated_p[k], 9570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong angle_axis_rotated_p[k], 9580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong kTolerance) << "p: " << p[0] 9590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << p[1] 9600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << p[2] 9610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " angle_axis: " << angle_axis[0] 9620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << angle_axis[1] 9630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong << " " << angle_axis[2]; 9640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong } 9660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} 9670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 9681d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha HaeberlingTEST(MatrixAdapter, RowMajor3x3ReturnTypeAndAccessIsCorrect) { 9691d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling double array[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; 9701d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling const float const_array[9] = 9711d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; 9721d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling MatrixAdapter<double, 3, 1> A = RowMajorAdapter3x3(array); 9731d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling MatrixAdapter<const float, 3, 1> B = RowMajorAdapter3x3(const_array); 9741d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 9751d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling for (int i = 0; i < 3; ++i) { 9761d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling for (int j = 0; j < 3; ++j) { 9771d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling // The values are integers from 1 to 9, so equality tests are appropriate 9781d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling // even for float and double values. 9791d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling EXPECT_EQ(A(i, j), array[3*i+j]); 9801d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling EXPECT_EQ(B(i, j), const_array[3*i+j]); 9811d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 9821d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 9831d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling} 9841d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 9851d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha HaeberlingTEST(MatrixAdapter, ColumnMajor3x3ReturnTypeAndAccessIsCorrect) { 9861d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling double array[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; 9871d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling const float const_array[9] = 9881d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f }; 9891d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling MatrixAdapter<double, 1, 3> A = ColumnMajorAdapter3x3(array); 9901d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling MatrixAdapter<const float, 1, 3> B = ColumnMajorAdapter3x3(const_array); 9911d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 9921d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling for (int i = 0; i < 3; ++i) { 9931d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling for (int j = 0; j < 3; ++j) { 9941d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling // The values are integers from 1 to 9, so equality tests are 9951d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling // appropriate even for float and double values. 9961d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling EXPECT_EQ(A(i, j), array[3*j+i]); 9971d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling EXPECT_EQ(B(i, j), const_array[3*j+i]); 9981d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 9991d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 10001d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling} 10011d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 10021d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha HaeberlingTEST(MatrixAdapter, RowMajor2x4IsCorrect) { 10031d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling const int expected[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 10041d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling int array[8]; 10051d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling MatrixAdapter<int, 4, 1> M(array); 10061d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling M(0, 0) = 1; M(0, 1) = 2; M(0, 2) = 3; M(0, 3) = 4; 10071d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling M(1, 0) = 5; M(1, 1) = 6; M(1, 2) = 7; M(1, 3) = 8; 10081d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling for (int k = 0; k < 8; ++k) { 10091d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling EXPECT_EQ(array[k], expected[k]); 10101d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 10111d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling} 10121d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling 10131d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha HaeberlingTEST(MatrixAdapter, ColumnMajor2x4IsCorrect) { 10141d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling const int expected[8] = { 1, 5, 2, 6, 3, 7, 4, 8 }; 10151d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling int array[8]; 10161d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling MatrixAdapter<int, 1, 2> M(array); 10171d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling M(0, 0) = 1; M(0, 1) = 2; M(0, 2) = 3; M(0, 3) = 4; 10181d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling M(1, 0) = 5; M(1, 1) = 6; M(1, 2) = 7; M(1, 3) = 8; 10191d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling for (int k = 0; k < 8; ++k) { 10201d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling EXPECT_EQ(array[k], expected[k]); 10211d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling } 10221d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling} 10230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong 10240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace internal 10250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong} // namespace ceres 1026