PyGEL3D 0.8.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pygel3d/PyGEL.dll ADDED
Binary file
pygel3d/__init__.py ADDED
@@ -0,0 +1,389 @@
1
+ """ PyGEL is a collection of classes and functions for geometry processing tasks.
2
+ Especially tasks that involve 3D polygonal meshes, but there is also a graph component
3
+ useful e.g. for skeletonization. The PyGEL package is called pygel3d and it contains
4
+ five modules:
5
+
6
+ hmesh provides Manifold which is a class that represents polygonal meshes using the
7
+ halfedge representation. hmesh also provides a slew of functions for manipulating
8
+ polygonal meshes and the MeshDistance class which makes it simple to compute the
9
+ distance to a triangle mesh.
10
+
11
+ graph contains the Graph class which is used for graphs: i.e. collections of
12
+ vertices (in 3D) connected by edges. Unlike a Manifold, a Graph does not have to
13
+ represent a surface. There are also some associated functions which may be useful:
14
+ in particular, there is the LS_skeleton function which computes a curve skeleton
15
+ from a Graph and returns the result as a new Graph.
16
+
17
+ gl_display provides the Viewer class which makes it simple to visualize meshes and
18
+ graphs.
19
+
20
+ jupyter_display makes it easy to use PyGEL in the context of a Jupyter Notebook.
21
+ This module contains a function that allows you to create a widget for interactively
22
+ visualizing a mesh or a graph in a Notebook. The feature is based on the Plotly
23
+ library and it is possible to export the resulting notebooks to HTML while preserving
24
+ the interactive 3D graphics in the notebook.
25
+
26
+ spatial contains the I3DTree class which is simply a kD-tree specialized for mapping
27
+ 3D points to integers - typically indices. Of course, scipy.spatial has a more
28
+ generic class, so this is perhaps not the most important part of PyGEL.
29
+
30
+ PyGEL is based on the C++ GEL library and provides a Python interface for most but not
31
+ all of the functionality of GEL.
32
+ """
33
+ def _read_version():
34
+ from pathlib import Path
35
+ for parent in list(Path(__file__).resolve().parents)[:6]:
36
+ vf = parent / "VERSION"
37
+ if vf.is_file():
38
+ return vf.read_text(encoding="utf-8").strip()
39
+ try:
40
+ from importlib.metadata import version as _pkg_version
41
+ return _pkg_version("PyGEL3D")
42
+ except Exception:
43
+ return "0.0.0"
44
+
45
+ __version__ = _read_version()
46
+
47
+ __all__ = ["hmesh", "graph", "gl_display", "jupyter_display", "spatial", "experimental"]
48
+
49
+ import os
50
+ from sys import platform, prefix
51
+ import ctypes as ct
52
+ import numpy as np
53
+ from numpy.ctypeslib import ndpointer
54
+
55
+ def _get_script_path():
56
+ return os.path.dirname(__file__)
57
+
58
+ def _get_lib_name():
59
+ if platform == "darwin":
60
+ return "libPyGEL.dylib"
61
+ if platform == "win32":
62
+ return "PyGEL.dll"
63
+ return "libPyGEL.so"
64
+
65
+ def _load_library():
66
+ name = _get_lib_name()
67
+ path = os.path.join(_get_script_path(), name)
68
+ if not os.path.isfile(path):
69
+ raise ImportError(
70
+ f"pygel3d: native library {name} not found at {path}. "
71
+ "Reinstall from PyPI (`pip install --force-reinstall PyGEL3D`) "
72
+ "or build from source."
73
+ )
74
+ try:
75
+ return ct.cdll.LoadLibrary(path)
76
+ except OSError as exc:
77
+ hint = ""
78
+ if platform.startswith("linux"):
79
+ hint = (
80
+ " On Linux the library needs system OpenGL "
81
+ "(e.g. `sudo apt-get install libgl1`)."
82
+ )
83
+ raise ImportError(
84
+ f"pygel3d: failed to load {path}: {exc}.{hint}"
85
+ ) from exc
86
+
87
+ # Load PyGEL the Python GEL bridge library
88
+ lib_py_gel = _load_library()
89
+
90
+ # An InvalidIndex is just a special integer value.
91
+ InvalidIndex = ct.c_size_t.in_dll(lib_py_gel, "InvalidIndex").value
92
+
93
+ # The following many lines explitize the arguments and return types of the C API
94
+
95
+ # IntVector
96
+ lib_py_gel.IntVector_new.restype = ct.c_void_p
97
+ lib_py_gel.IntVector_get.argtypes = (ct.c_void_p, ct.c_size_t)
98
+ lib_py_gel.IntVector_size.argtypes = (ct.c_void_p,)
99
+ lib_py_gel.IntVector_size.restype = ct.c_size_t
100
+ lib_py_gel.IntVector_delete.argtypes = (ct.c_void_p,)
101
+
102
+
103
+ # Vec3dVector
104
+ lib_py_gel.Vec3dVector_new.restype = ct.c_void_p
105
+ lib_py_gel.Vec3dVector_get.argtypes = (ct.c_void_p, ct.c_size_t)
106
+ lib_py_gel.Vec3dVector_get.restype = ct.POINTER(ct.c_double)
107
+ lib_py_gel.Vec3dVector_size.argtypes = (ct.c_void_p,)
108
+ lib_py_gel.Vec3dVector_size.restype = ct.c_size_t
109
+ lib_py_gel.Vec3dVector_delete.argtypes = (ct.c_void_p,)
110
+
111
+ # I3DTree
112
+ lib_py_gel.I3DTree_new.restype = ct.c_void_p
113
+ lib_py_gel.I3DTree_delete.argtypes = (ct.c_void_p,)
114
+ lib_py_gel.I3DTree_insert.argtypes = (ct.c_void_p, ct.c_double, ct.c_double, ct.c_double, ct.c_size_t)
115
+ lib_py_gel.I3DTree_build.argtypes = (ct.c_void_p,)
116
+ lib_py_gel.I3DTree_closest_point.argtypes = (ct.c_void_p, ct.c_double, ct.c_double, ct.c_double, ct.c_double, ct.POINTER(ct.c_double*3), ct.POINTER(ct.c_size_t))
117
+ lib_py_gel.I3DTree_in_sphere.argtypes = (ct.c_void_p, ct.c_double, ct.c_double, ct.c_double, ct.c_double, ct.c_void_p,ct.c_void_p)
118
+
119
+ # Manifold class
120
+ lib_py_gel.Manifold_from_triangles.argtypes = (ct.c_size_t,ct.c_size_t, ndpointer(np.float64, ndim=2, flags='C'), ndpointer(ct.c_int, ndim=2, flags='C'))
121
+ lib_py_gel.Manifold_from_triangles.restype = ct.c_void_p
122
+ lib_py_gel.Manifold_from_points.argtypes = (ct.c_size_t,ndpointer(np.float64, ndim=2, flags='C'), ndpointer(np.float64, shape=3),ndpointer(np.float64, shape=3))
123
+ lib_py_gel.Manifold_from_points.restype = ct.c_void_p
124
+ lib_py_gel.Manifold_new.restype = ct.c_void_p
125
+ lib_py_gel.Manifold_copy.restype = ct.c_void_p
126
+ lib_py_gel.Manifold_copy.argtypes = (ct.c_void_p,)
127
+ lib_py_gel.Manifold_merge.argtypes = (ct.c_void_p,ct.c_void_p)
128
+ lib_py_gel.Manifold_delete.argtypes = (ct.c_void_p,)
129
+ lib_py_gel.Manifold_positions.restype = ct.c_size_t
130
+ lib_py_gel.Manifold_positions.argtypes = (ct.c_void_p, ct.POINTER(ct.POINTER(ct.c_double)))
131
+ lib_py_gel.Manifold_no_allocated_vertices.restype = ct.c_size_t
132
+ lib_py_gel.Manifold_no_allocated_vertices.argtypes = (ct.c_void_p,)
133
+ lib_py_gel.Manifold_no_allocated_faces.restype = ct.c_size_t
134
+ lib_py_gel.Manifold_no_allocated_faces.argtypes = (ct.c_void_p,)
135
+ lib_py_gel.Manifold_no_allocated_halfedges.restype = ct.c_size_t
136
+ lib_py_gel.Manifold_no_allocated_halfedges.argtypes = (ct.c_void_p,)
137
+ lib_py_gel.Manifold_vertices.restype = ct.c_size_t
138
+ lib_py_gel.Manifold_vertices.argtypes = (ct.c_void_p, ct.c_void_p)
139
+ lib_py_gel.Manifold_faces.restype = ct.c_size_t
140
+ lib_py_gel.Manifold_faces.argtypes = (ct.c_void_p, ct.c_void_p)
141
+ lib_py_gel.Manifold_halfedges.restype = ct.c_size_t
142
+ lib_py_gel.Manifold_halfedges.argtypes = (ct.c_void_p,ct.c_void_p)
143
+ lib_py_gel.Manifold_circulate_vertex.restype = ct.c_size_t
144
+ lib_py_gel.Manifold_circulate_vertex.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_char, ct.c_void_p)
145
+ lib_py_gel.Manifold_circulate_face.restype = ct.c_size_t
146
+ lib_py_gel.Manifold_circulate_face.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_char, ct.c_void_p)
147
+ lib_py_gel.Manifold_add_face.argtypes = (ct.c_void_p, ct.c_size_t, ndpointer(np.float64, ndim=2, flags='C'))
148
+ lib_py_gel.Manifold_remove_face.restype = ct.c_bool
149
+ lib_py_gel.Manifold_remove_face.argtypes = (ct.c_void_p, ct.c_size_t)
150
+ lib_py_gel.Manifold_remove_edge.restype = ct.c_bool
151
+ lib_py_gel.Manifold_remove_edge.argtypes = (ct.c_void_p, ct.c_size_t)
152
+ lib_py_gel.Manifold_remove_vertex.restype = ct.c_bool
153
+ lib_py_gel.Manifold_remove_vertex.argtypes = (ct.c_void_p, ct.c_size_t)
154
+ lib_py_gel.Manifold_vertex_in_use.restype = ct.c_bool
155
+ lib_py_gel.Manifold_vertex_in_use.argtypes = (ct.c_void_p,ct.c_size_t)
156
+ lib_py_gel.Manifold_face_in_use.restype = ct.c_bool
157
+ lib_py_gel.Manifold_face_in_use.argtypes = (ct.c_void_p, ct.c_size_t)
158
+ lib_py_gel.Manifold_halfedge_in_use.restype = ct.c_bool
159
+ lib_py_gel.Manifold_halfedge_in_use.argtypes = (ct.c_void_p, ct.c_size_t)
160
+ lib_py_gel.Manifold_flip_edge.restype = ct.c_bool
161
+ lib_py_gel.Manifold_flip_edge.argtypes = (ct.c_void_p, ct.c_size_t)
162
+ lib_py_gel.Manifold_collapse_edge.restype = ct.c_bool
163
+ lib_py_gel.Manifold_collapse_edge.argtypes = (ct.c_void_p,ct.c_size_t,ct.c_bool)
164
+ lib_py_gel.Manifold_split_face_by_edge.restype = ct.c_size_t
165
+ lib_py_gel.Manifold_split_face_by_edge.argtypes = (ct.c_void_p, ct.c_size_t,ct.c_size_t,ct.c_size_t)
166
+ lib_py_gel.Manifold_split_face_by_vertex.restype = ct.c_size_t
167
+ lib_py_gel.Manifold_split_face_by_vertex.argtypes = (ct.c_void_p, ct.c_size_t)
168
+ lib_py_gel.Manifold_split_edge.restype = ct.c_size_t
169
+ lib_py_gel.Manifold_split_edge.argtypes = (ct.c_void_p, ct.c_size_t)
170
+ lib_py_gel.Manifold_stitch_boundary_edges.restype = ct.c_bool
171
+ lib_py_gel.Manifold_stitch_boundary_edges.argtypes = (ct.c_void_p, ct.c_size_t,ct.c_size_t)
172
+ lib_py_gel.Manifold_merge_faces.restype = ct.c_bool
173
+ lib_py_gel.Manifold_merge_faces.argtypes = (ct.c_void_p, ct.c_size_t,ct.c_size_t)
174
+ lib_py_gel.Manifold_close_hole.argtypes = (ct.c_void_p,ct.c_size_t)
175
+ lib_py_gel.Manifold_cleanup.argtypes = (ct.c_void_p,)
176
+
177
+
178
+ # Walker is a helper class assisting us in navigating a mesh.
179
+ # Not directly expose in PyGEL3D
180
+ lib_py_gel.Walker_next_halfedge.restype = ct.c_size_t
181
+ lib_py_gel.Walker_next_halfedge.argtypes = (ct.c_void_p, ct.c_size_t)
182
+ lib_py_gel.Walker_prev_halfedge.restype = ct.c_size_t
183
+ lib_py_gel.Walker_prev_halfedge.argtypes = (ct.c_void_p, ct.c_size_t)
184
+ lib_py_gel.Walker_opposite_halfedge.restype = ct.c_size_t
185
+ lib_py_gel.Walker_opposite_halfedge.argtypes = (ct.c_void_p, ct.c_size_t)
186
+ lib_py_gel.Walker_incident_face.restype = ct.c_size_t
187
+ lib_py_gel.Walker_incident_face.argtypes = (ct.c_void_p, ct.c_size_t)
188
+ lib_py_gel.Walker_incident_vertex.restype = ct.c_size_t
189
+ lib_py_gel.Walker_incident_vertex.argtypes = (ct.c_void_p, ct.c_size_t)
190
+
191
+ # A list of helper functions
192
+ lib_py_gel.is_halfedge_at_boundary.restype = ct.c_bool
193
+ lib_py_gel.is_halfedge_at_boundary.argtypes = (ct.c_void_p, ct.c_size_t)
194
+ lib_py_gel.is_vertex_at_boundary.restype = ct.c_bool
195
+ lib_py_gel.is_vertex_at_boundary.argtypes = (ct.c_void_p, ct.c_size_t)
196
+ lib_py_gel.length.restype = ct.c_double
197
+ lib_py_gel.length.argtypes = (ct.c_void_p, ct.c_size_t)
198
+ lib_py_gel.boundary_edge.restype = ct.c_bool
199
+ lib_py_gel.boundary_edge.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_size_t)
200
+ lib_py_gel.valency.restype = ct.c_size_t
201
+ lib_py_gel.valency.argtypes = (ct.c_void_p, ct.c_size_t)
202
+ lib_py_gel.vertex_normal.argtypes = (ct.c_void_p, ct.c_size_t, ndpointer(dtype=np.float64, shape=(3,)))
203
+ lib_py_gel.connected.restype = ct.c_bool
204
+ lib_py_gel.connected.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_size_t)
205
+ lib_py_gel.no_edges.restype = ct.c_size_t
206
+ lib_py_gel.no_edges.argtypes = (ct.c_void_p, ct.c_size_t)
207
+ lib_py_gel.face_normal.argtypes = (ct.c_void_p, ct.c_size_t, ndpointer(dtype=np.float64, shape=(3,)))
208
+ lib_py_gel.area.restype = ct.c_double
209
+ lib_py_gel.area.argtypes = (ct.c_void_p, ct.c_size_t)
210
+ lib_py_gel.one_ring_area.restype = ct.c_double
211
+ lib_py_gel.one_ring_area.argtypes = (ct.c_void_p, ct.c_size_t)
212
+ lib_py_gel.mixed_area.restype = ct.c_double
213
+ lib_py_gel.mixed_area.argtypes = (ct.c_void_p, ct.c_size_t)
214
+ lib_py_gel.gaussian_curvature.restype = ct.c_double
215
+ lib_py_gel.gaussian_curvature.argtypes = (ct.c_void_p, ct.c_size_t)
216
+ lib_py_gel.mean_curvature.restype = ct.c_double
217
+ lib_py_gel.mean_curvature.argtypes = (ct.c_void_p, ct.c_size_t)
218
+ lib_py_gel.principal_curvatures.argtypes = (ct.c_void_p, ct.c_size_t, ndpointer(dtype=np.float64, shape=(8,)))
219
+
220
+
221
+ lib_py_gel.total_area.restype = ct.c_double
222
+ lib_py_gel.total_area.argtypes = (ct.c_void_p,)
223
+ lib_py_gel.volume.restype = ct.c_double
224
+ lib_py_gel.volume.argtypes = (ct.c_void_p,)
225
+ lib_py_gel.perimeter.restype = ct.c_double
226
+ lib_py_gel.perimeter.argtypes = (ct.c_void_p, ct.c_size_t)
227
+ lib_py_gel.centre.argtypes = (ct.c_void_p, ct.c_size_t, ndpointer(dtype=np.float64, shape=(3,)))
228
+ lib_py_gel.valid.restype = ct.c_bool
229
+ lib_py_gel.valid.argtypes = (ct.c_void_p,)
230
+ lib_py_gel.closed.restype = ct.c_bool
231
+ lib_py_gel.closed.argtypes = (ct.c_void_p,)
232
+ lib_py_gel.bbox.argtypes = (ct.c_void_p, ndpointer(dtype=np.float64, shape=(3,)),ndpointer(dtype=np.float64, shape=(3,)))
233
+ lib_py_gel.bsphere.argtypes = (ct.c_void_p, ndpointer(dtype=np.float64, shape=(3,)), ct.POINTER(ct.c_double))
234
+ lib_py_gel.stitch_mesh.argtypes = (ct.c_void_p,ct.c_double)
235
+ lib_py_gel.stitch_mesh.restype = ct.c_int
236
+ lib_py_gel.obj_save.argtypes = (ct.c_char_p, ct.c_void_p)
237
+ lib_py_gel.off_save.argtypes = (ct.c_char_p, ct.c_void_p)
238
+ lib_py_gel.x3d_save.argtypes = (ct.c_char_p, ct.c_void_p)
239
+ lib_py_gel.obj_load.argtypes = (ct.c_char_p, ct.c_void_p)
240
+ lib_py_gel.off_load.argtypes = (ct.c_char_p, ct.c_void_p)
241
+ lib_py_gel.ply_load.argtypes = (ct.c_char_p, ct.c_void_p)
242
+ lib_py_gel.x3d_load.argtypes = (ct.c_char_p, ct.c_void_p)
243
+ lib_py_gel.rsr_recon.argtypes = (ct.c_void_p, ndpointer(ndim=2, dtype=ct.c_double,flags='F'), ndpointer(ndim=2, dtype=ct.c_double,flags='F'), ct.c_int, ct.c_int, ct.c_bool, ct.c_int, ct.c_int, ct.c_double, ct.c_double, ct.c_int)
244
+ lib_py_gel.hrsr_recon.argtypes = (ct.c_void_p, ndpointer(ndim=2, dtype=ct.c_double,flags='F'), ndpointer(ndim=2, dtype=ct.c_double,flags='F'), ct.c_size_t, ct.c_size_t, ct.c_int, ct.c_bool, ct.c_int, ct.c_int, ct.c_double, ct.c_double, ct.c_int, ct.c_bool)
245
+ lib_py_gel.remove_caps.argtypes = (ct.c_void_p, ct.c_float)
246
+ lib_py_gel.remove_needles.argtypes = (ct.c_void_p, ct.c_float, ct.c_bool)
247
+ lib_py_gel.close_holes.argtypes = (ct.c_void_p,ct.c_int)
248
+ lib_py_gel.flip_orientation.argtypes = (ct.c_void_p,)
249
+ lib_py_gel.merge_coincident_boundary_vertices.argtypes = (ct.c_void_p, ct.c_double)
250
+ lib_py_gel.minimize_curvature.argtypes = (ct.c_void_p,ct.c_bool)
251
+ lib_py_gel.minimize_dihedral_angle.argtypes = (ct.c_void_p, ct.c_int, ct.c_bool, ct.c_bool, ct.c_double)
252
+ lib_py_gel.maximize_min_angle.argtypes = (ct.c_void_p,ct.c_float,ct.c_bool)
253
+ lib_py_gel.optimize_valency.argtypes = (ct.c_void_p,ct.c_bool)
254
+ lib_py_gel.randomize_mesh.argtypes = (ct.c_void_p,ct.c_int)
255
+ lib_py_gel.quadric_simplify.argtypes = (ct.c_void_p,ct.c_double,ct.c_double,ct.c_double)
256
+ lib_py_gel.average_edge_length.argtypes = (ct.c_void_p,)
257
+ lib_py_gel.average_edge_length.restype = ct.c_float
258
+ lib_py_gel.median_edge_length.argtypes = (ct.c_void_p,)
259
+ lib_py_gel.median_edge_length.restype = ct.c_float
260
+ lib_py_gel.refine_edges.argtypes = (ct.c_void_p,ct.c_float)
261
+ lib_py_gel.refine_edges.restype = ct.c_int
262
+ lib_py_gel.cc_split.argtypes = (ct.c_void_p,)
263
+ lib_py_gel.loop_split.argtypes = (ct.c_void_p,)
264
+ lib_py_gel.root3_subdivide.argtypes = (ct.c_void_p,)
265
+ lib_py_gel.rootCC_subdivide.argtypes = (ct.c_void_p,)
266
+ lib_py_gel.butterfly_subdivide.argtypes = (ct.c_void_p,)
267
+ lib_py_gel.cc_smooth.argtypes = (ct.c_void_p,)
268
+ lib_py_gel.volume_preserving_cc_smooth.argtypes = (ct.c_void_p,ct.c_int)
269
+ lib_py_gel.regularize_quads.argtypes = (ct.c_void_p,ct.c_float,ct.c_float,ct.c_int)
270
+ lib_py_gel.loop_smooth.argtypes = (ct.c_void_p,)
271
+ lib_py_gel.ear_clip_triangulate.argtypes = (ct.c_void_p,)
272
+ lib_py_gel.shortest_edge_triangulate.argtypes = (ct.c_void_p,)
273
+ lib_py_gel.graph_to_feq.argtypes = (ct.c_void_p, ct.c_void_p, ndpointer(dtype=np.float64, ndim=1), ct.c_bool, ct.c_bool)
274
+ lib_py_gel.graph_to_feq.restype = ct.c_void_p
275
+ lib_py_gel.non_rigid_registration.argtypes = (ct.c_void_p, ct.c_void_p)
276
+ lib_py_gel.taubin_smooth.argtypes = (ct.c_void_p, ct.c_int)
277
+ lib_py_gel.laplacian_smooth.argtypes = (ct.c_void_p, ct.c_float, ct.c_int)
278
+ lib_py_gel.anisotropic_smooth.argtypes = (ct.c_void_p, ct.c_float, ct.c_int)
279
+ lib_py_gel.volumetric_isocontour.argtypes = (ct.c_void_p, ct.c_int, ct.c_int, ct.c_int, ndpointer(ndim=3, dtype=ct.c_float,flags='F'), ndpointer(dtype=ct.c_double,shape=(3,)), ndpointer(dtype=ct.c_double,shape=(3,)), ct.c_float, ct.c_bool, ct.c_bool, ct.c_bool )
280
+ lib_py_gel.extrude_faces.argtypes = (ct.c_void_p, ndpointer(dtype=ct.c_int, ndim=1), ct.c_int, ct.c_void_p)
281
+ lib_py_gel.kill_face_loop.argtypes = (ct.c_void_p,)
282
+ lib_py_gel.kill_degenerate_face_loops.argtypes = (ct.c_void_p,ct.c_double)
283
+ lib_py_gel.stable_marriage_registration.argtypes = (ct.c_void_p,ct.c_void_p)
284
+ lib_py_gel.stable_marriage_registration.restype = ct.c_int
285
+ lib_py_gel.connected_components.argtypes = (ct.c_void_p,)
286
+ lib_py_gel.connected_components.restype = ct.c_void_p
287
+ lib_py_gel.mesh_vec_size.argtypes = (ct.c_void_p,)
288
+ lib_py_gel.mesh_vec_size.restype = ct.c_size_t
289
+ lib_py_gel.mesh_vec_get.argtypes = (ct.c_void_p, ct.c_size_t)
290
+ lib_py_gel.mesh_vec_get.restype = ct.c_void_p
291
+ lib_py_gel.mesh_vec_del.argtypes = (ct.c_void_p,)
292
+ lib_py_gel.count_boundary_curves.argtypes = (ct.c_void_p,)
293
+ lib_py_gel.count_boundary_curves.restype = ct.c_int
294
+ lib_py_gel.sphere_delaunay.argtypes = (ct.c_void_p, ndpointer(dtype=ct.c_double, flags='C'), ct.c_int)
295
+ lib_py_gel.sphere_delaunay.restype = ct.c_void_p
296
+
297
+ # MeshDistance allows us to compute the signed distance to a mesh
298
+ lib_py_gel.MeshDistance_new.restype = ct.c_void_p
299
+ lib_py_gel.MeshDistance_new.argtypes = (ct.c_void_p,)
300
+ lib_py_gel.MeshDistance_signed_distance.argtypes = (ct.c_void_p,ct.c_int, ndpointer(dtype=ct.c_float,flags='C'),ndpointer(dtype=ct.c_float,flags='C',ndim=1),ct.c_float)
301
+ lib_py_gel.MeshDistance_ray_inside_test.argtypes = (ct.c_void_p,ct.c_int, ndpointer(dtype=ct.c_float,flags='C'),ndpointer(dtype=ct.c_int,flags='C',ndim=1),ct.c_int)
302
+ lib_py_gel.MeshDistance_ray_intersect.argtypes = (ct.c_void_p,ndpointer(dtype=ct.c_float,shape=3),ndpointer(dtype=ct.c_float,shape=3),ct.POINTER(ct.c_float))
303
+ lib_py_gel.MeshDistance_ray_intersect.restype = ct.c_bool
304
+ lib_py_gel.MeshDistance_delete.argtypes = (ct.c_void_p,)
305
+
306
+ # The Graph class
307
+ lib_py_gel.Graph_new.restype = ct.c_void_p
308
+ lib_py_gel.Graph_copy.restype = ct.c_void_p
309
+ lib_py_gel.Graph_copy.argtypes = (ct.c_void_p,)
310
+ lib_py_gel.Graph_delete.argtypes = (ct.c_void_p,)
311
+ lib_py_gel.Graph_clear.argtypes = (ct.c_void_p,)
312
+ lib_py_gel.Graph_cleanup.argtypes = (ct.c_void_p,)
313
+ lib_py_gel.Graph_nodes.argtypes = (ct.c_void_p, ct.c_void_p)
314
+ lib_py_gel.Graph_nodes.restype = ct.c_size_t
315
+ lib_py_gel.Graph_neighbors.restype = ct.c_size_t
316
+ lib_py_gel.Graph_neighbors.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_void_p, ct.c_char)
317
+ lib_py_gel.Graph_positions.argtypes = (ct.c_void_p,ct.POINTER(ct.POINTER(ct.c_double)))
318
+ lib_py_gel.Graph_positions.restype = ct.c_size_t
319
+ lib_py_gel.Graph_average_edge_length.argtypes = (ct.c_void_p,)
320
+ lib_py_gel.Graph_average_edge_length.restype = ct.c_double
321
+ lib_py_gel.Graph_add_node.argtypes = (ct.c_void_p, ndpointer(ct.c_double))
322
+ lib_py_gel.Graph_add_node.restype = ct.c_size_t
323
+ lib_py_gel.Graph_remove_node.argtypes = (ct.c_void_p, ct.c_size_t)
324
+ lib_py_gel.Graph_node_in_use.argtypes = (ct.c_void_p, ct.c_size_t)
325
+ lib_py_gel.Graph_node_in_use.restype = ct.c_bool
326
+ lib_py_gel.Graph_connect_nodes.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_size_t)
327
+ lib_py_gel.Graph_connect_nodes.restype = ct.c_size_t
328
+ lib_py_gel.Graph_disconnect_nodes.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_size_t)
329
+ lib_py_gel.Graph_merge_nodes.argtypes = (ct.c_void_p, ct.c_size_t, ct.c_size_t, ct.c_bool)
330
+
331
+ # Graph functions
332
+ lib_py_gel.graph_from_mesh.argtypes = (ct.c_void_p, ct.c_void_p)
333
+ lib_py_gel.graph_load.argtypes = (ct.c_void_p, ct.c_char_p)
334
+ lib_py_gel.graph_load.restype = ct.c_void_p
335
+ lib_py_gel.graph_save.argtypes = (ct.c_void_p, ct.c_char_p)
336
+ lib_py_gel.graph_save.restype = ct.c_bool
337
+ lib_py_gel.graph_to_mesh_cyl.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_float)
338
+ lib_py_gel.graph_to_mesh_cyl.restype = ct.c_void_p
339
+ lib_py_gel.graph_to_mesh_iso.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_float, ct.c_int)
340
+ lib_py_gel.graph_to_mesh_iso.restype = ct.c_void_p
341
+ lib_py_gel.graph_smooth.argtypes = (ct.c_void_p, ct.c_int, ct.c_float)
342
+ lib_py_gel.graph_edge_contract.argtypes = (ct.c_void_p, ct.c_double)
343
+ lib_py_gel.graph_prune.argtypes = (ct.c_void_p,)
344
+ lib_py_gel.graph_saturate.argtypes = (ct.c_void_p, ct.c_int, ct.c_double, ct.c_double)
345
+ lib_py_gel.graph_LS_skeleton.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_bool)
346
+ lib_py_gel.graph_MSLS_skeleton.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_int)
347
+ lib_py_gel.graph_front_skeleton.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_int, ndpointer(dtype=np.float64,flags='C'), ct.c_int)
348
+ lib_py_gel.graph_combined_skeleton.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_int, ndpointer(dtype=np.float64,flags='C'), ct.c_int)
349
+ lib_py_gel.graph_minimum_spanning_tree.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_int)
350
+ lib_py_gel.graph_close_chordless_cycles.argtypes = (ct.c_void_p, ct.c_int, ct.c_int, ct.c_double)
351
+
352
+ class IntVector:
353
+ """ Vector of integer values.
354
+ This is a simple class that implements iteration and index based
355
+ retrieval. Allocation happens in a call to libPyGEL. Since memory
356
+ is managed by the PyGEL library, the vector can be resized by library
357
+ functions. Not used directly by PyGEL3D users."""
358
+ def __init__(self):
359
+ self.obj = lib_py_gel.IntVector_new(0)
360
+ def __del__(self):
361
+ lib_py_gel.IntVector_delete(self.obj)
362
+ def __len__(self):
363
+ return int(lib_py_gel.IntVector_size(self.obj))
364
+ def __getitem__(self, key: int):
365
+ return lib_py_gel.IntVector_get(self.obj,key)
366
+ def __iter__(self):
367
+ n = lib_py_gel.IntVector_size(self.obj)
368
+ for i in range(0,n):
369
+ yield lib_py_gel.IntVector_get(self.obj, i)
370
+
371
+ class Vec3dVector:
372
+ """ Vector of 3D vectors.
373
+ This is a simple class that implements iteration and index based
374
+ retrieval. Allocation happens in a call to libPyGEL. Since memory
375
+ is managed by the PyGEL library, the vector can be resized by library
376
+ functions. Not used directly by PyGEL3D users."""
377
+ def __init__(self):
378
+ self.obj = lib_py_gel.Vec3dVector_new(0)
379
+ def __del__(self):
380
+ lib_py_gel.Vec3dVector_delete(self.obj)
381
+ def __len__(self):
382
+ return int(lib_py_gel.Vec3dVector_size(self.obj))
383
+ def __getitem__(self,key: int):
384
+ return lib_py_gel.Vec3dVector_get(self.obj,key)
385
+ def __iter__(self):
386
+ n = lib_py_gel.Vec3dVector_size(self.obj)
387
+ for i in range(0,n):
388
+ data = lib_py_gel.Vec3dVector_get(self.obj, i)
389
+ yield [data[0], data[1], data[2]]
@@ -0,0 +1 @@
1
+ __all__ = ["hmesh"]
@@ -0,0 +1,32 @@
1
+ import numpy as np
2
+ import ctypes as ct
3
+ from numpy.typing import ArrayLike
4
+ from pygel3d.hmesh import Manifold, _as_vec3_f
5
+ from pygel3d import lib_py_gel
6
+
7
+ def rsr_recon(verts: ArrayLike,
8
+ normals: ArrayLike=None,
9
+ use_Euclidean_distance: bool=False,
10
+ genus: int=-1,
11
+ k: int=70,
12
+ r: float=20,
13
+ theta: float=60,
14
+ n: int=50) -> Manifold:
15
+ """ RsR Reconstruction. The first argument, verts, is the point cloud. The next argument,
16
+ normals, are the normals associated with the vertices or empty list (default) if normals
17
+ need to be estimated during reconstruction. use_Euclidean_distance should be true if we
18
+ can use the Euclidean rather than projected distance. Set to true only for noise free
19
+ point clouds. genus is used to constrain the genus of the reconstructed object. genus
20
+ defaults to -1, meaning unknown genus. k is the number of nearest neighbors for each point,
21
+ r is the maximum distance to farthest neighbor measured in multiples of average distance,
22
+ theta is the threshold on angles between normals: two points are only connected if the angle
23
+ between their normals is less than theta. Finally, n is the threshold on the distance between
24
+ vertices that are connected by handle edges (check paper). For large n, it is harder for
25
+ the algorithm to add handles. """
26
+ m = Manifold()
27
+ verts_data, n_verts = _as_vec3_f(verts)
28
+ normal_data, n_normal = _as_vec3_f(normals)
29
+
30
+ lib_py_gel.rsr_recon_experimental(m.obj, verts_data, normal_data, n_verts, n_normal,
31
+ use_Euclidean_distance, genus, k, r, theta, n)
32
+ return m
pygel3d/gl_display.py ADDED
@@ -0,0 +1,127 @@
1
+ """ This modules provides an OpenGL based viewer for graphs and meshes """
2
+
3
+ from numpy.typing import ArrayLike
4
+ from typing import Self
5
+ from pygel3d import lib_py_gel
6
+ from pygel3d.hmesh import Manifold
7
+ from pygel3d.graph import Graph
8
+ import ctypes as ct
9
+ import numpy as np
10
+ from os import getcwd, chdir
11
+
12
+ try:
13
+ lib_py_gel.GLManifoldViewer_new.restype = ct.c_void_p
14
+ lib_py_gel.GLManifoldViewer_clone_controller.argtypes = (ct.c_void_p, ct.c_void_p)
15
+ lib_py_gel.GLManifoldViewer_clone_controller.restype = None
16
+ lib_py_gel.GLManifoldViewer_delete.argtypes = (ct.c_void_p,)
17
+ lib_py_gel.GLManifoldViewer_display.argtypes = (ct.c_void_p,ct.c_void_p,ct.c_void_p,ct.c_char,ct.c_bool, ct.POINTER(ct.c_float*3), ct.POINTER(ct.c_double),ct.c_bool,ct.c_bool)
18
+ lib_py_gel.GLManifoldViewer_get_annotation_points.restype = ct.c_size_t
19
+ lib_py_gel.GLManifoldViewer_get_annotation_points.argtypes = (ct.c_void_p, ct.POINTER(ct.POINTER(ct.c_double)))
20
+ lib_py_gel.GLManifoldViewer_set_annotation_points.argtypes = (ct.c_void_p, ct.c_int, ct.POINTER(ct.c_double))
21
+ lib_py_gel.GLManifoldViewer_event_loop.argtypes = (ct.c_bool,)
22
+ class Viewer:
23
+ """ An OpenGL Viewer for Manifolds and Graphs. Having created an instance of this
24
+ class, call display to show a mesh or a graph. The display function is flexible,
25
+ allowing several types of interactive visualization. Each instance of this
26
+ class corresponds to a single window, but you can have several
27
+ GLManifoldViewer and hence also several windows showing different
28
+ visualizations. """
29
+ def __init__(self):
30
+ current_directory = getcwd()
31
+ self.obj = lib_py_gel.GLManifoldViewer_new()
32
+ chdir(current_directory) # Necessary because init_glfw changes cwd
33
+ def __del__(self):
34
+ lib_py_gel.GLManifoldViewer_delete(self.obj)
35
+ def clone_controller(self, other: Self):
36
+ """ Clone the controller from another GLManifoldViewer. This is useful if you
37
+ want to display a mesh in a different window but keep the same view controller.
38
+ """
39
+ if isinstance(other, Viewer):
40
+ lib_py_gel.GLManifoldViewer_clone_controller(self.obj, other.obj)
41
+ else:
42
+ raise TypeError("Argument must be an instance of Viewer")
43
+ def display(self,
44
+ m: Manifold,
45
+ g: Graph=None,
46
+ mode: str='w',
47
+ smooth: bool=True,
48
+ bg_col: tuple[float, float, float]=(0.3,0.3,0.3),
49
+ data: ArrayLike|None=None,
50
+ reset_view: bool=False,
51
+ once: bool=False):
52
+ """ Display a mesh
53
+
54
+ Args:
55
+ ---
56
+ - m : the Manifold mesh or Graph we want to show.
57
+ - g : the Graph we want to show. If you only want to show a graph, you
58
+ can simply pass the graph as m, so the g argument is relevant only if
59
+ you need to show both a Manifold _and_ a Graph.
60
+ - mode : a single character that determines how the mesh is visualized:
61
+ 'w' - wireframe,
62
+ 'i' - isophote,
63
+ 'g' - glazed (try it and see),
64
+ 's' - scalar field,
65
+ 'l' - line field,
66
+ 'n' - normal.
67
+ 'x' - xray or ghost rendering. Useful to show Manifold on top of Graph
68
+ - smooth : if True we use vertex normals. Otherwise, face normals.
69
+ - bg_col : background color.
70
+ - data : per vertex data for visualization. scalar or vector field.
71
+ - reset_view : if False view is as left in the previous display call. If
72
+ True, the view is reset to the default.
73
+ - once : if True we immediately exit the event loop and return. However,
74
+ the window stays and if the event loop is called from this or any
75
+ other viewer, the window will still be responsive.
76
+
77
+ Interactive controls:
78
+ ---
79
+ When a viewer window is displayed on the screen, you can naviagate with
80
+ the mouse: Left mouse button rotates, right mouse button is used for
81
+ zooming and (if shift is pressed) for panning. If you hold control, any
82
+ mouse button will pick a point on the 3D model. Up to 19 of these points
83
+ have unique colors. If you pick an already placed annotation point it
84
+ will be removed and can now be placed elsewhere. Hit space bar to clear
85
+ the annotation points. Hitting ESC exits the event loop causing control
86
+ to return to the script.
87
+ """
88
+ data_ct = np.array(data,dtype=ct.c_double).ctypes
89
+ data_a = data_ct.data_as(ct.POINTER(ct.c_double))
90
+ bg_col_ct = np.array(bg_col,dtype=ct.c_float).ctypes
91
+ bg_col_a = bg_col_ct.data_as(ct.POINTER(ct.c_float*3))
92
+ if isinstance(m, Graph):
93
+ g = m
94
+ m = None
95
+ if isinstance(m,Manifold) and isinstance(g, Graph):
96
+ lib_py_gel.GLManifoldViewer_display(self.obj, m.obj, g.obj, ct.c_char(mode.encode('ascii')),smooth,bg_col_a,data_a,reset_view,once)
97
+ elif isinstance(m,Manifold):
98
+ lib_py_gel.GLManifoldViewer_display(self.obj, m.obj, 0, ct.c_char(mode.encode('ascii')),smooth,bg_col_a,data_a,reset_view,once)
99
+ elif isinstance(g,Graph):
100
+ lib_py_gel.GLManifoldViewer_display(self.obj, 0, g.obj, ct.c_char(mode.encode('ascii')),smooth,bg_col_a,data_a,reset_view,once)
101
+
102
+ def annotation_points(self) -> ArrayLike:
103
+ """ Retrieve a vector of annotation points. This vector is not a copy,
104
+ so any changes made to the points will be reflected in the viewer. """
105
+ pos = ct.POINTER(ct.c_double)()
106
+ n = lib_py_gel.GLManifoldViewer_get_annotation_points(self.obj, ct.byref(pos))
107
+ if n == 0:
108
+ return None
109
+ return np.ctypeslib.as_array(pos,(n,3))
110
+ def set_annotation_points(self, pts: ArrayLike):
111
+ """ Set the annotation points to the given list of points. The points
112
+ should be given as a flat list or array of size 3n where n is the
113
+ number of points. """
114
+ pts_ct = np.array(pts,dtype=ct.c_double).ctypes
115
+ if pts_ct.size % 3 != 0:
116
+ raise ValueError("Annotation points must be given as a flat array of size 3n")
117
+ n = int(pts_ct.size // 3)
118
+ pts_a = pts_ct.data_as(ct.POINTER(ct.c_double))
119
+ lib_py_gel.GLManifoldViewer_set_annotation_points(self.obj, n, pts_a)
120
+ @staticmethod
121
+ def event_loop():
122
+ """ Explicit call to the event loop. This function enters the event loop.
123
+ Call it if you want to turn on interactivity in the currently displayed
124
+ window."""
125
+ lib_py_gel.GLManifoldViewer_event_loop(False)
126
+ except AttributeError:
127
+ pass