Skip to content

Commit e0a54eb

Browse files
Impl ParamCurve, ParamCurveArclen for Arc
This uses an approximation of the arc length using beziers as the analytic solution is quite involved.
1 parent ebb8553 commit e0a54eb

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This release has an [MSRV][] of 1.65.
2020
- `Stroke` is now `PartialEq`, `StrokeOpts` is now `Clone`, `Copy`, `Debug`, `Eq`, `PartialEq`. ([#379][] by [@waywardmonkeys][])
2121
- Implement `Sum` for `Vec2`. ([#399][] by [@Philipp-M][])
2222
- Add triangle shape. ([#350][] by [@juliapaci][])
23+
- `Arc` now implements `ParamCurve` and `ParamCurveArclen`. ([#378] by [@waywardmonkeys])
2324

2425
### Changed
2526

@@ -90,6 +91,7 @@ Note: A changelog was not kept for or before this release
9091
[#370]: https://github.com/linebender/kurbo/pull/370
9192
[#375]: https://github.com/linebender/kurbo/pull/375
9293
[#376]: https://github.com/linebender/kurbo/pull/376
94+
[#378]: https://github.com/linebender/kurbo/pull/378
9395
[#379]: https://github.com/linebender/kurbo/pull/379
9496
[#383]: https://github.com/linebender/kurbo/pull/383
9597
[#388]: https://github.com/linebender/kurbo/pull/388

src/arc.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
//! An ellipse arc.
55
6-
use crate::{Affine, Ellipse, PathEl, Point, Rect, Shape, Vec2};
6+
use crate::{Affine, Ellipse, ParamCurve, ParamCurveArclen, PathEl, Point, Rect, Shape, Vec2};
77
use core::{
88
f64::consts::{FRAC_PI_2, PI},
99
iter,
10-
ops::Mul,
10+
ops::{Mul, Range},
1111
};
1212

1313
#[cfg(not(feature = "std"))]
@@ -171,6 +171,42 @@ fn rotate_pt(pt: Vec2, angle: f64) -> Vec2 {
171171
)
172172
}
173173

174+
impl ParamCurve for Arc {
175+
fn eval(&self, t: f64) -> Point {
176+
let angle = self.start_angle + (self.sweep_angle * t);
177+
sample_ellipse(self.radii, self.x_rotation, angle).to_point()
178+
}
179+
180+
fn subsegment(&self, range: Range<f64>) -> Self {
181+
Self {
182+
center: self.center,
183+
radii: self.radii,
184+
start_angle: self.start_angle + (self.sweep_angle * range.start),
185+
sweep_angle: self.sweep_angle - (self.sweep_angle * (range.end - range.start)),
186+
x_rotation: self.x_rotation,
187+
}
188+
}
189+
190+
fn start(&self) -> Point {
191+
sample_ellipse(self.radii, self.x_rotation, self.start_angle).to_point()
192+
}
193+
194+
fn end(&self) -> Point {
195+
sample_ellipse(
196+
self.radii,
197+
self.x_rotation,
198+
self.start_angle + self.sweep_angle,
199+
)
200+
.to_point()
201+
}
202+
}
203+
204+
impl ParamCurveArclen for Arc {
205+
fn arclen(&self, accuracy: f64) -> f64 {
206+
self.path_segments(0.1).perimeter(accuracy)
207+
}
208+
}
209+
174210
impl Shape for Arc {
175211
type PathElementsIter<'iter> = iter::Chain<iter::Once<PathEl>, ArcAppendIter>;
176212

0 commit comments

Comments
 (0)