pub struct CornerPathParams {
a: f32,
b: f32,
c: f32,
d: f32,
p: f32,
corner_radius: f32,
arc_section_length: f32
}
pub struct CornerParams {
pub corner_radius: f32,
pub corner_smoothing: f32,
pub preserve_smoothing: bool,
pub rounding_and_smoothing_budget: f32
}
pub fn get_path_params_for_corner(
CornerParams {
corner_radius,
mut corner_smoothing,
preserve_smoothing,
rounding_and_smoothing_budget
}: CornerParams
) -> CornerPathParams {
let mut p = (1.0 + corner_smoothing) * corner_radius;
if !preserve_smoothing {
let max_corner_smoothing = rounding_and_smoothing_budget / corner_radius - 1.0;
corner_smoothing = corner_smoothing.min(max_corner_smoothing);
p = p.min(rounding_and_smoothing_budget);
}
let arc_measure = 90.0 * (1.0 - corner_smoothing);
let arc_section_length =
(arc_measure / 2.0).to_radians().sin() * corner_radius * std::f32::consts::SQRT_2;
let angle_alpha = (90.0 - arc_measure) / 2.0;
let p3_to_p4_distance = corner_radius * (angle_alpha / 2.0).to_radians().tan();
let angle_beta = 45.0 * corner_smoothing;
let c = p3_to_p4_distance * angle_beta.to_radians().cos();
let d = c * angle_beta.to_radians().tan();
let mut b = (p - arc_section_length - c - d) / 3.0;
let mut a = 2.0 * b;
if preserve_smoothing && p > rounding_and_smoothing_budget {
let p1_to_p3_max_distance =
rounding_and_smoothing_budget - d - arc_section_length - c;
let min_a = p1_to_p3_max_distance / 6.0;
let max_b = p1_to_p3_max_distance - min_a;
b = b.min(max_b);
a = p1_to_p3_max_distance - b;
p = p.min(rounding_and_smoothing_budget);
}
CornerPathParams {
a,
b,
c,
d,
p,
corner_radius,
arc_section_length
}
}
pub struct SvgPathInput<'a> {
pub width: f32,
pub height: f32,
pub top_left_path_params: &'a CornerPathParams,
pub top_right_path_params: &'a CornerPathParams,
pub bottom_right_path_params: &'a CornerPathParams,
pub bottom_left_path_params: &'a CornerPathParams,
}
pub fn get_svg_path_from_path_params(
SvgPathInput {
width,
height,
top_right_path_params,
bottom_right_path_params,
bottom_left_path_params,
top_left_path_params
}: SvgPathInput
) -> String {
return format!(
"M {} 0 {} L {} {} {} L {} {} {} L 0 {} {} Z",
width - top_right_path_params.p,
draw_top_right_path(top_right_path_params),
width, height - bottom_right_path_params.p,
draw_bottom_right_path(bottom_right_path_params),
bottom_left_path_params.p, height,
draw_bottom_left_path(bottom_left_path_params),
top_left_path_params.p,
draw_top_left_path(top_left_path_params)
)
}
fn draw_top_right_path(CornerPathParams {
a,
b,
c,
d,
p: _p,
corner_radius,
arc_section_length,
}: &CornerPathParams) -> String {
if corner_radius != &0.0 {
format!(
"c {:.4} 0 {:.4} 0 {:.4} {:.4} a {:.4} {:.4} 0 0 1 {:.4} {:.4} c {:.4} {:.4} {:.4} {:.4} {:.4} {:.4}",
a, a + b, a + b + c, d,
corner_radius, corner_radius, arc_section_length, arc_section_length,
d, c,
d, b + c,
d, a + b + c
)
} else {
String::new()
}
}
fn draw_bottom_right_path(CornerPathParams {
a,
b,
c,
d,
p: _p,
corner_radius,
arc_section_length,
}: &CornerPathParams) -> String {
if corner_radius != &0.0 {
format!(
"c 0 {:.4} 0 {:.4} {:.4} {:.4} a {:.4} {:.4} 0 0 1 -{:.4} {:.4} c {:.4} {:.4} {:.4} {:.4} {:.4} {:.4}",
a,
a + b,
-d, a + b + c,
corner_radius, corner_radius, arc_section_length, arc_section_length,
-c, d,
-(b + c), d,
-(a + b + c), d
)
} else {
String::new()
}
}
fn draw_bottom_left_path(CornerPathParams {
a,
b,
c,
d,
p: _p,
corner_radius,
arc_section_length,
}: &CornerPathParams) -> String {
if corner_radius != &0.0 {
format!(
"c {:.4} 0 {:.4} 0 {:.4} {:.4} a {:.4} {:.4} 0 0 1 -{:.4} -{:.4} c {:.4} {:.4} {:.4} {:.4} {:.4} {:.4}",
-a,
-(a + b),
-(a + b + c), -d,
corner_radius, corner_radius, arc_section_length, arc_section_length,
-d, -c,
-d, -(b + c),
-d, -(a + b + c)
)
} else {
String::new()
}
}
fn draw_top_left_path(CornerPathParams {
a,
b,
c,
d,
p: _p,
corner_radius,
arc_section_length,
}: &CornerPathParams) -> String {
if corner_radius != &0.0 {
format!(
"c 0 {:.4} 0 {:.4} {:.4} {:.4} a {:.4} {:.4} 0 0 1 {:.4} -{:.4} c {:.4} {:.4} {:.4} {:.4} {:.4} {:.4}",
-a,
-(a + b),
d, -(a + b + c),
corner_radius, corner_radius, arc_section_length, arc_section_length,
c, -d,
b + c, -d,
a + b + c, -d
)
} else {
String::new()
}
}