-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathunfolder.py
More file actions
172 lines (146 loc) · 5.43 KB
/
unfolder.py
File metadata and controls
172 lines (146 loc) · 5.43 KB
1
2
3
4
5
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
from collections import deque
import graphs
import polytope_face_extractor
import polytope_point_generator
import numpy as np
import random
import heapq
import time
class TreeNode:
def __init__(self, face_id, face):
self.id = face_id
self.face = face
self.parent = None
self.children = []
def add_child(self, other):
self.children.append(other)
other.parent = self
def __str__(self):
s = f"== Diving ({self.id}) ==\n"
for child in self.children:
s += str(child)
s += f"== Surfacing ({self.id}) ==\n"
return s
def __repr__(self):
return str(self)
class UnfoldingTree:
def __init__(self, root_id, root_face):
self.root = TreeNode(root_id, root_face)
def get_root(self):
return self.root
def __str__(self):
return str(self.root)
def __repr__(self):
return str(self)
def bfs_unfolder(face_graph, faces, s=0):
T = UnfoldingTree(0, faces[0])
visited = {s}
frontier = deque([T.get_root()])
while len(frontier):
cur = frontier.popleft()
for nei in face_graph[cur.id]:
if nei in visited:
continue
# print(nei) # for debugging
visited.add(nei)
child = TreeNode(nei, faces[nei])
cur.add_child(child)
frontier.append(child)
return T
def steepest_edge_unfolder(face_graph, faces, vertex_graph, points):
# print("Steepest edge unfolding") # debugging
T_v = []
# random unit vector
c = np.array([random.uniform(-1, 1) for _ in range(3)])
c = c / np.linalg.norm(c)
# finding steepest point
p_max = float("-inf")
for idx in range(len(points)):
proj = np.dot(points[idx], c)
if proj > p_max:
p_max = proj
v_max = idx
for v in vertex_graph:
if v == v_max: # find the most descending steepest edge from the steepest point, not in the algorithm
steepest = float("inf")
for nei in vertex_graph[v]:
proj = np.dot(c, points[v] - points[nei])/np.linalg.norm(points[v] - points[nei])
if proj < steepest:
steepest = proj
steepest_v = nei
T_v.append((v, steepest_v))
else:
steepest = float("-inf")
for nei in vertex_graph[v]:
proj = np.dot(c, points[v] - points[nei])/np.linalg.norm(points[v] - points[nei])
if proj > steepest:
steepest = proj
steepest_v = nei
T_v.append((v, steepest_v))
# print("Cut edges:", T_v) # for debugging
T = UnfoldingTree(0, faces[0])
visited = {0}
parents = {0: None} # for cycle detection
frontier = deque([T.get_root()])
while len(frontier):
cur = frontier.popleft()
for nei in face_graph[cur.id]:
cut = False
intersection = set(faces[cur.id]) & set(faces[nei])
if len(intersection) == 2:
v1, v2 = list(intersection)
if (v1, v2) in T_v or (v2, v1) in T_v:
# print("Faces are joined by a cut edge so not a neighbour")
cut = True
if cut:
continue
if nei in visited:
if nei != parents[cur.id]:
print("Cycle detected") # the dual graph is not a tree if you remove the cut edges, which means the steepest edge unfolding failed
continue
visited.add(nei)
child = TreeNode(nei, faces[nei])
cur.add_child(child)
frontier.append(child)
parents[nei] = cur.id
return T, T_v, c
def chromosome_to_unfolding(G_f, faces, edge_idx, edge_priority):
# s = time.time()
# print("Chromosome:", edge_priority)
# 0th face has highest priority (-1)
heap = [(-1, 0, None)] # (priority, node, parent)
T = None
connected = set()
nodes = {}
while len(connected) < len(G_f):
next_node = heapq.heappop(heap)
if next_node[1] in connected: # skip nodes already in spanning tree
continue
if next_node[2] is None: # root
T = UnfoldingTree(0, faces[0])
nodes = {0: T.get_root()}
connected = {0}
else: # add child to spanning tree
child = TreeNode(next_node[1], faces[next_node[1]])
nodes[next_node[2]].add_child(child)
# print(f"added {child.id} under parent: {next_node[2]}")
nodes[child.id] = child
connected.add(child.id)
for nei in G_f[next_node[1]]:
if nei in connected:
continue
a, b = min(next_node[1], nei), max(next_node[1], nei)
# print(a, b)
heapq.heappush(heap, (edge_priority[edge_idx[(a, b)]], nei, next_node[1])) # get priority from chromosome
# e = time.time()
# print(f"Time to generate unfolding from chromosome: {e - s}")
return T
if __name__ == "__main__":
points = polytope_point_generator.generate_dodec()
faces, changed = polytope_face_extractor.get_conv_hull_faces(points)
# polytope_face_extractor.draw_polytope(points, faces, changed)
G = graphs.make_face_graph(faces)
faces = graphs.fix_face_orientation(G, faces)
T = bfs_unfolder(G, faces)
print(T)
graphs.draw_dual_graph(G)