spatialrust_io/e57/
schema.rs1use e57::PointCloud as E57PointCloud;
2use spatialrust_core::{DType, FieldSemantic, PointField, PointSchema, StandardSchemas};
3
4use crate::error::{e57_format, IoError};
5
6#[must_use]
8pub fn schema_for_e57_pointcloud(pc: &E57PointCloud) -> PointSchema {
9 let mut schema = StandardSchemas::point_xyz();
10 if pc.has_intensity() {
11 schema = schema.with_field(PointField::scalar(
12 "intensity",
13 FieldSemantic::Intensity,
14 DType::F32,
15 ));
16 }
17 if pc.has_color() {
18 schema = schema
19 .with_field(PointField::scalar("r", FieldSemantic::ColorR, DType::U8))
20 .with_field(PointField::scalar("g", FieldSemantic::ColorG, DType::U8))
21 .with_field(PointField::scalar("b", FieldSemantic::ColorB, DType::U8));
22 }
23 schema
24}
25
26pub fn schema_from_point_cloud(schema: &PointSchema) -> (PointSchema, Vec<e57::Record>) {
28 let export_schema = export_schema_for_cloud(schema);
29 let prototype = e57_prototype_from_schema(&export_schema);
30 (export_schema, prototype)
31}
32
33fn export_schema_for_cloud(source: &PointSchema) -> PointSchema {
34 let mut schema = StandardSchemas::point_xyz();
35 if source.find_semantic(FieldSemantic::Intensity).is_some() {
36 schema = schema.with_field(PointField::scalar(
37 "intensity",
38 FieldSemantic::Intensity,
39 DType::F32,
40 ));
41 }
42 if source.find_semantic(FieldSemantic::ColorR).is_some() {
43 schema = schema
44 .with_field(PointField::scalar("r", FieldSemantic::ColorR, DType::U8))
45 .with_field(PointField::scalar("g", FieldSemantic::ColorG, DType::U8))
46 .with_field(PointField::scalar("b", FieldSemantic::ColorB, DType::U8));
47 }
48 schema
49}
50
51#[must_use]
53pub fn e57_prototype_from_schema(schema: &PointSchema) -> Vec<e57::Record> {
54 let mut prototype = vec![
55 e57::Record::CARTESIAN_X_F32,
56 e57::Record::CARTESIAN_Y_F32,
57 e57::Record::CARTESIAN_Z_F32,
58 ];
59 if schema.find_semantic(FieldSemantic::Intensity).is_some() {
60 prototype.push(e57::Record::INTENSITY_UNIT_F32);
61 }
62 if schema.find_semantic(FieldSemantic::ColorR).is_some() {
63 prototype.push(e57::Record::COLOR_RED_U8);
64 prototype.push(e57::Record::COLOR_GREEN_U8);
65 prototype.push(e57::Record::COLOR_BLUE_U8);
66 }
67 prototype
68}
69
70pub fn validate_export_schema(schema: &PointSchema) -> Result<(), IoError> {
72 schema.validate_positions().map_err(IoError::from)?;
73 if schema.find_semantic(FieldSemantic::Intensity).is_none()
74 && schema.find_semantic(FieldSemantic::ColorR).is_none()
75 && schema.len() > 3
76 {
77 return Err(e57_format(
78 "E57 export supports xyz with optional intensity and rgb only".to_owned(),
79 ));
80 }
81 Ok(())
82}
83
84#[cfg(test)]
85mod tests {
86 use super::{e57_prototype_from_schema, schema_for_e57_pointcloud};
87 use e57::PointCloud as E57PointCloud;
88 use spatialrust_core::{FieldSemantic, StandardSchemas};
89
90 #[test]
91 fn builds_xyz_prototype() {
92 let prototype = e57_prototype_from_schema(&StandardSchemas::point_xyz());
93 assert_eq!(prototype.len(), 3);
94 }
95
96 #[test]
97 fn builds_xyzi_prototype() {
98 let prototype = e57_prototype_from_schema(&StandardSchemas::point_xyzi());
99 assert_eq!(prototype.len(), 4);
100 }
101
102 #[test]
103 fn schema_from_empty_e57_scan() {
104 let pc = E57PointCloud::default();
105 let schema = schema_for_e57_pointcloud(&pc);
106 assert!(schema.find_semantic(FieldSemantic::PositionX).is_some());
107 }
108}