...
 
Commits (4)
if (NOT DISABLE_OPENFLIPPER_PYTHON_SYSTEM)
include(plugin)
openflipper_plugin(PYTHONINTERFACE TYPES POLYMESH TRIANGLEMESH)
endif()
#include <pybind11/include/pybind11/pybind11.h>
#include <pybind11/include/pybind11/embed.h>
#include <iostream>
#include <OpenMeshPythonPlugin.hh>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
#include <OpenFlipper/BasePlugin/PythonFunctions.hh>
#include <OpenFlipper/PythonInterpreter/PythonTypeConversions.hh>
#include <OpenFlipper/common/Types.hh>
#include <ObjectTypes/PolyMesh/PolyMesh.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
#include "PythonInterface/MeshTypes.hh"
namespace py = pybind11;
py::object get_mesh(int _id) {
TriMesh* trimesh = nullptr;
PolyMesh* polymesh = nullptr;
if (PluginFunctions::getMesh(_id, trimesh)) {
return py::cast(static_cast<OpenMeshPython::TriMesh*>(trimesh));
}
else if (PluginFunctions::getMesh(_id, polymesh)) {
return py::cast(static_cast<OpenMeshPython::PolyMesh*>(polymesh));
}
else {
std::stringstream msg;
msg << "object with id " << _id << " is not a mesh";
PyErr_SetString(PyExc_RuntimeError, msg.str().c_str());
throw py::error_already_set();
}
}
void init_plugin(py::module m) {
QObject* pluginPointer = getPluginPointer("OpenMeshPython");
if (!pluginPointer) {
std::cerr << "Error Getting plugin pointer for Plugin-OpenMeshPython" << std::endl;
return;
}
OpenMeshPythonPlugin* plugin = qobject_cast<OpenMeshPythonPlugin*>(pluginPointer);
if (!plugin) {
std::cerr << "Error converting plugin pointer for Plugin-OpenMeshPython" << std::endl;
return;
}
// Export our core. Make sure that the c++ worlds core object is not deleted if
// the python side gets deleted!!
py::class_< OpenMeshPythonPlugin,std::unique_ptr<OpenMeshPythonPlugin, py::nodelete> > openMeshPython(m, "OpenMeshPython");
// On the c++ side we will just return the existing core instance
// and prevent the system to recreate a new core as we need
// to work on the existing one.
openMeshPython.def(py::init([plugin]() { return plugin; }));
m.def("getMesh", &get_mesh);
m.def("getMesh", [](const std::string& _name) -> py::object {
using namespace PluginFunctions;
DataType MESH_TYPES = DATA_TRIANGLE_MESH | DATA_POLY_MESH;
for (ObjectIterator o_it(ALL_OBJECTS, MESH_TYPES); o_it != objectsEnd(); ++o_it) {
if (o_it->name() == QString::fromStdString(_name)) {
return get_mesh(o_it->id());
}
}
std::stringstream msg;
msg << "there is no mesh with name \"" << _name << "\"";
PyErr_SetString(PyExc_RuntimeError, msg.str().c_str());
throw py::error_already_set();
});
m.def("addMesh", [plugin](OpenMeshPython::TriMesh& _mesh, std::string _name) {
// make sure that all properties used by OpenFlipper
// are present and update the normals
_mesh.request_vertex_normals();
_mesh.request_halfedge_normals();
_mesh.request_face_normals();
_mesh.update_normals();
_mesh.request_vertex_status();
_mesh.request_halfedge_status();
_mesh.request_edge_status();
_mesh.request_face_status();
int newObjectId = -1;
plugin->addEmptyObject(DATA_TRIANGLE_MESH, newObjectId);
TriMeshObject* object = nullptr;
PluginFunctions::getObject(newObjectId, object);
if (object && object->mesh()) {
TriMesh* mesh = object->mesh();
*mesh = _mesh;
if (_name != "")
object->setName(QString::fromStdString(_name));
plugin->updatedObject(object->id(), UPDATE_ALL);
return object->id();
}
else {
PyErr_SetString(PyExc_RuntimeError, "could not create new object");
throw py::error_already_set();
}
}, py::arg("mesh"), py::arg("name") = "");
}
#include "OpenMeshPythonPlugin.hh"
#ifndef OPENMESHPYTHONPLUGIN_HH_INCLUDED
#define OPENMESHPYTHONPLUGIN_HH_INCLUDED
#include <OpenFlipper/BasePlugin/BaseInterface.hh>
#include <OpenFlipper/BasePlugin/LoadSaveInterface.hh>
#include <OpenFlipper/BasePlugin/PythonInterface.hh>
class OpenMeshPythonPlugin : public QObject, BaseInterface, LoadSaveInterface, PythonInterface
{
Q_OBJECT
Q_INTERFACES(BaseInterface)
Q_INTERFACES(LoadSaveInterface)
Q_INTERFACES(PythonInterface)
Q_PLUGIN_METADATA(IID "org.OpenFlipper.Plugins.Plugin-OpenMeshPython")
signals:
void updatedObject(int _identifier, const UpdateType & _type);
void addEmptyObject(DataType _type, int& _id);
public:
~OpenMeshPythonPlugin() {}
QString name() { return QString("OpenMeshPython"); }
QString description() { return QString("OpenMesh Python Bindings for OpenFlipper"); }
public slots:
QString version() { return QString("1.0"); }
private slots:
void noguiSupported() {}
};
#endif
#include "MeshTypes.hh"
#include "Miscellaneous.hh"
#include "Mesh.hh"
#include "Iterator.hh"
#include "Circulator.hh"
#include "InputOutput.hh"
#include "Decimater.hh"
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#ifdef OPENMESH_PYTHON_EMBEDDED_MODULE
#include "InitPlugin.hh"
#endif
namespace py = pybind11;
namespace OM = OpenMesh;
namespace OpenMeshPython {
#ifdef OPENMESH_PYTHON_EMBEDDED_MODULE
PYBIND11_EMBEDDED_MODULE(OpenMeshPython, m) {
init_plugin(m);
#else
PYBIND11_MODULE(openmesh, m) {
#endif
expose_handles(m);
expose_mesh<PolyMesh>(m, "PolyMesh");
expose_mesh<TriMesh>(m, "TriMesh");
expose_iterator<OM::PolyConnectivity::VertexIter, &OM::ArrayKernel::n_vertices>(m, "VertexIter");
expose_iterator<OM::PolyConnectivity::HalfedgeIter, &OM::ArrayKernel::n_halfedges>(m, "HalfedgeIter");
expose_iterator<OM::PolyConnectivity::EdgeIter, &OM::ArrayKernel::n_edges>(m, "EdgeIter");
expose_iterator<OM::PolyConnectivity::FaceIter, &OM::ArrayKernel::n_faces>(m, "FaceIter");
expose_circulator<OM::PolyConnectivity::VertexVertexIter, OM::VertexHandle>(m, "VertexVertexIter");
expose_circulator<OM::PolyConnectivity::VertexIHalfedgeIter, OM::VertexHandle>(m, "VertexIHalfedgeIter");
expose_circulator<OM::PolyConnectivity::VertexOHalfedgeIter, OM::VertexHandle>(m, "VertexOHalfedgeIter");
expose_circulator<OM::PolyConnectivity::VertexEdgeIter, OM::VertexHandle>(m, "VertexEdgeIter");
expose_circulator<OM::PolyConnectivity::VertexFaceIter, OM::VertexHandle>(m, "VertexFaceIter");
expose_circulator<OM::PolyConnectivity::FaceVertexIter, OM::FaceHandle>(m, "FaceVertexIter");
expose_circulator<OM::PolyConnectivity::FaceHalfedgeIter, OM::FaceHandle>(m, "FaceHalfedgeIter");
expose_circulator<OM::PolyConnectivity::FaceEdgeIter, OM::FaceHandle>(m, "FaceEdgeIter");
expose_circulator<OM::PolyConnectivity::FaceFaceIter, OM::FaceHandle>(m, "FaceFaceIter");
expose_circulator<OM::PolyConnectivity::HalfedgeLoopIter, OM::HalfedgeHandle>(m, "HalfedgeLoopIter");
expose_io(m);
expose_decimater<PolyMesh>(m, "PolyMesh");
expose_decimater<TriMesh>(m, "TriMesh");
}
} // namespace OpenMeshPython
#ifndef OPENMESH_PYTHON_CIRCULATOR_HH
#define OPENMESH_PYTHON_CIRCULATOR_HH
#include "MeshTypes.hh"
#include <pybind11/pybind11.h>
namespace py = pybind11;
namespace OpenMeshPython {
/**
* Wrapper for circulators.
*
* This class template is used to wrap circulators for %Python. It implements
* %Python's iterator protocol (the magic methods \_\_iter\_\_ and
* \_\_next\_\_).
*
* @tparam Circulator A circulator type.
*/
template<class Circulator, class CenterEntityHandle>
class CirculatorWrapperT {
public:
/**
* Constructor
*
* @param _mesh The mesh that contains the items to iterate over.
* @param _center The handle to the center item.
*/
CirculatorWrapperT(PolyMesh& _mesh, CenterEntityHandle _center) :
circulator_(_mesh, _center) {
}
/**
* Constructor
*
* @param _mesh The mesh that contains the items to iterate over.
* @param _center The handle to the center item.
*/
CirculatorWrapperT(TriMesh& _mesh, CenterEntityHandle _center) :
circulator_(_mesh, _center) {
}
/**
* Implementation of %Python's \_\_iter\_\_ magic method.
*
* @return This circulator.
*/
CirculatorWrapperT iter() const {
return *this;
}
/**
* Implementation of %Python's \_\_next\_\_ magic method.
*
* @return The next item. Raises a %Python StopIteration exception if
* there are no more items.
*/
typename Circulator::value_type next() {
if (circulator_.is_valid()) {
typename Circulator::value_type res = *circulator_;
++circulator_;
return res;
}
else {
throw py::stop_iteration();
}
return typename Circulator::value_type();
}
private:
Circulator circulator_;
};
/**
* Expose a circulator type to %Python.
*
* @tparam Circulator A circulator type.
*
* @param _name The name of the circulator type to be exposed.
*
* @note Circulators are wrapped by CirculatorWrapperT before they are exposed
* to %Python, i.e. they are not exposed directly. This means that circulators
* that are passed from %Python to C++ are instances of CirculatorWrapperT.
*/
template<class Circulator, class CenterEntityHandle>
void expose_circulator(py::module& m, const char *_name) {
py::class_<CirculatorWrapperT<Circulator, CenterEntityHandle> >(m, _name)
.def(py::init<TriMesh&, CenterEntityHandle>())
.def(py::init<PolyMesh&, CenterEntityHandle>())
.def("__iter__", &CirculatorWrapperT<Circulator, CenterEntityHandle>::iter)
.def("__next__", &CirculatorWrapperT<Circulator, CenterEntityHandle>::next)
;
}
} // namespace OpenMeshPython
#endif
#ifndef OPENMESH_PYTHON_DECIMATER_HH
#define OPENMESH_PYTHON_DECIMATER_HH
#include "MeshTypes.hh"
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
#include <OpenMesh/Tools/Decimater/ModAspectRatioT.hh>
#include <OpenMesh/Tools/Decimater/ModEdgeLengthT.hh>
#include <OpenMesh/Tools/Decimater/ModHausdorffT.hh>
#include <OpenMesh/Tools/Decimater/ModIndependentSetsT.hh>
#include <OpenMesh/Tools/Decimater/ModNormalDeviationT.hh>
#include <OpenMesh/Tools/Decimater/ModNormalFlippingT.hh>
#include <OpenMesh/Tools/Decimater/ModProgMeshT.hh>
#include <OpenMesh/Tools/Decimater/ModQuadricT.hh>
#include <OpenMesh/Tools/Decimater/ModRoundnessT.hh>
#include <OpenMesh/Tools/Decimater/DecimaterT.hh>
#include <cstdio>
#include <pybind11/pybind11.h>
namespace py = pybind11;
namespace OM = OpenMesh;
namespace OpenMeshPython {
template <class Handle>
void expose_module_handle(py::module& m, const char *_name) {
py::class_<Handle>(m, _name)
.def(py::init<>())
.def("is_valid", &Handle::is_valid)
;
}
template <class Module>
py::list infolist(Module& _self) {
const typename Module::InfoList& infos = _self.infolist();
py::list res;
for (size_t i = 0; i < infos.size(); ++i) {
res.append(infos[i]);
}
return res;
}
template <class Mesh>
void expose_decimater(py::module& m, const char *_name) {
typedef OM::Decimater::ModBaseT<Mesh> ModBase;
typedef OM::Decimater::ModAspectRatioT<Mesh> ModAspectRatio;
typedef OM::Decimater::ModEdgeLengthT<Mesh> ModEdgeLength;
typedef OM::Decimater::ModHausdorffT<Mesh> ModHausdorff;
typedef OM::Decimater::ModIndependentSetsT<Mesh> ModIndependentSets;
typedef OM::Decimater::ModNormalDeviationT<Mesh> ModNormalDeviation;
typedef OM::Decimater::ModNormalFlippingT<Mesh> ModNormalFlipping;
typedef OM::Decimater::ModProgMeshT<Mesh> ModProgMesh;
typedef OM::Decimater::ModQuadricT<Mesh> ModQuadric;
typedef OM::Decimater::ModRoundnessT<Mesh> ModRoundness;
typedef OM::Decimater::ModHandleT<ModAspectRatio> ModAspectRatioHandle;
typedef OM::Decimater::ModHandleT<ModEdgeLength> ModEdgeLengthHandle;
typedef OM::Decimater::ModHandleT<ModHausdorff> ModHausdorffHandle;
typedef OM::Decimater::ModHandleT<ModIndependentSets> ModIndependentSetsHandle;
typedef OM::Decimater::ModHandleT<ModNormalDeviation> ModNormalDeviationHandle;
typedef OM::Decimater::ModHandleT<ModNormalFlipping> ModNormalFlippingHandle;
typedef OM::Decimater::ModHandleT<ModProgMesh> ModProgMeshHandle;
typedef OM::Decimater::ModHandleT<ModQuadric> ModQuadricHandle;
typedef OM::Decimater::ModHandleT<ModRoundness> ModRoundnessHandle;
typedef OM::Decimater::BaseDecimaterT<Mesh> BaseDecimater;
typedef OM::Decimater::DecimaterT<Mesh> Decimater;
typedef typename ModProgMesh::Info Info;
typedef std::vector<Info> InfoList;
// Decimater
// ----------------------------------------
char buffer[64];
snprintf(buffer, sizeof buffer, "%s%s", _name, "Decimater");
py::class_<Decimater>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("decimate", &Decimater::decimate, py::arg("n_collapses")=0)
.def("decimate_to", &Decimater::decimate_to)
.def("decimate_to_faces", &Decimater::decimate_to_faces,
py::arg("n_vertices")=0, py::arg("n_faces")=0)
.def("initialize", [](Decimater& _self) { return _self.initialize(); })
.def("is_initialized", [](Decimater& _self) { return _self.is_initialized(); })
.def("add", [](Decimater& _self, ModAspectRatioHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModEdgeLengthHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModHausdorffHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModIndependentSetsHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModNormalDeviationHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModNormalFlippingHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModProgMeshHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModQuadricHandle& _mod) { return _self.add(_mod); })
.def("add", [](Decimater& _self, ModRoundnessHandle& _mod) { return _self.add(_mod); })
.def("remove", [](Decimater& _self, ModAspectRatioHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModEdgeLengthHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModHausdorffHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModIndependentSetsHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModNormalDeviationHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModNormalFlippingHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModProgMeshHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModQuadricHandle& _mod) { return _self.remove(_mod); })
.def("remove", [](Decimater& _self, ModRoundnessHandle& _mod) { return _self.remove(_mod); })
.def("module", [](Decimater& _self, ModAspectRatioHandle& _mod) -> ModAspectRatio& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModEdgeLengthHandle& _mod) -> ModEdgeLength& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModHausdorffHandle& _mod) -> ModHausdorff& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModIndependentSetsHandle& _mod) -> ModIndependentSets& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModNormalDeviationHandle& _mod) -> ModNormalDeviation& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModNormalFlippingHandle& _mod) -> ModNormalFlipping& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModProgMeshHandle& _mod) -> ModProgMesh& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModQuadricHandle& _mod) -> ModQuadric& { return _self.module(_mod); }, py::return_value_policy::reference)
.def("module", [](Decimater& _self, ModRoundnessHandle& _mod) -> ModRoundness& { return _self.module(_mod); }, py::return_value_policy::reference)
;
// ModBase
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModBase");
py::class_<ModBase>(m, buffer)
.def("name", &ModBase::name, py::return_value_policy::copy)
.def("is_binary", &ModBase::is_binary)
.def("set_binary", &ModBase::set_binary)
.def("initialize", &ModBase::initialize) // TODO VIRTUAL
.def("collapse_priority", &ModBase::collapse_priority) // TODO VIRTUAL
.def("preprocess_collapse", &ModBase::preprocess_collapse) // TODO VIRTUAL
.def("postprocess_collapse", &ModBase::postprocess_collapse) // TODO VIRTUAL
.def("set_error_tolerance_factor", &ModBase::set_error_tolerance_factor) // TODO VIRTUAL
;
// ModAspectRatio
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModAspectRatio");
py::class_<ModAspectRatio, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("aspect_ratio", &ModAspectRatio::aspect_ratio)
.def("set_aspect_ratio", &ModAspectRatio::set_aspect_ratio)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModAspectRatioHandle");
expose_module_handle<ModAspectRatioHandle>(m, buffer);
// ModEdgeLength
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModEdgeLength");
py::class_<ModEdgeLength, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("edge_length", &ModEdgeLength::edge_length)
.def("set_edge_length", &ModEdgeLength::set_edge_length)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModEdgeLengthHandle");
expose_module_handle<ModEdgeLengthHandle>(m, buffer);
// ModHausdorff
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModHausdorff");
py::class_<ModHausdorff, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("tolerance", &ModHausdorff::tolerance)
.def("set_tolerance", &ModHausdorff::set_tolerance)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModHausdorffHandle");
expose_module_handle<ModHausdorffHandle>(m, buffer);
// ModIndependentSets
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModIndependentSets");
py::class_<ModIndependentSets, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModIndependentSetsHandle");
expose_module_handle<ModIndependentSetsHandle>(m, buffer);
// ModNormalDeviation
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModNormalDeviation");
py::class_<ModNormalDeviation, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("normal_deviation", &ModNormalDeviation::normal_deviation)
.def("set_normal_deviation", &ModNormalDeviation::set_normal_deviation)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModNormalDeviationHandle");
expose_module_handle<ModNormalDeviationHandle>(m, buffer);
// ModNormalFlipping
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModNormalFlipping");
py::class_<ModNormalFlipping, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("max_normal_deviation", &ModNormalFlipping::max_normal_deviation)
.def("set_max_normal_deviation", &ModNormalFlipping::set_max_normal_deviation)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModNormalFlippingHandle");
expose_module_handle<ModNormalFlippingHandle>(m, buffer);
// ModProgMesh
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModProgMeshInfo");
py::class_<Info>(m, buffer)
.def_readwrite("v0", &Info::v0)
.def_readwrite("v1", &Info::v1)
.def_readwrite("vl", &Info::vl)
.def_readwrite("vr", &Info::vr)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModProgMesh");
py::class_<ModProgMesh, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("pmi", &infolist<ModProgMesh>)
.def("infolist", &infolist<ModProgMesh>)
.def("write", &ModProgMesh::write)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModProgMeshHandle");
expose_module_handle<ModProgMeshHandle>(m, buffer);
// ModQuadric
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModQuadric");
py::class_<ModQuadric, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("set_max_err", &ModQuadric::set_max_err,
py::arg("err"), py::arg("binary")=true)
.def("unset_max_err", &ModQuadric::unset_max_err)
.def("max_err", &ModQuadric::max_err)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModQuadricHandle");
expose_module_handle<ModQuadricHandle>(m, buffer);
// ModRoundness
// ----------------------------------------
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModRoundness");
py::class_<ModRoundness, ModBase>(m, buffer)
.def(py::init<Mesh&>(), py::keep_alive<1,2>())
.def("set_min_angle", &ModRoundness::set_min_angle)
.def("set_min_roundness", &ModRoundness::set_min_roundness,
py::arg("min_roundness"), py::arg("binary")=true)
.def("unset_min_roundness", &ModRoundness::unset_min_roundness)
.def("roundness", &ModRoundness::roundness)
;
snprintf(buffer, sizeof buffer, "%s%s", _name, "ModRoundnessHandle");
expose_module_handle<ModRoundnessHandle>(m, buffer);
}
} // namespace OpenMeshPython
#endif
#include "InputOutput.hh"
#include "MeshTypes.hh"
#include <pybind11/operators.h>
namespace OM = OpenMesh;
namespace OpenMeshPython {
template <class Mesh>
void def_read_mesh(py::module& m, const char *_name) {
m.def(_name,
[](
const std::string& _filename,
bool _binary,
bool _msb,
bool _lsb,
bool _swap,
bool _vertex_normal,
bool _vertex_color,
bool _vertex_tex_coord,
bool _halfedge_tex_coord,
bool _edge_color,
bool _face_normal,
bool _face_color,
bool _face_texture_index,
bool _color_alpha,
bool _color_float
)
{
Mesh mesh;
OM::IO::Options options;
if (_binary) options += OM::IO::Options::Binary;
if (_msb) options += OM::IO::Options::MSB;
if (_lsb) options += OM::IO::Options::LSB;
if (_swap) options += OM::IO::Options::Swap;
if (_vertex_normal) {
options += OM::IO::Options::VertexNormal;
mesh.request_vertex_normals();
}
if (_vertex_color) {
options += OM::IO::Options::VertexColor;
mesh.request_vertex_colors();
}
if (_vertex_tex_coord) {
options += OM::IO::Options::VertexTexCoord;
mesh.request_vertex_texcoords1D();
mesh.request_vertex_texcoords2D();
mesh.request_vertex_texcoords3D();
}
if (_halfedge_tex_coord) {
options += OM::IO::Options::FaceTexCoord;
mesh.request_halfedge_texcoords1D();
mesh.request_halfedge_texcoords2D();
mesh.request_halfedge_texcoords3D();
}
if (_edge_color) {
options += OM::IO::Options::EdgeColor;
mesh.request_edge_colors();
}
if (_face_normal) {
options += OM::IO::Options::FaceNormal;
mesh.request_face_normals();
}
if (_face_color) {
options += OM::IO::Options::FaceColor;
mesh.request_face_colors();
}
if (_face_texture_index) {
mesh.request_face_texture_index();
}
if (_color_alpha) options += OM::IO::Options::ColorAlpha;
if (_color_float) options += OM::IO::Options::ColorFloat;
const bool ok = OM::IO::read_mesh(mesh, _filename, options);
if (!ok) {
const std::string msg = "File could not be read: " + _filename;
PyErr_SetString(PyExc_RuntimeError, msg.c_str());
throw py::error_already_set();
}
if (_vertex_normal && !options.vertex_has_normal()) {
PyErr_SetString(PyExc_RuntimeError, "Vertex normals could not be read.");
throw py::error_already_set();
}
if (_vertex_color && !options.vertex_has_color()) {
PyErr_SetString(PyExc_RuntimeError, "Vertex colors could not be read.");
throw py::error_already_set();
}
if (_vertex_tex_coord && !options.vertex_has_texcoord()) {
PyErr_SetString(PyExc_RuntimeError, "Vertex texcoords could not be read.");
throw py::error_already_set();
}
if (_edge_color && !options.edge_has_color()) {
PyErr_SetString(PyExc_RuntimeError, "Edge colors could not be read.");
throw py::error_already_set();
}
if (_face_normal && !options.face_has_normal()) {
PyErr_SetString(PyExc_RuntimeError, "Face normals could not be read.");
throw py::error_already_set();
}
if (_face_color && !options.face_has_color()) {
PyErr_SetString(PyExc_RuntimeError, "Face colors could not be read.");
throw py::error_already_set();
}
if (_halfedge_tex_coord && !options.face_has_texcoord()) {
PyErr_SetString(PyExc_RuntimeError, "Halfedge texcoords could not be read.");
throw py::error_already_set();
}
return mesh;
},
py::arg("filename"),
py::arg("binary")=false,
py::arg("msb")=false,
py::arg("lsb")=false,
py::arg("swap")=false,
py::arg("vertex_normal")=false,
py::arg("vertex_color")=false,
py::arg("vertex_tex_coord")=false,
py::arg("halfedge_tex_coord")=false,
py::arg("edge_color")=false,
py::arg("face_normal")=false,
py::arg("face_color")=false,
py::arg("face_texture_index")=false,
py::arg("color_alpha")=false,
py::arg("color_float")=false
);
}
template <class Mesh>
void def_write_mesh(py::module& m) {
m.def("write_mesh",
[](
const std::string& _filename,
const Mesh& _mesh,
bool _binary,
bool _msb,
bool _lsb,
bool _swap,
bool _vertex_normal,
bool _vertex_color,
bool _vertex_tex_coord,
bool _halfedge_tex_coord,
bool _edge_color,
bool _face_normal,
bool _face_color,
bool _color_alpha,
bool _color_float
)
{
OM::IO::Options options;
if (_binary) options += OM::IO::Options::Binary;
if (_msb) options += OM::IO::Options::MSB;
if (_lsb) options += OM::IO::Options::LSB;
if (_swap) options += OM::IO::Options::Swap;
if (_vertex_normal) options += OM::IO::Options::VertexNormal;
if (_vertex_color) options += OM::IO::Options::VertexColor;
if (_vertex_tex_coord) options += OM::IO::Options::VertexTexCoord;
if (_halfedge_tex_coord) options += OM::IO::Options::FaceTexCoord;
if (_edge_color) options += OM::IO::Options::EdgeColor;
if (_face_normal) options += OM::IO::Options::FaceNormal;
if (_face_color) options += OM::IO::Options::FaceColor;
if (_color_alpha) options += OM::IO::Options::ColorAlpha;
if (_color_float) options += OM::IO::Options::ColorFloat;
const bool ok = OM::IO::write_mesh(_mesh, _filename, options);
if (!ok) {
const std::string msg = "File could not be written: " + _filename;
PyErr_SetString(PyExc_RuntimeError, msg.c_str());
throw py::error_already_set();
}
},
py::arg("filename"),
py::arg("mesh"),
py::arg("binary")=false,
py::arg("msb")=false,
py::arg("lsb")=false,
py::arg("swap")=false,
py::arg("vertex_normal")=false,
py::arg("vertex_color")=false,
py::arg("vertex_tex_coord")=false,
py::arg("halfedge_tex_coord")=false,
py::arg("edge_color")=false,
py::arg("face_normal")=false,
py::arg("face_color")=false,
py::arg("color_alpha")=false,
py::arg("color_float")=false
);
}
void expose_io(py::module& m) {
def_read_mesh<TriMesh>(m, "read_trimesh");
def_read_mesh<PolyMesh>(m, "read_polymesh");
def_write_mesh<TriMesh>(m);
def_write_mesh<PolyMesh>(m);
}
} // namespace OpenMeshPython
#ifndef OPENMESH_PYTHON_INPUTOUTPUT_HH
#define OPENMESH_PYTHON_INPUTOUTPUT_HH
#include <pybind11/pybind11.h>
namespace py = pybind11;
namespace OpenMeshPython {
void expose_io(py::module& m);
} // namespace OpenMeshPython
#endif
#ifndef OPENMESH_PYTHON_ITERATOR_HH
#define OPENMESH_PYTHON_ITERATOR_HH
#include "MeshTypes.hh"
#include <pybind11/pybind11.h>
namespace py = pybind11;
namespace OpenMeshPython {
/**
* Wrapper for mesh item iterators.
*
* This class template is used to wrap mesh item iterators for %Python. It
* implements %Python's iterator protocol (the magic methods \_\_iter\_\_ and
* \_\_next\_\_).
*
* @tparam Iterator An iterator type.
* @tparam n_items A member function pointer that points to the mesh function
* that returns the number of items to iterate over (e.g. n_vertices).
*/
template<class Iterator, size_t (OpenMesh::ArrayKernel::*n_items)() const>
class IteratorWrapperT {
public:
/**
* Constructor
*
* @param _mesh The mesh that contains the items to iterate over.
* @param _hnd The handle of the first item to iterate over.
* @param _skip Specifies if deleted/hidden elements are skipped.
*/
IteratorWrapperT(const PolyMesh& _mesh, typename Iterator::value_type _hnd, bool _skip = false) :
mesh_(_mesh), n_items_(n_items),
iterator_(_mesh, _hnd, _skip),
iterator_end_(_mesh, typename Iterator::value_type(int((_mesh.*n_items)()))) {
}
/**
* Constructor
*
* @param _mesh The mesh that contains the items to iterate over.
* @param _hnd The handle of the first item to iterate over.
* @param _skip Specifies if deleted/hidden elements are skipped.
*/
IteratorWrapperT(const TriMesh& _mesh, typename Iterator::value_type _hnd, bool _skip = false) :
mesh_(_mesh), n_items_(n_items),
iterator_(_mesh, _hnd, _skip),
iterator_end_(_mesh, typename Iterator::value_type(int((_mesh.*n_items)()))) {
}
/**
* Implementation of %Python's \_\_iter\_\_ magic method.
*
* @return This iterator.
*/
IteratorWrapperT iter() const {
return *this;
}
/**
* Implementation of %Python's \_\_next\_\_ magic method.
*
* @return The next item. Raises a %Python StopIteration exception if
* there are no more items.
*/
typename Iterator::value_type next() {
if (iterator_ != iterator_end_) {
typename Iterator::value_type res = *iterator_;
++iterator_;
return res;
}
else {
throw py::stop_iteration();
}
return typename Iterator::value_type();
}
/**
* Implementation of %Python's \_\_len\_\_ magic method.
*
* @return The number of items in the mesh.
*/
unsigned int len() const {
return (mesh_.*n_items_)();
}
private:
const OpenMesh::PolyConnectivity& mesh_;
size_t (OpenMesh::ArrayKernel::*n_items_)() const;
Iterator iterator_;
Iterator iterator_end_;
};
/**
* Expose an iterator type to %Python.
*
* @tparam Iterator An iterator type.
* @tparam n_items A member function pointer that points to the mesh function
* that returns the number of items to iterate over (e.g. n_vertices).
*
* @param _name The name of the iterator type to be exposed.
*
* @note %Iterators are wrapped by IteratorWrapperT before they are exposed to
* %Python, i.e. they are not exposed directly. This means that iterators
* that are passed from %Python to C++ are instances of IteratorWrapperT.
*/
template<class Iterator, size_t (OpenMesh::ArrayKernel::*n_items)() const>
void expose_iterator(py::module& m, const char *_name) {
py::class_<IteratorWrapperT<Iterator, n_items> >(m, _name)
.def(py::init<PolyMesh&, typename Iterator::value_type>())
.def(py::init<PolyMesh&, typename Iterator::value_type, bool>())
.def(py::init<TriMesh&, typename Iterator::value_type>())
.def(py::init<TriMesh&, typename Iterator::value_type, bool>())
.def("__iter__", &IteratorWrapperT<Iterator, n_items>::iter)
.def("__next__", &IteratorWrapperT<Iterator, n_items>::next)
.def("__len__", &IteratorWrapperT<Iterator, n_items>::len)
;
}
} // namespace OpenMeshPython
#endif
#ifndef OPENMESH_PYTHON_MESH_HH
#define OPENMESH_PYTHON_MESH_HH
#include "Utilities.hh"
#include "TypeConversions.hh"
#include "MeshTypes.hh"
#include "Iterator.hh"
#include "Circulator.hh"
#include <algorithm>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
namespace py = pybind11;
namespace OM = OpenMesh;
namespace OpenMeshPython {
/**
* Thin wrapper for assign_connectivity.
*
* @tparam Mesh A mesh type.
* @tparam OtherMesh A mesh type.
*
* @param _self The mesh instance that is to be used.
* @param _other The mesh from which the connectivity is to be copied.
*/
template <class Mesh, class OtherMesh>
void assign_connectivity(Mesh& _self, const OtherMesh& _other) {
_self.assign_connectivity(_other);
}
/**
* Get an iterator.
*/
template <class Mesh, class Iterator, size_t (OM::ArrayKernel::*n_items)() const>
IteratorWrapperT<Iterator, n_items> get_iterator(Mesh& _self) {
return IteratorWrapperT<Iterator, n_items>(_self, typename Iterator::value_type(0));
}
/**
* Get a skipping iterator.
*/
template <class Mesh, class Iterator, size_t (OM::ArrayKernel::*n_items)() const>
IteratorWrapperT<Iterator, n_items> get_skipping_iterator(Mesh& _self) {
return IteratorWrapperT<Iterator, n_items>(_self, typename Iterator::value_type(0), true);
}
/**
* Get a circulator.
*
* @tparam Mesh A Mesh type.
* @tparam Circulator A circulator type.
* @tparam CenterEntityHandle The appropriate handle type.
*
* @param _self The mesh instance that is to be used.
* @param _handle The handle of the item to circulate around.
*/
template <class Mesh, class Circulator, class CenterEntityHandle>
CirculatorWrapperT<Circulator, CenterEntityHandle> get_circulator(Mesh& _self, CenterEntityHandle _handle) {
return CirculatorWrapperT<Circulator, CenterEntityHandle>(_self, _handle);
}
/**
* Garbage collection using lists instead of vectors to keep track of a set of
* handles.
*
* @tparam Mesh A Mesh type.
*
* @param _self The mesh instance that is to be used.
* @param _vh_to_update The list of vertex handles to be updated.
* @param _hh_to_update The list of halfedge handles to be updated.
* @param _fh_to_update The list of face handles to be updated.
* @param _v Remove deleted vertices?
* @param _e Remove deleted edges?
* @param _f Remove deleted faces?
*/
template <class Mesh>
void garbage_collection(Mesh& _self, py::list& _vh_to_update, py::list& _hh_to_update, py::list& _fh_to_update, bool _v = true, bool _e = true, bool _f = true) {
// Convert list of handles to vector of pointers
std::vector<OM::VertexHandle*> vh_vector;
for (auto item : _vh_to_update) {
if (py::isinstance<OM::VertexHandle>(item)) {
vh_vector.push_back(item.cast<OM::VertexHandle*>());
}
}
// Convert list of handles to vector of pointers
std::vector<OM::HalfedgeHandle*> hh_vector;
for (auto item : _hh_to_update) {
if (py::isinstance<OM::HalfedgeHandle>(item)) {
hh_vector.push_back(item.cast<OM::HalfedgeHandle*>());
}
}
// Convert list of handles to vector of pointers
std::vector<OM::FaceHandle*> fh_vector;
for (auto item : _fh_to_update) {
if (py::isinstance<OM::FaceHandle>(item)) {
fh_vector.push_back(item.cast<OM::FaceHandle*>());
}
}
// Call garbage collection
_self.garbage_collection(vh_vector, hh_vector, fh_vector, _v, _e, _f);
}
py::array_t<int> face_vertex_indices_trimesh(TriMesh& _self) {
if (_self.n_faces() == 0) {
return py::array_t<int>();
}
const bool has_status = _self.has_face_status();
int *indices = new int[_self.n_faces() * 3];
py::capsule base = free_when_done(indices);
for (auto fh : _self.all_faces()) {
if (has_status && _self.status(fh).deleted()) {
PyErr_SetString(PyExc_RuntimeError, "Mesh has deleted items. Please call garbage_collection() first.");
throw py::error_already_set();
}
auto fv_it = _self.fv_iter(fh);
indices[fh.idx() * 3 + 0] = fv_it->idx(); ++fv_it;
indices[fh.idx() * 3 + 1] = fv_it->idx(); ++fv_it;
indices[fh.idx() * 3 + 2] = fv_it->idx();
}
const auto shape = {_self.n_faces(), size_t(3)};
const auto strides = {3 * sizeof(int), sizeof(int)};
return py::array_t<int>(shape, strides, indices, base);
}
struct FuncEdgeVertex {
static void call(const OM::ArrayKernel& _mesh, OM::EdgeHandle _eh, int *_ptr) {
const auto heh = _mesh.halfedge_handle(_eh, 0);
_ptr[0] = _mesh.from_vertex_handle(heh).idx();
_ptr[1] = _mesh.to_vertex_handle(heh).idx();
}
};
struct FuncEdgeFace {
static void call(const OM::ArrayKernel& _mesh, OM::EdgeHandle _eh, int *_ptr) {
const auto heh1 = _mesh.halfedge_handle(_eh, 0);
const auto heh2 = _mesh.halfedge_handle(_eh, 1);
_ptr[0] = _mesh.face_handle(heh1).idx();
_ptr[1] = _mesh.face_handle(heh2).idx();
}
};
struct FuncEdgeHalfedge {
static void call(const OM::ArrayKernel& _mesh, OM::EdgeHandle _eh, int *_ptr) {
_ptr[0] = _mesh.halfedge_handle(_eh, 0).idx();
_ptr[1] = _mesh.halfedge_handle(_eh, 1).idx();
}
};
struct FuncHalfedgeToVertex {
static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
*_ptr = _mesh.to_vertex_handle(_heh).idx();
}
static size_t dim() { return 1; }
};
struct FuncHalfedgeFromVertex {
static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
*_ptr = _mesh.from_vertex_handle(_heh).idx();
}
static size_t dim() { return 1; }
};
struct FuncHalfedgeFace {
static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
*_ptr = _mesh.face_handle(_heh).idx();
}
static size_t dim() { return 1; }
};
struct FuncHalfedgeEdge {
static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
*_ptr = _mesh.edge_handle(_heh).idx();
}
static size_t dim() { return 1; }
};
struct FuncHalfedgeVertex {
static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
_ptr[0] = _mesh.from_vertex_handle(_heh).idx();
_ptr[1] = _mesh.to_vertex_handle(_heh).idx();
}
static size_t dim() { return 2; }
};
template <class Mesh, class CopyFunc>
py::array_t<int> edge_other_indices(Mesh& _self) {
if (_self.n_edges() == 0) {
return py::array_t<int>();
}
const bool has_status = _self.has_edge_status();
int *indices = new int[_self.n_edges() * 2];
py::capsule base = free_when_done(indices);
for (auto eh : _self.all_edges()) {
if (has_status && _self.status(eh).deleted()) {
PyErr_SetString(PyExc_RuntimeError, "Mesh has deleted items. Please call garbage_collection() first.");
throw py::error_already_set();
}
CopyFunc::call(_self, eh, &indices[eh.idx() * 2]);
}
const auto shape = {_self.n_edges(), size_t(2)};
const auto strides = {2 * sizeof(int), sizeof(int)};
return py::array_t<int>(shape, strides, indices, base);
}
template <class Mesh, class CopyFunc>
py::array_t<int> halfedge_other_indices(Mesh& _self) {
if (_self.n_halfedges() == 0) {
return py::array_t<int>();
}
const bool has_status = _self.has_halfedge_status();
const size_t dim = CopyFunc::dim();
int *indices = new int[_self.n_halfedges() * dim];
py::capsule base = free_when_done(indices);
for (auto heh : _self.all_halfedges()) {
if (has_status && _self.status(heh).deleted()) {
PyErr_SetString(PyExc_RuntimeError, "Mesh has deleted items. Please call garbage_collection() first.");
throw py::error_already_set();
}
CopyFunc::call(_self, heh, &indices[heh.idx() * dim]);
}
std::vector<size_t> shape;
std::vector<size_t> strides;
if (dim == 1) {
shape = {_self.n_halfedges()};
strides = {sizeof(int)};
}
else {
shape = {_self.n_halfedges(), dim};
strides = {dim * sizeof(int), sizeof(int)};
}
return py::array_t<int>(shape, strides, indices, base);
}
template <class Mesh, class Handle, class Circulator>
py::array_t<int> indices(Mesh& _self) {
const size_t n = _self.py_n_items(Handle());
if (n == 0) return py::array_t<int>();
const bool has_status = _self.py_has_status(Handle());
// find max valence and check status
size_t max_valence = 0;
for (size_t i = 0; i < n; ++i) {
Handle hnd(i);
if (has_status && _self.status(hnd).deleted()) {
PyErr_SetString(PyExc_RuntimeError, "Mesh has deleted items. Please call garbage_collection() first.");
throw py::error_already_set();
}
size_t valence = 0;
for (auto it = Circulator(_self, hnd); it.is_valid(); ++it) {
valence++;
}
max_valence = std::max(max_valence, valence);
}
// allocate memory
int *indices = new int[n * max_valence];
// copy indices
for (size_t i = 0; i < n; ++i) {
int valence = 0;
for (auto it = Circulator(_self, Handle(i)); it.is_valid(); ++it) {
indices[i * max_valence + valence] = it->idx();
valence++;
}
for (size_t j = valence; j < max_valence; ++j) {
indices[i * max_valence + j] = -1;
}
}
// make numpy array
const auto shape = {n, size_t(max_valence)};
const auto strides = {max_valence * sizeof(int), sizeof(int)};
py::capsule base = free_when_done(indices);
return py::array_t<int>(shape, strides, indices, base);
}
/**
* 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
* meshes or triangle meshes, but not both).
*
* @tparam Class A pybind11::class type.
*
* @param _class The pybind11::class instance for which the member
* functions are to be defined.
*/
template <class Class>
void expose_type_specific_functions(Class& _class) {
// See the template specializations below
}
/**
* Function template specialization for polygon meshes.
*/
template <>
void expose_type_specific_functions(py::class_<PolyMesh>& _class) {
typedef PolyMesh::Scalar Scalar;
typedef PolyMesh::Point Point;
typedef PolyMesh::Normal Normal;
typedef PolyMesh::Color Color;
typedef py::array_t<typename Point::value_type> np_point_t;
OM::FaceHandle (PolyMesh::*add_face_4_vh)(OM::VertexHandle, OM::VertexHandle, OM::VertexHandle, OM::VertexHandle) = &PolyMesh::add_face;
_class
.def("add_face", add_face_4_vh)
.def("split", [](PolyMesh& _self, OM::EdgeHandle _eh, np_point_t _arr) {
_self.split(_eh, Point(_arr.at(0), _arr.at(1), _arr.at(2)));
})
.def("split", [](PolyMesh& _self, OM::FaceHandle _fh, np_point_t _arr) {
_self.split(_fh, Point(_arr.at(0), _arr.at(1), _arr.at(2)));
})
.def("insert_edge", &PolyMesh::insert_edge)
.def("face_vertex_indices", &indices<PolyMesh, OM::FaceHandle, PolyMesh::FaceVertexIter>)
.def("fv_indices", &indices<PolyMesh, OM::FaceHandle, PolyMesh::FaceVertexIter>)
.def("calc_face_normal", [](PolyMesh& _self, np_point_t _p0, np_point_t _p1, np_point_t _p2) {
const Point p0(_p0.at(0), _p0.at(1), _p0.at(2));
const Point p1(_p1.at(0), _p1.at(1), _p1.at(2));
const Point p2(_p2.at(0), _p2.at(1), _p2.at(2));
return vec2numpy(_self.calc_face_normal(p0, p1, p2));
})
;
}
/**
* Function template specialization for triangle meshes.
*/
template <>
void expose_type_specific_functions(py::class_<TriMesh>& _class) {
typedef TriMesh::Scalar Scalar;
typedef TriMesh::Point Point;
typedef TriMesh::Normal Normal;
typedef TriMesh::Color Color;
typedef py::array_t<typename Point::value_type> np_point_t;
void (TriMesh::*split_copy_eh_vh)(OM::EdgeHandle, OM::VertexHandle) = &TriMesh::split_copy;
OM::HalfedgeHandle (TriMesh::*vertex_split_vh)(OM::VertexHandle, OM::VertexHandle, OM::VertexHandle, OM::VertexHandle) = &TriMesh::vertex_split;
_class
.def("split", [](TriMesh& _self, OM::EdgeHandle _eh, np_point_t _arr) {
return _self.split(_eh, Point(_arr.at(0), _arr.at(1), _arr.at(2)));
})
.def("split", [](TriMesh& _self, OM::FaceHandle _fh, np_point_t _arr) {
return _self.split(_fh, Point(_arr.at(0), _arr.at(1), _arr.at(2)));
})
.def("split_copy", split_copy_eh_vh)
.def("split_copy", [](TriMesh& _self, OM::EdgeHandle _eh, np_point_t _arr) {
return _self.split_copy(_eh, Point(_arr.at(0), _arr.at(1), _arr.at(2)));
})
.def("split_copy", [](TriMesh& _self, OM::FaceHandle _fh, np_point_t _arr) {
return _self.split_copy(_fh, Point(_arr.at(0), _arr.at(1), _arr.at(2)));
})
.def("opposite_vh", &TriMesh::opposite_vh)
.def("opposite_he_opposite_vh", &TriMesh::opposite_he_opposite_vh)
.def("vertex_split", vertex_split_vh)
.def("vertex_split", [](TriMesh& _self, np_point_t _arr, OM::VertexHandle _v1, OM::VertexHandle _vl, OM::VertexHandle _vr) {
return _self.vertex_split(Point(_arr.at(0), _arr.at(1), _arr.at(2)), _v1, _vl, _vr);
})
.def("is_flip_ok", &TriMesh::is_flip_ok)
.def("flip", &TriMesh::flip)
.def("face_vertex_indices", &face_vertex_indices_trimesh)
.def("fv_indices", &face_vertex_indices_trimesh)
;
}
/**
* Expose a mesh type to %Python.
*
* @tparam Mesh A mesh type.
*
* @param _name The name of the mesh type to be exposed.
*/
template <class Mesh>
void expose_mesh(py::module& m, const char *_name) {
typedef typename Mesh::Scalar Scalar;
typedef typename Mesh::Point Point;
typedef typename Mesh::Normal Normal;
typedef typename Mesh::Color Color;
typedef typename Mesh::TexCoord1D TexCoord1D;
typedef typename Mesh::TexCoord2D TexCoord2D;
typedef typename Mesh::TexCoord3D TexCoord3D;
typedef typename Mesh::TextureIndex TextureIndex;
//======================================================================
// KernelT Function Pointers
//======================================================================
// Get the i'th item
OM::VertexHandle (Mesh::*vertex_handle_uint )(unsigned int) const = &Mesh::vertex_handle;
OM::HalfedgeHandle (Mesh::*halfedge_handle_uint)(unsigned int) const = &Mesh::halfedge_handle;
OM::EdgeHandle (Mesh::*edge_handle_uint )(unsigned int) const = &Mesh::edge_handle;
OM::FaceHandle (Mesh::*face_handle_uint )(unsigned int) const = &Mesh::face_handle;
// Delete items
void (Mesh::*garbage_collection_bools)(bool, bool, bool) = &Mesh::garbage_collection;
void (*garbage_collection_lists_bools)(Mesh&, py::list&, py::list&, py::list&, bool, bool, bool) = &garbage_collection;
// Vertex connectivity
OM::HalfedgeHandle (Mesh::*halfedge_handle_vh)(OM::VertexHandle) const = &Mesh::halfedge_handle;
OM::HalfedgeHandle (Mesh::*halfedge_handle_fh)(OM::FaceHandle ) const = &Mesh::halfedge_handle;
// Halfedge connectivity
OM::FaceHandle (Mesh::*face_handle_hh )(OM::HalfedgeHandle) const = &Mesh::face_handle;
OM::HalfedgeHandle (Mesh::*prev_halfedge_handle_hh)(OM::HalfedgeHandle) const = &Mesh::prev_halfedge_handle;
OM::EdgeHandle (Mesh::*edge_handle_hh )(OM::HalfedgeHandle) const = &Mesh::edge_handle;
// Edge connectivity
OM::HalfedgeHandle (Mesh::*halfedge_handle_eh_uint)(OM::EdgeHandle, unsigned int) const = &Mesh::halfedge_handle;
// Set halfedge
void (Mesh::*set_halfedge_handle_vh_hh)(OM::VertexHandle, OM::HalfedgeHandle) = &Mesh::set_halfedge_handle;
void (Mesh::*set_halfedge_handle_fh_hh)(OM::FaceHandle, OM::HalfedgeHandle) = &Mesh::set_halfedge_handle;
// Low-level adding new items
OM::VertexHandle (Mesh::*new_vertex_void )(void ) = &Mesh::new_vertex;
OM::FaceHandle (Mesh::*new_face_void )(void ) = &Mesh::new_face;
OM::FaceHandle (Mesh::*new_face_face )(const typename Mesh::Face& ) = &Mesh::new_face;
// Kernel item iterators
IteratorWrapperT<typename Mesh::VertexIter, &Mesh::n_vertices > (*vertices )(Mesh&) = &get_iterator;
IteratorWrapperT<typename Mesh::HalfedgeIter, &Mesh::n_halfedges> (*halfedges)(Mesh&) = &get_iterator;
IteratorWrapperT<typename Mesh::EdgeIter, &Mesh::n_edges > (*edges )(Mesh&) = &get_iterator;
IteratorWrapperT<typename Mesh::FaceIter, &Mesh::n_faces > (*faces )(Mesh&) = &get_iterator;
IteratorWrapperT<typename Mesh::VertexIter, &Mesh::n_vertices > (*svertices )(Mesh&) = &get_skipping_iterator;
IteratorWrapperT<typename Mesh::HalfedgeIter, &Mesh::n_halfedges> (*shalfedges)(Mesh&) = &get_skipping_iterator;
IteratorWrapperT<typename Mesh::EdgeIter, &Mesh::n_edges > (*sedges )(Mesh&) = &get_skipping_iterator;
IteratorWrapperT<typename Mesh::FaceIter, &Mesh::n_faces > (*sfaces )(Mesh&) = &get_skipping_iterator;
//======================================================================
// BaseKernel Function Pointers
//======================================================================
// Copy all properties
void (Mesh::*copy_all_properties_vh_vh_bool)(OM::VertexHandle, OM::VertexHandle, bool) = &Mesh::copy_all_properties;
void (Mesh::*copy_all_properties_hh_hh_bool)(OM::HalfedgeHandle, OM::HalfedgeHandle, bool) = &Mesh::copy_all_properties;
void (Mesh::*copy_all_properties_eh_eh_bool)(OM::EdgeHandle, OM::EdgeHandle, bool) = &Mesh::copy_all_properties;
void (Mesh::*copy_all_properties_fh_fh_bool)(OM::FaceHandle, OM::FaceHandle, bool) = &Mesh::copy_all_properties;
//======================================================================
// PolyConnectivity Function Pointers
//======================================================================
// Assign connectivity
void (*assign_connectivity_poly)(Mesh&, const PolyMesh&) = &assign_connectivity;
void (*assign_connectivity_tri )(Mesh&, const TriMesh& ) = &assign_connectivity;
// Adding items to a mesh
OM::FaceHandle (Mesh::*add_face_3_vh)(OM::VertexHandle, OM::VertexHandle, OM::VertexHandle) = &Mesh::add_face;
OM::FaceHandle (Mesh::*add_face_list)(const std::vector<OM::VertexHandle>&) = &Mesh::add_face;
// Vertex and face valence
unsigned int (Mesh::*valence_vh)(OM::VertexHandle) const = &Mesh::valence;
unsigned int (Mesh::*valence_fh)(OM::FaceHandle ) const = &Mesh::valence;
// Triangulate face or mesh
void (Mesh::*triangulate_fh )(OM::FaceHandle) = &Mesh::triangulate;
void (Mesh::*triangulate_void)( ) = &Mesh::triangulate;
// Vertex and Face circulators
CirculatorWrapperT<typename Mesh::VertexVertexIter, OM::VertexHandle > (*vv )(Mesh&, OM::VertexHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::VertexIHalfedgeIter, OM::VertexHandle > (*vih)(Mesh&, OM::VertexHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::VertexOHalfedgeIter, OM::VertexHandle > (*voh)(Mesh&, OM::VertexHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::VertexEdgeIter, OM::VertexHandle > (*ve )(Mesh&, OM::VertexHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::VertexFaceIter, OM::VertexHandle > (*vf )(Mesh&, OM::VertexHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::FaceVertexIter, OM::FaceHandle > (*fv )(Mesh&, OM::FaceHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::FaceHalfedgeIter, OM::FaceHandle > (*fh )(Mesh&, OM::FaceHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::FaceEdgeIter, OM::FaceHandle > (*fe )(Mesh&, OM::FaceHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::FaceFaceIter, OM::FaceHandle > (*ff )(Mesh&, OM::FaceHandle ) = &get_circulator;
CirculatorWrapperT<typename Mesh::HalfedgeLoopIter, OM::HalfedgeHandle> (*hl )(Mesh&, OM::HalfedgeHandle) = &get_circulator;
// Boundary and manifold tests
bool (Mesh::*is_boundary_hh)(OM::HalfedgeHandle ) const = &Mesh::is_boundary;
bool (Mesh::*is_boundary_eh)(OM::EdgeHandle ) const = &Mesh::is_boundary;
bool (Mesh::*is_boundary_vh)(OM::VertexHandle ) const = &Mesh::is_boundary;
bool (Mesh::*is_boundary_fh)(OM::FaceHandle, bool) const = &Mesh::is_boundary;
//======================================================================
// PolyMeshT Function Pointers
//======================================================================
Scalar (Mesh::*calc_edge_length_eh)(OM::EdgeHandle ) const = &Mesh::calc_edge_length;
Scalar (Mesh::*calc_edge_length_hh)(OM::HalfedgeHandle) const = &Mesh::calc_edge_length;
Scalar (Mesh::*calc_edge_sqr_length_eh)(OM::EdgeHandle ) const = &Mesh::calc_edge_sqr_length;
Scalar (Mesh::*calc_edge_sqr_length_hh)(OM::HalfedgeHandle) const = &Mesh::calc_edge_sqr_length;