Simple little-endian binary format for Gaussian splat clouds.
Layout
magic: "GSPL" (4 bytes)
version: u16 LE = 1
flags: u16 LE (bit0 = has SH rest coeffs count in header)
count: u64 LE
sh_rest: u16 LE (number of f_rest floats per Gaussian; 0 if none)
records: count × recordEach record:
position: 3 × f32
color: 3 × f32 (f_dc)
opacity: f32
scale: 3 × f32
rotation: 4 × f32 (w, x, y, z)
sh_rest: sh_rest × f32 (optional)
Summary
Functions
Decodes a GSPL version 1 payload into a Gaussian cloud.
Encodes a Gaussian cloud in the GSPL version 1 binary format.
Returns an enumerable over Gaussians in a GSPL payload or file.
Streams %Gaussian{} values to a GSPL file using an explicit schema.
Functions
@spec decode( binary(), keyword() ) :: {:ok, ExCodecs.Spatial.GaussianCloud.t()} | {:error, ExCodecs.Error.t()}
Decodes a GSPL version 1 payload into a Gaussian cloud.
The decoder reads the header and declared record count described by
encode/2. When the shared SH-rest count is nonzero, each decoded
Gaussian's sh is [[r, g, b] | Enum.chunk_every(rest, 3)]; otherwise it
is nil. Trailing bytes and unknown flag bits are currently ignored.
Decoded cloud metadata contains %{"format" => "gsplat", "version" => 1}.
Arguments
data(binary()) - a complete GSPL payload.opts(keyword()) - reserved and currently ignored.
Returns
{:ok, %GaussianCloud{}}{:error, %ExCodecs.Error{reason: :invalid_data, codec: :gsplat}}when the magic/header is invalid or too short, the version is not 1, a declared 14-float record is truncated, or its declared SH-rest values are truncated.
Raises / exceptions
The external payload failures above are returned. opts is ignored, and
non-binary input is handled by the catch-all clause as :invalid_data; this
function does not intentionally raise for external payloads.
Examples
iex> alias ExCodecs.Spatial.{Gaussian, GaussianCloud}
iex> {:ok, bin} = ExCodecs.Spatial.Codec.Gsplat.encode(GaussianCloud.new([Gaussian.new({1.0, 0.0, 0.0})]))
iex> {:ok, %GaussianCloud{gaussians: [g]}} = ExCodecs.Spatial.Codec.Gsplat.decode(bin)
iex> elem(g.position, 0)
1.0
@spec encode( ExCodecs.Spatial.GaussianCloud.t(), keyword() ) :: {:ok, binary()} | {:error, ExCodecs.Error.t()}
Encodes a Gaussian cloud in the GSPL version 1 binary format.
The 18-byte header contains "GSPL", version u16 little-endian, flags
u16 little-endian, Gaussian count u64 little-endian, and a shared
spherical-harmonic-rest count u16 little-endian. Each record contains 14
little-endian f32 values: position XYZ, DC color RGB, opacity, scale XYZ,
and quaternion rotation (w, x, y, z), followed by the shared number of
little-endian f32 SH-rest values.
The shared SH count is the longest flattened rest coefficient list in the
cloud; shorter lists are padded with zero. The DC coefficient is represented
by Gaussian.color. Gaussian metadata and cloud-level metadata are not
stored.
Arguments
data(GaussianCloud.t()) - a cloud of valid%Gaussian{}structs. Each Gaussian has position/color/scale 3-tuples, a rotation 4-tuple, numeric opacity, and optional SH data shaped as[dc | rest](nested rest lists are flattened).opts(keyword()) - reserved and currently ignored.
Returns
{:ok, payload}wherepayloadis a GSPLbinary().{:error, %ExCodecs.Error{reason: :invalid_data, codec: :gsplat}}whendatais not a%GaussianCloud{}.
Raises / exceptions
A wrong top-level type is returned as :invalid_data, and opts is ignored.
Manually malformed cloud/Gaussian structs can raise FunctionClauseError,
MatchError, ArgumentError, ArithmeticError, or a bitstring construction
exception for invalid SH shapes, tuple shapes, counts, or non-numeric values.
Examples
iex> alias ExCodecs.Spatial.{Gaussian, GaussianCloud}
iex> cloud = GaussianCloud.new([Gaussian.new({0, 0, 0}, opacity: 0.75)])
iex> {:ok, <<"GSPL", 1::little-16, _flags::little-16, 1::little-64,
...> 0::little-16, _record::binary>>} =
...> ExCodecs.Spatial.Codec.Gsplat.encode(cloud)
iex> true
true
@spec stream_decode( Path.t() | binary(), keyword() ) :: Enumerable.t()
Returns an enumerable over Gaussians in a GSPL payload or file.
Streaming behavior
source: :file(or:autopath detection): header then chunked records - Rust mmap + DirtyCpu unpack when available, otherwiseIO.binread/2per record.source: :binary: chunked Rust unpack when available; otherwise materializes throughdecode/2.
Prefer source: :file for multi-MB / multi-GB .gspl paths.
Pass accel: false to force the pure-Elixir path.
Arguments
source(Path.t() | binary()) - filesystem path or complete GSPL payload. Both are binaries, so:sourcecontrols resolution.opts(keyword()) -:sourcemay be:binary(default),:file, or:auto. Prefer:filefor paths and:binaryfor payloads;:autois opt-in path sniffing (seedocs/spatial_formats.md).:binary.
Returns
An Enumerable.t() yielding %Gaussian{} values. Failures are delayed until
enumeration as exactly one {:error, %ExCodecs.Error{}}:
reason: :io_error- the file cannot be opened or readreason: :invalid_data- bad magic/version, truncated header, or a truncated record mid-stream (codec: :gsplat)
Raises / exceptions
Raises FunctionClauseError when source is not a binary. Unsupported
:source values raise CaseClauseError.
Examples
iex> alias ExCodecs.Spatial.{Gaussian, GaussianCloud}
iex> {:ok, bin} = ExCodecs.Spatial.Codec.Gsplat.encode(GaussianCloud.new([Gaussian.new({0, 0, 0})]))
iex> [%Gaussian{opacity: 1.0}] =
...> ExCodecs.Spatial.Codec.Gsplat.stream_decode(bin) |> Enum.to_list()
@spec stream_encode_to_file(Enumerable.t(), Path.t(), keyword()) :: :ok | {:error, ExCodecs.Error.t()}
Streams %Gaussian{} values to a GSPL file using an explicit schema.
Writes a placeholder header, encodes each Gaussian as it arrives, then seeks back to patch the final count. Peak memory is O(one Gaussian).
Arguments
enumerable(Enumerable.t()) -%Gaussian{}elements.path(Path.t()) - destination file path.opts(keyword()) - requires:schema. Use[]/%{}for no SH rest coefficients, or[sh_rest: n]/%{sh_rest: n}fornshared rest floats per Gaussian (shorter lists are zero-padded).
Returns
:ok{:error, %ExCodecs.Error{reason: :invalid_options}}when:schemais missing or invalid{:error, %ExCodecs.Error{reason: :invalid_data}}when an element is not a%Gaussian{}{:error, %ExCodecs.Error{reason: :io_error}}on file failures
Raises / exceptions
Schema and non-%Gaussian{} element failures are returned. Invalid path terms
or non-keyword opts can raise FunctionClauseError or ArgumentError in
the path/file/keyword APIs. Malformed Gaussian field shapes can raise during
bitstring construction (same class of exceptions as encode/2).
Examples
iex> alias ExCodecs.Spatial.{Gaussian, Codec.Gsplat}
iex> path = Path.join(System.tmp_dir!(), "gspl_enc_8.gspl")
iex> :ok = Gsplat.stream_encode_to_file([Gaussian.new({0, 0, 0})], path, schema: [])
iex> {:ok, <<"GSPL", _::binary>>} = File.read(path)
iex> File.rm!(path)
:ok