From 0a5ec5f380f52870caa2800e58d77a79a7b1f253 Mon Sep 17 00:00:00 2001 From: abv Date: Mon, 23 Sep 2019 06:34:09 +0300 Subject: [PATCH] 0030990: Foundation Classes - unexpected change in numerical results on bsplines after 0029769 Added DRAW command and test case for detection of inconsistent update of B-Spline surface cache --- src/QABugs/QABugs_20.cxx | 107 +++++++++++++++++++++++++++++++++++ tests/bugs/fclasses/bug30990 | 12 ++++ 2 files changed, 119 insertions(+) create mode 100644 tests/bugs/fclasses/bug30990 diff --git a/src/QABugs/QABugs_20.cxx b/src/QABugs/QABugs_20.cxx index d2e0bd841e..8a7ab78d29 100644 --- a/src/QABugs/QABugs_20.cxx +++ b/src/QABugs/QABugs_20.cxx @@ -3341,6 +3341,112 @@ static Standard_Integer OCC30704_1(Draw_Interpretor& di, Standard_Integer, const return 0; } +//======================================================================= +//function : OCC30990 +//purpose : check consistency of implementation of cache in B-Spline surfaces +// with respect to update of the cache for points located exactly +// on boundary between bspline spans (i.e. at knots) +//======================================================================= +static Standard_Integer OCC30990 (Draw_Interpretor& theDI, Standard_Integer theNArg, const char** theArgV) +{ + if (theNArg != 2) + { + std::cerr << "Use: " << theArgV[0] << "surface\n"; + return 1; + } + + const Handle(Geom_BSplineSurface) aSurf = + Handle(Geom_BSplineSurface)::DownCast (DrawTrSurf::GetSurface(theArgV[1])); + if (aSurf.IsNull()) + { + theDI << "Error: " << theArgV[1] << " is not a B-Spline surface"; + return 0; + } + GeomAdaptor_Surface aS (aSurf); + + // Evaluate points for U and V located exactly at b-spline knots, + // after evaluation of points inside the spans before and after the knot, + // and ensure that result at the knot is exactly the same regardless + // of previous evaluation (i.e. the cache is updated as necessary). + // Note: the points (D0) computed on different spans are slighly different + // due to rounding, which allows us to detect this situation without + // analysis of higher derivatives (which would show non-negligible difference). + Standard_Integer aNbErr = 0; + + theDI << "U knots: "; + for (int i = 1; i <= aSurf->NbUKnots(); i++) + { + theDI << aSurf->UKnot(i); + if (i < aSurf->NbUKnots()) theDI << ","; + } + theDI << "\n"; + for (int i = 2; i < aSurf->NbUKnots(); i++) + { + Standard_Real aUknot = aSurf->UKnot(i); + Standard_Real aUprev = 0.5 * (aUknot + aSurf->UKnot(i-1)); + Standard_Real aUnext = 0.5 * (aUknot + aSurf->UKnot(i+1)); + for (int j = 1; j < aSurf->NbVKnots(); j++) + { + Standard_Real aV = 0.5 * (aSurf->VKnot(j) + aSurf->VKnot(j + 1)); + aS.Value (aUprev, aV); + gp_Pnt aValue1 = aS.Value (aUknot, aV); + aS.Value (aUnext, aV); + gp_Pnt aValue2 = aS.Value (aUknot, aV); + for (int k = 1; k <= 3; k++) + { + if (aValue1.Coord(k) != aValue2.Coord(k)) + { + Standard_SStream aStr; + aStr.precision(20); + aStr << "Error evaluating point at UV = (" << aUknot << ", " << aV << "):\n"; + aStr << "probe 1: " << (char)('X' + k - 1) << " = " << aValue1.Coord(k) << "\n"; + aStr << "probe 2: " << (char)('X' + k - 1) << " = " << aValue2.Coord(k) << "\n"; + theDI << aStr.str().c_str(); + aNbErr++; + } + } + } + } + + theDI << "V knots: "; + for (int j = 1; j <= aSurf->NbVKnots(); j++) + { + theDI << aSurf->VKnot(j); + if (j < aSurf->NbVKnots()) theDI << ","; + } + theDI << "\n"; + for (int j = 2; j < aSurf->NbVKnots(); j++) + { + Standard_Real aVknot = aSurf->VKnot(j); + Standard_Real aVprev = 0.5 * (aVknot + aSurf->VKnot(j-1)); + Standard_Real aVnext = 0.5 * (aVknot + aSurf->VKnot(j+1)); + for (int i = 1; i < aSurf->NbUKnots(); i++) + { + Standard_Real aU = 0.5 * (aSurf->UKnot(i) + aSurf->UKnot(i + 1)); + aS.Value (aU, aVprev); + gp_Pnt aValue1 = aS.Value (aU, aVknot); + aS.Value (aU, aVnext); + gp_Pnt aValue2 = aS.Value (aU, aVknot); + for (int k = 1; k <= 3; k++) + { + if (aValue1.Coord(k) != aValue2.Coord(k)) + { + Standard_SStream aStr; + aStr.precision(20); + aStr << "Error evaluating point at UV = (" << aU << ", " << aVknot << "):\n"; + aStr << "probe 1: " << (char)('X' + k - 1) << " = " << aValue1.Coord(k) << "\n"; + aStr << "probe 2: " << (char)('X' + k - 1) << " = " << aValue2.Coord(k) << "\n"; + theDI << aStr.str().c_str(); + aNbErr++; + } + } + } + } + + theDI << "Total " << aNbErr << " deviations detected"; + return 0; +} + void QABugs::Commands_20(Draw_Interpretor& theCommands) { const char *group = "QABugs"; @@ -3379,6 +3485,7 @@ void QABugs::Commands_20(Draw_Interpretor& theCommands) { theCommands.Add("OCC29311", "OCC29311 shape counter nbiter: check performance of OBB calculation", __FILE__, OCC29311, group); theCommands.Add("OCC30391", "OCC30391 result face LenBeforeUfirst LenAfterUlast LenBeforeVfirst LenAfterVlast", __FILE__, OCC30391, group); theCommands.Add("OCC30435", "OCC30435 result curve inverse nbit", __FILE__, OCC30435, group); + theCommands.Add("OCC30990", "OCC30990 surface", __FILE__, OCC30990, group); theCommands.Add("QAStartsWith", "QAStartsWith string startstring", diff --git a/tests/bugs/fclasses/bug30990 b/tests/bugs/fclasses/bug30990 new file mode 100644 index 0000000000..24179ec86b --- /dev/null +++ b/tests/bugs/fclasses/bug30990 @@ -0,0 +1,12 @@ +puts "# ======================================================================" +puts "# 0030990: Foundation Classes - unexpected change in numerical results on bsplines after 0029769" +puts "# ======================================================================" +puts "" + +pload QAcommands + +restore [locate_data_file bug30990.brep] face +mksurface surf face + +puts "Check consistency of evaluation of BSpline surface at knots" +OCC30990 surf -- 2.20.1