Skip to main content

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::Result<()>  {
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::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//!     version: None,
87//! }
88//! .create("test_files/dump_ascii_untyped.pcd")?;
89//!
90//! // Send the points to the writer
91//! for point in points {
92//!     writer.push(&point)?;
93//! }
94//!
95//! // Finalize the writer
96//! writer.finish()?;
97//! # Ok(())
98//! # }
99//! ```
100#![cfg_attr(
101    feature = "derive",
102    doc = r##"
103# Static Schema Example
104
105The serde-like derives [PcdSerialize] and [PcdDeserialize] allows the
106[Reader] and [Writer] to read from to write to the annotated
107types. Both are available if the `derive` feature is enabled. The type
108must be a `struct` with named fields, where each field type is either
109a primitive type, an array or a `Vec`.
110
111## Reader
112
113The reader is constructed by [Reader::open()], which itself is an
114iterator. The [.push()](Writer::push) is used to append the data to
115the writer. The writer must be finished by [.finish()](Writer::finish)
116in the end.
117
118```rust
119# pub fn main() -> pcd_rs::Result<()> {
120use pcd_rs::{PcdDeserialize, Reader};
121
122#[derive(PcdDeserialize)]
123pub struct Point {
124    pub x: f32,
125    pub y: f32,
126    pub z: f32,
127    pub rgb: f32,
128}
129
130let reader = Reader::open("test_files/ascii.pcd")?;
131let points: pcd_rs::Result<Vec<Point>> = reader.collect();
132println!("{} points found", points?.len());
133# Ok(())
134# }
135```
136
137## Writer
138
139The writer is configured by [WriterInit] and then created by
140[WriterInit::create()].
141
142```rust
143# pub fn main() -> pcd_rs::Result<()> {
144use pcd_rs::{DataKind, PcdDeserialize, PcdSerialize, WriterInit};
145
146#[derive(PcdSerialize)]
147pub struct Point {
148    #[pcd(rename = "new_x")]
149    x: f32,
150    y: [u8; 3],
151    z: i32,
152}
153
154// point data
155let points = [
156    Point {
157        x: 3.14159,
158        y: [2, 1, 7],
159        z: -5,
160    },
161    Point {
162        x: -0.0,
163        y: [254, 6, 98],
164        z: 7,
165    },
166    Point {
167        x: 5.6,
168        y: [4, 0, 111],
169        z: -100000,
170    },
171];
172
173// serialize points
174let mut writer = WriterInit {
175    width: 300,
176    height: 1,
177    viewpoint: Default::default(),
178    data_kind: DataKind::Ascii,
179    schema: None,
180    version: None,
181}
182.create("test_files/dump_ascii_static.pcd")?;
183
184for point in points {
185    writer.push(&point)?;
186}
187
188writer.finish()?;
189# Ok(())
190# }
191```
192
193# Derives
194
195Both [PcdSerialize] and [PcdDeserialize] supports the following field
196attributes.
197
198- `#[pcd(rename = "NEW_NAME")]` sets the field name on the written PCD data.
199- `#[pcd(ignore)]` instructs the de/serializer to ignore the field.
200"##
201)]
202
203#[doc(hidden)]
204pub use byteorder;
205
206pub mod error;
207mod lzf;
208pub mod metas;
209pub mod prelude;
210pub mod reader;
211pub mod record;
212pub mod rgb;
213pub mod traits;
214mod utils;
215pub mod writer;
216
217pub use error::{Error, Result};
218pub use metas::{DataKind, FieldDef, PcdMeta, Schema, TypeKind, ValueKind, ViewPoint};
219#[cfg(feature = "derive")]
220pub use pcd_rs_derive::{PcdDeserialize, PcdSerialize};
221pub use reader::{DynReader, Reader};
222pub use record::{DynRecord, Field, PcdDeserialize, PcdSerialize};
223pub use rgb::{float_to_rgb, float_to_rgba, rgb_to_float, rgba_to_float, Rgb, Rgba};
224pub use traits::Value;
225pub use writer::{DynWriter, Writer, WriterInit};