Merge pull request #866 from borglab/Pose2-align
						commit
						e320bfa3b2
					
				|  | @ -25,6 +25,12 @@ namespace gtsam { | |||
| /// As of GTSAM 4, in order to make GTSAM more lean,
 | ||||
| /// it is now possible to just typedef Point2 to Vector2
 | ||||
| typedef Vector2 Point2; | ||||
|    | ||||
| // Convenience typedef
 | ||||
| using Point2Pair = std::pair<Point2, Point2>; | ||||
| GTSAM_EXPORT std::ostream &operator<<(std::ostream &os, const gtsam::Point2Pair &p); | ||||
| 
 | ||||
| using Point2Pairs = std::vector<Point2Pair>; | ||||
| 
 | ||||
| /// Distance of the point from the origin, with Jacobian
 | ||||
| GTSAM_EXPORT double norm2(const Point2& p, OptionalJacobian<1, 2> H = boost::none); | ||||
|  | @ -34,10 +40,6 @@ GTSAM_EXPORT double distance2(const Point2& p1, const Point2& q, | |||
|                  OptionalJacobian<1, 2> H1 = boost::none, | ||||
|                  OptionalJacobian<1, 2> H2 = boost::none); | ||||
| 
 | ||||
| // Convenience typedef
 | ||||
| typedef std::pair<Point2, Point2> Point2Pair; | ||||
| GTSAM_EXPORT std::ostream &operator<<(std::ostream &os, const gtsam::Point2Pair &p); | ||||
| 
 | ||||
| // For MATLAB wrapper
 | ||||
| typedef std::vector<Point2, Eigen::aligned_allocator<Point2> > Point2Vector; | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,6 +31,14 @@ class Point2 { | |||
|   // enable pickling in python | ||||
|   void pickle() const; | ||||
| }; | ||||
|    | ||||
| class Point2Pairs { | ||||
|   Point2Pairs(); | ||||
|   size_t size() const; | ||||
|   bool empty() const; | ||||
|   gtsam::Point2Pair at(size_t n) const; | ||||
|   void push_back(const gtsam::Point2Pair& point_pair); | ||||
| }; | ||||
| 
 | ||||
| // std::vector<gtsam::Point2> | ||||
| class Point2Vector { | ||||
|  | @ -429,6 +437,8 @@ class Pose2 { | |||
|   // enable pickling in python | ||||
|   void pickle() const; | ||||
| }; | ||||
|    | ||||
| boost::optional<gtsam::Pose2> align(const gtsam::Point2Pairs& pairs); | ||||
| 
 | ||||
| #include <gtsam/geometry/Pose3.h> | ||||
| class Pose3 { | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ set(ignore | |||
|     gtsam::BetweenFactorPose2s | ||||
|     gtsam::BetweenFactorPose3s | ||||
|     gtsam::Point2Vector | ||||
|     gtsam::Point2Pairs | ||||
|     gtsam::Point3Pairs | ||||
|     gtsam::Pose3Pairs | ||||
|     gtsam::Pose3Vector | ||||
|  |  | |||
|  | @ -10,9 +10,18 @@ | |||
|  * Without this they will be automatically converted to a Python object, and all | ||||
|  * mutations on Python side will not be reflected on C++. | ||||
|  */ | ||||
| #include <pybind11/stl.h> | ||||
| 
 | ||||
| // Support for binding boost::optional types in C++11.
 | ||||
| // https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
 | ||||
| namespace pybind11 { namespace detail { | ||||
|     template <typename T> | ||||
|     struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {}; | ||||
| }} | ||||
| 
 | ||||
| PYBIND11_MAKE_OPAQUE( | ||||
|     std::vector<gtsam::Point2, Eigen::aligned_allocator<gtsam::Point2>>); | ||||
| PYBIND11_MAKE_OPAQUE(gtsam::Point2Pairs); | ||||
| PYBIND11_MAKE_OPAQUE(gtsam::Point3Pairs); | ||||
| PYBIND11_MAKE_OPAQUE(gtsam::Pose3Pairs); | ||||
| PYBIND11_MAKE_OPAQUE(std::vector<gtsam::Pose3>); | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| py::bind_vector< | ||||
|     std::vector<gtsam::Point2, Eigen::aligned_allocator<gtsam::Point2>>>( | ||||
|     m_, "Point2Vector"); | ||||
| py::bind_vector<std::vector<gtsam::Point2Pair>>(m_, "Point2Pairs"); | ||||
| py::bind_vector<std::vector<gtsam::Point3Pair>>(m_, "Point3Pairs"); | ||||
| py::bind_vector<std::vector<gtsam::Pose3Pair>>(m_, "Pose3Pairs"); | ||||
| py::bind_vector<std::vector<gtsam::Pose3>>(m_, "Pose3Vector"); | ||||
|  |  | |||
|  | @ -6,27 +6,64 @@ All Rights Reserved | |||
| See LICENSE for the license information | ||||
| 
 | ||||
| Pose2 unit tests. | ||||
| Author: Frank Dellaert & Duy Nguyen Ta (Python) | ||||
| Author: Frank Dellaert & Duy Nguyen Ta & John Lambert | ||||
| """ | ||||
| import unittest | ||||
| 
 | ||||
| import numpy as np | ||||
| 
 | ||||
| import gtsam | ||||
| from gtsam import Pose2 | ||||
| from gtsam import Point2, Point2Pairs, Pose2 | ||||
| from gtsam.utils.test_case import GtsamTestCase | ||||
| 
 | ||||
| 
 | ||||
| class TestPose2(GtsamTestCase): | ||||
|     """Test selected Pose2 methods.""" | ||||
| 
 | ||||
|     def test_adjoint(self): | ||||
|     def test_adjoint(self) -> None: | ||||
|         """Test adjoint method.""" | ||||
|         xi = np.array([1, 2, 3]) | ||||
|         expected = np.dot(Pose2.adjointMap_(xi), xi) | ||||
|         actual = Pose2.adjoint_(xi, xi) | ||||
|         np.testing.assert_array_equal(actual, expected) | ||||
| 
 | ||||
|     def test_align(self) -> None: | ||||
|         """Ensure estimation of the Pose2 element to align two 2d point clouds succeeds. | ||||
| 
 | ||||
|         Two point clouds represent horseshoe-shapes of the same size, just rotated and translated: | ||||
| 
 | ||||
|                 |  X---X | ||||
|                 |  | | ||||
|                 |  X---X | ||||
|         ------------------ | ||||
|                 | | ||||
|                 | | ||||
|               O | O | ||||
|               | | | | ||||
|               O---O | ||||
|         """ | ||||
|         pts_a = [ | ||||
|             Point2(3, 1), | ||||
|             Point2(1, 1), | ||||
|             Point2(1, 3), | ||||
|             Point2(3, 3), | ||||
|         ] | ||||
|         pts_b = [ | ||||
|             Point2(1, -3), | ||||
|             Point2(1, -5), | ||||
|             Point2(-1, -5), | ||||
|             Point2(-1, -3), | ||||
|         ] | ||||
| 
 | ||||
|         # fmt: on | ||||
|         ab_pairs = Point2Pairs(list(zip(pts_a, pts_b))) | ||||
|         bTa = gtsam.align(ab_pairs) | ||||
|         aTb = bTa.inverse() | ||||
|         assert aTb is not None | ||||
| 
 | ||||
|         for pt_a, pt_b in zip(pts_a, pts_b): | ||||
|             pt_a_ = aTb.transformFrom(pt_b) | ||||
|             assert np.allclose(pt_a, pt_a_) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     unittest.main() | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue