Skip to content

Commit

Permalink
Impl ParamCurve, ParamCurveArclen for Arc
Browse files Browse the repository at this point in the history
This uses an approximation of the arc length using beziers as the
analytic solution is quite involved.
  • Loading branch information
waywardmonkeys committed Dec 7, 2024
1 parent ebb8553 commit e0a54eb
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This release has an [MSRV][] of 1.65.
- `Stroke` is now `PartialEq`, `StrokeOpts` is now `Clone`, `Copy`, `Debug`, `Eq`, `PartialEq`. ([#379][] by [@waywardmonkeys][])
- Implement `Sum` for `Vec2`. ([#399][] by [@Philipp-M][])
- Add triangle shape. ([#350][] by [@juliapaci][])
- `Arc` now implements `ParamCurve` and `ParamCurveArclen`. ([#378] by [@waywardmonkeys])

### Changed

Expand Down Expand Up @@ -90,6 +91,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
[#379]: https://github.com/linebender/kurbo/pull/379
[#383]: https://github.com/linebender/kurbo/pull/383
[#388]: https://github.com/linebender/kurbo/pull/388
Expand Down
40 changes: 38 additions & 2 deletions src/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down Expand Up @@ -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<f64>) -> 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 * (range.end - range.start)),
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<iter::Once<PathEl>, ArcAppendIter>;

Expand Down

0 comments on commit e0a54eb

Please sign in to comment.