From ca3a8852a64d7040b377e888dca56f88e7c25c3e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Feb 2019 18:25:48 -0800 Subject: [PATCH] Add more fast paths to the clipper --- geometry/src/clip.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/geometry/src/clip.rs b/geometry/src/clip.rs index 6f92c402..221fe571 100644 --- a/geometry/src/clip.rs +++ b/geometry/src/clip.rs @@ -276,6 +276,16 @@ trait ContourClipper where Self::Edge: TEdge { fn contour_mut(&mut self) -> &mut Contour; fn clip_against(&mut self, edge: Self::Edge) { + // Fast path to avoid allocation in the no-clip case. + match self.check_for_fast_clip(&edge) { + FastClipResult::SlowPath => {} + FastClipResult::AllInside => return, + FastClipResult::AllOutside => { + *self.contour_mut() = Contour::new(); + return; + } + } + let input = mem::replace(self.contour_mut(), Contour::new()); for mut segment in input.iter() { // Easy cases. @@ -334,6 +344,32 @@ trait ContourClipper where Self::Edge: TEdge { contour.push_segment(*segment); } } + + fn check_for_fast_clip(&mut self, edge: &Self::Edge) -> FastClipResult { + let mut result = None; + for segment in self.contour_mut().iter() { + let location = edge.trivially_test_segment(&segment); + match (result, location) { + (None, EdgeRelativeLocation::Outside) => { + result = Some(FastClipResult::AllOutside); + } + (None, EdgeRelativeLocation::Inside) => { + result = Some(FastClipResult::AllInside); + } + (Some(FastClipResult::AllInside), EdgeRelativeLocation::Inside) | + (Some(FastClipResult::AllOutside), EdgeRelativeLocation::Outside) => {} + (_, _) => return FastClipResult::SlowPath, + } + } + result.unwrap_or(FastClipResult::AllOutside) + } +} + +#[derive(Clone, Copy)] +enum FastClipResult { + SlowPath, + AllInside, + AllOutside, } // General convex polygon clipping in 2D @@ -375,6 +411,7 @@ impl ContourPolygonClipper { } } +#[derive(PartialEq)] enum EdgeRelativeLocation { Intersecting, Inside,