i_overlay 7.0.2

Boolean Operations for 2D Polygons: Supports intersection, union, difference, xor, and self-intersections for all polygon varieties.
Documentation
use crate::core::edge_data::OverlayEdgeData;
use crate::core::solver::Solver;
use crate::geom::line_range::LineRange;
use crate::geom::x_segment::XSegment;
use crate::segm::segment::Segment;
use crate::segm::winding::WindingCount;
use crate::split::snap_radius::SnapRadius;
use crate::split::solver::SplitSolver;
use alloc::vec::Vec;
use i_float::int::number::int::IntNumber;
use i_key_sort::sort::key::SortKey;
use i_tree::ExpiredVal;
use i_tree::seg::exp::{SegExpCollection, SegRange};
use i_tree::seg::tree::SegExpTree;
use i_tree::{Expiration, LayoutNumber};

#[derive(Clone, Copy)]
struct IdSegment<I: IntNumber> {
    id: usize,
    x_segment: XSegment<I>,
}

impl<I: IntNumber + Expiration> ExpiredVal<I> for IdSegment<I> {
    #[inline]
    fn expiration(&self) -> I {
        self.x_segment.b.x
    }
}

impl<I> SplitSolver<I>
where
    I: IntNumber + Expiration + LayoutNumber + SortKey,
{
    pub(super) fn tree_split<C: WindingCount, D: OverlayEdgeData<C>>(
        &mut self,
        snap_radius: SnapRadius,
        segments: &mut Vec<Segment<C, I, D>>,
        solver: &Solver,
        store: &mut D::Store,
    ) -> bool {
        let range: SegRange<I> = if let Some(range) = segments.ver_range() {
            range.into()
        } else {
            return false;
        };
        let mut tree: SegExpTree<I, I, IdSegment<I>> = if let Some(tree) = SegExpTree::new(range) {
            tree
        } else {
            return self.list_split(snap_radius, segments, solver, store);
        };

        let mut reusable_buffer = Vec::new();

        let mut need_to_fix = true;
        let mut any_intersection = false;

        let mut snap_radius = snap_radius;

        while need_to_fix && segments.len() > 2 {
            need_to_fix = false;
            self.marks.clear();

            let radius = snap_radius.radius::<I>();

            for (i, si) in segments.iter().enumerate() {
                let time = si.x_segment.a.x;
                let si_range = si.x_segment.y_range().into();
                for sj in tree.iter_by_range(si_range, time) {
                    let (this_index, scan_index, this, scan) = if si.x_segment < sj.x_segment {
                        (i, sj.id, &si.x_segment, &sj.x_segment)
                    } else {
                        (sj.id, i, &sj.x_segment, &si.x_segment)
                    };

                    let is_round = Self::cross(this_index, scan_index, this, scan, &mut self.marks, radius);

                    need_to_fix = is_round || need_to_fix;
                }

                tree.insert_by_range(si_range, si.id_segment(i));
            }

            if self.marks.is_empty() {
                return any_intersection;
            }

            any_intersection = true;
            tree.clear();

            self.apply(segments, &mut reusable_buffer, solver, store);

            snap_radius.increment();
        }

        any_intersection
    }
}

impl<I: IntNumber> From<LineRange<I>> for SegRange<I> {
    #[inline]
    fn from(value: LineRange<I>) -> Self {
        Self {
            min: value.min,
            max: value.max,
        }
    }
}

trait VerticalRange {
    type Int: IntNumber;

    fn ver_range(&self) -> Option<LineRange<Self::Int>>;
}

impl<I: IntNumber, C: Send, D: Send> VerticalRange for Vec<Segment<C, I, D>> {
    type Int = I;

    fn ver_range(&self) -> Option<LineRange<I>> {
        let mut min_y = self.first()?.x_segment.a.y;
        let mut max_y = min_y;

        for edge in self.iter() {
            min_y = min_y.min(edge.x_segment.a.y);
            max_y = max_y.max(edge.x_segment.a.y);
            min_y = min_y.min(edge.x_segment.b.y);
            max_y = max_y.max(edge.x_segment.b.y);
        }

        Some(LineRange {
            min: min_y,
            max: max_y,
        })
    }
}

impl<I: IntNumber, C: Send, D: Send> Segment<C, I, D> {
    #[inline]
    fn id_segment(&self, id: usize) -> IdSegment<I> {
        IdSegment {
            id,
            x_segment: self.x_segment,
        }
    }
}