rust_3d/
point_cloud_3d.rs1use std::{
26 fmt,
27 ops::{Index, IndexMut},
28};
29
30use crate::*;
31
32#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Hash)]
35pub struct PointCloud3D<P>
37where
38 P: Is3D,
39{
40 pub data: Vec<P>,
41}
42
43impl<P> PointCloud3D<P>
44where
45 P: Is3D,
46{
47 pub fn new() -> PointCloud3D<P> {
49 PointCloud3D { data: Vec::new() }
50 }
51 pub fn with_capacity(n: usize) -> PointCloud3D<P> {
53 PointCloud3D {
54 data: Vec::with_capacity(n),
55 }
56 }
57 pub fn to_str(&self) -> String {
59 let mut result = String::new();
60 for p in &self.data {
61 result = result + &p.to_str() + "\n";
62 }
63 result
64 }
65 pub fn for_each_point<F>(&mut self, mut f: F)
67 where
68 F: FnMut(&mut P),
69 {
70 for p in &mut self.data {
71 f(&mut *p);
72 }
73 }
74 pub fn reserve_vertices(&mut self, n: usize) {
76 self.data.reserve(n)
77 }
78}
79
80impl<P> PointCloud3D<P>
81where
82 P: IsBuildable3D + Clone,
83{
84 pub fn parse(text: &str) -> Result<PointCloud3D<P>> {
86 let lines = text.split("\n").skip_empty_string();
87
88 let mut pc = PointCloud3D::new();
89 for line in lines {
90 P::parse(line).map(|p| pc.push(p))?;
91 }
92 if pc.len() == 0 {
93 return Err(ErrorKind::ParseError);
94 }
95 Ok(pc)
96 }
97 pub fn append_ra<RA>(&mut self, ra: &RA)
99 where
100 RA: IsRandomAccessible<P>,
101 {
102 let n = ra.len();
103 self.data.reserve(n);
104
105 for i in 0..n {
106 self.data.push(ra[i].clone());
107 }
108 }
109}
110
111impl<P> IsDataContainer<P> for PointCloud3D<P>
114where
115 P: IsBuildable3D + Clone,
116{
117 fn reserve_d(&mut self, n: usize) {
118 self.data.reserve(n);
119 }
120
121 fn len_d(&self) -> usize {
122 self.data.len()
123 }
124
125 fn push_d(&mut self, p: P) {
126 self.push(p)
127 }
128
129 fn get_d(&self, index: usize) -> P {
130 self.data[index].clone()
131 }
132
133 fn set_d(&mut self, index: usize, p: P) {
134 self.data[index] = p
135 }
136}
137
138impl<P> Index<usize> for PointCloud3D<P>
139where
140 P: Is3D,
141{
142 type Output = P;
143 fn index(&self, i: usize) -> &P {
144 &self.data[i]
145 }
146}
147
148impl<P> IndexMut<usize> for PointCloud3D<P>
149where
150 P: Is3D,
151{
152 fn index_mut(&mut self, i: usize) -> &mut P {
153 &mut self.data[i]
154 }
155}
156
157impl<P> IsRandomAccessible<P> for PointCloud3D<P>
158where
159 P: Is3D,
160{
161 fn len(&self) -> usize {
162 self.data.len()
163 }
164}
165
166impl<P> IsRandomInsertible<P> for PointCloud3D<P>
167where
168 P: Is3D,
169{
170 fn insert(&mut self, index: usize, point: P) -> Result<()> {
171 if index > self.len() {
172 Err(ErrorKind::IncorrectVertexID)
173 } else {
174 self.data.insert(index, point);
175 Ok(())
176 }
177 }
178}
179
180impl<P> IsPushable<P> for PointCloud3D<P>
181where
182 P: Is3D,
183{
184 fn push(&mut self, point: P) {
185 self.data.push(point)
186 }
187 fn reserve(&mut self, n: usize) {
188 self.data.reserve(n)
189 }
190}
191
192impl<P> IsMovable3D for PointCloud3D<P>
193where
194 P: Is3D + IsMovable3D,
195{
196 fn move_by(&mut self, x: f64, y: f64, z: f64) {
197 for p in &mut self.data {
198 p.move_by(x, y, z);
199 }
200 }
201}
202
203impl<P> HasBoundingBox3DMaybe for PointCloud3D<P>
204where
205 P: Is3D,
206{
207 fn bounding_box_maybe(&self) -> Result<BoundingBox3D> {
208 BoundingBox3D::from_iterator(&self.data)
209 }
210}
211
212impl<P> HasCenterOfGravity3D for PointCloud3D<P>
213where
214 P: Is3D,
215{
216 fn center_of_gravity(&self) -> Result<Point3D> {
217 let size = self.len();
218
219 if size < 1 {
220 return Err(ErrorKind::TooFewPoints);
221 }
222
223 let sizef = size as f64;
224
225 let mut sumx: f64 = 0.0;
226 let mut sumy: f64 = 0.0;
227 let mut sumz: f64 = 0.0;
228
229 for p in &self.data {
230 sumx += p.x();
231 sumy += p.y();
232 sumz += p.z();
233 }
234
235 Ok(Point3D {
236 x: sumx / sizef,
237 y: sumy / sizef,
238 z: sumz / sizef,
239 })
240 }
241}
242
243impl<P> HasLength for PointCloud3D<P>
244where
245 P: Is3D,
246{
247 fn length(&self) -> f64 {
248 let mut length: f64 = 0.0;
249 if self.data.len() < 2 {
250 return length;
251 }
252
253 for i in 1..self.data.len() {
254 length += dist_3d(&self.data[i], &self.data[i - 1]);
255 }
256 length
257 }
258}
259
260impl<P> IsViewBuildable for PointCloud3D<P>
261where
262 P: Is3D + Clone,
263{
264 fn apply_view(&mut self, view: &View) -> Result<()> {
265 self.data.apply_view(view)?;
266 Ok(())
267 }
268
269 fn from_view(&self, view: &View) -> Result<Self> {
270 let mut cloned = self.clone();
271 cloned.apply_view(view)?;
272 Ok(cloned)
273 }
274}
275
276impl<P> IsSortableND for PointCloud3D<P>
277where
278 P: Is3D,
279{
280 fn n_dimensions() -> usize {
281 3
282 }
283
284 fn sort_dim(&mut self, dimension: usize) -> Result<()> {
285 match dimension {
286 0 => {
287 self.sort_x();
288 Ok(())
289 }
290 1 => {
291 self.sort_y();
292 Ok(())
293 }
294 2 => {
295 self.sort_z();
296 Ok(())
297 }
298 _ => Err(ErrorKind::IncorrectDimension),
299 }
300 }
301}
302
303impl<P> IsSortable3D for PointCloud3D<P>
304where
305 P: Is3D,
306{
307 fn sort_x(&mut self) {
308 sort_vec_3d_x(&mut self.data);
309 }
310
311 fn sort_y(&mut self) {
312 sort_vec_3d_y(&mut self.data);
313 }
314
315 fn sort_z(&mut self) {
316 sort_vec_3d_z(&mut self.data);
317 }
318}
319
320impl<P> IsMergeable for PointCloud3D<P>
321where
322 P: Is3D + Clone,
323{
324 fn consume(&mut self, other: Self) {
325 for p in other.data {
326 self.data.push(p.clone());
327 }
328 }
329
330 fn combine(&self, other: &Self) -> Self {
331 let mut result = self.clone();
332 result.consume(other.clone());
333 result
334 }
335}
336
337impl<P> IsScalable for PointCloud3D<P>
338where
339 P: IsEditable3D,
340{
341 fn scale(&mut self, factor: Positive) {
342 if let Ok(bb) = self.bounding_box_maybe() {
343 let c = bb.center_bb();
344 for p in &mut self.data {
345 p.increase_distance_to_by(&c, factor);
346 }
347 }
348 }
349}
350
351impl<P> IsMatrix4Transformable for PointCloud3D<P>
352where
353 P: Is3D + IsMatrix4Transformable + Clone,
354{
355 fn transformed(&self, m: &Matrix4) -> Self {
356 let mut new = self.clone();
357 new.transform(m);
358 new
359 }
360
361 fn transform(&mut self, m: &Matrix4) {
362 for p in &mut self.data {
363 p.transform(m);
364 }
365 }
366}
367
368impl<P> Default for PointCloud3D<P>
369where
370 P: Is3D,
372{
373 fn default() -> Self {
374 let data = Vec::new();
375 PointCloud3D { data }
376 }
377}
378
379impl<P> fmt::Display for PointCloud3D<P>
380where
381 P: Is3D + fmt::Display,
382{
383 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
384 for p in &self.data {
385 p.fmt(f)?;
386 f.write_str("\n")?;
387 }
388 Ok(())
389 }
390}
391
392impl<P> Into<Vec<P>> for PointCloud3D<P>
393where
394 P: Is3D,
395{
396 fn into(self) -> Vec<P> {
397 self.data
398 }
399}
400
401impl<P> From<Vec<P>> for PointCloud3D<P>
402where
403 P: Is3D,
404{
405 fn from(data: Vec<P>) -> Self {
406 Self { data }
407 }
408}