use crate::output::path::CubicSegment;
use crate::types::{Point, Vector};
use crate::utils::EPSILON;
use super::SmoothCornerGeometry;
use super::arc::{circle_point, circle_tangent};
pub(super) fn build_cubics(geometry: SmoothCornerGeometry) -> Vec<CubicSegment> {
if geometry.radius <= EPSILON {
return Vec::new();
}
let basis = ArcBasis::from_geometry(geometry);
let p1 = circle_point(
basis.center,
geometry.radius,
basis.e0,
basis.e1,
geometry.alpha0,
);
let p2 = circle_point(
basis.center,
geometry.radius,
basis.e0,
basis.e1,
geometry.angle - geometry.alpha1,
);
let handles = CornerHandles::from_geometry(geometry);
vec![
first_cubic(geometry, p1, handles.incoming),
middle_cubic(geometry, basis, p1, p2, handles.arc),
last_cubic(geometry, p2, handles.outgoing),
]
}
#[derive(Debug, Clone, Copy)]
struct ArcBasis {
center: Point,
e0: Vector,
e1: Vector,
}
impl ArcBasis {
fn from_geometry(geometry: SmoothCornerGeometry) -> Self {
let center = geometry.origin
+ (geometry.incoming_axis + geometry.outgoing_axis)
.normalized()
.expect("输入层已保证 smooth corner 角度有效")
* (geometry.radius / (geometry.angle / 2.0).sin());
let incoming_tangent = geometry.origin + geometry.incoming_axis * geometry.base_tangent;
Self {
center,
e0: (incoming_tangent - center) / geometry.radius,
e1: -geometry.incoming_axis,
}
}
}
#[derive(Debug, Clone, Copy)]
struct CornerHandles {
incoming: f64,
outgoing: f64,
arc: f64,
}
impl CornerHandles {
fn from_geometry(geometry: SmoothCornerGeometry) -> Self {
let tangent0 = geometry.base_tangent - geometry.radius * (geometry.alpha0 / 2.0).tan();
let tangent1 = geometry.base_tangent - geometry.radius * (geometry.alpha1 / 2.0).tan();
let arc = if geometry.middle_arc_angle <= EPSILON {
0.0
} else {
(4.0 / 3.0) * (geometry.middle_arc_angle / 4.0).tan() * geometry.radius
};
Self {
incoming: (geometry.incoming_influence - tangent0) / 3.0,
outgoing: (geometry.outgoing_influence - tangent1) / 3.0,
arc,
}
}
}
fn first_cubic(geometry: SmoothCornerGeometry, p1: Point, incoming_handle: f64) -> CubicSegment {
let tangent0 = geometry.base_tangent - geometry.radius * (geometry.alpha0 / 2.0).tan();
CubicSegment {
from: geometry.start,
ctrl1: geometry.origin
+ geometry.incoming_axis * (geometry.incoming_influence - 2.0 * incoming_handle),
ctrl2: geometry.origin + geometry.incoming_axis * tangent0,
to: p1,
}
}
fn middle_cubic(
geometry: SmoothCornerGeometry,
basis: ArcBasis,
p1: Point,
p2: Point,
arc_handle: f64,
) -> CubicSegment {
let arc_tangent0 = circle_tangent(basis.e0, basis.e1, geometry.alpha0);
let arc_tangent1 = circle_tangent(basis.e0, basis.e1, geometry.angle - geometry.alpha1);
CubicSegment {
from: p1,
ctrl1: p1 + arc_tangent0 * arc_handle,
ctrl2: p2 - arc_tangent1 * arc_handle,
to: p2,
}
}
fn last_cubic(geometry: SmoothCornerGeometry, p2: Point, outgoing_handle: f64) -> CubicSegment {
let tangent1 = geometry.base_tangent - geometry.radius * (geometry.alpha1 / 2.0).tan();
CubicSegment {
from: p2,
ctrl1: geometry.origin + geometry.outgoing_axis * tangent1,
ctrl2: geometry.origin + geometry.outgoing_axis * (tangent1 + outgoing_handle),
to: geometry.end,
}
}