From b79f652e0a9ba86c9e60309bac2c2b87442a9d77 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 Jan 2026 19:20:44 +0000 Subject: [PATCH 1/9] Initial plan From 1833ca7679d865f0c2f44838eb06c6ccc8e30821 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 Jan 2026 19:25:16 +0000 Subject: [PATCH 2/9] Fix BSpline rendering issue by correcting approximation cache condition Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 4404553e7..61832e6cb 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -87,7 +87,7 @@ private GeoPoint[] GetCashedApproximation(double precision) { lock (lockApproximationRecalc) { - if (((precision > 0) && (approxPrecision > precision)) || approximation == null) + if (approximation == null || approxPrecision == 0 || (precision > 0 && approxPrecision > precision)) { approxPrecision = precision; ICurve cv = (this as ICurve).Approximate(true, precision); From 53f0771ec8b236dba90dbc6119b5523f0c17f19c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 Jan 2026 19:39:41 +0000 Subject: [PATCH 3/9] Fix: Handle negative precision and reset approxPrecision on invalidation Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 61832e6cb..a822b7103 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -87,7 +87,7 @@ private GeoPoint[] GetCashedApproximation(double precision) { lock (lockApproximationRecalc) { - if (approximation == null || approxPrecision == 0 || (precision > 0 && approxPrecision > precision)) + if (approximation == null || approxPrecision <= 0 || (precision > 0 && approxPrecision > precision)) { approxPrecision = precision; ICurve cv = (this as ICurve).Approximate(true, precision); @@ -516,6 +516,7 @@ private void InvalidateSecondaryData() interdir = null; interparam = null; approximation = null; + approxPrecision = 0; extent = BoundingCube.EmptyBoundingCube; tetraederHull = null; extrema = null; From a005b0930c244633684b2b39160c8ba9bbecf4f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 06:57:34 +0000 Subject: [PATCH 4/9] Fix: Remove incorrect length check that simplified small valid curves to lines Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index a822b7103..101cf0b6b 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -3162,7 +3162,7 @@ ICurve ICurve.Approximate(bool linesOnly, double maxError) { Plane pl = (this as ICurve).GetPlane(); ICurve2D c2d = (this as ICurve).GetProjectedCurve(pl); - if (c2d == null || c2d.Length < maxError) + if (c2d == null) { // zu kurze machen u.U. Probleme Line line = Line.Construct(); line.SetTwoPoints((this as ICurve).StartPoint, (this as ICurve).EndPoint); From efe907b02a7521b4391b3bf296bc2bbe7bea6a2a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 06:58:34 +0000 Subject: [PATCH 5/9] Update comment to reflect removed length check Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 101cf0b6b..0f743ec7e 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -3163,7 +3163,7 @@ ICurve ICurve.Approximate(bool linesOnly, double maxError) Plane pl = (this as ICurve).GetPlane(); ICurve2D c2d = (this as ICurve).GetProjectedCurve(pl); if (c2d == null) - { // zu kurze machen u.U. Probleme + { // projection failed, return degenerate line Line line = Line.Construct(); line.SetTwoPoints((this as ICurve).StartPoint, (this as ICurve).EndPoint); return line; From ed52d671cc329be2d9b0ce4687f3d062ce23b2b2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 07:11:03 +0000 Subject: [PATCH 6/9] Fix: Filter identical poles when projecting BSpline to 2D Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 0f743ec7e..243c66b40 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -3045,6 +3045,36 @@ CADability.Curve2D.ICurve2D ICurve.GetProjectedCurve(Plane p) } else { + // When poles become identical after projection, we need to filter them out + // and create a BSpline2D with the unique poles + List uniquePoles = new List(); + List uniqueWeights = new List(); + uniquePoles.Add(poles2d[0]); + uniqueWeights.Add(weights[0]); + for (int i = 1; i < poles2d.Length; i++) + { + if (!Precision.IsEqual(poles2d[i], uniquePoles[uniquePoles.Count - 1])) + { + uniquePoles.Add(poles2d[i]); + uniqueWeights.Add(weights[i]); + } + } + + // If we have enough unique poles, try to create a BSpline2D + if (uniquePoles.Count >= degree + 1) + { + try + { + BSpline2D bsp2d = new BSpline2D(uniquePoles.ToArray(), degree, this.periodic); + return bsp2d; + } + catch + { + // Fall through to throughPoints approach + } + } + + // Fallback: create through points List throughPoints2d = new List(); if (ThroughPoints3dExist) { From 48659f26c27fe248c06d7bc1e6209c05fcf04439 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 07:38:20 +0000 Subject: [PATCH 7/9] Fix: Ensure minimum sample points for non-planar spline approximation Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 243c66b40..6579899ea 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -3245,6 +3245,17 @@ ICurve ICurve.Approximate(bool linesOnly, double maxError) } } pos.Add(1.0); + // Ensure we have enough sample points even if the curve appears linear + // This prevents circular/curved splines from being simplified to lines + if (pos.Count < 5) + { + pos.Clear(); + int minSamples = Math.Max(5, knots.Length); + for (int i = 0; i <= minSamples; ++i) + { + pos.Add((double)i / (double)minSamples); + } + } return Curves.ApproximateLinear(this, pos.ToArray(), maxError); } else From d61ee8d61da5089577d3a7b36656c27612f024fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 07:39:26 +0000 Subject: [PATCH 8/9] Fix off-by-one error in sample point generation Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 6579899ea..57d7101b0 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -3251,9 +3251,9 @@ ICurve ICurve.Approximate(bool linesOnly, double maxError) { pos.Clear(); int minSamples = Math.Max(5, knots.Length); - for (int i = 0; i <= minSamples; ++i) + for (int i = 0; i < minSamples; ++i) { - pos.Add((double)i / (double)minSamples); + pos.Add((double)i / (double)(minSamples - 1)); } } return Curves.ApproximateLinear(this, pos.ToArray(), maxError); From 4727a43a1c6857fc6039e6812fe6792005ce1c26 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 07:49:51 +0000 Subject: [PATCH 9/9] Add debug output to GetCashedApproximation for diagnostics Co-authored-by: dsn27 <45662116+dsn27@users.noreply.github.com> --- CADability/BSpline.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 57d7101b0..b1bb7a1ef 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -91,6 +91,36 @@ private GeoPoint[] GetCashedApproximation(double precision) { approxPrecision = precision; ICurve cv = (this as ICurve).Approximate(true, precision); + +#if DEBUG + // Debug output to help diagnose approximation issues + System.Diagnostics.Debug.WriteLine("=== BSpline Approximation Debug ==="); + System.Diagnostics.Debug.WriteLine($"Precision: {precision}"); + System.Diagnostics.Debug.WriteLine($"Poles count: {poles?.Length ?? 0}"); + System.Diagnostics.Debug.WriteLine($"Knots count: {knots?.Length ?? 0}"); + System.Diagnostics.Debug.WriteLine($"Degree: {degree}"); + System.Diagnostics.Debug.WriteLine($"Periodic: {periodic}"); + System.Diagnostics.Debug.WriteLine($"StartParam: {startParam}, EndParam: {endParam}"); + System.Diagnostics.Debug.WriteLine($"PlanarState: {(this as ICurve).GetPlanarState()}"); + System.Diagnostics.Debug.WriteLine($"Approximation result type: {cv?.GetType().Name ?? "null"}"); + if (cv is Line line) + { + System.Diagnostics.Debug.WriteLine($" Line: Start={line.StartPoint}, End={line.EndPoint}"); + System.Diagnostics.Debug.WriteLine($" Line Length: {line.Length}"); + } + else if (cv is Polyline polyline) + { + System.Diagnostics.Debug.WriteLine($" Polyline: {polyline.PointCount} points, Length={polyline.Length}"); + } + else if (cv is Path path) + { + System.Diagnostics.Debug.WriteLine($" Path: {path.CurveCount} curves, Length={path.Length}"); + } + System.Diagnostics.Debug.WriteLine($"Original BSpline: Start={StartPoint}, End={EndPoint}"); + System.Diagnostics.Debug.WriteLine($"Original BSpline Length: {(this as ICurve).Length}"); + System.Diagnostics.Debug.WriteLine("====================================="); +#endif + if (cv is Path) { Path path = (cv as Path);