From 397100e96cae1cdc343ea2403d679338b3e56adc Mon Sep 17 00:00:00 2001 From: Paul-Edouard Sarlin Date: Fri, 26 Jan 2024 11:40:24 +0100 Subject: [PATCH 1/4] Extended py::class for nonconst read --- pycolmap/geometry/bindings.h | 7 ++++--- pycolmap/pybind11_extension.h | 32 ++++++++++++++++++++++++++++++++ pycolmap/scene/point2D.h | 2 +- pycolmap/scene/point3D.h | 2 +- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/pycolmap/geometry/bindings.h b/pycolmap/geometry/bindings.h index 85f3d18..b3a8e2e 100644 --- a/pycolmap/geometry/bindings.h +++ b/pycolmap/geometry/bindings.h @@ -5,6 +5,7 @@ #include "pycolmap/geometry/homography_matrix.h" #include "pycolmap/helpers.h" +#include "pycolmap/pybind11_extension.h" #include @@ -20,7 +21,7 @@ using namespace pybind11::literals; void BindGeometry(py::module& m) { BindHomographyGeometry(m); - py::class_ PyRotation3d(m, "Rotation3d"); + py::class_ext_ PyRotation3d(m, "Rotation3d"); PyRotation3d.def(py::init([]() { return Eigen::Quaterniond::Identity(); })) .def(py::init(), "xyzw"_a, @@ -55,7 +56,7 @@ void BindGeometry(py::module& m) { py::implicitly_convertible(); MakeDataclass(PyRotation3d); - py::class_ PyRigid3d(m, "Rigid3d"); + py::class_ext_ PyRigid3d(m, "Rigid3d"); PyRigid3d.def(py::init<>()) .def(py::init()) .def(py::init([](const Eigen::Matrix3x4d& matrix) { @@ -87,7 +88,7 @@ void BindGeometry(py::module& m) { py::implicitly_convertible(); MakeDataclass(PyRigid3d); - py::class_ PySim3d(m, "Sim3d"); + py::class_ext_ PySim3d(m, "Sim3d"); PySim3d.def(py::init<>()) .def( py::init()) diff --git a/pycolmap/pybind11_extension.h b/pycolmap/pybind11_extension.h index a96d0c9..d7516c7 100644 --- a/pycolmap/pybind11_extension.h +++ b/pycolmap/pybind11_extension.h @@ -96,6 +96,38 @@ struct type_caster>> { } // namespace detail +template +class class_ext_ : public class_ { + public: + using Parent = class_; + using Parent::class_; // inherit constructors + using type = type_; + + template + class_ext_& def_readwrite(const char* name, D C::*pm, const Extra&... extra) { + static_assert( + std::is_same::value || std::is_base_of::value, + "def_readwrite() requires a class member (or base class member)"); + cpp_function fget([pm](type&c) -> D& { return c.*pm; }, is_method(*this)), + fset([pm](type&c, const D&value) { c.*pm = value; }, is_method(*this)); + this->def_property( + name, fget, fset, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ext_& def(Args&&... args) { + Parent::def(std::forward(args)...); + return *this; + } + + template + class_ext_& def_property(Args&&... args) { + Parent::def_property(std::forward(args)...); + return *this; + } +}; + // Fix long-standing bug https://github.com/pybind/pybind11/issues/4529 // TODO(sarlinpe): remove when https://github.com/pybind/pybind11/pull/4972 // appears in the next release of pybind11. diff --git a/pycolmap/scene/point2D.h b/pycolmap/scene/point2D.h index 97917cf..909632f 100644 --- a/pycolmap/scene/point2D.h +++ b/pycolmap/scene/point2D.h @@ -45,7 +45,7 @@ void BindPoint2D(py::module& m) { return repr; }); - py::class_> PyPoint2D(m, "Point2D"); + py::class_ext_> PyPoint2D(m, "Point2D"); PyPoint2D.def(py::init<>()) .def(py::init(), "xy"_a, diff --git a/pycolmap/scene/point3D.h b/pycolmap/scene/point3D.h index acf4fd5..7dd8ef1 100644 --- a/pycolmap/scene/point3D.h +++ b/pycolmap/scene/point3D.h @@ -26,7 +26,7 @@ void BindPoint3D(py::module& m) { std::to_string(self.size()) + ")"; }); - py::class_> PyPoint3D(m, "Point3D"); + py::class_ext_> PyPoint3D(m, "Point3D"); PyPoint3D.def(py::init<>()) .def_readwrite("xyz", &Point3D::xyz) .def_readwrite("color", &Point3D::color) From 8b7f7ba16dd4ab2e6e0da58ff39e551b87f99c2d Mon Sep 17 00:00:00 2001 From: Paul-Edouard Sarlin Date: Fri, 26 Jan 2024 14:52:51 +0100 Subject: [PATCH 2/4] Improve Rotation3d --- pycolmap/geometry/bindings.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pycolmap/geometry/bindings.h b/pycolmap/geometry/bindings.h index b3a8e2e..0884557 100644 --- a/pycolmap/geometry/bindings.h +++ b/pycolmap/geometry/bindings.h @@ -29,6 +29,12 @@ void BindGeometry(py::module& m) { .def(py::init(), "rotmat"_a, "3x3 rotation matrix.") + .def(py::init([](const Eigen::Vector3d& vec) { + return Eigen::Quaterniond( + Eigen::AngleAxis(vec.norm(), vec.normalized())); + }), + "axis_angle"_a, + "3D axis-angle representation.") .def_property( "quat", py::overload_cast<>(&Eigen::Quaterniond::coeffs), @@ -47,6 +53,14 @@ void BindGeometry(py::module& m) { .def("normalize", &Eigen::Quaterniond::normalize) .def("matrix", &Eigen::Quaterniond::toRotationMatrix) .def("norm", &Eigen::Quaterniond::norm) + .def("angle", + [](const Eigen::Quaterniond& self) { + return Eigen::AngleAxis(self).angle(); + }) + .def("angle_to", + [](const Eigen::Quaterniond& self, const Eigen::Quaterniond& other) { + return self.angularDistance(other); + }) .def("inverse", &Eigen::Quaterniond::inverse) .def("__repr__", [](const Eigen::Quaterniond& self) { std::stringstream ss; From f8cf4d1791770fb873f8bb8ed1abc6c23227ba7e Mon Sep 17 00:00:00 2001 From: Paul-Edouard Sarlin Date: Fri, 26 Jan 2024 14:56:04 +0100 Subject: [PATCH 3/4] Doc --- pycolmap/geometry/bindings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycolmap/geometry/bindings.h b/pycolmap/geometry/bindings.h index 0884557..1451b1a 100644 --- a/pycolmap/geometry/bindings.h +++ b/pycolmap/geometry/bindings.h @@ -34,7 +34,7 @@ void BindGeometry(py::module& m) { Eigen::AngleAxis(vec.norm(), vec.normalized())); }), "axis_angle"_a, - "3D axis-angle representation.") + "Axis-angle 3D vector.") .def_property( "quat", py::overload_cast<>(&Eigen::Quaterniond::coeffs), From 36730512aefcbc5c11f084461d6db7d5222235ae Mon Sep 17 00:00:00 2001 From: Paul-Edouard Sarlin Date: Fri, 26 Jan 2024 15:01:16 +0100 Subject: [PATCH 4/4] Fix --- pycolmap/geometry/bindings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycolmap/geometry/bindings.h b/pycolmap/geometry/bindings.h index 1451b1a..3ee64cb 100644 --- a/pycolmap/geometry/bindings.h +++ b/pycolmap/geometry/bindings.h @@ -31,7 +31,7 @@ void BindGeometry(py::module& m) { "3x3 rotation matrix.") .def(py::init([](const Eigen::Vector3d& vec) { return Eigen::Quaterniond( - Eigen::AngleAxis(vec.norm(), vec.normalized())); + Eigen::AngleAxis(vec.norm(), vec.normalized())); }), "axis_angle"_a, "Axis-angle 3D vector.")