diff --git a/CHANGELOG.md b/CHANGELOG.md index 7810278f..be5b580c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ You can find its changes [documented below](#0111-2024-09-12). This release has an [MSRV][] of 1.65. +### Changes + +- `Arc` now implements `ParamCurve` and `ParamCurveArclen`. ([#378] by [@waywardmonkeys]) + ## [0.11.1][] (2024-09-12) This release has an [MSRV][] of 1.65. @@ -75,6 +79,7 @@ Note: A changelog was not kept for or before this release [#370]: https://github.com/linebender/kurbo/pull/370 [#375]: https://github.com/linebender/kurbo/pull/375 [#376]: https://github.com/linebender/kurbo/pull/376 +[#378]: https://github.com/linebender/kurbo/pull/378 [Unreleased]: https://github.com/linebender/kurbo/compare/v0.11.1...HEAD [0.11.0]: https://github.com/linebender/kurbo/releases/tag/v0.11.0 diff --git a/src/arc.rs b/src/arc.rs index 9ac642be..ac18e874 100644 --- a/src/arc.rs +++ b/src/arc.rs @@ -3,11 +3,11 @@ //! An ellipse arc. -use crate::{Affine, Ellipse, PathEl, Point, Rect, Shape, Vec2}; +use crate::{Affine, Ellipse, ParamCurve, ParamCurveArclen, PathEl, Point, Rect, Shape, Vec2}; use core::{ f64::consts::{FRAC_PI_2, PI}, iter, - ops::Mul, + ops::{Mul, Range}, }; #[cfg(not(feature = "std"))] @@ -171,6 +171,42 @@ fn rotate_pt(pt: Vec2, angle: f64) -> Vec2 { ) } +impl ParamCurve for Arc { + fn eval(&self, t: f64) -> Point { + let angle = self.start_angle + (self.sweep_angle * t); + sample_ellipse(self.radii, self.x_rotation, angle).to_point() + } + + fn subsegment(&self, range: Range) -> Self { + Self { + center: self.center, + radii: self.radii, + start_angle: self.start_angle + (self.sweep_angle * range.start), + sweep_angle: self.sweep_angle - (self.sweep_angle * (1.0 - range.end)), + x_rotation: self.x_rotation, + } + } + + fn start(&self) -> Point { + sample_ellipse(self.radii, self.x_rotation, self.start_angle).to_point() + } + + fn end(&self) -> Point { + sample_ellipse( + self.radii, + self.x_rotation, + self.start_angle + self.sweep_angle, + ) + .to_point() + } +} + +impl ParamCurveArclen for Arc { + fn arclen(&self, accuracy: f64) -> f64 { + self.path_segments(0.1).perimeter(accuracy) + } +} + impl Shape for Arc { type PathElementsIter<'iter> = iter::Chain, ArcAppendIter>;