@@ -134,17 +134,20 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
134
134
135
135
# sort elements to make sure that they
136
136
# are traversed in adjacent-first order
137
- adjelems = sort ? adjsort (elems):: typeof (elems) : elems
138
- eleminds = sort ? indexin (adjelems, elems) : 1 : length (elems)
137
+ if sort
138
+ eleminds = adjsortperm (elems)
139
+ adjelems = map (collect ∘ indices, elems[eleminds]):: Vector{Vector{Int}}
140
+ else
141
+ adjelems, eleminds = map (collect ∘ indices, elems):: Vector{Vector{Int}} , eachindex (elems)
142
+ end
139
143
140
144
# start assuming that all elements are
141
145
# oriented consistently as CCW
142
146
CCW = trues (length (adjelems))
143
147
144
148
# initialize with first element
145
149
half4pair = Dict {Tuple{Int,Int},HalfEdge} ()
146
- elem = first (adjelems)
147
- inds:: Vector{Int} = collect (indices (elem))
150
+ inds = first (adjelems)
148
151
v = CircularVector (inds)
149
152
n = length (v)
150
153
for i in 1 : n
@@ -153,8 +156,7 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
153
156
154
157
# insert all other elements
155
158
for e in 2 : length (adjelems)
156
- elem = adjelems[e]
157
- inds = collect (indices (elem))
159
+ inds = adjelems[e]
158
160
v = CircularVector (inds)
159
161
n = length (v)
160
162
for i in 1 : n
@@ -183,8 +185,8 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
183
185
end
184
186
185
187
# add missing pointers
186
- for (e, elem ) in Iterators. enumerate (adjelems)
187
- inds = CCW[e] ? collect ( indices (elem)) : reverse (collect ( indices (elem)) )
188
+ for (e, inds ) in Iterators. enumerate (adjelems)
189
+ inds = CCW[e] ? inds : reverse (inds )
188
190
v = CircularVector (inds)
189
191
n = length (v)
190
192
for i in 1 : n
@@ -217,42 +219,50 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
217
219
HalfEdgeTopology (halves)
218
220
end
219
221
220
- function adjsort (elems:: AbstractVector{<:Connectivity} )
222
+ function adjsortperm (elems:: AbstractVector{<:Connectivity} )
223
+ listi = collect (eachindex (elems)[2 : end ])
221
224
# initialize list of adjacent elements
222
225
# with first element from original list
223
- list:: Vector{Tuple{Vararg{Int}}} = map (indices, elems)
224
- adjs = similar (list, 0 )
225
- push! (adjs, popfirst! (list))
226
-
227
- # the loop will terminate if the mesh
228
- # is manifold, and that is always true
229
- # with half-edge topology
230
- while ! isempty (list)
226
+ adjs = Int[1 ]
227
+ sizehint! (adjs, length (elems))
228
+
229
+ # found minimizes adjacency discontinuities. if `found == true` for the last edge in an
230
+ # element, then we continue from that new element adjacent to that edge
231
+ found = false
232
+ while ! isempty (listi)
231
233
# lookup all elements that share at least
232
234
# one vertex with the last adjacent element
233
- found = false
234
- vinds = last (adjs )
235
+ adj = last (adjs)
236
+ vinds:: Tuple{Vararg{Int}} = indices (elems[adj] )
235
237
for i in vinds
236
238
not_i = filter (!= (i), vinds)
237
- for j in reverse (eachindex (list))
239
+ j = 1
240
+ while j ≤ length (listi)
238
241
# equivalent to `length(vinds ∩ list[j]) > 1` but more efficient (no allocs(?))
239
- any (== (i), list[j]) || continue
240
- isdisjoint (not_i, list[j]) && continue
241
-
242
- # implicitly `list[j]` contains `i` and at least one other vertex
243
- found = true
244
- push! (adjs, popat! (list, j))
242
+ elem = indices (elems[listi[j]])
243
+ if any (== (i), elem) && ! isdisjoint (not_i, elem):: Bool
244
+ # `list[j]` contains `i` and at least one other vertex
245
+ push! (adjs, popat! (listi, j))
246
+ found = true
247
+ # don't increment j here because `popat!` just put the j+1 element at j
248
+ # (avoids the need to reverse the array)
249
+ else
250
+ j += 1
251
+ found = false
252
+ continue
253
+ end
245
254
end
246
255
end
247
256
248
- if ! found && ! isempty (list )
257
+ if ! found && ! isempty (listi )
249
258
# we are done with this connected component
250
259
# pop a new element from the original list
251
- push! (adjs, popfirst! (list))
260
+ push! (adjs, popfirst! (listi))
261
+ found = false
252
262
end
253
263
end
254
264
255
- map (connect, adjs)
265
+ adjs
256
266
end
257
267
258
268
paramdim (:: HalfEdgeTopology ) = 2
0 commit comments