Computes a list containing the oriented boundary loop for each boundary component of a triangle mesh in the style of a sorted polyline. This function only works on connected (i.e., single component) manifold triangle meshes.
Parameters:
Name |
Type |
Description |
Default |
f |
(m,3) numpy int array
|
face index list of a triangle mesh |
required
|
allow_wrong_orientations |
|
whether to allow F to contain wrongly oriented triangles |
True
|
Returns:
Name | Type |
Description |
loops |
list of numpy arrays that are themselves lists of boundary vertices
|
in oriented loops |
Examples:
from gpytoolbox import read_mesh, boundary_loops
v,f = read_mesh("test/unit_tests_data/bunny_oded.obj")
loops = boundary_loops(f)
Source code in src/gpytoolbox/boundary_loops.py
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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 | def boundary_loops(f, allow_wrong_orientations=True):
"""Computes a list containing the oriented boundary loop for each boundary component of a triangle mesh in the style of a sorted polyline. This function only works on connected (i.e., single component) manifold triangle meshes.
Parameters
----------
f : (m,3) numpy int array
face index list of a triangle mesh
allow_wrong_orientations: bool, optional (default True).
whether to allow F to contain wrongly oriented triangles
Returns
-------
loops : list of numpy arrays that are themselves lists of boundary vertices
in oriented loops
Examples
--------
```python
from gpytoolbox import read_mesh, boundary_loops
v,f = read_mesh("test/unit_tests_data/bunny_oded.obj")
loops = boundary_loops(f)
```
"""
assert f.shape[0] > 0
assert f.shape[1] == 3
# check mesh is manifold
assert len(non_manifold_edges(f)) == 0, "Mesh is not manifold"
bE = boundary_edges(f)
#Loop through each boundary, edge, marking them as seen, until all have
# been seen.
unseen = np.full(bE.shape[0], True)
loops = []
while np.any(unseen):
current_b = np.argmax(unseen)
current_bE = bE[current_b,:]
start = current_bE[0]
unseen[current_b] = False
loop_vertices = []
loop_vertices.append(start)
head = current_bE[1]
while head != start:
loop_vertices.append(head)
if allow_wrong_orientations:
current_b_0 = np.where((bE[:,0] == head) & unseen)[0]
current_b_1 = np.where((bE[:,1] == head) & unseen)[0]
if len(current_b_0)>len(current_b_1):
current_b = current_b_0
head_ind = 1
else:
current_b = current_b_1
head_ind = 0
else:
current_b = np.where((bE[:,0] == head) & unseen)[0]
head_ind = 1
assert len(current_b) == 1
current_b = current_b.item(0)
current_bE = bE[current_b,:]
unseen[current_b] = False
head = current_bE[head_ind]
loops.append(np.array(loop_vertices))
assert sum([len(l) for l in loops]) == bE.shape[0]
return loops
|