pcd_rs/
lib.rs

1//! Read and write PCD file format.
2//!
3//! This crate provides data serializer and deserializer for PCD
4//! (Point Cloud Data) file format. The [DynReader] and [DynWriter]
5//! can read and write PCD files with any valid schemas. It also
6//! supports deserializing to static types if the `derive` feature is
7//! enabled.
8//!
9//! # Supported Format Versions
10//!
11//! - 0.7
12//! - Older versions are not supported yet.
13//!
14//!
15//! # Any Schema Example
16//!
17//! In the case of any schema, the points are represented by an array
18//! or a slice of [DynRecord]s, where is record wraps a sequence of
19//! data [Field]s.
20//!
21//! ## Reader
22//!
23//! The reader is created by [DynReader::open()], returning an
24//! iterator, which generates a sequence of
25//! [Result\<DynRecord\>](DynRecord).
26//!
27//! ```rust
28//! # fn main() -> pcd_rs::pcd_rsResult<()>  {
29//! use pcd_rs::DynReader;
30//!
31//! // Declare the reader
32//! let reader = DynReader::open("test_files/binary.pcd")?;
33//!
34//! // The reader itself is an iterator of records
35//! let points: Result<Vec<_>> = reader.collect();
36//! println!("There are {} points found.", points?.len());
37//! # Ok(())
38//! # }
39//! ```
40//!
41//! ## Writer
42//!
43//! The writer is first configured by [WriterInit], and then call
44//! [WriterInit::create()] to construct the [DynWriter]. The
45//! [.push()](DynWriter::push) is used to append the data to the
46//! writer. The writer must be finished by
47//! [.finish()](DynWriter::finish) in the end.
48//!
49//! ```rust
50//! # fn main() -> pcd_rs::pcd_rs::Result<()>  {
51//! use pcd_rs::{DataKind, DynRecord, DynWriter, Field, Schema, ValueKind, WriterInit};
52//!
53//! // Declare point data
54//! let points = [
55//!     DynRecord(vec![
56//!         Field::F32(vec![3.14159]),
57//!         Field::U8(vec![2, 1, 7]),
58//!         Field::I32(vec![-5]),
59//!     ]),
60//!     DynRecord(vec![
61//!         Field::F32(vec![-0.0]),
62//!         Field::U8(vec![254, 6, 98]),
63//!         Field::I32(vec![7]),
64//!     ]),
65//!     DynRecord(vec![
66//!         Field::F32(vec![5.6]),
67//!         Field::U8(vec![4, 0, 111]),
68//!         Field::I32(vec![-100000]),
69//!     ]),
70//! ];
71//!
72//! // Declare the schema
73//! let schema = vec![
74//!     ("x", ValueKind::F32, 1),
75//!     ("y", ValueKind::U8, 3),
76//!     ("z", ValueKind::I32, 1),
77//! ];
78//!
79//! // Build a writer
80//! let mut writer: DynWriter<_> = WriterInit {
81//!     width: 300,
82//!     height: 1,
83//!     viewpoint: Default::default(),
84//!     data_kind: DataKind::Ascii,
85//!     schema: Some(Schema::from_iter(schema)),
86//! }
87//! .create("test_files/dump_ascii_untyped.pcd")?;
88//!
89//! // Send the points to the writer
90//! for point in points {
91//!     writer.push(&point)?;
92//! }
93//!
94//! // Finalize the writer
95//! writer.finish()?;
96//! # Ok(())
97//! # }
98//! ```
99#![cfg_attr(
100    feature = "derive",
101    doc = r##"
102# Static Schema Example
103
104The serde-like derives [PcdSerialize] and [PcdDeserialize] allows the
105[Reader] and [Writer] to read from to write to the annotated
106types. Both are available if the `derive` feature is enabled. The type
107must be a `struct` with named fields, where each field type is either
108a primitive type, an array or a `Vec`.
109
110## Reader
111
112The reader is constructed by [Reader::open()], which itself is an
113iterator. The [.push()](Writer::push) is used to append the data to
114the writer. The writer must be finished by [.finish()](Writer::finish)
115in the end.
116
117```rust
118# pub fn main() -> pcd_rs::Result<()> {
119use pcd_rs::{PcdDeserialize, Reader};
120
121#[derive(PcdDeserialize)]
122pub struct Point {
123    pub x: f32,
124    pub y: f32,
125    pub z: f32,
126    pub rgb: f32,
127}
128
129let reader = Reader::open("test_files/ascii.pcd")?;
130let points: Result<Vec<Point>> = reader.collect();
131println!("{} points found", points?.len());
132# Ok(())
133# }
134```
135
136## Writer
137
138The writer is configured by [WriterInit] and then created by
139[WriterInit::create()].
140
141```rust
142# pub fn main() -> pcd_rs::Result<()> {
143use pcd_rs::{DataKind, PcdDeserialize, PcdSerialize, WriterInit};
144
145#[derive(PcdSerialize)]
146pub struct Point {
147    #[pcd(rename = "new_x")]
148    x: f32,
149    y: [u8; 3],
150    z: i32,
151}
152
153// point data
154let points = [
155    Point {
156        x: 3.14159,
157        y: [2, 1, 7],
158        z: -5,
159    },
160    Point {
161        x: -0.0,
162        y: [254, 6, 98],
163        z: 7,
164    },
165    Point {
166        x: 5.6,
167        y: [4, 0, 111],
168        z: -100000,
169    },
170];
171
172// serialize points
173let mut writer = WriterInit {
174    width: 300,
175    height: 1,
176    viewpoint: Default::default(),
177    data_kind: DataKind::Ascii,
178    schema: None,
179}
180.create("test_files/dump_ascii_static.pcd")?;
181
182for point in points {
183    writer.push(&point)?;
184}
185
186writer.finish()?;
187# Ok(())
188# }
189```
190
191# Derives
192
193Both [PcdSerialize] and [PcdDeserialize] supports the following field
194attributes.
195
196- `#[pcd(rename = "NEW_NAME")]` sets the field name on the written PCD data.
197- `#[pcd(ignore)]` instructs the de/serializer to ignore the field.
198"##
199)]
200
201#[doc(hidden)]
202pub use byteorder;
203
204pub mod error;
205pub mod metas;
206pub mod prelude;
207pub mod reader;
208pub mod record;
209pub mod traits;
210mod utils;
211pub mod writer;
212
213pub use error::{Error, Result};
214pub use metas::{DataKind, FieldDef, PcdMeta, Schema, TypeKind, ValueKind, ViewPoint};
215#[cfg(feature = "derive")]
216pub use pcd_rs_derive::{PcdDeserialize, PcdSerialize};
217pub use reader::{DynReader, Reader};
218pub use record::{DynRecord, Field, PcdDeserialize, PcdSerialize};
219pub use traits::Value;
220pub use writer::{DynWriter, Writer, WriterInit};