Commit 992863a8 authored by Alexander Dielen's avatar Alexander Dielen

added functions that get and set properties for all mesh items

parent 81c40d03
......@@ -317,6 +317,92 @@ py::array_t<int> face_indices_poly(PolyMesh& _self) {
return py::array_t<int>(shape, strides, indices, free_when_done);
}
/**
* Attempts to return a custom property for all mesh items at once using a
* numpy array. Returns an empty array if the property contains elements that
* are not numpy arrays or at least one of the arrays has a non-uniform shape.
*
* @note The returned array is constructed on the fly and contains copies
* of the actual property values.
*/
template <class Mesh, class PropHandle, class IndexHandle>
py::array_t<double> property_array(Mesh& _self, PropHandle _ph, size_t _n) {
// assume that all arrays have the same size and
// retrieve the size of the first array
const py::object tmp_obj = _self.property(_ph, IndexHandle(0));
py::array_t<double> tmp_arr;
try {
tmp_arr = tmp_obj.cast<py::array_t<double> >();
}
catch (py::error_already_set& e) {
return py::array_t<double>();
}
const size_t size = tmp_arr.size();
// better check this now
if (size == 0) {
return py::array_t<double>();
}
// allocate memory
double *data = new double[size * _n];
// copy one array at a time
for (size_t i = 0; i < _n; ++i) {
const IndexHandle ih(i);
const py::object obj = _self.property(_ph, ih);
try {
const auto arr = obj.cast<py::array_t<double> >();
if (arr.size() != size) {
throw py::error_already_set();
}
std::copy(arr.data(0), arr.data(0) + size, &data[size * i]);
}
catch (py::error_already_set& e) {
delete[] data;
return py::array_t<double>();
}
}
// make numpy array
const auto shape = {_n, size};
const auto strides = {size * sizeof(double), sizeof(double)};
py::capsule free_when_done(data, [](void *f) {
double *ptr = reinterpret_cast<double *>(f);
delete[] ptr;
});
return py::array_t<double>(shape, strides, data, free_when_done);
}
/**
* Attempts to set a custom property for all mesh items at once using a
* numpy array.
*
* @note The property is set to copies of slices of _arr.
*/
template <class Mesh, class PropHandle, class IndexHandle>
void set_property_array(Mesh& _self, PropHandle _ph, py::array_t<double> _arr, size_t _n) {
// array cannot be empty and its shape has to be (_n, m,...)
if (_arr.size() == 0 || _arr.ndim() < 2 || _arr.shape(0) != _n) {
return;
}
// copy one array at a time
const size_t size = _arr.strides(0) / sizeof(double);
for (size_t i = 0; i < _n; ++i) {
double *data = new double[size];
std::copy(_arr.data(i), _arr.data(i) + size, data);
const auto shape = {size};
const auto strides = {sizeof(double)};
py::capsule free_when_done(data, [](void *f) {
double *ptr = reinterpret_cast<double *>(f);
delete[] ptr;
});
py::array_t<double> tmp(shape, strides, data, free_when_done);
_self.property(_ph, IndexHandle(i)) = tmp;
}
}
/**
* This function template is used to expose mesh member functions that are only
* available for a specific type of mesh (i.e. they are available for polygon
......@@ -1102,6 +1188,40 @@ void expose_mesh(py::module& m, const char *_name) {
.def("face_normals", [](Mesh& _self) { return vec2numpy(_self, _self.normal(OM::FaceHandle(0)), _self.n_faces()); })
.def("face_colors", [](Mesh& _self) { return vec2numpy(_self, _self.color (OM::FaceHandle(0)), _self.n_faces()); })
//======================================================================
// property_array
//======================================================================
.def("property_array", [] (Mesh& _self, OM::VPropHandleT<py::object> _ph) {
return property_array<Mesh, OM::VPropHandleT<py::object>, OM::VertexHandle>(_self, _ph, _self.n_vertices());
})
.def("property_array", [] (Mesh& _self, OM::HPropHandleT<py::object> _ph) {
return property_array<Mesh, OM::HPropHandleT<py::object>, OM::HalfedgeHandle>(_self, _ph, _self.n_halfedges());
})
.def("property_array", [] (Mesh& _self, OM::EPropHandleT<py::object> _ph) {
return property_array<Mesh, OM::EPropHandleT<py::object>, OM::EdgeHandle>(_self, _ph, _self.n_edges());
})
.def("property_array", [] (Mesh& _self, OM::FPropHandleT<py::object> _ph) {
return property_array<Mesh, OM::FPropHandleT<py::object>, OM::FaceHandle>(_self, _ph, _self.n_faces());
})
//======================================================================
// set_property_array
//======================================================================
.def("set_property_array", [] (Mesh& _self, OM::VPropHandleT<py::object> _ph, py::array_t<double> _arr) {
return set_property_array<Mesh, OM::VPropHandleT<py::object>, OM::VertexHandle>(_self, _ph, _arr, _self.n_vertices());
})
.def("set_property_array", [] (Mesh& _self, OM::HPropHandleT<py::object> _ph, py::array_t<double> _arr) {
return set_property_array<Mesh, OM::HPropHandleT<py::object>, OM::HalfedgeHandle>(_self, _ph, _arr, _self.n_halfedges());
})
.def("set_property_array", [] (Mesh& _self, OM::EPropHandleT<py::object> _ph, py::array_t<double> _arr) {
return set_property_array<Mesh, OM::EPropHandleT<py::object>, OM::EdgeHandle>(_self, _ph, _arr, _self.n_edges());
})
.def("set_property_array", [] (Mesh& _self, OM::FPropHandleT<py::object> _ph, py::array_t<double> _arr) {
return set_property_array<Mesh, OM::FPropHandleT<py::object>, OM::FaceHandle>(_self, _ph, _arr, _self.n_faces());
})
;
expose_type_specific_functions(class_mesh);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment