forked from 1b-agent/opencadstudio-upstream
fix(spline): reverse a spline without reshaping it
SPLINEDIT's REVERSE reversed the control points and then regenerated a clamped *uniform* knot vector. That is only harmless for a spline whose knots were evenly spaced to begin with; for any other — which is most of them once a modeller has been near one — the curve came back a different shape, bulging where it had been taut. It now mirrors the knots within the domain, which is exact, and swaps the end tangents to match. PEDIT's Spline option evaluated a uniform cubic B-spline from four blending polynomials written out by hand, clamped the open case by repeating end control points, and then pinned the two endpoints afterwards to undo the drift that leaves. A clamped knot vector says all of that directly, and the closed case gets a genuinely periodic curve rather than one whose seam is a special case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0677dd146c
commit
f1bc5f2cae
3 files changed
+81
-56
No files matched your search
@@ -9,9 +9,12 @@
|
||||
//
|
||||
// Control-point dragging is already supported via the grip editing system.
|
||||
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::EntityType;
|
||||
use glam::DVec3;
|
||||
|
||||
use crate::modules::draw::modify::spline_ops::spline_to_nurbs;
|
||||
|
||||
use crate::command::{CadCommand, CmdResult};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -190,12 +193,40 @@ pub fn apply_spline_op(doc: &mut acadrust::CadDocument, handle: acadrust::Handle
|
||||
}
|
||||
}
|
||||
"__SPLINEDIT_REVERSE__" => {
|
||||
spline.control_points.reverse();
|
||||
spline.fit_points.reverse();
|
||||
spline.knots = acadrust::entities::Spline::generate_clamped_knots(
|
||||
spline.degree as usize,
|
||||
spline.control_points.len(),
|
||||
);
|
||||
let begin = spline.begin_tangent;
|
||||
spline.begin_tangent = spline.end_tangent;
|
||||
spline.end_tangent = begin;
|
||||
// The knots mirror within the domain rather than being
|
||||
// regenerated. Rebuilding a clamped *uniform* vector here changed
|
||||
// the shape of any spline whose knots were unevenly spaced —
|
||||
// which is most of them once a modeller has been near one.
|
||||
match spline_to_nurbs(spline).map(|curve| curve.reversed()) {
|
||||
Some(reversed) => {
|
||||
let elevation = spline
|
||||
.control_points
|
||||
.first()
|
||||
.or_else(|| spline.fit_points.first())
|
||||
.map(|p| p.z)
|
||||
.unwrap_or(0.0);
|
||||
spline.degree = reversed.degree() as i32;
|
||||
spline.knots = reversed.knots().to_vec();
|
||||
spline.control_points = reversed
|
||||
.control_points()
|
||||
.iter()
|
||||
.map(|p| Vector3::new(p[0], p[1], elevation))
|
||||
.collect();
|
||||
spline.weights = if reversed.is_rational() {
|
||||
reversed.weights().to_vec()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
}
|
||||
// Nothing the kernel can read — a spline with too few points
|
||||
// to describe a curve. Reversing its stored points is still
|
||||
// the honest answer.
|
||||
None => spline.control_points.reverse(),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user