1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

0029843: Modeling Algorithms - Boolean FUSE produces incorrect result

When splitting the shell/face with internal faces/edges use the 'internal' criteria of the face to choose the way to create loops.

Side effect changes:
- When performing Boolean operation - move the objects located far from Origin to the Origin to increase the accuracy of intersections.
This commit is contained in:
emv
2019-09-20 08:56:21 +03:00
committed by apn
parent d7992a77f6
commit c08fd12706
17 changed files with 449 additions and 44 deletions

View File

@@ -89,28 +89,63 @@ class BOPAlgo_EdgeEdge :
Handle(BOPDS_PaveBlock)& PaveBlock2() {
return myPB2;
}
//
//
void SetBoxes (const Bnd_Box& theBox1,
const Bnd_Box& theBox2)
{
myBox1 = theBox1;
myBox2 = theBox2;
}
//
void SetFuzzyValue(const Standard_Real theFuzz) {
IntTools_EdgeEdge::SetFuzzyValue(theFuzz);
}
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
TopoDS_Edge anE1 = myEdge1, anE2 = myEdge2;
Standard_Boolean hasTrsf = false;
try
{
OCC_CATCH_SIGNALS
gp_Trsf aTrsf;
if (BOPAlgo_Tools::TrsfToPoint (myBox1, myBox2, aTrsf))
{
// Shapes are located far from origin, move the shapes to the origin,
// to increase the accuracy of intersection.
TopLoc_Location aLoc (aTrsf);
myEdge1.Move (aLoc);
myEdge2.Move (aLoc);
hasTrsf = Standard_True;
}
IntTools_EdgeEdge::Perform();
}
catch (Standard_Failure const&)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
myEdge1 = anE1;
myEdge2 = anE2;
if (hasTrsf)
{
for (Standard_Integer i = 1; i <= myCommonParts.Length(); ++i)
{
IntTools_CommonPrt& aCPart = myCommonParts (i);
aCPart.SetEdge1 (myEdge1);
aCPart.SetEdge2 (myEdge2);
}
}
}
//
protected:
Handle(BOPDS_PaveBlock) myPB1;
Handle(BOPDS_PaveBlock) myPB2;
Bnd_Box myBox1;
Bnd_Box myBox2;
};
//
//=======================================================================
@@ -216,6 +251,7 @@ void BOPAlgo_PaveFiller::PerformEE()
//
anEdgeEdge.SetEdge1(aE1, aT11, aT12);
anEdgeEdge.SetEdge2(aE2, aT21, aT22);
anEdgeEdge.SetBoxes (aBB1, aBB2);
anEdgeEdge.SetFuzzyValue(myFuzzyValue);
anEdgeEdge.SetProgressIndicator(myProgressIndicator);
}//for (; aIt2.More(); aIt2.Next()) {
@@ -924,6 +960,8 @@ void BOPAlgo_PaveFiller::ForceInterfEE()
if (!aNbPB)
return;
const Standard_Boolean bSICheckMode = (myArguments.Extent() == 1);
// Prepare pave blocks with the same vertices for intersection.
BOPAlgo_VectorOfEdgeEdge aVEdgeEdge;
@@ -940,10 +978,12 @@ void BOPAlgo_PaveFiller::ForceInterfEE()
const TopoDS_Vertex& aV1 = TopoDS::Vertex(myDS->Shape(nV1));
const TopoDS_Vertex& aV2 = TopoDS::Vertex(myDS->Shape(nV2));
// Use the max tolerance of vertices as Fuzzy value for intersection
// of edges
Standard_Real aTolAdd = 2 * Max(BRep_Tool::Tolerance(aV1),
BRep_Tool::Tolerance(aV2));
// Use the max tolerance of vertices as Fuzzy value for intersection of edges.
// In the Self-Interference check mode we are interested in real
// intersections only, so use only the real tolerance of edges,
// no need to use the extended tolerance.
Standard_Real aTolAdd = (bSICheckMode ? myFuzzyValue :
2 * Max(BRep_Tool::Tolerance(aV1), BRep_Tool::Tolerance(aV2)));
// All possible pairs combined from the list <aLPB> should be checked
BOPDS_ListIteratorOfListOfPaveBlock aItLPB1(aLPB);
@@ -1022,6 +1062,7 @@ void BOPAlgo_PaveFiller::ForceInterfEE()
anEdgeEdge.SetPaveBlock2(aPB2);
anEdgeEdge.SetEdge1(aE1, aT11, aT12);
anEdgeEdge.SetEdge2(aE2, aT21, aT22);
anEdgeEdge.SetBoxes (myDS->ShapeInfo(nE1).Box(), myDS->ShapeInfo (nE2).Box());
if (bUseAddTol)
anEdgeEdge.SetFuzzyValue(myFuzzyValue + aTolAdd);
else

