use std::cmp::Ordering;
use crate::operations::Orient;
use crate::oriented::Orientation;
use crate::traits::Elemental;
use super::event::Event;
pub(super) struct SweepLineKey<Point> {
pub(super) event: Event,
endpoints: *const Vec<Point>,
opposites: *const Vec<Event>,
}
impl<Point> SweepLineKey<Point> {
pub(super) fn new(
event: Event,
endpoints: &Vec<Point>,
opposites: &Vec<Event>,
) -> Self {
Self {
event,
endpoints,
opposites,
}
}
}
impl<Point> SweepLineKey<Point> {
fn get_endpoints(&self) -> &[Point] {
unsafe { &(*self.endpoints) }
}
fn get_opposites(&self) -> &[Event] {
unsafe { &(*self.opposites) }
}
}
impl<Point: PartialEq> PartialEq for SweepLineKey<Point> {
fn eq(&self, other: &Self) -> bool {
self.event == other.event
}
}
impl<Point: Eq> Eq for SweepLineKey<Point> {}
impl<Scalar: Ord, Point> PartialOrd for SweepLineKey<Point>
where
Self: PartialEq,
for<'a> &'a Point: Elemental<Coordinate = &'a Scalar> + Orient,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(compare_sweep_line_keys(
self.event,
other.event,
self.get_endpoints(),
self.get_opposites(),
))
}
}
impl<Scalar: Ord, Point> Ord for SweepLineKey<Point>
where
Self: Eq + PartialOrd,
for<'a> &'a Point: Elemental<Coordinate = &'a Scalar> + Orient,
{
fn cmp(&self, other: &Self) -> Ordering {
compare_sweep_line_keys(
self.event,
other.event,
self.get_endpoints(),
self.get_opposites(),
)
}
}
fn compare_sweep_line_keys<Scalar: Ord, Point>(
left_event: Event,
right_event: Event,
endpoints: &[Point],
opposites: &[Event],
) -> Ordering
where
for<'a> &'a Point: Elemental<Coordinate = &'a Scalar> + Orient,
{
compare_segments_position(
&endpoints[left_event],
&endpoints[opposites[left_event]],
&endpoints[right_event],
&endpoints[opposites[right_event]],
)
}
fn compare_segments_position<Scalar: Ord, Point>(
first_start: &Point,
first_end: &Point,
second_start: &Point,
second_end: &Point,
) -> Ordering
where
for<'a> &'a Point: Elemental<Coordinate = &'a Scalar> + Orient,
{
let other_start_orientation = first_start.orient(first_end, second_start);
let other_end_orientation = first_start.orient(first_end, second_end);
if other_start_orientation == other_end_orientation {
match other_start_orientation {
Orientation::Collinear => match first_start
.y()
.cmp(second_start.y())
{
Ordering::Equal => match first_start.x().cmp(second_start.x())
{
Ordering::Equal => match first_end.y().cmp(second_end.y())
{
Ordering::Equal => first_end.x().cmp(second_end.x()),
value => value,
},
value => value,
},
value => value,
},
Orientation::Clockwise => Ordering::Greater,
Orientation::Counterclockwise => Ordering::Less,
}
} else {
let start_orientation = second_start.orient(second_end, first_start);
let end_orientation = second_start.orient(second_end, first_end);
if start_orientation == end_orientation {
match start_orientation {
Orientation::Clockwise => Ordering::Less,
_ => Ordering::Greater,
}
} else if other_start_orientation == Orientation::Collinear {
match other_end_orientation {
Orientation::Counterclockwise => Ordering::Less,
_ => Ordering::Greater,
}
} else if start_orientation == Orientation::Collinear {
match end_orientation {
Orientation::Clockwise => Ordering::Less,
_ => Ordering::Greater,
}
} else if end_orientation == Orientation::Collinear {
match start_orientation {
Orientation::Clockwise => Ordering::Less,
_ => Ordering::Greater,
}
} else {
match other_start_orientation {
Orientation::Counterclockwise => Ordering::Less,
_ => Ordering::Greater,
}
}
}
}