14 #include <pybind11/numpy.h>
15 #include <pybind11/pybind11.h>
18 #include <type_traits>
21 using namespace pybind11::literals;
24 template <
class T>
using observer_ptr = std::unique_ptr<T, py::nodelete>;
33 static_assert(std::is_base_of<CCShareable, T>::value ==
true,
"T must be a subclass of CCShareable");
74 template <
class T> py::array_t<T>
SpanAsNumpyArray(T *data, py::array::ShapeContainer shape)
77 return py::array(shape, data, capsule);
83 return py::array(len, data, capsule);
93 template <
class Po
intCloudType>
95 py::array_t<PointCoordinateType> &xs,
96 py::array_t<PointCoordinateType> &ys,
97 py::array_t<PointCoordinateType> &zs)
99 if (xs.size() != ys.size() || xs.size() != zs.size())
101 throw py::value_error(
"xs, ys, zs must have the same size");
104 const py::ssize_t numToReserve =
self.size() + xs.size();
107 throw std::out_of_range(
std::to_string(numToReserve) +
" cannot be casted to unsigned int");
109 self.reserve(
static_cast<unsigned int>(numToReserve));
111 auto xs_it = xs.begin();
112 auto ys_it = ys.begin();
113 auto zs_it = zs.begin();
115 for (; xs_it != xs.end();)
128 Adds a scalar field with the given name to the point cloud.
133 name of the scalar field that will be added.
134 values: optional, numpy.array, list of float
135 values to use when initializing the new scalar field
139 RuntimeError if the point cloud already has a scalar field with the given ``name``
140 ValueError if values are provided don't have the same length (size) as the point cloud
145 Returns the size (number of points) in the point cloud.
147 ``len`` also works as an alias to size.
151 pc = pycc.ccPointCloud("name")
152 assert len(pc) == pc.size()
155 #define DEFINE_POINTCLOUDTPL(T, module, name) \
156 py::class_<cloudViewer::PointCloudTpl<T>, T>(module, name) \
157 .def("size", &cloudViewer::PointCloudTpl<T>::size, SIZE_SCALAR_FIELD_DOCSTRING) \
158 .def("forEach", &cloudViewer::PointCloudTpl<T>::forEach, "action"_a) \
159 .def("getBoundingBox", &cloudViewer::PointCloudTpl<T>::getBoundingBox, "bbMin"_a, "bbMax"_a) \
160 .def("getNextPoint", \
161 &cloudViewer::PointCloudTpl<T>::getNextPoint, \
162 py::return_value_policy::reference) \
163 .def("enableScalarField", &cloudViewer::PointCloudTpl<T>::enableScalarField) \
164 .def("isScalarFieldEnabled", &cloudViewer::PointCloudTpl<T>::isScalarFieldEnabled) \
165 .def("setPointScalarValue", \
166 &cloudViewer::PointCloudTpl<T>::setPointScalarValue, \
169 .def("getPointScalarValue", &cloudViewer::PointCloudTpl<T>::getPointScalarValue, "pointIndex"_a) \
170 .def("resize", &cloudViewer::PointCloudTpl<T>::resize, "newCount"_a) \
171 .def("reserve", &cloudViewer::PointCloudTpl<T>::reserve, "newCapacity"_a) \
172 .def("reset", &cloudViewer::PointCloudTpl<T>::reset) \
173 .def("invalidateBoundingBox", &cloudViewer::PointCloudTpl<T>::invalidateBoundingBox) \
174 .def("getNumberOfScalarFields", \
175 &cloudViewer::PointCloudTpl<T>::getNumberOfScalarFields, \
176 "Returns the number of scalar field of the point cloud") \
179 &cloudViewer::PointCloudTpl<T>::getScalarField, \
182 Returns the scalar field identified by its index. \
184 If index is invalid, None is returned \
187 "getScalarFieldName", \
188 &cloudViewer::PointCloudTpl<T>::getScalarFieldName, \
191 Returns the name of the scalar field identified by the index. \
193 If index is invalid, -1 is returned \
196 "getScalarFieldIndexByName", \
197 &cloudViewer::PointCloudTpl<T>::getScalarFieldIndexByName, \
200 Returns the scalar field identified by its name. \
202 If no scalar field has the given name, None is returned \
204 .def("getCurrentInScalarField", &cloudViewer::PointCloudTpl<T>::getCurrentInScalarField) \
205 .def("getCurrentOutScalarField", &cloudViewer::PointCloudTpl<T>::getCurrentOutScalarField) \
206 .def("setCurrentInScalarField", &cloudViewer::PointCloudTpl<T>::setCurrentInScalarField, "index"_a) \
207 .def("getCurrentInScalarFieldIndex", &cloudViewer::PointCloudTpl<T>::getCurrentInScalarFieldIndex) \
209 "setCurrentOutScalarField", &cloudViewer::PointCloudTpl<T>::setCurrentOutScalarField, "index"_a) \
210 .def("getCurrentOutScalarFieldIndex", &cloudViewer::PointCloudTpl<T>::getCurrentOutScalarFieldIndex) \
211 .def("setCurrentScalarField", &cloudViewer::PointCloudTpl<T>::setCurrentScalarField, "index"_a) \
212 .def("renameScalarField", &cloudViewer::PointCloudTpl<T>::renameScalarField, "index"_a, "newName"_a) \
215 [](cloudViewer::PointCloudTpl<T> &self, \
216 const char *sfName, \
217 const py::object &maybe_values = py::none()) \
219 int idx = self.addScalarField(sfName); \
222 throw std::runtime_error("Failed to add scalar field"); \
224 if (!maybe_values.is_none()) \
226 py::array_t<ScalarType> values(maybe_values); \
227 if (values.size() != self.size()) \
229 throw py::value_error("value must have the same len as the poinc cloud size"); \
231 auto values_u = values.unchecked<1>(); \
232 cloudViewer::ScalarField *sf = self.getScalarField(idx); \
233 for (py::ssize_t i{0}; i < values.size(); ++i) \
235 sf->setValue(i, values_u(i)); \
241 "values"_a = py::none(), \
242 ADD_SCALAR_FIELD_DOCSTRING) \
244 "deleteScalarField", \
245 &cloudViewer::PointCloudTpl<T>::deleteScalarField, \
248 Removes the scalar field identified by the index . \
251 This operation may modify the scalar fields order \
252 (especially if the deleted SF is not the last one). \
253 However current IN & OUT scalar fields will stay up-to-date \
254 (while their index may change). \
256 Does nothing if index is invalid \
258 .def("deleteAllScalarFields", \
259 &cloudViewer::PointCloudTpl<T>::deleteAllScalarFields, \
260 "Deletes all scalar fields associated to this cloud") \
263 [](cloudViewer::PointCloudTpl<T> &self, const CCVector3 &P) { self.addPoint(P); }, \
266 Adds a 3D point to the point cloud \
269 For better performances it is better to use :meth:`.addPoints`. \
273 &PyCC::addPointsFromArrays<cloudViewer::PointCloudTpl<T>>, \
278 Takes values from xs, yz, zs array and add them as points of the point cloud. \
282 Value error if xs,ys,zs do not have the same length \
284 .def("__len__", &cloudViewer::PointCloudTpl<T>::size);
float PointCoordinateType
Type of the coordinates of a (N-D) point.
CCShareableHolder(T *obj)
CCShareableHolder()=default
py::array_t< T > SpanAsNumpyArray(T *data, size_t len)
py::array_t< T > VectorAsNumpyArray(std::vector< T > &vector)
void addPointsFromArrays(PointCloudType &self, py::array_t< PointCoordinateType > &xs, py::array_t< PointCoordinateType > &ys, py::array_t< PointCoordinateType > &zs)
std::string to_string(const T &n)
PYBIND11_DECLARE_HOLDER_TYPE(T, CCShareableHolder< T >)
static constexpr const char SIZE_SCALAR_FIELD_DOCSTRING[]
static constexpr const char ADD_SCALAR_FIELD_DOCSTRING[]
std::unique_ptr< T, py::nodelete > observer_ptr
A unique_ptr that never free its ptr.