#[allow(unused_imports)]
use approx::abs_diff_eq;
use boostvoronoi::prelude as BV;
use boostvoronoi::prelude::*;
#[allow(unused_imports)]
use boostvoronoi::try_cast;
#[allow(dead_code)]
pub fn almost_equal(x1: f64, x2: f64, y1: f64, y2: f64) -> bool {
let epsilon = 0.000001;
abs_diff_eq!(x1, x2, epsilon = epsilon) && abs_diff_eq!(y1, y2, epsilon = epsilon)
}
#[cfg(feature = "geo")]
fn geo_line_point_distance<T: geo::GeoFloat>(coord: geo::Coord<T>, line: geo::Line<T>) -> T {
use geo::algorithm::closest_point::ClosestPoint;
use geo::{Closest, Distance, Euclidean};
let point: geo::Point<T> = coord.into();
match line.closest_point(&point) {
Closest::Intersection(c_point) | Closest::SinglePoint(c_point) => {
Euclidean.distance(c_point, point)
}
Closest::Indeterminate => {
unreachable!("Simple line segment should always have a determinate closest point")
}
}
}
#[cfg(feature = "geo")]
fn geo_point_point_distance<T: geo::GeoFloat>(point0: geo::Coord<T>, point1: geo::Coord<T>) -> T {
use geo::{Distance, Euclidean};
Euclidean.distance(point0, point1)
}
#[cfg(feature = "geo")]
#[allow(dead_code)]
pub fn diagram_sanity_check<I: InputType + geo::CoordNum>(
diagram: &Diagram,
points: &[BV::Point<I>],
segments: &[BV::Line<I>],
delta: f64,
) -> Result<(), BvError> {
assert!(delta.is_sign_positive() && delta <= 0.0001);
let coordinates: Vec<_> = points
.iter()
.map(|p| {
Ok(geo::Coord::<f64>::from([
try_cast::<I, f64>(p.x)?,
try_cast::<I, f64>(p.y)?,
]))
})
.collect::<Result<Vec<_>, BvError>>()?;
let lines: Vec<_> = segments
.iter()
.map(|l| {
Ok(geo::Line::<f64>::from([
(
try_cast::<I, f64>(l.start.x)?,
try_cast::<I, f64>(l.start.y)?,
),
(try_cast::<I, f64>(l.end.x)?, try_cast::<I, f64>(l.end.y)?),
]))
})
.collect::<Result<Vec<_>, BvError>>()?;
let mut heap: Vec<f64> = Vec::new();
for v in diagram.vertices().iter() {
let v = geo::Coord::from(v);
for l in lines.iter() {
let distance = geo_line_point_distance(v, *l);
if let Some(peek) = heap.first() {
if distance <= *peek {
if *peek - distance > delta {
heap.clear();
}
} else if distance - *peek > delta {
continue;
}
}
heap.push(distance);
}
for c in coordinates.iter() {
let distance = geo_point_point_distance(v, *c);
if let Some(peek) = heap.first() {
if distance <= *peek {
if *peek - distance > delta {
heap.clear();
}
} else if distance - *peek > delta {
continue;
}
}
heap.push(distance);
}
if heap.len() < 2 {
let err_msg = format!(
"Got a vertex with only one close neighbour: {:?}, dist:{:?}",
v,
heap.first()
);
eprintln!("{}", err_msg);
return Err(BvError::InternalError(err_msg));
}
heap.clear();
}
Ok(())
}
#[allow(dead_code)]
pub fn retrieve_point<T: InputType>(
point_data_: &[Point<T>],
segment_data_: &[Line<T>],
source: (BV::SourceIndex, SourceCategory),
) -> Point<T> {
let source_index: usize = source.0.usize();
match source.1 {
SourceCategory::SinglePoint => point_data_[source_index],
SourceCategory::SegmentStart => segment_data_[source_index - point_data_.len()].start,
SourceCategory::Segment | SourceCategory::SegmentEnd => {
segment_data_[source_index - point_data_.len()].end
}
}
}
#[allow(dead_code)]
pub fn to_points<I: InputType>(points: &[[I; 2]]) -> Vec<Point<I>> {
points.iter().map(|p| p.into()).collect()
}
#[allow(dead_code)]
pub fn to_segments<I: InputType>(segments: &[[I; 4]]) -> Vec<Line<I>> {
segments.iter().map(|l| l.into()).collect()
}