0027300: Boolean operation produces invalid shape in terms of "bopargcheck" command
authornbv <nbv@opencascade.com>
Tue, 29 Mar 2016 13:29:55 +0000 (16:29 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 8 Apr 2016 08:42:42 +0000 (11:42 +0300)
1. Check, if value found by math_PSO algorithm cannot be precised by math_NewtonMinimum algorithm. In this case, we call math_PSO algorithm repeatedly, however, with other parameters.

2. Some margin of edge tolerance value has been provided in IntTools_Tools class.

3. Interface of math_NewtonMinimum class has been changed (method GetStatus() has been added).

Correction of some test cases according to their new behavior.

src/GeomLib/GeomLib_CheckCurveOnSurface.cxx
src/IntTools/IntTools_Tools.cxx
src/math/math_NewtonMinimum.cxx
src/math/math_NewtonMinimum.hxx
src/math/math_NewtonMinimum.lxx
tests/bugs/modalg_6/bug25613_1
tests/bugs/modalg_6/bug26896_2
tests/bugs/modalg_6/bug27282_1

index 7f8c8a8..88f31d7 100644 (file)
@@ -576,6 +576,56 @@ Standard_Integer FillSubIntervals(const Handle(Geom_Curve)& theCurve3d,
 }
 
 //=======================================================================
+//class   : PSO_Perform
+//purpose : Searches minimal distance with math_PSO class
+//=======================================================================
+Standard_Boolean PSO_Perform(GeomLib_CheckCurveOnSurface_TargetFunc& theFunction,
+                             const math_Vector &theParInf,
+                             const math_Vector &theParSup,
+                             const Standard_Real theEpsilon,
+                             const Standard_Integer theNbParticles, 
+                             Standard_Real& theBestValue,
+                             math_Vector &theOutputParam)
+{
+  const Standard_Real aDeltaParam = theParSup(1) - theParInf(1);
+  if(aDeltaParam < Precision::PConfusion())
+    return Standard_False;
+
+  math_Vector aStepPar(1, 1);
+  aStepPar(1) = theEpsilon*aDeltaParam;
+
+  math_PSOParticlesPool aParticles(theNbParticles, 1);
+
+  //They are used for finding a position of theNbParticles worst places
+  const Standard_Integer aNbControlPoints = 3*theNbParticles;
+
+  const Standard_Real aStep = aDeltaParam/(aNbControlPoints-1);
+  Standard_Integer aCount = 1;
+  for(Standard_Real aPrm = theParInf(1); aCount <= aNbControlPoints; aCount++,
+    aPrm = (aCount == aNbControlPoints)? theParSup(1) : aPrm+aStep)
+  {
+    Standard_Real aVal = RealLast();
+    if(!theFunction.Value(aPrm, aVal))
+      continue;
+
+    PSO_Particle* aParticle = aParticles.GetWorstParticle();
+
+    if(aVal > aParticle->BestDistance)
+      continue;
+
+    aParticle->Position[0] = aPrm;
+    aParticle->BestPosition[0] = aPrm;
+    aParticle->Distance     = aVal;
+    aParticle->BestDistance = aVal;
+  }
+
+  math_PSO aPSO(&theFunction, theParInf, theParSup, aStepPar);
+  aPSO.Perform(aParticles, theNbParticles, theBestValue, theOutputParam);
+
+  return Standard_True;
+}
+
+//=======================================================================
 //class   : MinComputing
 //purpose : Performs computing minimal value
 //=======================================================================
@@ -590,61 +640,52 @@ Standard_Boolean MinComputing (
   {
     OCC_CATCH_SIGNALS
 
-    //They are used for finding a position of theNbParticles worst places
-    const Standard_Integer aNbControlPoints = 3*theNbParticles;
     //
-    math_Vector aParInf(1, 1), aParSup(1, 1), anOutputParam(1, 1), aStepPar(1,1);
+    math_Vector aParInf(1, 1), aParSup(1, 1), anOutputParam(1, 1);
     aParInf(1) = theFunction.FirstParameter();
     aParSup(1) = theFunction.LastParameter();
     theBestParameter = aParInf(1);
     theBestValue = RealLast();
 
-    const Standard_Real aDeltaParam = aParSup(1) - aParInf(1);
-    if(aDeltaParam < Precision::PConfusion())
-        return Standard_False;
-
-    aStepPar(1) = theEpsilon*aDeltaParam;
-
-    math_PSOParticlesPool aParticles(theNbParticles, 1);
-
-    const Standard_Real aStep = aDeltaParam/(aNbControlPoints-1);
-    Standard_Integer aCount = 1;
-    for(Standard_Real aPrm = aParInf(1); aCount <= aNbControlPoints; aCount++,
-                      aPrm = (aCount == aNbControlPoints)? aParSup(1) : aPrm+aStep)
+    if(!PSO_Perform(theFunction, aParInf, aParSup, theEpsilon, theNbParticles,
+                    theBestValue, anOutputParam))
     {
-      Standard_Real aVal = RealLast();
-      theFunction.Value(aPrm, aVal);
-
-      PSO_Particle* aParticle = aParticles.GetWorstParticle();
-
-      if(aVal > aParticle->BestDistance)
-        continue;
-
-      aParticle->Position[0] = aPrm;
-      aParticle->BestPosition[0] = aPrm;
-      aParticle->Distance     = aVal;
-      aParticle->BestDistance = aVal;
+#ifdef OCCT_DEBUG
+      cout << "BRepLib_CheckCurveOnSurface::Compute(): math_PSO is failed!" << endl;
+#endif
+      return Standard_False;
     }
 
-    math_PSO aPSO(&theFunction, aParInf, aParSup, aStepPar);
-    aPSO.Perform(aParticles, theNbParticles, theBestValue, anOutputParam);
+    theBestParameter = anOutputParam(1);
 
     //Here, anOutputParam contains parameter, which is near to optimal.
     //It needs to be more precise. Precision is made by math_NewtonMinimum.
-    math_NewtonMinimum anA(theFunction);
-    anA.Perform(theFunction, anOutputParam);
-
-    if(!anA.IsDone())
-    {
-#ifdef OCCT_DEBUG
-      cout << "BRepLib_CheckCurveOnSurface::Compute(): No solution found!" << endl;
-#endif
-      return Standard_False;
+    math_NewtonMinimum aMinSol(theFunction);
+    aMinSol.Perform(theFunction, anOutputParam);
+
+    if(aMinSol.IsDone() && (aMinSol.GetStatus() == math_OK))
+    {//math_NewtonMinimum has precised the value. We take it.
+      aMinSol.Location(anOutputParam);
+      theBestParameter =  anOutputParam(1);
+      theBestValue = aMinSol.Minimum();
+    }
+    else
+    {//Use math_PSO again but on smaller range.
+      const Standard_Real aStep = theEpsilon*(aParSup(1) - aParInf(1));
+      aParInf(1) = theBestParameter - 0.5*aStep;
+      aParSup(1) = theBestParameter + 0.5*aStep;
+
+      Standard_Real aValue = RealLast();
+      if(PSO_Perform(theFunction, aParInf, aParSup, theEpsilon, theNbParticles,
+                     aValue, anOutputParam))
+      {
+        if(aValue < theBestValue)
+        {
+          theBestValue = aValue;
+          theBestParameter = anOutputParam(1);
+        }
+      }
     }
-
-    anA.Location(anOutputParam);
-    theBestParameter =  anOutputParam(1);
-    theBestValue = anA.Minimum();
   }
   catch(Standard_Failure)
   {
index 9a3c112..c6a71f3 100644 (file)
@@ -797,8 +797,16 @@ Standard_Boolean IntTools_Tools::ComputeTolerance
   if (!aCS.IsDone()) {
     return Standard_False;
   }
-  //
-  theMaxDist = aCS.MaxDistance();
+
+  //Obtaining precise result is impossible if we use 
+  //numeric methods for solution. Therefore, we must provide
+  //some margin. Otherwise, in the future
+  //(when geometrical properties of the curve will be changed,
+  //e.g. after trimming) we will be able to come
+  //to the more precise minimum point. As result, this curve with the
+  //tolerance computed earlier will become invalid.
+  const Standard_Real anEps = (1.0+1.0e-9);
+  theMaxDist = anEps*aCS.MaxDistance();
   theMaxPar  = aCS.MaxParameter();
   //
   return Standard_True;
index 27d7345..d859583 100644 (file)
@@ -140,8 +140,9 @@ void math_NewtonMinimum::Perform(math_MultipleVarFunctionWithHessian& F,
             }
         }
        else {
-           TheStatus = math_FunctionError;
-           return;
+         Done = Standard_False;
+         TheStatus = math_FunctionError;
+         return;
        }
      }
 
index 7de5f81..a344203 100644 (file)
@@ -98,6 +98,11 @@ public:
   //! calculation of the minimum.
   //! The exception NotDone is raised if an error has occured.
     Standard_Integer NbIterations() const;
+
+  //! Returns the Status of computation.
+  //! The exception NotDone is raised if an error has occured.
+    math_Status GetStatus() const;
+
   
   //! Prints on the stream o information on the current state
   //! of the object.
index 2d6852b..78b3fee 100644 (file)
@@ -63,3 +63,7 @@ inline Standard_Integer math_NewtonMinimum::NbIterations() const
    return nbiter;
 }
 
+inline math_Status math_NewtonMinimum::GetStatus() const 
+{
+  return TheStatus;
+}
index 91936d4..1f9b9cd 100644 (file)
@@ -6,8 +6,8 @@ puts ""
 ## Wrong distance found by xdistef command for attached shapes
 ###############################
 
-set Tol 1.0e-14
-set dist_good 8.5127062130336385e-006
+set Tol 5.0e-14
+set dist_good 8.512706220911343e-006
 
 restore [locate_data_file bug698_f.brep] f
 nexplode f e
index 110bab0..5f2a9fa 100755 (executable)
@@ -29,7 +29,7 @@ bsection result b1 f2
 
 regexp {Tolerance +MAX=([-0-9.+eE]+)} [tolerance result] full MaxTolerance
 
-set expected_MaxTolerance 0.0068942263850054935
+set expected_MaxTolerance 0.0068942263920076944
 set tol_abs_MaxTolerance 0.0
 set tol_rel_MaxTolerance 1.0e-4
 checkreal "MaxTolerance" ${MaxTolerance} ${expected_MaxTolerance} ${tol_abs_MaxTolerance} ${tol_rel_MaxTolerance}
index 1efe3b0..2dc5a1e 100644 (file)
@@ -1,5 +1,3 @@
-puts "TODO OCC27300 ALL: ERROR. result is not valid for BOP"
-
 puts "============"
 puts "OCC27282"
 puts "============"