Skip to content

Commit 2f17f7b

Browse files
Refactor `HalfEdgeTopology(::Vector{Connectivity})
1 parent 0e37a0f commit 2f17f7b

File tree

1 file changed

+96
-50
lines changed

1 file changed

+96
-50
lines changed

src/topologies/halfedge.jl

+96-50
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,28 @@ function HalfEdgeTopology(halves::AbstractVector{Tuple{HalfEdge,HalfEdge}})
129129
HalfEdgeTopology(halfedges, half4elem, half4vert, edge4pair)
130130
end
131131

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+
132154
function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
133155
assertion(all(e -> paramdim(e) == 2, elems), "invalid element for half-edge topology")
134156

@@ -144,74 +166,98 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
144166
# initialize with first element
145167
half4pair = Dict{Tuple{Int,Int},HalfEdge}()
146168
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
151178
end
152179

153180
# 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
167219
end
168-
break
169220
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
172230
end
173231
end
174232

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
180238
end
181239
end
182240

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}}()
184244
for (e, inds) in Iterators.enumerate(adjelems)
185245
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)]
189251
# 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))
201257
end
202258
end
203259
end
204260

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-
215261
HalfEdgeTopology(halves)
216262
end
217263

0 commit comments

Comments
 (0)