1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// SPDX-License-Identifier: ISC
use crate::point::Point3;
use crate::value::GroupValue;
use alloc::vec::Vec;
/// A SPLINE entity (NURBS curve).
#[derive(Debug, Clone, Default)]
pub struct Spline {
/// Spline degree.
///
/// Typically 3 for a cubic B-spline. The number of knots must be
/// `control_points.len() + degree + 1`.
pub degree: i16,
/// Spline flags.
///
/// `0b1` = closed, `0b10` = periodic, `0b100` = rational,
/// `0b1000` = planar, `0b1_0000` = linear (planar bit is also set).
pub flags: i16,
/// Knot values.
///
/// A non-decreasing sequence defining the parameter domain. The
/// length must be `control_points.len() + degree + 1`.
pub knot_values: Vec<f64>,
/// Control point weights.
///
/// One weight per control point. Empty for non-rational splines
/// (all weights implicitly 1.0).
pub weights: Vec<f64>,
/// Control points.
pub control_points: Vec<Point3>,
/// Fit points.
///
/// Points that the spline is constrained to pass through. These
/// are an alternative to control points for defining the curve;
/// both may be present.
pub fit_points: Vec<Point3>,
/// Start tangent direction.
pub start_tangent: Point3,
/// End tangent direction.
pub end_tangent: Point3,
/// Knot tolerance.
pub knot_tolerance: f64,
/// Control point tolerance.
pub control_point_tolerance: f64,
/// Fit tolerance.
pub fit_tolerance: f64,
/// In-progress control point being accumulated.
current_pt: Option<Point3>,
/// In-progress fit point being accumulated.
current_fit_pt: Option<Point3>,
}
impl Spline {
/// Returns `true` if the closed flag (`0b1`) is set.
pub fn is_closed(&self) -> bool {
self.flags & 1 != 0
}
}
impl Spline {
pub(crate) fn feed(&mut self, code: u16, val: &GroupValue) {
match code {
70 => {
if let Some(v) = val.as_i16() {
self.flags = v;
}
}
71 => {
if let Some(v) = val.as_i16() {
self.degree = v;
}
}
10 => {
if let Some(pt) = self.current_pt.take() {
self.control_points.push(pt);
}
self.current_pt = Some(Point3 {
x: val.as_f64().unwrap_or(0.0),
..Default::default()
});
}
20 => {
if let Some(ref mut pt) = self.current_pt {
pt.y = val.as_f64().unwrap_or(0.0);
}
}
30 => {
if let Some(ref mut pt) = self.current_pt {
pt.z = val.as_f64().unwrap_or(0.0);
}
}
11 => {
if let Some(pt) = self.current_fit_pt.take() {
self.fit_points.push(pt);
}
self.current_fit_pt = Some(Point3 {
x: val.as_f64().unwrap_or(0.0),
..Default::default()
});
}
21 => {
if let Some(ref mut pt) = self.current_fit_pt {
pt.y = val.as_f64().unwrap_or(0.0);
}
}
31 => {
if let Some(ref mut pt) = self.current_fit_pt {
pt.z = val.as_f64().unwrap_or(0.0);
}
}
_ => {
if let Some(v) = val.as_f64() {
match code {
12 => self.start_tangent.x = v,
22 => self.start_tangent.y = v,
32 => self.start_tangent.z = v,
13 => self.end_tangent.x = v,
23 => self.end_tangent.y = v,
33 => self.end_tangent.z = v,
40 => self.knot_values.push(v),
41 => self.weights.push(v),
42 => self.knot_tolerance = v,
43 => self.control_point_tolerance = v,
44 => self.fit_tolerance = v,
_ => {}
}
}
}
}
}
/// Flushes in-progress points. Called by the scanner after the last pair.
pub(crate) fn finish(&mut self) {
if let Some(pt) = self.current_pt.take() {
self.control_points.push(pt);
}
if let Some(pt) = self.current_fit_pt.take() {
self.fit_points.push(pt);
}
}
}