View File

@@ -105,18 +105,50 @@ class BOPAlgo_EdgeFace :
IntTools_EdgeFace::SetFuzzyValue(theFuzz);
}
//
void SetBoxes (const Bnd_Box& theBox1,
const Bnd_Box& theBox2)
{
myBox1 = theBox1;
myBox2 = theBox2;
}
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
TopoDS_Face aFace = myFace;
TopoDS_Edge anEdge = myEdge;
Standard_Boolean hasTrsf = false;
try
{
OCC_CATCH_SIGNALS
gp_Trsf aTrsf;
if (BOPAlgo_Tools::TrsfToPoint (myBox1, myBox2, aTrsf))
{
// Shapes are located far from origin, move the shapes to the origin,
// to increase the accuracy of intersection.
TopLoc_Location aLoc (aTrsf);
myEdge.Move (aLoc);
myFace.Move (aLoc);
hasTrsf = Standard_True;
}
IntTools_EdgeFace::Perform();
}
catch (Standard_Failure const&)
{
AddError(new BOPAlgo_AlertIntersectionFailed);
}
myFace = aFace;
myEdge = anEdge;
if (hasTrsf)
{
for (Standard_Integer i = 1; i <= mySeqOfCommonPrts.Length(); ++i)
{
IntTools_CommonPrt& aCPart = mySeqOfCommonPrts (i);
aCPart.SetEdge1 (myEdge);
}
}
}
//
protected:
@@ -124,6 +156,8 @@ class BOPAlgo_EdgeFace :
Standard_Integer myIF;
IntTools_Range myNewSR;
Handle(BOPDS_PaveBlock) myPB;
Bnd_Box myBox1;
Bnd_Box myBox2;
};
//
//=======================================================================
@@ -231,6 +265,7 @@ void BOPAlgo_PaveFiller::PerformEF()
//
aEdgeFace.SetEdge (aE);
aEdgeFace.SetFace (aF);
aEdgeFace.SetBoxes (myDS->ShapeInfo(nE).Box(), myDS->ShapeInfo (nF).Box());
aEdgeFace.SetFuzzyValue(myFuzzyValue);
aEdgeFace.UseQuickCoincidenceCheck(bExpressCompute);
//
@@ -756,6 +791,8 @@ void BOPAlgo_PaveFiller::ForceInterfEF(const BOPDS_IndexedMapOfPaveBlock& theMPB
// Shake the tree
aBBTree.Build();
const Standard_Boolean bSICheckMode = (myArguments.Extent() == 1);
// Find pairs of Face/PaveBlock containing the same vertices
// and prepare those pairs for intersection.
BOPAlgo_VectorOfEdgeFace aVEdgeFace;
@@ -874,8 +911,12 @@ void BOPAlgo_PaveFiller::ForceInterfEF(const BOPDS_IndexedMapOfPaveBlock& theMPB
// tolerance as the criteria.
const TopoDS_Vertex& aV1 = TopoDS::Vertex(myDS->Shape(nV1));
const TopoDS_Vertex& aV2 = TopoDS::Vertex(myDS->Shape(nV2));
Standard_Real aTolCheck = 2 * Max(BRep_Tool::Tolerance(aV1),
BRep_Tool::Tolerance(aV2));
// In the Self-Interference check mode we are interested in real
// intersections only, so use only the real tolerance of edges,
// no need to use the extended tolerance.
Standard_Real aTolCheck = (bSICheckMode ? myFuzzyValue :
2 * Max(BRep_Tool::Tolerance(aV1), BRep_Tool::Tolerance(aV2)));
if (aProjPS.LowerDistance() > aTolCheck + myFuzzyValue)
continue;
@@ -940,6 +981,7 @@ void BOPAlgo_PaveFiller::ForceInterfEF(const BOPDS_IndexedMapOfPaveBlock& theMPB
aEdgeFace.SetPaveBlock(aPB);
aEdgeFace.SetEdge(aE);
aEdgeFace.SetFace(aF);
aEdgeFace.SetBoxes (myDS->ShapeInfo(nE).Box(), myDS->ShapeInfo (nF).Box());
aEdgeFace.SetFuzzyValue(myFuzzyValue + aTolAdd);
aEdgeFace.UseQuickCoincidenceCheck(Standard_True);
aEdgeFace.SetRange(IntTools_Range(aPB->Pave1().Parameter(), aPB->Pave2().Parameter()));

View File

@@ -122,6 +122,12 @@ class BOPAlgo_FaceFace :
myF2=aF2;
}
//
void SetBoxes(const Bnd_Box& theBox1,
const Bnd_Box& theBox2) {
myBox1 = theBox1;
myBox2 = theBox2;
}
//
const TopoDS_Face& Face1()const {
return myF1;
}
@@ -142,13 +148,37 @@ class BOPAlgo_FaceFace :
IntTools_FaceFace::SetFuzzyValue(theFuzz);
}
//
const gp_Trsf& Trsf() const { return myTrsf; }
//
virtual void Perform() {
BOPAlgo_Algo::UserBreak();
try
{
OCC_CATCH_SIGNALS
IntTools_FaceFace::Perform(myF1, myF2);
gp_Trsf aTrsf;
TopoDS_Face aF1 = myF1, aF2 = myF2;
if (BOPAlgo_Tools::TrsfToPoint (myBox1, myBox2, aTrsf))
{
// Shapes are located far from origin, move the shapes to the origin,
// to increase the accuracy of intersection.
TopLoc_Location aLoc (aTrsf);
aF1.Move (aLoc);
aF2.Move (aLoc);
// The starting point is initialized only with the UV parameters
// on the faces - 3D point is not set (see GetEFPnts method),
// so no need to transform anything.
//for (IntSurf_ListOfPntOn2S::Iterator it (myListOfPnts); it.More(); it.Next())
//{
// IntSurf_PntOn2S& aP2S = it.ChangeValue();
// aP2S.SetValue (aP2S.Value().Transformed (aTrsf));
//}
myTrsf = aTrsf.Inverted();
}
IntTools_FaceFace::Perform (aF1, aF2);
}
catch (Standard_Failure const&)
{
@@ -156,12 +186,39 @@ class BOPAlgo_FaceFace :
}
}
//
void ApplyTrsf()
{
if (IsDone())
{
// Update curves
for (Standard_Integer i = 1; i <= mySeqOfCurve.Length(); ++i)
{
IntTools_Curve& aIC = mySeqOfCurve (i);
aIC.Curve()->Transform (myTrsf);
}
// Update points
for (Standard_Integer i = 1; i <= myPnts.Length(); ++i)
{
IntTools_PntOn2Faces& aP2F = myPnts (i);
IntTools_PntOnFace aPOnF1 = aP2F.P1(), aPOnF2 = aP2F.P2();
aPOnF1.SetPnt (aPOnF1.Pnt().Transformed (myTrsf));
aPOnF2.SetPnt (aPOnF2.Pnt().Transformed (myTrsf));
aP2F.SetP1 (aPOnF1);
aP2F.SetP2 (aPOnF2);
}
}
}
//
protected:
Standard_Integer myIF1;
Standard_Integer myIF2;
Standard_Real myTolFF;
TopoDS_Face myF1;
TopoDS_Face myF2;
Bnd_Box myBox1;
Bnd_Box myBox2;
gp_Trsf myTrsf;
};
//
//=======================================================================
@@ -235,6 +292,7 @@ void BOPAlgo_PaveFiller::PerformFF()
//
aFaceFace.SetIndices(nF1, nF2);
aFaceFace.SetFaces(aF1, aF2);
aFaceFace.SetBoxes (myDS->ShapeInfo (nF1).Box(), myDS->ShapeInfo (nF2).Box());
// compute minimal tolerance for the curves
Standard_Real aTolFF = ToleranceFF(aBAS1, aBAS2);
aFaceFace.SetTolFF(aTolFF);
@@ -282,6 +340,8 @@ void BOPAlgo_PaveFiller::PerformFF()
//
aFaceFace.PrepareLines3D(bSplitCurve);
//
aFaceFace.ApplyTrsf();
//
const IntTools_SequenceOfCurves& aCvsX = aFaceFace.Lines();
const IntTools_SequenceOfPntOn2Faces& aPntsX = aFaceFace.Points();
//
@@ -1711,12 +1771,16 @@ void BOPAlgo_PaveFiller::PutBoundPaveOnCurve(const TopoDS_Face& aF1,
getBoundPaves(myDS, aNC, aBndNV);
//
Standard_Real aTolVnew = Precision::Confusion();
Standard_Boolean isClosed = aP[1].IsEqual (aP[0], aTolVnew);
if (isClosed && (aBndNV[0] > 0 || aBndNV[1] > 0))
return;
for (Standard_Integer j = 0; j<2; ++j)
{
if (aBndNV[j] < 0)
{
// no vertex on this end
if (j && aP[1].IsEqual(aP[0], aTolVnew)) {
if (j && isClosed) {
//if curve is closed, process only one bound
continue;
}

View File

@@ -215,11 +215,15 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
//
// use only connected faces
TopTools_ListOfShape aLFConnected;
// Boundary faces
TopTools_MapOfShape aBoundaryFaces;
aItF.Initialize (myShapes);
for (; aItF.More(); aItF.Next()) {
const TopoDS_Shape& aF = aItF.Value();
if (aMFaces.Contains(aF)) {
aLFConnected.Append(aF);
if (!aBoundaryFaces.Add (aF))
aBoundaryFaces.Remove (aF);
}
}
//
@@ -254,6 +258,7 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
aItS.Initialize(aShell);
for (; aItS.More(); aItS.Next()) {
const TopoDS_Face& aF = (*(TopoDS_Face*)(&aItS.Value()));
Standard_Boolean isBoundary = aBoundaryFaces.Contains (aF);
//
// loop on edges of aF; find a good neighbor face of aF by aE
aExp.Init(aF, TopAbs_EDGE);
@@ -289,6 +294,8 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
// take only not-processed faces as a candidates
BOPTools_ListOfCoupleOfShape aLCSOff;
//
Standard_Integer aNbWaysInside = 0;
TopoDS_Face aSelF;
TopTools_ListIteratorOfListOfShape aItLF(aLF);
for (; aItLF.More(); aItLF.Next()) {
const TopoDS_Face& aFL = (*(TopoDS_Face*)(&aItLF.Value()));
@@ -301,6 +308,11 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
continue;
}
//
if (isBoundary && !aBoundaryFaces.Contains (aFL))
{
++aNbWaysInside;
aSelF = aFL;
}
aCSOff.SetShape1(aEL);
aCSOff.SetShape2(aFL);
aLCSOff.Append(aCSOff);
@@ -313,12 +325,14 @@ void BOPAlgo_ShellSplitter::SplitBlock(BOPTools_ConnexityBlock& aCB)
//
// among all the adjacent faces chose one with the minimal
// angle to the current one
TopoDS_Face aSelF;
if (aNbOff == 1) {
aSelF = (*(TopoDS_Face*)(&aLCSOff.First().Shape2()));
}
else if (aNbOff > 1) {
BOPTools_AlgoTools::GetFaceOff(aE, aF, aLCSOff, aSelF, aContext);
if (!isBoundary || aNbWaysInside != 1)
{
if (aNbOff == 1) {
aSelF = (*(TopoDS_Face*)(&aLCSOff.First().Shape2()));
}
else if (aNbOff > 1) {
BOPTools_AlgoTools::GetFaceOff(aE, aF, aLCSOff, aSelF, aContext);
}
}
//
if (!aSelF.IsNull() && AddedFacesMap.Add(aSelF)) {

View File

@@ -1756,3 +1756,30 @@ void BOPAlgo_Tools::FillInternals(const TopTools_ListOfShape& theSolids,
}
}
}
//=======================================================================
//function : TrsfToPoint
//purpose :
//=======================================================================
Standard_Boolean BOPAlgo_Tools::TrsfToPoint (const Bnd_Box& theBox1,
const Bnd_Box& theBox2,
gp_Trsf& theTrsf,
const gp_Pnt& thePoint,
const Standard_Real theCriteria)
{
// Unify two boxes
Bnd_Box aBox = theBox1;
aBox.Add (theBox2);
gp_XYZ aBCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) / 2.;
Standard_Real aPBDist = (thePoint.XYZ() - aBCenter).Modulus();
if (aPBDist < theCriteria)
return Standard_False;
Standard_Real aBSize = Sqrt (aBox.SquareExtent());
if ((aBSize / aPBDist) > (1. / theCriteria))
return Standard_False;
theTrsf.SetTranslation (gp_Vec (aBox.CornerMin(), thePoint));
return Standard_True;
}

View File

@@ -205,6 +205,20 @@ public:
const TopTools_DataMapOfShapeListOfShape& theImages,
const Handle(IntTools_Context)& theContext);
//! Computes the transformation needed to move the objects
//! to the given point to increase the quality of computations.
//! Returns true if the objects are located far from the given point
//! (relatively given criteria), false otherwise.
//! @param theBox1 the AABB of the first object
//! @param theBox2 the AABB of the second object
//! @param theTrsf the computed transformation
//! @param thePoint the Point to compute transformation to
//! @param theCriteria the Criteria to check whether thranformation is required
Standard_EXPORT static Standard_Boolean TrsfToPoint (const Bnd_Box& theBox1,
const Bnd_Box& theBox2,
gp_Trsf& theTrsf,
const gp_Pnt& thePoint = gp_Pnt (0.0, 0.0, 0.0),
const Standard_Real theCriteria = 1.e+5);
};
#endif // _BOPAlgo_Tools_HeaderFile

View File

@@ -27,7 +27,9 @@ class BOPAlgo_EdgeInfo {
BOPAlgo_EdgeInfo() :
myPassed(Standard_False),
myInFlag(Standard_False),
myAngle (-1.) {
myIsInside (Standard_False),
myAngle (-1.)
{
};
//
void SetEdge(const TopoDS_Edge& theE) {
@@ -62,10 +64,19 @@ class BOPAlgo_EdgeInfo {
return myAngle;
};
//
Standard_Boolean IsInside() const {
return myIsInside;
};
//
void SetIsInside (const Standard_Boolean theIsInside) {
myIsInside = theIsInside;
};
//
protected:
TopoDS_Edge myEdge;
Standard_Boolean myPassed;
Standard_Boolean myInFlag;
Standard_Boolean myIsInside;
Standard_Real myAngle;
};

View File

@@ -166,6 +166,8 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
MyDataMapOfShapeBoolean aVertMap;
//
const TopTools_ListOfShape& myEdges=aCB.Shapes();
TopTools_MapOfShape aMS;
//
// 1.Filling mySmartMap
aIt.Initialize(myEdges);
@@ -177,6 +179,10 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
//
bIsClosed = BRep_Tool::Degenerated(aE) ||
BRep_Tool::IsClosed(aE, myFace);
if (!aMS.Add (aE) && !bIsClosed)
aMS.Remove (aE);
//
aItS.Initialize(aE);
for(i = 0; aItS.More(); aItS.Next(), ++i) {
@@ -218,7 +224,7 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
for (i=1; i<=aNb; i++) {
aCntIn=0;
aCntOut=0;
const BOPAlgo_ListOfEdgeInfo& aLEInfo= mySmartMap(i);
const BOPAlgo_ListOfEdgeInfo& aLEInfo = mySmartMap(i);
BOPAlgo_ListIteratorOfListOfEdgeInfo anIt(aLEInfo);
for (; anIt.More(); anIt.Next()) {
const BOPAlgo_EdgeInfo& aEI=anIt.Value();
@@ -304,6 +310,7 @@ void BOPAlgo_WireSplitter::SplitBlock(const TopoDS_Face& myFace,
for (; aItLEI.More(); aItLEI.Next()) {
BOPAlgo_EdgeInfo& aEI=aItLEI.ChangeValue();
const TopoDS_Edge& aE=aEI.Edge();
aEI.SetIsInside (!aMS.Contains (aE));
//
aVV = aV;
bIsIN = aEI.IsIn();
@@ -366,7 +373,7 @@ void Path (const GeomAdaptor_Surface& aGAS,
Standard_Integer i, j, aNb, aNbj;
Standard_Real anAngleIn, anAngleOut, anAngle, aMinAngle;
Standard_Real aTol2D, aTol2D2, aD2, aTwoPI;
Standard_Boolean anIsSameV2d, anIsSameV, anIsFound, anIsOut, anIsNotPassed;
Standard_Boolean anIsSameV2d, anIsSameV, anIsOut, anIsNotPassed;
Standard_Boolean bIsClosed;
TopoDS_Vertex aVa, aVb;
TopoDS_Edge aEOuta;
@@ -501,8 +508,12 @@ void Path (const GeomAdaptor_Surface& aGAS,
//
anAngleIn = AngleIn(aEOuta, aLEInfo);
aMinAngle = 100.;
anIsFound = Standard_False;
Standard_Integer iCnt = NbWaysOut(aLEInfo);
Standard_Boolean isBoundary = !anEdgeInfo->IsInside();
Standard_Integer aNbWaysInside = 0;
BOPAlgo_EdgeInfo *pOnlyWayIn = NULL;
Standard_Integer aCurIndexE = 0;
anIt.Initialize(aLEInfo);
for (; anIt.More(); anIt.Next()) {
@@ -525,7 +536,6 @@ void Path (const GeomAdaptor_Surface& aGAS,
if (iCnt==1) {
// the one and only way to go out .
pEdgeInfo=&anEI;
anIsFound=Standard_True;
break;
}
//
@@ -548,15 +558,25 @@ void Path (const GeomAdaptor_Surface& aGAS,
anAngleOut=anEI.Angle();
anAngle=ClockWiseAngle(anAngleIn, anAngleOut);
}
if (isBoundary && anEI.IsInside())
{
++aNbWaysInside;
pOnlyWayIn = &anEI;
}
if (anAngle < aMinAngle - eps) {
aMinAngle=anAngle;
pEdgeInfo=&anEI;
anIsFound=Standard_True;
}
}
} // for (; anIt.More(); anIt.Next())
if (aNbWaysInside == 1)
{
pEdgeInfo = pOnlyWayIn;
}
//
if (!anIsFound) {
if (!pEdgeInfo) {
// no way to go . (Error)
return;
}