diff --git a/geometry/src/lib.rs b/geometry/src/lib.rs index 3130ab33..0875dd24 100644 --- a/geometry/src/lib.rs +++ b/geometry/src/lib.rs @@ -18,6 +18,7 @@ extern crate bitflags; pub mod clip; pub mod cubic_to_quadratic; pub mod line_segment; +pub mod monotonic; pub mod normals; pub mod orientation; pub mod outline; diff --git a/geometry/src/monotonic.rs b/geometry/src/monotonic.rs new file mode 100644 index 00000000..67aa35ec --- /dev/null +++ b/geometry/src/monotonic.rs @@ -0,0 +1,79 @@ +// pathfinder/geometry/src/monotonic.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Converts paths to monotonically increasing/decreasing segments. + +use crate::segment::{Segment, SegmentKind}; +use arrayvec::ArrayVec; + +// TODO(pcwalton): I think we only need to be monotonic in Y, maybe? +pub struct MonotonicConversionIter +where + I: Iterator, +{ + iter: I, + buffer: ArrayVec<[Segment; 2]>, +} + +impl Iterator for MonotonicConversionIter +where + I: Iterator, +{ + type Item = Segment; + + #[inline] + fn next(&mut self) -> Option { + if let Some(segment) = self.buffer.pop() { + return Some(segment); + } + + let segment = self.iter.next()?; + match segment.kind { + SegmentKind::None => self.next(), + SegmentKind::Line => Some(segment), + SegmentKind::Cubic => self.handle_cubic(&segment), + SegmentKind::Quadratic => { + // TODO(pcwalton): Don't degree elevate! + self.handle_cubic(&segment.to_cubic()) + } + } + } +} + +impl MonotonicConversionIter +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I) -> MonotonicConversionIter { + MonotonicConversionIter { + iter, + buffer: ArrayVec::new(), + } + } + + pub fn handle_cubic(&mut self, segment: &Segment) -> Option { + match segment.as_cubic_segment().y_extrema() { + (Some(t0), Some(t1)) => { + let (segments_01, segment_2) = segment.as_cubic_segment().split(t1); + self.buffer.push(segment_2); + let (segment_0, segment_1) = segments_01.as_cubic_segment().split(t0 / t1); + self.buffer.push(segment_1); + Some(segment_0) + } + (Some(t0), None) | (None, Some(t0)) => { + let (segment_0, segment_1) = segment.as_cubic_segment().split(t0); + self.buffer.push(segment_1); + Some(segment_0) + } + (None, None) => Some(*segment), + } + } +} diff --git a/utils/tile-svg/src/main.rs b/utils/tile-svg/src/main.rs index 8d70a4da..1a5e08bf 100644 --- a/utils/tile-svg/src/main.rs +++ b/utils/tile-svg/src/main.rs @@ -15,7 +15,6 @@ extern crate quickcheck; #[cfg(test)] extern crate rand; -use arrayvec::ArrayVec; use byteorder::{LittleEndian, WriteBytesExt}; use clap::{App, Arg}; use euclid::{Point2D, Rect, Size2D}; @@ -24,10 +23,11 @@ use hashbrown::HashMap; use jemallocator; use lyon_path::iterator::PathIter; use pathfinder_geometry::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8}; +use pathfinder_geometry::monotonic::MonotonicConversionIter; use pathfinder_geometry::outline::{Contour, Outline, PointIndex}; use pathfinder_geometry::point::Point2DF32; -use pathfinder_geometry::segment::{PathEventsToSegments, Segment, SegmentFlags}; -use pathfinder_geometry::segment::{SegmentKind, SegmentsToPathEvents}; +use pathfinder_geometry::segment::{PathEventsToSegments, Segment}; +use pathfinder_geometry::segment::{SegmentFlags, SegmentsToPathEvents}; use pathfinder_geometry::simd::{F32x4, I32x4}; use pathfinder_geometry::stroke::{StrokeStyle, StrokeToFillIter}; use pathfinder_geometry::transform::{Transform2DF32, Transform2DF32PathIter}; @@ -1364,69 +1364,6 @@ where // Monotonic conversion utilities -// TODO(pcwalton): I think we only need to be monotonic in Y, maybe? -struct MonotonicConversionIter -where - I: Iterator, -{ - iter: I, - buffer: ArrayVec<[Segment; 2]>, -} - -impl Iterator for MonotonicConversionIter -where - I: Iterator, -{ - type Item = Segment; - - fn next(&mut self) -> Option { - if let Some(segment) = self.buffer.pop() { - return Some(segment); - } - - let segment = self.iter.next()?; - match segment.kind { - SegmentKind::None => self.next(), - SegmentKind::Line => Some(segment), - SegmentKind::Cubic => self.handle_cubic(&segment), - SegmentKind::Quadratic => { - // TODO(pcwalton): Don't degree elevate! - self.handle_cubic(&segment.to_cubic()) - } - } - } -} - -impl MonotonicConversionIter -where - I: Iterator, -{ - fn new(iter: I) -> MonotonicConversionIter { - MonotonicConversionIter { - iter, - buffer: ArrayVec::new(), - } - } - - fn handle_cubic(&mut self, segment: &Segment) -> Option { - match segment.as_cubic_segment().y_extrema() { - (Some(t0), Some(t1)) => { - let (segments_01, segment_2) = segment.as_cubic_segment().split(t1); - self.buffer.push(segment_2); - let (segment_0, segment_1) = segments_01.as_cubic_segment().split(t0 / t1); - self.buffer.push(segment_1); - Some(segment_0) - } - (Some(t0), None) | (None, Some(t0)) => { - let (segment_0, segment_1) = segment.as_cubic_segment().split(t0); - self.buffer.push(segment_1); - Some(segment_0) - } - (None, None) => Some(*segment), - } - } -} - // SortedVector #[derive(Clone, Debug)]