use crate::{
BezierAlgebraicImageStatus, BezierAlgebraicParameter2, BezierAlgebraicPointImage2,
BezierAlgebraicTangentImage2, BezierSubcurve2, CubicBezier2, CurvePolicy, CurveResult,
QuadraticBezier2, RationalBezierAlgebraicPointImage2, RationalBezierAlgebraicTangentImage2,
RationalQuadraticBezier2,
};
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, PartialEq)]
pub enum BezierEndpointPointImage2 {
Polynomial(BezierAlgebraicPointImage2),
RationalQuadratic(RationalBezierAlgebraicPointImage2),
}
impl BezierEndpointPointImage2 {
pub const fn status(&self) -> BezierAlgebraicImageStatus {
match self {
Self::Polynomial(image) => image.status(),
Self::RationalQuadratic(image) => image.status(),
}
}
pub const fn is_transformed(&self) -> bool {
matches!(self.status(), BezierAlgebraicImageStatus::Transformed)
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, PartialEq)]
pub enum BezierEndpointTangentImage2 {
Polynomial(BezierAlgebraicTangentImage2),
RationalQuadratic(RationalBezierAlgebraicTangentImage2),
}
impl BezierEndpointTangentImage2 {
pub const fn status(&self) -> BezierAlgebraicImageStatus {
match self {
Self::Polynomial(image) => image.status(),
Self::RationalQuadratic(image) => image.status(),
}
}
pub const fn is_transformed(&self) -> bool {
matches!(self.status(), BezierAlgebraicImageStatus::Transformed)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct BezierAlgebraicEndpointImage2 {
parameter: BezierAlgebraicParameter2,
point: BezierEndpointPointImage2,
tangent: BezierEndpointTangentImage2,
second_derivative: Option<Box<BezierEndpointTangentImage2>>,
third_derivative: Option<Box<BezierEndpointTangentImage2>>,
}
impl BezierAlgebraicEndpointImage2 {
pub fn from_source_curve(
source_curve: &BezierSubcurve2,
parameter: &BezierAlgebraicParameter2,
policy: &CurvePolicy,
) -> CurveResult<Self> {
match source_curve {
BezierSubcurve2::Quadratic(curve) => Self::quadratic(curve, parameter, policy),
BezierSubcurve2::Cubic(curve) => Self::cubic(curve, parameter, policy),
BezierSubcurve2::RationalQuadratic(curve) => {
Self::rational_quadratic(curve, parameter, policy)
}
}
}
pub fn quadratic(
curve: &QuadraticBezier2,
parameter: &BezierAlgebraicParameter2,
policy: &CurvePolicy,
) -> CurveResult<Self> {
Ok(Self {
parameter: parameter.clone(),
point: BezierEndpointPointImage2::Polynomial(
curve.point_at_algebraic_parameter(parameter, policy)?,
),
tangent: BezierEndpointTangentImage2::Polynomial(
curve.tangent_at_algebraic_parameter(parameter, policy)?,
),
second_derivative: Some(Box::new(BezierEndpointTangentImage2::Polynomial(
curve.second_derivative_at_algebraic_parameter(parameter, policy)?,
))),
third_derivative: None,
})
}
pub fn cubic(
curve: &CubicBezier2,
parameter: &BezierAlgebraicParameter2,
policy: &CurvePolicy,
) -> CurveResult<Self> {
Ok(Self {
parameter: parameter.clone(),
point: BezierEndpointPointImage2::Polynomial(
curve.point_at_algebraic_parameter(parameter, policy)?,
),
tangent: BezierEndpointTangentImage2::Polynomial(
curve.tangent_at_algebraic_parameter(parameter, policy)?,
),
second_derivative: Some(Box::new(BezierEndpointTangentImage2::Polynomial(
curve.second_derivative_at_algebraic_parameter(parameter, policy)?,
))),
third_derivative: Some(Box::new(BezierEndpointTangentImage2::Polynomial(
curve.third_derivative_at_algebraic_parameter(parameter, policy)?,
))),
})
}
pub fn rational_quadratic(
curve: &RationalQuadraticBezier2,
parameter: &BezierAlgebraicParameter2,
policy: &CurvePolicy,
) -> CurveResult<Self> {
let second_derivative =
curve.second_derivative_at_algebraic_parameter(parameter, policy)?;
Ok(Self {
parameter: parameter.clone(),
point: BezierEndpointPointImage2::RationalQuadratic(
curve.point_at_algebraic_parameter(parameter, policy)?,
),
tangent: BezierEndpointTangentImage2::RationalQuadratic(
curve.tangent_at_algebraic_parameter(parameter, policy)?,
),
second_derivative: (second_derivative.status()
== BezierAlgebraicImageStatus::Transformed)
.then_some(Box::new(BezierEndpointTangentImage2::RationalQuadratic(
second_derivative,
))),
third_derivative: None,
})
}
pub const fn parameter(&self) -> &BezierAlgebraicParameter2 {
&self.parameter
}
pub const fn point(&self) -> &BezierEndpointPointImage2 {
&self.point
}
pub const fn tangent(&self) -> &BezierEndpointTangentImage2 {
&self.tangent
}
pub fn second_derivative(&self) -> Option<&BezierEndpointTangentImage2> {
self.second_derivative.as_deref()
}
pub fn third_derivative(&self) -> Option<&BezierEndpointTangentImage2> {
self.third_derivative.as_deref()
}
pub const fn is_transformed(&self) -> bool {
self.point.is_transformed() && self.tangent.is_transformed()
}
}