diff --git a/CADability/BSpline.cs b/CADability/BSpline.cs index 4404553e7..b1bb7a1ef 100644 --- a/CADability/BSpline.cs +++ b/CADability/BSpline.cs @@ -87,10 +87,40 @@ 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); + +#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); @@ -516,6 +546,7 @@ private void InvalidateSecondaryData() interdir = null; interparam = null; approximation = null; + approxPrecision = 0; extent = BoundingCube.EmptyBoundingCube; tetraederHull = null; extrema = null; @@ -3044,6 +3075,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) { @@ -3161,8 +3222,8 @@ 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) - { // zu kurze machen u.U. Probleme + if (c2d == null) + { // projection failed, return degenerate line Line line = Line.Construct(); line.SetTwoPoints((this as ICurve).StartPoint, (this as ICurve).EndPoint); return line; @@ -3214,6 +3275,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 - 1)); + } + } return Curves.ApproximateLinear(this, pos.ToArray(), maxError); } else