ExCodecs.Spatial (ex_codecs v0.2.3)

Copy Markdown View Source

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

StructRole
ExCodecs.Spatial.PointXYZ (+ color, normal, attributes)
ExCodecs.Spatial.PointCloudList of points + bounds/metadata
ExCodecs.Spatial.GaussianSingle splat primitive
ExCodecs.Spatial.GaussianCloudList of Gaussians
ExCodecs.Spatial.BoundsAxis-aligned bounding box
ExCodecs.Spatial.TransformTranslation/rotation/scale metadata
ExCodecs.Spatial.MetadataComments and free-form entries

Formats

AtomModuleInput type
:plyExCodecs.Spatial.Codec.PLYPointCloud or GaussianCloud
:spatial_binaryExCodecs.Spatial.Codec.BinaryPointCloud (EXCP)
:gsplatExCodecs.Spatial.Codec.GsplatGaussianCloud (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

available_formats()

@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]

decode(data, opts \\ [])

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

encode(data, opts \\ [])

Encodes a point cloud or Gaussian cloud in a selected spatial format.

Arguments

  • data (PointCloud.t() | GaussianCloud.t()) - a point cloud for :ply or :spatial_binary, or a Gaussian cloud for :ply or :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_format selects :ascii, :binary, :binary_le, or :binary_be; :comments overrides 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} where payload is the encoded binary().
  • {:error, %ExCodecs.Error{reason: :invalid_data}} when data is 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 :format is 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

stream_decode(source, opts \\ [])

@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, use source: :file to force path interpretation or source: :binary to force payload interpretation.

  • opts (keyword()) - requires :format (:ply, :spatial_binary, or :gsplat). :source may 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_options when :format is missing.
  • reason: :unsupported_codec for an unknown format.
  • reason: :io_error when a forced or auto-detected file cannot be read.
  • reason: :invalid_data for 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

stream_encode(enumerable, opts \\ [])

@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 as encode/2.

Returns

  • {:ok, payload} where payload is a binary().
  • {:error, %ExCodecs.Error{reason: :invalid_options}} when :format is 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

supports?(format)

@spec supports?(atom()) :: boolean()

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