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

          Line data    Source code
       1             : using FileIO
       2             : import GeometryBasics
       3             : using  GeometryBasics: coordinates, meta,
       4             :        GLTriangleFace, Point3, Vec3, Vec2, Point
       5             : 
       6             : # NOTE: Look at Meshes.jl and GeoIO.jl for more readers
       7             : 
       8             : """
       9             :     mesh = createmesh(mobj::GeometryBasics.Mesh, template::Mesh;
      10             :                       [position = :x])
      11             : 
      12             : Convert `GeometryBasics.Mesh` to `Mesh`.
      13             : """
      14           0 : function createmesh(mobj::GeometryBasics.Mesh,
      15             :                     template::Mesh{V, F, H, E};
      16             :                     position=Val(:x),
      17             :                     normal=Val(:n), texcoord=Val(:u)) where {V, F, H, E}
      18           0 :     n = length(coordinates(mobj))
      19           0 :     m = length(GeometryBasics.faces(mobj))
      20             : 
      21           0 :     mesh = similar(template)
      22             : 
      23           0 :     sizehint!(mesh, n, m)
      24             : 
      25           0 :     addvertices!(mesh, n)
      26             : 
      27           0 :     maybesetvattr(f, name::Symbol) = maybeattr(f, Val(S))
      28             : 
      29           0 :     function maybesetvattr(f, ::Val{S}) where {S}
      30           0 :         hasvattr(mesh, S) || return nothing
      31           0 :         attr = vattr(mesh, Val(S))
      32           0 :         isenabled(attr) && f(attr)
      33           0 :         nothing
      34             :     end
      35             : 
      36           0 :     vx = vattr(mesh, position)
      37             : 
      38           0 :     for (j, c) in enumerate(coordinates(mobj))
      39           0 :         vx[VHnd(j)] = c
      40           0 :     end
      41             : 
      42           0 :     for f in GeometryBasics.faces(mobj)
      43           0 :         addface!(mesh, VHnd.(convert.(Int, f))...)
      44           0 :     end
      45             : 
      46           0 :     hasproperty(mobj, :normal) && maybesetvattr(normal) do vn
      47           0 :         if isa(GeometryBasics.normals(mobj), GeometryBasics.FaceView)
      48           0 :             @warn "Drop vertex normals from GeometryBasics.FaceView"
      49           0 :             return nothing
      50             :         end
      51             : 
      52           0 :         for (j, n) in enumerate(GeometryBasics.normals(mobj))
      53           0 :             vn[VHnd(j)] = n
      54           0 :         end
      55             :     end
      56             : 
      57           0 :     hasproperty(mobj, :uv) && maybesetvattr(texcoord) do vu
      58           0 :         for (j, u) in enumerate(GeometryBasics.texturecoordinates(mobj))
      59           0 :             vu[VHnd(j)] = u
      60           0 :         end
      61             :     end
      62             : 
      63           0 :     mesh
      64             : end
      65             : 
      66             : # TODO: MeshIO loaders don't recognize all options (OFF fails for
      67             : #       uvtyupe=...), but I have problems passing just options...
      68             : #       -- currently restriction to pointstype
      69             : 
      70             : """
      71             :     mesh, mobj = read(:MeshIO, filename, template::Mesh
      72             :                       [; position=:x, exceptions=false,
      73             :                          pointstype=Point3])
      74             : 
      75             : Load `mesh` from file, e.g., in OFF format using
      76             : [`FileIO`](https://juliaio.github.io/FileIO.jl/stable/) and
      77             : [`GeometryBasics`](https://juliageometry.github.io/GeometryBasics.jl/stable/)
      78             : 
      79             : `mobj` is the mesh as defined by `GeometryBasics` and can be used for
      80             : rendering. `GeometryBasics.coordinates(mobj)` and `GeometryBasics.faces(mobj)`
      81             : provide `Vector`s of vertex positions and triangle indices, respectively.
      82             : 
      83             : !!! warning "Precondition"
      84             :     This method requires a **triangle mesh**!
      85             : 
      86             : !!! warning
      87             :     `MeshIO.load` takes keyword arguments `uvtype` and `normaltype` only
      88             :     for file formats, which support these. For other formats, it just
      89             :     fails. We stick to the default settings (`Float32`) and pass only
      90             :     the vertex position type.
      91             : 
      92             : !!! note
      93             :     For some file formats (e.g., OBJ), `FileIO.load` returns a `MetaMesh`.
      94             :     We drop the meta data, which may include material properties etc.
      95             : """
      96           0 : function Base.read(::Val{:MeshIO},
      97             :                    filename::AbstractString,
      98             :                    template::Mesh{V, F, H, E};
      99             :                    position=Val(:x),
     100             :                    normal=Val(:n), texcoord=Val(:u),
     101             :                    exceptions::Bool=false,
     102             :                    pointstype=Point3{Float32},
     103             :                    options...) where {V, F, H, E}
     104           0 :     try
     105             :         # NOTE: MeshIO labels option "pointtype" instead of "pointstype" !!
     106           0 :         mobj = GeometryBasics.Mesh(FileIO.load(abspath(filename);
     107             :                                             pointtype=pointstype)) :: GeometryBasics.Mesh
     108             :         # NOTE: Mesh(...) drops extras from MetaMesh (e.g., from OBJ)
     109             : 
     110           0 :         createmesh(mobj, template; position, normal, texcoord), mobj
     111             :     catch e
     112           0 :         exceptions && rethrow()
     113           0 :         showerror(stderr, e, Base.catch_backtrace())
     114           0 :         nothing
     115             :     end
     116             : end
     117             : 
     118           0 : _len(::Type{SVector{N, T}}) where {N, T} = N
     119           0 : _len(::Type{NTuple{N, T}}) where {N, T} = N
     120           0 : _len(::Type{T}) where {T<:Number} = 1
     121             : 
     122           0 : toPoint(x::V, p::Point{N, T}) where {V, N, T} =
     123             :     toPoint(x, Val(_len(V)), p) :: Point{N, T}
     124             : 
     125           0 : toPoint(x, ::Val{N}, p::Point{N, T}) where {N, T} = Point{N, T}(x...)
     126             : 
     127           0 : toPoint(x, m::Val{M}, p::Point{N, T}) where {M, N, T} =
     128             :     toPoint(x, m, Val(M < N), p)
     129           0 : toPoint(x, ::Val{M}, ::Val{true}, _::Point{N, T}) where {M, N, T} =
     130             :     Point{N, T}(x..., (zero(T) for _ in M+1:N)...)
     131           0 : toPoint(x, ::Val{M}, ::Val{false}, _::Point{N, T}) where {M, N, T} =
     132           0 :     Point{N, T}(ntuple(i -> x[i], N)...)
     133             : 
     134           0 : toPoints(vx::Attribute{V}, pointstype::Point{N, T}, n) where {V, N, T} =
     135             :     [ toPoint(vx[VHnd(j)], pointstype) for j in 1:n ]
     136             : 
     137             : # TODO: make this type stable
     138             : 
     139           0 : function meshobj(mesh::Mesh;
     140             :                  position = Val(:x),
     141             :                  uv = nothing, normals = nothing,
     142             :                  pointstype::Type{Point{N, T}} = Point3{Float32},
     143             :                  uvtype=Vec2{Float32},
     144             :                  normaltype=Vec3{Float32}) where {N, T}
     145             :     # see, e.g., https://github.com/JuliaIO/MeshIO.jl/blob/master/src/io/obj.jl
     146           0 :     n = n_total(vattr(mesh))
     147           0 :     m = nf(mesh)
     148             : 
     149           0 :     @massert istrianglemesh(mesh)
     150             : 
     151           0 :     vx = vattr(mesh, position)
     152           0 :     points = toPoints(vx, zero(pointstype), n)
     153             : 
     154           0 :     t = triangletable(mesh)
     155           0 :     faces = [ GLTriangleFace(t[j]...) for j in 1:m ]
     156             : 
     157           0 :     point_attributes = Dict{Symbol, Any}()
     158             : 
     159           0 :     if uv !== nothing
     160           0 :         u =  vattr(mesh, uv)
     161           0 :         point_attributes[:uv] = [ uvtype(u[VHnd(j)]...) for j in 1:n ]
     162             :     end
     163             : 
     164           0 :     if normals !== nothing
     165           0 :         point_attributes[:normals] =
     166             :             if normals == :auto
     167           0 :                 GeometryBasics.normals(points, faces)
     168             :             else
     169           0 :                 nrm =  vattr(mesh, normals)
     170           0 :                 [ normalize(normaltype(nrm[VHnd(j)]...)) for j in 1:n ]
     171             :             end
     172             :     end
     173             : 
     174             :     # GeometryBasics.Mesh(meta(points; point_attributes...), faces) # < v0.5.0
     175           0 :     GeometryBasics.Mesh(points, faces; point_attributes...)         # >=v0.0.5
     176             : end
     177             : 
     178             : """
     179             :     mobj = meshobj(mesh[; position=:x, uv=nothing, normals=nothing,
     180             :                           pointstype = Point3, uvtype=Vec2,
     181             :                           normaltype=Vec3])
     182             : 
     183             : Convert `mesh` to mesh as defined by
     184             : [`GeometryBasics`](https://juliageometry.github.io/GeometryBasics.jl),
     185             : which can be used for rendering, e.g., with
     186             : [`Makie`](https://makie.juliaplots.org) (see `Makie.mesh`). Texture
     187             : coordinates `uv` are passed as matrix columns or as a function that
     188             : maps vertex positions. Normals are passed as a matrix. They are
     189             : estimated if either `:auto` or an empty matrix is passed.
     190             : 
     191             : The argument `normals` is used as follows:
     192             : 
     193             : - `nothing`: don't include normals as attributes
     194             : - `:auto`: have `GeometryBasics` compute normals
     195             : - use provided *attribute* as normals.
     196             : 
     197             : The dimension `ni` of the input `position` attribute may differ from the
     198             : dimension `no` of the output `pointstype`:
     199             : 
     200             : - `ni == no` copy (possibly convert types)
     201             : - `ni < no` copy and fill remaining components of output with zeros
     202             : - `ni > ni` copy only fist `no` dimensions of input
     203             : 
     204             : !!! note
     205             :     `meshobj` calls [`triangletable`](@ref) and *not*
     206             :     [`compacttriangletable`](@ref), i.e., the returned object may represent
     207             :     a mesh including unused vertices.
     208             : 
     209             : """ meshobj

Generated by: LCOV version 1.16