rust_3d/
point_cloud_2d.rs1use std::{
26 fmt,
27 ops::{Index, IndexMut},
28};
29
30use crate::*;
31
32#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Hash)]
35pub struct PointCloud2D<P>
37where
38 P: Is2D,
39{
40 pub data: Vec<P>,
41}
42
43impl<P> PointCloud2D<P>
44where
45 P: Is2D,
46{
47 pub fn new() -> PointCloud2D<P> {
49 PointCloud2D { data: Vec::new() }
50 }
51 pub fn with_capacity(n: usize) -> PointCloud2D<P> {
53 PointCloud2D {
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> PointCloud2D<P>
81where
82 P: IsBuildable2D + Clone,
83{
84 pub fn parse(text: &str) -> Result<PointCloud2D<P>> {
86 let lines = text.split("\n").skip_empty_string();
87
88 let mut pc = PointCloud2D::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 PointCloud2D<P>
114where
115 P: IsBuildable2D + 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 PointCloud2D<P>
139where
140 P: Is2D,
141{
142 type Output = P;
143 fn index(&self, i: usize) -> &P {
144 &self.data[i]
145 }
146}
147
148impl<P> IndexMut<usize> for PointCloud2D<P>
149where
150 P: Is2D,
151{
152 fn index_mut(&mut self, i: usize) -> &mut P {
153 &mut self.data[i]
154 }
155}
156
157impl<P> IsRandomAccessible<P> for PointCloud2D<P>
158where
159 P: Is2D,
160{
161 fn len(&self) -> usize {
162 self.data.len()
163 }
164}
165
166impl<P> IsRandomInsertible<P> for PointCloud2D<P>
167where
168 P: Is2D,
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 PointCloud2D<P>
181where
182 P: Is2D,
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> IsMovable2D for PointCloud2D<P>
193where
194 P: Is2D + IsMovable2D,
195{
196 fn move_by(&mut self, x: f64, y: f64) {
197 for p in &mut self.data {
198 p.move_by(x, y);
199 }
200 }
201}
202
203impl<P> HasBoundingBox2DMaybe for PointCloud2D<P>
204where
205 P: Is2D,
206{
207 fn bounding_box_maybe(&self) -> Result<BoundingBox2D> {
208 BoundingBox2D::from_iterator(&self.data)
209 }
210}
211
212impl<P> HasCenterOfGravity2D for PointCloud2D<P>
213where
214 P: Is2D,
215{
216 fn center_of_gravity(&self) -> Result<Point2D> {
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
228 for p in &self.data {
229 sumx += p.x();
230 sumy += p.y();
231 }
232
233 Ok(Point2D {
234 x: sumx / sizef,
235 y: sumy / sizef,
236 })
237 }
238}
239
240impl<P> HasLength for PointCloud2D<P>
241where
242 P: Is2D,
243{
244 fn length(&self) -> f64 {
245 let mut length: f64 = 0.0;
246 if self.data.len() < 2 {
247 return length;
248 }
249
250 for i in 1..self.data.len() {
251 length += dist_2d(&self.data[i], &self.data[i - 1]);
252 }
253 length
254 }
255}
256
257impl<P> IsViewBuildable for PointCloud2D<P>
258where
259 P: Is2D + Clone,
260{
261 fn apply_view(&mut self, view: &View) -> Result<()> {
262 self.data.apply_view(view)?;
263 Ok(())
264 }
265
266 fn from_view(&self, view: &View) -> Result<Self> {
267 let mut cloned = self.clone();
268 cloned.apply_view(view)?;
269 Ok(cloned)
270 }
271}
272
273impl<P> IsSortableND for PointCloud2D<P>
274where
275 P: Is2D,
276{
277 fn n_dimensions() -> usize {
278 2
279 }
280
281 fn sort_dim(&mut self, dimension: usize) -> Result<()> {
282 match dimension {
283 0 => {
284 self.sort_x();
285 Ok(())
286 }
287 1 => {
288 self.sort_y();
289 Ok(())
290 }
291 _ => Err(ErrorKind::IncorrectDimension),
292 }
293 }
294}
295
296impl<P> IsSortable2D for PointCloud2D<P>
297where
298 P: Is2D,
299{
300 fn sort_x(&mut self) {
301 sort_vec_2d_x(&mut self.data)
302 }
303
304 fn sort_y(&mut self) {
305 sort_vec_2d_y(&mut self.data)
306 }
307}
308
309impl<P> IsMergeable for PointCloud2D<P>
310where
311 P: Is2D + Clone,
312{
313 fn consume(&mut self, other: Self) {
314 for p in other.data {
315 self.data.push(p.clone());
316 }
317 }
318
319 fn combine(&self, other: &Self) -> Self {
320 let mut result = self.clone();
321 result.consume(other.clone());
322 result
323 }
324}
325
326impl<P> IsScalable for PointCloud2D<P>
327where
328 P: IsEditable2D,
329{
330 fn scale(&mut self, factor: Positive) {
331 if let Ok(bb) = self.bounding_box_maybe() {
332 let c = bb.center_bb();
333 for p in &mut self.data {
334 p.increase_distance_to_by(&c, factor);
335 }
336 }
337 }
338}
339
340impl<P> IsMatrix3Transformable for PointCloud2D<P>
341where
342 P: Is2D + IsMatrix3Transformable + Clone,
343{
344 fn transformed(&self, m: &Matrix3) -> Self {
345 let mut new = self.clone();
346 new.transform(m);
347 new
348 }
349
350 fn transform(&mut self, m: &Matrix3) {
351 for p in &mut self.data {
352 p.transform(m);
353 }
354 }
355}
356
357impl<P> Default for PointCloud2D<P>
358where
359 P: Is2D,
361{
362 fn default() -> Self {
363 let data = Vec::new();
364 PointCloud2D { data }
365 }
366}
367
368impl<P> fmt::Display for PointCloud2D<P>
369where
370 P: Is2D + fmt::Display,
371{
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 for p in &self.data {
374 p.fmt(f)?;
375 f.write_str("\n")?;
376 }
377 Ok(())
378 }
379}
380
381impl<P> Into<Vec<P>> for PointCloud2D<P>
382where
383 P: Is2D,
384{
385 fn into(self) -> Vec<P> {
386 self.data
387 }
388}
389
390impl<P> From<Vec<P>> for PointCloud2D<P>
391where
392 P: Is2D,
393{
394 fn from(data: Vec<P>) -> Self {
395 Self { data }
396 }
397}