From c64d8a359fa6dedf9f42243a9f60bd8d43c28905 Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Fri, 11 Sep 2026 14:59:32 +0300 Subject: [PATCH] Bound fit-only splines through their interpolated control hull --- src/entities/spline.rs | 24 ++++++++++++++++++++++++ src/scene/convert/tess.rs | 5 +++++ 2 files changed, 29 insertions(+) diff --git a/src/entities/spline.rs b/src/entities/spline.rs index 5c143ea47..51ae50541 100644 --- a/src/entities/spline.rs +++ b/src/entities/spline.rs @@ -21,6 +21,30 @@ pub(crate) fn shows_fit_points(spline: &Spline) -> bool { uses_fit_method(spline) && (!spline.cv_frame_visible || spline.flags.periodic) } +/// Conservative world bounds of a fit-only spline. Fit points are interpolation +/// constraints, not control-hull vertices, so their box can exclude the curve. +/// The shared kernel reconstructs the same spatial interpolation used by the +/// curve consumers, then its control hull bounds every point of that curve. +pub(crate) fn fit_geometry_bounds(spline: &Spline) -> Option { + if !spline.control_points.is_empty() || spline.fit_points.len() < 2 { return None; } + use cadkernel::space::{NurbsCurve3, Parameterization}; + let points: Vec<_> = spline.fit_points.iter().map(|p| [p.x,p.y,p.z]).collect(); + let parameterization = match spline.knot_parameterization { + 1 => Parameterization::Centripetal, 2 => Parameterization::Uniform, + _ => Parameterization::Chord, + }; + let curve = if spline.flags.periodic { + NurbsCurve3::interpolate_periodic(&points, parameterization)? + } else { + if spline.flags.closed { return None; } + NurbsCurve3::interpolate_fit(&points, + Some([spline.begin_tangent.x,spline.begin_tangent.y,spline.begin_tangent.z]), + Some([spline.end_tangent.x,spline.end_tangent.y,spline.end_tangent.z]), + parameterization)? + }; + let curve = curve.compact_knots(spline.control_tolerance.max(1e-9))?; + cadkernel::brep::Aabb::around(curve.control_points().iter().copied()) +} fn to_render(spl: &Spline) -> RenderEntity { let n = spl.control_points.len(); if n < 2 { diff --git a/src/scene/convert/tess.rs b/src/scene/convert/tess.rs index a84d3d60d..db78e6930 100644 --- a/src/scene/convert/tess.rs +++ b/src/scene/convert/tess.rs @@ -1731,6 +1731,11 @@ fn entity_bounds(e: &acadrust::EntityType) -> ([f64; 3], [f64; 3]) { return (bounds.min, bounds.max); } } + if let acadrust::EntityType::Spline(spline) = e { + if let Some(bounds) = crate::entities::spline::fit_geometry_bounds(spline) { + return (bounds.min, bounds.max); + } + } let bounds = e.as_entity().bounding_box(); ( [bounds.min.x, bounds.min.y, bounds.min.z],