22from __future__ import absolute_import
33from __future__ import division
44
5+ from compas .utilities import pairwise
6+ from compas .geometry import centroid_points
57from compas .topology import breadth_first_traverse
68
79
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+
117220def 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