diff --git a/src/GeomLib/GeomLib_CheckCurveOnSurface.cxx b/src/GeomLib/GeomLib_CheckCurveOnSurface.cxx index 7f8c8a8ae6..88f31d7c51 100644 --- a/src/GeomLib/GeomLib_CheckCurveOnSurface.cxx +++ b/src/GeomLib/GeomLib_CheckCurveOnSurface.cxx @@ -575,6 +575,56 @@ Standard_Integer FillSubIntervals(const Handle(Geom_Curve)& theCurve3d, return aNbSubIntervals; } +//======================================================================= +//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) - { - 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; - } - - math_PSO aPSO(&theFunction, aParInf, aParSup, aStepPar); - aPSO.Perform(aParticles, theNbParticles, theBestValue, anOutputParam); - - //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()) + if(!PSO_Perform(theFunction, aParInf, aParSup, theEpsilon, theNbParticles, + theBestValue, anOutputParam)) { #ifdef OCCT_DEBUG - cout << "BRepLib_CheckCurveOnSurface::Compute(): No solution found!" << endl; + cout << "BRepLib_CheckCurveOnSurface::Compute(): math_PSO is failed!" << endl; #endif return Standard_False; } - anA.Location(anOutputParam); - theBestParameter = anOutputParam(1); - theBestValue = anA.Minimum(); + 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 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); + } + } + } } catch(Standard_Failure) { diff --git a/src/IntTools/IntTools_Tools.cxx b/src/IntTools/IntTools_Tools.cxx index 9a3c1123aa..c6a71f3ca8 100644 --- a/src/IntTools/IntTools_Tools.cxx +++ b/src/IntTools/IntTools_Tools.cxx @@ -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; diff --git a/src/math/math_NewtonMinimum.cxx b/src/math/math_NewtonMinimum.cxx index 27d73450ae..d8595833cd 100644 --- a/src/math/math_NewtonMinimum.cxx +++ b/src/math/math_NewtonMinimum.cxx @@ -140,8 +140,9 @@ void math_NewtonMinimum::Perform(math_MultipleVarFunctionWithHessian& F, } } else { - TheStatus = math_FunctionError; - return; + Done = Standard_False; + TheStatus = math_FunctionError; + return; } } diff --git a/src/math/math_NewtonMinimum.hxx b/src/math/math_NewtonMinimum.hxx index 7de5f81d83..a344203a16 100644 --- a/src/math/math_NewtonMinimum.hxx +++ b/src/math/math_NewtonMinimum.hxx @@ -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. diff --git a/src/math/math_NewtonMinimum.lxx b/src/math/math_NewtonMinimum.lxx index 2d6852b97f..78b3fee14c 100644 --- a/src/math/math_NewtonMinimum.lxx +++ b/src/math/math_NewtonMinimum.lxx @@ -63,3 +63,7 @@ inline Standard_Integer math_NewtonMinimum::NbIterations() const return nbiter; } +inline math_Status math_NewtonMinimum::GetStatus() const +{ + return TheStatus; +} diff --git a/tests/bugs/modalg_6/bug25613_1 b/tests/bugs/modalg_6/bug25613_1 index 91936d4e1d..1f9b9cd322 100644 --- a/tests/bugs/modalg_6/bug25613_1 +++ b/tests/bugs/modalg_6/bug25613_1 @@ -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 diff --git a/tests/bugs/modalg_6/bug26896_2 b/tests/bugs/modalg_6/bug26896_2 index 110bab0985..5f2a9fa08e 100755 --- a/tests/bugs/modalg_6/bug26896_2 +++ b/tests/bugs/modalg_6/bug26896_2 @@ -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} diff --git a/tests/bugs/modalg_6/bug27282_1 b/tests/bugs/modalg_6/bug27282_1 index 1efe3b05a8..2dc5a1efb6 100644 --- a/tests/bugs/modalg_6/bug27282_1 +++ b/tests/bugs/modalg_6/bug27282_1 @@ -1,5 +1,3 @@ -puts "TODO OCC27300 ALL: ERROR. result is not valid for BOP" - puts "============" puts "OCC27282" puts "============"