1 // ----------------------------------------------------------------------------
2 // - Open3D: www.open3d.org -
3 // ----------------------------------------------------------------------------
4 // The MIT License (MIT)
5 //
6 // Copyright (c) 2018 www.open3d.org
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // ----------------------------------------------------------------------------
26
27 #include "open3d.h"
28
29 namespace pybind11 {
30
31 template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
bind_vector_without_repr(pybind11::module & m,std::string const & name,Args &&...args)32 pybind11::class_<Vector, holder_type> bind_vector_without_repr(
33 pybind11::module &m, std::string const &name, Args&&... args) {
34 // hack function to disable __repr__ for the convenient function
35 // bind_vector()
36 using Class_ = pybind11::class_<Vector, holder_type>;
37 Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
38 cl.def(pybind11::init<>());
39 detail::vector_if_copy_constructible<Vector, Class_>(cl);
40 detail::vector_if_equal_operator<Vector, Class_>(cl);
41 detail::vector_modifiers<Vector, Class_>(cl);
42 detail::vector_accessor<Vector, Class_>(cl);
43 cl.def("__bool__", [](const Vector &v) -> bool {
44 return !v.empty();
45 }, "Check whether the list is nonempty");
46 cl.def("__len__", &Vector::size);
47 return cl;
48 }
49
50 } //namespace pybind11
51
52 namespace {
53
54 template <typename Scalar>
pybind_eigen_vector_of_scalar(py::module & m,const std::string & bind_name)55 void pybind_eigen_vector_of_scalar(py::module &m, const std::string &bind_name)
56 {
57 auto vec = py::bind_vector<std::vector<Scalar>>(m, bind_name,
58 py::buffer_protocol());
59 vec.def_buffer([](std::vector<Scalar> &v) -> py::buffer_info {
60 return py::buffer_info(
61 v.data(), sizeof(Scalar),
62 py::format_descriptor<Scalar>::format(),
63 1, {v.size()}, {sizeof(Scalar)});
64 });
65 vec.def("__copy__", [](std::vector<Scalar> &v) {
66 return std::vector<Scalar>(v);
67 });
68 vec.def("__deepcopy__", [](std::vector<Scalar> &v, py::dict &memo) {
69 return std::vector<Scalar>(v);
70 });
71 // We use iterable __init__ by default
72 //vec.def("__init__", [](std::vector<Scalar> &v,
73 // py::array_t<Scalar, py::array::c_style> b) {
74 // py::buffer_info info = b.request();
75 // if (info.format != py::format_descriptor<Scalar>::format() ||
76 // info.ndim != 1)
77 // throw std::runtime_error("Incompatible buffer format!");
78 // new (&v) std::vector<Scalar>(info.shape[0]);
79 // memcpy(v.data(), info.ptr, sizeof(Scalar) * v.size());
80 //});
81 }
82
83 template <typename EigenVector>
pybind_eigen_vector_of_vector(py::module & m,const std::string & bind_name,const std::string & repr_name)84 void pybind_eigen_vector_of_vector(py::module &m, const std::string &bind_name,
85 const std::string &repr_name)
86 {
87 typedef typename EigenVector::Scalar Scalar;
88 auto vec = py::bind_vector_without_repr<std::vector<EigenVector>>(
89 m, bind_name, py::buffer_protocol());
90 vec.def_buffer([](std::vector<EigenVector> &v) -> py::buffer_info {
91 size_t rows = EigenVector::RowsAtCompileTime;
92 return py::buffer_info(
93 v.data(), sizeof(Scalar),
94 py::format_descriptor<Scalar>::format(),
95 2, {v.size(), rows},
96 {sizeof(EigenVector), sizeof(Scalar)});
97 });
98 vec.def("__repr__", [repr_name](const std::vector<EigenVector> &v) {
99 return repr_name + std::string(" with ") +
100 std::to_string(v.size()) + std::string(" elements.\n") +
101 std::string("Use numpy.asarray() to access data.");
102 });
103 vec.def("__copy__", [](std::vector<EigenVector> &v) {
104 return std::vector<EigenVector>(v);
105 });
106 vec.def("__deepcopy__", [](std::vector<EigenVector> &v,
107 py::dict &memo) {
108 return std::vector<EigenVector>(v);
109 });
110 // Bare bones interface
111 // We choose to disable them because they do not support slice indices
112 // such as [:,:]. It is recommanded to convert it to numpy.asarray()
113 // to access raw data.
114 //v.def("__getitem__", [](const std::vector<Eigen::Vector3d> &v,
115 // std::pair<size_t, size_t> i) {
116 // if (i.first >= v.size() || i.second >= 3)
117 // throw py::index_error();
118 // return v[i.first](i.second);
119 //});
120 //v.def("__setitem__", [](std::vector<Eigen::Vector3d> &v,
121 // std::pair<size_t, size_t> i, double x) {
122 // if (i.first >= v.size() || i.second >= 3)
123 // throw py::index_error();
124 // v[i.first](i.second) = x;
125 //});
126 // We use iterable __init__ by default
127 //vec.def("__init__", [](std::vector<EigenVector> &v,
128 // py::array_t<Scalar, py::array::c_style> b) {
129 // py::buffer_info info = b.request();s
130 // if (info.format !=
131 // py::format_descriptor<Scalar>::format() ||
132 // info.ndim != 2 ||
133 // info.shape[1] != EigenVector::RowsAtCompileTime)
134 // throw std::runtime_error("Incompatible buffer format!");
135 // new (&v) std::vector<EigenVector>(info.shape[0]);
136 // memcpy(v.data(), info.ptr, sizeof(EigenVector) * v.size());
137 //});
138 }
139
140 template <typename EigenMatrix>
pybind_eigen_vector_of_matrix(py::module & m,const std::string & bind_name,const std::string & repr_name)141 void pybind_eigen_vector_of_matrix(py::module &m, const std::string &bind_name,
142 const std::string &repr_name)
143 {
144 typedef typename EigenMatrix::Scalar Scalar;
145 auto vec = py::bind_vector_without_repr<std::vector<EigenMatrix>>(
146 m, bind_name, py::buffer_protocol());
147 vec.def_buffer([](std::vector<EigenMatrix> &v) -> py::buffer_info {
148 // We use this function to bind Eigen default matrix.
149 // Thus they are all column major.
150 size_t rows = EigenMatrix::RowsAtCompileTime;
151 size_t cols = EigenMatrix::ColsAtCompileTime;
152 return py::buffer_info(
153 v.data(), sizeof(Scalar),
154 py::format_descriptor<Scalar>::format(),
155 3, {v.size(), rows, cols},
156 {sizeof(EigenMatrix), sizeof(Scalar),
157 sizeof(Scalar) * rows});
158 });
159 vec.def("__repr__", [repr_name](const std::vector<EigenMatrix> &v) {
160 return repr_name + std::string(" with ") +
161 std::to_string(v.size()) + std::string(" elements.\n") +
162 std::string("Use numpy.asarray() to access data.");
163 });
164 vec.def("__copy__", [](std::vector<EigenMatrix> &v) {
165 return std::vector<EigenMatrix>(v);
166 });
167 vec.def("__deepcopy__", [](std::vector<EigenMatrix> &v,
168 py::dict &memo) {
169 return std::vector<EigenMatrix>(v);
170 });
171 }
172
173 } // unnamed namespace
174
pybind_eigen(py::module & m)175 void pybind_eigen(py::module &m)
176 {
177 pybind_eigen_vector_of_scalar<int>(m, "IntVector");
178 pybind_eigen_vector_of_scalar<double>(m, "DoubleVector");
179 pybind_eigen_vector_of_vector<Eigen::Vector3d>(m, "Vector3dVector",
180 "std::vector<Eigen::Vector3d>");
181 pybind_eigen_vector_of_vector<Eigen::Vector3i>(m, "Vector3iVector",
182 "std::vector<Eigen::Vector3i>");
183 pybind_eigen_vector_of_vector<Eigen::Vector2i>(m, "Vector2iVector",
184 "std::vector<Eigen::Vector2i>");
185 pybind_eigen_vector_of_matrix<Eigen::Matrix4d>(m, "Matrix4dVector",
186 "std::vector<Eigen::Matrix4d>");
187 }
188