ASCII and binary PLY for point clouds and Gaussian splats.
Options
:format/:ply_format- wire encoding::ascii(default),:binary/:binary_le,:binary_be(not Spatial'sformat: :ply):comments- header comments:as- decode as:auto|:point_cloud|:gaussian_cloud:source- forstream_decode/2::auto|:file|:binary
Public functions: encode/2, decode/2, stream_decode/2.
Summary
Types
Wire encoding used for a PLY payload.
Functions
Decodes a complete PLY 1.0 payload into a point or Gaussian cloud.
Encodes a point cloud or Gaussian cloud as a PLY 1.0 payload.
Returns an enumerable over vertices from a PLY path or binary.
Types
@type ply_format() :: :ascii | :binary | :binary_le | :binary_be
Wire encoding used for a PLY payload.
:ascii writes textual scalar values. :binary_le and :binary_be write
packed scalar values in little- and big-endian order, respectively.
:binary is an encoding-option shorthand for :binary_le; decoded headers
report the explicit endian atom.
For example, encode(cloud, ply_format: :binary_be) emits a
format binary_big_endian 1.0 header.
Functions
@spec decode( binary(), keyword() ) :: {:ok, ExCodecs.Spatial.PointCloud.t() | ExCodecs.Spatial.GaussianCloud.t()} | {:error, ExCodecs.Error.t()}
Decodes a complete PLY 1.0 payload into a point or Gaussian cloud.
ASCII and binary little-/big-endian scalar vertex properties are supported:
char/int8, uchar/uint8, short/int16, ushort/uint16,
int/int32, uint/uint32, float/float32, and
double/float64. List properties and non-vertex payloads are unsupported.
Point decoding recognizes x/y/z, RGB or RGBA, and nx/ny/nz; all other
scalar properties become string-keyed point attributes. Gaussian decoding
interprets f_dc_*, opacity, scale, rotation, and ordered f_rest_*
properties. Header comments and the detected PLY format are retained in
cloud metadata.
Arguments
data(binary()) - the complete PLY header and vertex body.opts(keyword()) -:asmay be:auto(default),:point_cloud, or:gaussian_cloud.:autochooses Gaussian output when the property set containsf_dc_0,scale_0, orrot_0; otherwise it chooses points. The wire format is always read from the header.
Returns
{:ok, %PointCloud{}}or{:ok, %GaussianCloud{}}, including metadata.{:error, %ExCodecs.Error{reason: :invalid_data, codec: :ply}}for non-binary input, missing/invalid magic or format/header lines, missing vertex elements, invalid counts/properties, unsupported list/property types, invalid ASCII scalar tokens, token/property count mismatches, missingx/y/z, too few ASCII rows, or a short binary body.
Raises / exceptions
The listed structural failures are returned. Keyword.get/3 raises
FunctionClauseError when opts is not a proper keyword list. An unsupported
:as value raises CaseClauseError. Malformed binary row contents may also
raise (KeyError, ArgumentError, FunctionClauseError, or a bitstring match
exception) when scalar unpacking is not fully wrapped.
Examples
iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> cloud = PointCloud.new([Point.new(1.0, 0.0, 0.0, normal: {0.0, 0.0, 1.0})])
iex> {:ok, ply} = ExCodecs.Spatial.Codec.PLY.encode(cloud, ply_format: :binary_le)
iex> {:ok, %PointCloud{points: [point]}} = ExCodecs.Spatial.Codec.PLY.decode(ply)
iex> point.normal
{0.0, 0.0, 1.0}
@spec encode( ExCodecs.Spatial.PointCloud.t() | ExCodecs.Spatial.GaussianCloud.t(), keyword() ) :: {:ok, binary()} | {:error, ExCodecs.Error.t()}
Encodes a point cloud or Gaussian cloud as a PLY 1.0 payload.
Point vertices always contain x, y, and z as float. If any point has
color or a normal, the corresponding uchar RGB/RGBA or float normal
properties are emitted for every point; missing values are zero-filled
(alpha defaults to 255). The union of point attribute keys is emitted as
sorted float properties, with absent attributes set to 0.0.
Gaussian vertices contain position, f_dc_0..2, opacity, scale, and
quaternion rot_0..3 (w, x, y, z) as float. If spherical-harmonic
coefficients are present, flattened f_rest_N properties are appended and
shorter rows are zero-filled.
Arguments
data(PointCloud.t() | GaussianCloud.t()) - a cloud containing valid%Point{}or%Gaussian{}structs.opts(keyword()) - supported options::ply_format- preferred wire format::ascii(default),:binary(little-endian),:binary_le, or:binary_be.:format- legacy alias for:ply_formatwhen calling this codec directly.:ply_formattakes precedence.:comments- enumerable of strings for PLYcommentheader lines; defaults tocloud.metadata.comments.
:little and :big are also normalized to little-/big-endian output.
Unrecognized wire-format values return :invalid_options.
Returns
{:ok, payload}wherepayloadis an ASCII or binary PLYbinary().{:error, %ExCodecs.Error{reason: :invalid_options, codec: :ply}}when:format/:ply_formatis not a supported wire encoding.{:error, %ExCodecs.Error{reason: :invalid_data, codec: :ply}}whendatais not a supported cloud or any exception occurs while deriving properties, building the header, or encoding rows.
Raises / exceptions
The cloud clauses rescue encoding exceptions and return :invalid_data,
including invalid keyword options, malformed nested structs, non-string
comments, invalid scalar ranges/types, and bad attribute shapes. Unsupported
top-level data is also returned as :invalid_data; this function does not
intentionally raise.
Examples
iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> cloud = PointCloud.new([Point.new(0, 1, 2, color: {255, 64, 0})])
iex> {:ok, ply} = ExCodecs.Spatial.Codec.PLY.encode(cloud, ply_format: :ascii)
iex> String.contains?(ply, "property uchar red")
true
@spec stream_decode( binary() | Path.t(), keyword() ) :: Enumerable.t()
Returns an enumerable over vertices from a PLY path or binary.
Streaming behavior
source: :file(or:autopath detection): scans the header untilend_header, then yields one vertex at a time - binary formats via fixed-strideIO.binread/2, ASCII via line reads. Peak memory is O(header + one vertex / read chunk), not the whole cloud.source: :binary: still materializes throughdecode/2, then yields.
Arguments
source(Path.t() | binary()) - a path or complete PLY payload.opts(keyword()) -:sourcemay be:binary(default),:file, or:auto. Prefer:filefor paths and:binaryfor payloads;:autois opt-in path sniffing. PLY also accepts:as.:binary. Auto mode treats a short path-like binary as a file only when it names a regular file; otherwise it is payload data.:ashas the same meaning as indecode/2.
Returns
An Enumerable.t() yielding %Point{} or %Gaussian{}. Decode failures,
including reason: :invalid_data, are represented by exactly one
{:error, %ExCodecs.Error{}} element. A selected path that cannot be read
yields one error with reason: :io_error and the file reason in details.
Raises / exceptions
File and normal decode failures become stream elements. A non-binary
source raises FunctionClauseError. Keyword access raises
FunctionClauseError for invalid opts; unsupported :source values raise
CaseClauseError. Exceptions described by decode/2 may occur while the
stream is initialized or enumerated.
Examples
iex> alias ExCodecs.Spatial.{Point, PointCloud}
iex> {:ok, ply} = ExCodecs.Spatial.Codec.PLY.encode(PointCloud.new([Point.new(0, 0, 0)]))
iex> [%Point{x: 0.0}] = ExCodecs.Spatial.Codec.PLY.stream_decode(ply) |> Enum.to_list()