1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0026938: Boolean operations fail between two ellipsoids

Treatment for single singular point is added.
Test cases are updated to the new behavior.
New test cases are added,
Message of "bad" state is corrected.
This commit is contained in:
aml
2016-05-13 13:36:33 +03:00
committed by bugmaster
parent 871776ea38
commit 882e1d11aa
14 changed files with 254 additions and 229 deletions

View File

@@ -113,7 +113,8 @@ static void IsParallel(const Handle(IntSurf_LineOn2S)& theLine,
theIsUparallel = theIsVparallel = Standard_True;
Standard_Integer aNbPoints = theLine->NbPoints();
const Standard_Integer aNbLinePnts = theLine->NbPoints();
Standard_Integer aNbPoints = aNbLinePnts;
if(aNbPoints > aNbPointsMAX)
{
aNbPoints = aNbPointsMAX;
@@ -131,10 +132,9 @@ static void IsParallel(const Handle(IntSurf_LineOn2S)& theLine,
Standard_Real aUmin = RealLast(), aUmax = RealFirst(), aVmin = RealLast(), aVmax = RealFirst();
for(Standard_Integer aNum = 1; aNum <= aNbPoints; aNum++, aNPoint += aStep)
{
if(aNPoint > aNbPoints)
{
aNPoint = aNbPoints;
}
// Fix possible "out of parameter" case.
if (aNPoint > aNbLinePnts)
aNPoint = aNbLinePnts;
Standard_Real u, v;
if(theCheckSurf1)
@@ -159,100 +159,6 @@ static void IsParallel(const Handle(IntSurf_LineOn2S)& theLine,
theIsUparallel = ((aVmax - aVmin) < theToler);
}
//=======================================================================
//function : Checking
//purpose : Check, if given point is in surface's boundaries.
// If "yes" then theFactTol = 0.0, else theFactTol is
// equal maximal deviation.
//=======================================================================
static Standard_Boolean Checking( const Handle(Adaptor3d_HSurface)& theASurf1,
const Handle(Adaptor3d_HSurface)& theASurf2,
Standard_Real& theU1,
Standard_Real& theV1,
Standard_Real& theU2,
Standard_Real& theV2,
Standard_Real& theFactTol)
{
const Standard_Real aTol = Precision::PConfusion();
const Standard_Real aU1bFirst = theASurf1->FirstUParameter();
const Standard_Real aU1bLast = theASurf1->LastUParameter();
const Standard_Real aU2bFirst = theASurf2->FirstUParameter();
const Standard_Real aU2bLast = theASurf2->LastUParameter();
const Standard_Real aV1bFirst = theASurf1->FirstVParameter();
const Standard_Real aV1bLast = theASurf1->LastVParameter();
const Standard_Real aV2bFirst = theASurf2->FirstVParameter();
const Standard_Real aV2bLast = theASurf2->LastVParameter();
Standard_Boolean isOnOrIn = Standard_True;
theFactTol = 0.0;
Standard_Real aDelta = aU1bFirst - theU1;
if(aDelta > aTol)
{
theU1 = aU1bFirst;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = theU1 - aU1bLast;
if(aDelta > aTol)
{
theU1 = aU1bLast;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = aV1bFirst - theV1;
if(aDelta > aTol)
{
theV1 = aV1bFirst;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = theV1 - aV1bLast;
if(aDelta > aTol)
{
theV1 = aV1bLast;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = aU2bFirst - theU2;
if(aDelta > aTol)
{
theU2 = aU2bFirst;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = theU2 - aU2bLast;
if(aDelta > aTol)
{
theU2 = aU2bLast;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = aV2bFirst - theV2;
if(aDelta > aTol)
{
theV2 = aV2bFirst;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
aDelta = theV2 - aV2bLast;
if(aDelta > aTol)
{
theV2 = aV2bLast;
theFactTol = Max(theFactTol, aDelta);
isOnOrIn = Standard_False;
}
return isOnOrIn;
}
//==================================================================================
// function : IntWalk_PWalking::IntWalk_PWalking
// purpose :
@@ -2260,6 +2166,55 @@ DistanceMinimizeByExtrema(const Handle(Adaptor3d_HSurface)& theASurf,
return (aSQDistPrev < aTol);
}
//=======================================================================
//function : HandleSingleSingularPoint
//purpose :
//=======================================================================
Standard_Boolean IntWalk_PWalking::HandleSingleSingularPoint(const Handle(Adaptor3d_HSurface)& theASurf1,
const Handle(Adaptor3d_HSurface)& theASurf2,
const Standard_Real the3DTol,
TColStd_Array1OfReal &thePnt)
{
// u1, v1, u2, v2 order is used.
Standard_Real aLowBorder[4] = {theASurf1->FirstUParameter(),
theASurf1->FirstVParameter(),
theASurf2->FirstUParameter(),
theASurf2->FirstVParameter()};
Standard_Real aUppBorder[4] = {theASurf1->LastUParameter(),
theASurf1->LastVParameter(),
theASurf2->LastUParameter(),
theASurf2->LastVParameter()};
IntImp_ConstIsoparametric aLockedDir[4] = {IntImp_UIsoparametricOnCaro1,
IntImp_VIsoparametricOnCaro1,
IntImp_UIsoparametricOnCaro2,
IntImp_VIsoparametricOnCaro2};
// Create new intersector with new tolerance.
IntWalk_TheInt2S anInt(theASurf1, theASurf2, the3DTol);
math_FunctionSetRoot aRsnld(anInt.Function());
for (Standard_Integer i = 1; i <= 4; ++i)
{
if ( Abs(thePnt(i) - aLowBorder[i - 1]) < Precision::PConfusion() ||
Abs(thePnt(i) - aUppBorder[i - 1]) < Precision::PConfusion())
{
anInt.Perform(thePnt,aRsnld, aLockedDir[i - 1]);
if (!anInt.IsDone())
continue;
if (anInt.IsEmpty())
continue;
anInt.Point().Parameters(thePnt(1), thePnt(2), thePnt(3), thePnt(4));
return Standard_True;
}
}
return Standard_False;
}
//=======================================================================
//function : SeekPointOnBoundary
//purpose :
@@ -2273,79 +2228,64 @@ SeekPointOnBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
const Standard_Real theV2,
const Standard_Boolean isTheFirst)
{
const Standard_Real aTol = 1.0e-14;
Standard_Boolean isOK = Standard_False;
Standard_Real U1prec = theU1, V1prec = theV1, U2prec = theU2, V2prec = theV2;
Standard_Boolean flFinish = Standard_False;
// Tune solution tolerance according with object size.
const Standard_Real aRes1 = Max(Precision::PConfusion() / theASurf1->UResolution(1.0),
Precision::PConfusion() / theASurf1->VResolution(1.0));
const Standard_Real aRes2 = Max(Precision::PConfusion() / theASurf2->UResolution(1.0),
Precision::PConfusion() / theASurf2->VResolution(1.0));
const Standard_Real a3DTol = Max(aRes1, aRes2);
const Standard_Real aTol = Max(Precision::Confusion(), a3DTol);
// u1, v1, u2, v2 order is used.
TColStd_Array1OfReal aPnt(1,4);
aPnt(1) = theU1; aPnt(2) = theV1; aPnt(3) = theU2; aPnt(4) = theV2;
TColStd_Array1OfReal aSingularPnt(aPnt);
Standard_Integer aNbIter = 20;
while(!flFinish)
Standard_Boolean aStatus = Standard_False;
do
{
flFinish = Standard_False;
Standard_Boolean aStatus = Standard_False;
do
{
aNbIter--;
aStatus = DistanceMinimizeByGradient(theASurf1, theASurf2, U1prec, V1prec, U2prec, V2prec);
if(aStatus)
{
break;
}
aStatus = DistanceMinimizeByExtrema(theASurf1, theASurf2->Value(U2prec, V2prec), U1prec, V1prec);
if(aStatus)
{
break;
}
aStatus = DistanceMinimizeByExtrema(theASurf2, theASurf1->Value(U1prec, V1prec), U2prec, V2prec);
if(aStatus)
{
break;
}
}
while(!aStatus && (aNbIter > 0));
aNbIter--;
aStatus = DistanceMinimizeByGradient(theASurf1, theASurf2, aPnt(1), aPnt(2), aPnt(3), aPnt(4));
if(aStatus)
{
const Standard_Real aTolMax = 1.0e-8;
Standard_Real aTolF = 0.0;
Standard_Real u1 = U1prec, v1 = V1prec, u2 = U2prec, v2 = V2prec;
flFinish = Checking(theASurf1, theASurf2, U1prec, V1prec, U2prec, V2prec, aTolF);
if(aTolF <= aTolMax)
{
gp_Pnt aP1 = theASurf1->Value(u1, v1),
aP2 = theASurf2->Value(u2, v2);
gp_Pnt aPInt(0.5*(aP1.XYZ() + aP2.XYZ()));
const Standard_Real aSQDist1 = aPInt.SquareDistance(aP1),
aSQDist2 = aPInt.SquareDistance(aP2);
if((aSQDist1 < aTol) && (aSQDist2 < aTol))
{
IntSurf_PntOn2S anIP;
anIP.SetValue(aPInt, u1, v1, u2, v2);
if(isTheFirst)
line->InsertBefore(1,anIP);
else
line->Add(anIP);
isOK = Standard_True;
}
}
}
else
{
break;
}
if(aNbIter < 0)
aStatus = DistanceMinimizeByExtrema(theASurf1, theASurf2->Value(aPnt(3), aPnt(4)), aPnt(1), aPnt(2));
if(aStatus)
break;
aStatus = DistanceMinimizeByExtrema(theASurf2, theASurf1->Value(aPnt(1), aPnt(2)), aPnt(3), aPnt(4));
if(aStatus)
break;
}
while(!aStatus && (aNbIter > 0));
// Handle singular points.
Standard_Boolean aSingularStatus = HandleSingleSingularPoint(theASurf1, theASurf2, aTol, aSingularPnt);
if (aSingularStatus)
aPnt = aSingularPnt;
if(aStatus || aSingularStatus)
{
gp_Pnt aP1 = theASurf1->Value(aPnt(1), aPnt(2)),
aP2 = theASurf2->Value(aPnt(3), aPnt(4));
gp_Pnt aPInt(0.5*(aP1.XYZ() + aP2.XYZ()));
const Standard_Real aSQDist = aPInt.SquareDistance(aP1);
if (aSQDist < aTol * aTol)
{
IntSurf_PntOn2S anIP;
anIP.SetValue(aPInt, aPnt(1), aPnt(2), aPnt(3), aPnt(4));
if(isTheFirst)
line->InsertBefore(1,anIP);
else
line->Add(anIP);
isOK = Standard_True;
}
}
return isOK;
@@ -2396,7 +2336,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = u1 - aU1bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u1 = aU1bFirst - aDelta;
u1 = aU1bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2404,7 +2344,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aU1bLast - u1;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u1 = aU1bLast + aDelta;
u1 = aU1bLast;
isNeedAdding = Standard_True;
}
}
@@ -2415,7 +2355,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = u2 - aU2bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u2 = aU2bFirst - aDelta;
u2 = aU2bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2423,7 +2363,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aU2bLast - u2;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u2 = aU2bLast + aDelta;
u2 = aU2bLast;
isNeedAdding = Standard_True;
}
}
@@ -2434,7 +2374,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = v1 - aV1bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v1 = aV1bFirst - aDelta;
v1 = aV1bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2442,7 +2382,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aV1bLast - v1;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v1 = aV1bLast + aDelta;
v1 = aV1bLast;
isNeedAdding = Standard_True;
}
}
@@ -2453,7 +2393,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = v2 - aV2bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v2 = aV2bFirst - aDelta;
v2 = aV2bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2461,7 +2401,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aV2bLast - v2;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v2 = aV2bLast + aDelta;
v2 = aV2bLast;
isNeedAdding = Standard_True;
}
}
@@ -2483,7 +2423,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = u1 - aU1bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u1 = aU1bFirst - aDelta;
u1 = aU1bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2491,7 +2431,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aU1bLast - u1;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u1 = aU1bLast + aDelta;
u1 = aU1bLast;
isNeedAdding = Standard_True;
}
}
@@ -2502,7 +2442,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = u2 - aU2bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u2 = aU2bFirst - aDelta;
u2 = aU2bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2510,7 +2450,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aU2bLast - u2;
if((aTolMin < aDelta) && (aDelta < aTol))
{
u2 = aU2bLast + aDelta;
u2 = aU2bLast;
isNeedAdding = Standard_True;
}
}
@@ -2521,7 +2461,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = v1 - aV1bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v1 = aV1bFirst - aDelta;
v1 = aV1bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2529,7 +2469,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aV1bLast - v1;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v1 = aV1bLast + aDelta;
v1 = aV1bLast;
isNeedAdding = Standard_True;
}
}
@@ -2540,7 +2480,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = v2 - aV2bFirst;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v2 = aV2bFirst - aDelta;
v2 = aV2bFirst;
isNeedAdding = Standard_True;
}
else
@@ -2548,7 +2488,7 @@ PutToBoundary(const Handle(Adaptor3d_HSurface)& theASurf1,
aDelta = aV2bLast - v2;
if((aTolMin < aDelta) && (aDelta < aTol))
{
v2 = aV2bLast + aDelta;
v2 = aV2bLast;
isNeedAdding = Standard_True;
}
}

View File

@@ -167,6 +167,11 @@ private:
Standard_EXPORT Standard_Boolean SeekPointOnBoundary (const Handle(Adaptor3d_HSurface)& theASurf1, const Handle(Adaptor3d_HSurface)& theASurf2, const Standard_Real theU1, const Standard_Real theV1, const Standard_Real theU2, const Standard_Real theV2, const Standard_Boolean isTheFirst);
// Method to handle single singular point. Sub-method in SeekPointOnBoundary.
Standard_Boolean HandleSingleSingularPoint(const Handle(Adaptor3d_HSurface) &theASurf1,
const Handle(Adaptor3d_HSurface) &theASurf2,
const Standard_Real the3DTol,
TColStd_Array1OfReal &thePnt);
Standard_Boolean done;
Handle(IntSurf_LineOn2S) line;