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

          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

Generated by: LCOV version 1.16