@@ -129,6 +129,28 @@ function HalfEdgeTopology(halves::AbstractVector{Tuple{HalfEdge,HalfEdge}})
129
129
HalfEdgeTopology (halfedges, half4elem, half4vert, edge4pair)
130
130
end
131
131
132
+ function any_edges_exist (inds, half4pair)
133
+ n = length (inds)
134
+ for i in eachindex (inds)
135
+ ordered_uv = minmax (inds[i], inds[mod1 (i + 1 , n)])
136
+ if haskey (half4pair, ordered_uv)
137
+ return true
138
+ end
139
+ end
140
+ return false
141
+ end
142
+
143
+ function any_claimed_edges_exist (inds, half4pair)
144
+ n = length (inds)
145
+ for i in eachindex (inds)
146
+ uv = (inds[i], inds[mod1 (i + 1 , n)])
147
+ if haskey (half4pair, uv) && ! isnothing (half4pair[uv]. elem)
148
+ return true
149
+ end
150
+ end
151
+ return false
152
+ end
153
+
132
154
function HalfEdgeTopology (elems:: AbstractVector{<:Connectivity} ; sort= true )
133
155
assertion (all (e -> paramdim (e) == 2 , elems), " invalid element for half-edge topology" )
134
156
@@ -144,74 +166,98 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
144
166
# initialize with first element
145
167
half4pair = Dict {Tuple{Int,Int},HalfEdge} ()
146
168
inds = first (adjelems)
147
- v = CircularVector (inds)
148
- n = length (v)
149
- for i in 1 : n
150
- half4pair[(v[i], v[i + 1 ])] = HalfEdge (v[i], eleminds[1 ])
169
+ for i in eachindex (inds)
170
+ u = inds[i]
171
+ u1 = inds[mod1 (i + 1 , length (inds))]
172
+ ei = eleminds[1 ]
173
+ he = get! (() -> HalfEdge (u, ei), half4pair, (u, u1))
174
+ # reserve half-edge to enable recognizing orientation mismatches
175
+ half = get! (() -> HalfEdge (u1, nothing ), half4pair, (u1, u))
176
+ he. half = half
177
+ half. half = he
151
178
end
152
179
153
180
# insert all other elements
154
- for e in 2 : length (adjelems)
155
- inds = adjelems[e]
156
- v = CircularVector (inds)
157
- n = length (v)
158
- for i in 1 : n
159
- # if pair of vertices is already in the
160
- # dictionary this means that the current
161
- # polygon has inconsistent orientation
162
- if haskey (half4pair, (v[i], v[i + 1 ]))
163
- # delete inserted pairs so far
164
- CCW[e] = false
165
- for j in 1 : (i - 1 )
166
- delete! (half4pair, (v[j], v[j + 1 ]))
181
+ remaining = collect (2 : length (adjelems))
182
+ added = false
183
+ disconnected = false
184
+ while ! isempty (remaining)
185
+ iter = 1
186
+ while iter ≤ length (remaining)
187
+ e = remaining[iter]
188
+ inds = adjelems[e]
189
+ n = length (inds)
190
+ if any_edges_exist (inds, half4pair) || disconnected
191
+ # at least one edge has been reserved, so we can assess the orientation w.r.t.
192
+ # previously added elements/edges
193
+ deleteat! (remaining, iter)
194
+ added = true
195
+ disconnected = false
196
+ else
197
+ iter += 1
198
+ continue
199
+ end
200
+
201
+ ei = eleminds[e]
202
+ if any_claimed_edges_exist (inds, half4pair)
203
+ CCW[e] = false
204
+ end
205
+
206
+ if ! CCW[e]
207
+ # reinsert pairs in CCW orientation
208
+ for i in eachindex (inds)
209
+ u = inds[i]
210
+ u1 = inds[mod1 (i + 1 , n)]
211
+ he = get! (() -> HalfEdge (u1, ei), half4pair, (u1, u))
212
+ if ! isnothing (he. elem)
213
+ @assert he. elem === ei lazy " inconsistent duplicate edge $he for $(ei) and $(he.elem)"
214
+ end
215
+ he. elem = ei
216
+ half = get! (() -> HalfEdge (u, nothing ), half4pair, (u, u1))
217
+ he. half = half
218
+ half. half = he
167
219
end
168
- break
169
220
else
170
- # insert pair in consistent orientation
171
- half4pair[(v[i], v[i + 1 ])] = HalfEdge (v[i], eleminds[e])
221
+ for i in eachindex (inds)
222
+ u = inds[i]
223
+ u1 = inds[mod1 (i + 1 , n)]
224
+ he = get! (() -> HalfEdge (u, ei), half4pair, (u, u1))
225
+ he. elem = ei
226
+ half = get! (() -> HalfEdge (u1, nothing ), half4pair, (u1, u))
227
+ he. half = half
228
+ half. half = he
229
+ end
172
230
end
173
231
end
174
232
175
- if ! CCW[e]
176
- # reinsert pairs in CCW orientation
177
- for i in 1 : n
178
- half4pair[(v[i + 1 ], v[i])] = HalfEdge (v[i + 1 ], eleminds[e])
179
- end
233
+ if added
234
+ added = false
235
+ elseif ! isempty (remaining)
236
+ disconnected = true
237
+ added = false
180
238
end
181
239
end
182
240
183
- # add missing pointers
241
+ # add missing pointers and save halfedges in a vector of pairs
242
+ halves = Vector {Tuple{HalfEdge,HalfEdge}} ()
243
+ visited = Set {Tuple{Int,Int}} ()
184
244
for (e, inds) in Iterators. enumerate (adjelems)
185
245
inds = CCW[e] ? inds : reverse (inds)
186
- v = CircularVector (inds)
187
- n = length (v)
188
- for i in 1 : n
246
+ n = length (inds)
247
+ for i in eachindex (inds)
248
+ vi = inds[i]
249
+ vi1 = inds[mod1 (i+ 1 ,n)]
250
+ vi2 = inds[mod1 (i+ 2 ,n)]
189
251
# update pointers prev and next
190
- he = half4pair[(v[i], v[i + 1 ])]
191
- he. prev = half4pair[(v[i - 1 ], v[i])]
192
- he. next = half4pair[(v[i + 1 ], v[i + 2 ])]
193
-
194
- # if not a border element, update half
195
- if haskey (half4pair, (v[i + 1 ], v[i]))
196
- he. half = half4pair[(v[i + 1 ], v[i])]
197
- else # create half-edge for border
198
- be = HalfEdge (v[i + 1 ], nothing )
199
- be. half = he
200
- he. half = be
252
+ he = half4pair[(vi, vi1)]
253
+ he. next = half4pair[(vi1, vi2)]
254
+ he. next. prev = he
255
+ if ! in! (minmax (vi, vi1), visited)
256
+ push! (halves, (he, he. half))
201
257
end
202
258
end
203
259
end
204
260
205
- # save halfedges in a vector of pairs
206
- halves = Vector {Tuple{HalfEdge,HalfEdge}} ()
207
- visited = Set {Tuple{Int,Int}} ()
208
- for ((u, v), he) in half4pair
209
- if minmax (u, v) ∉ visited
210
- push! (halves, (he, he. half))
211
- push! (visited, minmax (u, v))
212
- end
213
- end
214
-
215
261
HalfEdgeTopology (halves)
216
262
end
217
263
0 commit comments