forked from 1b-agent/opencadstudio-upstream
fix(automation): validate spline degree, knots and weights on entities_create
#1688 accepted any degree (falling back to 3 on a malformed value) and overwrote the degree the codec had clamped to the control-point count, so a two-point default spline stored degree 3 against a degree-1 knot vector. Reject a non-integer or out-of-range degree, too few control points for the degree, a knot vector that is not control_points + degree + 1 non-decreasing values, and weights that are not one positive value per control point. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
cdf8e60fbf
commit
731286c8cc
1 file changed
+38
-6
@@ -212,14 +212,27 @@ fn build_entity(spec: &Value) -> Parsed<codec::EntityType> {
|
||||
}
|
||||
let degree = match spec.get("degree") {
|
||||
None | Some(Value::Null) => 3,
|
||||
Some(value) => value.as_i64().unwrap_or(3),
|
||||
Some(value) => value
|
||||
.as_i64()
|
||||
.filter(|degree| (1..=10).contains(degree))
|
||||
.ok_or_else(|| {
|
||||
failure("invalid_spline_values", "degree must be an integer 1..10")
|
||||
})? as i32,
|
||||
};
|
||||
let count = control_points.len();
|
||||
if count > 0 && count <= degree as usize {
|
||||
return Err(failure(
|
||||
"invalid_spline_values",
|
||||
format!("a degree {degree} spline needs more than {degree} control_points"),
|
||||
));
|
||||
}
|
||||
let mut spline = if control_points.is_empty() {
|
||||
Spline::from_fit_points(fit_points.clone())
|
||||
let mut spline = Spline::from_fit_points(fit_points.clone());
|
||||
spline.degree = degree;
|
||||
spline
|
||||
} else {
|
||||
Spline::from_control_points(degree as i32, control_points)
|
||||
Spline::from_control_points(degree, control_points)
|
||||
};
|
||||
spline.degree = degree as i32;
|
||||
if !fit_points.is_empty() {
|
||||
spline.fit_points = fit_points;
|
||||
}
|
||||
@@ -230,7 +243,19 @@ fn build_entity(spec: &Value) -> Parsed<codec::EntityType> {
|
||||
"spline knots require control_points",
|
||||
));
|
||||
}
|
||||
spline.knots = finite_number_list_field(spec, "knots")?;
|
||||
let knots = finite_number_list_field(spec, "knots")?;
|
||||
if knots.len() != count + degree as usize + 1
|
||||
|| knots.windows(2).any(|pair| pair[1] < pair[0])
|
||||
{
|
||||
return Err(failure(
|
||||
"invalid_spline_values",
|
||||
format!(
|
||||
"knots must be {} non-decreasing values (control_points + degree + 1)",
|
||||
count + degree as usize + 1
|
||||
),
|
||||
));
|
||||
}
|
||||
spline.knots = knots;
|
||||
}
|
||||
if spec.get("weights").is_some() {
|
||||
if spline.control_points.is_empty() {
|
||||
@@ -239,7 +264,14 @@ fn build_entity(spec: &Value) -> Parsed<codec::EntityType> {
|
||||
"spline weights require control_points",
|
||||
));
|
||||
}
|
||||
spline.weights = finite_number_list_field(spec, "weights")?;
|
||||
let weights = finite_number_list_field(spec, "weights")?;
|
||||
if weights.len() != count || weights.iter().any(|weight| *weight <= 0.0) {
|
||||
return Err(failure(
|
||||
"invalid_spline_values",
|
||||
format!("weights must be {count} positive values, one per control point"),
|
||||
));
|
||||
}
|
||||
spline.weights = weights;
|
||||
spline.flags.rational = true;
|
||||
}
|
||||
if let Some(value) = spec["closed"].as_bool() {
|
||||
|
||||
Reference in new issue
Block a user