iron_shapes/
simple_rpolygon.rs

1// Copyright (c) 2018-2020 Thomas Kramer.
2// SPDX-FileCopyrightText: 2018-2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! This module contains data types and functions for basic rectilinear polygons without holes.
7
8use crate::CoordinateType;
9
10use crate::point::Point;
11use crate::rect::Rect;
12
13pub use crate::traits::{DoubledOrientedArea, MapPointwise, TryBoundingBox, WindingNumber};
14
15use crate::types::*;
16
17use crate::prelude::SimpleTransform;
18use crate::redge::{REdge, REdgeOrientation};
19use crate::simple_polygon::SimplePolygon;
20use crate::traits::TryCastCoord;
21use num_traits::NumCast;
22use std::cmp::{Ord, PartialEq};
23
24/// A `SimpleRPolygon` is a rectilinear polygon. It does not contain holes but can be self-intersecting.
25/// The vertices are stored in an implicit format (one coordinate of two neighbour vertices is always the same
26/// for rectilinear polygons). This reduces memory usage but has the drawback that edges must
27/// alternate between horizontal and vertical. Vertices between two edges of the same orientation will
28/// be dropped.
29///
30#[derive(Clone, Debug, Hash, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32pub struct SimpleRPolygon<T> {
33    /// Vertices of the polygon.
34    /// Begin with a y-coordinate. First edge is horizontal.
35    half_points: Vec<T>,
36    normalized: bool,
37}
38
39/// Shorthand notation for creating a simple polygon.
40/// # Example
41/// ```
42/// # #[macro_use]
43/// # extern crate iron_shapes;
44/// # fn main() {
45/// use iron_shapes::prelude::*;
46/// let p = simple_rpolygon!((0, 0), (1, 0), (1, 1), (0, 1));
47/// assert_eq!(Some(p), SimpleRPolygon::try_new(&vec![(0, 0), (1, 0), (1, 1), (0, 1)]));
48/// # }
49/// ```
50#[macro_export]
51macro_rules! simple_rpolygon {
52 ($($x:expr),*) => {SimpleRPolygon::try_new((&vec![$($x),*])).unwrap()}
53}
54
55impl<T> SimpleRPolygon<T> {
56    /// Create empty polygon without any vertices.
57    pub fn empty() -> Self {
58        Self {
59            half_points: Vec::new(),
60            normalized: true,
61        }
62    }
63
64    /// Get the number of vertices.
65    #[deprecated(note = "use len() instead")]
66    pub fn num_points(&self) -> usize {
67        self.half_points.len()
68    }
69
70    /// Get the number of vertices.
71    pub fn len(&self) -> usize {
72        self.half_points.len()
73    }
74
75    /// Check if polygon has no vertices.
76    pub fn is_empty(&self) -> bool {
77        self.half_points.is_empty()
78    }
79
80    /// Reverse the order of the vertices in-place.
81    pub fn reverse(&mut self) {
82        self.half_points.reverse();
83        self.half_points.rotate_right(1);
84    }
85
86    /// Get index of previous half-point.
87    fn prev(&self, i: usize) -> usize {
88        match i {
89            0 => self.half_points.len() - 1,
90            x => x - 1,
91        }
92    }
93
94    /// Get index of next half-point.
95    fn next(&self, i: usize) -> usize {
96        match i {
97            _ if i == self.half_points.len() - 1 => 0,
98            x => x + 1,
99        }
100    }
101}
102
103impl<T> SimpleRPolygon<T> {
104    /// Reverse the order of vertices.
105    pub fn reversed(mut self) -> Self {
106        self.reverse();
107        self
108    }
109}
110
111impl<T: Copy> SimpleRPolygon<T> {
112    /// Get `i`-th point of the polygon.
113    fn get_point(&self, i: usize) -> Point<T> {
114        if i % 2 == 0 {
115            Point::new(self.half_points[self.prev(i)], self.half_points[i])
116        } else {
117            Point::new(self.half_points[i], self.half_points[self.prev(i)])
118        }
119    }
120
121    /// Iterate over the points.
122    pub fn points(
123        &self,
124    ) -> impl DoubleEndedIterator<Item = Point<T>> + ExactSizeIterator + Clone + '_ {
125        (0..self.len()).map(move |i| self.get_point(i))
126    }
127
128    /// Get all exterior edges of the polygon.
129    /// # Examples
130    ///
131    /// ```
132    /// use iron_shapes::simple_rpolygon::SimpleRPolygon;
133    /// use iron_shapes::redge::REdge;
134    /// let coords = vec![(0, 0), (1, 0), (1, 1), (0, 1)];
135    ///
136    /// let poly = SimpleRPolygon::try_new(&coords).unwrap();
137    /// let edges: Vec<_> = poly.edges().collect();
138    /// assert_eq!(edges, vec![
139    ///     REdge::new((0, 0), (1, 0)),
140    ///     REdge::new((1, 0), (1, 1)),
141    ///     REdge::new((1, 1), (0, 1)),
142    ///     REdge::new((0, 1), (0, 0)),
143    /// ]);
144    ///
145    /// ```
146    pub fn edges(&self) -> impl Iterator<Item = REdge<T>> + '_ {
147        (0..self.len()).map(move |i| {
148            let orientation = if i % 2 == 0 {
149                REdgeOrientation::Horizontal
150            } else {
151                REdgeOrientation::Vertical
152            };
153
154            REdge::new_raw(
155                self.half_points[self.prev(i)],
156                self.half_points[self.next(i)],
157                self.half_points[i],
158                orientation,
159            )
160        })
161    }
162
163    /// Get all exterior edges of the polygon.
164    /// In contrast to [`SimpleRPolygon::edges`] this method takes ownership of the polygon.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use iron_shapes::simple_rpolygon::SimpleRPolygon;
170    /// use iron_shapes::redge::REdge;
171    /// let coords = vec![(0, 0), (1, 0), (1, 1), (0, 1)];
172    ///
173    /// let poly = SimpleRPolygon::try_new(&coords).unwrap();
174    /// let edges: Vec<_> = poly.edges().collect();
175    /// assert_eq!(edges, vec![
176    ///     REdge::new((0, 0), (1, 0)),
177    ///     REdge::new((1, 0), (1, 1)),
178    ///     REdge::new((1, 1), (0, 1)),
179    ///     REdge::new((0, 1), (0, 0)),
180    /// ]);
181    ///
182    /// ```
183    pub fn into_edges(self) -> impl Iterator<Item = REdge<T>> {
184        (0..self.len()).map(move |i| {
185            let orientation = if i % 2 == 0 {
186                REdgeOrientation::Horizontal
187            } else {
188                REdgeOrientation::Vertical
189            };
190
191            REdge::new_raw(
192                self.half_points[self.prev(i)],
193                self.half_points[self.next(i)],
194                self.half_points[i],
195                orientation,
196            )
197        })
198    }
199}
200
201impl<T: Copy + PartialEq> SimpleRPolygon<T> {
202    /// Create new rectilinear polygon from points.
203    /// Returns `None` if the polygon defined by the points is not rectilinear.
204    /// ```
205    /// use iron_shapes::simple_rpolygon::SimpleRPolygon;
206    ///
207    /// let poly1 = SimpleRPolygon::try_new(&vec![(0, 0), (1, 0), (1, 1), (0, 1)]);
208    /// assert!(poly1.is_some());
209    ///
210    /// // A triangle cannot be rectilinear.
211    /// let poly1 = SimpleRPolygon::try_new(&vec![(0, 0), (1, 0), (1, 1)]);
212    /// assert!(poly1.is_none());
213    ///
214    /// ```
215    pub fn try_new<I, Points, P>(points: I) -> Option<Self>
216    where
217        I: IntoIterator<Item = P, IntoIter = Points>,
218        Points: DoubleEndedIterator<Item = P> + ExactSizeIterator + Clone,
219        P: Copy + Into<Point<T>>,
220    {
221        let points = points.into_iter();
222
223        if let Some(last) = points.clone().last() {
224            let mut half_points = Vec::new();
225
226            let mut last: Point<T> = last.into();
227            #[derive(PartialEq, Eq, Debug)]
228            enum Orientation {
229                None,
230                Vertical,
231                Horizontal,
232            }
233
234            let mut orientation = Orientation::None;
235
236            let num_points = points.len();
237            for p in points.cycle().take(num_points + 1) {
238                let p: Point<T> = p.into();
239                match (last.x == p.x, last.y == p.y) {
240                    (true, true) => {
241                        // Same point. Do nothing.
242                    }
243                    (false, false) => {
244                        // Not rectilinear.
245                        return None;
246                    }
247                    (false, true) => {
248                        // Horizontal line. Store x.
249                        if orientation != Orientation::Horizontal {
250                            // Corner.
251                            if orientation == Orientation::Vertical {
252                                half_points.push(last.x);
253                            }
254                            orientation = Orientation::Horizontal;
255                        }
256                    }
257                    (true, false) => {
258                        // Vertical line.
259                        if orientation != Orientation::Vertical {
260                            // Corner.
261                            if orientation == Orientation::Horizontal {
262                                half_points.push(last.y);
263                            }
264                            orientation = Orientation::Vertical;
265                        }
266                    }
267                }
268                last = p;
269            }
270
271            debug_assert!(half_points.len() % 2 == 0);
272
273            if orientation == Orientation::Vertical {
274                // Last edge was horizontal.
275                // Make sure to *start* with a horizontal edge.
276
277                if !half_points.is_empty() {
278                    half_points.rotate_left(1);
279                }
280            }
281            Some(Self {
282                half_points,
283                normalized: false,
284            })
285        } else {
286            // Empty polygon.
287            Some(Self::empty())
288        }
289    }
290}
291
292impl<T: CoordinateType> SimpleRPolygon<T> {
293    /// Apply the transformation to this rectilinear polygon.
294    pub fn transformed(&self, tf: &SimpleTransform<T>) -> Self {
295        let points = self.points().map(|p| tf.transform_point(p));
296        // Unwrap should be fine because the edges will remain axis-aligned under the Simple Transform.
297        Self::try_new(points).unwrap()
298    }
299
300    /// Convert to a `SimplePolygon`.
301    pub fn to_simple_polygon(&self) -> SimplePolygon<T> {
302        SimplePolygon::new(self.points().collect())
303    }
304
305    /// Get the convex hull of the polygon.
306    ///
307    /// Implements Andrew's Monotone Chain algorithm.
308    /// See: <http://geomalgorithms.com/a10-_hull-1.html>
309    pub fn convex_hull(&self) -> SimplePolygon<T>
310    where
311        T: Ord,
312    {
313        crate::algorithms::convex_hull::convex_hull(self.points().collect())
314    }
315
316    /// Get the vertex with lowest x-coordinate. Prefer lower y-coordinates to break ties.
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// use iron_shapes::simple_rpolygon::SimpleRPolygon;
322    /// use iron_shapes::point::Point;
323    /// let coords = vec![(0, 0), (1, 0), (1, 1), (0, 1)];
324    ///
325    /// let poly = SimpleRPolygon::try_new(&coords).unwrap();
326    ///
327    /// assert_eq!(poly.lower_left_vertex(), Point::new(0, 0));
328    ///
329    /// ```
330    pub fn lower_left_vertex(&self) -> Point<T> {
331        debug_assert!(!self.is_empty());
332
333        self.lower_left_vertex_with_index().1
334    }
335
336    /// Get the vertex with lowest x-coordinate and its index.
337    /// Prefer lower y-coordinates to break ties.
338    fn lower_left_vertex_with_index(&self) -> (usize, Point<T>) {
339        debug_assert!(!self.is_empty());
340
341        // Find minimum.
342        let min = self
343            .points()
344            .enumerate()
345            .min_by(|(_, p1), (_, p2)| p1.partial_cmp(p2).unwrap());
346        let (idx, point) = min.unwrap();
347
348        (idx, point)
349    }
350
351    /// Get the orientation of the polygon,
352    /// i.e. check if it is wound clock-wise or counter-clock-wise.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// use iron_shapes::simple_rpolygon::SimpleRPolygon;
358    /// use iron_shapes::point::Point;
359    /// use iron_shapes::types::Orientation;
360    /// let coords = vec![(0, 0), (1, 0), (1, 1), (0, 1)];
361    ///
362    /// let poly = SimpleRPolygon::try_new(&coords).unwrap();
363    ///
364    /// assert_eq!(poly.orientation(), Orientation::CounterClockWise);
365    ///
366    /// ```
367    pub fn orientation(&self) -> Orientation {
368        // Find the orientation by the polygon area.
369
370        let area2 = self.area_doubled_oriented();
371
372        if area2 > T::zero() {
373            Orientation::CounterClockWise
374        } else if area2 < T::zero() {
375            Orientation::ClockWise
376        } else {
377            debug_assert!(area2 == T::zero());
378            Orientation::Straight
379        }
380    }
381
382    // TODO:
383    // /// Decompose into non-overlapping rectangles.
384    // pub fn decompose_rectangles(&self) -> Vec<Rect<T>> {
385    //     // Get vertical edges and order them by their lower end.
386    //     struct Vertical {
387    //         x: T,
388    //         y_low: T,
389    //         y_high: T,
390    //     }
391    //     impl Ord for Vertical {
392    //         fn cmp(&self, other: &Self) -> Ordering {
393    //
394    //         }
395    //     }
396    //     let mut verticals = BinaryHeap::new();
397    //     self.edges().filter(|e| e.is_vertical())
398    //         .for_each(|e| {
399    //             let (y_low, y_high) = if e.start < e.end {
400    //                 (e.start, e.end)
401    //             } else {
402    //                 (e.end, e.start)
403    //             };
404    //             let v = Vertical {
405    //                 x: e.offset,
406    //                 y_low,
407    //                 y_high,
408    //             };
409    //             verticals.push(v);
410    //         });
411    //     unimplemented!()
412    // }
413}
414
415impl<T> WindingNumber<T> for SimpleRPolygon<T>
416where
417    T: CoordinateType,
418{
419    /// Calculate the winding number of the polygon around this point.
420    ///
421    /// TODO: Define how point on edges and vertices is handled.
422    ///
423    /// See: <http://geomalgorithms.com/a03-_inclusion.html>
424    fn winding_number(&self, point: Point<T>) -> isize {
425        let mut winding_number = 0isize;
426
427        // Edge Crossing Rules
428        //
429        // 1. an upward edge includes its starting endpoint, and excludes its final endpoint;
430        // 2. a downward edge excludes its starting endpoint, and includes its final endpoint;
431        // 3. horizontal edges are excluded
432        // 4. the edge-ray intersection point must be strictly right of the point P.
433
434        for e in self.edges() {
435            if e.start().y <= point.y {
436                // Crosses upward?
437                if e.end().y > point.y {
438                    // Crosses really upward?
439                    // Yes, crosses upward.
440                    if e.side_of(point) == Side::Left {
441                        winding_number += 1;
442                    }
443                }
444            } else if e.end().y <= point.y {
445                // Crosses downward?
446                // Yes, crosses downward.
447                // `e.start.y > point.y` needs not to be checked anymore.
448                if e.side_of(point) == Side::Right {
449                    winding_number -= 1;
450                }
451            }
452        }
453
454        winding_number
455    }
456}
457
458impl<T: CoordinateType> From<Rect<T>> for SimpleRPolygon<T> {
459    fn from(r: Rect<T>) -> Self {
460        Self {
461            half_points: vec![
462                r.lower_left.y,
463                r.upper_right.x,
464                r.upper_right.y,
465                r.lower_left.x,
466            ],
467            normalized: true,
468        }
469    }
470}
471
472#[test]
473fn test_from_rect() {
474    use super::rect::Rect;
475    let r = Rect::new((0, 1), (2, 3));
476    let p = SimpleRPolygon::from(r);
477    assert_eq!(
478        p.points().collect::<Vec<_>>(),
479        [
480            Point::new(0, 1),
481            Point::new(2, 1),
482            Point::new(2, 3),
483            Point::new(0, 3)
484        ]
485    );
486
487    assert_eq!(p, p.clone().normalized());
488}
489
490// /// Create a polygon from a type that is convertible into an iterator of values convertible to `Point`s.
491// impl<I, T, P> TryFrom<I> for SimpleRPolygon<T>
492//     where T: CoordinateType,
493//           I: IntoIterator<Item=P>,
494//           Point<T>: From<P>
495// {
496//     type Error = ();
497//     /// Create a polygon from a type that is convertible into an iterator of values convertible to `Point`s.
498//     /// Return `None` if the polygon is not rectilinear.
499//     fn try_from(iter: I) -> Result<Self, ()> {
500//         let points: Vec<Point<T>> = iter.into_iter().map(
501//             |x| x.into()
502//         ).collect();
503//
504//         match SimpleRPolygon::try_new(points) {
505//             None => Err(()),
506//             Some(p) => Ok(p)
507//         }
508//     }
509// }
510
511//
512// /// Create a polygon from a `Vec` of values convertible to `Point`s.
513// impl<'a, T, P> From<&'a Vec<P>> for SimplePolygon<T>
514//     where T: CoordinateType,
515//           Point<T>: From<&'a P>
516// {
517//     fn from(vec: &'a Vec<P>) -> Self {
518//         let points: Vec<Point<T>> = vec.into_iter().map(
519//             |x| x.into()
520//         ).collect();
521//
522//         SimplePolygon { points }
523//     }
524// }
525//
526// /// Create a polygon from a `Vec` of values convertible to `Point`s.
527// impl<T, P> From<Vec<P>> for SimplePolygon<T>
528//     where T: CoordinateType,
529//           Point<T>: From<P>
530// {
531//     fn from(vec: Vec<P>) -> Self {
532//         let points: Vec<Point<T>> = vec.into_iter().map(
533//             |x| x.into()
534//         ).collect();
535//
536//         SimplePolygon { points }
537//     }
538// }
539
540impl<T> SimpleRPolygon<T>
541where
542    T: Copy + PartialOrd,
543{
544    /// Check if the polygon is an axis-aligned rectangle.
545    pub fn is_rect(&self) -> bool {
546        self.len() == 4
547    }
548}
549
550impl<T> TryBoundingBox<T> for SimpleRPolygon<T>
551where
552    T: Copy + PartialOrd,
553{
554    fn try_bounding_box(&self) -> Option<Rect<T>> {
555        if !self.is_empty() {
556            let mut xmax = self.half_points[1];
557            let mut ymax = self.half_points[0];
558            let mut xmin = xmax;
559            let mut ymin = ymax;
560            self.half_points.chunks(2).for_each(|c| {
561                let x = c[1];
562                let y = c[0];
563                if x > xmax {
564                    xmax = x
565                };
566                if x < xmin {
567                    xmin = x
568                };
569                if y > ymax {
570                    ymax = y
571                };
572                if y < ymin {
573                    ymin = y
574                };
575            });
576
577            Some(Rect::new((xmin, ymin), (xmax, ymax)))
578        } else {
579            None
580        }
581    }
582}
583
584impl<T: CoordinateType> DoubledOrientedArea<T> for SimpleRPolygon<T> {
585    /// Calculates the doubled oriented area.
586    ///
587    /// Using doubled area allows to compute in the integers because the area
588    /// of a polygon with integer coordinates is either integer or half-integer.
589    ///
590    /// The area will be positive if the vertices are listed counter-clockwise,
591    /// negative otherwise.
592    ///
593    /// Complexity: O(n)
594    ///
595    /// # Examples
596    ///
597    /// ```
598    /// use iron_shapes::traits::DoubledOrientedArea;
599    /// use iron_shapes::simple_rpolygon::SimpleRPolygon;
600    /// let coords = vec![(0, 0), (1, 0), (1, 1), (0, 1)];
601    ///
602    /// let poly = SimpleRPolygon::try_new(&coords).unwrap();
603    ///
604    /// assert_eq!(poly.area_doubled_oriented(), 2);
605    ///
606    /// ```
607    fn area_doubled_oriented(&self) -> T {
608        debug_assert!(self.half_points.len() % 2 == 0);
609        // Iterate over all horizontal edges. Compute the area
610        // as the sum of (oriented edge length) * (edge distance to origin).
611        let area: T = (0..self.len())
612            .step_by(2)
613            .map(move |i| {
614                let start = self.half_points[self.prev(i)];
615                let end = self.half_points[self.next(i)];
616                let offset = self.half_points[i];
617
618                (start - end) * offset
619            })
620            .fold(T::zero(), |acc, area| acc + area);
621
622        area + area
623    }
624}
625
626impl<T: PartialOrd> SimpleRPolygon<T> {
627    /// Rotate the vertices to get the lexicographically smallest polygon.
628    /// Does not change the orientation.
629    pub fn normalize(&mut self) {
630        let rotated = |rot: usize| {
631            self.half_points
632                .iter()
633                .cycle()
634                .skip(rot)
635                .take(self.half_points.len())
636        };
637        let best_rot =
638            (0..self.half_points.len() / 2)
639                .skip(1)
640                .map(|r| r * 2)
641                .fold(0, |best_rot, rot| {
642                    if rotated(rot).lt(rotated(best_rot)) {
643                        rot
644                    } else {
645                        best_rot
646                    }
647                });
648        self.half_points.rotate_left(best_rot);
649    }
650
651    /// Rotate the vertices to get the lexicographically smallest polygon.
652    /// Does not change the orientation.
653    pub fn normalized(mut self) -> Self {
654        self.normalize();
655        self
656    }
657}
658
659impl<T: PartialEq> SimpleRPolygon<T> {
660    /// Equality test for simple polygons.
661    ///
662    /// Two polygons are equal iff a cyclic shift on their vertices can be applied
663    /// such that the both lists of vertices match exactly.
664    pub fn normalized_eq(&self, other: &Self) -> bool {
665        if self.len() != other.len() {
666            false
667        } else {
668            let n = self.half_points.len();
669            debug_assert!(n % 2 == 0);
670            (0..n / 2).any(|rot| {
671                let rotated = self.half_points.iter().cycle().skip(rot * 2).take(n);
672                rotated.eq(other.half_points.iter())
673            })
674        }
675    }
676}
677
678impl<T: CoordinateType + NumCast, Dst: CoordinateType + NumCast> TryCastCoord<T, Dst>
679    for SimpleRPolygon<T>
680{
681    type Output = SimpleRPolygon<Dst>;
682
683    fn try_cast(&self) -> Option<Self::Output> {
684        let new_half_points: Option<Vec<_>> =
685            self.half_points.iter().map(|&p| Dst::from(p)).collect();
686
687        new_half_points.map(|p| SimpleRPolygon {
688            half_points: p,
689            normalized: self.normalized,
690        })
691    }
692}
693
694#[test]
695fn test_create_rpolygon() {
696    let p = SimpleRPolygon::try_new(&vec![(0, 0), (1, 0), (1, 2), (0, 2)]).unwrap();
697    assert_eq!(p.half_points, vec![0, 1, 2, 0]);
698
699    let p = SimpleRPolygon::try_new(&vec![(1, 0), (1, 2), (0, 2), (0, 0)]).unwrap();
700    assert_eq!(p.half_points, vec![0, 1, 2, 0]);
701
702    // Zero-area polygon is converted to an empty polygon.
703    let p = SimpleRPolygon::try_new(&vec![(0, 1), (0, 0)]).unwrap();
704    assert_eq!(p.half_points, vec![]);
705
706    // Intermediate vertices on straight lines are removed.
707    let p = SimpleRPolygon::try_new(&vec![(0, 0), (1, 0), (1, 1), (1, 2), (0, 2), (0, 1)]).unwrap();
708
709    assert_eq!(p.half_points, vec![0, 1, 2, 0]);
710}
711
712/// Two simple polygons should be the same even if points are shifted cyclical.
713#[test]
714fn test_partial_eq() {
715    let p1 = simple_rpolygon!((0, 0), (0, 1), (1, 1), (1, 0));
716    let p2 = simple_rpolygon!((0, 0), (0, 1), (1, 1), (1, 0));
717    assert!(p1.normalized_eq(&p2));
718
719    let p2 = simple_rpolygon!((0, 1), (1, 1), (1, 0), (0, 0));
720    assert!(p1.normalized_eq(&p2));
721}
722
723/// Simple sanity check for computation of bounding box.
724#[test]
725fn test_bounding_box() {
726    let p = simple_rpolygon!((0, 1), (2, 1), (2, 3), (0, 3));
727    assert_eq!(p.try_bounding_box(), Some(Rect::new((0, 1), (2, 3))));
728}
729
730#[test]
731fn test_reversed() {
732    let p = simple_rpolygon!((0, 0), (1, 0), (1, 1), (2, 1), (2, 2), (0, 2));
733    let p_rev_expected = simple_rpolygon!((0, 2), (2, 2), (2, 1), (1, 1), (1, 0), (0, 0));
734    let p_rev_actual = p.clone().reversed();
735    assert!(p_rev_actual.normalized_eq(&p_rev_expected));
736    assert_eq!(
737        p.clone().reversed().reversed().normalized().half_points,
738        p.normalized().half_points
739    )
740}