Skip to content
78 changes: 75 additions & 3 deletions CADability/BSpline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -516,6 +546,7 @@ private void InvalidateSecondaryData()
interdir = null;
interparam = null;
approximation = null;
approxPrecision = 0;
extent = BoundingCube.EmptyBoundingCube;
tetraederHull = null;
extrema = null;
Expand Down Expand Up @@ -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<GeoPoint2D> uniquePoles = new List<GeoPoint2D>();
List<double> uniqueWeights = new List<double>();
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<GeoPoint2D> throughPoints2d = new List<GeoPoint2D>();
if (ThroughPoints3dExist)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down