Skip to content

Commit 04543e7

Browse files
authored
Simplify and optimize Ellipse::area (#559)
Instead of performing a singular value decomposition (via the `Ellipse::radii` call), use the property that the area of a region transformed by an affine is that area multiplied by the determinant of the affine: https://en.wikipedia.org/w/index.php?title=Determinant&oldid=1344268205#Geometric_meaning.
1 parent 2ab2448 commit 04543e7

2 files changed

Lines changed: 16 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This release has an [MSRV][] of 1.85.
2626

2727
- Improve performance of `RoundedRect::winding` and `RoundedRect::contains`. ([#534][] by [@tomcur][])
2828
- `Axis`, `Ellipse::from_affine`, `Insets`, `Line::reversed`, `Rect::min_x/max_x/min_y/max_y`, `RoundedRectRadii::abs/clamp/as_single_radius`, `RoundedRect::width/height/radii/rect/origin/center`, `Size::aspect_ratio`, `Stroke::new/with_join/with_miter_limit/with_start_cap/with_end_cap/with_caps` are all now `const`. ([#536][] by [@xStrom], [#539][] and [#561][] by [@tomcur][])
29+
- Improve performance of `Ellipse::area`. Note: for non-finite ellipses, this method may now return `f64::INFINITY` where it returned `f64::NAN` before. ([#559][] by [@tomcur][])
2930

3031
## Fixed
3132

@@ -288,6 +289,7 @@ Note: A changelog was not kept for or before this release
288289
[#545]: https://github.com/linebender/kurbo/pull/545
289290
[#548]: https://github.com/linebender/kurbo/pull/548
290291
[#549]: https://github.com/linebender/kurbo/pull/549
292+
[#559]: https://github.com/linebender/kurbo/pull/559
291293
[#561]: https://github.com/linebender/kurbo/pull/561
292294

293295
[Unreleased]: https://github.com/linebender/kurbo/compare/v0.13.0...HEAD

kurbo/src/ellipse.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,22 @@ impl Shape for Ellipse {
235235
.path_elements(tolerance)
236236
}
237237

238+
/// The area of the ellipse.
239+
///
240+
/// This is always positive if the result is finite.
241+
///
242+
/// If non-finite, this will be [`f64::INFINITY`] or [`f64::NAN`] depending on whether the
243+
/// inner affine's [determinant](Affine::determinant) is [`f64::INFINITY`] (either positive or
244+
/// negative) or [`f64::NAN`].
238245
#[inline]
239246
fn area(&self) -> f64 {
240-
let Vec2 { x, y } = self.radii();
241-
PI * x * y
247+
// `Ellipse` is represented as a unit circle transformed by `Affine`. The transformed area
248+
// of a region is `area * |det(affine)|`, see
249+
// <https://en.wikipedia.org/w/index.php?title=Determinant&oldid=1344268205#Geometric_meaning>.
250+
//
251+
// A unit circle has area `PI`. Therefore, the area of this ellipse is PI multiplied by the
252+
// affine's determinant.
253+
PI * self.inner.determinant().abs()
242254
}
243255

244256
/// Approximate the ellipse perimeter.

0 commit comments

Comments
 (0)