Add corner rounding to the Rectangle node (#1648)

* add skeleton implementation

* add corner rounding

* fix crash when `border_radius` is zero

* rename `Border Radius` to `Corner Radius`

* add clamped property

* add `TaggedValue::F64Array4`

* add frontend support for individual corner rounding

* added individual corner rounding

* fix rebase

* change default values when switching rounding type

* fix crash caused by negative scale

* remove `Any` trait

* add `Message::Batched`

* fix stale property bug

* add smarter clamping for individual rounding

* Rearrange widgets in properties panel

* update individual clamping algorithm

* add better variable names

* make variable names clearer

* Final code cleanup

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Karthik Prakash
2024-04-06 10:39:55 +05:30
committed by GitHub
parent d09e7eaf86
commit 438c45eb80
8 changed files with 221 additions and 17 deletions

View File

@@ -217,6 +217,39 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
Self::from_anchors([corner1, DVec2::new(corner2.x, corner1.y), corner2, DVec2::new(corner1.x, corner2.y)], true)
}
/// Constructs a rounded rectangle with `corner1` and `corner2` as the two corners and `corner_radii` as the radii of the corners: `[top_left, top_right, bottom_right, bottom_left]`.
pub fn new_rounded_rect(corner1: DVec2, corner2: DVec2, corner_radii: [f64; 4]) -> Self {
use std::f64::consts::{FRAC_1_SQRT_2, PI};
let new_arc = |center: DVec2, corner: DVec2, radius: f64| -> Vec<ManipulatorGroup<ManipulatorGroupId>> {
let point1 = center + DVec2::from_angle(-PI * 0.25).rotate(corner - center) * FRAC_1_SQRT_2;
let point2 = center + DVec2::from_angle(PI * 0.25).rotate(corner - center) * FRAC_1_SQRT_2;
if radius == 0. {
return vec![ManipulatorGroup::new_anchor(point1), ManipulatorGroup::new_anchor(point2)];
}
// Based on https://pomax.github.io/bezierinfo/#circles_cubic
const HANDLE_OFFSET_FACTOR: f64 = 0.551784777779014;
let handle_offset = radius * HANDLE_OFFSET_FACTOR;
vec![
ManipulatorGroup::new_anchor(point1),
ManipulatorGroup::new(point1, None, Some(point1 + handle_offset * (corner - point1).normalize())),
ManipulatorGroup::new(point2, Some(point2 + handle_offset * (corner - point2).normalize()), None),
ManipulatorGroup::new_anchor(point2),
]
};
Self::new(
[
new_arc(DVec2::new(corner1.x + corner_radii[0], corner1.y + corner_radii[0]), DVec2::new(corner1.x, corner1.y), corner_radii[0]),
new_arc(DVec2::new(corner2.x - corner_radii[1], corner1.y + corner_radii[1]), DVec2::new(corner2.x, corner1.y), corner_radii[1]),
new_arc(DVec2::new(corner2.x - corner_radii[2], corner2.y - corner_radii[2]), DVec2::new(corner2.x, corner2.y), corner_radii[2]),
new_arc(DVec2::new(corner1.x + corner_radii[3], corner2.y - corner_radii[3]), DVec2::new(corner1.x, corner2.y), corner_radii[3]),
]
.concat(),
true,
)
}
/// Constructs an ellipse with `corner1` and `corner2` as the two corners of the bounding box.
pub fn new_ellipse(corner1: DVec2, corner2: DVec2) -> Self {
let size = (corner1 - corner2).abs();