From 44167beff5cbb8005751aee26498e55adb146895 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 31 May 2019 16:01:53 -0700 Subject: [PATCH] Implement `Path2D::arc_to`. --- canvas/src/lib.rs | 19 +++++++++++++++++++ geometry/src/outline.rs | 10 +++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index 1a0163a6..674bc2d6 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -14,6 +14,7 @@ use font_kit::family_name::FamilyName; use font_kit::hinting::HintingOptions; use font_kit::properties::Properties; use font_kit::source::SystemSource; +use pathfinder_geometry::basic::line_segment::LineSegmentF; use pathfinder_geometry::basic::point::Point2DF; use pathfinder_geometry::basic::rect::RectF; use pathfinder_geometry::basic::transform2d::Transform2DF; @@ -341,6 +342,24 @@ impl Path2D { self.current_contour.push_arc(&transform, start_angle, end_angle); } + #[inline] + pub fn arc_to(&mut self, ctrl: Point2DF, to: Point2DF, radius: f32) { + // FIXME(pcwalton): What should we do if there's no initial point? + let from = self.current_contour.last_position().unwrap_or_default(); + let (v0, v1) = (from - ctrl, to - ctrl); + let (vu0, vu1) = (v0.normalize(), v1.normalize()); + let hypot = radius / f32::sqrt(0.5 * (1.0 - vu0.dot(vu1))); + let bisector = vu0 + vu1; + let center = ctrl + bisector.scale(hypot / bisector.length()); + + let mut transform = Transform2DF::from_scale(Point2DF::splat(radius)); + transform = transform.post_mul(&Transform2DF::from_translation(center)); + + let chord = LineSegmentF::new(vu0.yx().scale_xy(Point2DF::new(-1.0, 1.0)), + vu1.yx().scale_xy(Point2DF::new(1.0, -1.0))); + self.current_contour.push_arc_from_unit_chord(&transform, chord); + } + pub fn rect(&mut self, rect: RectF) { self.flush_current_contour(); self.current_contour.push_endpoint(rect.origin()); diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index 2cb65a13..a0e1c374 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -269,13 +269,13 @@ impl Contour { } #[inline] - pub(crate) fn position_of_last(&self, index: u32) -> Point2DF { - self.points[self.points.len() - index as usize] + pub fn last_position(&self) -> Option { + self.points.last().cloned() } #[inline] - pub(crate) fn last_position(&self) -> Option { - self.points.last().cloned() + pub(crate) fn position_of_last(&self, index: u32) -> Point2DF { + self.points[self.points.len() - index as usize] } #[inline] @@ -409,7 +409,7 @@ impl Contour { break; } - vector = sweep_vector.rotate_by(vector); + vector = vector.rotate_by(sweep_vector); } const EPSILON: f32 = 0.001;