ExCodecs.Spatial.Stream (ex_codecs v0.2.3)

Copy Markdown View Source

Stream helpers for spatial formats.

What actually streams today

  • EXCP (:spatial_binary), GSPL (:gsplat), and PLY with source: :file (or :auto path detection) read the header, then one record/vertex at a time from disk - O(header + one record) memory. Binary PLY uses a fixed stride; ASCII PLY reads lines.
  • In-memory binaries still materialize through decode/2, then yield. A future Rust backend may memory-map large binaries.
  • encode_to_file/3 with an explicit :schema streams EXCP/GSPL to disk (placeholder header, then seek-back count patch). Without :schema, encoding still collects in memory first.

Prefer source: :file when the argument is a filesystem path, or source: :binary when it is an encoded payload (:binary is the default). With explicit :auto, a short path-like binary that names a regular file is opened; otherwise the argument is treated as payload bytes. Prefer explicit :file / :binary for untrusted input - :auto can open local paths. Path-like means under 4 KiB, no ply/EXCP/GSPL magic prefix, and contains / or \ or ends with .ply/.excp/.gspl/.bin, and File.regular?/1 is true.

Summary

Functions

Returns an enumerable over points or Gaussians decoded from a path or binary.

Encodes an enumerable of points or Gaussians after collecting it in memory.

Encodes spatial data and writes the binary to path.

Functions

decode(source, opts \\ [])

@spec decode(
  Path.t() | binary(),
  keyword()
) :: Enumerable.t()

Returns an enumerable over points or Gaussians decoded from a path or binary.

EXCP/GSPL/PLY file sources stream incrementally; in-memory binaries still materialize before emitting elements.

Arguments

  • source (Path.t() | binary()) - a path or complete encoded payload. Paths and payloads are both binaries, so :source controls resolution.

  • opts (keyword()) - requires :format: :ply, :spatial_binary, or :gsplat. :source may be :binary (default), :file, or :auto. :file, or :binary; PLY also accepts :as.

Returns

An Enumerable.t() yielding %Point{} for PLY/EXCP point clouds or %Gaussian{} for PLY/GSPL Gaussian clouds. A failure is delayed until enumeration and represented by exactly one {:error, %ExCodecs.Error{}} element:

  • reason: :invalid_options - :format is absent.
  • reason: :unsupported_codec - :format is unknown.
  • reason: :io_error - a selected file cannot be opened or read.
  • reason: :invalid_data - the payload is malformed, unsupported, or truncated.

Raises / exceptions

A missing format does not raise. Keyword.fetch/2 and decoder option access raise FunctionClauseError when opts is not a proper keyword list. PLY source dispatch raises FunctionClauseError for a non-binary source. EXCP/GSPL source resolution has no clause for non-binaries and may return an invalid value that causes CaseClauseError; an unsupported :source value also raises CaseClauseError. Decoder exceptions may occur during enumeration.

Examples

iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> {:ok, bin} = ExCodecs.Spatial.encode(PointCloud.new([Point.new(0.0, 0.0, 0.0)]), format: :ply)
iex> [%Point{}] = ExCodecs.Spatial.Stream.decode(bin, format: :ply) |> Enum.to_list()
iex> true
true

encode(enumerable, opts \\ [])

@spec encode(
  Enumerable.t(),
  keyword()
) :: {:ok, binary()} | {:error, ExCodecs.Error.t()}

Encodes an enumerable of points or Gaussians after collecting it in memory.

A non-empty enumerable is classified by its first element. Empty input is encoded as an empty %PointCloud{} for PLY/EXCP and as an empty %GaussianCloud{} for GSPL.

Arguments

  • enumerable (Enumerable.t()) - %Point{} or %Gaussian{} elements. The list should be homogeneous and contain valid struct shapes.
  • opts (keyword()) - requires :format: :ply, :spatial_binary, or :gsplat. Remaining keys are forwarded to ExCodecs.Spatial.encode/2.

Returns

  • {:ok, payload} where payload is a binary().
  • {:error, %ExCodecs.Error{reason: :invalid_options}} if :format is absent.
  • {:error, %ExCodecs.Error{reason: :unsupported_codec}} for an unknown format (including empty input).
  • {:error, %ExCodecs.Error{reason: :invalid_data}} when the first item is an error tuple or is not a %Point{}/%Gaussian{}, when cloud and format are incompatible, or when codec validation fails.

Raises / exceptions

Enum.to_list/1 raises Protocol.UndefinedError for a non-enumerable and propagates exceptions raised by enumeration. Keyword access raises FunctionClauseError for a non-keyword opts. Manually malformed point or Gaussian structs can raise codec shape/numeric exceptions; PLY converts its encoding exceptions to :invalid_data.

Examples

iex> alias ExCodecs.Spatial.Point
iex> {:ok, bin} = ExCodecs.Spatial.Stream.encode([Point.new(1.0, 0.0, 0.0)], format: :ply)
iex> is_binary(bin)
true

encode_to_file(data, path, opts \\ [])

@spec encode_to_file(
  Enumerable.t()
  | ExCodecs.Spatial.PointCloud.t()
  | ExCodecs.Spatial.GaussianCloud.t(),
  Path.t(),
  keyword()
) :: :ok | {:error, ExCodecs.Error.t()}

Encodes spatial data and writes the binary to path.

When :schema is present and :format is :spatial_binary or :gsplat, points/Gaussians are written incrementally via Binary.stream_encode_to_file/3 / Gsplat.stream_encode_to_file/3 (placeholder header + seek-back count). Otherwise the payload is encoded in memory and written with File.write/2.

Arguments

  • data (PointCloud.t() | GaussianCloud.t() | Enumerable.t()) - a cloud, or an enumerable of %Point{}/%Gaussian{} values.

  • path (Path.t()) - destination path; parent directories must already exist.
  • opts (keyword()) - the options for ExCodecs.Spatial.encode/2, with :format required for enumerable input and defaulting to :ply for an already-built cloud. For streaming EXCP/GSPL writes, pass :schema (see codec docs).

Returns

  • :ok after the complete payload is written.
  • any :invalid_options, :unsupported_codec, or :invalid_data error returned by encoding.
  • {:error, %ExCodecs.Error{reason: :io_error, details: reason}} when a file/POSIX error occurs (e.g. :enoent, :eacces, :enospc).

Raises / exceptions

Normal path/POSIX failures are returned. Invalid path terms or non-path binaries can raise FunctionClauseError or ArgumentError in the path/file APIs. Encoding also has the enumerable, keyword, and malformed-struct exceptions documented by encode/2.

Examples

iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> path = Path.join(System.tmp_dir!(), "ex_codecs_doc_3202.ply")
iex> :ok = ExCodecs.Spatial.Stream.encode_to_file(PointCloud.new([Point.new(0, 0, 0)]), path, format: :ply)
iex> {:ok, "ply" <> _} = File.read(path)
iex> File.rm!(path)
:ok