0027048: BSpline cache is always wrong outside of surface
authorazv <azv@opencascade.com>
Thu, 21 Jan 2016 08:35:24 +0000 (11:35 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 28 Jan 2016 10:05:10 +0000 (13:05 +0300)
1. Disable recalculation of B-spline cache when the parameter is out of surface boundary but near the cached span.
2. Rebuild cache each time a curve/surface is loaded into adaptor (B-spline knots may be re-parametrized outside adaptor without changing base curve)
3. Test cases.

src/BSplCLib/BSplCLib_Cache.cxx
src/BSplCLib/BSplCLib_Cache.hxx
src/BSplSLib/BSplSLib_Cache.cxx
src/BSplSLib/BSplSLib_Cache.hxx
src/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx
src/GeomAdaptor/GeomAdaptor_Curve.cxx
src/GeomAdaptor/GeomAdaptor_Surface.cxx
src/QABugs/QABugs_19.cxx
tests/bugs/moddata_3/bug27048_1 [new file with mode: 0644]
tests/bugs/moddata_3/bug27048_2 [new file with mode: 0644]

index 81b6998..275a7b9 100644 (file)
@@ -73,7 +73,8 @@ Standard_Boolean BSplCLib_Cache::IsCacheValid(Standard_Real theParameter) const
     PeriodicNormalization(myFlatKnots->Array1(), aNewParam);
 
   Standard_Real aDelta = aNewParam - mySpanStart;
-  return (aDelta >= 0.0 && (aDelta < mySpanLength || mySpanIndex == mySpanIndexMax));
+  return ((aDelta >= 0.0 || mySpanIndex == mySpanIndexMin) &&
+          (aDelta < mySpanLength || mySpanIndex == mySpanIndexMax));
 }
 
 void BSplCLib_Cache::PeriodicNormalization(const TColStd_Array1OfReal& theFlatKnots, 
@@ -126,6 +127,7 @@ void BSplCLib_Cache::BuildCache(const Standard_Real&           theParameter,
                             aNewParam, thePeriodic, mySpanIndex, aNewParam);
   mySpanStart  = theFlatKnots.Value(mySpanIndex);
   mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart;
+  mySpanIndexMin = thePeriodic ? 0 : myDegree + 1;
   mySpanIndexMax = theFlatKnots.Length() - 1 - theDegree;
 
   // Calculate new cache data
@@ -164,6 +166,7 @@ void BSplCLib_Cache::BuildCache(const Standard_Real&           theParameter,
                             aNewParam, thePeriodic, mySpanIndex, aNewParam);
   mySpanStart  = theFlatKnots.Value(mySpanIndex);
   mySpanLength = theFlatKnots.Value(mySpanIndex + 1) - mySpanStart;
+  mySpanIndexMin = thePeriodic ? 0 : myDegree + 1;
   mySpanIndexMax = theFlatKnots.Length() - 1 - theDegree;
 
   // Calculate new cache data
index f2f8f39..74bcd14 100644 (file)
@@ -167,6 +167,7 @@ private:
   Standard_Real                 mySpanStart;  ///< parameter for the first point of the span
   Standard_Real                 mySpanLength; ///< length of the span
   Standard_Integer              mySpanIndex;  ///< index of the span on Bezier/B-spline curve
+  Standard_Integer              mySpanIndexMin; ///< minimal index of span on Bezier/B-spline curve
   Standard_Integer              mySpanIndexMax; ///< maximal number of spans on Bezier/B-spline curve
   Standard_Integer              myDegree;     ///< degree of Bezier/B-spline
   Handle(TColStd_HArray1OfReal) myFlatKnots;  ///< knots of Bezier/B-spline (used for periodic normalization of parameters, exists only for periodical splines)
index ea8b833..dd9ba2e 100644 (file)
@@ -75,8 +75,10 @@ Standard_Boolean BSplSLib_Cache::IsCacheValid(Standard_Real theParameterU,
 
   Standard_Real aDelta0 = aNewU - mySpanStart[0];
   Standard_Real aDelta1 = aNewV - mySpanStart[1];
-  return (aDelta0 >= -mySpanLength[0] && (aDelta0 < mySpanLength[0] || mySpanIndex[0] == mySpanIndexMax[0]) && 
-          aDelta1 >= -mySpanLength[1] && (aDelta1 < mySpanLength[1] || mySpanIndex[1] == mySpanIndexMax[1]));
+  return ((aDelta0 >= -mySpanLength[0] || mySpanIndex[0] == mySpanIndexMin[0]) &&
+          (aDelta0 < mySpanLength[0] || mySpanIndex[0] == mySpanIndexMax[0]) &&
+          (aDelta1 >= -mySpanLength[1] || mySpanIndex[1] == mySpanIndexMin[1]) &&
+          (aDelta1 < mySpanLength[1] || mySpanIndex[1] == mySpanIndexMax[1]));
 }
 
 void BSplSLib_Cache::PeriodicNormalization(const Standard_Integer& theDegree, 
@@ -164,7 +166,9 @@ void BSplSLib_Cache::BuildCache(const Standard_Real&           theParameterU,
 
   mySpanLength[1] = (theFlatKnotsV.Value(mySpanIndex[1] + 1) - theFlatKnotsV.Value(mySpanIndex[1])) * 0.5;
   mySpanStart[1]  = theFlatKnotsV.Value(mySpanIndex[1]) + mySpanLength[1];
+  mySpanIndexMin[0] = thePeriodicU ? 0 : theDegreeU + 1;
   mySpanIndexMax[0] = theFlatKnotsU.Length() - 1 - theDegreeU;
+  mySpanIndexMin[1] = thePeriodicV ? 0 : theDegreeV + 1;
   mySpanIndexMax[1] = theFlatKnotsV.Length() - 1 - theDegreeV;
 
   // Calculate new cache data
index ac6e596..821cf7e 100644 (file)
@@ -144,6 +144,7 @@ private:
   Standard_Real                 mySpanStart[2];  ///< parameters (u, v) for the frst point of the span
   Standard_Real                 mySpanLength[2]; ///< lengths of the span along corresponding parameter
   Standard_Integer              mySpanIndex[2];  ///< indexes of the span on Bezier/B-spline surface
+  Standard_Integer              mySpanIndexMin[2]; ///< minimal indexes of span
   Standard_Integer              mySpanIndexMax[2]; ///< maximal indexes of span
   Standard_Integer              myDegree[2];     ///< degrees of Bezier/B-spline for each parameter
   Handle(TColStd_HArray1OfReal) myFlatKnots[2];  ///< arrays of knots of Bezier/B-spline 
index 983e46c..3b6c945 100644 (file)
@@ -237,6 +237,8 @@ void Geom2dAdaptor_Curve::load(const Handle(Geom2d_Curve)& C,
       myTypeCurve = GeomAbs_OtherCurve;
     }
   }
+  else // rebuild cache of Bezier and B-spline curve even if the loaded curve is same
+    RebuildCache(myFirst);
 }
 
 //    --
index 39647ad..ddd5996 100644 (file)
@@ -194,7 +194,9 @@ void GeomAdaptor_Curve::load(const Handle(Geom_Curve)& C,
       myTypeCurve = GeomAbs_OtherCurve;
     }
   }
