Skip to content

Commit 7a19189

Browse files
Refactor `HalfEdgeTopology(::Vector{Connectivity})
1 parent 7f8770a commit 7a19189

File tree

1 file changed

+96
-40
lines changed

1 file changed

+96
-40
lines changed

src/topologies/halfedge.jl

Lines changed: 96 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,28 @@ function HalfEdgeTopology(halves::AbstractVector{Tuple{HalfEdge,HalfEdge}}, nele
136136
HalfEdgeTopology(halfedges, half4elem, half4vert, edge4pair)
137137
end
138138

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

@@ -151,60 +173,94 @@ function HalfEdgeTopology(elems::AbstractVector{<:Connectivity}; sort=true)
151173
# initialize with first element
152174
half4pair = Dict{Tuple{Int,Int},HalfEdge}()
153175
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
158185
end
159186

160187
# 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
174226
end
175-
break
176227
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
179237
end
180238
end
181239

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
187245
end
188246
end
189247

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}}()
191251
for (e, inds) in Iterators.enumerate(adjelems)
192252
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)]
196258
# 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))
208264
end
209265
end
210266
end

0 commit comments

Comments
 (0)