Spatial category API for point clouds and Gaussian splats.
ExCodecs is one codec framework with entry points specialized by data shape.
Binary→binary registry codecs use ExCodecs.encode/3 / decode/3; spatial
codecs map the domain structs below to and from interchange formats through
this module.
Domain types
| Struct | Role |
|---|---|
ExCodecs.Spatial.Point | XYZ (+ color, normal, attributes) |
ExCodecs.Spatial.PointCloud | List of points + bounds/metadata |
ExCodecs.Spatial.Gaussian | Single splat primitive |
ExCodecs.Spatial.GaussianCloud | List of Gaussians |
ExCodecs.Spatial.Bounds | Axis-aligned bounding box |
ExCodecs.Spatial.Transform | Translation/rotation/scale metadata |
ExCodecs.Spatial.Metadata | Comments and free-form entries |
Formats
| Atom | Module | Input type |
|---|---|---|
:ply | ExCodecs.Spatial.Codec.PLY | PointCloud or GaussianCloud |
:spatial_binary | ExCodecs.Spatial.Codec.Binary | PointCloud (EXCP) |
:gsplat | ExCodecs.Spatial.Codec.Gsplat | GaussianCloud (GSPL) |
Spatial formats are registered in the shared codec catalog. Discover all
entries with ExCodecs.available_codecs/0, or only this category with
available_formats/0.
Quick start
alias ExCodecs.Spatial.{Point, PointCloud}
cloud =
PointCloud.new([
Point.new(0.0, 0.0, 0.0, color: {255, 0, 0}),
Point.new(1.0, 1.0, 1.0, color: {0, 255, 0})
])
{:ok, ply} = ExCodecs.Spatial.encode(cloud, format: :ply)
{:ok, decoded} = ExCodecs.Spatial.decode(ply, format: :ply)Streaming note
EXCP (:spatial_binary), GSPL (:gsplat), and PLY file sources
(source: :file or :auto path detection) stream record-by-record from
disk: only the header and one record are held in memory at a time. Binary
PLY uses a fixed stride; ASCII PLY reads lines. In-memory binaries still
materialize through decode/2 before yielding, unless the spatial NIF is
loaded, in which case EXCP/GSPL use chunked Rust unpack. Prefer
source: :file for large paths, or source: :binary for payloads. See
docs/spatial_formats.md for :auto path heuristics and wire-format
layouts.
Summary
Functions
Lists the spatial formats accepted by this module.
Decodes a spatial payload into a point cloud or Gaussian cloud.
Encodes a point cloud or Gaussian cloud in a selected spatial format.
Returns an enumerable over points or Gaussians decoded from a path or binary.
Encodes an enumerable of points or Gaussians to one spatial payload.
Tests whether an atom names a supported spatial format.
Functions
@spec available_formats() :: [atom()]
Lists the spatial formats accepted by this module.
Arguments
This function takes no arguments.
Returns
The list [:ply, :spatial_binary, :gsplat], where :ply supports point and
Gaussian clouds, :spatial_binary supports point clouds, and :gsplat
supports Gaussian clouds.
Raises / exceptions
This function does not raise.
Examples
iex> ExCodecs.Spatial.available_formats()
[:ply, :spatial_binary, :gsplat]
@spec decode( binary(), keyword() ) :: {:ok, ExCodecs.Spatial.PointCloud.t() | ExCodecs.Spatial.GaussianCloud.t()} | {:error, ExCodecs.Error.t()}
Decodes a spatial payload into a point cloud or Gaussian cloud.
Arguments
data(binary()) - a complete encoded payload.opts(keyword()) - decode options::format-:ply(default),:spatial_binary, or:gsplat.:as- PLY interpretation::auto(default),:point_cloud, or:gaussian_cloud. In:auto, Gaussian property names select a%GaussianCloud{}; other vertex schemas select a%PointCloud{}.
Returns
{:ok, %PointCloud{}}for EXCP or point-oriented PLY.{:ok, %GaussianCloud{}}for GSPL or Gaussian-oriented PLY.{:error, %ExCodecs.Error{reason: :invalid_data}}for a non-binary input, bad magic/version, malformed or unsupported PLY header/property, missing/truncated records, or otherwise invalid payload.{:error, %ExCodecs.Error{reason: :unsupported_codec}}for an unknown:format.
Raises / exceptions
Payload validation failures are returned. Keyword.pop/3 and codec option
access raise FunctionClauseError when opts is not a proper keyword list.
For PLY, an unsupported :as value has no matching interpretation clause
and raises CaseClauseError; malformed ASCII rows can also surface
constructor/shape exceptions instead of an error tuple.
Examples
iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> {:ok, bin} = ExCodecs.Spatial.encode(PointCloud.new([Point.new(0.0, 0.0, 1.0)]), format: :ply)
iex> {:ok, %PointCloud{points: points}} = ExCodecs.Spatial.decode(bin, format: :ply)
iex> length(points)
1
@spec encode( ExCodecs.Spatial.PointCloud.t() | ExCodecs.Spatial.GaussianCloud.t(), keyword() ) :: {:ok, binary()} | {:error, ExCodecs.Error.t()}
Encodes a point cloud or Gaussian cloud in a selected spatial format.
Arguments
data(PointCloud.t() | GaussianCloud.t()) - a point cloud for:plyor:spatial_binary, or a Gaussian cloud for:plyor:gsplat.opts(keyword()) - options passed to the selected codec::format- spatial container::ply(default),:spatial_binary, or:gsplat. This key is removed before codec dispatch.- for PLY,
:ply_formatselects:ascii,:binary,:binary_le, or:binary_be;:commentsoverrides metadata comments. - the binary and GSPL codecs currently ignore remaining options.
%PointCloud{} contains a list of %Point{} values; %GaussianCloud{}
contains a list of %Gaussian{} values. See the selected codec for the
fields represented on the wire.
Returns
{:ok, payload}wherepayloadis the encodedbinary().{:error, %ExCodecs.Error{reason: :invalid_data}}whendatais not a supported cloud, the cloud type does not match the format, a PLY value cannot be encoded, or a malformed struct causes PLY encoding to fail.{:error, %ExCodecs.Error{reason: :unsupported_codec}}when:formatis not one of the supported spatial format atoms.
Raises / exceptions
Validation errors above are returned. Keyword.pop/3 raises
FunctionClauseError when opts is not a proper keyword list. EXCP and GSPL
encoding can also raise exceptions such as MatchError, FunctionClauseError,
or ArgumentError when callers manually construct malformed cloud/member
structs whose tuple shapes or numeric values violate the documented struct
contracts. PLY catches encoding exceptions and returns :invalid_data.
Examples
iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> cloud = PointCloud.new([Point.new(1.0, 2.0, 3.0)])
iex> {:ok, bin} = ExCodecs.Spatial.encode(cloud, format: :ply)
iex> is_binary(bin)
true
@spec stream_decode( Path.t() | binary(), keyword() ) :: Enumerable.t()
Returns an enumerable over points or Gaussians decoded from a path or binary.
File sources (source: :file or :auto path detection) stream
record-by-record: only the header and one record are held in memory at a
time. In-memory binaries materialize through decode/2 before yielding,
unless the spatial NIF is loaded, in which case EXCP/GSPL use chunked Rust
unpack. See ExCodecs.Spatial.Stream for details.
Arguments
source(Path.t() | binary()) - a filesystem path or encoded payload. Since paths are binaries in Elixir, usesource: :fileto force path interpretation orsource: :binaryto force payload interpretation.opts(keyword()) - requires:format(:ply,:spatial_binary, or:gsplat).:sourcemay be:auto(default),:file, or:binary; remaining options go to the selected decoder.
Returns
An Enumerable.t() yielding %Point{} or %Gaussian{}. On failure it
yields exactly one {:error, %ExCodecs.Error{}} element:
reason: :invalid_optionswhen:formatis missing.reason: :unsupported_codecfor an unknown format.reason: :io_errorwhen a forced or auto-detected file cannot be read.reason: :invalid_datafor malformed, unsupported, or truncated data.
Raises / exceptions
Missing :format is represented by an error element. Keyword operations
raise FunctionClauseError for a non-keyword opts. PLY only accepts a
binary/path source and raises FunctionClauseError otherwise. Invalid
:source values can raise CaseClauseError. Exceptions documented by the
selected decoder can occur while the returned stream is enumerated.
Examples
iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> {:ok, bin} = ExCodecs.Spatial.encode(PointCloud.new([Point.new(1.0, 0.0, 0.0)]), format: :ply)
iex> list = ExCodecs.Spatial.stream_decode(bin, format: :ply) |> Enum.to_list()
iex> match?([%Point{}], list)
true
@spec stream_encode( Enumerable.t(), keyword() ) :: {:ok, binary()} | {:error, ExCodecs.Error.t()}
Encodes an enumerable of points or Gaussians to one spatial payload.
The enumerable is fully collected so the codec can write the element count. A non-empty enumerable is classified by its first element and must contain valid values of that same struct type. An empty enumerable becomes an empty point cloud for PLY/EXCP or an empty Gaussian cloud for GSPL.
Arguments
enumerable(Enumerable.t()) -%Point{}or%Gaussian{}elements.opts(keyword()) - requires:format(:ply,:spatial_binary, or:gsplat); remaining options are the same asencode/2.
Returns
{:ok, payload}wherepayloadis abinary().{:error, %ExCodecs.Error{reason: :invalid_options}}when:formatis missing.{:error, %ExCodecs.Error{reason: :unsupported_codec}}for an unknown format.{:error, %ExCodecs.Error{reason: :invalid_data}}when the first element is not a point/Gaussian, is an error tuple, the primitive type does not match the format, or codec encoding fails.
Raises / exceptions
Missing :format is returned as :invalid_options. Enum.to_list/1 may
raise Protocol.UndefinedError for a non-enumerable or propagate an
exception raised by the enumerable. Keyword operations raise
FunctionClauseError for invalid opts; malformed member structs may raise
the codec exceptions described by encode/2.
Examples
iex> alias ExCodecs.Spatial.Point
iex> {:ok, bin} = ExCodecs.Spatial.stream_encode([Point.new(0.0, 0.0, 0.0)], format: :spatial_binary)
iex> is_binary(bin)
true
Tests whether an atom names a supported spatial format.
Arguments
format(atom()) - the candidate format name.
Returns
true for :ply, :spatial_binary, or :gsplat; otherwise false.
Raises / exceptions
Raises FunctionClauseError when format is not an atom because the public
function is guarded with is_atom/1.
Examples
iex> ExCodecs.Spatial.supports?(:ply)
true
iex> ExCodecs.Spatial.supports?(:sog)
false