use rayon::prelude::*;
use crate::contour::Contour;
use crate::polysegment::Polysegment;
use crate::primitive::Primitive;
use crate::segment::{Segment, SegmentPolygonizer, SegmentRef};
use crate::shape::Shape;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct SegmentKey {
pub contour_idx: usize,
pub segment_idx: usize,
}
impl SegmentKey {
pub fn new(contour_idx: usize, segment_idx: usize) -> Self {
return Self {
contour_idx,
segment_idx,
};
}
pub fn from_segment_idx(segment_idx: usize) -> Self {
return Self {
contour_idx: 0,
segment_idx,
};
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Intersection {
pub point: [f64; 2],
pub left: SegmentKey,
pub right: SegmentKey,
}
impl Intersection {
pub fn switch(self) -> Intersection {
Intersection {
point: self.point,
left: self.right,
right: self.left,
}
}
}
impl From<Intersection> for [f64; 2] {
fn from(value: Intersection) -> Self {
value.point
}
}
impl From<[f64; 2]> for Intersection {
fn from(value: [f64; 2]) -> Self {
Intersection {
point: value,
left: Default::default(),
right: Default::default(),
}
}
}
impl approx::AbsDiffEq for Intersection {
type Epsilon = f64;
fn default_epsilon() -> f64 {
f64::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: f64) -> bool {
return self.point.abs_diff_eq(&other.point, epsilon)
&& self.left == other.left
&& self.right == other.right;
}
}
impl approx::RelativeEq for Intersection {
fn default_max_relative() -> f64 {
f64::default_max_relative()
}
fn relative_eq(&self, other: &Self, epsilon: f64, max_relative: f64) -> bool {
return self.point.relative_eq(&other.point, epsilon, max_relative)
&& self.left == other.left
&& self.right == other.right;
}
}
impl approx::UlpsEq for Intersection {
fn default_max_ulps() -> u32 {
f64::default_max_ulps()
}
fn ulps_eq(&self, other: &Self, epsilon: f64, max_ulps: u32) -> bool {
return self.point.ulps_eq(&other.point, epsilon, max_ulps)
&& self.left == other.left
&& self.right == other.right;
}
}
impl Default for Intersection {
fn default() -> Self {
Self {
point: Default::default(),
left: Default::default(),
right: Default::default(),
}
}
}
pub(crate) mod private {
pub trait Sealed {}
}
pub trait Composite: private::Sealed + Sync {
fn segment(&self, key: SegmentKey) -> Option<&Segment>;
fn iter<'a>(&'a self) -> impl Iterator<Item = (SegmentKey, &'a Segment)>;
fn par_iter<'a>(&'a self) -> impl ParallelIterator<Item = (SegmentKey, &'a Segment)>;
fn num_segments(&self) -> usize;
fn centroid(&self) -> [f64; 2];
fn contains_point(&self, point: [f64; 2], epsilon: f64, max_ulps: u32) -> bool;
fn contains_segment<'a, T: Into<SegmentRef<'a>>>(
&self,
segment: T,
epsilon: f64,
max_ulps: u32,
) -> bool;
fn contains_polysegment(&self, polysegment: &Polysegment, epsilon: f64, max_ulps: u32) -> bool {
return polysegment
.segments_par()
.all(|s| self.contains_segment(s, epsilon, max_ulps));
}
fn contains_contour(&self, contour: &Contour, epsilon: f64, max_ulps: u32) -> bool {
return self.contains_polysegment(contour.polysegment(), epsilon, max_ulps);
}
fn contains_shape(&self, shape: &Shape, epsilon: f64, max_ulps: u32) -> bool {
return self.contains_contour(shape.contour(), epsilon, max_ulps);
}
fn contains_composite<'a, T: Composite>(
&'a self,
other: &'a T,
epsilon: f64,
max_ulps: u32,
) -> bool;
fn covers_point(&self, point: [f64; 2], epsilon: f64, max_ulps: u32) -> bool;
fn covers_segment<'a, T: Into<SegmentRef<'a>>>(
&self,
segment: T,
epsilon: f64,
max_ulps: u32,
) -> bool;
fn covers_polysegment(&self, polysegment: &Polysegment, epsilon: f64, max_ulps: u32) -> bool {
return polysegment
.segments_par()
.all(|s| self.covers_segment(s, epsilon, max_ulps));
}
fn covers_contour(&self, contour: &Contour, epsilon: f64, max_ulps: u32) -> bool {
return self.covers_polysegment(contour.polysegment(), epsilon, max_ulps);
}
fn covers_shape(&self, shape: &Shape, epsilon: f64, max_ulps: u32) -> bool {
return self.covers_contour(shape.contour(), epsilon, max_ulps);
}
fn covers_composite<'a, T: Composite + Sync>(
&'a self,
other: &'a T,
epsilon: f64,
max_ulps: u32,
) -> bool;
fn intersections_primitive<'a, T: Primitive>(
&'a self,
primitive: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl Iterator<Item = Intersection> + 'a {
self.iter()
.map(move |(k, s)| {
s.intersections_primitive(primitive, epsilon, max_ulps)
.into_iter()
.map(move |point| Intersection {
point,
left: k,
right: Default::default(),
})
})
.flatten()
}
fn intersections_primitive_par<'a, T: Primitive>(
&'a self,
primitive: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a {
self.par_iter()
.map(move |(k, s)| {
s.intersections_primitive(primitive, epsilon, max_ulps)
.into_iter()
.par_bridge()
.map(move |point| Intersection {
point,
left: k,
right: Default::default(),
})
})
.flatten()
}
fn intersections_polysegment<'a>(
&'a self,
polysegment: &'a Polysegment,
epsilon: f64,
max_ulps: u32,
) -> impl Iterator<Item = Intersection> + 'a;
fn intersections_polysegment_par<'a>(
&'a self,
polysegment: &'a Polysegment,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a;
fn intersections_contour<'a>(
&'a self,
contour: &'a Contour,
epsilon: f64,
max_ulps: u32,
) -> impl Iterator<Item = Intersection> + 'a {
self.intersections_polysegment(contour.polysegment(), epsilon, max_ulps)
}
fn intersections_contour_par<'a>(
&'a self,
contour: &'a Contour,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a {
self.intersections_polysegment_par(contour.polysegment(), epsilon, max_ulps)
}
fn intersections_shape<'a>(
&'a self,
shape: &'a Shape,
epsilon: f64,
max_ulps: u32,
) -> impl Iterator<Item = Intersection> + 'a;
fn intersections_shape_par<'a>(
&'a self,
shape: &'a Shape,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a;
fn intersections_composite<'a, T: Composite>(
&'a self,
other: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl Iterator<Item = Intersection> + 'a;
fn intersections_composite_par<'a, T: Composite>(
&'a self,
other: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a;
fn intersections<'a, T: Into<crate::geometry::GeometryRef<'a>>>(
&self,
other: T,
epsilon: f64,
max_ulps: u32,
) -> Vec<Intersection>
where
Self: Sized,
{
let geo_ref: crate::geometry::GeometryRef = other.into();
return geo_ref.intersections_composite(self, epsilon, max_ulps);
}
fn intersections_par<'a, T: Into<crate::geometry::GeometryRef<'a>>>(
&self,
other: T,
epsilon: f64,
max_ulps: u32,
) -> Vec<Intersection>
where
Self: Sized,
{
let geo_ref: crate::geometry::GeometryRef = other.into();
return geo_ref.intersections_composite_par(self, epsilon, max_ulps);
}
fn overlaps_point(&self, point: [f64; 2], epsilon: f64, max_ulps: u32) -> bool {
self.contains_point(point, epsilon, max_ulps)
}
fn overlaps_segment<'a, T: Into<SegmentRef<'a>>>(
&self,
segment: T,
epsilon: f64,
max_ulps: u32,
) -> bool;
fn overlaps_polysegment(&self, polysegment: &Polysegment, epsilon: f64, max_ulps: u32) -> bool {
polysegment
.segments_par()
.any(|s| self.overlaps_segment(s, epsilon, max_ulps))
}
fn overlaps_contour(&self, contour: &Contour, epsilon: f64, max_ulps: u32) -> bool;
fn overlaps_shape(&self, shape: &Shape, epsilon: f64, max_ulps: u32) -> bool;
fn overlaps_composite<'a, T: Composite>(
&'a self,
other: &'a T,
epsilon: f64,
max_ulps: u32,
) -> bool;
}
#[derive(Debug, Clone)]
pub enum Polygonizer {
PerType {
arc: SegmentPolygonizer,
straight: SegmentPolygonizer,
},
Individual {
default: SegmentPolygonizer,
map: std::collections::HashMap<usize, SegmentPolygonizer>,
},
}
impl Polygonizer {
pub fn segment_polygonizer<'a, T>(&self, segment: T, index: usize) -> SegmentPolygonizer
where
T: Into<SegmentRef<'a>>,
{
let segment: SegmentRef = segment.into();
match self {
Polygonizer::PerType { arc, straight } => match segment {
SegmentRef::LineSegment(_) => return *straight,
SegmentRef::ArcSegment(_) => return *arc,
},
Polygonizer::Individual { default, map } => return *map.get(&index).unwrap_or(default),
};
}
}
impl Default for Polygonizer {
fn default() -> Self {
return Polygonizer::PerType {
arc: SegmentPolygonizer::default(),
straight: SegmentPolygonizer::default(),
};
}
}
#[derive(Clone, Debug)]
pub struct PointIterator<'a> {
polysegment: &'a Polysegment,
index: usize,
skip_last_vertex: bool,
polygonizer: Polygonizer,
sub_iterator: Option<crate::segment::PolygonPointsIterator<'a>>,
}
impl<'a> PointIterator<'a> {
pub(crate) fn new(
polysegment: &'a Polysegment,
skip_last_vertex: bool,
polygonizer: Polygonizer,
) -> Self {
let sub_iterator = polysegment.front().map(|first_segment| {
let sub_polygonizer = polygonizer.segment_polygonizer(first_segment, 0);
first_segment.polygonize(sub_polygonizer)
});
return Self {
polysegment,
index: 0,
skip_last_vertex,
polygonizer,
sub_iterator,
};
}
}
impl<'a> Iterator for PointIterator<'a> {
type Item = [f64; 2];
fn next(&mut self) -> Option<[f64; 2]> {
match self.sub_iterator.as_mut()?.next() {
Some(pt) => return Some(pt),
None => {
self.index += 1;
let segment = match self.polysegment.get(self.index) {
Some(s) => s,
None => {
self.sub_iterator = None;
return None;
}
};
let sub_polygonizer = self.polygonizer.segment_polygonizer(segment, self.index);
let mut sub_iterator = segment.polygonize(sub_polygonizer);
sub_iterator.start_at_second_point();
if self.index + 1 == self.polysegment.len() && self.skip_last_vertex {
sub_iterator.skip_last_vertex();
}
self.sub_iterator = Some(sub_iterator);
return self.next();
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let length = self.polysegment.len();
(length, None)
}
}