Skip to content

Commit 40181a6

Browse files
committed
fixed error in function for unifying cycle directions and added non mesh specific variations
1 parent 20813c7 commit 40181a6

File tree

1 file changed

+107
-4
lines changed

1 file changed

+107
-4
lines changed

src/compas/topology/orientation.py

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from __future__ import absolute_import
33
from __future__ import division
44

5+
from compas.utilities import pairwise
6+
from compas.geometry import centroid_points
57
from compas.topology import breadth_first_traverse
68

79

@@ -12,12 +14,89 @@
1214

1315

1416
__all__ = [
17+
'face_adjacency',
18+
'mesh_face_adjacency',
19+
'unify_cycles',
1520
'mesh_unify_cycles',
1621
'mesh_flip_cycles',
1722
]
1823

1924

20-
def face_adjacency(mesh):
25+
def face_adjacency(xyz, faces):
26+
""""""
27+
points = [centroid_points([xyz[index] for index in face]) for face in faces]
28+
29+
try:
30+
from scipy.spatial import cKDTree
31+
32+
tree = cKDTree(points)
33+
_, closest = tree.query(points, k=10, n_jobs=-1)
34+
35+
except Exception:
36+
try:
37+
import Rhino
38+
39+
except Exception:
40+
from compas.geometry import KDTree
41+
42+
tree = KDTree(points)
43+
closest = [tree.nearest_neighbours(point, 10) for point in points]
44+
closest = [[index for _, index, _ in nnbrs] for nnbrs in closest]
45+
46+
else:
47+
from Rhino.Geometry import RTree
48+
from Rhino.Geometry import Sphere
49+
from Rhino.Geometry import Point3d
50+
51+
tree = RTree()
52+
for i, point in enumerate(points):
53+
tree.Insert(Point3d(* point), i)
54+
55+
def callback(sender, e):
56+
data = e.Tag
57+
data.append(e.Id)
58+
59+
closest = []
60+
for i, point in enumerate(points):
61+
sphere = Sphere(Point3d(* point), 2.0)
62+
data = []
63+
tree.Search(sphere, callback, data)
64+
closest.append(data)
65+
66+
adjacency = {}
67+
68+
for face, vertices in enumerate(faces):
69+
nbrs = []
70+
found = set()
71+
72+
nnbrs = set(closest[face])
73+
74+
for u, v in pairwise(vertices + vertices[0:1]):
75+
for nbr in nnbrs:
76+
77+
if nbr == face:
78+
continue
79+
if nbr in found:
80+
continue
81+
82+
for a, b in pairwise(faces[nbr] + faces[nbr][0:1]):
83+
if v == a and u == b:
84+
nbrs.append(nbr)
85+
found.add(nbr)
86+
break
87+
88+
for a, b in pairwise(faces[nbr] + faces[nbr][0:1]):
89+
if u == a and v == b:
90+
nbrs.append(nbr)
91+
found.add(nbr)
92+
break
93+
94+
adjacency[face] = nbrs
95+
96+
return adjacency
97+
98+
99+
def mesh_face_adjacency(mesh):
21100
"""Build a face adjacency dict.
22101
23102
Parameters
@@ -86,7 +165,7 @@ def callback(sender, e):
86165
index = fkey_index[fkey]
87166
found = set()
88167

89-
nnbrs = closest[index]
168+
nnbrs = set(closest[index])
90169

91170
for u, v in mesh.face_halfedges(fkey):
92171
for index in nnbrs:
@@ -114,6 +193,30 @@ def callback(sender, e):
114193
return adjacency
115194

116195

196+
def unify_cycles(vertices, faces, root=0):
197+
""""""
198+
def unify(node, nbr):
199+
# find the common edge
200+
for u, v in pairwise(faces[nbr] + faces[nbr][0:1]):
201+
if u in faces[node] and v in faces[node]:
202+
# node and nbr have edge u-v in common
203+
i = faces[node].index(u)
204+
j = faces[node].index(v)
205+
if i == j - 1 or (j == 0 and u == faces[node][-1]):
206+
# if the traversal of a neighbouring halfedge
207+
# is in the same direction
208+
# flip the neighbour
209+
faces[nbr][:] = faces[nbr][::-1]
210+
return
211+
212+
adj = face_adjacency(vertices, faces)
213+
214+
visited = breadth_first_traverse(adj, root, unify)
215+
216+
assert len(list(visited)) == len(faces), 'Not all faces were visited'
217+
return faces
218+
219+
117220
def mesh_unify_cycles(mesh, root=None):
118221
"""Unify the cycle directions of all faces.
119222
@@ -135,7 +238,7 @@ def unify(node, nbr):
135238
# node and nbr have edge u-v in common
136239
i = mesh.face[node].index(u)
137240
j = mesh.face[node].index(v)
138-
if i == j - 1:
241+
if i == j - 1 or (j == 0 and u == mesh.face[node][-1]):
139242
# if the traversal of a neighbouring halfedge
140243
# is in the same direction
141244
# flip the neighbour
@@ -145,7 +248,7 @@ def unify(node, nbr):
145248
if root is None:
146249
root = mesh.get_any_face()
147250

148-
adj = face_adjacency(mesh)
251+
adj = mesh_face_adjacency(mesh)
149252

150253
visited = breadth_first_traverse(adj, root, unify)
151254

0 commit comments

Comments
 (0)