use rayon::prelude::ParallelIterator;
use crate::contour::Contour;
use crate::polysegment::Polysegment;
use crate::primitive::Primitive;
use crate::segment::{Segment, SegmentPolygonizer};
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 {
fn segment(&self, key: SegmentKey) -> Option<&crate::segment::Segment>;
fn num_segments(&self) -> usize;
fn centroid(&self) -> [f64; 2];
fn intersections_primitive<'a, T: Primitive>(
&'a self,
primitive: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl Iterator<Item = Intersection> + 'a;
fn intersections_primitive_par<'a, T: Primitive + std::marker::Sync>(
&'a self,
primitive: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a;
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;
fn intersections_contour_par<'a>(
&'a self,
contour: &'a Contour,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a;
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
where
Self: Sized;
fn intersections_composite_par<'a, T: Composite>(
&'a self,
other: &'a T,
epsilon: f64,
max_ulps: u32,
) -> impl ParallelIterator<Item = Intersection> + 'a
where
Self: Sized;
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 contains_point(&self, point: [f64; 2], 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(&self, segment: &Segment, index: usize) -> SegmentPolygonizer {
match self {
Polygonizer::PerType { arc, straight } => match segment {
Segment::LineSegment(_) => return *straight,
Segment::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)
}
}