ExCodecs.Spatial.Codec.Binary (ex_codecs v0.2.0)

Copy Markdown View Source

Compact little-endian binary format for point clouds.

Layout

magic:   "EXCP" (4 bytes)
version: u16 LE = 1
flags:   u16 LE  (bit0=color, bit1=alpha, bit2=normal)
count:   u64 LE
records: count × record

Each record always has x,y,z as f32. Optional rgb/rgba as u8 and normals as f32 follow according to flags.

Generic attributes are not stored in this format — use PLY for that.

Summary

Functions

Decodes an EXCP version 1 payload into a point cloud.

Encodes a point cloud in the EXCP version 1 binary format.

Returns an enumerable over points in an EXCP payload.

Functions

decode(data, opts \\ [])

@spec decode(
  binary(),
  keyword()
) :: {:ok, ExCodecs.Spatial.PointCloud.t()} | {:error, ExCodecs.Error.t()}

Decodes an EXCP version 1 payload into a point cloud.

The decoder reads the global color/alpha/normal flags and the declared number of fixed-shape records described by encode/2. Trailing bytes are currently ignored. Decoded metadata contains %{"format" => "excp", "version" => 1}; attributes and other cloud-level fields use their constructor defaults.

Arguments

  • data (binary()) — a complete EXCP payload.
  • opts (keyword()) — reserved and currently ignored.

Returns

  • {:ok, %PointCloud{}}
  • {:error, %ExCodecs.Error{reason: :invalid_data, codec: :spatial_binary}} when the magic/header is invalid or too short, the version is not 1, or a declared coordinate, RGB/RGBA, or normal field is truncated.

Raises / exceptions

Corrupt/truncated payloads covered above are returned, and opts is ignored. This function has a catch-all data clause, so non-binary input also returns :invalid_data; it does not intentionally raise for external payloads.

Examples

iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> {:ok, bin} = ExCodecs.Spatial.Codec.Binary.encode(PointCloud.new([Point.new(1.0, 2.0, 3.0)]))
iex> {:ok, %PointCloud{points: [p]}} = ExCodecs.Spatial.Codec.Binary.decode(bin)
iex> p.x
1.0

encode(data, opts \\ [])

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

Encodes a point cloud in the EXCP version 1 binary format.

The 16-byte header is "EXCP", version u16 little-endian, global flags u16 little-endian, and point count u64 little-endian. Each record starts with three little-endian f32 coordinates. Global flag bits then add RGB (3 bytes), RGBA (4 bytes; alpha takes precedence), and/or three little-endian f32 normal components to every record.

Flags are selected from the whole cloud. Consequently, points missing an optional field are zero-filled (missing alpha is 255). Point attributes, cloud bounds, transform, and metadata are not represented.

Arguments

  • data (PointCloud.t()) — a cloud whose points are valid %Point{} structs with numeric coordinates, optional {r, g, b} or {r, g, b, a} color, and optional {nx, ny, nz} normal.
  • opts (keyword()) — reserved and currently ignored.

Returns

  • {:ok, payload} where payload is an EXCP binary().
  • {:error, %ExCodecs.Error{reason: :invalid_data, codec: :spatial_binary}} when data is not a %PointCloud{}.

Raises / exceptions

A wrong top-level type is returned as :invalid_data. Because opts is ignored, even a non-keyword value does not raise. Manually malformed cloud or point structs can raise FunctionClauseError, MatchError, ArgumentError, or a bitstring construction exception when a point, tuple shape, channel range, or numeric field violates the struct contract.

Examples

iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> cloud = PointCloud.new([Point.new(1, 2, 3, color: {10, 20, 30})])
iex> {:ok, <<"EXCP", 1::little-16, flags::little-16, 1::little-64, _::binary>>} =
...>   ExCodecs.Spatial.Codec.Binary.encode(cloud)
iex> Bitwise.band(flags, 0b001)
1

stream_decode(data, opts \\ [])

@spec stream_decode(
  binary(),
  keyword()
) :: Enumerable.t()

Returns an enumerable over points in an EXCP payload.

Arguments

  • data (binary()) — a complete EXCP payload.
  • opts (keyword()) — reserved and currently ignored.

Returns

An Enumerable.t() that yields decoded %Point{} values after the complete cloud has been materialized. If decode/2 fails, it yields exactly one {:error, %ExCodecs.Error{reason: :invalid_data, codec: :spatial_binary}} element.

Raises / exceptions

Raises FunctionClauseError when data is not a binary because this public function is guarded. opts is ignored. Binary validation failures are delayed as the single error element rather than raised.

Examples

iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> {:ok, bin} = ExCodecs.Spatial.Codec.Binary.encode(PointCloud.new([Point.new(0, 0, 0)]))
iex> [%Point{x: 0.0, y: 0.0, z: 0.0}] =
...>   ExCodecs.Spatial.Codec.Binary.stream_decode(bin) |> Enum.to_list()