Commit 905b4f8c authored by Alexander Dielen's avatar Alexander Dielen

added missing python/c++ conversions

parent 3d829c44
Pipeline #9480 passed with stages
in 5 minutes and 53 seconds
......@@ -2,6 +2,7 @@
#define OPENMESH_PYTHON_MESH_HH
#include "Utilities.hh"
#include "TypeConversions.hh"
#include "MeshTypes.hh"
#include "Iterator.hh"
#include "Circulator.hh"
......@@ -107,61 +108,6 @@ void garbage_collection(Mesh& _self, py::list& _vh_to_update, py::list& _hh_to_u
_self.garbage_collection(vh_vector, hh_vector, fh_vector, _v, _e, _f);
}
/**
* Converts OpenMesh vectors to numpy arrays.
*
* @tparam vector A Vector type.
* @param _vec The vector to be converted.
*/
template<class Vector>
py::array_t<typename Vector::value_type> vec2numpy(const Vector& _vec) {
typedef typename Vector::value_type dtype;
dtype *data = new dtype[_vec.size()];
std::copy_n(_vec.data(), _vec.size(), data);
py::capsule base = free_when_done(data);
return py::array_t<dtype>({_vec.size()}, {sizeof(dtype)}, data, base);
}
/**
* Converts OpenMesh vectors to numpy arrays.
*
* The returned array references the vector's underlying data, i.e. changes
* made to the returned array affect the original mesh.
*
* @tparam Mesh A Mesh type.
* @tparam vector A Vector type.
*
* @param _mesh The mesh that owns the vector's underlying memory. In order
* to avaoid dangling pointers, the lifetime of this mesh is tied to the
* lifetime of the returned numpy array.
* @param _vec The vector to be converted.
*/
template<class Mesh, class Vector>
py::array_t<typename Vector::value_type> vec2numpy(Mesh& _mesh, Vector& _vec, size_t _n = 1) {
typedef typename Vector::value_type dtype;
std::vector<size_t> shape;
std::vector<size_t> strides;
if (_n == 1) {
shape = {_vec.size()};
strides = {sizeof(dtype)};
}
else {
shape = {_n, _vec.size()};
strides = {_vec.size() * sizeof(dtype), sizeof(dtype)};
}
return py::array_t<dtype>(shape, strides, _vec.data(), py::cast(_mesh));
}
template<class Mesh>
py::array_t<float> flt2numpy(Mesh& _mesh, const float& _flt, size_t _n = 1) {
return py::array_t<float>({_n}, {sizeof(float)}, &_flt, py::cast(_mesh));
}
template<class Mesh>
py::array_t<double> flt2numpy(Mesh& _mesh, const double& _flt, size_t _n = 1) {
return py::array_t<double>({_n}, {sizeof(double)}, &_flt, py::cast(_mesh));
}
py::array_t<int> face_vertex_indices_trimesh(TriMesh& _self) {
if (_self.n_faces() == 0) {
return py::array_t<int>();
......@@ -1356,10 +1302,10 @@ void expose_mesh(py::module& m, const char *_name) {
// new property interface: single item
//======================================================================
.def("vertex_property", &Mesh::template py_property<OM::VertexHandle, typename Mesh::VPropHandle>)
.def("halfedge_property", &Mesh::template py_property<OM::HalfedgeHandle, typename Mesh::HPropHandle>)
.def("edge_property", &Mesh::template py_property<OM::EdgeHandle, typename Mesh::EPropHandle>)
.def("face_property", &Mesh::template py_property<OM::FaceHandle, typename Mesh::FPropHandle>)
.def("vertex_property", &Mesh::template py_property<OM::VertexHandle>)
.def("halfedge_property", &Mesh::template py_property<OM::HalfedgeHandle>)
.def("edge_property", &Mesh::template py_property<OM::EdgeHandle>)
.def("face_property", &Mesh::template py_property<OM::FaceHandle>)
.def("set_vertex_property", &Mesh::template py_set_property<OM::VertexHandle>)
.def("set_halfedge_property", &Mesh::template py_set_property<OM::HalfedgeHandle>)
......
......@@ -6,6 +6,7 @@
#define OM_STATIC_BUILD
#include "Utilities.hh"
#include "TypeConversions.hh"
#include <OpenMesh/Core/IO/MeshIO.hh>
......@@ -51,10 +52,71 @@ public:
typedef OpenMesh::EPropHandleT<py::none> EPropHandle;
typedef OpenMesh::FPropHandleT<py::none> FPropHandle;
template <class Handle, class PropHandle>
py::none py_property(const std::string& _name, Handle _h) {
const auto prop = py_prop_on_demand<Handle, PropHandle>(_name);
template <class Handle>
py::object py_property(const std::string& _name, Handle _h) {
#ifdef OPENMESH_PYTHON_HIDE_CPP_PROPERTIES
const auto prop = py_prop_on_demand<Handle, HandleToPropHandle<Handle, py::none>>(_name);
return Mesh::property(prop, _h);
#else
OpenMesh::BaseProperty *base_prop = nullptr;
int idx = -1;
if (py_get_base_property<Handle>(base_prop, idx, _name)) {
// there is a property with the given name
if (dynamic_cast<OpenMesh::PropertyT<py::none>*>(base_prop)) {
HandleToPropHandle<Handle, py::none> prop(idx);
return Mesh::property(prop, _h);
}
else if (dynamic_cast<OpenMesh::PropertyT<bool>*>(base_prop)) {
HandleToPropHandle<Handle, bool> prop(idx);
return convert_to_python(Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<int>*>(base_prop)) {
HandleToPropHandle<Handle, int> prop(idx);
return convert_to_python(Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<float>*>(base_prop)) {
HandleToPropHandle<Handle, float> prop(idx);
return convert_to_python(Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<double>*>(base_prop)) {
HandleToPropHandle<Handle, double> prop(idx);
return convert_to_python(Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec2f>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec2f> prop(idx);
return vec2numpy(*this, Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec3f>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec3f> prop(idx);
return vec2numpy(*this, Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec4f>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec4f> prop(idx);
return vec2numpy(*this, Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec2d>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec2d> prop(idx);
return vec2numpy(*this, Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec3d>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec3d> prop(idx);
return vec2numpy(*this, Mesh::property(prop, _h));
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec4d>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec4d> prop(idx);
return vec2numpy(*this, Mesh::property(prop, _h));
}
else {
PyErr_SetString(PyExc_RuntimeError, "Unsupported C++ property type.");
throw py::error_already_set();
}
}
else {
// there is no property with the given name
const auto prop = py_prop_on_demand<Handle, HandleToPropHandle<Handle, py::none>>(_name);
return Mesh::property(prop, _h);
}
#endif
}
template <class Handle>
......@@ -73,14 +135,45 @@ public:
HandleToPropHandle<Handle, py::none> prop(idx);
Mesh::property(prop, _h) = _val;
}
else if (dynamic_cast<OpenMesh::PropertyT<bool>*>(base_prop)) {
HandleToPropHandle<Handle, bool> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<bool>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<int>*>(base_prop)) {
HandleToPropHandle<Handle, int> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<int>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<float>*>(base_prop)) {
HandleToPropHandle<Handle, float> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<float>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<double>*>(base_prop)) {
HandleToPropHandle<Handle, double> prop(idx);
Mesh::property(prop, _h) = py::cast<double>(_val);
Mesh::property(prop, _h) = convert_to_cpp<double>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec2f>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec2f> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<OpenMesh::Vec2f>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec3f>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec3f> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<OpenMesh::Vec3f>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec4f>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec4f> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<OpenMesh::Vec4f>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec2d>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec2d> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<OpenMesh::Vec2d>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec3d>*>(base_prop)) {
py::array_t<double> arr(_val);
HandleToPropHandle<Handle, OpenMesh::Vec3d> prop(idx);
Mesh::property(prop, _h) = OpenMesh::Vec3d(arr.at(0), arr.at(1), arr.at(2));
Mesh::property(prop, _h) = convert_to_cpp<OpenMesh::Vec3d>(_val);
}
else if (dynamic_cast<OpenMesh::PropertyT<OpenMesh::Vec4d>*>(base_prop)) {
HandleToPropHandle<Handle, OpenMesh::Vec4d> prop(idx);
Mesh::property(prop, _h) = convert_to_cpp<OpenMesh::Vec4d>(_val);
}
else {
PyErr_SetString(PyExc_RuntimeError, "Unsupported C++ property type.");
......@@ -269,12 +362,44 @@ public:
PyErr_SetString(PyExc_RuntimeError, "A property with the given name already exists.");
throw py::error_already_set();
}
if (_type == "double") {
if (_type == "bool") {
HandleToPropHandle<Handle, bool> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "int") {
HandleToPropHandle<Handle, int> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "float") {
HandleToPropHandle<Handle, float> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "double") {
HandleToPropHandle<Handle, double> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "vec2f") {
HandleToPropHandle<Handle, OpenMesh::Vec2f> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "vec3f") {
HandleToPropHandle<Handle, OpenMesh::Vec3f> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "vec4f") {
HandleToPropHandle<Handle, OpenMesh::Vec4f> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "vec2d") {
HandleToPropHandle<Handle, OpenMesh::Vec2d> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "vec3d") {
HandleToPropHandle<Handle, double> prop;
HandleToPropHandle<Handle, OpenMesh::Vec3d> prop;
Mesh::add_property(prop, _name);
}
else if (_type == "vec4d") {
HandleToPropHandle<Handle, OpenMesh::Vec4d> prop;
Mesh::add_property(prop, _name);
}
else {
......@@ -361,8 +486,12 @@ private:
template <class Handle, class PropHandle>
PropHandle py_prop_on_demand(const std::string& _name) {
PropHandle result;
if (!py_get_property_handle<Handle>(result, _name))
if (py_has_property<Handle>(_name)) {
py_get_property_handle<Handle>(result, _name);
}
else {
Mesh::add_property(result, _name);
}
return result;
}
......
#ifndef OPENMESH_PYTHON_TYPECONVERSIONS_HH
#define OPENMESH_PYTHON_TYPECONVERSIONS_HH
#include <OpenMesh/Core/Geometry/VectorT.hh>
#include <pybind11/pybind11.h>
namespace py = pybind11;
namespace OpenMeshPython {
template<class dtype, int n>
OpenMesh::VectorT<dtype, n> convert_to_vector(py::object _obj) {
py::array_t<dtype> arr(_obj);
if (arr.size() != n) {
std::stringstream msg;
msg << "could not convert array with size " << arr.size();
msg << " to " << n << "-dimensional vector";
PyErr_SetString(PyExc_ValueError, msg.str().c_str());
throw py::error_already_set();
}
return OpenMesh::VectorT<dtype, n>(arr.data());
}
template<class T>
T convert_to_cpp(py::object _obj) {
return _obj.cast<T>();
}
template<>
inline OpenMesh::VectorT<float, 2> convert_to_cpp(py::object _obj) {
return convert_to_vector<float, 2>(_obj);
}
template<>
inline OpenMesh::VectorT<float, 3> convert_to_cpp(py::object _obj) {
return convert_to_vector<float, 3>(_obj);
}
template<>
inline OpenMesh::VectorT<float, 4> convert_to_cpp(py::object _obj) {
return convert_to_vector<float, 4>(_obj);
}
template<>
inline OpenMesh::VectorT<double, 2> convert_to_cpp(py::object _obj) {
return convert_to_vector<double, 2>(_obj);
}
template<>
inline OpenMesh::VectorT<double, 3> convert_to_cpp(py::object _obj) {
return convert_to_vector<double, 3>(_obj);
}
template<>
inline OpenMesh::VectorT<double, 4> convert_to_cpp(py::object _obj) {
return convert_to_vector<double, 4>(_obj);
}
inline py::object convert_to_python(bool _val) {
return py::bool_(_val);
}
inline py::object convert_to_python(int _val) {
return py::int_(_val);
}
inline py::object convert_to_python(float _val) {
return py::float_(_val);
}
inline py::object convert_to_python(double _val) {
return py::float_(_val);
}
/**
* Converts OpenMesh vectors to numpy arrays.
*
* The returned array contains a copy of the vector's underlying data.
*
* @tparam vector A Vector type.
* @param _vec The vector to be converted.
*/
template<class Vector>
inline py::array_t<typename Vector::value_type> vec2numpy(const Vector& _vec) {
typedef typename Vector::value_type dtype;
dtype *data = new dtype[_vec.size()];
std::copy_n(_vec.data(), _vec.size(), data);
py::capsule base = free_when_done(data);
return py::array_t<dtype>({_vec.size()}, {sizeof(dtype)}, data, base);
}
/**
* Converts OpenMesh vectors to numpy arrays.
*
* The returned array references the vector's underlying data, i.e. changes
* made to the returned array affect the original mesh.
*
* @tparam Mesh A Mesh type.
* @tparam vector A Vector type.
*
* @param _mesh The mesh that owns the vector's underlying memory. In order
* to avaoid dangling pointers, the lifetime of this mesh is tied to the
* lifetime of the returned numpy array.
* @param _vec The vector to be converted.
*/
template<class Mesh, class Vector>
inline py::array_t<typename Vector::value_type> vec2numpy(Mesh& _mesh, Vector& _vec, size_t _n = 1) {
typedef typename Vector::value_type dtype;
std::vector<size_t> shape;
std::vector<size_t> strides;
if (_n == 1) {
shape = {_vec.size()};
strides = {sizeof(dtype)};
}
else {
shape = {_n, _vec.size()};
strides = {_vec.size() * sizeof(dtype), sizeof(dtype)};
}
return py::array_t<dtype>(shape, strides, _vec.data(), py::cast(_mesh));
}
template<class Mesh>
inline py::array_t<float> flt2numpy(Mesh& _mesh, const float& _flt, size_t _n = 1) {
return py::array_t<float>({_n}, {sizeof(float)}, &_flt, py::cast(_mesh));
}
template<class Mesh>
inline py::array_t<double> flt2numpy(Mesh& _mesh, const double& _flt, size_t _n = 1) {
return py::array_t<double>({_n}, {sizeof(double)}, &_flt, py::cast(_mesh));
}
} // namespace OpenMeshPython
#endif
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