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