1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-03 17:56:21 +03:00

0027300: Boolean operation produces invalid shape in terms of "bopargcheck" command

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.
This commit is contained in:
nbv 2016-03-29 16:29:55 +03:00 committed by bugmaster
parent cb120537bf
commit 243505b81b
8 changed files with 109 additions and 52 deletions

View File

@ -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)
{

View 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;

View File

@ -140,8 +140,9 @@ void math_NewtonMinimum::Perform(math_MultipleVarFunctionWithHessian& F,
}
}
else {
TheStatus = math_FunctionError;
return;
Done = Standard_False;
TheStatus = math_FunctionError;
return;
}
}

View 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.

View File

@ -63,3 +63,7 @@ inline Standard_Integer math_NewtonMinimum::NbIterations() const
return nbiter;
}
inline math_Status math_NewtonMinimum::GetStatus() const
{
return TheStatus;
}

View 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

View File

@ -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}

View File

@ -1,5 +1,3 @@
puts "TODO OCC27300 ALL: ERROR. result is not valid for BOP"
puts "============"
puts "OCC27282"
puts "============"