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

          Line data    Source code
       1           0 : localframe(g::AbstractGeometry, f::FHnd) =
       2             :     localframe(g::AbstractGeometry, f::FHnd, _has_vx(g), _has_fn(g))
       3             : 
       4           0 : function localframe(g::AbstractGeometry, f::FHnd, ::HasVX, ::NoFN)
       5           0 :     x0, u, v = rawfacebase(g, f)
       6           0 :     u = normalize(u)
       7           0 :     nrm = normalize(u × v)
       8           0 :     v = normalize(u × nrm) # works w/o normalize up to rounding # TODO: check orientation
       9             : 
      10           0 :     x0, u, v, nrm
      11             : end
      12             : 
      13           0 : function localframe(g::AbstractGeometry, f::FHnd, ::HasVX, ::HasFN)
      14           0 :     h = halfedge(_mesh(g), f)
      15           0 :     u = edgevector(g, h)
      16           0 :     nrm = normal(g, f)
      17           0 :     @massert dot(u, nrm) ≈ 0
      18           0 :     u = normalize(u)
      19             : 
      20           0 :     _vpos(g)[source(h)], u, cross(u, nrm), nrm
      21             : end
      22             : 
      23           0 : localframe(g::AbstractGeometry, v::VHnd) =
      24             :     localframe(g, v, _has_vx(g), _has_vn(g))
      25             : 
      26           0 : localframe(g::AbstractGeometry, v::VHnd, ::HasVX, ::HasVN) =
      27             :     _vlocalframe(g, v, _vnrm(g)[v])
      28             : 
      29           0 : localframe(g::AbstractGeometry, v::VHnd, ::HasVX, ::NoVN) =
      30             :     _vlocalframe(g, v, normal(g, v))
      31             : 
      32           0 : function _vlocalframe(g, v, nrm)
      33           0 :     h = halfedge(_mesh(g), v)
      34           0 :     x0 = _vpos(g)[v]
      35           0 :     u = _vpos(g)[destination(_mesh(g), h)] - x0
      36             : 
      37           0 :     u -= dot(u, nrm) * nrm
      38           0 :     u = normalize(u)
      39             : 
      40           0 :     x0, u, cross(u, nrm), nrm
      41             : end
      42             : 
      43             : """
      44             :     g = geometry(mesh, x, ...)
      45             :     x0, u, v = localframe(g, f)
      46             : 
      47             : Compute orthonormal basis `u, v, n` such that `u, v` span plane of face
      48             : `f` and `n` is the normal vector. The origin is shifted to `x0`.
      49             : 
      50             :     x0, u, v, n = localframe(g, v)
      51             : 
      52             : Compute orthonormal basis `u, v, n` such that `u, v` span tangent plane
      53             : defined by vertex normal `n`. Here, `x0` is the position of vertex `v`.
      54             : 
      55             : !!! note
      56             :     This method uses stored [`normal`](@ref) if attribute is available.
      57             : 
      58             : !!! note
      59             :     This method is similar to [`tangentspace`](@ref) but returns also
      60             :     the normal vector.
      61             : 
      62             : See also [`geometry`](@ref), [`rawfacebase`](@ref), [`normal`](@ref),
      63             : [`tangentspace`](@ref), [`tolocal`](@ref)
      64             : """ localframe
      65             : 
      66           0 : function tolocal(g::AbstractGeometry, h::Hnd)
      67           0 :     x0, u, v, n = localframe(g, h)
      68           0 :     A = [u'; v'; n']
      69           0 :     affinemap(A, A * x0)
      70             : end
      71             : 
      72           0 : function tolocal(g::AbstractGeometry, h::Hnd, x)
      73           0 :     x0, u, v, n = localframe(g, h)
      74           0 :     [u v n]' * (x - x0)
      75             : end
      76             : 
      77             : """
      78             :     g = geometry(mesh, x, ...)
      79             :     u = tolocal(g, f, z)
      80             :     u = tolocal(g, v, z)
      81             : 
      82             :     m = tolocal(g, f)      # Provide callable object
      83             :     m = tolocal(g, v)
      84             :     u = m(z)
      85             : 
      86             :     invm = toworld(m)
      87             :     z = invm(u)
      88             : 
      89             : Transform 3d point `x` to 3d local coordinates `u` defined by
      90             : [`localframe`](@ref) of face `f` or vertex `v`.
      91             : 
      92             : !!! note
      93             :     The local coordinate system for a vertex `v` has `x[v]` as
      94             :     origin, i.e., `x[v]` is mapped to the null vector.
      95             : 
      96             : !!! tip
      97             :     Combine with [`positions`](@ref) to map, e.g., a 1-ring:
      98             : 
      99             :     ```julia
     100             :     us = map(tolocal(g, v) ∘ positions(g), ring(mesh, v))
     101             :     ```
     102             : 
     103             : See also [`localframe`](@ref), [`toworld`](@ref),
     104             : [`tolocal2d`](@ref), [`positions`](@ref)
     105             : """ tolocal
     106             : 
     107           0 : function tolocal2d(g::AbstractGeometry, h::Hnd)
     108           0 :     x0, u, v, _ = localframe(g, h)
     109           0 :     A = [u'; v']
     110           0 :     affinemap(A, A * x0)
     111             : end
     112             : 
     113           0 : function tolocal2d(g::AbstractGeometry, h::Hnd, x)
     114           0 :     x0, u, v = tangentspace(g, h)
     115           0 :     [u v]' * (x - x0)
     116             : end
     117             : 
     118             : """
     119             :     g = geometry(mesh, x, ...)
     120             :     u = tolocal2d(g, f, z)
     121             :     u = tolocal2d(g, v, z)
     122             : 
     123             :     f = tolocal2d(g, f)      # Provide callable object
     124             :     f = tolocal2d(g, v)
     125             :     u = f(x)
     126             : 
     127             : Transform point `x` 2d to local coordinates `u` defined by
     128             : [`tangentspace`](@ref) of face `f` or vertex `v`.
     129             : 
     130             : !!! note
     131             :     The local coordinate system for a vertex `v` has `x[v]` as
     132             :     origin, i.e., `x[v]` is mapped to the null vector.
     133             : 
     134             : !!! tip
     135             :     Combine with [`positions`](@ref) to map, e.g., a 1-ring:
     136             : 
     137             :     ```julia
     138             :     us = map(tolocal2d(g, v) ∘ positions(g), ring(mesh, v))
     139             :     ```
     140             : 
     141             : See also [`localframe`](@ref), [`tolocal`](@ref),
     142             : [`positions`](@ref)
     143             : """ tolocal2d
     144             : 
     145             : """
     146             :     g = geometry(mesh, x, ...)
     147             :     m = tolocal(g, ...)
     148             :     im = toworld(m)
     149             : 
     150             :     u = m(z)
     151             :     z = im(u)
     152             : 
     153             : Inverse map to affine map obtained from [`tolocal`](@ref) or
     154             : [`tolocal2d`](@ref).
     155             : 
     156             : !!! note
     157             :     [`toworld`](@ref) maps *points* in local coordinates to
     158             :     *points* in world coordinates by an *affine map*.
     159             : 
     160             :     Use [`linearmap`](@ref) or [`mapvector`](@ref) to obtain
     161             :     a *linear map* to map *vectors* in local coordinates to
     162             :     *vectors* in world coordinates.
     163             : 
     164             : !!! warning "precondition"
     165             :     Requires *rigid* transformation as obtained
     166             :     from [`tolocal`](@ref), i.e., `A'A == I`.
     167             : 
     168             : See also [`localframe`](@ref), [`tolocal`](@ref),
     169             : [`tolocal2d`](@ref)
     170             : """
     171           0 : toworld(f::AffineMap) = affinemap(f.A', -(f.A' * f.b))
     172             : 
     173             : """
     174             :     g = geometry(mesh, x, ...)
     175             :     x0, u, v = tangentspace(g, f)
     176             : 
     177             : Compute orthonormal basis u, v, for plane spanning face `f` with origin
     178             : shifted to `x0`.
     179             : 
     180             :     x0, u, v = tangentspace(g, v)
     181             : 
     182             : Compute orthonormal basis for tangent plane defined by vertex normal. Here,
     183             : `x0` is the position of vertex `v`.
     184             : 
     185             : !!! note
     186             :     This method uses stored [`normal`](@ref) if attribute is available.
     187             : 
     188             : !!! note
     189             :     This method is similar to [`localframe`](@ref) but does not return
     190             :      normal vector.
     191             : 
     192             : See also [`geometry`](@ref), [`rawfacebase`](@ref), [`normal`](@ref),
     193             : [`localframe`](@ref), [`projectintotangentspace`](@ref),
     194             : [`tolocal2d`](@ref)
     195             : """
     196           0 : function tangentspace(g::AbstractGeometry, h::Hnd)
     197           0 :     x0, u, v, _ = localframe(g, h)
     198           0 :     x0, u, v
     199             : end
     200             : 
     201           0 : function projectintotangentspace(g::AbstractGeometry, f::FHnd, x)
     202           0 :     m = _mesh(g)
     203           0 :     h = halfedge(m, f)
     204           0 :     x0 = _vpos(g)[destination(m, h)]
     205           0 :     nrm = normal(g, f)
     206             : 
     207           0 :     x - dot(x - x0, nrm) * nrm
     208             : end
     209             : 
     210           0 : function projectintotangentspace(g::AbstractGeometry, v::VHnd, x)
     211           0 :     x0 = _vpos(g)[v]
     212           0 :     nrm = normal(g, v)
     213             : 
     214           0 :     x - dot(x - x0, nrm) * nrm
     215             : end
     216             : 
     217             : """
     218             :     g = geometry(mesh, x, ...)
     219             :     xhat = projectintotangentspace(g, f, x)
     220             :     xhat = projectintotangentspace(g, v, x)
     221             : 
     222             : Project `x` into [`tangentspace`](@ref) of face `f` or vertex `v`. The
     223             : projection `xhat` is a 3d vector.
     224             : 
     225             : For a planar face `f`, its tangent space is the respective plane. For
     226             : a vertex `v`, its tangent space is defined implicitly by the
     227             : [`normal`](@ref) vector.
     228             : 
     229             : !!! note
     230             :     This method uses the stored [`normal`](@ref) if attribute is
     231             :     available. It does require a basis, i.e., does *not* call
     232             :     [`tangentspace`](@ref).
     233             : 
     234             : See also [`geometry`](@ref), [`normal`](@ref), [`tangentspace`](@ref)
     235             : """
     236             : projectintotangentspace

Generated by: LCOV version 1.16