Line data Source code
1 19330 : addface!(mesh::Mesh, v0::VHnd, v1::VHnd, v2::VHnd, vertices...;
2 : fhint::FHnd = NoF) =
3 : addface!(mesh, (v0, v1, v2, vertices...); fhint)
4 :
5 19342 : addface!(mesh::Mesh, vertices; fhint::FHnd = NoF) =
6 : addface!(mesh, fhint, collect(VHnd, vertices))
7 :
8 121 : addface!(mesh::Mesh, vertices::Vector{VHnd}) =
9 : addface!(mesh, NoF, vertices)
10 :
11 9792 : function addface!(mesh::Mesh, fhint::FHnd, vertices::Vector{VHnd})
12 : # check & find half-edges
13 9792 : _no_complex_vertices(mesh, vertices) || return NoF
14 :
15 9792 : halfedges = _halfedges(mesh, vertices)
16 9793 : _no_complex_edge(mesh, halfedges) || return NoF
17 :
18 9791 : links = Vector{Tuple{HHnd, HHnd}}()
19 59254 : push_link!(h01) = push!(links, h01)
20 :
21 : # relink patches if necessary
22 9791 : _possibly_relink_patches(push_link!, mesh, halfedges) || return NoF
23 :
24 : # create missing (half-)edges & face, remember what is new
25 9791 : isnew = [ h == NoH for h in halfedges ]
26 :
27 19582 : for (i, j) in _pieces(1:length(vertices))
28 29760 : (halfedges[i] != NoH) && continue
29 :
30 15003 : halfedges[i] = _create_edge(mesh, vertices[i], vertices[j])
31 49729 : end
32 :
33 9791 : f = _create_face(mesh, halfedges[end], fhint)
34 :
35 9791 : to_adjust = Vector{VHnd}()
36 :
37 : # setup half-edges
38 19582 : for (i, j) in _pieces(1:length(vertices))
39 29760 : v = vertices[j]
40 29760 : iprev = halfedges[i]
41 29760 : inext = halfedges[j]
42 :
43 29760 : id = 0
44 29760 : id |= isnew[i] ? 1 : 0
45 29760 : id |= isnew[j] ? 2 : 0
46 :
47 29760 : (id != 0) && _set_outer_link(push_link!, mesh, id, v, inext, iprev)
48 29760 : (id != 0) && push_link!((iprev, inext)) # inner link
49 29760 : (id == 0) && push!(to_adjust, v)
50 :
51 29760 : _setface!(mesh, iprev, f)
52 49729 : end
53 :
54 : # process links
55 9791 : for link in links
56 49463 : _setnexthalfedge!(mesh, link...)
57 49463 : end
58 :
59 : # adjust vertex - half-edge links
60 9791 : for v in to_adjust
61 5032 : _adjustoutgoinghalfedge!(mesh, v)
62 5032 : end
63 :
64 9791 : f
65 : end
66 :
67 : """
68 : f = addface!(mesh, vertices[; fhint])
69 : f = addface!(mesh, v1, v2, v3[, ...; fhint])
70 :
71 : Add and link new face spanned by oriented sequence of `vertices`
72 : (`VHnd`).
73 :
74 : If the optional `fhint::FHnd` is a valid handle to an unused face, this
75 : handle will be "reused" as `f`.
76 :
77 : !!! note "Reusing faces"
78 : The current implementation can "reuse" face handles -- but *not*
79 : unused half-edges!
80 :
81 : !!! warning "Preconditions"
82 : - Face will not generate complex vertices/edges.
83 : - [`isused`](@ref) and [`isboundary`](@ref) for vertices.
84 :
85 : Returns face handle `FHnd`. Returns `NoF` if the face could not be
86 : linked (prints an error message).
87 :
88 : See also [`removeface!`](@ref)
89 : """ addface!
90 :
91 9823 : function _create_face(mesh, h = NoH, fhint = NoF)
92 9823 : fs = fattr(mesh)
93 :
94 9807 : if fhint != NoF
95 1 : isindex(fhint) || (fhint = NoF)
96 1 : !isused(mesh, fhint) || (fhint = NoF)
97 : end
98 :
99 9807 : f =
100 : if fhint == NoF
101 9806 : FHnd(pushattr!(fs))
102 : else
103 1 : setused!(fattr(mesh), fhint)
104 9808 : fhint
105 : end
106 :
107 9807 : link(fs)[f] = h
108 :
109 9807 : f
110 : end
111 :
112 9792 : function _no_complex_vertices(mesh, vertices)
113 49347 : any(v -> isinner(mesh, v), vertices) || return true
114 :
115 0 : @error "complex vertex"
116 0 : false
117 : end
118 :
119 39165 : function _pieces(elements)
120 39165 : n = length(elements)
121 39165 : ((elements[i], elements[i % n + 1]) for i in 1:n)
122 : end
123 :
124 9792 : _halfedges(mesh::Mesh, vertices::Array{VHnd}) =
125 : [ halfedge(mesh, v01) for v01 in _pieces(vertices) ]
126 :
127 9792 : function _no_complex_edge(mesh, halfedges)
128 49344 : any(h -> (h != NoH && !isboundary(mesh, h)), halfedges) || return true
129 :
130 1 : @error "complex edge"
131 0 : false
132 : end
133 :
134 9791 : function _possibly_relink_patches(f, mesh, halfedges)
135 19582 : for (hp, hn) in _pieces(halfedges)
136 44517 : (hp == NoH || hn == NoH) && continue
137 5032 : (next(mesh, hp) == hn) && continue
138 :
139 0 : _relink_patch(f, mesh, hp, hn) || return false
140 29760 : end
141 :
142 0 : true
143 : end
144 :
145 0 : function _relink_patch(f, mesh, iprev, inext)
146 0 : @debug "relink patch"
147 :
148 0 : oprev = opposite(mesh, inext)
149 0 : onext = opposite(mesh, iprev)
150 :
151 0 : bprev = oprev
152 :
153 0 : while true
154 0 : bprev = opposite(mesh, next(mesh, bprev))
155 :
156 0 : isboundary(mesh, bprev) && (bprev != iprev) && break
157 0 : end
158 :
159 0 : bnext = next(mesh, bprev)
160 0 : @massert isboundary(mesh, bprev) && isboundary(mesh, bnext)
161 :
162 0 : if bnext == inext
163 0 : @error "failed to relink patch"
164 0 : return false
165 : end
166 :
167 0 : f((bprev, next(mesh, iprev)))
168 0 : f((prev(mesh, inext), bnext))
169 0 : f((iprev, inext))
170 :
171 0 : true
172 : end
173 :
174 24728 : function _set_outer_link(f, mesh, id, v, inext, iprev)
175 24728 : @massert 1 <= id <= 3
176 24728 : oprev = opposite(mesh, inext)
177 24728 : onext = opposite(mesh, iprev)
178 :
179 24728 : if id == 1 # prev new, next old
180 9725 : bprev = prev(mesh, inext)
181 9725 : _sethalfedge!(mesh, v, onext)
182 9725 : f((bprev, onext))
183 15003 : elseif id == 2 # next new, prev old
184 9725 : bnext = next(mesh, iprev)
185 9725 : _sethalfedge!(mesh, v, bnext)
186 9725 : f((oprev, bnext))
187 : else # both new
188 5278 : @massert id == 3
189 5278 : bnext = halfedge(mesh, v)
190 5278 : if bnext == NoH
191 5271 : _sethalfedge!(mesh, v, onext)
192 5271 : f((oprev, onext))
193 : else
194 7 : bprev = prev(mesh, bnext)
195 7 : f((bprev, onext))
196 7 : f((oprev, bnext))
197 : end
198 : end
199 : end
|