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