Skip to content

Commit c4e52dc

Browse files
committed
gh-50 Optimize spatial predicates with FillHandler segment access
Change FillHandler trait to receive segment reference, enabling handlers to access segment data during sweep for point coincidence detection. Key changes: - FillHandler<C> now passes &Segment<C> to handle() method - Add PointCoincidenceChecker helper struct with optimizations: - Uses IntPoint (8 bytes) vs (i32,i32,bool,bool) (16 bytes) = 2x memory reduction - Collects into separate subj/clip Vecs, sorts with sort_by_two_keys - Dedup removes ~50% duplicate endpoints from adjacent segments - Binary search from shorter array into longer for O(min(S,C) * log(max(S,C))) - Skips interior segments (SUBJ_BOTH/CLIP_BOTH fill) that can't contribute - IntersectsHandler and TouchesHandler now collect points during sweep - Remove standalone has_point_coincidence function from relate.rs - Add integration tests for doughnut+diamond hole boundary scenarios
1 parent 430a64e commit c4e52dc

File tree

4 files changed

+424
-105
lines changed

4 files changed

+424
-105
lines changed

iOverlay/src/build/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ impl<'a> StoreFillsHandler<'a> {
2424
}
2525
}
2626

27-
impl FillHandler for StoreFillsHandler<'_> {
27+
impl<C> FillHandler<C> for StoreFillsHandler<'_> {
2828
type Output = ();
2929

3030
#[inline(always)]
31-
fn handle(&mut self, index: usize, fill: SegmentFill) -> ControlFlow<()> {
31+
fn handle(&mut self, index: usize, _segment: &Segment<C>, fill: SegmentFill) -> ControlFlow<()> {
3232
// fills is pre-allocated to segments.len() and index is guaranteed
3333
// to be in range by the sweep algorithm
3434
unsafe { *self.fills.get_unchecked_mut(index) = fill };

iOverlay/src/build/sweep.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ pub(crate) trait FillStrategy<C> {
1616
fn add_and_fill(this: C, bot: C) -> (C, SegmentFill);
1717
}
1818

19-
pub(crate) trait FillHandler {
19+
pub(crate) trait FillHandler<C> {
2020
type Output;
21-
fn handle(&mut self, index: usize, fill: SegmentFill) -> ControlFlow<Self::Output>;
21+
fn handle(&mut self, index: usize, segment: &Segment<C>, fill: SegmentFill) -> ControlFlow<Self::Output>;
2222
fn finalize(self) -> Self::Output;
2323
}
2424

@@ -28,7 +28,7 @@ where
2828
C: WindingCount,
2929
F: FillStrategy<C>,
3030
S: KeyExpCollection<VSegment, i32, C>,
31-
H: FillHandler,
31+
H: FillHandler<C>,
3232
{
3333
let mut node = Vec::with_capacity(4);
3434
let n = segments.len();
@@ -62,7 +62,7 @@ where
6262
let (new_sum, fill) = F::add_and_fill(sid.count, sum_count);
6363
sum_count = new_sum;
6464

65-
if let ControlFlow::Break(result) = handler.handle(se.index, fill) {
65+
if let ControlFlow::Break(result) = handler.handle(se.index, sid, fill) {
6666
return result;
6767
}
6868

@@ -95,7 +95,7 @@ impl<C: WindingCount> SweepRunner<C> {
9595
pub(crate) fn run<F, H>(&mut self, solver: &Solver, segments: &[Segment<C>], handler: H) -> H::Output
9696
where
9797
F: FillStrategy<C>,
98-
H: FillHandler,
98+
H: FillHandler<C>,
9999
{
100100
let count = segments.len();
101101
if solver.is_list_fill(segments) {
@@ -122,7 +122,7 @@ impl<C: WindingCount> SweepRunner<C> {
122122
handler: H,
123123
) -> H::Output
124124
where
125-
H: FillHandler,
125+
H: FillHandler<C>,
126126
EvenOddStrategy: FillStrategy<C>,
127127
NonZeroStrategy: FillStrategy<C>,
128128
PositiveStrategy: FillStrategy<C>,

0 commit comments

Comments
 (0)