LCOV - code coverage report
Current view: top level - src/geometry - vnormals.jl (source / functions) Hit Total Coverage
Test: on branch nothing Lines: 71 76 93.4 %
Date: 2025-07-10 13:12:25 Functions: 0 0 -

          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!

Generated by: LCOV version 1.16