Skip to main content

planar_geo/
polysegment.rs

1/*!
2Defines the [`Polysegment`] type, a foundational [`Composite`] used throughout
3this crate.
4
5Segment polysegments serve as the basis for higher-level geometric types such as
6[`Contour`](crate::contour::Contour) and [`Shape`](crate::shape::Shape). They
7represent connected sequences of segments and provide the core functionality
8required by composite geometries.
9
10Most users should interact with this module through the [`Polysegment`] type
11itself; see its documentation for details on construction, invariants, and
12usage.
13*/
14
15use std::collections::VecDeque;
16
17use crate::primitive::Primitive;
18use crate::segment::{ArcSegment, LineSegment, Segment, SegmentRef};
19use crate::{DEFAULT_EPSILON, DEFAULT_MAX_ULPS};
20use crate::{Transformation, composite::*};
21use approx::ulps_eq;
22use bounding_box::{BoundingBox, ToBoundingBox};
23use rayon::prelude::*;
24
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28/**
29A sequence of [`Segment`]s where each segment is "connected" to its successor
30(end / stop point of a segment is approximately equal to the start point of the
31successor).
32
33*/
34#[doc = ""]
35#[cfg_attr(
36    feature = "doc-images",
37    doc = "![Polysegment example][example_polysegment]"
38)]
39#[cfg_attr(
40    feature = "doc-images",
41    embed_doc_image::embed_doc_image("example_polysegment", "docs/img/example_polysegment.svg")
42)]
43#[cfg_attr(
44    not(feature = "doc-images"),
45    doc = "**Doc images not enabled**. Compile docs with `cargo doc --features 'doc-images'` and Rust version >= 1.54."
46)]
47/**
48
49The approximate equality of start and end point is defined by
50[`DEFAULT_EPSILON`] and [`DEFAULT_MAX_ULPS`]:
51
52```ignore
53approx::ulps_eq!(polysegment[i].stop(), polysegment[i+1].start(), epsilon = DEFAULT_EPSILON, max_ulps = DEFAULT_MAX_ULPS)
54```
55
56A polysegment can intersect itself (i.e. at least two of its segments
57intersect each other). This can be tested using its [`Composite`] trait
58implementation:
59
60```
61use planar_geo::prelude::*;
62
63let polysegment = Polysegment::from_points(&[[0.0, 0.0], [2.0, 2.0], [0.0, 2.0], [2.0, 0.0]]);
64assert_eq!(polysegment.intersections_polysegment(&polysegment, 0.0, 0).count(), 1);
65```
66
67# Constructing a polysegment
68
69A polysegment is essentially a [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html)
70wrapper around a [`VecDeque<Segment>`] and therefore exposes many of the same
71methods. For example, a polysegment can be built via
72[`push_front`](Polysegment::push_front) and
73[`push_back`](Polysegment::push_back) just like a [`VecDeque`]. The
74[`extend_front`](Polysegment::extend_front) and
75[`extend_back`](Polysegment::extend_back) methods can be used to implicitly
76add [`LineSegment`]s.
77
78There are multiple constructors available:
79- [`new`](Polysegment::new): A new, empty polysegment with no segment.
80- [`with_capacity`](Polysegment::with_capacity): A new, empty polysegment
81with a defined space for segments preallocated with no segment.
82- [`from_points`](Polysegment::from_points): A polysegment consisting of
83[`LineSegment`]s which connect the given points.
84- [`from_iter`](Polysegment::from_iter): A polysegment consisting of the
85segments given by an iterator. In case two subsequent segments are not
86connected, a "filler" [`LineSegment`] is introduced between them.
87
88# Modifying a polysegment
89
90To uphold the "connection" property, it is not possible to manipulate arbitrary
91segments, which is why methods like [`VecDeque::get_mut`] are missing.
92It is however possible to manipulate the whole polysegment via the
93[`Transformation`] implementation. Additionally, individual segments can be
94removed from the ends of the polysegment with [`pop_front`](Polysegment::pop_front)
95and [`pop_back`](Polysegment::pop_back).
96
97# Access of individual segments
98
99Accessing individual segments is possible via indexing (which panics when
100out-of-bounds) and the [`get`](Polysegment::get) method (which returns `None`
101when out-of-bounds). As in the underlying deque, the segments are not
102necessarily contiguous in memory and can generally only be accessed via two
103slices with the [`as_slices`](Polysegment::as_slices) method. [`Polysegment`]
104does however expose the [`make_contiguous`](Polysegment::make_contiguous) to
105store the segments contiguous in memory.
106
107# Serialization and deserialization
108
109When the `serde` feature is enabled, a polysegment can be serialized and
110deserialized using the [`serde`] crate. It uses the same serialized
111representation as a [`VecDeque`].
112 */
113#[derive(Debug, Clone, PartialEq)]
114#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
115pub struct Polysegment(VecDeque<Segment>);
116
117impl Polysegment {
118    /**
119    Creates an empty [`Polysegment`].
120
121    # Examples
122
123    ```
124    use planar_geo::prelude::Polysegment;
125
126    let polysegment = Polysegment::new();
127    ```
128     */
129    pub fn new() -> Self {
130        return Self(VecDeque::new());
131    }
132
133    /**
134    Creates an empty [`Polysegment`] with space for at least `capacity`
135    [`Segment`].
136
137    # Examples
138
139    ```
140    use planar_geo::prelude::Polysegment;
141
142    let polysegment = Polysegment::with_capacity(10);
143    ```
144     */
145    pub fn with_capacity(capacity: usize) -> Self {
146        return Self(VecDeque::with_capacity(capacity));
147    }
148
149    /**
150    Creates an [`Polysegment`] of [`LineSegment`]s from the given points.
151    If two consecutive points are equal (within the tolerances defined by
152    [`DEFAULT_EPSILON`] and [`DEFAULT_MAX_ULPS`]), they are treated as a single
153    vertex.
154
155    # Examples
156
157    ```
158    use planar_geo::prelude::Polysegment;
159
160    // Three points -> Two line segments
161    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]);
162    assert_eq!(polysegment.len(), 2);
163
164    // Two consecutive points are equal
165    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [0.0, 0.0], [0.0, 1.0]]);
166    assert_eq!(polysegment.len(), 1);
167    ```
168     */
169    pub fn from_points(points: &[[f64; 2]]) -> Self {
170        let mut segments: VecDeque<Segment> = VecDeque::with_capacity(points.len());
171        for window in points.windows(2) {
172            let start = window[0];
173            let stop = window[1];
174            match segments.back() {
175                Some(last_segment) => {
176                    if last_segment.stop() == stop {
177                        continue;
178                    }
179                }
180                None => (),
181            }
182
183            if let Ok(ls) = LineSegment::new(start, stop, DEFAULT_EPSILON, DEFAULT_MAX_ULPS) {
184                segments.push_back(ls.into());
185            }
186        }
187        return Self(segments);
188    }
189
190    /**
191    "Closes" the [`Polysegment`] by connecting the start point of the first /
192    "front" segment with the stop point of the last / "back" segment with a
193    [`LineSegment`] (if the two points aren't already equal).
194
195    # Examples
196
197    ```
198    use planar_geo::prelude::Polysegment;
199
200    // Three points -> Two line segments
201    let mut polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]);
202    assert_eq!(polysegment.len(), 2);
203
204    // Close the polysegment
205    polysegment.close();
206    assert_eq!(polysegment.len(), 3);
207    ```
208     */
209    pub fn close(&mut self) -> () {
210        if let Some(start) = self.0.front() {
211            if let Some(stop) = self.0.back() {
212                if let Ok(ls) = LineSegment::new(
213                    stop.stop(),
214                    start.start(),
215                    DEFAULT_EPSILON,
216                    DEFAULT_MAX_ULPS,
217                ) {
218                    self.0.push_back(ls.into())
219                }
220            }
221        }
222    }
223
224    /**
225    Returns a reference to the underlying [`VecDeque`].
226
227    This allows using all methods of [`VecDeque`] which use a shared reference,
228    e.g. its iterators, accessor methods etc.
229     */
230    pub fn vec_deque(&self) -> &VecDeque<Segment> {
231        return &self.0;
232    }
233
234    /**
235    Calls the [`VecDeque::as_slices`] method of the underlying deque. See its
236    docstring for more.
237     */
238    pub fn as_slices(&self) -> (&[Segment], &[Segment]) {
239        return self.0.as_slices();
240    }
241
242    /**
243    Calls the [`VecDeque::make_contiguous`] method of the underlying deque. See
244    its docstring for more.
245     */
246    pub fn make_contiguous(&mut self) -> &[Segment] {
247        return self.0.make_contiguous();
248    }
249
250    /**
251    Appends a [`Segment`] to the back of the [`Polysegment`].
252
253    If the polysegment already has a "back" segment ([`Polysegment::back`] returns
254    [`Some`]), the start point of `segment` is compared to the stop point of
255    the back segment. If they aren't equal within the tolerances defined by
256    [`DEFAULT_EPSILON`] and [`DEFAULT_MAX_ULPS`], a filler line segment is
257    inserted between the two.
258
259    # Examples
260
261    ```
262    use planar_geo::prelude::*;
263
264    let mut polysegment = Polysegment::new();
265    assert_eq!(polysegment.len(), 0);
266
267    polysegment.push_back(LineSegment::new([0.0, 0.0], [1.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
268    assert_eq!(polysegment.len(), 1);
269
270    // The start point of this segment matches the stop point of the already
271    // inserted segment
272    polysegment.push_back(LineSegment::new([1.0, 0.0], [1.0, 1.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
273    assert_eq!(polysegment.len(), 2);
274
275    // Start and stop point don't match -> A filler segment is introduced
276    polysegment.push_back(LineSegment::new([2.0, 1.0], [2.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
277    assert_eq!(polysegment.len(), 4);
278    ```
279     */
280    pub fn push_back(&mut self, segment: Segment) {
281        let opt_stop = self.back().map(Segment::stop);
282        if let Some(stop) = opt_stop {
283            if let Ok(ls) =
284                LineSegment::new(stop, segment.start(), DEFAULT_EPSILON, DEFAULT_MAX_ULPS)
285            {
286                self.0.push_back(ls.into());
287            }
288        }
289        self.0.push_back(segment);
290    }
291
292    /**
293    Prepends a [`Segment`] to the front of the [`Polysegment`].
294
295    If the polysegment already has a "front" segment ([`Polysegment::front`] returns
296    [`Some`]), the stop point of `segment` is compared to the start point of
297    the front segment. If they aren't equal within the tolerances defined by
298    [`DEFAULT_EPSILON`] and [`DEFAULT_MAX_ULPS`], a filler line segment is
299    inserted between the two.
300
301    # Examples
302
303    ```
304    use planar_geo::prelude::*;
305
306    let mut polysegment = Polysegment::new();
307    assert_eq!(polysegment.len(), 0);
308
309    polysegment.push_front(LineSegment::new([0.0, 0.0], [1.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
310    assert_eq!(polysegment.len(), 1);
311
312    // The stop point of this segment matches the start point of the already
313    // inserted segment
314    polysegment.push_front(LineSegment::new([0.0, 1.0], [0.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
315    assert_eq!(polysegment.len(), 2);
316
317    // Start and stop point don't match -> A filler segment is introduced
318    polysegment.push_front(LineSegment::new([2.0, 1.0], [2.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
319    assert_eq!(polysegment.len(), 4);
320    ```
321     */
322    pub fn push_front(&mut self, segment: Segment) {
323        let opt_start = self.front().map(Segment::start);
324        if let Some(start) = opt_start {
325            if let Ok(ls) =
326                LineSegment::new(segment.stop(), start, DEFAULT_EPSILON, DEFAULT_MAX_ULPS)
327            {
328                self.0.push_front(ls.into());
329            }
330        }
331        self.0.push_front(segment);
332    }
333
334    /**
335    Removes the last / back element from the polysegment and returns it, or [`None`]
336    if it is empty.
337
338    # Examples
339
340    ```
341    use planar_geo::prelude::*;
342
343    let mut polysegment = Polysegment::new();
344
345    let ls: Segment = LineSegment::new([0.0, 0.0], [1.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into();
346
347    polysegment.push_back(ls.clone());
348    assert_eq!(polysegment.len(), 1);
349
350    assert_eq!(polysegment.pop_back(), Some(ls));
351    assert_eq!(polysegment.pop_back(), None);
352     */
353    pub fn pop_back(&mut self) -> Option<Segment> {
354        return self.0.pop_back();
355    }
356
357    /**
358    Removes the first / front element from the polysegment and returns it, or [`None`]
359    if it is empty.
360
361    # Examples
362
363    ```
364    use planar_geo::prelude::*;
365
366    let mut polysegment = Polysegment::new();
367
368    let ls: Segment = LineSegment::new([0.0, 0.0], [1.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into();
369
370    polysegment.push_front(ls.clone());
371    assert_eq!(polysegment.len(), 1);
372
373    assert_eq!(polysegment.pop_front(), Some(ls));
374    assert_eq!(polysegment.pop_front(), None);
375     */
376    pub fn pop_front(&mut self) -> Option<Segment> {
377        return self.0.pop_front();
378    }
379
380    /**
381    Provides a reference to the back element, or [`None`] if the polysegment is empty.
382
383    # Examples
384
385    ```
386    use planar_geo::prelude::*;
387
388    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]);
389    let ls: Segment = LineSegment::new([1.0, 0.0], [0.0, 1.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into();
390
391    assert_eq!(polysegment.back(), Some(&ls));
392    ```
393     */
394    pub fn back(&self) -> Option<&Segment> {
395        return self.0.back();
396    }
397
398    /**
399    Provides a reference to the front element, or [`None`] if the polysegment is empty.
400
401    # Examples
402
403    ```
404    use planar_geo::prelude::*;
405
406    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]);
407    let ls: Segment = LineSegment::new([0.0, 0.0], [1.0, 0.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into();
408
409    assert_eq!(polysegment.front(), Some(&ls));
410     */
411    pub fn front(&self) -> Option<&Segment> {
412        return self.0.front();
413    }
414
415    /**
416    Adds a [`LineSegment`] to the front of `self` which stops at `point` and
417    starts at the current stop point of `self` - i.e., the `stop` point of the
418    [`Segment`] returned from [`Polysegment::back`]. If `self` is empty or
419    `point` is equal to `stop`, this is a no-op.
420
421    # Examples
422
423    ```
424    use planar_geo::prelude::*;
425
426    let mut polysegment = Polysegment::new();
427    assert_eq!(polysegment.len(), 0);
428
429    // No-op, since the polysegment is empty
430    polysegment.extend_back([0.0, 0.0]);
431    assert_eq!(polysegment.len(), 0);
432
433    // Now add a line
434    polysegment.push_back(LineSegment::new([1.0, 0.0], [1.0, 1.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
435    assert_eq!(polysegment.len(), 1);
436
437    // Now adding the point works
438    polysegment.extend_back([0.0, 0.0]);
439    assert_eq!(polysegment.len(), 2);
440    ```
441     */
442    pub fn extend_back(&mut self, point: [f64; 2]) {
443        let endpoint = self.back().map(|s| s.stop());
444        if let Some(endpoint) = endpoint {
445            if let Ok(ls) = LineSegment::new(endpoint, point, DEFAULT_EPSILON, DEFAULT_MAX_ULPS) {
446                self.push_back(ls.into());
447            }
448        }
449    }
450
451    /**
452    Adds a [`LineSegment`] to the front of `self` which starts at `point` and
453    stops at the current start point of `self` - i.e., the `start` point of the
454    [`Segment`] returned from [`Polysegment::front`]. If `self` is empty or
455    `point` is equal to `start`, this is a no-op.
456
457    # Examples
458
459    ```
460    use planar_geo::prelude::*;
461
462    let mut polysegment = Polysegment::new();
463    assert_eq!(polysegment.len(), 0);
464
465    // No-op, since the polysegment is empty
466    polysegment.extend_front([0.0, 0.0]);
467    assert_eq!(polysegment.len(), 0);
468
469    // Now add a line
470    polysegment.push_front(LineSegment::new([1.0, 0.0], [1.0, 1.0], DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into());
471    assert_eq!(polysegment.len(), 1);
472
473    // Now adding the point works
474    polysegment.extend_front([0.0, 0.0]);
475    assert_eq!(polysegment.len(), 2);
476    ```
477     */
478    pub fn extend_front(&mut self, point: [f64; 2]) {
479        let endpoint = self.front().map(|s| s.start());
480        if let Some(endpoint) = endpoint {
481            if let Ok(ls) = LineSegment::new(point, endpoint, DEFAULT_EPSILON, DEFAULT_MAX_ULPS) {
482                self.push_front(ls.into());
483            }
484        }
485    }
486
487    /**
488    Returns whether the polysegment / the underlying [`VecDeque`] is empty or not.
489
490    # Examples
491
492    ```
493     use planar_geo::prelude::*;
494
495    let mut polysegment = Polysegment::new();
496    assert!(polysegment.is_empty());
497
498    polysegment.push_back(LineSegment::new([0.0, 0.0], [1.0, 0.0], 0.0, 0).unwrap().into());
499    assert!(!polysegment.is_empty());
500    ```
501     */
502    pub fn is_empty(&self) -> bool {
503        return self.0.is_empty();
504    }
505
506    /**
507    Provides a reference to the [`Segment`] at the given index.
508
509    The segment at index 0 is the front of the polysegment.
510
511    # Examples
512
513    ```
514     use planar_geo::prelude::*;
515
516    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]);
517    assert!(polysegment.get(0).is_some());
518    assert!(polysegment.get(3).is_none());
519    ```
520     */
521    pub fn get(&self, index: usize) -> Option<&Segment> {
522        return self.0.get(index);
523    }
524
525    /**
526    Returns the number of [`Segment`]s in `self`.
527
528    # Examples
529
530    ```
531    use planar_geo::prelude::*;
532
533    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]);
534    assert_eq!(polysegment.len(), 2);
535    ```
536     */
537    pub fn len(&self) -> usize {
538        return self.0.len();
539    }
540
541    /**
542    Returns a front-to-back iterator over all [`Segment`]s of `self`.
543
544    # Examples
545
546    ```
547    use planar_geo::prelude::*;
548
549    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]);
550    let mut iter = polysegment.segments();
551    assert!(iter.next().is_some());
552    assert!(iter.next().is_some());
553    assert!(iter.next().is_none());
554    ```
555     */
556    pub fn segments(&self) -> std::collections::vec_deque::Iter<'_, Segment> {
557        return self.0.iter();
558    }
559
560    /**
561    Returns a parallel front-to-back iterator over all [`Segment`]s of `self`.
562
563    # Examples
564
565    ```
566    use rayon::prelude::*;
567    use planar_geo::prelude::*;
568
569    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]);
570    let vec: Vec<_> = polysegment.segments_par().collect();
571    assert_eq!(vec.len(), 2);
572    ```
573     */
574    pub fn segments_par(&self) -> rayon::collections::vec_deque::Iter<'_, Segment> {
575        return self.0.par_iter();
576    }
577
578    /**
579    Moves all [`Segment`]s of `other` into `self`, leaving `other` empty.
580
581    If the first point of `other` is not equal to the last point of `self`, a
582    filler line segment is introduced first
583
584    # Panics
585
586    Panics if the new number of elements in `self` overflows an [`usize`].
587
588    # Examples
589
590    ```
591    use planar_geo::prelude::*;
592
593    let mut polysegment1 = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]);
594    let mut polysegment2 = Polysegment::from_points(&[[1.0, 1.0], [0.0, 1.0]]);
595    let mut polysegment3 = Polysegment::from_points(&[[0.0, 2.0], [0.0, 3.0]]);
596
597    assert_eq!(polysegment1.len(), 2);
598    assert_eq!(polysegment2.len(), 1);
599    assert_eq!(polysegment3.len(), 1);
600
601    polysegment1.append(&mut polysegment2);
602    assert_eq!(polysegment1.len(), 3);
603
604    polysegment1.append(&mut polysegment3);
605    assert_eq!(polysegment1.len(), 5);
606    ```
607     */
608    pub fn append(&mut self, other: &mut Polysegment) -> () {
609        if let Some(s) = other.0.front() {
610            let start = s.start();
611            if let Some(s) = self.0.back() {
612                let stop = s.stop();
613                if let Ok(ls) = LineSegment::new(stop, start, DEFAULT_EPSILON, DEFAULT_MAX_ULPS) {
614                    self.0.push_back(ls.into())
615                }
616            }
617        }
618
619        // Append the segments
620        self.0.append(&mut other.0);
621    }
622
623    /**
624    Returns an iterator over all points of the polysegment.
625
626    # Examples
627
628    ```
629    use planar_geo::prelude::*;
630
631    let polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]);
632
633    let mut iter = polysegment.points();
634    assert_eq!(iter.next(), Some([0.0, 0.0]));
635    assert_eq!(iter.next(), Some([1.0, 0.0]));
636    assert_eq!(iter.next(), Some([1.0, 1.0]));
637    assert_eq!(iter.next(), None);
638    ```
639     */
640    pub fn points(&self) -> PointIterator<'_> {
641        return PointIterator::new(self, false, Polygonizer::default());
642    }
643
644    /**
645    Returns the points of a polygon polysegment which approximates `self`. The
646    individual segments are "polygonized" via [`Segment::polygonize`] and
647    an [`SegmentPolygonizer`](crate::segment::SegmentPolygonizer) specified
648    within [`Polygonizer`]. See the docstring of the latter fore more.
649     */
650    pub fn polygonize(&self, polygonizer: Polygonizer) -> PointIterator<'_> {
651        return PointIterator::new(self, false, polygonizer);
652    }
653
654    /**
655    Returns the combined length of all segments of `self`.
656
657    ```
658    use planar_geo::prelude::*;
659    use std::f64::consts::{PI, TAU, SQRT_2};
660
661    // Square with a side length of 1
662    let points = &[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
663    let mut polysegment = Polysegment::from_points(points);
664    polysegment.close();
665    assert_eq!(polysegment.length(), 4.0);
666
667    // Circle with a radius of 1
668    let segment: Segment = ArcSegment::from_center_radius_start_offset_angle([0.0, 0.0], 1.0, 0.0, TAU, DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into();
669    let polysegment = Polysegment::from(segment);
670    assert_eq!(polysegment.length(), TAU);
671
672    // Half-circle segment
673    let segment: Segment = ArcSegment::from_center_radius_start_offset_angle([0.0, 0.0], 1.0, 0.0, PI, DEFAULT_EPSILON, DEFAULT_MAX_ULPS).unwrap().into();
674    let mut polysegment = Polysegment::from(segment);
675    polysegment.close();
676    assert_eq!(polysegment.length(), PI + 2.0);
677
678    // Triangle
679    let points = &[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]];
680    let mut polysegment = Polysegment::from_points(points);
681    polysegment.close();
682    assert_eq!(polysegment.length(), 2.0 + SQRT_2);
683    ```
684     */
685    pub fn length(&self) -> f64 {
686        return self.segments_par().map(|segment| segment.length()).sum();
687    }
688
689    /**
690    Cuts `self` into multiple polysegments by intersecting it with `other` and returns
691    those them.
692
693    The specified tolerances `epsilon` and `max_ulps` are used to determine
694    intersections, see documentation of
695    [`PrimitiveIntersections`](crate::primitive::PrimitiveIntersections).
696
697    # Examples
698
699    ```
700    use planar_geo::prelude::*;
701
702    let points = &[[0.0, 0.0], [2.0, 0.0], [2.0, 2.0], [0.0, 2.0]];
703    let line = Polysegment::from_points(points);
704    let cut = Polysegment::from_points(&[[-1.0, 1.0], [3.0, 1.0]]);
705
706    let separated_lines = line.intersection_cut(&cut, DEFAULT_EPSILON, DEFAULT_MAX_ULPS);
707
708    // This cut results in two separate polysegments
709    assert_eq!(separated_lines.len(), 2);
710    ```
711     */
712    pub fn intersection_cut(
713        &self,
714        other: &Polysegment,
715        epsilon: f64,
716        max_ulps: u32,
717    ) -> Vec<Polysegment> {
718        // Inner helper function
719        fn create_cut_segment(
720            segment: &Segment,
721            start: [f64; 2],
722            stop: [f64; 2],
723            center: [f64; 2],
724            epsilon: f64,
725            max_ulps: u32,
726        ) -> Option<Segment> {
727            // Check to avoid degenerated segments, when start equals stop
728            if !ulps_eq!(start, stop, epsilon = epsilon, max_ulps = max_ulps) {
729                match segment {
730                    Segment::LineSegment(_) => {
731                        if let Ok(ls) = LineSegment::new(start, stop, epsilon, max_ulps) {
732                            return Some(ls.into());
733                        } else {
734                            return None;
735                        }
736                    }
737                    Segment::ArcSegment(_) => {
738                        let normalized_stop = [stop[0] - center[0], stop[1] - center[1]];
739                        let normalized_start = [start[0] - center[0], start[1] - center[1]];
740                        let stop_angle = normalized_stop[1].atan2(normalized_stop[0]);
741                        let start_angle = normalized_start[1].atan2(normalized_start[0]);
742                        let offset_angle = stop_angle - start_angle;
743
744                        if let Ok(arc) = ArcSegment::from_start_center_angle(
745                            start,
746                            center,
747                            offset_angle,
748                            epsilon,
749                            max_ulps,
750                        ) {
751                            return Some(arc.into());
752                        } else {
753                            return None;
754                        }
755                    }
756                };
757            } else {
758                return None;
759            }
760        }
761
762        let mut lines: Vec<Polysegment> = Vec::new();
763        let mut segments_of_current_line: Vec<Segment> = Vec::new();
764
765        // Temporary variables. The values themselves are dummy values to satisfy the
766        // borrow checker.
767        let mut center: [f64; 2] = [0.0, 0.0];
768
769        // Storage for intersections
770        let mut intersections: Vec<[f64; 2]> = Vec::new();
771
772        for segment_self in self.0.iter() {
773            // Preparations for the current segment
774            match segment_self {
775                Segment::LineSegment(_) => (),
776                Segment::ArcSegment(arc) => {
777                    center = arc.center();
778                }
779            }
780
781            // Reset the intersections vector
782            intersections.clear();
783
784            for segment_other in other.0.iter() {
785                let intersections_segment_other =
786                    segment_self.intersections_primitive(segment_other, epsilon, max_ulps);
787                intersections.extend(
788                    intersections_segment_other
789                        .into_iter()
790                        .map::<[f64; 2], _>(From::from),
791                );
792            }
793
794            if intersections.is_empty() {
795                // No intersections could be found -> add segment_self to the list of segments
796                // forming the current line
797                segments_of_current_line.push(segment_self.clone())
798            } else {
799                // Sort the intersections depending on their distance from the start of
800                // segment_self (smalles first)
801                intersections.sort_unstable_by(|a, b| {
802                    let start = segment_self.start();
803
804                    // Calculate the distance of a from segment_self.start and compare it to the
805                    // distance of b from segment_self. Since we are only
806                    // interested in the order, it is not necessary to normalize the distance.
807                    // Do the same for b.
808                    let dist_a = (start[0] - a[0]).powi(2) + (start[1] - a[1]).powi(2);
809                    let dist_b = (start[0] - b[0]).powi(2) + (start[1] - b[1]).powi(2);
810
811                    // When non-comparable values are used (e.g. NaN), the user
812                    // has provided nonsensical values for the segment points
813                    // and the result of the intersection cut will be
814                    // meaningless anyway -> We can return any ordering
815                    dist_a
816                        .partial_cmp(&dist_b)
817                        .unwrap_or(std::cmp::Ordering::Equal)
818                });
819
820                for (idx, intersection) in intersections.iter().enumerate() {
821                    if idx == 0 {
822                        let start = segment_self.start();
823                        let stop = *intersection;
824
825                        if let Some(segment) = create_cut_segment(
826                            &segment_self,
827                            start,
828                            stop,
829                            center,
830                            epsilon,
831                            max_ulps,
832                        ) {
833                            if segments_of_current_line.is_empty() {
834                                lines.push(Polysegment::from(segment));
835                            } else {
836                                let mut polysegment =
837                                    Polysegment::with_capacity(segments_of_current_line.len());
838                                for s in segments_of_current_line.into_iter() {
839                                    polysegment.push_back(s);
840                                }
841                                polysegment.push_back(segment);
842                                lines.push(polysegment);
843                            }
844                        } else {
845                            if !segments_of_current_line.is_empty() {
846                                let mut polysegment =
847                                    Polysegment::with_capacity(segments_of_current_line.len());
848                                for s in segments_of_current_line.into_iter() {
849                                    polysegment.push_back(s);
850                                }
851                                lines.push(polysegment);
852                            }
853                        }
854
855                        // Reinstatiate the vector for the next segment_self
856                        segments_of_current_line = Vec::new();
857                    } else {
858                        // SAFETY: An out-of-bound index is catched by the if idx == 0 above
859                        let start = unsafe { *intersections.get_unchecked(idx - 1) };
860                        let stop = *intersection;
861
862                        // Found some intersections => finish the current line and create a new one
863                        if let Some(segment) = create_cut_segment(
864                            &segment_self,
865                            start,
866                            stop,
867                            center,
868                            epsilon,
869                            max_ulps,
870                        ) {
871                            lines.push(Polysegment::from(segment));
872                        }
873                    };
874                }
875
876                // Populate the "tail end" (the last cut)
877                if let Some(start) = intersections.last() {
878                    if let Some(segment) = create_cut_segment(
879                        &segment_self,
880                        start.clone(),
881                        segment_self.stop(),
882                        center,
883                        epsilon,
884                        max_ulps,
885                    ) {
886                        segments_of_current_line.push(segment);
887                    }
888                }
889            };
890        }
891
892        // Store the last segments as a line into the lines vector
893        let mut polysegment = Polysegment::with_capacity(segments_of_current_line.len());
894        for s in segments_of_current_line.into_iter() {
895            polysegment.push_back(s);
896        }
897        lines.push(polysegment);
898
899        return lines;
900    }
901
902    /**
903    Reverses all [`Segment`]s of the polysegment by switching their start and stop
904    points (see [`Segment::reverse`]). To ensure the "connected" property holds
905    true, the ordering of the segments itself is exchanged as well.
906
907    This method calls [`make_contiguous`](Polysegment::make_contiguous) so all
908    segments are in the first slice before reversing it.
909
910    # Examples
911
912    ```
913    use planar_geo::prelude::*;
914
915    let mut polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]);
916    assert_eq!(polysegment.front().unwrap().start(), [0.0, 0.0]);
917    assert_eq!(polysegment.back().unwrap().stop(), [0.0, 1.0]);
918
919    polysegment.reverse();
920    assert_eq!(polysegment.front().unwrap().start(), [0.0, 1.0]);
921    assert_eq!(polysegment.back().unwrap().stop(), [0.0, 0.0]);
922    ```
923     */
924    pub fn reverse(&mut self) -> () {
925        self.make_contiguous();
926
927        // After making the deque contiguous, the second slice is empty
928        let (slice, _) = self.0.as_mut_slices();
929        for segment in slice.iter_mut() {
930            segment.reverse();
931        }
932        slice.reverse();
933    }
934
935    /**
936    Creates a rotated pattern from `self`. For each one of the specified
937    `repetitions`, the individual segments of `self` are cloned, rotated around
938    `center` and then pushed to the back of `self`. The rotation angle is
939    `angle` times the index of the current repetition plus one.
940
941    # Examples
942
943    ```
944    use planar_geo::prelude::*;
945    use std::f64::consts::FRAC_PI_2;
946
947    let mut polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0]]);
948
949    // 0 repetitions => The original polysegment is left unchanged
950    polysegment.rotational_pattern([1.0, 1.0], FRAC_PI_2, 0);
951    let points: Vec<[f64; 2]> = polysegment.points().collect();
952    assert_eq!(points.len(), 2);
953    approx::assert_abs_diff_eq!(points[0], [0.0, 0.0], epsilon = 1e-10);
954    approx::assert_abs_diff_eq!(points[1], [1.0, 0.0], epsilon = 1e-10);
955
956    // Two repetitions: The points are rotated by 90° and 180° respectively.
957    // The polysegment has 6 points after the extension
958    polysegment.rotational_pattern([1.0, 1.0], FRAC_PI_2, 2);
959    let points: Vec<[f64; 2]> = polysegment.points().collect();
960    assert_eq!(points.len(), 6);
961    approx::assert_abs_diff_eq!(points[0], [0.0, 0.0], epsilon = 1e-10);
962    approx::assert_abs_diff_eq!(points[1], [1.0, 0.0], epsilon = 1e-10);
963    approx::assert_abs_diff_eq!(points[2], [2.0, 0.0], epsilon = 1e-10);
964    approx::assert_abs_diff_eq!(points[3], [2.0, 1.0], epsilon = 1e-10);
965    approx::assert_abs_diff_eq!(points[4], [2.0, 2.0], epsilon = 1e-10);
966    approx::assert_abs_diff_eq!(points[5], [1.0, 2.0], epsilon = 1e-10);
967    ```
968    */
969    pub fn rotational_pattern(&mut self, center: [f64; 2], angle: f64, repetitions: usize) -> () {
970        let num_segments = self.num_segments();
971        for rep in 0..repetitions {
972            for seg_idx in 0..num_segments {
973                // Index is always in bounds, because its maximum value is
974                // the number of segments at the start of the outer loop
975                // and no segments are removed from self.
976                let mut segment = self[seg_idx].clone();
977                segment.rotate(center, angle * (rep as f64 + 1.0));
978                self.push_back(segment);
979            }
980        }
981    }
982
983    /**
984    Creates a translated pattern from `self`. For each one of the specified
985    `repetitions`, the individual segments of `self` are cloned, shifted and
986    then pushed to the back of `self`. The shift vector is `shift` times the
987    index of the current repetition plus one.
988
989    # Examples
990
991    ```
992    use planar_geo::prelude::*;
993    use std::f64::consts::FRAC_PI_2;
994
995    let mut polysegment = Polysegment::from_points(&[[0.0, 0.0], [1.0, 0.0]]);
996
997    // 0 repetitions => The original polysegment is left unchanged
998    polysegment.translational_pattern([1.0, 1.0], 0);
999    let points: Vec<[f64; 2]> = polysegment.points().collect();
1000    assert_eq!(points.len(), 2);
1001    approx::assert_abs_diff_eq!(points[0], [0.0, 0.0], epsilon = 1e-10);
1002    approx::assert_abs_diff_eq!(points[1], [1.0, 0.0], epsilon = 1e-10);
1003
1004    // Two repetitions: A "stair" polysegment is created
1005    polysegment.translational_pattern([1.0, 1.0], 2);
1006    let points: Vec<[f64; 2]> = polysegment.points().collect();
1007    assert_eq!(points.len(), 6);
1008    approx::assert_abs_diff_eq!(points[0], [0.0, 0.0], epsilon = 1e-10);
1009    approx::assert_abs_diff_eq!(points[1], [1.0, 0.0], epsilon = 1e-10);
1010    approx::assert_abs_diff_eq!(points[2], [1.0, 1.0], epsilon = 1e-10);
1011    approx::assert_abs_diff_eq!(points[3], [2.0, 1.0], epsilon = 1e-10);
1012    approx::assert_abs_diff_eq!(points[4], [2.0, 2.0], epsilon = 1e-10);
1013    approx::assert_abs_diff_eq!(points[5], [3.0, 2.0], epsilon = 1e-10);
1014    ```
1015    */
1016    pub fn translational_pattern(&mut self, shift: [f64; 2], repetitions: usize) -> () {
1017        let num_segments = self.num_segments();
1018        for rep in 0..repetitions {
1019            let f = rep as f64 + 1.0; // f for "factor"
1020            for seg_idx in 0..num_segments {
1021                // Index is always in bounds, because its maximum value is
1022                // the number of segments at the start of the outer loop
1023                // and no segments are removed from self.
1024                let mut segment = self[seg_idx].clone();
1025                segment.translate([shift[0] * f, shift[1] * f]);
1026                self.push_back(segment);
1027            }
1028        }
1029    }
1030}
1031
1032impl FromIterator<Segment> for Polysegment {
1033    fn from_iter<T: IntoIterator<Item = Segment>>(iter: T) -> Self {
1034        let mut polysegment = Polysegment::new();
1035        for segment in iter {
1036            polysegment.push_back(segment);
1037        }
1038        return polysegment;
1039    }
1040}
1041
1042impl crate::composite::private::Sealed for Polysegment {}
1043
1044impl Composite for Polysegment {
1045    fn segment(&self, key: SegmentKey) -> Option<&crate::segment::Segment> {
1046        return self.get(key.segment_idx);
1047    }
1048
1049    fn num_segments(&self) -> usize {
1050        return self.len();
1051    }
1052
1053    fn centroid(&self) -> [f64; 2] {
1054        return crate::CentroidData::from(self).into();
1055    }
1056
1057    fn iter<'a>(&'a self) -> impl Iterator<Item = (SegmentKey, &'a crate::segment::Segment)> {
1058        return self
1059            .segments()
1060            .enumerate()
1061            .map(|(i, s)| (SegmentKey::from_segment_idx(i), s));
1062    }
1063
1064    fn par_iter<'a>(
1065        &'a self,
1066    ) -> impl ParallelIterator<Item = (SegmentKey, &'a crate::segment::Segment)> {
1067        return self
1068            .segments_par()
1069            .enumerate()
1070            .map(|(i, s)| (SegmentKey::from_segment_idx(i), s));
1071    }
1072
1073    fn intersections_polysegment<'a>(
1074        &'a self,
1075        other: &'a Self,
1076        epsilon: f64,
1077        max_ulps: u32,
1078    ) -> impl Iterator<Item = Intersection> + 'a {
1079        let same_polysegment_len = if std::ptr::eq(self, other) {
1080            Some(self.num_segments())
1081        } else {
1082            None
1083        };
1084
1085        // Naive implementation: Loop over all segments of segments_self. Check each
1086        // segment of self for an intersection with all segments of
1087        // segments_other.
1088        return other
1089            .0
1090            .iter()
1091            .enumerate()
1092            .flat_map(move |(right_idx, right_seg)| {
1093                intersections_between_polysegment_and_segment_priv(
1094                    self.0.iter(),
1095                    right_idx,
1096                    right_seg,
1097                    same_polysegment_len,
1098                    epsilon,
1099                    max_ulps,
1100                )
1101            });
1102    }
1103
1104    fn intersections_polysegment_par<'a>(
1105        &'a self,
1106        other: &'a Self,
1107        epsilon: f64,
1108        max_ulps: u32,
1109    ) -> impl ParallelIterator<Item = Intersection> + 'a {
1110        let same_polysegment_len = if std::ptr::eq(self, other) {
1111            Some(self.num_segments())
1112        } else {
1113            None
1114        };
1115
1116        // Naive implementation: Loop over all segments of segments_self. Check each
1117        // segment of self for an intersection with all segments of
1118        // segments_other. The outer iteration is done in parallel,
1119        // therefore the intersections are out of order.
1120        return other
1121            .0
1122            .par_iter()
1123            .enumerate()
1124            .flat_map(move |(right_idx, right_seg)| {
1125                intersections_between_polysegment_and_segment_priv_par(
1126                    self.0.par_iter(),
1127                    right_idx,
1128                    right_seg,
1129                    same_polysegment_len,
1130                    epsilon,
1131                    max_ulps,
1132                )
1133            });
1134    }
1135
1136    fn intersections_shape<'a>(
1137        &'a self,
1138        shape: &'a crate::prelude::Shape,
1139        epsilon: f64,
1140        max_ulps: u32,
1141    ) -> impl Iterator<Item = Intersection> {
1142        shape
1143            .intersections_polysegment(self, epsilon, max_ulps)
1144            .map(Intersection::switch)
1145    }
1146
1147    fn intersections_shape_par<'a>(
1148        &'a self,
1149        shape: &'a crate::prelude::Shape,
1150        epsilon: f64,
1151        max_ulps: u32,
1152    ) -> impl ParallelIterator<Item = Intersection> {
1153        shape
1154            .intersections_polysegment_par(self, epsilon, max_ulps)
1155            .map(Intersection::switch)
1156    }
1157
1158    fn intersections_composite<'a, T: Composite>(
1159        &'a self,
1160        other: &'a T,
1161        epsilon: f64,
1162        max_ulps: u32,
1163    ) -> impl Iterator<Item = Intersection> + 'a
1164    where
1165        Self: Sized,
1166    {
1167        return other
1168            .intersections_polysegment(self, epsilon, max_ulps)
1169            .map(Intersection::switch);
1170    }
1171
1172    fn intersections_composite_par<'a, T: Composite>(
1173        &'a self,
1174        other: &'a T,
1175        epsilon: f64,
1176        max_ulps: u32,
1177    ) -> impl ParallelIterator<Item = Intersection> + 'a
1178    where
1179        Self: Sized,
1180    {
1181        return other
1182            .intersections_polysegment_par(self, epsilon, max_ulps)
1183            .map(Intersection::switch);
1184    }
1185
1186    fn covers_point(&self, point: [f64; 2], epsilon: f64, max_ulps: u32) -> bool {
1187        return self
1188            .intersections_primitive(&point, epsilon, max_ulps)
1189            .next()
1190            .is_some();
1191    }
1192
1193    fn covers_segment<'a, T: Into<SegmentRef<'a>>>(
1194        &self,
1195        segment: T,
1196        epsilon: f64,
1197        max_ulps: u32,
1198    ) -> bool {
1199        let segment: SegmentRef = segment.into();
1200        return covers_segment(self.0.iter(), segment, epsilon, max_ulps);
1201    }
1202
1203    fn contains_point(&self, _: [f64; 2], _: f64, _: u32) -> bool {
1204        // A polysegment has no surface area and therefore cannot contain a point.
1205        return false;
1206    }
1207
1208    fn contains_segment<'a, T: Into<SegmentRef<'a>>>(&self, _: T, _: f64, _: u32) -> bool {
1209        return false;
1210    }
1211
1212    fn covers_composite<'a, T: Composite>(
1213        &'a self,
1214        other: &'a T,
1215        epsilon: f64,
1216        max_ulps: u32,
1217    ) -> bool {
1218        return other.covers_polysegment(self, epsilon, max_ulps);
1219    }
1220
1221    fn contains_composite<'a, T: Composite>(
1222        &'a self,
1223        other: &'a T,
1224        epsilon: f64,
1225        max_ulps: u32,
1226    ) -> bool {
1227        return other.contains_polysegment(self, epsilon, max_ulps);
1228    }
1229
1230    fn overlaps_segment<'a, T: Into<SegmentRef<'a>>>(
1231        &self,
1232        _segment: T,
1233        _epsilon: f64,
1234        _max_ulps: u32,
1235    ) -> bool {
1236        return false;
1237    }
1238
1239    fn overlaps_contour(
1240        &self,
1241        _contour: &crate::prelude::Contour,
1242        _epsilon: f64,
1243        _max_ulps: u32,
1244    ) -> bool {
1245        return false;
1246    }
1247
1248    fn overlaps_shape(
1249        &self,
1250        _shape: &crate::prelude::Shape,
1251        _epsilon: f64,
1252        _max_ulps: u32,
1253    ) -> bool {
1254        return false;
1255    }
1256
1257    fn overlaps_composite<'a, T: Composite>(
1258        &'a self,
1259        _other: &'a T,
1260        _epsilon: f64,
1261        _max_ulps: u32,
1262    ) -> bool {
1263        return false;
1264    }
1265}
1266
1267impl std::ops::Index<usize> for Polysegment {
1268    type Output = Segment;
1269
1270    fn index(&self, index: usize) -> &Self::Output {
1271        &self.0[index]
1272    }
1273}
1274
1275impl From<Segment> for Polysegment {
1276    fn from(value: Segment) -> Self {
1277        let mut polysegment = Polysegment::new();
1278        polysegment.push_back(value);
1279        return polysegment;
1280    }
1281}
1282
1283impl From<LineSegment> for Polysegment {
1284    fn from(value: LineSegment) -> Self {
1285        return Polysegment::from(Segment::LineSegment(value));
1286    }
1287}
1288
1289impl From<ArcSegment> for Polysegment {
1290    fn from(value: ArcSegment) -> Self {
1291        return Polysegment::from(Segment::ArcSegment(value));
1292    }
1293}
1294
1295impl crate::Transformation for Polysegment {
1296    fn rotate(&mut self, center: [f64; 2], angle: f64) -> () {
1297        self.0.par_iter_mut().for_each(|segment| {
1298            segment.rotate(center, angle);
1299        })
1300    }
1301
1302    fn translate(&mut self, shift: [f64; 2]) -> () {
1303        self.0.par_iter_mut().for_each(|segment| {
1304            segment.translate(shift);
1305        })
1306    }
1307
1308    fn scale(&mut self, factor: f64) -> () {
1309        self.0.par_iter_mut().for_each(|segment| {
1310            segment.scale(factor);
1311        })
1312    }
1313
1314    fn line_reflection(&mut self, start: [f64; 2], stop: [f64; 2]) -> () {
1315        self.0.par_iter_mut().for_each(|segment| {
1316            segment.line_reflection(start, stop);
1317        })
1318    }
1319}
1320
1321impl ToBoundingBox for Polysegment {
1322    fn bounding_box(&self) -> BoundingBox {
1323        // Use the bounding box of the first segment as a starting point
1324        return self
1325            .segments_par()
1326            .skip(1)
1327            .map(|segment| BoundingBox::from(segment))
1328            .reduce(
1329                || {
1330                    if let Some(s) = self.get(0) {
1331                        BoundingBox::from(s)
1332                    } else {
1333                        BoundingBox::new(0.0, 0.0, 0.0, 0.0)
1334                    }
1335                },
1336                |prev, curr| prev.union(&curr),
1337            );
1338    }
1339}
1340
1341impl IntoIterator for Polysegment {
1342    type Item = Segment;
1343    type IntoIter = std::collections::vec_deque::IntoIter<Segment>;
1344
1345    fn into_iter(self) -> Self::IntoIter {
1346        return self.0.into_iter();
1347    }
1348}
1349
1350impl From<Polysegment> for VecDeque<Segment> {
1351    fn from(line: Polysegment) -> Self {
1352        return line.0;
1353    }
1354}
1355
1356impl From<BoundingBox> for Polysegment {
1357    fn from(bounding_box: BoundingBox) -> Self {
1358        return Self::from(&bounding_box);
1359    }
1360}
1361
1362impl From<&BoundingBox> for Polysegment {
1363    fn from(bounding_box: &BoundingBox) -> Self {
1364        return Polysegment::from_points(&[
1365            [bounding_box.xmin(), bounding_box.ymin()],
1366            [bounding_box.xmax(), bounding_box.ymin()],
1367            [bounding_box.xmax(), bounding_box.ymax()],
1368            [bounding_box.xmin(), bounding_box.ymax()],
1369            [bounding_box.xmin(), bounding_box.ymin()],
1370        ]);
1371    }
1372}
1373
1374impl From<&Polysegment> for crate::CentroidData {
1375    fn from(value: &Polysegment) -> Self {
1376        return value
1377            .segments_par()
1378            .map(|segment| match segment {
1379                Segment::LineSegment(line) => Self::from(line),
1380                Segment::ArcSegment(arc) => Self::from(arc),
1381            })
1382            .reduce(
1383                || Self {
1384                    area: 0.0,
1385                    x: 0.0,
1386                    y: 0.0,
1387                },
1388                |prev, curr| prev.union(&curr),
1389            );
1390    }
1391}
1392
1393/**
1394Calculates the area of a polygon defined by the points given by an iterator.
1395If the polygon orientation is mathematically positive (points are given
1396counterclockwise), then the result is also positive. Otherwise, it is negative.
1397
1398This implementation uses the "Shoelace formula", as e.g. described here:
1399<https://en.wikipedia.org/wiki/Shoelace_formula>.
1400
1401```
1402use planar_geo::polysegment::area_signed;
1403
1404let pt1 = [0.0, 0.0];
1405let pt2 = [1.0, 0.0];
1406let pt3 = [1.0, 1.0];
1407assert_eq!(
1408    area_signed([pt1, pt2, pt3].into_iter()),
1409    0.5
1410);
1411assert_eq!(
1412    area_signed([pt2, pt1, pt3].into_iter()),
1413    -0.5
1414);
1415```
1416 */
1417pub fn area_signed<'a, I>(mut points: I) -> f64
1418where
1419    I: Iterator<Item = [f64; 2]>,
1420{
1421    // Keep the first vertex
1422    let first_vertex = match points.next() {
1423        Some(vertex) => vertex,
1424        None => return 0.0,
1425    };
1426    let mut previous_vertex = first_vertex.clone();
1427
1428    let mut area = 0.0;
1429
1430    // The polysegmented element covers the end value x_n*y_0 - x_0*y_n, where n
1431    // equals the last iterator element
1432    for current_vertex in points.chain(std::iter::once(first_vertex)) {
1433        area += (previous_vertex[1] + current_vertex[1]) * (previous_vertex[0] - current_vertex[0]);
1434        previous_vertex = current_vertex.clone();
1435    }
1436
1437    return 0.5 * area; // Correction factor of 0.5 comes from the area formel of a triangle.
1438}
1439
1440pub(crate) fn covers_segment<'a, 'b, I>(
1441    iterator: I,
1442    segment: SegmentRef<'b>,
1443    epsilon: f64,
1444    max_ulps: u32,
1445) -> bool
1446where
1447    I: Iterator<Item = &'a Segment>,
1448{
1449    match segment {
1450        SegmentRef::LineSegment(line_segment) => {
1451            // Multiple subsequent line segments are combined into a single
1452            // one if they form a single line segment (i.e. their angles are
1453            // identical)
1454            let mut combined: Option<LineSegment> = None;
1455            for seg in iterator {
1456                if let Segment::LineSegment(sl) = seg {
1457                    combined = match combined {
1458                        Some(c) => {
1459                            if ulps_eq!(
1460                                c.angle(),
1461                                sl.angle(),
1462                                epsilon = epsilon,
1463                                max_ulps = max_ulps
1464                            ) {
1465                                // Add the new line segment, if it has the same angle as
1466                                // "combined"
1467                                if let Ok(new_combined) =
1468                                    LineSegment::new(c.start(), sl.stop(), epsilon, max_ulps)
1469                                {
1470                                    if new_combined.covers(line_segment, epsilon, max_ulps) {
1471                                        return true;
1472                                    }
1473                                    Some(new_combined)
1474                                } else {
1475                                    None
1476                                }
1477                            } else {
1478                                // Replace the old combined segment with the new line segment
1479                                if sl.covers(line_segment, epsilon, max_ulps) {
1480                                    return true;
1481                                }
1482                                Some(sl.clone())
1483                            }
1484                        }
1485                        None => {
1486                            if sl.covers(line_segment, epsilon, max_ulps) {
1487                                return true;
1488                            }
1489                            Some(sl.clone())
1490                        }
1491                    };
1492                } else {
1493                    // Arc segment breaks the chain
1494                    combined = None;
1495                }
1496            }
1497            return false;
1498        }
1499        SegmentRef::ArcSegment(arc_segment) => {
1500            // Multiple subsequent arc segments are combined into a single
1501            // one if they form a single arc segment
1502            // (i.e. their radius and center are identical).
1503            let mut combined: Option<ArcSegment> = None;
1504            for seg in iterator {
1505                if let Segment::ArcSegment(sa) = seg {
1506                    combined = match combined {
1507                        Some(c) => {
1508                            if ulps_eq!(
1509                                c.center(),
1510                                sa.center(),
1511                                epsilon = epsilon,
1512                                max_ulps = max_ulps
1513                            ) && ulps_eq!(
1514                                c.radius(),
1515                                sa.radius(),
1516                                epsilon = epsilon,
1517                                max_ulps = max_ulps
1518                            ) {
1519                                // Add the new line segment, if it has the same angle as
1520                                // "combined"
1521                                if let Ok(new_combined) =
1522                                    ArcSegment::from_center_radius_start_offset_angle(
1523                                        c.center(),
1524                                        c.radius(),
1525                                        c.start_angle(),
1526                                        c.offset_angle() + sa.offset_angle(),
1527                                        epsilon,
1528                                        max_ulps,
1529                                    )
1530                                {
1531                                    if new_combined.covers(arc_segment, epsilon, max_ulps) {
1532                                        return true;
1533                                    }
1534                                    Some(new_combined)
1535                                } else {
1536                                    None
1537                                }
1538                            } else {
1539                                // Replace the old combined segment with the new line segment
1540                                if sa.covers(arc_segment, epsilon, max_ulps) {
1541                                    return true;
1542                                }
1543                                Some(sa.clone())
1544                            }
1545                        }
1546                        None => {
1547                            if sa.covers(arc_segment, epsilon, max_ulps) {
1548                                return true;
1549                            }
1550                            Some(sa.clone())
1551                        }
1552                    };
1553                } else {
1554                    // Line segment breaks the chain
1555                    combined = None;
1556                }
1557            }
1558            return false;
1559        }
1560    }
1561}
1562
1563fn intersections_between_polysegment_and_segment_priv<'a, L>(
1564    left: L,
1565    right_idx: usize,
1566    right_seg: &'a Segment,
1567    same_polysegment_len: Option<usize>,
1568    epsilon: f64,
1569    max_ulps: u32,
1570) -> impl Iterator<Item = Intersection> + 'a
1571where
1572    L: Iterator<Item = &'a Segment> + 'a,
1573{
1574    left.enumerate()
1575        .filter_map(move |(left_idx, left_seg)| {
1576            segment_intersections(
1577                left_seg,
1578                left_idx,
1579                right_seg,
1580                right_idx,
1581                same_polysegment_len,
1582                epsilon,
1583                max_ulps,
1584            )
1585        })
1586        .flatten()
1587}
1588
1589fn intersections_between_polysegment_and_segment_priv_par<'a, L>(
1590    left: L,
1591    right_idx: usize,
1592    right_seg: &'a Segment,
1593    same_polysegment_len: Option<usize>,
1594    epsilon: f64,
1595    max_ulps: u32,
1596) -> impl ParallelIterator<Item = Intersection> + 'a
1597where
1598    L: IndexedParallelIterator<Item = &'a Segment> + 'a,
1599{
1600    left.enumerate()
1601        .filter_map(move |(left_idx, left_seg)| {
1602            segment_intersections(
1603                left_seg,
1604                left_idx,
1605                right_seg,
1606                right_idx,
1607                same_polysegment_len,
1608                epsilon,
1609                max_ulps,
1610            )
1611            .map(|iter| iter.par_bridge())
1612        })
1613        .flatten()
1614}
1615
1616fn segment_intersections<'a>(
1617    left_seg: &'a Segment,
1618    left_idx: usize,
1619    right_seg: &'a Segment,
1620    right_idx: usize,
1621    same_polysegment_len: Option<usize>,
1622    epsilon: f64,
1623    max_ulps: u32,
1624) -> Option<impl Iterator<Item = Intersection> + 'a> {
1625    /*
1626    If the two segments are identical, they have no intersection by definition.
1627
1628    If slices_are_identical, an additional optimization is possible:
1629    It is sufficient to only check segments where left_idx < right_idx.
1630    This is possible because a naive loop implementation visits every segment pair twice:
1631    a) Left segment is in the outer loop, right segment is in the inner loop
1632    b) Left segment is in the outer loop, right segment is in the inner loop
1633     */
1634    if same_polysegment_len.is_some() {
1635        if left_idx == right_idx {
1636            return None;
1637        }
1638        if left_idx >= right_idx {
1639            return None;
1640        }
1641    } else {
1642        if left_seg == right_seg {
1643            return None;
1644        }
1645    }
1646
1647    let intersection_iter = left_seg
1648        .intersections_primitive(right_seg, epsilon, max_ulps)
1649        .into_iter()
1650        .filter_map(move |point| {
1651            let point: [f64; 2] = point.into();
1652
1653            /*
1654            If the two slices are identical, check whether left_seg is a
1655            successor / predecessor of right_seg. If yes, filter out the
1656            connection points.
1657             */
1658
1659            if let Some(len) = same_polysegment_len {
1660                /*
1661                This check evaluates whether the left segment is a predecessor
1662                of the right segment. If that is the case, filter out
1663                "intersections" which are actually just the connection point
1664                between the two segments.
1665                 */
1666                if left_idx + 1 == right_idx || (left_idx == 0 && right_idx == len - 1) {
1667                    if approx::ulps_eq!(
1668                        point,
1669                        left_seg.stop(),
1670                        epsilon = epsilon,
1671                        max_ulps = max_ulps
1672                    ) {
1673                        return None;
1674                    }
1675                }
1676            }
1677
1678            Some(Intersection {
1679                point,
1680                left: SegmentKey::from_segment_idx(left_idx),
1681                right: SegmentKey::from_segment_idx(right_idx),
1682            })
1683        });
1684
1685    return Some(intersection_iter);
1686}