-}  
+  else // rebuild cache of Bezier and B-spline curve even if the loaded curve is same
+    RebuildCache(myFirst);
+}
 
 //    --
 //    --     Global methods - Apply to the whole curve.
index 973b915..11723d6 100644 (file)
@@ -217,6 +217,8 @@ void GeomAdaptor_Surface::load(const Handle(Geom_Surface)& S,
     else
       mySurfaceType = GeomAbs_OtherSurface;
   }
+  else // rebuild cache of Bezier and B-spline surface even if the loaded surface is same
+    RebuildCache(myUFirst, myVFirst);
 }
 
 //    --
index 98aa2a3..7ee6034 100644 (file)
@@ -5027,6 +5027,32 @@ static Standard_Integer OCC26945_close (Draw_Interpretor& theDI, Standard_Intege
   return 0;
 }
 
+//=======================================================================
+//function : OCC27048
+//purpose  : Calculate value of B-spline surface N times
+//=======================================================================
+static Standard_Integer OCC27048(Draw_Interpretor& theDI, Standard_Integer theArgc, const char** theArgv)
+{
+  if (theArgc != 5)
+  {
+    std::cout << "Incorrect number of arguments. See usage:" << std::endl;
+    theDI.PrintHelp(theArgv[0]);
+    return 1;
+  }
+
+  Handle(Geom_Surface) aSurf = DrawTrSurf::GetSurface(theArgv[1]);
+  GeomAdaptor_Surface anAdaptor(aSurf);
+
+  Standard_Real aU = Draw::Atof(theArgv[2]);
+  Standard_Real aV = Draw::Atof(theArgv[3]);
+  Standard_Integer aN = Draw::Atoi(theArgv[4]);
+
+  for (; aN > 0; --aN)
+    anAdaptor.Value(aU, aV);
+
+  return 0;
+}
+
 void QABugs::Commands_19(Draw_Interpretor& theCommands) {
   const char *group = "QABugs";
 
@@ -5132,6 +5158,10 @@ void QABugs::Commands_19(Draw_Interpretor& theCommands) {
                    "OCC26945 localCtxToClose"
                    "\n\t\t: Closes local context with the ID localCtxToClose",
                    __FILE__, OCC26945_close, group);
+
+  theCommands.Add ("OCC27048",
+                   "OCC27048 surf U V N\nCalculate value of surface N times in the point (U, V)",
+                   __FILE__, OCC27048, group);
   
   return;
 }
