diff --git a/geometry/src/segment.rs b/geometry/src/segment.rs index 8cedb3eb..e648f82c 100644 --- a/geometry/src/segment.rs +++ b/geometry/src/segment.rs @@ -13,6 +13,7 @@ use crate::line_segment::LineSegmentF32; use crate::point::Point2DF32; use crate::simd::F32x4; +use lyon_path::PathEvent; #[derive(Clone, Copy, Debug, PartialEq)] pub struct Segment { @@ -262,3 +263,156 @@ impl<'s> CubicSegment<'s> { const EPSILON: f32 = 0.001; } } + +// Lyon interoperability + +pub struct PathEventsToSegments +where + I: Iterator, +{ + iter: I, + first_subpath_point: Point2DF32, + last_subpath_point: Point2DF32, + just_moved: bool, +} + +impl PathEventsToSegments +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I) -> PathEventsToSegments { + PathEventsToSegments { + iter, + first_subpath_point: Point2DF32::default(), + last_subpath_point: Point2DF32::default(), + just_moved: false, + } + } +} + +impl Iterator for PathEventsToSegments +where + I: Iterator, +{ + type Item = Segment; + + #[inline] + fn next(&mut self) -> Option { + match self.iter.next()? { + PathEvent::MoveTo(to) => { + let to = Point2DF32::from_euclid(to); + self.first_subpath_point = to; + self.last_subpath_point = to; + self.just_moved = true; + self.next() + } + PathEvent::LineTo(to) => { + let to = Point2DF32::from_euclid(to); + let mut segment = + Segment::line(&LineSegmentF32::new(&self.last_subpath_point, &to)); + if self.just_moved { + segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH); + } + self.last_subpath_point = to; + self.just_moved = false; + Some(segment) + } + PathEvent::QuadraticTo(ctrl, to) => { + let (ctrl, to) = (Point2DF32::from_euclid(ctrl), Point2DF32::from_euclid(to)); + let mut segment = + Segment::quadratic(&LineSegmentF32::new(&self.last_subpath_point, &to), &ctrl); + if self.just_moved { + segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH); + } + self.last_subpath_point = to; + self.just_moved = false; + Some(segment) + } + PathEvent::CubicTo(ctrl0, ctrl1, to) => { + let ctrl0 = Point2DF32::from_euclid(ctrl0); + let ctrl1 = Point2DF32::from_euclid(ctrl1); + let to = Point2DF32::from_euclid(to); + let mut segment = Segment::cubic( + &LineSegmentF32::new(&self.last_subpath_point, &to), + &LineSegmentF32::new(&ctrl0, &ctrl1), + ); + if self.just_moved { + segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH); + } + self.last_subpath_point = to; + self.just_moved = false; + Some(segment) + } + PathEvent::Close => { + let mut segment = Segment::line(&LineSegmentF32::new( + &self.last_subpath_point, + &self.first_subpath_point, + )); + segment.flags.insert(SegmentFlags::CLOSES_SUBPATH); + self.just_moved = false; + self.last_subpath_point = self.first_subpath_point; + Some(segment) + } + PathEvent::Arc(..) => panic!("TODO: arcs"), + } + } +} + +pub struct SegmentsToPathEvents +where + I: Iterator, +{ + iter: I, + buffer: Option, +} + +impl SegmentsToPathEvents +where + I: Iterator, +{ + #[inline] + pub fn new(iter: I) -> SegmentsToPathEvents { + SegmentsToPathEvents { iter, buffer: None } + } +} + +impl Iterator for SegmentsToPathEvents +where + I: Iterator, +{ + type Item = PathEvent; + + #[inline] + fn next(&mut self) -> Option { + if let Some(event) = self.buffer.take() { + return Some(event); + } + + let segment = self.iter.next()?; + if segment.flags.contains(SegmentFlags::CLOSES_SUBPATH) { + return Some(PathEvent::Close); + } + + let event = match segment.kind { + SegmentKind::None => return self.next(), + SegmentKind::Line => PathEvent::LineTo(segment.baseline.to().as_euclid()), + SegmentKind::Quadratic => PathEvent::QuadraticTo( + segment.ctrl.from().as_euclid(), + segment.baseline.to().as_euclid(), + ), + SegmentKind::Cubic => PathEvent::CubicTo( + segment.ctrl.from().as_euclid(), + segment.ctrl.to().as_euclid(), + segment.baseline.to().as_euclid(), + ), + }; + + if segment.flags.contains(SegmentFlags::FIRST_IN_SUBPATH) { + self.buffer = Some(event); + Some(PathEvent::MoveTo(segment.baseline.from().as_euclid())) + } else { + Some(event) + } + } +} diff --git a/utils/tile-svg/src/main.rs b/utils/tile-svg/src/main.rs index a9fe46b2..fd6ee3b7 100644 --- a/utils/tile-svg/src/main.rs +++ b/utils/tile-svg/src/main.rs @@ -23,11 +23,11 @@ use fixedbitset::FixedBitSet; use hashbrown::HashMap; use jemallocator; use lyon_path::iterator::PathIter; -use lyon_path::PathEvent; use pathfinder_geometry::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8}; use pathfinder_geometry::outline::{Contour, Outline, PointIndex}; use pathfinder_geometry::point::Point2DF32; -use pathfinder_geometry::segment::{Segment, SegmentFlags, SegmentKind}; +use pathfinder_geometry::segment::{PathEventsToSegments, Segment, SegmentFlags}; +use pathfinder_geometry::segment::{SegmentKind, SegmentsToPathEvents}; use pathfinder_geometry::simd::{F32x4, I32x4}; use pathfinder_geometry::stroke::{StrokeStyle, StrokeToFillIter}; use pathfinder_geometry::transform::Transform2DF32; @@ -1362,157 +1362,6 @@ where } } -// Euclid interoperability -// -// TODO(pcwalton): Remove this once we're fully on Pathfinder's native geometry. - -struct PathEventsToSegments -where - I: Iterator, -{ - iter: I, - first_subpath_point: Point2DF32, - last_subpath_point: Point2DF32, - just_moved: bool, -} - -impl PathEventsToSegments -where - I: Iterator, -{ - fn new(iter: I) -> PathEventsToSegments { - PathEventsToSegments { - iter, - first_subpath_point: Point2DF32::default(), - last_subpath_point: Point2DF32::default(), - just_moved: false, - } - } -} - -impl Iterator for PathEventsToSegments -where - I: Iterator, -{ - type Item = Segment; - - fn next(&mut self) -> Option { - match self.iter.next()? { - PathEvent::MoveTo(to) => { - let to = Point2DF32::from_euclid(to); - self.first_subpath_point = to; - self.last_subpath_point = to; - self.just_moved = true; - self.next() - } - PathEvent::LineTo(to) => { - let to = Point2DF32::from_euclid(to); - let mut segment = - Segment::line(&LineSegmentF32::new(&self.last_subpath_point, &to)); - if self.just_moved { - segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH); - } - self.last_subpath_point = to; - self.just_moved = false; - Some(segment) - } - PathEvent::QuadraticTo(ctrl, to) => { - let (ctrl, to) = (Point2DF32::from_euclid(ctrl), Point2DF32::from_euclid(to)); - let mut segment = - Segment::quadratic(&LineSegmentF32::new(&self.last_subpath_point, &to), &ctrl); - if self.just_moved { - segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH); - } - self.last_subpath_point = to; - self.just_moved = false; - Some(segment) - } - PathEvent::CubicTo(ctrl0, ctrl1, to) => { - let ctrl0 = Point2DF32::from_euclid(ctrl0); - let ctrl1 = Point2DF32::from_euclid(ctrl1); - let to = Point2DF32::from_euclid(to); - let mut segment = Segment::cubic( - &LineSegmentF32::new(&self.last_subpath_point, &to), - &LineSegmentF32::new(&ctrl0, &ctrl1), - ); - if self.just_moved { - segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH); - } - self.last_subpath_point = to; - self.just_moved = false; - Some(segment) - } - PathEvent::Close => { - let mut segment = Segment::line(&LineSegmentF32::new( - &self.last_subpath_point, - &self.first_subpath_point, - )); - segment.flags.insert(SegmentFlags::CLOSES_SUBPATH); - self.just_moved = false; - self.last_subpath_point = self.first_subpath_point; - Some(segment) - } - PathEvent::Arc(..) => panic!("TODO: arcs"), - } - } -} - -struct SegmentsToPathEvents -where - I: Iterator, -{ - iter: I, - buffer: Option, -} - -impl SegmentsToPathEvents -where - I: Iterator, -{ - fn new(iter: I) -> SegmentsToPathEvents { - SegmentsToPathEvents { iter, buffer: None } - } -} - -impl Iterator for SegmentsToPathEvents -where - I: Iterator, -{ - type Item = PathEvent; - - fn next(&mut self) -> Option { - if let Some(event) = self.buffer.take() { - return Some(event); - } - - let segment = self.iter.next()?; - if segment.flags.contains(SegmentFlags::CLOSES_SUBPATH) { - return Some(PathEvent::Close); - } - - let event = match segment.kind { - SegmentKind::None => return self.next(), - SegmentKind::Line => PathEvent::LineTo(segment.baseline.to().as_euclid()), - SegmentKind::Quadratic => PathEvent::QuadraticTo( - segment.ctrl.from().as_euclid(), - segment.baseline.to().as_euclid(), - ), - SegmentKind::Cubic => PathEvent::CubicTo( - segment.ctrl.from().as_euclid(), - segment.ctrl.to().as_euclid(), - segment.baseline.to().as_euclid(), - ), - }; - - if segment.flags.contains(SegmentFlags::FIRST_IN_SUBPATH) { - self.buffer = Some(event); - Some(PathEvent::MoveTo(segment.baseline.from().as_euclid())) - } else { - Some(event) - } - } -} - // Path transformation utilities struct PathTransformingIter