diff --git a/VirtualRobot/Util/json/eigen_conversion.cpp b/VirtualRobot/Util/json/eigen_conversion.cpp index afe96e578637bb4ca86e7879e44517265c5e7dfa..7486c73a184e06542533a363289ac4e9a6f10504 100644 --- a/VirtualRobot/Util/json/eigen_conversion.cpp +++ b/VirtualRobot/Util/json/eigen_conversion.cpp @@ -3,46 +3,40 @@ namespace Eigen { - template <> - void to_json<Vector3f>(nlohmann::json& j, const MatrixBase<Vector3f>& vector) - { - j["x"] = vector.x(); - j["y"] = vector.y(); - j["z"] = vector.z(); - } - template <> void from_json<Vector3f>(const nlohmann::json& j, MatrixBase<Vector3f>& vector) { - vector.x() = j.at("x").get<float>(); - vector.y() = j.at("y").get<float>(); - vector.z() = j.at("z").get<float>(); - } - - - template <> - void to_json<Matrix4f>(nlohmann::json& j, const MatrixBase<Matrix4f>& matrix) - { - // check lower row for [ 0 0 0 1 ] - if (matrix.row(3).isApprox(Eigen::Vector4f(0, 0, 0, 1).transpose(), 1e-9f)) + if (j.is_object()) { - // must construct a Vector3f to trigger specialized version of to_json() - j["pos"] = Eigen::Vector3f(math::Helpers::Position(matrix)); - j["ori"] = math::Helpers::Orientation(matrix); + vector.x() = j.at("x").get<float>(); + vector.y() = j.at("y").get<float>(); + vector.z() = j.at("z").get<float>(); } - else + else // j.is_array() { - jsonbase::to_json(j, matrix); + jsonbase::from_json(j, vector); } } + template <> void from_json<Matrix4f>(const nlohmann::json& j, MatrixBase<Matrix4f>& matrix) { - if (j.count("pos") > 0 && j.count("ori") > 0) + if (j.is_object()) { - matrix = math::Helpers::Pose(j.at("pos").get<Eigen::Vector3f>(), - j.at("ori").get<Eigen::Matrix3f>()); + const auto& j_ori = j.at("ori"); + Eigen::Matrix3f ori; + + if (j_ori.is_object()) + { + ori = j_ori.get<Eigen::Quaternionf>().toRotationMatrix(); + } + else + { + ori = j_ori.get<Eigen::Matrix3f>(); + } + + matrix = math::Helpers::Pose(j.at("pos").get<Eigen::Vector3f>(), ori); } else { diff --git a/VirtualRobot/Util/json/eigen_conversion.h b/VirtualRobot/Util/json/eigen_conversion.h index be04d1cf353ecfe2d1ba55a274ae0c24183909a6..4af202990214a068b6e8945ea87d863ebefb7274 100644 --- a/VirtualRobot/Util/json/eigen_conversion.h +++ b/VirtualRobot/Util/json/eigen_conversion.h @@ -10,8 +10,9 @@ #include "json.hpp" + /** - * Provide to_json() and from_json() overloads for nlohmann::json, + * Provide `to_json()` and `from_json()` overloads for `nlohmann::json`, * which allows simple syntax like: * * @code @@ -30,7 +31,7 @@ namespace Eigen { - // MatrixBase (non-specialized) + // MatrixBase (non-specialized). /// Writes the matrix as list of rows. template <typename Derived> @@ -43,44 +44,30 @@ namespace Eigen // Specialization for Vector3f (implemented in .cpp) - /// Writes vector with x, y, z keys. - template <> - void to_json<Vector3f>(nlohmann::json& j, const MatrixBase<Vector3f>& vector); - - /// Reads vector from x, y, z keys. + /// If `j` is an object, reads vector from `x, y, z` keys. Otherwise, reads it as matrix. template <> void from_json<Vector3f>(const nlohmann::json& j, MatrixBase<Vector3f>& vector); - // Specialization for Matrix4f as Transformation matrix (implemented in .cpp) - - /** - * @brief Write a 4x4 matrix, with optimization for transformation matrices. - * - * If the matrix is a transformation matrix, writes it as position - * (Vector3f) and orientation (Matrix3f). - * Otherwise, uses the non-specialized method (list of rows). - */ - template <> - void to_json<Matrix4f>(nlohmann::json& j, const MatrixBase<Matrix4f>& vector); + // Specialization for Matrix4f as transformation matrix (implemented in .cpp). /** - * @brief Reads a 4x4 matrix as written by to_json<Matrix4f>(). + * @brief Reads a 4x4 matrix from list of rows or `pos` and `ori` keys. * - * Reads the matrix as transformation matrix from position and orientation - * or from list of rows, depending on j's contents. + * If `j` is an object, reads `matrix` as transformation matrix from `pos` and `ori` keys. + * Otherweise, reads it from list of rows. */ template <> - void from_json<Matrix4f>(const nlohmann::json& j, MatrixBase<Matrix4f>& vector); + void from_json<Matrix4f>(const nlohmann::json& j, MatrixBase<Matrix4f>& matrix); // Quaternion - /// Writes the quaternion with qw, qx, qy, qz keys. + /// Writes the quaternion with `qw, qx, qy, qz` keys. template <typename Derived> void to_json(nlohmann::json& j, const QuaternionBase<Derived>& quat); - /// Reads the quaternion from qw, qx, qy, qz keys. + /// Reads the quaternion from `qw, qx, qy, qz` keys. template <typename Derived> void from_json(const nlohmann::json& j, QuaternionBase<Derived>& quat); diff --git a/VirtualRobot/tests/VirtualRobotJsonEigenConversionTest.cpp b/VirtualRobot/tests/VirtualRobotJsonEigenConversionTest.cpp index 9026027ef2e5111c2a22112ba8f3507686877de9..f362e6f5b89d18857c2605e5d2957314134ebc30 100644 --- a/VirtualRobot/tests/VirtualRobotJsonEigenConversionTest.cpp +++ b/VirtualRobot/tests/VirtualRobotJsonEigenConversionTest.cpp @@ -34,7 +34,8 @@ using namespace Eigen; BOOST_AUTO_TEST_SUITE(VirtualRobotJsonEigenConversionTest) -BOOST_AUTO_TEST_CASE(test_matrix4f_non_transform) + +BOOST_AUTO_TEST_CASE(test_Matrix4f_non_transform) { Matrix4f in = in.Identity(), out = out.Zero(); @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(test_matrix4f_non_transform) BOOST_CHECK_EQUAL(in, out); } -BOOST_AUTO_TEST_CASE(test_matrix4f_transform) +BOOST_AUTO_TEST_CASE(test_Matrix4f_transform) { Matrix4f in = math::Helpers::Pose(Vector3f { 3, 2, 3 }, AngleAxisf( 1.2f, Eigen::Vector3f(1,2,3).normalized())); @@ -72,7 +73,7 @@ BOOST_AUTO_TEST_CASE(test_matrix4f_transform) } -BOOST_AUTO_TEST_CASE(test_vector3f) +BOOST_AUTO_TEST_CASE(test_Vector3f) { Vector3f in = in.Identity(), out = out.Zero(); @@ -93,7 +94,25 @@ BOOST_AUTO_TEST_CASE(test_vector3f) } -BOOST_AUTO_TEST_CASE(test_quaternionf) +BOOST_AUTO_TEST_CASE(test_Vector3f_from_xyz) +{ + Eigen::Vector3f in(0, -1, 2.5), out; + nlohmann::json j; + j["x"] = in.x(); + j["y"] = in.y(); + j["z"] = in.z(); + + BOOST_TEST_MESSAGE("JSON: \n" << j.dump(2)); + + out = j; + BOOST_CHECK_EQUAL(in, out); + + out = j.get<Eigen::Vector3f>(); + BOOST_CHECK_EQUAL(in, out); +} + + +BOOST_AUTO_TEST_CASE(test_Quaternionf) { Quaternionf in { AngleAxisf(static_cast<float>(M_PI), Vector3f(1, 1, 1).normalized()) }; Quaternionf out = out.Identity(); @@ -109,4 +128,38 @@ BOOST_AUTO_TEST_CASE(test_quaternionf) } +BOOST_AUTO_TEST_CASE(test_Matrix4f_transform_from_pos_ori) +{ + Eigen::Vector3f pos(0, -1, 2.5); + Eigen::Quaternionf ori(AngleAxisf(static_cast<float>(M_PI_2), Eigen::Vector3f::UnitY())); + Matrix4f in = math::Helpers::Pose(pos, ori); + Matrix4f out = out.Zero(); + + // ori = Quaternion + nlohmann::json j; + j["pos"] = pos; + j["ori"] = ori; + BOOST_TEST_MESSAGE("JSON (ori = quat): \n" << j.dump(2)); + + out = j; + BOOST_CHECK_EQUAL(in, out); + + out = j.get<Matrix4f>(); + BOOST_CHECK_EQUAL(in, out); + + // ori = Matrix + j = nlohmann::json(); + j["pos"] = pos; + j["ori"] = ori.toRotationMatrix(); + + BOOST_TEST_MESSAGE("JSON (ori = mat): \n" << j.dump(2)); + + out = j; + BOOST_CHECK_EQUAL(in, out); + + out = j.get<Matrix4f>(); + BOOST_CHECK_EQUAL(in, out); +} + + BOOST_AUTO_TEST_SUITE_END()