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