|
26 | 26 |
|
27 | 27 | /** \author Wim Meeussen */ |
28 | 28 |
|
| 29 | +// To get M_PI, especially on Windows. |
| 30 | + |
| 31 | +#ifdef _MSC_VER |
| 32 | +#ifndef _USE_MATH_DEFINES |
| 33 | +#define _USE_MATH_DEFINES |
| 34 | +#endif |
| 35 | +#endif |
| 36 | + |
| 37 | +#include <math.h> |
| 38 | + |
29 | 39 |
|
30 | | -#include <tf2_eigen/tf2_eigen.h> |
31 | 40 | #include <gtest/gtest.h> |
32 | 41 | #include <tf2/convert.h> |
| 42 | +#include <tf2_eigen/tf2_eigen.h> |
| 43 | +#include <tf2_ros/buffer.h> |
| 44 | +#include <tf2_ros/transform_listener.h> |
| 45 | + |
| 46 | + |
| 47 | +#include <memory> |
33 | 48 |
|
34 | 49 | TEST(TfEigen, ConvertVector3dStamped) |
35 | 50 | { |
@@ -204,9 +219,124 @@ TEST(TfEigen, ConvertTransform) |
204 | 219 | EXPECT_TRUE(tm.isApprox(Iback.matrix())); |
205 | 220 | } |
206 | 221 |
|
| 222 | +struct EigenTransform : public ::testing::Test |
| 223 | +{ |
| 224 | + static void SetUpTestSuite() |
| 225 | + { |
| 226 | + geometry_msgs::TransformStamped t; |
| 227 | + transform.transform.translation.x = 10; |
| 228 | + transform.transform.translation.y = 20; |
| 229 | + transform.transform.translation.z = 30; |
| 230 | + transform.transform.rotation.w = 0; |
| 231 | + transform.transform.rotation.x = 1; |
| 232 | + transform.transform.rotation.y = 0; |
| 233 | + transform.transform.rotation.z = 0; |
| 234 | + transform.header.stamp = ros::Time(2.0); |
| 235 | + transform.header.frame_id = "A"; |
| 236 | + transform.child_frame_id = "B"; |
| 237 | + } |
| 238 | + |
| 239 | + template<int mode> |
| 240 | + void testEigenTransform(); |
| 241 | + |
| 242 | + ::testing::AssertionResult doTestEigenQuaternion( |
| 243 | + const Eigen::Quaterniond & parameter, const Eigen::Quaterniond & expected); |
| 244 | + |
| 245 | + static geometry_msgs::TransformStamped transform; |
| 246 | + static constexpr double EPS = 1e-3; |
| 247 | +}; |
| 248 | + |
| 249 | +geometry_msgs::TransformStamped EigenTransform::transform; |
| 250 | + |
| 251 | +template<int mode> |
| 252 | +void EigenTransform::testEigenTransform() |
| 253 | +{ |
| 254 | + using T = Eigen::Transform<double, 3, mode>; |
| 255 | + using stampedT = tf2::Stamped<T>; |
| 256 | + |
| 257 | + const stampedT i1{ |
| 258 | + T{Eigen::Translation3d{1, 2, 3} *Eigen::Quaterniond{0, 1, 0, 0}}, ros::Time(2), "A"}; |
| 259 | + |
| 260 | + stampedT i_simple; |
| 261 | + tf2::doTransform(i1, i_simple, transform); |
| 262 | + |
| 263 | + EXPECT_NEAR(i_simple.translation().x(), 11, EPS); |
| 264 | + EXPECT_NEAR(i_simple.translation().y(), 18, EPS); |
| 265 | + EXPECT_NEAR(i_simple.translation().z(), 27, EPS); |
| 266 | + const auto q1 = Eigen::Quaterniond(i_simple.linear()); |
| 267 | + EXPECT_NEAR(q1.x(), 0.0, EPS); |
| 268 | + EXPECT_NEAR(q1.y(), 0.0, EPS); |
| 269 | + EXPECT_NEAR(q1.z(), 0.0, EPS); |
| 270 | + EXPECT_NEAR(q1.w(), 1.0, EPS); |
| 271 | +} |
| 272 | + |
| 273 | +TEST_F(EigenTransform, Affine3d) { |
| 274 | + testEigenTransform<Eigen::Affine>(); |
| 275 | +} |
| 276 | + |
| 277 | +TEST_F(EigenTransform, Isometry3d) { |
| 278 | + testEigenTransform<Eigen::Isometry>(); |
| 279 | +} |
| 280 | + |
| 281 | +TEST_F(EigenTransform, Vector) |
| 282 | +{ |
| 283 | + const tf2::Stamped<Eigen::Vector3d> v1{{1, 2, 3}, ros::Time(2), "A"}; |
207 | 284 |
|
| 285 | + // simple api |
| 286 | + tf2::Stamped<Eigen::Vector3d> v_simple; |
| 287 | + tf2::doTransform(v1, v_simple, transform); |
208 | 288 |
|
209 | | -int main(int argc, char **argv){ |
| 289 | + EXPECT_NEAR(v_simple.x(), 11, EPS); |
| 290 | + EXPECT_NEAR(v_simple.y(), 18, EPS); |
| 291 | + EXPECT_NEAR(v_simple.z(), 27, EPS); |
| 292 | +} |
| 293 | + |
| 294 | +// helper method for Quaternion tests |
| 295 | +::testing::AssertionResult EigenTransform::doTestEigenQuaternion( |
| 296 | + const Eigen::Quaterniond & parameter, const Eigen::Quaterniond & expected) |
| 297 | +{ |
| 298 | + const tf2::Stamped<Eigen::Quaterniond> q1{parameter, ros::Time(2), "A"}; |
| 299 | + // avoid linking error |
| 300 | + const double eps = EPS; |
| 301 | + |
| 302 | + // simple api |
| 303 | + tf2::Stamped<Eigen::Quaterniond> q_simple; |
| 304 | + tf2::doTransform(q1, q_simple, transform); |
| 305 | + // compare rotation matrices, as the quaternions can be ambigous |
| 306 | + EXPECT_TRUE(q_simple.toRotationMatrix().isApprox(expected.toRotationMatrix(), eps)); |
| 307 | + |
| 308 | + return ::testing::AssertionSuccess(); |
| 309 | +} |
| 310 | + |
| 311 | +TEST_F(EigenTransform, QuaternionRotY) |
| 312 | +{ |
| 313 | + // rotated by -90° around y |
| 314 | + // 0, 0, -1 |
| 315 | + // 0, 1, 0, |
| 316 | + // 1, 0, 0 |
| 317 | + const Eigen::Quaterniond param{Eigen::AngleAxisd(-1 * M_PI_2, Eigen::Vector3d::UnitY())}; |
| 318 | + const Eigen::Quaterniond expected{0, M_SQRT1_2, 0, -1 * M_SQRT1_2}; |
| 319 | + EXPECT_TRUE(doTestEigenQuaternion(param, expected)); |
| 320 | +} |
| 321 | + |
| 322 | +TEST_F(EigenTransform, QuaternionRotX) |
| 323 | +{ |
| 324 | + // rotated by 90° around y |
| 325 | + const Eigen::Quaterniond param{Eigen::AngleAxisd(M_PI_2, Eigen::Vector3d::UnitX())}; |
| 326 | + const Eigen::Quaterniond expected{Eigen::AngleAxisd(-1 * M_PI_2, Eigen::Vector3d::UnitX())}; |
| 327 | + EXPECT_TRUE(doTestEigenQuaternion(param, expected)); |
| 328 | +} |
| 329 | + |
| 330 | +TEST_F(EigenTransform, QuaternionRotZ) |
| 331 | +{ |
| 332 | + // rotated by 180° around z |
| 333 | + const Eigen::Quaterniond param{Eigen::AngleAxisd(M_PI, Eigen::Vector3d::UnitZ())}; |
| 334 | + const Eigen::Quaterniond expected{Eigen::AngleAxisd(M_PI, Eigen::Vector3d::UnitY())}; |
| 335 | + EXPECT_TRUE(doTestEigenQuaternion(param, expected)); |
| 336 | +} |
| 337 | + |
| 338 | +int main(int argc, char ** argv) |
| 339 | +{ |
210 | 340 | testing::InitGoogleTest(&argc, argv); |
211 | 341 |
|
212 | 342 | return RUN_ALL_TESTS(); |
|
0 commit comments