Add a fast path for monotonic conversion
This commit is contained in:
parent
70e615205e
commit
f19757e4cf
|
@ -287,14 +287,19 @@ trait ContourClipper where Self::Edge: TEdge {
|
|||
}
|
||||
|
||||
let input = self.contour_mut().take();
|
||||
for mut segment in input.iter() {
|
||||
for segment in input.iter() {
|
||||
self.clip_segment_against(segment, &edge);
|
||||
}
|
||||
}
|
||||
|
||||
fn clip_segment_against(&mut self, mut segment: Segment, edge: &Self::Edge) {
|
||||
// Easy cases.
|
||||
match edge.trivially_test_segment(&segment) {
|
||||
EdgeRelativeLocation::Outside => continue,
|
||||
EdgeRelativeLocation::Outside => return,
|
||||
EdgeRelativeLocation::Inside => {
|
||||
//println!("trivial test inside, pushing segment");
|
||||
push_segment(self.contour_mut(), &segment);
|
||||
continue;
|
||||
self.push_segment(&segment);
|
||||
return;
|
||||
}
|
||||
EdgeRelativeLocation::Intersecting => {}
|
||||
}
|
||||
|
@ -316,7 +321,7 @@ trait ContourClipper where Self::Edge: TEdge {
|
|||
starts_inside);*/
|
||||
if starts_inside {
|
||||
//println!("... split segment case, pushing segment");
|
||||
push_segment(self.contour_mut(), &before_split);
|
||||
self.push_segment(&before_split);
|
||||
}
|
||||
|
||||
// We've now transitioned from inside to outside or vice versa.
|
||||
|
@ -328,12 +333,13 @@ trait ContourClipper where Self::Edge: TEdge {
|
|||
// No more intersections. Push the last segment if applicable.
|
||||
if starts_inside {
|
||||
//println!("... last segment case, pushing segment");
|
||||
push_segment(self.contour_mut(), &segment);
|
||||
self.push_segment(&segment);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_segment(contour: &mut Contour, segment: &Segment) {
|
||||
fn push_segment(&mut self, segment: &Segment) {
|
||||
//println!("... push_segment({:?}, edge={:?}", segment, edge);
|
||||
let contour = self.contour_mut();
|
||||
if let Some(last_position) = contour.last_position() {
|
||||
if last_position != segment.baseline.from() {
|
||||
// Add a line to join up segments.
|
||||
|
@ -343,7 +349,6 @@ 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;
|
||||
|
|
|
@ -8,12 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Converts paths to monotonically increasing/decreasing segments.
|
||||
//! Converts paths to monotonically increasing/decreasing segments in Y.
|
||||
|
||||
use crate::segment::{Segment, SegmentKind};
|
||||
use arrayvec::ArrayVec;
|
||||
|
||||
// TODO(pcwalton): I think we only need to be monotonic in Y, maybe?
|
||||
pub struct MonotonicConversionIter<I>
|
||||
where
|
||||
I: Iterator<Item = Segment>,
|
||||
|
|
|
@ -356,7 +356,12 @@ impl Contour {
|
|||
|
||||
#[inline]
|
||||
pub fn make_monotonic(&mut self) {
|
||||
// TODO(pcwalton): Make monotonic in place?
|
||||
// Fast path.
|
||||
if self.iter().all(|segment| segment.is_monotonic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Slow path.
|
||||
let contour = self.take();
|
||||
for segment in MonotonicConversionIter::new(contour.iter()) {
|
||||
self.push_segment(segment);
|
||||
|
|
|
@ -112,6 +112,16 @@ impl Segment {
|
|||
new_segment
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_monotonic(&self) -> bool {
|
||||
// FIXME(pcwalton): Don't degree elevate!
|
||||
match self.kind {
|
||||
SegmentKind::None | SegmentKind::Line => true,
|
||||
SegmentKind::Quadratic => self.to_cubic().as_cubic_segment().is_monotonic(),
|
||||
SegmentKind::Cubic => self.as_cubic_segment().is_monotonic(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reversed(&self) -> Segment {
|
||||
Segment {
|
||||
|
@ -265,19 +275,25 @@ impl<'s> CubicSegment<'s> {
|
|||
self.split(t).0.baseline.to()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_monotonic(self) -> bool {
|
||||
// TODO(pcwalton): Optimize this.
|
||||
let (p0, p3) = (self.0.baseline.from_y(), self.0.baseline.to_y());
|
||||
let (p1, p2) = (self.0.ctrl.from_y(), self.0.ctrl.to_y());
|
||||
(p0 <= p1 && p1 <= p2 && p2 <= p3) || (p0 >= p1 && p1 >= p2 && p2 >= p3)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn y_extrema(self) -> (Option<f32>, Option<f32>) {
|
||||
if self.is_monotonic() {
|
||||
return (None, None)
|
||||
}
|
||||
|
||||
let p0p1p2p3 = F32x4::new(self.0.baseline.from_y(),
|
||||
self.0.ctrl.from_y(),
|
||||
self.0.ctrl.to_y(),
|
||||
self.0.baseline.to_y());
|
||||
|
||||
// TODO(pcwalton): Optimize this.
|
||||
if p0p1p2p3[0] <= p0p1p2p3[1] && p0p1p2p3[0] <= p0p1p2p3[2] &&
|
||||
p0p1p2p3[1] <= p0p1p2p3[3] && p0p1p2p3[2] <= p0p1p2p3[3] {
|
||||
return (None, None);
|
||||
}
|
||||
|
||||
let pxp0p1p2 = p0p1p2p3.wxyz();
|
||||
let pxv0v1v2 = p0p1p2p3 - pxp0p1p2;
|
||||
let (v0, v1, v2) = (pxv0v1v2[1], pxv0v1v2[2], pxv0v1v2[3]);
|
||||
|
|
Loading…
Reference in New Issue