use super::{Entity, EntityCommon};
use crate::types::{BoundingBox3D, Color, Handle, LineWeight, Transparency, Vector3};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SplineFlags {
pub closed: bool,
pub periodic: bool,
pub rational: bool,
pub planar: bool,
pub linear: bool,
}
impl SplineFlags {
pub fn new() -> Self {
SplineFlags {
closed: false,
periodic: false,
rational: false,
planar: false,
linear: false,
}
}
}
impl Default for SplineFlags {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Spline {
pub common: EntityCommon,
pub degree: i32,
pub flags: SplineFlags,
pub knots: Vec<f64>,
pub control_points: Vec<Vector3>,
pub weights: Vec<f64>,
pub fit_points: Vec<Vector3>,
pub normal: Vector3,
}
impl Spline {
pub fn new() -> Self {
Spline {
common: EntityCommon::new(),
degree: 3,
flags: SplineFlags::new(),
knots: Vec::new(),
control_points: Vec::new(),
weights: Vec::new(),
fit_points: Vec::new(),
normal: Vector3::UNIT_Z,
}
}
pub fn from_control_points(degree: i32, control_points: Vec<Vector3>) -> Self {
let knots = Self::generate_clamped_knots(degree as usize, control_points.len());
Spline {
degree,
control_points,
knots,
..Self::new()
}
}
pub fn from_fit_points(fit_points: Vec<Vector3>) -> Self {
Spline {
fit_points,
..Self::new()
}
}
pub fn generate_clamped_knots(degree: usize, num_control_points: usize) -> Vec<f64> {
if num_control_points == 0 {
return Vec::new();
}
let n = num_control_points;
let p = degree;
let m = n + p + 1;
let mut kv = Vec::with_capacity(m);
for _ in 0..=p {
kv.push(0.0);
}
let internal = m - 2 * (p + 1);
for i in 1..=internal {
kv.push(i as f64 / (internal + 1) as f64);
}
for _ in 0..=p {
kv.push(1.0);
}
kv
}
pub fn control_point_count(&self) -> usize {
self.control_points.len()
}
pub fn knot_count(&self) -> usize {
self.knots.len()
}
pub fn add_control_point(&mut self, point: Vector3) {
self.control_points.push(point);
}
pub fn add_knot(&mut self, knot: f64) {
self.knots.push(knot);
}
}
impl Default for Spline {
fn default() -> Self {
Self::new()
}
}
impl Entity for Spline {
fn handle(&self) -> Handle {
self.common.handle
}
fn set_handle(&mut self, handle: Handle) {
self.common.handle = handle;
}
fn layer(&self) -> &str {
&self.common.layer
}
fn set_layer(&mut self, layer: String) {
self.common.layer = layer;
}
fn color(&self) -> Color {
self.common.color
}
fn set_color(&mut self, color: Color) {
self.common.color = color;
}
fn line_weight(&self) -> LineWeight {
self.common.line_weight
}
fn set_line_weight(&mut self, weight: LineWeight) {
self.common.line_weight = weight;
}
fn transparency(&self) -> Transparency {
self.common.transparency
}
fn set_transparency(&mut self, transparency: Transparency) {
self.common.transparency = transparency;
}
fn is_invisible(&self) -> bool {
self.common.invisible
}
fn set_invisible(&mut self, invisible: bool) {
self.common.invisible = invisible;
}
fn bounding_box(&self) -> BoundingBox3D {
if self.control_points.is_empty() {
if self.fit_points.is_empty() {
return BoundingBox3D::from_point(Vector3::ZERO);
}
return BoundingBox3D::from_points(&self.fit_points).unwrap();
}
BoundingBox3D::from_points(&self.control_points).unwrap()
}
fn translate(&mut self, offset: Vector3) {
super::translate::translate_spline(self, offset);
}
fn entity_type(&self) -> &'static str {
"SPLINE"
}
fn apply_transform(&mut self, transform: &crate::types::Transform) {
super::transform::transform_spline(self, transform);
}
}