use geo_types::{MultiLineString, MultiPolygon};
use crate::{CoordsIter, GeoFloat, GeoNum, Polygon};
pub trait BooleanOps: Sized {
type Scalar: GeoNum;
fn boolean_op(&self, other: &Self, op: OpType) -> MultiPolygon<Self::Scalar>;
fn intersection(&self, other: &Self) -> MultiPolygon<Self::Scalar> {
self.boolean_op(other, OpType::Intersection)
}
fn union(&self, other: &Self) -> MultiPolygon<Self::Scalar> {
self.boolean_op(other, OpType::Union)
}
fn xor(&self, other: &Self) -> MultiPolygon<Self::Scalar> {
self.boolean_op(other, OpType::Xor)
}
fn difference(&self, other: &Self) -> MultiPolygon<Self::Scalar> {
self.boolean_op(other, OpType::Difference)
}
fn clip(
&self,
ls: &MultiLineString<Self::Scalar>,
invert: bool,
) -> MultiLineString<Self::Scalar>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum OpType {
Intersection,
Union,
Difference,
Xor,
}
impl<T: GeoFloat> BooleanOps for Polygon<T> {
type Scalar = T;
fn boolean_op(&self, other: &Self, op: OpType) -> MultiPolygon<Self::Scalar> {
let spec = BoolOp::from(op);
let mut bop = Proc::new(spec, self.coords_count() + other.coords_count());
bop.add_polygon(self, 0);
bop.add_polygon(other, 1);
bop.sweep()
}
fn clip(
&self,
ls: &MultiLineString<Self::Scalar>,
invert: bool,
) -> MultiLineString<Self::Scalar> {
let spec = ClipOp::new(invert);
let mut bop = Proc::new(spec, self.coords_count() + ls.coords_count());
bop.add_polygon(self, 0);
ls.0.iter().enumerate().for_each(|(idx, l)| {
bop.add_line_string(l, idx + 1);
});
bop.sweep()
}
}
impl<T: GeoFloat> BooleanOps for MultiPolygon<T> {
type Scalar = T;
fn boolean_op(&self, other: &Self, op: OpType) -> MultiPolygon<Self::Scalar> {
let spec = BoolOp::from(op);
let mut bop = Proc::new(spec, self.coords_count() + other.coords_count());
bop.add_multi_polygon(self, 0);
bop.add_multi_polygon(other, 1);
bop.sweep()
}
fn clip(
&self,
ls: &MultiLineString<Self::Scalar>,
invert: bool,
) -> MultiLineString<Self::Scalar> {
let spec = ClipOp::new(invert);
let mut bop = Proc::new(spec, self.coords_count() + ls.coords_count());
bop.add_multi_polygon(self, 0);
ls.0.iter().enumerate().for_each(|(idx, l)| {
bop.add_line_string(l, idx + 1);
});
bop.sweep()
}
}
mod op;
use op::*;
mod assembly;
use assembly::*;
mod spec;
use spec::*;
#[cfg(test)]
mod tests;