Skip to main content

pcd_rs/
metas.rs

1//! Types for PCD metadata.
2
3use crate::Result;
4use std::{
5    fs::File,
6    io::{BufRead, BufReader},
7    iter::FromIterator,
8    ops::Index,
9    path::Path,
10};
11
12/// The struct keep meta data of PCD file.
13#[derive(Debug, Clone, PartialEq)]
14pub struct PcdMeta {
15    pub version: String,
16    pub width: u64,
17    pub height: u64,
18    pub viewpoint: ViewPoint,
19    pub num_points: u64,
20    pub data: DataKind,
21    pub field_defs: Schema,
22}
23
24impl PcdMeta {
25    /// Read only the PCD header from a file path, without loading point data.
26    pub fn from_path(path: impl AsRef<Path>) -> Result<Self> {
27        let file = BufReader::new(File::open(path.as_ref())?);
28        Self::from_reader(file)
29    }
30
31    /// Read only the PCD header from a reader, without loading point data.
32    pub fn from_reader(mut reader: impl BufRead) -> Result<Self> {
33        let mut line_count = 0;
34        crate::utils::load_meta(&mut reader, &mut line_count)
35    }
36}
37
38/// Represents VIEWPOINT field in meta data.
39#[derive(Debug, Clone, PartialEq)]
40pub struct ViewPoint {
41    pub tx: f64,
42    pub ty: f64,
43    pub tz: f64,
44    pub qw: f64,
45    pub qx: f64,
46    pub qy: f64,
47    pub qz: f64,
48}
49
50impl Default for ViewPoint {
51    fn default() -> Self {
52        ViewPoint {
53            tx: 0.0,
54            ty: 0.0,
55            tz: 0.0,
56            qw: 1.0,
57            qx: 0.0,
58            qy: 0.0,
59            qz: 0.0,
60        }
61    }
62}
63
64/// The enum indicates whether the point cloud data is encoded in Ascii, binary, or compressed binary.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum DataKind {
67    Ascii,
68    Binary,
69    BinaryCompressed,
70}
71
72/// The enum specifies one of signed, unsigned integers, and floating point number type to the field.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum TypeKind {
75    I,
76    U,
77    F,
78}
79
80/// The enum specifies the exact type for each PCD field.
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum ValueKind {
83    U8,
84    U16,
85    U32,
86    U64,
87    I8,
88    I16,
89    I32,
90    I64,
91    F32,
92    F64,
93}
94
95impl ValueKind {
96    /// Returns the byte size of a value of this kind.
97    pub fn byte_size(&self) -> usize {
98        match self {
99            ValueKind::U8 | ValueKind::I8 => 1,
100            ValueKind::U16 | ValueKind::I16 => 2,
101            ValueKind::U32 | ValueKind::I32 | ValueKind::F32 => 4,
102            ValueKind::U64 | ValueKind::I64 | ValueKind::F64 => 8,
103        }
104    }
105}
106
107/// Define the properties of a PCD field.
108#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct FieldDef {
110    pub name: String,
111    pub kind: ValueKind,
112    pub count: u64,
113}
114
115impl FieldDef {
116    /// Returns true if this field represents PCL-style padding (`_` name).
117    pub fn is_padding(&self) -> bool {
118        self.name == "_"
119    }
120}
121
122/// Define the schema of PCD format.
123#[derive(Debug, Clone, PartialEq, Eq)]
124pub struct Schema {
125    pub fields: Vec<FieldDef>,
126}
127
128impl Schema {
129    pub fn is_empty(&self) -> bool {
130        self.fields.is_empty()
131    }
132
133    pub fn len(&self) -> usize {
134        self.fields.len()
135    }
136
137    pub fn iter(&self) -> std::slice::Iter<'_, FieldDef> {
138        self.into_iter()
139    }
140}
141
142impl Index<usize> for Schema {
143    type Output = FieldDef;
144
145    fn index(&self, index: usize) -> &Self::Output {
146        self.fields.index(index)
147    }
148}
149
150impl IntoIterator for Schema {
151    type Item = FieldDef;
152    type IntoIter = std::vec::IntoIter<FieldDef>;
153
154    fn into_iter(self) -> Self::IntoIter {
155        self.fields.into_iter()
156    }
157}
158
159impl<'a> IntoIterator for &'a Schema {
160    type Item = &'a FieldDef;
161    type IntoIter = std::slice::Iter<'a, FieldDef>;
162
163    fn into_iter(self) -> Self::IntoIter {
164        self.fields.iter()
165    }
166}
167
168impl FromIterator<(String, ValueKind, u64)> for Schema {
169    fn from_iter<T: IntoIterator<Item = (String, ValueKind, u64)>>(iter: T) -> Self {
170        let fields = iter
171            .into_iter()
172            .map(|(name, kind, count)| FieldDef { name, kind, count })
173            .collect();
174        Self { fields }
175    }
176}
177
178impl<'a> FromIterator<(&'a str, ValueKind, u64)> for Schema {
179    fn from_iter<T: IntoIterator<Item = (&'a str, ValueKind, u64)>>(iter: T) -> Self {
180        iter.into_iter()
181            .map(|(name, kind, count)| (name.to_string(), kind, count))
182            .collect()
183    }
184}
185
186impl FromIterator<FieldDef> for Schema {
187    fn from_iter<T: IntoIterator<Item = FieldDef>>(iter: T) -> Self {
188        Self {
189            fields: iter.into_iter().collect(),
190        }
191    }
192}
193
194impl<'a> FromIterator<&'a FieldDef> for Schema {
195    fn from_iter<T: IntoIterator<Item = &'a FieldDef>>(iter: T) -> Self {
196        Self {
197            fields: iter.into_iter().map(|field| field.to_owned()).collect(),
198        }
199    }
200}