use geometry_coords::CoordinateScalar;
use geometry_trait::Point;
pub const SAFE_ABS_MAX: f64 = 67_108_864.0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RangeError {
pub point_index: usize,
pub dimension: usize,
}
impl core::fmt::Display for RangeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"coordinate at point {} dimension {} exceeds the safe overlay range (±{SAFE_ABS_MAX})",
self.point_index, self.dimension
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for RangeError {}
#[must_use]
pub fn coordinate_in_range<P>(p: &P) -> bool
where
P: Point,
P::Scalar: CoordinateScalar + Into<f64>,
{
let x: f64 = p.get::<0>().into();
let y: f64 = p.get::<1>().into();
x.abs() <= SAFE_ABS_MAX && y.abs() <= SAFE_ABS_MAX
}
#[must_use]
pub fn polygon_in_range<G, P>(polygon: &G) -> bool
where
G: geometry_trait::Polygon<Point = P>,
P: Point,
P::Scalar: CoordinateScalar + Into<f64>,
{
use geometry_trait::Ring as _;
polygon.exterior().points().all(coordinate_in_range)
&& polygon
.interiors()
.all(|r| r.points().all(coordinate_in_range))
}
#[cfg(test)]
mod tests {
use super::{RangeError, SAFE_ABS_MAX, coordinate_in_range};
use geometry_cs::Cartesian;
use geometry_model::Point2D;
type P = Point2D<f64, Cartesian>;
#[test]
fn in_range_ok() {
assert!(coordinate_in_range(&P::new(0.0, 0.0)));
assert!(coordinate_in_range(&P::new(SAFE_ABS_MAX, -SAFE_ABS_MAX)));
assert!(coordinate_in_range(&P::new(1.0e6, 3.0e6)));
}
#[test]
fn out_of_range_rejected() {
assert!(!coordinate_in_range(&P::new(SAFE_ABS_MAX + 1.0, 0.0)));
assert!(!coordinate_in_range(&P::new(0.0, -SAFE_ABS_MAX * 4.0)));
assert!(!coordinate_in_range(&P::new(f64::MAX, 0.0)));
}
#[test]
fn range_error_display_mentions_index_and_dim() {
let e = RangeError {
point_index: 2,
dimension: 1,
};
let s = alloc_display(&e);
assert!(s.contains("point 2"));
assert!(s.contains("dimension 1"));
}
#[cfg(feature = "std")]
fn alloc_display(e: &RangeError) -> String {
e.to_string()
}
#[cfg(not(feature = "std"))]
fn alloc_display(_e: &RangeError) -> &'static str {
"point 2 dimension 1"
}
}