Line data Source code
1 : abstract type VertexNormalWeights end
2 :
3 32295 : struct AngleWeights <: VertexNormalWeights end
4 8092 : struct AreaWeights <: VertexNormalWeights end
5 3 : struct InverseAreaWeights <: VertexNormalWeights end
6 3 : struct UniformWeights <: VertexNormalWeights end
7 :
8 80696 : vertexnormal(g::AbstractGeometry, v::VHnd,
9 : weights::W=AngleWeights()) where {W<:VertexNormalWeights} =
10 : _vertexnormal(g, v, _has_vx(g), weights)
11 :
12 4034 : function _vertexnormal(g::AbstractGeometry, v::VHnd, ::HasVX, ::UniformWeights)
13 4034 : m = _mesh(g)
14 4034 : nrm = zeros(eltype(_vpos(g)))
15 :
16 4034 : isisolated(m, v) && return nrm
17 :
18 4034 : for f in fan(m, v)
19 24192 : fnrm = normal(g, f)
20 24192 : @massert all(isfinite.(fnrm))
21 :
22 24192 : nrm += fnrm
23 24192 : end
24 :
25 4034 : normalize(nrm)
26 : end
27 :
28 36314 : function _vertexnormal(g::AbstractGeometry, v::VHnd, ::HasVX, ::AngleWeights)
29 36314 : m = _mesh(g)
30 36314 : x = _vpos(g)
31 36314 : nrm = zeros(eltype(x))
32 :
33 36314 : isisolated(m, v) && return nrm
34 :
35 36314 : x0 = x[v]
36 :
37 72628 : for h in star(m, v)
38 218240 : isboundary(m, h) && continue
39 :
40 218240 : x1 = x[destination(m, h)] - x0
41 218240 : x2 = x[source(m, prev(m, h))] - x0
42 :
43 218240 : denom = sqrt(dot(x1, x1) * dot(x2, x2))
44 218240 : (denom > eps(eltype(x1))) || continue
45 :
46 436480 : α = acos(clamp(dot(x1, x2) / denom, -1, +1))
47 218240 : nrmh = normal(g, face(m, h))
48 218240 : @massert all(isfinite.(nrmh))
49 :
50 218240 : nrm += nrmh * α
51 400166 : end
52 :
53 36314 : normalize(nrm)
54 : end
55 :
56 4034 : _vertexnormal(g::AbstractGeometry, v::VHnd, vx::HasVX, w::AreaWeights) =
57 : _vertexnormal(g, v, vx, w, AreaWeights())
58 :
59 4034 : _vertexnormal(g::AbstractGeometry, v::VHnd, vx::HasVX, w::InverseAreaWeights) =
60 : _vertexnormal(g, v, vx, w, AreaWeights())
61 :
62 8068 : function _vertexnormal(g::AbstractGeometry, v::VHnd, ::HasVX, w, ::AreaWeights)
63 8068 : m = _mesh(g)
64 8068 : x = _vpos(g)
65 8068 : nrm = zeros(eltype(x))
66 :
67 8068 : isisolated(m, v) && return nrm
68 :
69 32260 : _invarea(ar, ::AreaWeights) = ar
70 48384 : _invarea(ar::T, ::InverseAreaWeights) where {T} =
71 : (ar < eps(T)) ? T(0) : one(T) / ar
72 :
73 8068 : for f in fan(m, v)
74 48384 : nrmf, ar = facenormalarea(g, f)
75 48384 : @massert all(isfinite.(nrmf))
76 :
77 72576 : nrm += nrmf * _invarea(ar, w)
78 48384 : end
79 :
80 8068 : normalize(nrm)
81 : end
82 :
83 0 : vertexnormal(m::Mesh, x, v::VHnd,
84 : weights::W=AngleWeights()) where {W<:VertexNormalWeights} =
85 : vertexnormal(geometry(m, x), v, weights)
86 :
87 : """
88 : nrm = vertexnormal(mesh, x, v[, weights=AngleWeights()])
89 :
90 : g = geometry(mesh, x)
91 : nrm = vertexnormal(g, v[, weights=AngleWeights()])
92 :
93 : Compute vertex normal from weighted sum of [`facenormal`](@ref)s.
94 :
95 : !!! note
96 : This method uses [`normal`](@ref) to query face normals:
97 : If face normals are provided as an attribute, use their values
98 : *assuming* they are up to date! Otherwise, compute them
99 : explicitly.
100 :
101 : Possible values of for `weights` are
102 : - `AngleWeights()` **(default)**
103 : - `AreaWeights()`
104 : - `InverseAreaWeights()`
105 : - `UniformWeights()`
106 :
107 : See [`geometry`](@ref), [`normal`](@ref), [`updatenormal!](@ref),
108 : [`facenormal`](@ref), [`updatevertexnormals!`](@ref)
109 : """ vertexnormal
110 :
111 : # TODO: move vertex normals to file
112 :
113 : # TODO: updatevertexnormals! (bool)
114 :
115 371614 : normal(g::AbstractGeometry, f::FHnd) = normal(g, f, _has_fn(g))
116 :
117 274480 : normal(g, f::FHnd, ::HasFN) = _fnrm(g)[f]
118 :
119 97134 : normal(g, f::FHnd, ::NoFN) = facenormal(g, f)
120 :
121 80692 : normal(g::AbstractGeometry, v::VHnd) = normal(g, v, _has_vn(g))
122 :
123 48412 : normal(g, v::VHnd, ::HasVN) = _vnrm(g)[v]
124 :
125 32280 : normal(g, v::VHnd, ::NoVN) = vertexnormal(g, v)
126 :
127 : # TODO: weight (ingored if stored)
128 :
129 : """
130 : g = geometry(mesh, x, ...)
131 : nrm = normal(g, f)
132 : nrm = normal(g, v)
133 :
134 : Get or compute face or vertex normal depending on availability of
135 : attribute.
136 :
137 : See also [`geometry`](@ref), [`updatenormal!`](@ref),
138 : [`facenormal`](@ref), [`vertexnormal`](@ref)
139 : """ normal
140 :
141 129036 : updatenormal!(g::AbstractGeometry, f::FHnd, nrm::SVector{3} = facenormal(g, f)) =
142 : updatenormal!(g, f, nrm, _has_fn(g))
143 :
144 64518 : updatenormal!(g::AbstractGeometry, f::FHnd, nrm, ::HasFN) = (_fnrm(g)[f] = nrm)
145 :
146 0 : updatenormal!(g::AbstractGeometry, f::FHnd, nrm, ::NoFN) = nothing
147 :
148 16136 : updatenormal!(g::AbstractGeometry, v::VHnd, nrm::SVector{3} = vertexnormal(g, v)) =
149 : updatenormal!(g, v, nrm, _has_vn(g))
150 :
151 : # TODO: weight
152 :
153 16136 : updatenormal!(g::AbstractGeometry, v::VHnd, nrm, ::HasVN) = (_vnrm(g)[v] = nrm)
154 :
155 0 : updatenormal!(g::AbstractGeometry, v::VHnd, nrm, ::NoVN) = nothing
156 :
157 : """
158 : g = geometry(mesh, x, ...)
159 : updatenormal!(g, f[, nrm])
160 : updatenormal!(f, v[, nrm])
161 :
162 : Update face normal or vertex normal from `nrm` or [`facenormal`] or
163 : [`vertexnormal`](@ref). **No effect** if `g` has no attribute for
164 : face normals.
165 :
166 : See also [`geometry`](@ref), [`trianglenormal`](@ref), [`facenormal`](@ref),
167 : [`normal`](@ref)
168 : """ updatenormal!
169 :
170 14 : updatefacenormals!(g::AbstractGeometry) = updatefacenormals!(g, _has_fn(g))
171 :
172 9 : function updatefacenormals!(g::AbstractGeometry, ::HasFN)
173 18 : for f in faces(_mesh(g))
174 64518 : updatenormal!(g, f)
175 64518 : end
176 : end
177 :
178 0 : updatefacenormals!(g::AbstractGeometry, ::NoFN) = nothing
179 :
180 : """
181 : g = geometry(mesh, x, ...)
182 : updatefacenormals!(g)
183 :
184 : Recompute and update all face normals.
185 :
186 : !!! note
187 : This method has **no effect** if `g` does not provide an attribute
188 : for face normals.
189 :
190 : See also [`geometry`](@ref), [`updatenormal!`](@ref), [`facenormal`](@ref),
191 : [`updatevertexnormals!`](@ref), [`updatenormals!`](@ref)
192 : """ updatefacenormals!
193 :
194 12 : updatevertexnormals!(g::AbstractGeometry,
195 : weights::W=AreaWeights()) where {W<:VertexNormalWeights} =
196 : updatevertexnormals!(g, _has_vn(g), weights)
197 :
198 4 : function updatevertexnormals!(g::AbstractGeometry, ::HasVN, weights)
199 8 : for v in vertices(_mesh(g))
200 16136 : updatenormal!(g, v, vertexnormal(g, v, weights))
201 16136 : end
202 : end
203 :
204 0 : updatevertexnormals!(g::AbstractGeometry, ::NoVN, weights) = nothing
205 :
206 :
207 : """
208 : g = geometry(mesh, x, ...)
209 : updatevertexnormals!(g[, weights=AngleWeights()])
210 :
211 : Recompute and update vertex normals using `weights` (see
212 : [`vertexnormal`](@ref).
213 :
214 : !!! note
215 : This method has **no effect** if `g` does not provide an attribute
216 : for vertex normals.
217 :
218 : !!! note
219 : This method does **not** update vertex normals.
220 : If `g` provides an attribute for vertex normals, they are assumed to be
221 : up to date and may be used w/o recomputation!
222 :
223 : See also [`geometry`](@ref), [`updatenormal!`](@ref), [`vertexnormal`](@ref),
224 : [`updatevertexnormals!`](@ref), [`updatenormals!`](@ref)
225 : """ updatevertexnormals!
226 :
227 12 : function updatenormals!(g::AbstractGeometry,
228 : weights::W=AngleWeights()) where {W<:VertexNormalWeights}
229 12 : updatefacenormals!(g)
230 12 : updatevertexnormals!(g, weights)
231 : end
232 :
233 : """
234 : g = geometry(mesh, x, ...)
235 : updatenormals!(g[, weights=AngleWeights()])
236 :
237 : Short for
238 :
239 : updatefacenormals!(g)
240 : updatevertexnormals!(g[, weights=AngleWeights()])
241 :
242 : """ updatenormals!
|