Mesh.hh 59.7 KB
Newer Older
1
2
3
#ifndef OPENMESH_PYTHON_MESH_HH
#define OPENMESH_PYTHON_MESH_HH

Alexander Dielen's avatar
Alexander Dielen committed
4
#include "Utilities.hh"
5
#include "MeshTypes.hh"
6
7
8
#include "Iterator.hh"
#include "Circulator.hh"

9
10
#include <algorithm>

Alexander Dielen's avatar
Alexander Dielen committed
11
12
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
13
#include <pybind11/stl.h>
14

Alexander Dielen's avatar
Alexander Dielen committed
15
16
namespace py = pybind11;
namespace OM = OpenMesh;
17

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

/**
 * 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.
 */
Alexander Dielen's avatar
Alexander Dielen committed
36
template <class Mesh, class Iterator, size_t (OM::ArrayKernel::*n_items)() const>
37
38
39
40
41
42
43
IteratorWrapperT<Iterator, n_items> get_iterator(Mesh& _self) {
	return IteratorWrapperT<Iterator, n_items>(_self, typename Iterator::value_type(0));
}

/**
 * Get a skipping iterator.
 */
Alexander Dielen's avatar
Alexander Dielen committed
44
template <class Mesh, class Iterator, size_t (OM::ArrayKernel::*n_items)() const>
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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>
Alexander Dielen's avatar
Alexander Dielen committed
79
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) {
80
	// Convert list of handles to vector of pointers
Alexander Dielen's avatar
Alexander Dielen committed
81
82
83
84
85
86
	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*>());
		}
	}
87
88

	// Convert list of handles to vector of pointers
Alexander Dielen's avatar
Alexander Dielen committed
89
90
91
92
93
94
	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*>());
		}
	}
95
96

	// Convert list of handles to vector of pointers
Alexander Dielen's avatar
Alexander Dielen committed
97
98
99
100
101
102
	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*>());
		}
	}
103
104
105
106
107

	// Call garbage collection
	_self.garbage_collection(vh_vector, hh_vector, fh_vector, _v, _e, _f);
}

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/**
 * 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);
}

123
/**
Alexander Dielen's avatar
Alexander Dielen committed
124
 * Converts OpenMesh vectors to numpy arrays.
125
 *
Alexander Dielen's avatar
Alexander Dielen committed
126
127
 * The returned array references the vector's underlying data, i.e. changes
 * made to the returned array affect the original mesh.
128
129
 *
 * @tparam Mesh A Mesh type.
Alexander Dielen's avatar
Alexander Dielen committed
130
 * @tparam vector A Vector type.
131
 *
Alexander Dielen's avatar
Alexander Dielen committed
132
133
134
135
 * @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.
136
 */
Alexander Dielen's avatar
Alexander Dielen committed
137
template<class Mesh, class Vector>
138
py::array_t<typename Vector::value_type> vec2numpy(Mesh& _mesh, Vector& _vec, size_t _n = 1) {
Alexander Dielen's avatar
Alexander Dielen committed
139
	typedef typename Vector::value_type dtype;
140
141
142
143
144
145
146
147
148
149
150
	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));
Alexander Dielen's avatar
Alexander Dielen committed
151
152
153
}

template<class Mesh>
154
155
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));
Alexander Dielen's avatar
Alexander Dielen committed
156
157
}

158
template<class Mesh>
159
160
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));
161
162
}

163
py::array_t<int> face_vertex_indices_trimesh(TriMesh& _self) {
164
165
166
	if (_self.n_faces() == 0) {
		return py::array_t<int>();
	}
167
168
169

	const bool has_status = _self.has_face_status();

170
	int *indices = new int[_self.n_faces() * 3];
171
172
	py::capsule base = free_when_done(indices);

Alexander Dielen's avatar
Alexander Dielen committed
173
	for (auto fh : _self.all_faces()) {
174
175
176
177
		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();
		}
178
179
180
181
182
183
184
		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)};
185
	return py::array_t<int>(shape, strides, indices, base);
186
187
}

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
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();
	}
216
	static size_t dim() { return 1; }
217
218
219
220
221
222
};

struct FuncHalfedgeFromVertex {
	static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
		*_ptr = _mesh.from_vertex_handle(_heh).idx();
	}
223
	static size_t dim() { return 1; }
224
225
226
227
228
229
};

struct FuncHalfedgeFace {
	static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
		*_ptr = _mesh.face_handle(_heh).idx();
	}
230
	static size_t dim() { return 1; }
231
232
233
234
235
236
};

struct FuncHalfedgeEdge {
	static void call(const OM::ArrayKernel& _mesh, OM::HalfedgeHandle _heh, int *_ptr) {
		*_ptr = _mesh.edge_handle(_heh).idx();
	}
237
238
239
240
241
242
243
244
245
	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; }
246
247
248
249
};

template <class Mesh, class CopyFunc>
py::array_t<int> edge_other_indices(Mesh& _self) {
250
251
252
	if (_self.n_edges() == 0) {
		return py::array_t<int>();
	}
253
254
255

	const bool has_status = _self.has_edge_status();

256
	int *indices = new int[_self.n_edges() * 2];
257
258
	py::capsule base = free_when_done(indices);

Alexander Dielen's avatar
Alexander Dielen committed
259
	for (auto eh : _self.all_edges()) {
260
261
262
263
		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();
		}
264
		CopyFunc::call(_self, eh, &indices[eh.idx() * 2]);
265
266
267
268
269
270
	}
	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);
}

271
272
template <class Mesh, class CopyFunc>
py::array_t<int> halfedge_other_indices(Mesh& _self) {
273
274
275
	if (_self.n_halfedges() == 0) {
		return py::array_t<int>();
	}
276
277
278
279
280
281
282

	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);

Alexander Dielen's avatar
Alexander Dielen committed
283
	for (auto heh : _self.all_halfedges()) {
284
285
286
287
288
		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]);
289
	}
290
291
292
293
294
295
296
297
298
299
300
301

	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)};
	}

302
303
304
305
306
307
308
309
	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>();

310
311
312
	const bool has_status = _self.py_has_status(Handle());

	// find max valence and check status
313
314
	int max_valence = 0;
	for (size_t i = 0; i < n; ++i) {
315
316
317
318
319
		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();
		}
320
		int valence = 0;
321
		for (auto it = Circulator(_self, hnd); it.is_valid(); ++it) {
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
			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)};
