RasmahRasmah

.rasmah: The Parametric Model Format

using Rasmah

Overview

.rasmah is Rasmah’s own format. Unlike STL/VTK (a frozen mesh) or STEP (a frozen boundary representation), a .rasmah file serialises the parametric model itself — the feature operations and parameters that build the model — as a JSON (JavaScript Object Notation) document. It is the portable, human-readable source of truth: read one back and you get the full parametric model, not a snapshot of its geometry.

  • write_rasmah(model, io/path) — serialize the parametric model to JSON.
  • read_rasmah(io/path) — parse it back into the identical parametric model.

What gets stored

The model is built from features over plain values:

r = 0.5
model = difference(box(4.0, 2.0, 0.5), cylinder(r, 1.0))
Difference{Box{Float64, Float64, Float64}, Cylinder{Float64, Float64}}(Box{Float64, Float64, Float64}(4.0, 2.0, 0.5), Cylinder{Float64, Float64}(0.5, 1.0))

write_rasmah encodes the model as nested JSON — each feature operation records its inputs, and each parameter value is stored inline:

io = IOBuffer()
write_rasmah(model, io)
println(String(take!(io)))
{"node":{"type":"difference","children":[{"type":"box","children":[{"value":4.0,"type":"value"},{"value":2.0,"type":"value"},{"value":0.5,"type":"value"}]},{"type":"cylinder","children":[{"value":0.5,"type":"value"},{"value":1.0,"type":"value"}]}]},"schema":"rasmah","version":1}

That JSON is the whole model: difference → box + cylinder, where the cylinder’s radius is the value 0.5.

Writing and reading back

read_rasmah reconstructs the model exactly — the values come back as plain numbers, so the model is still parametric and still rebuildable:

mktempdir() do dir
    p = joinpath(dir, "bracket.rasmah")
    write_rasmah(model, p)

    model2 = read_rasmah(p)
    println("round-trip field: ", field(model2, [1.0, 0.0, 0.0]))
end
round-trip field: -0.25

The round-trip preserves the intent (a parametric model with a cylinder radius of 0.5), which a mesh or BRep format cannot.

Geometry is reproduced, not stored

Because the model is stored, the read-back model reproduces the exact same signed-distance field — no lossy re-sampling:

mktempdir() do dir
    p = joinpath(dir, "bracket.rasmah")
    write_rasmah(model, p)
    model2 = read_rasmah(p)
    println("field at origin: ", round(field(model, [0.0, 0.0, 0.0]); digits=6),
            "  vs  ", round(field(model2, [0.0, 0.0, 0.0]); digits=6))
end
field at origin: 0.5  vs  0.5

Streams and files

Every entry point accepts an IO stream or a path, so the same serializer works for files, byte buffers, and network sockets alike:

buf = IOBuffer()
write_rasmah(model, buf)
seekstart(buf)
println("round-trip via stream: ", field(read_rasmah(buf), [1.0, 0.0, 0.0]))
round-trip via stream: -0.25

When to use each format

Format Stores Use it to…
.rasmah parametric model keep the editable parametric model
.step exact BRep exchange exact geometry with CAD kernels
.vtk/.stl mesh hand geometry to meshers, solvers, viewers

.rasmah is the only one that keeps your design editable: the parametric model is reconstructed exactly, so the model can be re-optimised later.

Next steps