draco_core/
point_cloud.rs1use crate::geometry_attribute::{GeometryAttributeType, PointAttribute};
2use crate::metadata::{AttributeMetadata, GeometryMetadata, Metadata};
3use crate::status::DracoError;
4
5#[derive(Debug, Default, Clone)]
7pub struct PointCloud {
8 attributes: Vec<PointAttribute>,
9 num_points: usize,
10 metadata: Option<GeometryMetadata>,
11}
12
13impl PointCloud {
14 pub fn new() -> Self {
16 Self::default()
17 }
18
19 pub fn set_num_points(&mut self, num_points: usize) {
21 self.num_points = num_points;
22 }
23
24 pub fn add_attribute(&mut self, mut attribute: PointAttribute) -> i32 {
26 if self.num_points == 0 && attribute.size() > 0 {
27 self.num_points = attribute.size();
28 }
29 let id = self.attributes.len() as i32;
30 attribute.set_unique_id(id as u32);
31 self.attributes.push(attribute);
32 id
33 }
34
35 pub fn add_attribute_preserve_unique_id(&mut self, attribute: PointAttribute) -> i32 {
37 if self.num_points == 0 && attribute.size() > 0 {
38 self.num_points = attribute.size();
39 }
40 let id = self.attributes.len() as i32;
41 self.attributes.push(attribute);
42 id
43 }
44
45 pub fn set_attribute(&mut self, att_id: i32, mut attribute: PointAttribute) {
51 debug_assert!(att_id >= 0);
52 let index = att_id as usize;
53 if index >= self.attributes.len() {
54 self.attributes.resize_with(index + 1, PointAttribute::new);
55 }
56 attribute.set_unique_id(att_id as u32);
57 self.attributes[index] = attribute;
58 }
59
60 pub fn num_attributes(&self) -> i32 {
62 self.attributes.len() as i32
63 }
64
65 pub fn attribute_id_by_unique_id(&self, unique_id: u32) -> i32 {
69 for (i, att) in self.attributes.iter().enumerate() {
70 if att.unique_id() == unique_id {
71 return i as i32;
72 }
73 }
74 -1
75 }
76
77 pub fn attribute_by_unique_id(&self, unique_id: u32) -> Option<&PointAttribute> {
81 let id = self.attribute_id_by_unique_id(unique_id);
82 (id >= 0).then(|| &self.attributes[id as usize])
83 }
84
85 pub fn attribute(&self, att_id: i32) -> &PointAttribute {
87 &self.attributes[att_id as usize]
88 }
89
90 pub fn try_attribute(&self, att_id: i32) -> Result<&PointAttribute, DracoError> {
92 let Some(attribute) = (att_id >= 0)
93 .then_some(att_id as usize)
94 .and_then(|index| self.attributes.get(index))
95 else {
96 return Err(DracoError::DracoError(
97 "Point cloud attribute id out of range".to_string(),
98 ));
99 };
100 Ok(attribute)
101 }
102
103 pub fn attribute_mut(&mut self, att_id: i32) -> &mut PointAttribute {
105 &mut self.attributes[att_id as usize]
106 }
107
108 pub fn try_attribute_mut(&mut self, att_id: i32) -> Result<&mut PointAttribute, DracoError> {
110 let Some(attribute) = (att_id >= 0)
111 .then_some(att_id as usize)
112 .and_then(|index| self.attributes.get_mut(index))
113 else {
114 return Err(DracoError::DracoError(
115 "Point cloud attribute id out of range".to_string(),
116 ));
117 };
118 Ok(attribute)
119 }
120
121 pub fn named_attribute_id(&self, att_type: GeometryAttributeType) -> i32 {
123 for (i, att) in self.attributes.iter().enumerate() {
124 if att.attribute_type() == att_type {
125 return i as i32;
126 }
127 }
128 -1
129 }
130
131 pub fn named_attribute(&self, att_type: GeometryAttributeType) -> Option<&PointAttribute> {
133 let id = self.named_attribute_id(att_type);
134 if id >= 0 {
135 Some(&self.attributes[id as usize])
136 } else {
137 None
138 }
139 }
140
141 pub fn num_points(&self) -> usize {
143 self.num_points
144 }
145
146 pub fn metadata(&self) -> Option<&GeometryMetadata> {
148 self.metadata.as_ref()
149 }
150
151 pub fn metadata_mut(&mut self) -> Option<&mut GeometryMetadata> {
153 self.metadata.as_mut()
154 }
155
156 pub fn metadata_or_insert(&mut self) -> &mut GeometryMetadata {
158 self.metadata.get_or_insert_with(GeometryMetadata::new)
159 }
160
161 pub fn set_metadata(&mut self, metadata: Option<GeometryMetadata>) {
163 self.metadata = metadata;
164 }
165
166 pub fn attribute_metadata_by_unique_id(
168 &self,
169 attribute_unique_id: u32,
170 ) -> Option<&AttributeMetadata> {
171 self.metadata
172 .as_ref()
173 .and_then(|metadata| metadata.attribute_metadata_by_unique_id(attribute_unique_id))
174 }
175
176 pub fn attribute_metadata_by_string_entry(
178 &self,
179 entry_name: &str,
180 entry_value: &str,
181 ) -> Option<&AttributeMetadata> {
182 self.metadata.as_ref().and_then(|metadata| {
183 metadata.attribute_metadata_by_string_entry(entry_name, entry_value)
184 })
185 }
186
187 pub fn set_attribute_metadata(
189 &mut self,
190 att_id: i32,
191 metadata: Metadata,
192 ) -> Result<(), DracoError> {
193 let unique_id = self.try_attribute(att_id)?.unique_id();
194 self.metadata_or_insert()
195 .set_attribute_metadata(unique_id, metadata);
196 Ok(())
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn try_attribute_rejects_out_of_range_ids() {
206 let mut point_cloud = PointCloud::new();
207
208 assert!(point_cloud.try_attribute(-1).is_err());
209 assert!(point_cloud.try_attribute(0).is_err());
210 assert!(point_cloud.try_attribute_mut(-1).is_err());
211 assert!(point_cloud.try_attribute_mut(0).is_err());
212 }
213}