345
346
347
348
	py::capsule base = free_when_done(indices);
	return py::array_t<int>(shape, strides, indices, base);
}

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
template <class Mesh>
void add_vertices(Mesh& _self, py::array_t<typename Mesh::Point::value_type> _points) {
	// return if _points is empty
	if (_points.size() == 0) {
		return;
	}

	// _points is not empty, throw if _points has wrong shape
	if (_points.ndim() != 2 || _points.shape(1) != 3) {
		PyErr_SetString(PyExc_RuntimeError, "Array 'points' must have shape (n, 3)");
		throw py::error_already_set();
	}

	for (ssize_t i = 0; i < _points.shape(0); ++i) {
		_self.add_vertex(typename Mesh::Point(_points.at(i, 0), _points.at(i, 1), _points.at(i, 2)));
	}
}

template <class Mesh>
void add_faces(Mesh& _self, py::array_t<int> _faces) {
	// return if _faces is empty
	if (_self.n_vertices() < 3 || _faces.size() == 0) {
		return;
	}

	// _faces is not empty, throw if _faces has wrong shape
	if (_faces.ndim() != 2 || _faces.shape(1) < 3) {
		PyErr_SetString(PyExc_RuntimeError, "Array 'face_vertex_indices' must have shape (n, m) with m > 2");
		throw py::error_already_set();
	}

	for (ssize_t i = 0; i < _faces.shape(0); ++i) {
		std::vector<OM::VertexHandle> vhandles;
		for (ssize_t j = 0; j < _faces.shape(1); ++j) {
			if (_faces.at(i, j) >= 0 && _faces.at(i, j) < _self.n_vertices()) {
				vhandles.push_back(OM::VertexHandle(_faces.at(i, j)));
			}
		}
		if (vhandles.size() >= 3) {
			_self.add_face(vhandles);
		}
	}
}

393
394
395
396
397
/**
 * 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).
 *
Alexander Dielen's avatar
Alexander Dielen committed
398
 * @tparam Class A pybind11::class type.
399
 *
Alexander Dielen's avatar
Alexander Dielen committed
400
 * @param _class The pybind11::class instance for which the member
401
402
403
404
405
406
407
408
409
410
411
 * 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 <>
Alexander Dielen's avatar
Alexander Dielen committed
412
void expose_type_specific_functions(py::class_<PolyMesh>& _class) {
413
414
415
416
417
	typedef PolyMesh::Scalar Scalar;
	typedef PolyMesh::Point  Point;
	typedef PolyMesh::Normal Normal;
	typedef PolyMesh::Color  Color;

418
	typedef py::array_t<typename Point::value_type> np_point_t;
419

420
	_class
Isaak Lim's avatar
Isaak Lim committed
421
422
423
		.def("add_face", [](PolyMesh& _self, OM::VertexHandle _vh0, OM::VertexHandle _vh1, OM::VertexHandle _vh2, OM::VertexHandle _vh3) {
				 return static_cast<OM::FaceHandle>(_self.add_face(_vh0, _vh1, _vh2, _vh3));
			})
424

425
426
427
428
429
430
431
		.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)));
			})
432
433

		.def("insert_edge", &PolyMesh::insert_edge)
434

435
436
		.def("face_vertex_indices", &indices<PolyMesh, OM::FaceHandle, PolyMesh::FaceVertexIter>)
		.def("fv_indices", &indices<PolyMesh, OM::FaceHandle, PolyMesh::FaceVertexIter>)
437

438
		.def("calc_face_normal", [](PolyMesh& _self, np_point_t _p0, np_point_t _p1, np_point_t _p2) {
439
440
441
442
443
				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));
			})
444
445
446
447
448
449
450
		;
}

/**
 * Function template specialization for triangle meshes.
 */
template <>
Alexander Dielen's avatar
Alexander Dielen committed
451
void expose_type_specific_functions(py::class_<TriMesh>& _class) {
452
453
454
455
456
	typedef TriMesh::Scalar Scalar;
	typedef TriMesh::Point  Point;
	typedef TriMesh::Normal Normal;
	typedef TriMesh::Color  Color;

457
458
459
	typedef py::array_t<typename Point::value_type> np_point_t;

	void (TriMesh::*split_copy_eh_vh)(OM::EdgeHandle, OM::VertexHandle) = &TriMesh::split_copy;
Alexander Dielen's avatar
Alexander Dielen committed
460
	OM::HalfedgeHandle (TriMesh::*vertex_split_vh)(OM::VertexHandle, OM::VertexHandle, OM::VertexHandle, OM::VertexHandle) = &TriMesh::vertex_split;
461
462

	_class
463
464
465
466
467
468
469
		.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)));
			})
470
471

		.def("split_copy", split_copy_eh_vh)
472
473
474
475
476
477
478
479

		.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)));
			})
480
481
482
483
484
485

		.def("opposite_vh", &TriMesh::opposite_vh)
		.def("opposite_he_opposite_vh", &TriMesh::opposite_he_opposite_vh)

		.def("vertex_split", vertex_split_vh)

486
487
488
489
		.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);
			})

490
491
		.def("is_flip_ok", &TriMesh::is_flip_ok)
		.def("flip", &TriMesh::flip)
492

493
494
		.def("face_vertex_indices", &face_vertex_indices_trimesh)
		.def("fv_indices", &face_vertex_indices_trimesh)
495
496
497
498
499
500
501
502
503
504
505
506
		;
}


