Skip to main content

pointrain_io/pcd/
point.rs

1use pointrain_core::{
2    pc::point::{
3        PointXYZ, PointXYZI, PointXYZINormal, PointXYZNormal, PointXYZRgb, PointXYZRgbNormal,
4    },
5    types::{Normal, Position},
6};
7
8use crate::{
9    error::{MissingField, PointRainIOError},
10    field::{PointField, PointFieldDatum},
11};
12
13fn find_field(fields: &[PointField], name: &'static str) -> Result<usize, MissingField> {
14    fields
15        .iter()
16        .enumerate()
17        .find(|(_, f)| f.name == name)
18        .map(|(i, _)| i)
19        .ok_or(MissingField(name))
20}
21
22fn find_xyz(fields: &[PointField]) -> Result<(usize, usize, usize), MissingField> {
23    Ok((
24        find_field(fields, "x")?,
25        find_field(fields, "y")?,
26        find_field(fields, "z")?,
27    ))
28}
29
30fn find_normal(fields: &[PointField]) -> Result<(usize, usize, usize, usize), MissingField> {
31    Ok((
32        find_field(fields, "normal_x")?,
33        find_field(fields, "normal_y")?,
34        find_field(fields, "normal_z")?,
35        find_field(fields, "curvature")?,
36    ))
37}
38
39fn find_intensity(fields: &[PointField]) -> Result<usize, MissingField> {
40    find_field(fields, "intensity")
41}
42
43fn find_rgb(fields: &[PointField]) -> Result<usize, MissingField> {
44    find_field(fields, "rgb")
45}
46
47pub type PointMapper<T> = Box<dyn Fn(&[PointFieldDatum]) -> Result<T, PointRainIOError>>;
48
49pub trait PointReadable: Sized {
50    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError>;
51}
52
53impl PointReadable for PointXYZ {
54    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError> {
55        let (x, y, z) = find_xyz(fields)?;
56
57        let closure = move |data: &[PointFieldDatum]| {
58            Ok(Self {
59                pos: Position::new(data[x].to_float(), data[y].to_float(), data[z].to_float()),
60            })
61        };
62
63        Ok(Box::new(closure))
64    }
65}
66
67impl PointReadable for PointXYZNormal {
68    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError> {
69        let (x, y, z) = find_xyz(fields)?;
70        let (nx, ny, nz, curvature) = find_normal(fields)?;
71
72        let closure = move |data: &[PointFieldDatum]| {
73            Ok(Self {
74                pos: Position::new(data[x].to_float(), data[y].to_float(), data[z].to_float()),
75                normal: Normal::new(
76                    data[nx].to_float(),
77                    data[ny].to_float(),
78                    data[nz].to_float(),
79                ),
80                curvature: data[curvature].to_float(),
81            })
82        };
83
84        Ok(Box::new(closure))
85    }
86}
87
88impl PointReadable for PointXYZI {
89    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError> {
90        let (x, y, z) = find_xyz(fields)?;
91        let intensity = find_intensity(fields)?;
92
93        let closure = move |data: &[PointFieldDatum]| {
94            Ok(Self {
95                pos: Position::new(data[x].to_float(), data[y].to_float(), data[z].to_float()),
96                intensity: data[intensity].to_float(),
97            })
98        };
99
100        Ok(Box::new(closure))
101    }
102}
103
104impl PointReadable for PointXYZINormal {
105    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError> {
106        let (x, y, z) = find_xyz(fields)?;
107        let intensity = find_intensity(fields)?;
108        let (nx, ny, nz, curvature) = find_normal(fields)?;
109
110        let closure = move |data: &[PointFieldDatum]| {
111            Ok(Self {
112                pos: Position::new(data[x].to_float(), data[y].to_float(), data[z].to_float()),
113                intensity: data[intensity].to_float(),
114                normal: Normal::new(
115                    data[nx].to_float(),
116                    data[ny].to_float(),
117                    data[nz].to_float(),
118                ),
119                curvature: data[curvature].to_float(),
120            })
121        };
122
123        Ok(Box::new(closure))
124    }
125}
126
127impl PointReadable for PointXYZRgb {
128    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError> {
129        let (x, y, z) = find_xyz(fields)?;
130        let rgb = find_rgb(fields)?;
131
132        let closure = move |data: &[PointFieldDatum]| {
133            Ok(Self {
134                pos: Position::new(data[x].to_float(), data[y].to_float(), data[z].to_float()),
135                color: data[rgb].to_color()?,
136            })
137        };
138
139        Ok(Box::new(closure))
140    }
141}
142
143impl PointReadable for PointXYZRgbNormal {
144    fn read_data_func(fields: &[PointField]) -> Result<PointMapper<Self>, PointRainIOError> {
145        let (x, y, z) = find_xyz(fields)?;
146        let rgb = find_rgb(fields)?;
147        let (nx, ny, nz, curvature) = find_normal(fields)?;
148
149        let closure = move |data: &[PointFieldDatum]| {
150            Ok(Self {
151                pos: Position::new(data[x].to_float(), data[y].to_float(), data[z].to_float()),
152                color: data[rgb].to_color()?,
153                normal: Normal::new(
154                    data[nx].to_float(),
155                    data[ny].to_float(),
156                    data[nz].to_float(),
157                ),
158                curvature: data[curvature].to_float(),
159            })
160        };
161
162        Ok(Box::new(closure))
163    }
164}