1use std::{ops::{Add, AddAssign, Index, Mul, MulAssign, Range, RangeFrom, RangeFull, RangeTo, Sub, SubAssign}, rc::Rc};
2
3use usvg::tiny_skia_path;
4use wasm_bindgen::prelude::*;
5
6use crate::utils::{console::log, interpolation::lerp, linear_algebra::matrix_product_path};
7
8use super::{bezier::{AnchorsAndHandles, CubicBezierTuple}, linear_algebra::TransformationMatrix};
9
10#[wasm_bindgen]
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct Point2D {
14 pub x: f32,
16 pub y: f32,
18}
19
20impl Default for Point2D {
21 fn default() -> Point2D {
22 Point2D { x: 0.0, y: 0.0 }
23 }
24}
25
26#[wasm_bindgen]
27impl Point2D {
28 #[wasm_bindgen(constructor, return_description = "A 2D point.")]
30 pub fn new(
31 #[wasm_bindgen(param_description = "The x-coordinate of the point.")]
32 x: f32,
33 #[wasm_bindgen(param_description = "The y-coordinate of the point.")]
34 y: f32
35 ) -> Point2D {
36 Point2D { x, y }
37 }
38
39 #[wasm_bindgen(return_description = "The interpolated point.")]
41 pub fn lerp(
42 #[wasm_bindgen(param_description = "The start point.")]
43 point1: &Point2D,
44 #[wasm_bindgen(param_description = "The end point.")]
45 point2: &Point2D,
46 #[wasm_bindgen(param_description = "The progress value.")]
47 t: f32
48 ) -> Point2D {
49 Point2D {
50 x: lerp(point1.x, point2.x, t),
51 y: lerp(point1.y, point2.y, t),
52 }
53 }
54 #[wasm_bindgen(return_description = "A 2D point.")]
56 pub fn from_polar(
57 #[wasm_bindgen(param_description = "The radius of the point.")]
58 radius: f32,
59 #[wasm_bindgen(param_description = "The angle of the point.")]
60 angle: f32
61 ) -> Point2D {
62 Point2D {
63 x: radius * angle.cos(),
64 y: radius * angle.sin(),
65 }
66 }
67 #[wasm_bindgen(return_description = "The distance between the two points.")]
69 pub fn distance_squared(
70 &self,
71 #[wasm_bindgen(param_description = "The other point.")]
72 other: &Point2D
73 ) -> f32 {
74 let dx = self.x - other.x;
75 let dy = self.y - other.y;
76 dx * dx + dy * dy
77 }
78 #[wasm_bindgen(return_description = "A boolean indicating whether the two points are equal.")]
80 pub fn equals(
81 &self,
82 #[wasm_bindgen(param_description = "The other point.")]
83 other: &Point2D,
84 #[wasm_bindgen(param_description = "The tolerance.")]
85 tolerance: Option<f32>
86 ) -> bool {
87 let tolerance = tolerance.unwrap_or(0.01);
88 self.distance_squared(other) < tolerance * tolerance
89 }
90 #[wasm_bindgen(return_description = "The rotated point.")]
92 pub fn rotate_around(
93 &self,
94 #[wasm_bindgen(param_description = "The center point to rotate around.")]
95 center: Point2D,
96 #[wasm_bindgen(param_description = "The angle to rotate by.")]
97 angle: f32
98 ) -> Point2D {
99 let (sin, cos) = angle.sin_cos();
100 let x = cos * (self.x - center.x) - sin * (self.y - center.y) + center.x;
101 let y = sin * (self.x - center.x) + cos * (self.y - center.y) + center.y;
102 Point2D { x, y }
103 }
104 #[wasm_bindgen(return_description = "The distance between the two points.")]
106 pub fn distance(
107 &self,
108 #[wasm_bindgen(param_description = "The other point.")]
109 other: &Point2D
110 ) -> f32 {
111 self.distance_squared(other).sqrt()
112 }
113 #[wasm_bindgen(js_name = clone)]
115 pub fn copy(&self) -> Point2D {
116 *self
117 }
118 #[wasm_bindgen(getter, return_description = "The squared magnitude of the point.")]
120 pub fn magnitude_squared(&self) -> f32 {
121 self.x * self.x + self.y * self.y
122 }
123 #[wasm_bindgen(getter, return_description = "The magnitude of the point.")]
125 pub fn magnitude(&self) -> f32 {
126 self.magnitude_squared().sqrt()
127 }
128 #[wasm_bindgen(getter, return_description = "The normalized point.")]
130 pub fn normalized(&self) -> Point2D {
131 let magnitude = self.magnitude();
132 Point2D {
133 x: self.x / magnitude,
134 y: self.y / magnitude,
135 }
136 }
137 #[wasm_bindgen(return_description = "The dot product of the two points.")]
139 pub fn dot(
140 &self,
141 #[wasm_bindgen(param_description = "The other point.")]
142 other: &Point2D
143 ) -> f32 {
144 self.x * other.x + self.y * other.y
145 }
146 #[wasm_bindgen(return_description = "The angle between the two points.")]
148 pub fn angle(
149 &self,
150 #[wasm_bindgen(param_description = "The other point.")]
151 other: &Point2D
152 ) -> f32 {
153 let dot = self.dot(other);
154 let magnitude_product = self.magnitude() * other.magnitude();
155 (dot / magnitude_product).acos()
156 }
157 #[wasm_bindgen(getter, return_description = "The direction angle of the point.")]
159 pub fn direction(&self) -> f32 {
160 self.y.atan2(self.x)
161 }
162 #[wasm_bindgen(return_description = "The proportion of the line.")]
164 pub fn project_onto_line(
165 &self,
166 #[wasm_bindgen(param_description = "The start point of the line.")]
167 start: &Point2D,
168 #[wasm_bindgen(param_description = "The end point of the line.")]
169 end: &Point2D
170 ) -> f32 {
171 let line = *end - *start;
172 let line_squared = line.magnitude_squared();
173 if line_squared == 0.0 {
174 return 0.0;
175 }
176 let projection = *self - *start;
177 (line.dot(&projection) / line_squared).max(0.0).min(1.0)
178 }
179 #[wasm_bindgen(return_description = "A boolean indicating whether the point is finite.")]
181 pub fn is_finite(&self) -> bool {
182 self.x.is_finite() && self.y.is_finite()
183 }
184}
185
186impl Add<Point2D> for Point2D {
187 type Output = Point2D;
188
189 fn add(self, other: Point2D) -> Point2D {
190 Point2D {
191 x: self.x + other.x,
192 y: self.y + other.y,
193 }
194 }
195}
196
197impl Add<Point2D> for f32 {
198 type Output = Point2D;
199
200 fn add(self, point: Point2D) -> Point2D {
201 Point2D {
202 x: self + point.x,
203 y: self + point.y,
204 }
205 }
206}
207
208impl Add<f32> for Point2D {
209 type Output = Point2D;
210
211 fn add(self, scalar: f32) -> Point2D {
212 Point2D {
213 x: self.x + scalar,
214 y: self.y + scalar,
215 }
216 }
217}
218
219impl AddAssign<Point2D> for Point2D {
220 fn add_assign(&mut self, other: Point2D) {
221 self.x += other.x;
222 self.y += other.y;
223 }
224}
225
226impl AddAssign<f32> for Point2D {
227 fn add_assign(&mut self, scalar: f32) {
228 self.x += scalar;
229 self.y += scalar;
230 }
231}
232
233impl Sub<Point2D> for Point2D {
234 type Output = Point2D;
235
236 fn sub(self, other: Point2D) -> Point2D {
237 Point2D {
238 x: self.x - other.x,
239 y: self.y - other.y,
240 }
241 }
242}
243
244impl Sub<Point2D> for f32 {
245 type Output = Point2D;
246
247 fn sub(self, point: Point2D) -> Point2D {
248 Point2D {
249 x: self - point.x,
250 y: self - point.y,
251 }
252 }
253}
254
255impl Sub<f32> for Point2D {
256 type Output = Point2D;
257
258 fn sub(self, scalar: f32) -> Point2D {
259 Point2D {
260 x: self.x - scalar,
261 y: self.y - scalar,
262 }
263 }
264}
265
266impl SubAssign<Point2D> for Point2D {
267 fn sub_assign(&mut self, other: Point2D) {
268 self.x -= other.x;
269 self.y -= other.y;
270 }
271}
272
273impl SubAssign<f32> for Point2D {
274 fn sub_assign(&mut self, scalar: f32) {
275 self.x -= scalar;
276 self.y -= scalar;
277 }
278}
279
280impl Mul<f32> for Point2D {
281 type Output = Point2D;
282
283 fn mul(self, scalar: f32) -> Point2D {
284 Point2D {
285 x: self.x * scalar,
286 y: self.y * scalar,
287 }
288 }
289}
290
291impl Mul<Point2D> for f32 {
292 type Output = Point2D;
293
294 fn mul(self, point: Point2D) -> Point2D {
295 Point2D {
296 x: self * point.x,
297 y: self * point.y,
298 }
299 }
300}
301
302impl Mul<Point2D> for Point2D {
303 type Output = Point2D;
304
305 fn mul(self, other: Point2D) -> Point2D {
306 Point2D {
307 x: self.x * other.x,
308 y: self.y * other.y,
309 }
310 }
311}
312
313impl MulAssign<Point2D> for Point2D {
314 fn mul_assign(&mut self, other: Point2D) {
315 self.x *= other.x;
316 self.y *= other.y;
317 }
318}
319
320impl MulAssign<f32> for Point2D {
321 fn mul_assign(&mut self, scalar: f32) {
322 self.x *= scalar;
323 self.y *= scalar;
324 }
325}
326
327#[wasm_bindgen]
329#[derive(Clone, Debug, PartialEq)]
330pub struct Path2D {
331 points: Rc<Vec<Point2D>>
333}
334
335#[wasm_bindgen]
336impl Path2D {
337 #[wasm_bindgen(constructor, return_description = "A 2D path.")]
339 pub fn new(
340 #[wasm_bindgen(param_description = "The points of the path.")]
341 points: Vec<Point2D>
342 ) -> Path2D {
343 Path2D { points: Rc::new(points) }
344 }
345
346 #[wasm_bindgen(return_description = "A 2D path.")]
348 pub fn from_anchors_and_handles(
349 #[wasm_bindgen(param_description = "The AnchorsAndHandles object.")]
350 anchors_and_handles: &AnchorsAndHandles
351 ) -> Path2D {
352 let mut points = Vec::new();
353 for i in 0..anchors_and_handles.len() {
354 points.push(anchors_and_handles.start_anchors()[i]);
355 points.push(anchors_and_handles.first_controls()[i]);
356 points.push(anchors_and_handles.second_controls()[i]);
357 points.push(anchors_and_handles.end_anchors()[i]);
358 }
359 Path2D { points: Rc::new(points) }
360 }
361
362 #[wasm_bindgen(js_name = clone)]
364 pub fn copy(&self) -> Path2D {
365 self.clone()
366 }
367
368 #[wasm_bindgen(return_description = "The repeated path.")]
370 pub fn repeat(
371 &self,
372 #[wasm_bindgen(param_description = "The number of times to repeat the path.")]
373 count: usize
374 ) -> Path2D {
375 let mut points = Vec::with_capacity(self.points.len() * count);
376 for _ in 0..count {
377 points.extend(Rc::clone(&self.points).iter());
378 }
379 Path2D { points: Rc::new(points) }
380 }
381
382 #[wasm_bindgen(getter, return_description = "The points of the path.")]
384 pub fn points(&self) -> Vec<Point2D> {
385 Rc::clone(&self.points).to_vec()
386 }
387
388 #[wasm_bindgen(setter)]
390 pub fn set_points(
391 &mut self,
392 #[wasm_bindgen(param_description = "The points of the path.")]
393 points: Vec<Point2D>
394 ) {
395 self.points = Rc::new(points);
396 }
397
398 #[wasm_bindgen(getter, return_description = "A boolean indicating whether the path is empty.")]
400 pub fn is_empty(&self) -> bool {
401 self.points.is_empty()
402 }
403
404 #[wasm_bindgen(return_description = "The closest point in the path.")]
406 pub fn closest_point(
407 &self,
408 #[wasm_bindgen(param_description = "The point to find the closest point to.")]
409 point: &Point2D
410 ) -> Point2D {
411 let mut closest_point = self.points[0];
412 let mut closest_distance = point.distance(&closest_point);
413 for i in 1..self.points.len() {
414 let distance = point.distance(&self.points[i]);
415 if distance < closest_distance {
416 closest_point = self.points[i];
417 closest_distance = distance;
418 }
419 }
420 closest_point
421 }
422
423 #[wasm_bindgen(getter, return_description = "The length of the path.")]
425 pub fn len(&self) -> usize {
426 self.points.len()
427 }
428
429 #[wasm_bindgen(return_description = "The first point of the path.")]
431 pub fn get(
432 &self,
433 #[wasm_bindgen(param_description = "The index of the point.")]
434 index: usize
435 ) -> Point2D {
436 self.points[index]
437 }
438
439 pub fn set(
441 &mut self,
442 #[wasm_bindgen(param_description = "The index of the point.")]
443 index: usize,
444 #[wasm_bindgen(param_description = "The new point.")]
445 point: Point2D
446 ) {
447 Rc::make_mut(&mut self.points)[index] = point;
448 }
449
450 pub fn push(
452 &mut self,
453 #[wasm_bindgen(param_description = "The point to append.")]
454 point: Point2D
455 ) {
456 Rc::make_mut(&mut self.points).push(point);
457 }
458
459 #[wasm_bindgen(return_description = "The last point of the path.")]
461 pub fn pop(&mut self) -> Option<Point2D> {
462 Rc::make_mut(&mut self.points).pop()
463 }
464
465 pub fn insert(
467 &mut self,
468 #[wasm_bindgen(param_description = "The index to insert the point at.")]
469 index: usize,
470 #[wasm_bindgen(param_description = "The point to insert.")]
471 point: Point2D
472 ) {
473 Rc::make_mut(&mut self.points).insert(index, point);
474 }
475
476 #[wasm_bindgen(return_description = "The removed point.")]
478 pub fn remove(
479 &mut self,
480 #[wasm_bindgen(param_description = "The index of the point to remove.")]
481 index: usize
482 ) -> Point2D {
483 Rc::make_mut(&mut self.points).remove(index)
484 }
485
486 pub fn clear(&mut self) {
488 Rc::make_mut(&mut self.points).clear();
489 }
490
491 #[wasm_bindgen(return_description = "A Path2D object representing the portion of the input path.")]
493 pub fn partial_bezier_path(
494 &self,
495 #[wasm_bindgen(param_description = "The start proportion of the input path. A number between 0 and 1.")]
496 a: f32,
497 #[wasm_bindgen(param_description = "The end proportion of the input path. A number between 0 and 1.")]
498 b: f32,
499 ) -> Path2D {
500 if a == 1.0 {
501 return Path2D::fill(self.get(self.len() - 1), self.len());
502 }
503 if b == 0.0 {
504 return Path2D::fill(self.get(0), self.len());
505 }
506 let degree = self.len() - 1;
507 if degree == 3 {
508 let (ma, mb) = (
509 1.0 - a,
510 1.0 - b,
511 );
512 let (a2, b2, ma2, mb2) = (
513 a * a,
514 b * b,
515 ma * ma,
516 mb * mb,
517 );
518 let (a3, b3, ma3, mb3) = (
519 a2 * a,
520 b2 * b,
521 ma2 * ma,
522 mb2 * mb,
523 );
524 let portion_matrix = vec![
525 ma3, 3.0 * ma2 * a, 3.0 * ma * a2, a3,
526 ma2 * mb, 2.0 * ma * a * mb + ma2 * b, a2 * mb + 2.0 * ma * a * b, a2 * b,
527 ma * mb2, a * mb2 + 2.0 * ma * mb * b, 2.0 * a * mb * b + ma * b2, a * b2,
528 mb3, 3.0 * mb2 * b, 3.0 * mb * b2, b3,
529 ];
530 let a_rows = 4;
531 let a_columns = 4;
532 let b_columns = 2;
533 let result = matrix_product_path(portion_matrix, &self, a_rows, a_columns, b_columns);
534 return result;
535 }
536 if degree == 2 {
537 let (ma, mb) = (
538 1.0 - a,
539 1.0 - b,
540 );
541 let (a2, b2, ma2, mb2) = (
542 a * a,
543 b * b,
544 ma * ma,
545 mb * mb,
546 );
547 let portion_matrix = vec![
548 ma2, 2.0 * ma * a, a2,
549 ma * mb, ma * b + a * mb, a * b,
550 mb2, 2.0 * mb * b, b2,
551 ];
552 let a_rows = 3;
553 let a_columns = 3;
554 let b_columns = 2;
555 let result = matrix_product_path(portion_matrix, &self, a_rows, a_columns, b_columns);
556 return result;
557 }
558 if degree == 1 {
559 let direction = self[1] - self[0];
560 return Path2D::new(vec![
561 self[0] + direction * a,
562 self[0] + direction * b,
563 ]);
564 }
565 if degree == 0 {
566 return Path2D::fill(self[0], 1);
567 }
568 let n = self.len();
569 let mut points = Rc::clone(&self.points);
570 if a != 0.0 {
571 for i in 1..n {
572 let new_points = points[1..n - i + 1].iter().zip(points[0..n - i].iter()).map(|(a, b)| *a + *a * (*a - *b)).collect::<Vec<Point2D>>();
573 Rc::make_mut(&mut points).splice(0..n - i, new_points);
574 }
575 }
576 if b != 1.0 {
577 let mu = (1.0 - b) / (1.0 - a);
578 for i in 1..n {
579 let new_points = points[i - 1..n - 1].iter().zip(points[i..n].iter()).map(|(a, b)| *a + mu * (*a - *b)).collect::<Vec<Point2D>>();
580 Rc::make_mut(&mut points).splice(i..n, new_points);
581 }
582 }
583 Path2D { points }
584 }
585
586 #[wasm_bindgen(return_description = "A path that is a portion of the input path.")]
588 pub fn fill(
589 #[wasm_bindgen(param_description = "The point to fill the path with.")]
590 point: Point2D,
591 #[wasm_bindgen(param_description = "The number of times to fill the path with the point.")]
592 count: usize
593 ) -> Path2D {
594 Path2D {
595 points: Rc::new(vec![point; count])
596 }
597 }
598
599 pub fn reverse(&mut self) {
601 Rc::make_mut(&mut self.points).reverse();
602 }
603
604 pub fn set_slice(
606 &mut self,
607 #[wasm_bindgen(param_description = "The start index of the slice.")]
608 start: usize,
609 #[wasm_bindgen(param_description = "The end index of the slice.")]
610 end: usize,
611 #[wasm_bindgen(param_description = "The new path.")]
612 path: Path2D
613 ) {
614 let points = Rc::clone(&path.points);
615 Rc::make_mut(&mut self.points).splice(start..end, points.to_vec());
616 }
617
618 #[wasm_bindgen(return_description = "A slice of the path.")]
620 pub fn slice(
621 &self,
622 #[wasm_bindgen(param_description = "The start index of the slice.")]
623 start: usize,
624 #[wasm_bindgen(param_description = "The end index of the slice.")]
625 end: usize
626 ) -> Path2D {
627 Path2D {
628 points: Rc::new(self.points[start..end].to_vec())
629 }
630 }
631
632 #[wasm_bindgen(getter, return_description = "The cubic bezier tuples of the path.")]
634 pub fn cubic_bezier_tuples(&self) -> Vec<CubicBezierTuple> {
635 let remainder = self.points.len() % 4;
636 let points = self.slice(0, self.points.len() - remainder);
637 points.points.chunks(4).map(|chunk| {
638 CubicBezierTuple::new(chunk[0], chunk[1], chunk[2], chunk[3])
639 }).collect()
640 }
641
642 pub fn push_bezier(
644 &mut self,
645 #[wasm_bindgen(param_description = "The cubic bezier tuple to add.")]
646 cubic_bezier: CubicBezierTuple
647 ) {
648 if self.points.len() % 4 != 0 && !cubic_bezier.start_anchor().equals(&self.points[self.points.len() - 1], None) {
649 log("The path length must be a multiple of 4.");
650 return;
651 }
652 if self.points.len() % 4 == 0 {
653 Rc::make_mut(&mut self.points).push(cubic_bezier.start_anchor());
654 }
655 Rc::make_mut(&mut self.points).push(cubic_bezier.first_control());
656 Rc::make_mut(&mut self.points).push(cubic_bezier.second_control());
657 Rc::make_mut(&mut self.points).push(cubic_bezier.end_anchor());
658 }
659
660 #[wasm_bindgen(return_description = "An approximation of the length of the path.")]
662 pub fn length(
663 &self,
664 #[wasm_bindgen(param_description = "The number of samples to take along each cubic bezier curve.")]
665 samples_per_cubic: Option<usize>,
666 #[wasm_bindgen(param_description = "An optional extra length to add to each cubic bezier length approximation.")]
667 extra_length_per_cubic: Option<f32>
668 ) -> f32 {
669 self.cubic_bezier_tuples().iter().map(|tuple| tuple.length(samples_per_cubic, extra_length_per_cubic)).sum()
670 }
671
672 #[wasm_bindgen(getter, return_description = "The first point of the path.")]
674 pub fn first(&self) -> Point2D {
675 self.points[0]
676 }
677
678 #[wasm_bindgen(getter, return_description = "The last point of the path.")]
680 pub fn last(&self) -> Option<Point2D> {
681 self.points.last().copied()
682 }
683}
684
685impl Path2D {
686 pub fn from_svg_path_data(
688 data: &tiny_skia_path::Path,
689 ) -> Path2D {
690 let mut path = Path2D::default();
691 let mut move_point = Point2D::default();
692 let mut current_point = Point2D::default();
693 for segment in data.segments() {
694 match segment {
695 tiny_skia_path::PathSegment::MoveTo(point) => {
696 current_point = Point2D::new(point.x, point.y);
697 move_point = current_point;
698 }
699 tiny_skia_path::PathSegment::LineTo(point) => {
700 path.push_bezier(CubicBezierTuple::from_line(current_point, Point2D::new(point.x, point.y)));
701 current_point = Point2D::new(point.x, point.y);
702 }
703 tiny_skia_path::PathSegment::QuadTo(control, point) => {
704 path.push_bezier(CubicBezierTuple::from_quadratic(current_point, Point2D::new(control.x, control.y), Point2D::new(point.x, point.y)));
705 current_point = Point2D::new(point.x, point.y);
706 }
707 tiny_skia_path::PathSegment::CubicTo(control1, control2, point) => {
708 path.push_bezier(CubicBezierTuple::new(current_point, Point2D::new(control1.x, control1.y), Point2D::new(control2.x, control2.y), Point2D::new(point.x, point.y)));
709 current_point = Point2D::new(point.x, point.y);
710 }
711 tiny_skia_path::PathSegment::Close => {
712 path.push_bezier(CubicBezierTuple::from_line(current_point, move_point));
713 current_point = move_point;
714 }
715 }
716 }
717 path
718 }
719 pub fn transform(
721 &self,
722 matrix: &TransformationMatrix
723 ) -> Path2D {
724 Path2D {
725 points: Rc::new(self.points.iter().map(|point| *matrix * *point).collect())
726 }
727 }
728}
729
730impl Add<Point2D> for Path2D {
731 type Output = Path2D;
732
733 fn add(self, point: Point2D) -> Path2D {
734 Path2D {
735 points: Rc::new(self.points.to_vec().into_iter().map(|p| p + point).collect())
736 }
737 }
738}
739
740impl Add<Path2D> for Point2D {
741 type Output = Path2D;
742
743 fn add(self, path: Path2D) -> Path2D {
744 Path2D {
745 points: Rc::new(path.points.to_vec().into_iter().map(|p| self + p).collect())
746 }
747 }
748}
749
750impl AddAssign<Point2D> for Path2D {
751 fn add_assign(&mut self, point: Point2D) {
752 Rc::make_mut(&mut self.points).iter_mut().for_each(|p| *p += point);
753 }
754}
755
756impl Add<Path2D> for Path2D {
757 type Output = Path2D;
758
759 fn add(self, other: Path2D) -> Path2D {
760 Path2D {
761 points: Rc::new(self.points.iter().zip(other.points.iter()).map(|(a, b)| *a + *b).collect())
762 }
763 }
764}
765
766impl AddAssign<Path2D> for Path2D {
767 fn add_assign(&mut self, other: Path2D) {
768 Rc::make_mut(&mut self.points).iter_mut().zip(other.points.iter()).for_each(|(a, b)| *a += *b);
769 }
770}
771
772impl Sub<Point2D> for Path2D {
773 type Output = Path2D;
774
775 fn sub(self, point: Point2D) -> Path2D {
776 Path2D {
777 points: Rc::new(self.points.to_vec().into_iter().map(|p| p - point).collect())
778 }
779 }
780}
781
782impl Sub<Path2D> for Point2D {
783 type Output = Path2D;
784
785 fn sub(self, path: Path2D) -> Path2D {
786 Path2D {
787 points: Rc::new(path.points.to_vec().into_iter().map(|p| self - p).collect())
788 }
789 }
790}
791
792impl SubAssign<Point2D> for Path2D {
793 fn sub_assign(&mut self, point: Point2D) {
794 Rc::make_mut(&mut self.points).iter_mut().for_each(|p| *p -= point);
795 }
796}
797
798impl Sub<Path2D> for Path2D {
799 type Output = Path2D;
800
801 fn sub(self, other: Path2D) -> Path2D {
802 Path2D {
803 points: Rc::new(self.points.iter().zip(other.points.iter()).map(|(a, b)| *a - *b).collect())
804 }
805 }
806}
807
808impl SubAssign<Path2D> for Path2D {
809 fn sub_assign(&mut self, other: Path2D) {
810 Rc::make_mut(&mut self.points).iter_mut().zip(other.points.iter()).for_each(|(a, b)| *a -= *b);
811 }
812}
813
814impl Mul<f32> for Path2D {
815 type Output = Path2D;
816
817 fn mul(self, scalar: f32) -> Path2D {
818 Path2D {
819 points: Rc::new(self.points.to_vec().into_iter().map(|p| p * scalar).collect())
820 }
821 }
822}
823
824impl Mul<Path2D> for f32 {
825 type Output = Path2D;
826
827 fn mul(self, path: Path2D) -> Path2D {
828 Path2D {
829 points: Rc::new(path.points.to_vec().into_iter().map(|p| self * p).collect())
830 }
831 }
832}
833
834impl Mul<Point2D> for Path2D {
835 type Output = Path2D;
836
837 fn mul(self, point: Point2D) -> Path2D {
838 Path2D {
839 points: Rc::new(self.points.to_vec().into_iter().map(|p| p * point).collect())
840 }
841 }
842}
843
844impl Mul<Path2D> for Point2D {
845 type Output = Path2D;
846
847 fn mul(self, path: Path2D) -> Path2D {
848 Path2D {
849 points: Rc::new(path.points.to_vec().into_iter().map(|p| self * p).collect())
850 }
851 }
852}
853
854impl MulAssign<f32> for Path2D {
855 fn mul_assign(&mut self, scalar: f32) {
856 Rc::make_mut(&mut self.points).iter_mut().for_each(|p| *p *= scalar);
857 }
858}
859
860impl MulAssign<Point2D> for Path2D {
861 fn mul_assign(&mut self, point: Point2D) {
862 Rc::make_mut(&mut self.points).iter_mut().for_each(|p| *p *= point);
863 }
864}
865
866impl Index<usize> for Path2D {
867 type Output = Point2D;
868
869 fn index(&self, index: usize) -> &Point2D {
870 &self.points[index]
871 }
872}
873
874impl Index<Range<usize>> for Path2D {
875 type Output = [Point2D];
876
877 fn index(&self, range: Range<usize>) -> &[Point2D] {
878 &self.points[range]
879 }
880}
881
882impl Index<RangeTo<usize>> for Path2D {
883 type Output = [Point2D];
884
885 fn index(&self, range: RangeTo<usize>) -> &[Point2D] {
886 &self.points[range]
887 }
888}
889
890impl Index<RangeFrom<usize>> for Path2D {
891 type Output = [Point2D];
892
893 fn index(&self, range: RangeFrom<usize>) -> &[Point2D] {
894 &self.points[range]
895 }
896}
897
898impl Index<RangeFull> for Path2D {
899 type Output = [Point2D];
900
901 fn index(&self, range: RangeFull) -> &[Point2D] {
902 &self.points[range]
903 }
904}
905
906impl IntoIterator for Path2D {
907 type Item = Point2D;
908 type IntoIter = std::vec::IntoIter<Point2D>;
909
910 fn into_iter(self) -> Self::IntoIter {
911 self.points.to_vec().into_iter()
912 }
913}
914
915impl Extend<Point2D> for Path2D {
916 fn extend<T: IntoIterator<Item = Point2D>>(&mut self, iter: T) {
917 Rc::make_mut(&mut self.points).extend(iter);
918 }
919}
920
921impl Default for Path2D {
922 fn default() -> Self {
923 Path2D { points: Rc::new(Vec::new()) }
924 }
925}