fix(polyline): spline-fit 2D polylines draw the curve, not the frame

A curve-/spline-fit heavy polyline stores both the fitted curve points
(vertex flag 8 / 1) and the spline-frame control points (flag 16),
which only SPLFRAME is meant to show. Chaining every stored vertex
drew spokes from the curve to the control frame — stray points on the
curve and, on wide polylines, a blobbed band (#408). drawn_vertices2d
now drops the control points whenever fit data is present (falling
back to the stored vertices when it is not) and feeds the wire, the
wide-band fills and the tapered band alike, so snapping no longer
lands on frame points either.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Fable 5 committed 2026-07-21 15:12:52 +03:00
1 parent 8ff7b6b25c
commit 1546c1dc30
1 file changed
+35 -4
+35 -4
View File
@@ -166,8 +166,37 @@ impl Transformable for Polyline {
// ── Polyline2D (heavy 2D polyline with bulge) ─────────────────────────────────
/// The vertices a curve-/spline-fit 2D polyline actually DRAWS: the
/// fit-generated points (VertexFlags 8 / 1) plus any unflagged originals,
/// with the spline-frame CONTROL points (flag 16) dropped — those are editing
/// scaffolding shown only under SPLFRAME, and chaining through them draws
/// spokes across the fitted curve (#408). `None` = no fit data, draw the
/// stored vertices as-is. A fit-flagged polyline whose fit points are missing
/// falls back to the stored vertices rather than drawing nothing.
pub fn drawn_vertices2d(
pl: &Polyline2D,
) -> Option<Vec<acadrust::entities::Vertex2D>> {
use acadrust::entities::polyline::VertexFlags;
let has_fit = pl.vertices.iter().any(|v| {
v.flags.bits()
& (VertexFlags::SPLINE_VERTEX.bits() | VertexFlags::EXTRA_VERTEX.bits())
!= 0
});
if !has_fit {
return None;
}
let kept: Vec<_> = pl
.vertices
.iter()
.filter(|v| v.flags.bits() & VertexFlags::SPLINE_CONTROL.bits() == 0)
.cloned()
.collect();
(kept.len() >= 2).then_some(kept)
}
fn tessellate_polyline2d(pl: &Polyline2D) -> TruckEntity {
let verts = &pl.vertices;
let filtered = drawn_vertices2d(pl);
let verts: &[acadrust::entities::Vertex2D] = filtered.as_deref().unwrap_or(&pl.vertices);
if verts.is_empty() {
return TruckEntity {
pick_tris: Vec::new(),
@@ -355,8 +384,9 @@ fn tapered_band_verts_2d(
pl: &acadrust::entities::Polyline2D,
) -> Option<Vec<([f64; 2], f64, f64, f64)>> {
let d = pl.start_width.max(pl.end_width);
let band: Vec<([f64; 2], f64, f64, f64)> = pl
.vertices
let filtered = drawn_vertices2d(pl);
let verts: &[acadrust::entities::Vertex2D] = filtered.as_deref().unwrap_or(&pl.vertices);
let band: Vec<([f64; 2], f64, f64, f64)> = verts
.iter()
.map(|v| {
let sw = if v.start_width > 1e-9 { v.start_width } else { d };
@@ -835,7 +865,8 @@ pub(crate) fn wide_fills(pl: &acadrust::entities::Polyline2D) -> ([f64; 2], Vec<
// The stored widths are the band's FULL width and `polyline_segment_fill`
// offsets ±hw about the centreline — halve them. See `lwpolyline::wide_fills`.
let hw_default = pl.start_width.max(pl.end_width) as f32 * 0.5;
let verts = &pl.vertices;
let filtered = drawn_vertices2d(pl);
let verts: &[acadrust::entities::Vertex2D] = filtered.as_deref().unwrap_or(&pl.vertices);
let n = verts.len();
if n < 2 {
return ([0.0; 2], vec![]);