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

          Line data    Source code
       1             : #
       2             : # --- DEPRECATED!!! --- (see MP example 2023)
       3             : #
       4             : 
       5             : using LinearAlgebra
       6             : using Statistics
       7             : 
       8             : # TODO: use geometry(), defin helper for "marking" fearures & sizing fields
       9             : # TODO: provide/store context in a IsometricRemeshing struct
      10             : 
      11           0 : function facenormals!(mesh; pos::Symbol=:x, fnrm::Symbol=:n, farea::Symbol=:a)
      12           0 :     x = vattr(mesh, pos)
      13           0 :     fn = fattr(mesh, fnrm)
      14           0 :     area = fattr(mesh, farea)
      15             : 
      16           0 :     for f in faces(mesh)
      17           0 :         h = halfedge(mesh, f)
      18           0 :         v0, vc = vertices(mesh, h)
      19           0 :         v1 = destination(mesh, next(mesh, h))
      20             : 
      21           0 :         u = x[v0] - x[vc]
      22           0 :         v = x[v1] - x[vc]
      23             : 
      24           0 :         nrm = cross(u, v)
      25           0 :         ar2 = norm(nrm)
      26           0 :         area[f] =  ar2 / 2
      27             : 
      28           0 :         if ar2 > eps(ar2)
      29           0 :             fn[f] = nrm / ar2
      30             :         else
      31           0 :             fn[f] = zeros(typeof(nrm))
      32             :         end
      33           0 :     end
      34             : end
      35             : 
      36             : # TODO: face areas
      37             : 
      38           0 : function normals!(mesh;
      39             :                   pos::Symbol=:x, vnrm::Symbol=:n,
      40             :                   fnrm::Symbol=:n, farea::Symbol=:a)
      41           0 :     x = vattr(mesh, pos)
      42           0 :     vn = vattr(mesh, vnrm)
      43           0 :     fn = fattr(mesh, fnrm)
      44           0 :     area = fattr(mesh, farea)
      45             : 
      46           0 :     facenormals!(mesh; pos, fnrm, farea)
      47             : 
      48           0 :     for v in vertices(mesh)
      49           0 :         nrm = sum(fn[f] * area[f] for f in fan(mesh, v))
      50           0 :         vn[v] = nrm / norm(nrm)
      51           0 :     end
      52             : end
      53             : 
      54           0 : function tangentialsmoothing!(mesh, k::Int=1, μ=0.25;
      55             :                               pos::Symbol=:x, vnrm::Symbol=:n,
      56             :                               fnrm::Symbol=:n, farea::Symbol=:a)
      57           0 :     @info "tangential smoothing μ=$μ, k=$k"
      58             : 
      59           0 :     normals!(mesh; pos, vnrm, fnrm)
      60             : 
      61           0 :     for _ in 1:k
      62           0 :         _tangentialsmoothing!(mesh, μ; pos, vnrm)
      63           0 :     end
      64             : end
      65             : 
      66           0 : function _tangentialsmoothing!(mesh, μ;
      67             :                                pos::Symbol=:x, vnrm::Symbol=:n,
      68             :                                farea::Symbol=:a)
      69           0 :     x = vattr(mesh, pos)
      70           0 :     vn = vattr(mesh, vnrm)
      71             : 
      72             :     # TODO: store update vector?
      73           0 :     @assert allfinite(mesh)
      74             : 
      75           0 :     for v in vertices(mesh)
      76           0 :         u = (mean(x[vn] for vn in ring(mesh, v)) - x[v]) * μ
      77           0 :         n = vn[v]
      78             : 
      79           0 :         if !isfinite(sum(n))
      80           0 :             @show v
      81           0 :             @show x[v]
      82           0 :             @show degree(mesh, v)
      83           0 :             @show [fattr(mesh, :n)[f] for f in fan(mesh, v)]
      84           0 :             @show [fattr(mesh, :a)[f] for f in fan(mesh, v)]
      85             : 
      86           0 :             break
      87             :         end
      88             : 
      89           0 :         if !isfinite(sum(u))
      90           0 :             @show v
      91           0 :             @show [vn for vn in ring(mesh, v)]
      92           0 :             @show [isused(mesh, vn) for vn in ring(mesh, v)]
      93           0 :             @show [x[vn] for vn in ring(mesh, v)]
      94           0 :             @show x[v]
      95           0 :             @show u
      96           0 :             @show mean(x[vn] for vn in ring(mesh, v))
      97           0 :             @show sum(x[vn] for vn in ring(mesh, v))
      98           0 :             @show degree(mesh, v)
      99           0 :             break
     100             :         end
     101             : 
     102           0 :         x[v] += u - dot(u, n) * n
     103           0 :     end
     104             : end
     105             : 
     106             : # TODO: projection (w/ distance queries)
     107             : 
     108             : #-----------------------------------------------------------------------------
     109             : 
     110             : # TODO: pass arguments
     111             : 
     112             : # TODO: check isfinite
     113             : 
     114           0 : function allfinite(mesh)
     115           0 :     x = vattr(mesh, :x)
     116             : 
     117           0 :    all(isfinite(sum(x[v])) for v in vertices(mesh))
     118             : end
     119             : 
     120             : ###
     121             : 
     122           0 : remesh!(mesh;
     123             :         k=32,
     124             :         pos::Symbol=:x, vnrm::Symbol=:n,
     125             :         fnrm::Symbol=:n, farea::Symbol=:a) =
     126             :     remesh!(mesh, mean(edgelengths(mesh, pos)); k, pos, vnrm, fnrm, farea)
     127             : 
     128           0 : function remesh!(mesh, len;
     129             :                  k=32,
     130             :                  pos::Symbol=:x, vnrm::Symbol=:n,
     131             :                  fnrm::Symbol=:n, farea::Symbol=:a)
     132             :     # TODO: no special cases for feature edges, boundaries, adaptive sizing
     133             : 
     134           0 :     for _ in 1:k
     135           0 :         splitlongedges!(mesh, 4len/3, pos)
     136           0 :         @assert allfinite(mesh)
     137           0 :         collapseshortedges!(mesh, 4len/5, pos)
     138           0 :         @assert allfinite(mesh)
     139           0 :         balancevalence!(mesh)
     140           0 :         tangentialsmoothing!(mesh; pos, vnrm, fnrm, farea)
     141           0 :         @assert allfinite(mesh)
     142             :         # TODO: projection
     143           0 :     end
     144             : end
     145             : 
     146             : """
     147             :     remesh!(mesh[, len=meanedgelength(mesh);
     148             :             k=32, pos=:x, vnrm=:n, fnrm=:n, farea=:a)
     149             : 
     150             : Apply `k` iterations of isotropic remeshing (w/o projection onto the mesh).
     151             : 
     152             : !!! warning
     153             :     This method is intended only for tests and benchmarks!
     154             : """ remesh!
     155             : 
     156           0 : function splitlongedges!(mesh, lmax, pos::Symbol=:x)
     157           0 :     @info "split long edges"
     158           0 :     n = 0
     159           0 :     x = vattr(mesh, pos)
     160           0 :     for _ in 1:10
     161           0 :         done = true
     162           0 :         for e in edges(mesh)
     163           0 :             v01 = vertices(mesh, e)
     164           0 :             (edgelength(mesh, v01, x) <= lmax) && continue
     165             : 
     166           0 :             done = false
     167           0 :             _, vnew = split!(mesh, e)
     168           0 :             x[vnew] = (x[v01[1]] + x[v01[2]]) / 2
     169           0 :             n += 1
     170           0 :         end
     171             : 
     172           0 :         done && break
     173           0 :     end
     174           0 :     @info "$n splits"
     175             : end
     176             : 
     177           0 : function collapseshortedges!(mesh, lmin, pos::Symbol=:x)
     178           0 :     @info "collapse short edges"
     179           0 :     n = 0
     180           0 :     x = vattr(mesh, pos)
     181           0 :     for _ in 1:10
     182           0 :         done = true
     183           0 :         for e in edges(mesh)
     184           0 :             isused(mesh, e) || continue
     185             : 
     186           0 :             (edgelength(mesh, e, x) >= lmin) && continue
     187             : 
     188           0 :             hs = halfedges(mesh, e)
     189           0 :             yes = (maycollapse(mesh, h) for h in hs)
     190           0 :             any(yes) || continue
     191             : 
     192           0 :             h =
     193             :                 if all(yes)
     194           0 :                     ds = tuple((degree(mesh, destination(mesh, h)) for h in hs)...)
     195           0 :                     ds[1] >= ds[2] ? hs[1] : hs[2]
     196             :                 else
     197           0 :                     yes[1] ? hs[1] : hs[2]
     198             :                 end
     199             : 
     200           0 :             done = false
     201           0 :             collapse!(mesh, h)
     202             : 
     203           0 :             n += 1
     204           0 :         end
     205             : 
     206           0 :         done && break
     207           0 :     end
     208           0 :     compact!(mesh; stable=false)
     209           0 :     @info "$n collapses & compact"
     210             : end
     211             : 
     212           0 : function balancevalence!(mesh)
     213           0 :     @info "balance valance"
     214           0 :     n = 0
     215             : 
     216           0 :     for _ in 1:10
     217           0 :         done = true
     218             : 
     219           0 :         for e in edges(mesh)
     220           0 :             mayflip(mesh, e) || continue
     221             : 
     222           0 :             h1, h2 = halfedges(mesh, e)
     223           0 :             vl = destination(mesh, h1)
     224           0 :             vr = destination(mesh, h2)
     225           0 :             vu = destination(mesh, next(mesh, h1))
     226           0 :             vd = destination(mesh, next(mesh, h2))
     227             : 
     228           0 :             ds = tuple((degree(mesh, v) for v in (vl, vr, vu, vd))...)
     229           0 :             before = sum((d-6)^2 for d in ds)
     230             : 
     231           0 :             ds = (ds[1]-1, ds[2]-1, ds[3]+1, ds[4]+1)
     232           0 :             after = sum((d-6)^2 for d in ds)
     233             : 
     234           0 :             (before <= after) && continue
     235             : 
     236           0 :             flip!(mesh, e)
     237           0 :             done = false
     238           0 :             n += 1
     239           0 :         end
     240             : 
     241           0 :         done && break
     242           0 :     end
     243           0 :     @info "$n flips"
     244           0 :     n
     245             : end

Generated by: LCOV version 1.16