More Interchange Formats: AMF, USD, X3D, Collada, SVG, UNV, EnSight
Overview
Beyond the core formats (STL, OBJ, PLY, VTK, MSH, INP, STEP, DICOM, NIfTI) and the modern interchange set (glTF, 3MF, XDMF, NRRD, IGES), Rasmah reads and writes a long tail of formats, each with a niche job:
- AMF — the XML additive-manufacturing format (millimetres).
- USD — Pixar’s scene-description format.
- X3D — the ISO web-3D format (meshes and line sets).
- Collada (DAE) — the digital-asset-exchange format.
- SVG — 2D vector line art.
- UNV / EnSight — legacy solver mesh formats (read-only).
using Rasmah
dir = mktempdir()
m = icosphere(1)TriangleMesh{Matrix{Float64}, Matrix{Int64}, Nothing}([-0.5257311121191336 0.5257311121191336 … 0.8090169943749475 1.0; 0.85065080835204 0.85065080835204 … -0.5000000000000001 0.0; 0.0 0.0 … -0.30901699437494745 0.0], [1 12 … 2 42; 13 14 … 24 31; 15 13 … 31 24], nothing)
AMF, USD, X3D and Collada (triangle meshes)
These all round-trip a TriangleMesh through their own serialisation:
write_amf(m, joinpath(dir, "sphere.amf"))
write_usd(m, joinpath(dir, "sphere.usd"))
write_x3d(m, joinpath(dir, "sphere.x3d"))
write_dae(m, joinpath(dir, "sphere.dae"))
println("AMF round-trip: ", length(read_amf(joinpath(dir, "sphere.amf")).vertices) == length(m.vertices))
println("USD round-trip: ", length(read_usd(joinpath(dir, "sphere.usd")).vertices) == length(m.vertices))
println("X3D round-trip: ", length(read_x3d(joinpath(dir, "sphere.x3d")).vertices) == length(m.vertices))
println("Collada round-trip: ", length(read_dae(joinpath(dir, "sphere.dae")).vertices) == length(m.vertices))AMF round-trip: true
USD round-trip: true
X3D round-trip: true
Collada round-trip: true
SVG (line art)
SVG stores 2D line sets. Build a LineMesh, write it, and read it back:
l = LineMesh([0.0 1.0 1.0 0.0; 0.0 0.0 1.0 1.0; 0.0 0.0 0.0 0.0], [1 2 3 4; 2 3 4 1])
write_svg(l, joinpath(dir, "square.svg"))
l2 = read_svg(joinpath(dir, "square.svg"))
println("SVG round-trip: ", l2 isa LineMesh)SVG round-trip: true
UNV (read-only, legacy solver mesh)
The UNV reader parses the I-deas solver format. Here a single tetrahedron is read from an inline deck:
unv = """
-1
2411
4
1
0.000000000000000D+00 0.000000000000000D+00 0.000000000000000D+00
2
1.000000000000000D+00 0.000000000000000D+00 0.000000000000000D+00
3
0.000000000000000D+00 1.000000000000000D+00 0.000000000000000D+00
4
0.000000000000000D+00 0.000000000000000D+00 1.000000000000000D+00
-1
2412
1
1 111 1 1 0 4
1 2 3 4
"""
um = read_unv(IOBuffer(unv))
println("UNV: ", typeof(um), " with ", size(um.nodes, 2), " nodes, ", size(um.elements, 2), " element")UNV: TetMesh{Matrix{Float64}, Matrix{Int64}, Nothing} with 4 nodes, 1 element
EnSight (read-only, CFD post-processing)
The EnSight reader parses the .geo geometry format:
geo = """
node id off
triangle
two lines of description
coordinates
3
0.0 1.0 0.0
0.0 0.0 1.0
0.0 0.0 0.0
tria3
part
1
part description
line two
1
1
1 2 3
"""
em = read_ensight(IOBuffer(geo))
println("EnSight: ", typeof(em), " with ", size(em.faces, 2), " face")EnSight: TriangleMesh{Matrix{Float64}, Matrix{Int64}, Nothing} with 1 face
Checkpoint / restart
write_checkpoint / read_checkpoint serialise any solver state (field vectors, snapshots, (; u, p), …) so a long run can be interrupted and resumed:
state = (u = rand(10), p = rand(10), t = 0.5)
write_checkpoint(state, joinpath(dir, "state.ckpt"))
restored = read_checkpoint(joinpath(dir, "state.ckpt"))
println("checkpoint round-trip: ", restored.u == state.u && restored.t == state.t)checkpoint round-trip: true
Next steps
- More interchange formats — glTF, 3MF, XDMF, NRRD, IGES.
- Converting representations — what is lossless and what is not.
