myelin_geometry/
polygon.rs

1//! Types relating to 2D convex polygons and their construction
2
3pub use self::builder::*;
4use super::*;
5use crate::ConvexHull;
6use crate::Intersects;
7use itertools::Itertools;
8use serde::{Deserialize, Serialize};
9
10mod builder;
11
12/// A convex polygon.
13///
14/// Can either be constructed using a [`PolygonBuilder`]
15/// or with [`Polygon::try_new`].
16///
17/// [`PolygonBuilder`]: ./struct.PolygonBuilder.html
18/// [`Polygon::try_new`]: ./struct.Polygon.html#method.try_new
19#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
20pub struct Polygon {
21    /// The vertices of the polygon
22    vertices: Vec<Point>,
23}
24
25impl Polygon {
26    /// Creates a new [`Polygon`] from the given [`Point`]s.
27    ///
28    /// # Errors
29    /// This method will return an error if the number of configured
30    /// vertices is less than three (as the resulting [`Polygon`]
31    /// would not be two-dimensional), or if the resulting [`Polygon`] is not convex.
32    ///
33    /// [`Polygon`]: ./struct.Polygon.html
34    /// [`Point`]: ./struct.Point.html
35    pub fn try_new(vertices: Vec<Point>) -> Result<Self, ()> {
36        const MINIMUM_VERTICES_IN_EUCLIDEAN_GEOMETRY: usize = 3;
37
38        if vertices.len() >= MINIMUM_VERTICES_IN_EUCLIDEAN_GEOMETRY
39            && vertices.iter().all(is_finite)
40            && is_convex_polygon(&vertices)
41        {
42            Ok(Self { vertices })
43        } else {
44            Err(())
45        }
46    }
47
48    /// Returns the vertices of the polygon
49    pub fn vertices(&self) -> &[Point] {
50        &self.vertices
51    }
52
53    /// Apply translation specified by `translation`, represented as
54    /// a relative point
55    pub fn translate(&self, translation: Point) -> Self {
56        let translated_vertices = self
57            .vertices
58            .iter()
59            .map(|&vertex| vertex + translation)
60            .collect();
61
62        Polygon {
63            vertices: translated_vertices,
64        }
65    }
66
67    /// Rotate polygon by a `rotation` around a `point`
68    pub fn rotate_around_point(&self, rotation: Radians, point: Point) -> Self {
69        let rotation = rotation.value();
70        let rotated_vertices = self
71            .vertices
72            .iter()
73            .map(|&vertex| {
74                // See https://en.wikipedia.org/wiki/Rotation_matrix
75                let delta = vertex - point;
76                let (rotation_sin, rotation_cos) = rotation.sin_cos();
77                let rotated_x = rotation_cos * delta.x + rotation_sin * delta.y + point.x;
78                let rotated_y = -rotation_sin * delta.x + rotation_cos * delta.y + point.y;
79                Point {
80                    x: rotated_x,
81                    y: rotated_y,
82                }
83            })
84            .collect();
85        Self {
86            vertices: rotated_vertices,
87        }
88    }
89
90    /// Checks if a given point rests inside the polygon
91    pub fn contains_point(&self, point: Point) -> bool {
92        let vector_to_point: Vector = point.into();
93        // The following unwraps are safe, as we do an
94        // early return if we don't contain at least 2 vertices
95        let vector_to_last_point: Vector = (*self.vertices.last().unwrap()).into();
96        let vector_to_first_point: Vector = (*self.vertices.first().unwrap()).into();
97        let reference_side =
98            calculate_facing_side(vector_to_last_point, vector_to_first_point, vector_to_point);
99
100        // If the point lies on the same side of all lines of the polygon,
101        // the point is contained in the polygon.
102        self.vertices
103            .iter()
104            .tuple_windows()
105            .map(|(&vector_to_point_a, &vector_to_point_b)| {
106                calculate_facing_side(
107                    vector_to_point_a.into(),
108                    vector_to_point_b.into(),
109                    vector_to_point,
110                )
111            })
112            .all(|side| side == reference_side || side == Side::OnTheLine)
113    }
114
115    /// Returns an [`Aabb`] which fully contains this polygon.
116    ///
117    /// # Panics
118    /// Panics if the floating-point values representing the vertices' coordinates
119    /// are not comparable, e.g. `NaN` or if the polygon has no vertices.
120    /// The latter should never occur, because the constructor validates that the polygon is valid.
121    pub fn aabb(&self) -> Aabb {
122        let mut vertices = self.vertices.clone();
123
124        // Safe unwrap: A polygon's vertex should not be baloney like NaN
125        vertices.sort_unstable_by(|a, b| a.x.partial_cmp(&b.x).unwrap());
126        // Safe unwraps: A polygon should always have at least one vertex
127        let min_x = vertices.first().unwrap().x;
128        let max_x = vertices.last().unwrap().x;
129
130        vertices.sort_unstable_by(|a, b| a.y.partial_cmp(&b.y).unwrap());
131        let min_y = vertices.first().unwrap().y;
132        let max_y = vertices.last().unwrap().y;
133
134        // Safe unwrap: A polygon where all four points are the same is not valid
135        Aabb::try_new((min_x, min_y), (max_x, max_y)).unwrap()
136    }
137
138    /// Returns the polygon's edges, i.e. the lines between vertices, as vectors.
139    pub fn edges(&self) -> impl Iterator<Item = Vector> + '_ {
140        let vertices = self.vertices();
141        let shifted_vertices = vertices.iter().cycle().skip(1).take(vertices.len());
142        vertices
143            .iter()
144            .zip(shifted_vertices)
145            .map(|(&first_vertex, &second_vertex)| second_vertex - first_vertex)
146            .map(Vector::from)
147    }
148
149    fn scalar_project_onto_unit_vector(&self, axis: Vector) -> (f64, f64) {
150        let projection: Vec<_> = self
151            .vertices()
152            .iter()
153            .cloned()
154            .map(Vector::from)
155            .map(|vector| vector.dot_product(axis))
156            .collect();
157        (
158            *projection
159                .iter()
160                .min_by(|lhs, rhs| lhs.partial_cmp(rhs).unwrap())
161                .unwrap(),
162            *projection
163                .iter()
164                .max_by(|lhs, rhs| lhs.partial_cmp(rhs).unwrap())
165                .unwrap(),
166        )
167    }
168}
169
170impl Intersects for Polygon {
171    /// Returns wether this polygon touches, contains or is contained in another polygon
172    fn intersects(&self, other: &Polygon) -> bool {
173        // The following codes describes the Separating Axis Theorem (SAT),
174        // which states that if we are able to draw a straight line (i.e. axis)
175        // between two polygons (i.e. separating them), they are not intersecting
176
177        // Take all edges
178        self.edges()
179            .chain(other.edges())
180            // If we can draw a perpendicular (i.e. normal) between them,
181            // the polygons are separate
182            .map(Vector::normal)
183            // Make axis a unit vector to simplify the following math:
184            // If the axis has a magnitude of 1, we don't need to divide
185            // the scalar projection by it.
186            .map(Vector::unit)
187            .all(|axis| {
188                // Take the bounds of the line that is created by projecting all
189                // vertices onto the axis
190                let (own_min, own_max) = self.scalar_project_onto_unit_vector(axis);
191                let (other_min, other_max) = other.scalar_project_onto_unit_vector(axis);
192
193                // If both bounds are outside the other polygon's projection, we are
194                // able to draw a separating axis between them
195                own_min.max(other_min) <= own_max.min(other_max)
196            })
197    }
198}
199
200impl From<Aabb> for Polygon {
201    fn from(aabb: Aabb) -> Self {
202        Polygon {
203            vertices: vec![
204                Point {
205                    x: aabb.upper_left.x,
206                    y: aabb.upper_left.y,
207                },
208                Point {
209                    x: aabb.upper_left.x,
210                    y: aabb.lower_right.y,
211                },
212                Point {
213                    x: aabb.lower_right.x,
214                    y: aabb.upper_left.y,
215                },
216                Point {
217                    x: aabb.lower_right.x,
218                    y: aabb.lower_right.y,
219                },
220            ],
221        }
222    }
223}
224
225/// Calculate which on which side of a line from `a` to `b` a
226/// given `point` is
227fn calculate_facing_side(a: Vector, b: Vector, point: Vector) -> Side {
228    let side_vector = b - a;
229    let vector_from_a_to_point = point - a;
230    let cross_product = side_vector.cross_product(vector_from_a_to_point);
231
232    /// Minimal distance from `point` to the line to be considered
233    /// exactly *on* the line
234    const EPSILON: f64 = 0.000_001;
235    if cross_product < -EPSILON {
236        Side::Left
237    } else if cross_product > EPSILON {
238        Side::Right
239    } else {
240        Side::OnTheLine
241    }
242}
243
244fn is_convex_polygon(vertices: &[Point]) -> bool {
245    let convex_hull_vertice_count = ConvexHull::try_new(vertices).unwrap().count();
246    convex_hull_vertice_count == vertices.len()
247}
248
249fn is_finite(vertice: &Point) -> bool {
250    vertice.x.is_finite() && vertice.y.is_finite()
251}
252
253/// The side that a [`Point`] lies on, from the
254/// point of view of a line
255#[derive(Eq, PartialEq, Debug)]
256enum Side {
257    /// The point lies to the right of the line
258    Right,
259    /// The point lies to the left of the line
260    Left,
261    /// The point is exactly on the line
262    OnTheLine,
263}
264
265#[cfg(test)]
266mod tests {
267    use self::builder::PolygonBuilder;
268    use super::*;
269    use std::f64::consts::PI;
270
271    fn polygon() -> Polygon {
272        PolygonBuilder::default()
273            .vertex(-10.0, -10.0)
274            .vertex(10.0, -10.0)
275            .vertex(10.0, 10.0)
276            .vertex(-10.0, 10.0)
277            .build()
278            .unwrap()
279    }
280
281    fn translation() -> Point {
282        Point { x: 30.0, y: 40.0 }
283    }
284
285    #[test]
286    fn translates() {
287        let polygon = polygon();
288        assert_eq!(
289            Polygon {
290                vertices: vec![
291                    Point { x: 20.0, y: 30.0 },
292                    Point { x: 40.0, y: 30.0 },
293                    Point { x: 40.0, y: 50.0 },
294                    Point { x: 20.0, y: 50.0 },
295                ],
296            },
297            polygon.translate(translation())
298        );
299    }
300
301    #[test]
302    fn rotates_by_pi() {
303        let polygon = polygon();
304
305        const FLOATING_POINT_INACCURACY: f64 = 0.000_000_000_000_002;
306        assert_eq!(
307            Polygon {
308                vertices: vec![
309                    Point {
310                        x: 10.0 - FLOATING_POINT_INACCURACY,
311                        y: 10.0 + FLOATING_POINT_INACCURACY,
312                    },
313                    Point {
314                        x: -10.0 - FLOATING_POINT_INACCURACY,
315                        y: 10.0 - FLOATING_POINT_INACCURACY,
316                    },
317                    Point {
318                        x: -10.0 + FLOATING_POINT_INACCURACY,
319                        y: -10.0 - FLOATING_POINT_INACCURACY,
320                    },
321                    Point {
322                        x: 10.0 + FLOATING_POINT_INACCURACY,
323                        y: -10.0 + FLOATING_POINT_INACCURACY,
324                    },
325                ],
326            },
327            polygon.rotate_around_point(Radians::try_new(PI).unwrap(), Point::default())
328        );
329    }
330
331    #[test]
332    fn rotates_by_arbitrary_orientation() {
333        let polygon = polygon();
334
335        const ROTATION_A: f64 = 8.488_724_885_405_782;
336        const ROTATION_B: f64 = 11.311_125_046_603_125;
337
338        assert_eq!(
339            Polygon {
340                vertices: vec![
341                    Point {
342                        x: ROTATION_A,
343                        y: ROTATION_B,
344                    },
345                    Point {
346                        x: -ROTATION_B,
347                        y: ROTATION_A,
348                    },
349                    Point {
350                        x: -ROTATION_A,
351                        y: -ROTATION_B,
352                    },
353                    Point {
354                        x: ROTATION_B,
355                        y: -ROTATION_A,
356                    },
357                ],
358            },
359            polygon.rotate_around_point(Radians::try_new(3.0).unwrap(), Point::default())
360        );
361    }
362
363    #[test]
364    fn translates_and_rotates() {
365        let polygon = polygon();
366        let translation = translation();
367        let translated_polygon = polygon.translate(translation);
368
369        assert_eq!(
370            Polygon {
371                vertices: vec![
372                    Point {
373                        x: 38.488_724_885_405_78,
374                        y: 51.311_125_046_603_124,
375                    },
376                    Point {
377                        x: 18.688_874_953_396_876,
378                        y: 48.488_724_885_405_78,
379                    },
380                    Point {
381                        x: 21.511_275_114_594_22,
382                        y: 28.688_874_953_396_876,
383                    },
384                    Point {
385                        x: 41.311_125_046_603_124,
386                        y: 31.511_275_114_594_22,
387                    },
388                ],
389            },
390            translated_polygon.rotate_around_point(Radians::try_new(3.0).unwrap(), translation)
391        );
392    }
393
394    #[test]
395    fn contains_point_when_point_is_positive() {
396        let translation = Point { x: 10.43, y: 20.1 };
397        let polygon = polygon().translate(translation);
398        let point = Point { x: 12.0, y: 18.0 };
399        assert!(polygon.contains_point(point));
400    }
401
402    #[test]
403    fn contains_point_when_point_is_negative() {
404        let translation = Point { x: -20.0, y: -5.0 };
405        let polygon = polygon().translate(translation);
406        let point = Point { x: -21.70, y: -2.3 };
407        assert!(polygon.contains_point(point));
408    }
409
410    #[test]
411    fn contains_point_when_point_is_at_zero() {
412        let polygon = polygon();
413        let point = Point::default();
414        assert!(polygon.contains_point(point));
415    }
416
417    #[test]
418    fn contains_point_at_border() {
419        let polygon = polygon();
420        let point = Point { x: 10.0, y: -10.0 };
421        assert!(polygon.contains_point(point));
422    }
423
424    #[test]
425    fn does_not_contain_point_barely_outside_polygon() {
426        let polygon = polygon();
427        let point = Point { x: 10.1, y: -10.1 };
428        assert!(!polygon.contains_point(point));
429    }
430
431    #[test]
432    fn does_not_contain_point_way_outside_polygon() {
433        let polygon = polygon();
434        let point = Point {
435            x: -9000.0,
436            y: -9000.0,
437        };
438        assert!(!polygon.contains_point(point));
439    }
440
441    #[test]
442    fn does_not_contain_point_when_point_is_at_zero() {
443        let translation = Point { x: 11.0, y: 11.0 };
444        let polygon = polygon().translate(translation);
445        let point = Point::default();
446        assert!(!polygon.contains_point(point));
447    }
448
449    #[test]
450    #[should_panic]
451    fn aabb_panics_when_polygon_has_zero_vertices() {
452        let polygon = Polygon::default();
453        let _aabb = polygon.aabb();
454    }
455
456    #[test]
457    fn aabb_returns_works_with_three_vertices() {
458        let polygon = Polygon {
459            vertices: vec![
460                Point { x: -5.0, y: -5.0 },
461                Point { x: 5.0, y: 0.0 },
462                Point { x: 5.0, y: 5.0 },
463            ],
464        };
465        let expected_aabb = Aabb::try_new((-5.0, -5.0), (5.0, 5.0)).unwrap();
466
467        assert_eq!(expected_aabb, polygon.aabb());
468    }
469
470    #[test]
471    fn aabb_returns_works_with_four_vertices() {
472        let polygon = Polygon {
473            vertices: vec![
474                Point { x: 5.0, y: 0.0 },
475                Point { x: 0.0, y: 5.0 },
476                Point { x: -5.0, y: -5.0 },
477                Point { x: 5.0, y: 5.0 },
478            ],
479        };
480        let expected_aabb = Aabb::try_new((-5.0, -5.0), (5.0, 5.0)).unwrap();
481
482        assert_eq!(expected_aabb, polygon.aabb());
483    }
484
485    #[test]
486    fn try_new_errors_for_zero_vertices() {
487        assert!(Polygon::try_new(Vec::new()).is_err());
488    }
489
490    #[test]
491    fn try_new_errors_for_one_vertex() {
492        assert!(Polygon::try_new(vec![Point { x: 0.0, y: 0.0 }]).is_err());
493    }
494
495    #[test]
496    fn try_new_errors_for_two_vertices() {
497        assert!(
498            Polygon::try_new(vec![Point { x: 0.0, y: 0.0 }, Point { x: 1.0, y: 0.0 }]).is_err()
499        );
500    }
501
502    #[test]
503    fn try_new_works_for_three_vertices() {
504        assert_eq!(
505            Ok(Polygon {
506                vertices: vec![
507                    Point { x: 0.0, y: 0.0 },
508                    Point { x: 1.0, y: 0.0 },
509                    Point { x: 0.0, y: 1.0 },
510                ]
511            }),
512            Polygon::try_new(vec![
513                Point { x: 0.0, y: 0.0 },
514                Point { x: 1.0, y: 0.0 },
515                Point { x: 0.0, y: 1.0 },
516            ])
517        );
518    }
519
520    #[test]
521    fn try_new_works_for_four_vertices() {
522        assert_eq!(
523            Ok(Polygon {
524                vertices: vec![
525                    Point { x: 0.0, y: 0.0 },
526                    Point { x: 1.0, y: 0.0 },
527                    Point { x: 0.0, y: 1.0 },
528                    Point { x: 1.0, y: 1.0 },
529                ]
530            }),
531            Polygon::try_new(vec![
532                Point { x: 0.0, y: 0.0 },
533                Point { x: 1.0, y: 0.0 },
534                Point { x: 0.0, y: 1.0 },
535                Point { x: 1.0, y: 1.0 },
536            ])
537        );
538    }
539
540    #[test]
541    fn try_new_does_not_work_with_concave_polygon() {
542        assert!(Polygon::try_new(vec![
543            Point { x: 10.0, y: 10.0 },
544            Point { x: 5.0, y: 5.0 },
545            Point { x: 10.0, y: 5.0 },
546            Point { x: 15.0, y: 0.0 },
547            Point { x: 10.0, y: 0.0 },
548        ])
549        .is_err());
550    }
551
552    #[test]
553    fn try_new_works_with_convex_polygon() {
554        let vertices = vec![
555            Point { x: 10.0, y: 10.0 },
556            Point { x: 5.0, y: 5.0 },
557            Point { x: 20.0, y: 5.0 },
558            Point { x: 15.0, y: 0.0 },
559            Point { x: 10.0, y: 0.0 },
560        ];
561
562        assert_eq!(
563            Ok(Polygon {
564                vertices: vertices.clone(),
565            }),
566            Polygon::try_new(vertices)
567        );
568    }
569
570    #[test]
571    fn try_new_does_not_work_when_x_value_of_vertice_is_positive_infinity() {
572        let vertices = vec![
573            Point {
574                x: f64::INFINITY,
575                y: 0.0,
576            },
577            Point { x: 1.0, y: 0.0 },
578            Point { x: 0.0, y: 1.0 },
579        ];
580        assert!(Polygon::try_new(vertices).is_err());
581    }
582
583    #[test]
584    fn try_new_does_not_work_when_x_value_of_vertice_is_negative_infinity() {
585        let vertices = vec![
586            Point {
587                x: f64::NEG_INFINITY,
588                y: 0.0,
589            },
590            Point { x: 1.0, y: 0.0 },
591            Point { x: 0.0, y: 1.0 },
592        ];
593        assert!(Polygon::try_new(vertices).is_err());
594    }
595
596    #[test]
597    fn try_new_does_not_work_when_x_value_of_vertice_is_nan() {
598        let vertices = vec![
599            Point {
600                x: f64::NAN,
601                y: 0.0,
602            },
603            Point { x: 1.0, y: 0.0 },
604            Point { x: 0.0, y: 1.0 },
605        ];
606        assert!(Polygon::try_new(vertices).is_err());
607    }
608
609    #[test]
610    fn try_new_does_not_work_when_y_value_of_vertice_is_positive_infinity() {
611        let vertices = vec![
612            Point {
613                x: 0.0,
614                y: f64::INFINITY,
615            },
616            Point { x: 1.0, y: 0.0 },
617            Point { x: 0.0, y: 1.0 },
618        ];
619        assert!(Polygon::try_new(vertices).is_err());
620    }
621
622    #[test]
623    fn try_new_does_not_work_when_y_value_of_vertice_is_negative_infinity() {
624        let vertices = vec![
625            Point {
626                x: 0.0,
627                y: f64::NEG_INFINITY,
628            },
629            Point { x: 1.0, y: 0.0 },
630            Point { x: 0.0, y: 1.0 },
631        ];
632        assert!(Polygon::try_new(vertices).is_err());
633    }
634
635    #[test]
636    fn try_new_does_not_work_when_y_value_of_vertice_is_nan() {
637        let vertices = vec![
638            Point {
639                x: 0.0,
640                y: f64::NAN,
641            },
642            Point { x: 1.0, y: 0.0 },
643            Point { x: 0.0, y: 1.0 },
644        ];
645        assert!(Polygon::try_new(vertices).is_err());
646    }
647
648    #[test]
649    fn can_be_created_from_aabb() {
650        let aabb = Aabb::try_new(Point { x: 10.0, y: 15.0 }, Point { x: 20.0, y: 30.0 }).unwrap();
651        let expected_polygon = Polygon::try_new(vec![
652            Point { x: 10.0, y: 15.0 },
653            Point { x: 10.0, y: 30.0 },
654            Point { x: 20.0, y: 15.0 },
655            Point { x: 20.0, y: 30.0 },
656        ])
657        .unwrap();
658
659        assert_eq!(expected_polygon, Polygon::from(aabb));
660    }
661
662    #[test]
663    fn edges_are_reported_correctly() {
664        let polygon = Polygon::try_new(vec![
665            Point { x: 10.0, y: 15.0 },
666            Point { x: 10.0, y: 30.0 },
667            Point { x: 20.0, y: 15.0 },
668            Point { x: 20.0, y: 30.0 },
669        ])
670        .unwrap();
671
672        let expected_edges = vec![
673            Vector { x: 0.0, y: 15.0 },
674            Vector { x: 10.0, y: -15.0 },
675            Vector { x: 0.0, y: 15.0 },
676            Vector { x: -10.0, y: -15.0 },
677        ];
678
679        let edges: Vec<_> = polygon.edges().collect();
680        assert_eq!(expected_edges, edges);
681    }
682
683    #[test]
684    fn intersects_self() {
685        let polygon = Polygon::try_new(vec![
686            Point { x: 0.0, y: 0.0 },
687            Point { x: 10.0, y: 0.0 },
688            Point { x: 10.0, y: 10.0 },
689        ])
690        .unwrap();
691        assert!(polygon.intersects(&polygon));
692    }
693
694    #[test]
695    fn intersects_contained() {
696        let bigger_polygon = Polygon::try_new(vec![
697            Point { x: 0.0, y: 0.0 },
698            Point { x: 10.0, y: 0.0 },
699            Point { x: 10.0, y: 10.0 },
700        ])
701        .unwrap();
702        let smaller_polygon = Polygon::try_new(vec![
703            Point { x: 2.0, y: 2.0 },
704            Point { x: 8.0, y: 2.0 },
705            Point { x: 8.0, y: 8.0 },
706        ])
707        .unwrap();
708        assert!(bigger_polygon.intersects(&smaller_polygon));
709        assert!(smaller_polygon.intersects(&bigger_polygon));
710    }
711
712    #[test]
713    fn intersects_touching_line() {
714        let left_polygon = Polygon::try_new(vec![
715            Point { x: 0.0, y: 0.0 },
716            Point { x: 10.0, y: 0.0 },
717            Point { x: 10.0, y: 10.0 },
718        ])
719        .unwrap();
720        let right_polygon = Polygon::try_new(vec![
721            Point { x: 10.0, y: 0.0 },
722            Point { x: 5.0, y: 5.0 },
723            Point { x: 20.0, y: 10.0 },
724        ])
725        .unwrap();
726        assert!(left_polygon.intersects(&right_polygon));
727        assert!(right_polygon.intersects(&left_polygon));
728    }
729
730    #[test]
731    fn intersects_touching_point() {
732        let left_polygon = Polygon::try_new(vec![
733            Point { x: 0.0, y: 0.0 },
734            Point { x: 10.0, y: 0.0 },
735            Point { x: 10.0, y: 10.0 },
736        ])
737        .unwrap();
738        let right_polygon = Polygon::try_new(vec![
739            Point { x: 10.0, y: 10.0 },
740            Point { x: 20.0, y: 10.0 },
741            Point { x: 20.0, y: 11.0 },
742        ])
743        .unwrap();
744        assert!(left_polygon.intersects(&right_polygon));
745        assert!(right_polygon.intersects(&left_polygon));
746    }
747
748    #[test]
749    fn intersects_intersecting() {
750        let first_polygon = Polygon::try_new(vec![
751            Point { x: 0.0, y: 0.0 },
752            Point { x: 10.0, y: 0.0 },
753            Point { x: 10.0, y: 10.0 },
754        ])
755        .unwrap();
756        let second_polygon = Polygon::try_new(vec![
757            Point { x: 8.0, y: 8.0 },
758            Point { x: 20.0, y: 8.0 },
759            Point { x: 20.0, y: 20.0 },
760        ])
761        .unwrap();
762        assert!(first_polygon.intersects(&second_polygon));
763        assert!(second_polygon.intersects(&first_polygon));
764    }
765
766    #[test]
767    fn intersects_intersecting_when_negative() {
768        let first_polygon = Polygon::try_new(vec![
769            Point { x: -10.0, y: -10.0 },
770            Point { x: -5.0, y: -10.0 },
771            Point { x: -5.0, y: -5.0 },
772        ])
773        .unwrap();
774        let second_polygon = Polygon::try_new(vec![
775            Point { x: -8.0, y: -20.0 },
776            Point { x: -3.0, y: -20.0 },
777            Point { x: -3.0, y: -3.0 },
778        ])
779        .unwrap();
780        assert!(first_polygon.intersects(&second_polygon));
781        assert!(second_polygon.intersects(&first_polygon));
782    }
783
784    #[test]
785    fn intersects_intersecting_when_negative_and_positive() {
786        let first_polygon = Polygon::try_new(vec![
787            Point { x: -5.0, y: -5.0 },
788            Point { x: 5.0, y: -5.0 },
789            Point { x: 5.0, y: 5.0 },
790        ])
791        .unwrap();
792        let second_polygon = Polygon::try_new(vec![
793            Point { x: -6.0, y: -20.0 },
794            Point { x: 0.0, y: -20.0 },
795            Point { x: 0.0, y: 2.0 },
796        ])
797        .unwrap();
798        assert!(first_polygon.intersects(&second_polygon));
799        assert!(second_polygon.intersects(&first_polygon));
800    }
801
802    #[test]
803    fn does_not_intersect_when_apart() {
804        let first_polygon = Polygon::try_new(vec![
805            Point { x: 0.0, y: 0.0 },
806            Point { x: 10.0, y: 0.0 },
807            Point { x: 10.0, y: 10.0 },
808        ])
809        .unwrap();
810        let second_polygon = Polygon::try_new(vec![
811            Point { x: 20.0, y: 0.0 },
812            Point { x: 21.0, y: 0.0 },
813            Point { x: 21.0, y: 20.0 },
814        ])
815        .unwrap();
816        assert!(!first_polygon.intersects(&second_polygon));
817        assert!(!second_polygon.intersects(&first_polygon));
818    }
819}