/// @file /// Transformations between poses and hyperplanes. #ifndef GEOMETRY_HPP #define GEOMETRY_HPP #include "se2.hpp" #include "se3.hpp" #include "so2.hpp" #include "so3.hpp" #include "types.hpp" namespace Sophus { /// Takes in a rotation ``R_foo_plane`` and returns the corresponding line /// normal along the y-axis (in reference frame ``foo``). /// template Vector2 normalFromSO2(SO2 const& R_foo_line) { return R_foo_line.matrix().col(1); } /// Takes in line normal in reference frame foo and constructs a corresponding /// rotation matrix ``R_foo_line``. /// /// Precondition: ``normal_foo`` must not be close to zero. /// template SO2 SO2FromNormal(Vector2 normal_foo) { SOPHUS_ENSURE(normal_foo.squaredNorm() > Constants::epsilon(), "%", normal_foo.transpose()); normal_foo.normalize(); return SO2(normal_foo.y(), -normal_foo.x()); } /// Takes in a rotation ``R_foo_plane`` and returns the corresponding plane /// normal along the z-axis /// (in reference frame ``foo``). /// template Vector3 normalFromSO3(SO3 const& R_foo_plane) { return R_foo_plane.matrix().col(2); } /// Takes in plane normal in reference frame foo and constructs a corresponding /// rotation matrix ``R_foo_plane``. /// /// Note: The ``plane`` frame is defined as such that the normal points along /// the positive z-axis. One can specify hints for the x-axis and y-axis /// of the ``plane`` frame. /// /// Preconditions: /// - ``normal_foo``, ``xDirHint_foo``, ``yDirHint_foo`` must not be close to /// zero. /// - ``xDirHint_foo`` and ``yDirHint_foo`` must be approx. perpendicular. /// template Matrix3 rotationFromNormal(Vector3 const& normal_foo, Vector3 xDirHint_foo = Vector3(T(1), T(0), T(0)), Vector3 yDirHint_foo = Vector3(T(0), T(1), T(0))) { SOPHUS_ENSURE(xDirHint_foo.dot(yDirHint_foo) < Constants::epsilon(), "xDirHint (%) and yDirHint (%) must be perpendicular.", xDirHint_foo.transpose(), yDirHint_foo.transpose()); using std::abs; using std::sqrt; T const xDirHint_foo_sqr_length = xDirHint_foo.squaredNorm(); T const yDirHint_foo_sqr_length = yDirHint_foo.squaredNorm(); T const normal_foo_sqr_length = normal_foo.squaredNorm(); SOPHUS_ENSURE(xDirHint_foo_sqr_length > Constants::epsilon(), "%", xDirHint_foo.transpose()); SOPHUS_ENSURE(yDirHint_foo_sqr_length > Constants::epsilon(), "%", yDirHint_foo.transpose()); SOPHUS_ENSURE(normal_foo_sqr_length > Constants::epsilon(), "%", normal_foo.transpose()); Matrix3 basis_foo; basis_foo.col(2) = normal_foo; if (abs(xDirHint_foo_sqr_length - T(1)) > Constants::epsilon()) { xDirHint_foo.normalize(); } if (abs(yDirHint_foo_sqr_length - T(1)) > Constants::epsilon()) { yDirHint_foo.normalize(); } if (abs(normal_foo_sqr_length - T(1)) > Constants::epsilon()) { basis_foo.col(2).normalize(); } T abs_x_dot_z = abs(basis_foo.col(2).dot(xDirHint_foo)); T abs_y_dot_z = abs(basis_foo.col(2).dot(yDirHint_foo)); if (abs_x_dot_z < abs_y_dot_z) { // basis_foo.z and xDirHint are far from parallel. basis_foo.col(1) = basis_foo.col(2).cross(xDirHint_foo).normalized(); basis_foo.col(0) = basis_foo.col(1).cross(basis_foo.col(2)); } else { // basis_foo.z and yDirHint are far from parallel. basis_foo.col(0) = yDirHint_foo.cross(basis_foo.col(2)).normalized(); basis_foo.col(1) = basis_foo.col(2).cross(basis_foo.col(0)); } T det = basis_foo.determinant(); // sanity check SOPHUS_ENSURE(abs(det - T(1)) < Constants::epsilon(), "Determinant of basis is not 1, but %. Basis is \n%\n", det, basis_foo); return basis_foo; } /// Takes in plane normal in reference frame foo and constructs a corresponding /// rotation matrix ``R_foo_plane``. /// /// See ``rotationFromNormal`` for details. /// template SO3 SO3FromNormal(Vector3 const& normal_foo) { return SO3(rotationFromNormal(normal_foo)); } /// Returns a line (wrt. to frame ``foo``), given a pose of the ``line`` in /// reference frame ``foo``. /// /// Note: The plane is defined by X-axis of the ``line`` frame. /// template Line2 lineFromSE2(SE2 const& T_foo_line) { return Line2(normalFromSO2(T_foo_line.so2()), T_foo_line.translation()); } /// Returns the pose ``T_foo_line``, given a line in reference frame ``foo``. /// /// Note: The line is defined by X-axis of the frame ``line``. /// template SE2 SE2FromLine(Line2 const& line_foo) { T const d = line_foo.offset(); Vector2 const n = line_foo.normal(); SO2 const R_foo_plane = SO2FromNormal(n); return SE2(R_foo_plane, -d * n); } /// Returns a plane (wrt. to frame ``foo``), given a pose of the ``plane`` in /// reference frame ``foo``. /// /// Note: The plane is defined by XY-plane of the frame ``plane``. /// template Plane3 planeFromSE3(SE3 const& T_foo_plane) { return Plane3(normalFromSO3(T_foo_plane.so3()), T_foo_plane.translation()); } /// Returns the pose ``T_foo_plane``, given a plane in reference frame ``foo``. /// /// Note: The plane is defined by XY-plane of the frame ``plane``. /// template SE3 SE3FromPlane(Plane3 const& plane_foo) { T const d = plane_foo.offset(); Vector3 const n = plane_foo.normal(); SO3 const R_foo_plane = SO3FromNormal(n); return SE3(R_foo_plane, -d * n); } /// Takes in a hyperplane and returns unique representation by ensuring that the /// ``offset`` is not negative. /// template Eigen::Hyperplane makeHyperplaneUnique( Eigen::Hyperplane const& plane) { if (plane.offset() >= 0) { return plane; } return Eigen::Hyperplane(-plane.normal(), -plane.offset()); } } // namespace Sophus #endif // GEOMETRY_HPP