#![cfg_attr(feature = "doc-images",
cfg_attr(all(),
doc = ::embed_doc_image::embed_image!("type_overview.svg", "docs/img/type_overview.svg"),
doc = ::embed_doc_image::embed_image!("shape.svg", "docs/img/shape.svg"),
doc = ::embed_doc_image::embed_image!("intersection_segments.svg", "docs/img/intersection_segments.svg"),
doc = ::embed_doc_image::embed_image!("intersection_composites.svg", "docs/img/intersection_composites.svg"),
))]
#![cfg_attr(
not(feature = "doc-images"),
doc = "**Doc images not enabled**. Compile docs with `cargo doc --features 'doc-images'` and Rust version >= 1.54."
)]
#![doc = include_str!("../docs/main.md")]
#![deny(missing_docs)]
use bounding_box::BoundingBox;
pub const DEFAULT_EPSILON: f64 = 0.000000014901161193847656_f64;
pub const DEFAULT_MAX_ULPS: u32 = 4;
pub mod error;
pub mod prelude;
pub mod line;
pub mod primitive;
pub mod segment;
pub mod composite;
pub mod contour;
pub mod polysegment;
pub mod shape;
pub mod geometry;
#[cfg(feature = "cairo")]
pub mod draw;
pub trait Transformation {
fn translate(&mut self, shift: [f64; 2]);
fn rotate(&mut self, center: [f64; 2], angle: f64);
fn scale(&mut self, factor: f64);
fn line_reflection(&mut self, start: [f64; 2], stop: [f64; 2]) -> ();
fn point_reflection(&mut self, point: [f64; 2]) -> () {
self.rotate(point, std::f64::consts::PI);
}
}
impl Transformation for [f64; 2] {
fn translate(&mut self, shift: [f64; 2]) {
*self = [self[0] + shift[0], self[1] + shift[1]];
}
fn rotate(&mut self, center: [f64; 2], angle: f64) {
let t = Rotation2::new(angle);
let pt = [self[0] - center[0], self[1] - center[1]];
let mut p = t * pt;
p.translate([center[0], center[1]]);
*self = p;
}
fn scale(&mut self, factor: f64) {
*self = [self[0] * factor, self[1] * factor];
}
fn line_reflection(&mut self, start: [f64; 2], stop: [f64; 2]) -> () {
if start[0] == stop[0] {
*self = [-self[0] + 2.0 * start[0], self[1]];
} else if start[1] == stop[1] {
*self = [self[0], -self[1] + 2.0 * start[1]];
} else {
let m = (stop[1] - start[1]) / (stop[0] - start[0]);
let c = (stop[0] * start[1] - start[0] * stop[1]) / (stop[0] - start[0]);
let d = (self[0] + (self[1] - c) * m) / (1.0 + m.powi(2));
*self = [2.0 * d - self[0], 2.0 * d * m - self[1] + 2.0 * c];
}
}
}
impl Transformation for BoundingBox {
fn translate(&mut self, shift: [f64; 2]) {
BoundingBox::translate(self, shift);
}
fn rotate(&mut self, center: [f64; 2], angle: f64) {
let mut ll = [self.xmin(), self.ymin()];
let mut ul = [self.xmin(), self.xmax()];
let mut lr = [self.xmax(), self.ymin()];
let mut ur = [self.xmax(), self.xmax()];
ll.rotate(center, angle);
ul.rotate(center, angle);
lr.rotate(center, angle);
ur.rotate(center, angle);
*self = BoundingBox::from_points([ll, ul, lr, ur].into_iter())
.expect("supplied more than zero points")
}
fn scale(&mut self, factor: f64) {
BoundingBox::scale(self, factor);
}
fn line_reflection(&mut self, start: [f64; 2], stop: [f64; 2]) -> () {
let mut ll = [self.xmin(), self.ymin()];
let mut ul = [self.xmin(), self.xmax()];
let mut lr = [self.xmax(), self.ymin()];
let mut ur = [self.xmax(), self.xmax()];
ll.line_reflection(start, stop);
ul.line_reflection(start, stop);
lr.line_reflection(start, stop);
ur.line_reflection(start, stop);
*self = BoundingBox::from_points([ll, ul, lr, ur].into_iter())
.expect("supplied more than zero points")
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CentroidData {
pub(crate) area: f64,
pub(crate) x: f64,
pub(crate) y: f64,
}
impl CentroidData {
pub(crate) fn union(&self, other: &Self) -> Self {
let area = self.area + other.area;
if area == 0.0 {
let x = 0.0;
let y = 0.0;
return Self { area, x, y };
} else {
let x = (self.area * self.x + other.area * other.x) / area;
let y = (self.area * self.y + other.area * other.y) / area;
return Self { area, x, y };
}
}
pub(crate) fn subtract(&self, other: &Self) -> Self {
let area = self.area - other.area;
if area == 0.0 {
let x = 0.0;
let y = 0.0;
return Self { area, x, y };
} else {
let x = (self.area * self.x - other.area * other.x) / area;
let y = (self.area * self.y - other.area * other.y) / area;
return Self { area, x, y };
}
}
}
impl From<CentroidData> for [f64; 2] {
fn from(value: CentroidData) -> Self {
return [value.x, value.y];
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Rotation2 {
sin: f64,
cos: f64,
}
impl Rotation2 {
pub(crate) fn new(angle: f64) -> Self {
return Self {
sin: angle.sin(),
cos: angle.cos(),
};
}
}
impl std::ops::Mul<[f64; 2]> for Rotation2 {
type Output = [f64; 2];
fn mul(self, rhs: [f64; 2]) -> Self::Output {
return [
rhs[0] * self.cos - rhs[1] * self.sin,
rhs[0] * self.sin + rhs[1] * self.cos,
];
}
}