/**
 * 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>
Alexander Dielen's avatar
Alexander Dielen committed
507
void expose_mesh(py::module& m, const char *_name) {
508
509
510
511
512
	typedef typename Mesh::Scalar Scalar;
	typedef typename Mesh::Point  Point;
	typedef typename Mesh::Normal Normal;
	typedef typename Mesh::Color  Color;

513
514
515
	typedef typename Mesh::TexCoord1D TexCoord1D;
	typedef typename Mesh::TexCoord2D TexCoord2D;
	typedef typename Mesh::TexCoord3D TexCoord3D;
516
	typedef typename Mesh::TextureIndex TextureIndex;
517

518
519
520
521
522
	//======================================================================
	//  KernelT Function Pointers
	//======================================================================

	// Get the i'th item
Alexander Dielen's avatar
Alexander Dielen committed
523
524
525
526
	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;
527
528
529

	// Delete items
	void (Mesh::*garbage_collection_bools)(bool, bool, bool) = &Mesh::garbage_collection;
Alexander Dielen's avatar
Alexander Dielen committed
530
	void (*garbage_collection_lists_bools)(Mesh&, py::list&, py::list&, py::list&, bool, bool, bool) = &garbage_collection;
531
532

	// Vertex connectivity
Alexander Dielen's avatar
Alexander Dielen committed
533
534
	OM::HalfedgeHandle (Mesh::*halfedge_handle_vh)(OM::VertexHandle) const = &Mesh::halfedge_handle;
	OM::HalfedgeHandle (Mesh::*halfedge_handle_fh)(OM::FaceHandle  ) const = &Mesh::halfedge_handle;
535
536

	// Halfedge connectivity
Alexander Dielen's avatar
Alexander Dielen committed
537
538
539
	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;
540
541

	// Edge connectivity
Alexander Dielen's avatar
Alexander Dielen committed
542
	OM::HalfedgeHandle (Mesh::*halfedge_handle_eh_uint)(OM::EdgeHandle, unsigned int) const = &Mesh::halfedge_handle;
543
544

	// Set halfedge
Alexander Dielen's avatar
Alexander Dielen committed
545
546
	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;
547
548

	// Low-level adding new items
Alexander Dielen's avatar
Alexander Dielen committed
549
550
	OM::FaceHandle   (Mesh::*new_face_void   )(void                        ) = &Mesh::new_face;
	OM::FaceHandle   (Mesh::*new_face_face   )(const typename Mesh::Face&  ) = &Mesh::new_face;
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567

	// 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
Alexander Dielen's avatar
Alexander Dielen committed
568
569
570
571
	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;
572
573
574
575
576
577
578
579
580
581

	//======================================================================
	//  PolyConnectivity Function Pointers
	//======================================================================

	// Assign connectivity
	void (*assign_connectivity_poly)(Mesh&, const PolyMesh&) = &assign_connectivity;
	void (*assign_connectivity_tri )(Mesh&, const TriMesh& ) = &assign_connectivity;

	// Vertex and face valence
Alexander Dielen's avatar
Alexander Dielen committed
582
583
	unsigned int (Mesh::*valence_vh)(OM::VertexHandle) const = &Mesh::valence;
	unsigned int (Mesh::*valence_fh)(OM::FaceHandle  ) const = &Mesh::valence;
584
585

	// Triangulate face or mesh
Alexander Dielen's avatar
Alexander Dielen committed
586
587
	void (Mesh::*triangulate_fh  )(OM::FaceHandle) = &Mesh::triangulate;
	void (Mesh::*triangulate_void)(              ) = &Mesh::triangulate;
588
589

	// Vertex and Face circulators
Alexander Dielen's avatar
Alexander Dielen committed
590
591
592
593
594
595
596
597
598
599
	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;
600
601

	// Boundary and manifold tests
Alexander Dielen's avatar
Alexander Dielen committed
602
603
604
605
	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;
606
607
608
609
610

	//======================================================================
	//  PolyMeshT Function Pointers
	//======================================================================

Alexander Dielen's avatar
Alexander Dielen committed
611
612
	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;
613

Alexander Dielen's avatar
Alexander Dielen committed
614
615
	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;
616

Alexander Dielen's avatar
Alexander Dielen committed
617
618
	Scalar (Mesh::*calc_dihedral_angle_fast_hh)(OM::HalfedgeHandle) const = &Mesh::calc_dihedral_angle_fast;
	Scalar (Mesh::*calc_dihedral_angle_fast_eh)(OM::EdgeHandle    ) const = &Mesh::calc_dihedral_angle_fast;
619

Alexander Dielen's avatar
Alexander Dielen committed
620
621
	Scalar (Mesh::*calc_dihedral_angle_hh)(OM::HalfedgeHandle) const = &Mesh::calc_dihedral_angle;
	Scalar (Mesh::*calc_dihedral_angle_eh)(OM::EdgeHandle    ) const = &Mesh::calc_dihedral_angle;
622
623
624

	unsigned int (Mesh::*find_feature_edges)(Scalar) = &Mesh::find_feature_edges;

Alexander Dielen's avatar
Alexander Dielen committed
625
626
	void (Mesh::*split_fh_vh)(OM::FaceHandle, OM::VertexHandle) = &Mesh::split;
	void (Mesh::*split_eh_vh)(OM::EdgeHandle, OM::VertexHandle) = &Mesh::split;
627

628
629
	void (Mesh::*split_copy_fh_vh)(OM::FaceHandle, OM::VertexHandle) = &Mesh::split_copy;

630
631
632
633
	//======================================================================
	//  Mesh Type
	//======================================================================

Alexander Dielen's avatar
Alexander Dielen committed
634
	py::class_<Mesh> class_mesh(m, _name);
635
636

	class_mesh
Alexander Dielen's avatar
Alexander Dielen committed
637
		.def(py::init<>())
638

639
640
		.def(py::init([](py::array_t<typename Point::value_type> _points, py::array_t<int> _faces) {
				Mesh mesh;
641
642
				add_vertices(mesh, _points);
				add_faces(mesh, _faces);
643
644
645
				return mesh;
			}), py::arg("points"), py::arg("face_vertex_indices")=py::array_t<int>())

Alexander Dielen's avatar
Alexander Dielen committed
646
647
648
649
650
651
652
		//======================================================================
		//  Copy interface
		//======================================================================

		.def("__copy__", &Mesh::py_copy)
		.def("__deepcopy__", &Mesh::py_deepcopy)

653
654
655
656
657
658
659
660
661
662
663
664
665
		//======================================================================
		//  KernelT
		//======================================================================

		.def("reserve", &Mesh::reserve)

		.def("vertex_handle", vertex_handle_uint)
		.def("halfedge_handle", halfedge_handle_uint)
		.def("edge_handle", edge_handle_uint)
		.def("face_handle", face_handle_uint)

		.def("clear", &Mesh::clear)
		.def("clean", &Mesh::clean)
Alexander Dielen's avatar
Alexander Dielen committed
666
667
668
669
670
		.def("garbage_collection", garbage_collection_bools,
			py::arg("v")=true, py::arg("e")=true, py::arg("f")=true)
		.def("garbage_collection", garbage_collection_lists_bools,
			py::arg("vh_to_update"), py::arg("hh_to_update"), py::arg("fh_to_update"),
			py::arg("v")=true, py::arg("e")=true, py::arg("f")=true)
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688

		.def("n_vertices", &Mesh::n_vertices)
		.def("n_halfedges", &Mesh::n_halfedges)
		.def("n_edges", &Mesh::n_edges)
		.def("n_faces", &Mesh::n_faces)
		.def("vertices_empty", &Mesh::vertices_empty)
		.def("halfedges_empty", &Mesh::halfedges_empty)
		.def("edges_empty", &Mesh::edges_empty)
		.def("faces_empty", &Mesh::faces_empty)

		.def("halfedge_handle", halfedge_handle_vh)
		.def("set_halfedge_handle", set_halfedge_handle_vh_hh)

		.def("to_vertex_handle", &Mesh::to_vertex_handle)
		.def("from_vertex_handle", &Mesh::from_vertex_handle)
		.def("set_vertex_handle", &Mesh::set_vertex_handle)
		.def("face_handle", face_handle_hh)
		.def("set_face_handle", &Mesh::set_face_handle)
Isaak Lim's avatar
Isaak Lim committed
689
690
691
692
693
694
		.def("next_halfedge_handle", [](Mesh& _self, OM::HalfedgeHandle heh) {
				 return static_cast<OM::HalfedgeHandle>(_self.next_halfedge_handle(heh));
			})
		.def("set_next_halfedge_handle", [](Mesh& _self, OM::HalfedgeHandle heh0, OM::HalfedgeHandle heh1) {
				 _self.set_next_halfedge_handle(heh0, heh1);
			})
695
		.def("prev_halfedge_handle", prev_halfedge_handle_hh)
Isaak Lim's avatar
Isaak Lim committed
696
697
698
699
700
701
702
703
704
		.def("opposite_halfedge_handle", [](Mesh& _self, OM::HalfedgeHandle heh) {
				 return static_cast<OM::HalfedgeHandle>(_self.opposite_halfedge_handle(heh));
			})
		.def("ccw_rotated_halfedge_handle", [](Mesh& _self, OM::HalfedgeHandle heh) {
				 return static_cast<OM::HalfedgeHandle>(_self.ccw_rotated_halfedge_handle(heh));
			})
		.def("cw_rotated_halfedge_handle", [](Mesh& _self, OM::HalfedgeHandle heh) {
				 return static_cast<OM::HalfedgeHandle>(_self.cw_rotated_halfedge_handle(heh));
			})
705
706
707
708
709
710
711
		.def("edge_handle", edge_handle_hh)

		.def("halfedge_handle", halfedge_handle_eh_uint)

		.def("halfedge_handle", halfedge_handle_fh)
		.def("set_halfedge_handle", set_halfedge_handle_fh_hh)

712
		.def("is_deleted", [](Mesh& _self, OM::VertexHandle _h) {
713
				if (!_self.has_vertex_status()) return false;
714
715
				return _self.status(_h).deleted();
			})
716

717
		.def("set_deleted", [](Mesh& _self, OM::VertexHandle _h, bool _val) {
718
				if (!_self.has_vertex_status()) _self.request_vertex_status();
719
				_self.status(_h).set_deleted(_val);
720
721
			})

722
		.def("is_deleted", [](Mesh& _self, OM::HalfedgeHandle _h) {
723
				if (!_self.has_halfedge_status()) return false;
724
725
				return _self.status(_h).deleted();
			})
726

727
		.def("set_deleted", [](Mesh& _self, OM::HalfedgeHandle _h, bool _val) {
728
				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
729
				_self.status(_h).set_deleted(_val);
730
731
			})

732
		.def("is_deleted", [](Mesh& _self, OM::EdgeHandle _h) {
733
				if (!_self.has_edge_status()) return false;
734
735
				return _self.status(_h).deleted();
			})
736

737
		.def("set_deleted", [](Mesh& _self, OM::EdgeHandle _h, bool _val) {
738
				if (!_self.has_edge_status()) _self.request_edge_status();
739
				_self.status(_h).set_deleted(_val);
740
741
			})

742
		.def("is_deleted", [](Mesh& _self, OM::FaceHandle _h) {
743
				if (!_self.has_face_status()) return false;
744
745
				return _self.status(_h).deleted();
			})
746

747
		.def("set_deleted", [](Mesh& _self, OM::FaceHandle _h, bool _val) {
748
				if (!_self.has_face_status()) _self.request_face_status();
749
				_self.status(_h).set_deleted(_val);
750
			})
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796

		.def("request_vertex_normals", &Mesh::request_vertex_normals)
		.def("request_vertex_colors", &Mesh::request_vertex_colors)
		.def("request_vertex_texcoords1D", &Mesh::request_vertex_texcoords1D)
		.def("request_vertex_texcoords2D", &Mesh::request_vertex_texcoords2D)
		.def("request_vertex_texcoords3D", &Mesh::request_vertex_texcoords3D)
		.def("request_halfedge_normals", &Mesh::request_halfedge_normals)
		.def("request_halfedge_colors", &Mesh::request_halfedge_colors)
		.def("request_halfedge_texcoords1D", &Mesh::request_halfedge_texcoords1D)
		.def("request_halfedge_texcoords2D", &Mesh::request_halfedge_texcoords2D)
		.def("request_halfedge_texcoords3D", &Mesh::request_halfedge_texcoords3D)
		.def("request_edge_colors", &Mesh::request_edge_colors)
		.def("request_face_normals", &Mesh::request_face_normals)
		.def("request_face_colors", &Mesh::request_face_colors)
		.def("request_face_texture_index", &Mesh::request_face_texture_index)

		.def("release_vertex_normals", &Mesh::release_vertex_normals)
		.def("release_vertex_colors", &Mesh::release_vertex_colors)
		.def("release_vertex_texcoords1D", &Mesh::release_vertex_texcoords1D)
		.def("release_vertex_texcoords2D", &Mesh::release_vertex_texcoords2D)
		.def("release_vertex_texcoords3D", &Mesh::release_vertex_texcoords3D)
		.def("release_halfedge_normals", &Mesh::release_halfedge_normals)
		.def("release_halfedge_colors", &Mesh::release_halfedge_colors)
		.def("release_halfedge_texcoords1D", &Mesh::release_halfedge_texcoords1D)
		.def("release_halfedge_texcoords2D", &Mesh::release_halfedge_texcoords2D)
		.def("release_halfedge_texcoords3D", &Mesh::release_halfedge_texcoords3D)
		.def("release_edge_colors", &Mesh::release_edge_colors)
		.def("release_face_normals", &Mesh::release_face_normals)
		.def("release_face_colors", &Mesh::release_face_colors)
		.def("release_face_texture_index", &Mesh::release_face_texture_index)

		.def("has_vertex_normals", &Mesh::has_vertex_normals)
		.def("has_vertex_colors", &Mesh::has_vertex_colors)
		.def("has_vertex_texcoords1D", &Mesh::has_vertex_texcoords1D)
		.def("has_vertex_texcoords2D", &Mesh::has_vertex_texcoords2D)
		.def("has_vertex_texcoords3D", &Mesh::has_vertex_texcoords3D)
		.def("has_halfedge_normals", &Mesh::has_halfedge_normals)
		.def("has_halfedge_colors", &Mesh::has_halfedge_colors)
		.def("has_halfedge_texcoords1D", &Mesh::has_halfedge_texcoords1D)
		.def("has_halfedge_texcoords2D", &Mesh::has_halfedge_texcoords2D)
		.def("has_halfedge_texcoords3D", &Mesh::has_halfedge_texcoords3D)
		.def("has_edge_colors", &Mesh::has_edge_colors)
		.def("has_face_normals", &Mesh::has_face_normals)
		.def("has_face_colors", &Mesh::has_face_colors)
		.def("has_face_texture_index", &Mesh::has_face_texture_index)

Isaak Lim's avatar
Isaak Lim committed
797
798
799
		.def("new_vertex", [](Mesh& _self) {
				 return static_cast<OM::VertexHandle>(_self.new_vertex());
			})
800
		.def("new_vertex", [](Mesh& _self, py::array_t<typename Point::value_type> _arr) {
Isaak Lim's avatar
Isaak Lim committed
801
				return static_cast<OM::VertexHandle>(_self.new_vertex(Point(_arr.at(0), _arr.at(1), _arr.at(2))));
802
803
			})

804
		.def("new_edge", &Mesh::new_edge)
805

806
807
808
809
810
811
812
813
814
815
816
817
818
		.def("new_face", new_face_void)
		.def("new_face", new_face_face)

		.def("vertices", vertices)
		.def("halfedges", halfedges)
		.def("edges", edges)
		.def("faces", faces)

		.def("svertices", svertices)
		.def("shalfedges", shalfedges)
		.def("sedges", sedges)
		.def("sfaces", sfaces)

819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
		.def("texture_index", [](Mesh& _self, OM::FaceHandle _h) {
				if (!_self.has_face_texture_index()) _self.request_face_texture_index();
				return _self.texture_index(_h);
			})

		.def("set_texture_index", [](Mesh& _self, OM::FaceHandle _h, TextureIndex _idx) {
				if (!_self.has_face_texture_index()) _self.request_face_texture_index();
				_self.set_texture_index(_h, _idx);
			})

		.def("texture_name", [](Mesh& _self, TextureIndex _idx) {
				OM::MPropHandleT<std::map<TextureIndex, std::string> > prop;
				if (_self.get_property_handle(prop, "TextureMapping")) {
					const auto map =  _self.property(prop);
					if (map.count(_idx) == 0) {
						throw py::index_error();
					}
					else {
						return map.at(_idx);
					}
				}
				else {
					PyErr_SetString(PyExc_RuntimeError, "Mesh has no textures.");
					throw py::error_already_set();
				}
			})

846
847
848
849
		//======================================================================
		//  BaseKernel
		//======================================================================

Alexander Dielen's avatar
Alexander Dielen committed
850
851
852
853
854
855
856
857
		.def("copy_all_properties", copy_all_properties_vh_vh_bool,
			py::arg("vh_from"), py::arg("vh_to"), py::arg("copy_build_in")=false)
		.def("copy_all_properties", copy_all_properties_hh_hh_bool,
			py::arg("hh_from"), py::arg("hh_to"), py::arg("copy_build_in")=false)
		.def("copy_all_properties", copy_all_properties_eh_eh_bool,
			py::arg("eh_from"), py::arg("eh_to"), py::arg("copy_build_in")=false)
		.def("copy_all_properties", copy_all_properties_fh_fh_bool,
			py::arg("fh_from"), py::arg("fh_to"), py::arg("copy_build_in")=false)
858

859
860
861
862
863
864
865
866
867
868
869
870
871
872
		//======================================================================
		//  ArrayKernel
		//======================================================================

		.def("is_valid_handle", (bool (Mesh::*)(OM::VertexHandle) const) &Mesh::is_valid_handle)
		.def("is_valid_handle", (bool (Mesh::*)(OM::HalfedgeHandle) const) &Mesh::is_valid_handle)
		.def("is_valid_handle", (bool (Mesh::*)(OM::EdgeHandle) const) &Mesh::is_valid_handle)
		.def("is_valid_handle", (bool (Mesh::*)(OM::FaceHandle) const) &Mesh::is_valid_handle)

		.def("delete_isolated_vertices", [](Mesh& _self) {
				if (!_self.has_vertex_status()) _self.request_vertex_status();
				_self.delete_isolated_vertices();
			})

873
874
875
876
877
878
879
		//======================================================================
		//  PolyConnectivity
		//======================================================================

		.def("assign_connectivity", assign_connectivity_poly)
		.def("assign_connectivity", assign_connectivity_tri)

Isaak Lim's avatar
Isaak Lim committed
880
881
882
883
884
885
		.def("add_face", [](Mesh& _self, OM::VertexHandle _vh0, OM::VertexHandle _vh1, OM::VertexHandle _vh2) {
				 return static_cast<OM::FaceHandle>(_self.add_face(_vh0, _vh1, _vh2));
			})
		.def("add_face", [](Mesh& _self, const std::vector<OM::VertexHandle>& _vhs) {
				 return static_cast<OM::FaceHandle>(_self.add_face(_vhs));
			})
886

887
888
		.def("opposite_face_handle", &Mesh::opposite_face_handle)
		.def("adjust_outgoing_halfedge", &Mesh::adjust_outgoing_halfedge)
889
890
891
		.def("find_halfedge", [](Mesh& _self, OM::VertexHandle _vh0, OM::VertexHandle _vh1) {
				 return static_cast<OM::HalfedgeHandle>(_self.find_halfedge(_vh0, _vh1));
			})
892
893
894
895
896
897
898
899
900
901
902
		.def("valence", valence_vh)
		.def("valence", valence_fh)
		.def("is_simple_link", &Mesh::is_simple_link)
		.def("is_simply_connected", &Mesh::is_simply_connected)
		.def("remove_edge", &Mesh::remove_edge)
		.def("reinsert_edge", &Mesh::reinsert_edge)
		.def("triangulate", triangulate_fh)
		.def("triangulate", triangulate_void)
		.def("split_edge", &Mesh::split_edge)
		.def("split_edge_copy", &Mesh::split_edge_copy)

903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
		.def("is_collapse_ok", [](Mesh& _self, OM::HalfedgeHandle _heh) {
				if (!_self.has_vertex_status()) _self.request_vertex_status();
				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
				if (!_self.has_edge_status()) _self.request_edge_status();
				if (!_self.has_face_status()) _self.request_face_status();
				return _self.is_collapse_ok(_heh);
			})

		.def("collapse", [](Mesh& _self, OM::HalfedgeHandle _heh) {
				if (!_self.has_vertex_status()) _self.request_vertex_status();
				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
				if (!_self.has_edge_status()) _self.request_edge_status();
				if (!_self.has_face_status()) _self.request_face_status();
				_self.collapse(_heh);
			})
918

919
		.def("add_vertex", [](Mesh& _self, py::array_t<typename Point::value_type> _arr) {
920
				return static_cast<OM::VertexHandle>(_self.add_vertex(Point(_arr.at(0), _arr.at(1), _arr.at(2))));
921
			})
922
923
924

		.def("delete_vertex", [](Mesh& _self, OM::VertexHandle _vh, bool _delete_isolated) {
				if (!_self.has_vertex_status()) _self.request_vertex_status();
925
926
				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
				if (!_self.has_edge_status()) _self.request_edge_status();
927
928
929
				if (!_self.has_face_status()) _self.request_face_status();
				_self.delete_vertex(_vh, _delete_isolated);
			}, py::arg("vh"), py::arg("delete_isolated_vertices")=true)
930

931
		.def("delete_edge", [](Mesh& _self, OM::EdgeHandle _eh, bool _delete_isolated) {
932
				if (!_self.has_vertex_status() && _delete_isolated) _self.request_vertex_status();
933
				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
934
935
936
937
				if (!_self.has_edge_status()) _self.request_edge_status();
				if (!_self.has_face_status()) _self.request_face_status();
				_self.delete_edge(_eh, _delete_isolated);
			}, py::arg("eh"), py::arg("delete_isolated_vertices")=true)
938

939
		.def("delete_face", [](Mesh& _self, OM::FaceHandle _fh, bool _delete_isolated) {
940
				if (!_self.has_vertex_status() && _delete_isolated) _self.request_vertex_status();
941
942
				if (!_self.has_halfedge_status()) _self.request_halfedge_status();
				if (!_self.has_edge_status()) _self.request_edge_status();
943
944
945
				if (!_self.has_face_status()) _self.request_face_status();
				_self.delete_face(_fh, _delete_isolated);
			}, py::arg("fh"), py::arg("delete_isolated_vertices")=true)
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962

		.def("vv", vv)
		.def("vih", vih)
		.def("voh", voh)
		.def("ve", ve)
		.def("vf", vf)

		.def("fv", fv)
		.def("fh", fh)
		.def("fe", fe)
		.def("ff", ff)

		.def("hl", hl)

		.def("is_boundary", is_boundary_hh)
		.def("is_boundary", is_boundary_eh)
		.def("is_boundary", is_boundary_vh)
Alexander Dielen's avatar
Alexander Dielen committed
963
		.def("is_boundary", is_boundary_fh, py::arg("fh"), py::arg("check_vertex")=false)
964
965
		.def("is_manifold", &Mesh::is_manifold)

Alexander Dielen's avatar
Alexander Dielen committed
966
		.def_static("is_triangles", &Mesh::is_triangles)
967

Alexander Dielen's avatar
Alexander Dielen committed
968
969
970
971
		.def_readonly_static("InvalidVertexHandle", &Mesh::InvalidVertexHandle)
		.def_readonly_static("InvalidHalfedgeHandle", &Mesh::InvalidHalfedgeHandle)
		.def_readonly_static("InvalidEdgeHandle", &Mesh::InvalidEdgeHandle)
		.def_readonly_static("InvalidFaceHandle", &Mesh::InvalidFaceHandle)
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989

		//======================================================================
		//  PolyMeshT
		//======================================================================

		.def("calc_edge_length", calc_edge_length_eh)
		.def("calc_edge_length", calc_edge_length_hh)
		.def("calc_edge_sqr_length", calc_edge_sqr_length_eh)
		.def("calc_edge_sqr_length", calc_edge_sqr_length_hh)

		.def("calc_sector_angle", &Mesh::calc_sector_angle)
		.def("calc_sector_area", &Mesh::calc_sector_area)

		.def("calc_dihedral_angle_fast", calc_dihedral_angle_fast_hh)
		.def("calc_dihedral_angle_fast", calc_dihedral_angle_fast_eh)
		.def("calc_dihedral_angle", calc_dihedral_angle_hh)
		.def("calc_dihedral_angle", calc_dihedral_angle_eh)

Alexander Dielen's avatar
Alexander Dielen committed
990
		.def("find_feature_edges", find_feature_edges, py::arg("angle_tresh")=OM::deg_to_rad(44.0))
991
992
993
994

		.def("split", split_fh_vh)
		.def("split", split_eh_vh)

995
996
		.def("split_copy", split_copy_fh_vh)

997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
		.def("update_normals", [](Mesh& _self) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
				}
				if (!_self.has_halfedge_normals()) {
					_self.request_halfedge_normals();
				}
				if (!_self.has_vertex_normals()) {
					_self.request_vertex_normals();
				}
				_self.update_normals();
			})

		.def("update_normal", [](Mesh& _self, OM::FaceHandle _fh) {
				if (!_self.has_face_normals()) _self.request_face_normals();
				_self.update_normal(_fh);
			})
1014

1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
		.def("update_face_normals", [](Mesh& _self) {
				if (!_self.has_face_normals()) _self.request_face_normals();
				_self.update_face_normals();
			})

		.def("update_normal", [](Mesh& _self, OM::HalfedgeHandle _hh, double _feature_angle) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				if (!_self.has_halfedge_normals()) {
					_self.request_halfedge_normals();
				}
				_self.update_normal(_hh, _feature_angle);
			}, py::arg("heh"), py::arg("feature_angle")=0.8)
1030

1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
		.def("update_halfedge_normals", [](Mesh& _self, double _feature_angle) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				if (!_self.has_halfedge_normals()) {
					_self.request_halfedge_normals();
				}
				_self.update_halfedge_normals(_feature_angle);
			}, py::arg("feature_angle")=0.8)

		.def("update_normal", [](Mesh& _self, OM::VertexHandle _vh) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				if (!_self.has_vertex_normals()) {
					_self.request_vertex_normals();
				}
				_self.update_normal(_vh);
			})
1052

1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
		.def("update_vertex_normals", [](Mesh& _self) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				if (!_self.has_vertex_normals()) {
					_self.request_vertex_normals();
				}
				_self.update_vertex_normals();
			})
1063
1064
1065

		.def("is_estimated_feature_edge", &Mesh::is_estimated_feature_edge)

Alexander Dielen's avatar
Alexander Dielen committed
1066
		.def_static("is_polymesh", &Mesh::is_polymesh)
1067
		.def("is_trimesh", &Mesh::is_trimesh)
1068

1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
		//======================================================================
		//  numpy calc_*
		//======================================================================

		.def("calc_face_normal", [](Mesh& _self, OM::FaceHandle _fh) {
				return vec2numpy(_self.calc_face_normal(_fh));
			})

		.def("calc_halfedge_normal", [](Mesh& _self, OM::HalfedgeHandle _heh, double _feature_angle) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				return vec2numpy(_self.calc_halfedge_normal(_heh, _feature_angle));
			}, py::arg("heh"), py::arg("feature_angle")=0.8)

		.def("calc_vertex_normal", [](Mesh& _self, OM::VertexHandle _vh) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				return vec2numpy(_self.calc_vertex_normal(_vh));
			})

		.def("calc_vertex_normal_fast", [](Mesh& _self, OM::VertexHandle _vh) {
				if (!_self.has_face_normals()) {
					_self.request_face_normals();
					_self.update_face_normals();
				}
				typename Mesh::Normal n;
				_self.calc_vertex_normal_fast(_vh, n);
				return vec2numpy(n);
			})

		.def("calc_vertex_normal_correct", [](Mesh& _self, OM::VertexHandle _vh) {
				typename Mesh::Normal n;
				_self.calc_vertex_normal_correct(_vh, n);
				return vec2numpy(n);
			})

		.def("calc_vertex_normal_loop", [](Mesh& _self, OM::VertexHandle _vh) {
				typename Mesh::Normal n;
				_self.calc_vertex_normal_loop(_vh, n);
				return vec2numpy(n);
			})

		.def("calc_face_centroid", [](Mesh& _self, OM::FaceHandle _fh) {
				return vec2numpy(_self.calc_face_centroid(_fh));
			})

		.def("calc_edge_vector", [](Mesh& _self, OM::EdgeHandle _eh) {
				return vec2numpy(_self.calc_edge_vector(_eh));
			})

		.def("calc_edge_vector", [](Mesh& _self, OM::HalfedgeHandle _heh) {
				return vec2numpy(_self.calc_edge_vector(_heh));
			})

		.def("calc_sector_vectors", [](Mesh& _self, OM::HalfedgeHandle _heh) {
				typename Mesh::Normal vec0;
				typename Mesh::Normal vec1;
				_self.calc_sector_vectors(_heh, vec0, vec1);
				return std::make_tuple(vec2numpy(vec0), vec2numpy(vec1));
			})

		.def("calc_sector_normal", [](Mesh& _self, OM::HalfedgeHandle _heh) {
				typename Mesh::Normal n;
				_self.calc_sector_normal(_heh, n);
				return vec2numpy(n);
			})

1140
		//======================================================================
1141
		//  numpy vector getter
1142
1143
		//======================================================================

1144
1145
1146
		.def("point", [](Mesh& _self, OM::VertexHandle _h) {
				return vec2numpy(_self, _self.point(_h));
			})
Alexander Dielen's avatar
Alexander Dielen committed
1147

1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
		.def("normal", [](Mesh& _self, OM::VertexHandle _h) {
				if (!_self.has_vertex_normals()) _self.request_vertex_normals();
				return vec2numpy(_self, _self.normal(_h));
			})
		.def("normal", [](Mesh& _self, OM::HalfedgeHandle _h) {
				if (!_self.has_halfedge_normals()) _self.request_halfedge_normals();
				return vec2numpy(_self, _self.normal(_h));
			})
		.def("normal", [](Mesh& _self, OM::FaceHandle _h) {
				if (!_self.has_face_normals()) _self.request_face_normals();
				return vec2numpy(_self, _self.normal(_h));
			})
Alexander Dielen's avatar
Alexander Dielen committed
1160

1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
		.def("color", [](Mesh& _self, OM::VertexHandle _h) {
				if (!_self.has_vertex_colors()) _self.request_vertex_colors();
				return vec2numpy(_self, _self.color(_h));
			})
		.def("color", [](Mesh& _self, OM::HalfedgeHandle _h) {
				if (!_self.has_halfedge_colors()) _self.request_halfedge_colors();
				return vec2numpy(_self, _self.color(_h));
			})
		.def("color", [](Mesh& _self, OM::EdgeHandle _h) {
				if (!_self.has_edge_colors()) _self.request_edge_colors();
				return vec2numpy(_self, _self.color(_h));
			})
		.def("color", [](Mesh& _self, OM::FaceHandle _h) {
				if (!_self.has_face_colors()) _self.request_face_colors();
				return vec2numpy(_self, _self.color(_h));
			})
Alexander Dielen's avatar
Alexander Dielen committed
1177

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
		.def("texcoord1D", [](Mesh& _self, OM::VertexHandle _h) {
				if (!_self.has_vertex_texcoords1D()) _self.request_vertex_texcoords1D();
				return flt2numpy(_self, _self.texcoord1D(_h));
			})
		.def("texcoord1D", [](Mesh& _self, OM::HalfedgeHandle _h) {
				if (!_self.has_halfedge_texcoords1D()) _self.request_halfedge_texcoords1D();
				return flt2numpy(_self, _self.texcoord1D(_h));
			})
		.def("texcoord2D", [](Mesh& _self, OM::VertexHandle _h) {
				if (!_self.has_vertex_texcoords2D()) _self.request_vertex_texcoords2D();
				return vec2numpy(_self, _self.texcoord2D(_h));
			})
		.def("texcoord2D", [](Mesh& _self, OM::HalfedgeHandle _h) {
				if (!_self.has_halfedge_texcoords2D()) _self.request_halfedge_texcoords2D();
				return vec2numpy(_self, _self.texcoord2D(_h));
			})
		.def("texcoord3D", [](Mesh& _self, OM::VertexHandle _h) {
				if (!_self.has_vertex_texcoords3D()) _self.request_vertex_texcoords3D();
				return vec2numpy(_self, _self.texcoord3D(_h));
			})
		.def("texcoord3D", [](Mesh& _self, OM::HalfedgeHandle _h) {
				if (!_self.has_halfedge_texcoords3D()) _self.request_halfedge_texcoords3D();
				return vec2numpy(_self, _self.texcoord3D(_h));
			})
Alexander Dielen's avatar
Alexander Dielen committed
1202

1203
1204
1205
1206
		//======================================================================
		//  numpy vector setter
		//======================================================================

1207
1208
1209
		.def("set_point", [](Mesh& _self, OM::VertexHandle _h, py::array_t<typename Point::value_type> _arr) {
				_self.point(_h) = Point(_arr.at(0), _arr.at(1), _arr.at(2));
			})
1210

1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
		.def("set_normal", [](Mesh& _self, OM::VertexHandle _h, py::array_t<typename Normal::value_type> _arr) {
				if (!_self.has_vertex_normals()) _self.request_vertex_normals();
				_self.set_normal(_h, typename Mesh::Normal(_arr.at(0), _arr.at(1), _arr.at(2)));
			})
		.def("set_normal", [](Mesh& _self, OM::HalfedgeHandle _h, py::array_t<typename Normal::value_type> _arr) {
				if (!_self.has_halfedge_normals()) _self.request_halfedge_normals();
				_self.set_normal(_h, typename Mesh::Normal(_arr.at(0), _arr.at(1), _arr.at(2)));
			})
		.def("set_normal", [](Mesh& _self, OM::FaceHandle _h, py::array_t<typename Normal::value_type> _arr) {
				if (!_self.has_face_normals()) _self.request_face_normals();
				_self.set_normal(_h, typename Mesh::Normal(_arr.at(0), _arr.at(1), _arr.at(2)));
			})
1223

1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
		.def("set_color", [](Mesh& _self, OM::VertexHandle _h, py::array_t<typename Color::value_type> _arr) {
				if(!_self.has_vertex_colors()) _self.request_vertex_colors();
				_self.set_color(_h, typename Mesh::Color(_arr.at(0), _arr.at(1), _arr.at(2), _arr.at(3)));
			})
		.def("set_color", [](Mesh& _self, OM::HalfedgeHandle _h, py::array_t<typename Color::value_type> _arr) {
				if(!_self.has_halfedge_colors()) _self.request_halfedge_colors();
				_self.set_color(_h, typename Mesh::Color(_arr.at(0), _arr.at(1), _arr.at(2), _arr.at(3)));
			})
		.def("set_color", [](Mesh& _self, OM::EdgeHandle _h, py::array_t<typename Color::value_type> _arr) {
				if(!_self.has_edge_colors()) _self.request_edge_colors();
				_self.set_color(_h, typename Mesh::Color(_arr.at(0), _arr.at(1), _arr.at(2), _arr.at(3)));
			})
		.def("set_color", [](Mesh& _self, OM::FaceHandle _h, py::array_t<typename Color::value_type> _arr) {
				if(!_self.has_face_colors()) _self.request_face_colors();
				_self.set_color(_h, typename Mesh::Color(_arr.at(0), _arr.at(1), _arr.at(2), _arr.at(3)));
			})
1240

1241
1242
1243
1244
1245
1246
1247
1248
		.def("set_texcoord1D", [](Mesh& _self, OM::VertexHandle _h, py::array_t<TexCoord1D> _arr) {
				if (!_self.has_vertex_texcoords1D()) _self.request_vertex_texcoords1D();
				_self.set_texcoord1D(_h, _arr.at(0));
			})
		.def("set_texcoord1D", [](Mesh& _self, OM::HalfedgeHandle _h, py::array_t<TexCoord1D> _arr) {
				if (!_self.has_halfedge_texcoords1D()) _self.request_halfedge_texcoords1D();
				_self.set_texcoord1D(_h, _arr.at(0));
			})
1249

1250
1251
1252
1253
1254
1255
1256
1257
		.def("set_texcoord2D", [](Mesh& _self, OM::VertexHandle _h, py::array_t<typename TexCoord2D::value_type> _arr) {
				if (!_self.has_vertex_texcoords2D()) _self.request_vertex_texcoords2D();
				_self.set_texcoord2D(_h, typename Mesh::TexCoord2D(_arr.at(0), _arr.at(1)));
			})
		.def("set_texcoord2D", [](Mesh& _self, OM::HalfedgeHandle _h, py::array_t<typename TexCoord2D::value_type> _arr) {
				if (!_self.has_halfedge_texcoords2D()) _self.request_halfedge_texcoords2D();
				_self.set_texcoord2D(_h, typename Mesh::TexCoord2D(_arr.at(0), _arr.at(1)));
			})
1258

1259
1260
1261
1262
1263
1264
1265
1266
		.def("set_texcoord3D", [](Mesh& _self, OM::VertexHandle _h, py::array_t<typename TexCoord3D::value_type> _arr) {
				if (!_self.has_vertex_texcoords3D()) _self.request_vertex_texcoords3D();
				_self.set_texcoord3D(_h, typename Mesh::TexCoord3D(_arr.at(0), _arr.at(1), _arr.at(2)));
			})
		.def("set_texcoord3D", [](Mesh& _self, OM::HalfedgeHandle _h, py::array_t<typename TexCoord3D::value_type> _arr) {
				if (!_self.has_halfedge_texcoords3D()) _self.request_halfedge_texcoords3D();
				_self.set_texcoord3D(_h, typename Mesh::TexCoord3D(_arr.at(0), _arr.at(1), _arr.at(2)));
			})
1267
1268
1269
1270
1271

		//======================================================================
		//  numpy matrix getter
		//======================================================================

1272
1273
1274
		.def("points", [](Mesh& _self) {
				return vec2numpy(_self, _self.point(OM::VertexHandle(0)), _self.n_vertices());
			})
1275

1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
		.def("vertex_normals", [](Mesh& _self) {
				if (!_self.has_vertex_normals()) _self.request_vertex_normals();
				return vec2numpy(_self, _self.normal(OM::VertexHandle(0)), _self.n_vertices());
			})
		.def("vertex_colors", [](Mesh& _self) {
				if (!_self.has_vertex_colors()) _self.request_vertex_colors();
				return vec2numpy(_self, _self.color(OM::VertexHandle(0)), _self.n_vertices());
			})
		.def("vertex_texcoords1D", [](Mesh& _self) {
				if (!_self.has_vertex_texcoords1D()) _self.request_vertex_texcoords1D();
				return flt2numpy(_self, _self.texcoord1D(OM::VertexHandle(0)), _self.n_vertices());
			})
		.def("vertex_texcoords2D", [](Mesh& _self) {
				if (!_self.has_vertex_texcoords2D()) _self.request_vertex_texcoords2D();
				return vec2numpy(_self, _self.texcoord2D(OM::VertexHandle(0)), _self.n_vertices());
			})
		.def("vertex_texcoords3D", [](Mesh& _self) {
				if (!_self.has_vertex_texcoords3D()) _self.request_vertex_texcoords3D();
				return vec2numpy(_self, _self.texcoord3D(OM::VertexHandle(0)), _self.n_vertices());
			})