diff --git a/tests/bugs/moddata_3/bug27048_1 b/tests/bugs/moddata_3/bug27048_1
new file mode 100644 (file)
index 0000000..4bfe0e1
--- /dev/null
@@ -0,0 +1,34 @@
+puts "============"
+puts "OCC27048"
+puts "============"
+puts ""
+############################################################################
+#  Recalculation of BSpline cache causes a performance problems
+############################################################################
+
+pload QAcommands
+
+bsplinesurf surf \
+3 4 0 4 1 1 2 1 3 4 \
+3 4 0 4 1 1 2 1 3 4 \
+0  0  0 1   2  0  0 1   3  0 15 1   5  0 15 1   7  0  0 1   10  0  0 1 \
+0  2  0 1   1  3  0 1   4  2 15 1   6  3 15 1   8  2  0 1   10  3  0 1 \
+0  4  0 1   3  4  0 1   4  3 15 1   5  3 15 1   7  4  0 1   10  5  0 1 \
+0  6  0 1   3  6  0 1   4  6 15 1   5  6 15 1   8  5  0 1   10  7  0 1 \
+0  8  0 1   2  8  0 1   4  8 15 1   6  8 15 1   7  7  0 1   10  8  0 1 \
+0 10  0 1   2 10  0 1   4 10 15 1   6 10 15 1   7 10  0 1   10 10  0 1
+
+dchrono t reset
+dchrono t start
+OCC27048 surf -0.1 -0.1 1000000
+dchrono t stop
+set elapsed [dchrono t show]
+
+regexp {CPU user time: ([-0-9.+eE]+) seconds} $elapsed full cpu_time
+set max_time 1
+
+if { $cpu_time > ${max_time} } {
+    puts "Error: calculating B-spline value takes too long time (greater than ${max_time} sec)"
+} else {
+    puts "OK: performance calculating B-spline is suitable"
+}
diff --git a/tests/bugs/moddata_3/bug27048_2 b/tests/bugs/moddata_3/bug27048_2
new file mode 100644 (file)
index 0000000..0ff2043
--- /dev/null
@@ -0,0 +1,28 @@
+puts "============"
+puts "OCC27048"
+puts "============"
+puts ""
+############################################################################
+#  Recalculation of BSpline cache causes a performance problems
+############################################################################
+
+pload XSDRAW
+
+dchrono t reset
+dchrono t start
+testreadstep [locate_data_file bug27048.stp] result
+dchrono t stop
+set elapsed [dchrono t show]
+
+regexp {CPU user time: ([-0-9.+eE]+) seconds} $elapsed full cpu_time
+set max_time 40
+
+if { $cpu_time > ${max_time} } {
+    puts "Error: reading document Doc is too long (greater than ${max_time} sec)"
+} else {
+    puts "OK: performance reading document Doc is suitable"
+}
+
+smallview
+fit
+set only_screen_axo 1