diff --git a/src/BRepOffset/BRepOffset_MakeOffset_1.cxx b/src/BRepOffset/BRepOffset_MakeOffset_1.cxx index de3239f7a1..76efbc9cf7 100644 --- a/src/BRepOffset/BRepOffset_MakeOffset_1.cxx +++ b/src/BRepOffset/BRepOffset_MakeOffset_1.cxx @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -130,6 +131,7 @@ static static void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild, const TopTools_MapOfShape& theModifiedEdges, + const BRepOffset_Analyse* theAnalyse, TopTools_IndexedDataMapOfShapeListOfShape& theFImages, TopTools_DataMapOfShapeListOfShape& theDMFNewHoles, TopTools_DataMapOfShapeListOfShape& theEdgesOrigins, @@ -172,6 +174,17 @@ static TopTools_MapOfShape& theEdgesInvalidByVertex, TopTools_MapOfShape& theEdgesValidByVertex); +static + void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset, + const TopTools_IndexedDataMapOfShapeListOfShape& theFImages, + const TopTools_DataMapOfShapeShape& theFacesOrigins, + const BRepOffset_Analyse* theAnalyse, + const TopTools_IndexedMapOfShape& theInvEdges, + const TopTools_IndexedMapOfShape& theValidEdges, + BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges, + BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges, + BRepOffset_DataMapOfShapeMapOfShape& theNeutralEdges); + static void FindInvalidFaces(TopTools_ListOfShape& theLFImages, const TopTools_IndexedMapOfShape& theInvEdges, @@ -324,6 +337,7 @@ static const TopTools_MapOfShape& theFSelfRebAvoid, const TopoDS_Shape& theSolids, const TopTools_DataMapOfShapeListOfShape& theSSInterfs, + const BRepOffset_Analyse* theAnalyse, TopTools_IndexedDataMapOfShapeListOfShape& theFImages, TopTools_DataMapOfShapeListOfShape& theDMFNewHoles, TopTools_DataMapOfShapeListOfShape& theEdgesOrigins, @@ -734,7 +748,7 @@ void BRepOffset_MakeOffset::BuildSplitsOfExtendedFaces(const TopTools_ListOfShap if (aFToRebuild.Extent()) { // vertices to avoid TopTools_MapOfShape aVAEmpty; - RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, aFImages, aDMFNewHoles, + RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, &theAnalyse, aFImages, aDMFNewHoles, theEdgesOrigins, theFacesOrigins, anOEImages, anOEOrigins, aLastInvEdges, anEdgesToAvoid, anInvEdges, aValidEdges, anInvertedEdges, anAlreadyInvFaces, anInvFaces, anArtInvFaces, aVAEmpty, theETrimEInf, theAsDes); @@ -755,6 +769,7 @@ void BRepOffset_MakeOffset::BuildSplitsOfExtendedFaces(const TopTools_ListOfShap //======================================================================= void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild, const TopTools_MapOfShape& theModifiedEdges, + const BRepOffset_Analyse* theAnalyse, TopTools_IndexedDataMapOfShapeListOfShape& theFImages, TopTools_DataMapOfShapeListOfShape& theDMFNewHoles, TopTools_DataMapOfShapeListOfShape& theEdgesOrigins, @@ -794,7 +809,7 @@ void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theF // TopoDS_Shape aSolids; // - BuildSplitsOfFaces(aLF, theModifiedEdges, theEdgesOrigins, NULL, theAsDes, theFacesOrigins, + BuildSplitsOfFaces(aLF, theModifiedEdges, theEdgesOrigins, theAnalyse, theAsDes, theFacesOrigins, theOEImages, theOEOrigins, theLastInvEdges, theEdgesToAvoid, anInvEdges, theValidEdges, anInvertedEdges, theAlreadyInvFaces, anInvFaces, anArtInvFaces, theFImages, theDMFNewHoles, aSolids, aSSInterfs); @@ -805,7 +820,7 @@ void BuildSplitsOfInvFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theF FindFacesToRebuild(theFImages, anInvEdges, anInvFaces, aSSInterfs, aFToRebuild, aFSelfRebAvoid); // if (aFToRebuild.Extent()) { - RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, theFImages, theDMFNewHoles, + RebuildFaces(aFToRebuild, aFSelfRebAvoid, aSolids, aSSInterfs, theAnalyse, theFImages, theDMFNewHoles, theEdgesOrigins, theFacesOrigins, theOEImages, theOEOrigins, theLastInvEdges, theEdgesToAvoid, anInvEdges, theValidEdges, anInvertedEdges, theAlreadyInvFaces, anInvFaces, anArtInvFaces, theVertsToAvoid, theETrimEInf, theAsDes); @@ -999,7 +1014,12 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF, if (theInvEdges.IsEmpty() && theArtInvFaces.IsEmpty() && aDMFMIE.IsEmpty()) { return; } - // + + // Additional step to find invalid edges by checking unclassified edges + // in the splits of SD faces + FindInvalidEdges (aLFDone, theFImages, theFacesOrigins, theAnalyse, + theInvEdges, theValidEdges, aDMFMIE, aDMFMVE, aDMFMNE); + #ifdef OFFSET_DEBUG // show invalid edges TopoDS_Compound aCEInv1; @@ -1960,6 +1980,196 @@ void FindInvalidEdges(const TopoDS_Face& theF, } } +namespace +{ + static void addAsNeutral (const TopoDS_Shape& theE, + const TopoDS_Shape& theFInv, + const TopoDS_Shape& theFVal, + BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges, + BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges) + { + TopTools_IndexedMapOfShape* pMEInv = theLocInvEdges.ChangeSeek (theFInv); + if (!pMEInv) + pMEInv = theLocInvEdges.Bound (theFInv, TopTools_IndexedMapOfShape()); + pMEInv->Add (theE); + + TopTools_MapOfShape* pMEVal = theLocValidEdges.ChangeSeek (theFVal); + if (!pMEVal) + pMEVal = theLocValidEdges.Bound (theFVal, TopTools_MapOfShape()); + pMEVal->Add (theE); + } + +} +//======================================================================= +//function : FindInvalidEdges +//purpose : Additional method to look for invalid faces +//======================================================================= +void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset, + const TopTools_IndexedDataMapOfShapeListOfShape& theFImages, + const TopTools_DataMapOfShapeShape& theFacesOrigins, + const BRepOffset_Analyse* theAnalyse, + const TopTools_IndexedMapOfShape& theInvEdges, + const TopTools_IndexedMapOfShape& theValidEdges, + BRepOffset_DataMapOfShapeIndexedMapOfShape& theLocInvEdges, + BRepOffset_DataMapOfShapeMapOfShape& theLocValidEdges, + BRepOffset_DataMapOfShapeMapOfShape& theNeutralEdges) +{ + // 1. Find edges unclassified in faces + // 2. Find SD faces in which the same edge is classified + // 3. Check if the edge is neutral in face in which it wasn't classified + + NCollection_IndexedDataMap aMEUnclassified; + TopTools_DataMapOfShapeShape aFSplitFOffset; + + // Avoid artificial faces + TopTools_MapOfShape aNewFaces; + if (theAnalyse) + { + TopTools_MapOfShape aMapNewTmp; + for (TopTools_ListOfShape::Iterator it (theAnalyse->NewFaces()); it.More(); it.Next()) + aMapNewTmp.Add (it.Value()); + + for (TopTools_ListOfShape::Iterator it (theLFOffset); it.More(); it.Next()) + { + const TopoDS_Shape& aFOffset = it.Value(); + const TopoDS_Shape& aFOrigin = theFacesOrigins.Find (aFOffset); + if (aMapNewTmp.Contains (aFOrigin)) + aNewFaces.Add (aFOffset); + } + } + + TopTools_IndexedDataMapOfShapeListOfShape anEFMap; + for (TopTools_ListOfShape::Iterator itLFO (theLFOffset); itLFO.More(); itLFO.Next()) + { + const TopoDS_Shape& aF = itLFO.Value(); + if (aNewFaces.Contains (aF)) + continue; + + const TopTools_ListOfShape& aLFImages = theFImages.FindFromKey (aF); + for (TopTools_ListOfShape::Iterator itLF (aLFImages); itLF.More(); itLF.Next()) + { + const TopoDS_Shape& aFIm = itLF.Value(); + + TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, anEFMap); + + const TopTools_IndexedMapOfShape* pMEInvalid = theLocInvEdges.Seek (aFIm); + const TopTools_MapOfShape* pMEValid = theLocValidEdges.Seek (aFIm); + + for (TopExp_Explorer expE (aFIm, TopAbs_EDGE); expE.More(); expE.Next()) + { + const TopoDS_Shape& aE = expE.Current(); + if (theInvEdges.Contains (aE) != theValidEdges.Contains (aE)) + { + // edge is classified in some face + + if ((!pMEInvalid || !pMEInvalid->Contains (aE)) && + (!pMEValid || !pMEValid->Contains (aE))) + { + // but not in the current one + TopTools_MapOfShape *pMap = aMEUnclassified.ChangeSeek (aE); + if (!pMap) + pMap = &aMEUnclassified (aMEUnclassified.Add (aE, TopTools_MapOfShape())); + pMap->Add (aFIm); + + aFSplitFOffset.Bind (aFIm, aF); + } + } + } + } + } + + if (aMEUnclassified.IsEmpty()) + return; + + // Analyze unclassified edges + const Standard_Integer aNbE = aMEUnclassified.Extent(); + for (Standard_Integer iE = 1; iE <= aNbE; ++iE) + { + const TopoDS_Shape& aE = aMEUnclassified.FindKey (iE); + const TopTools_MapOfShape& aMFUnclassified = aMEUnclassified (iE); + + const TopTools_ListOfShape& aLF = anEFMap.FindFromKey (aE); + + for (TopTools_ListOfShape::Iterator itLF (aLF); itLF.More(); itLF.Next()) + { + const TopoDS_Shape& aFClassified = itLF.Value(); + if (aMFUnclassified.Contains (aFClassified)) + continue; + + BOPTools_Set anEdgeSetClass; + anEdgeSetClass.Add (aFClassified, TopAbs_EDGE); + + TopoDS_Shape aEClassified; + FindShape (aE, aFClassified, NULL, aEClassified); + TopAbs_Orientation anOriClass = aEClassified.Orientation(); + + gp_Dir aDNClass; + BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (TopoDS::Edge (aEClassified), TopoDS::Face (aFClassified), aDNClass); + + const TopTools_IndexedMapOfShape* pMEInvalid = theLocInvEdges.Seek (aFClassified); + Standard_Boolean isInvalid = pMEInvalid && pMEInvalid->Contains (aE); + + for (TopTools_MapOfShape::Iterator itM (aMFUnclassified); itM.More(); itM.Next()) + { + const TopoDS_Shape& aFUnclassified = itM.Value(); + + BOPTools_Set anEdgeSetUnclass; + anEdgeSetUnclass.Add (aFUnclassified, TopAbs_EDGE); + + if (anEdgeSetClass.IsEqual (anEdgeSetUnclass)) + { + gp_Dir aDNUnclass; + BOPTools_AlgoTools3D::GetNormalToFaceOnEdge (TopoDS::Edge (aE), TopoDS::Face (aFUnclassified), aDNUnclass); + + Standard_Boolean isSameOri = aDNClass.IsEqual (aDNUnclass, Precision::Angular()); + + // Among other splits of the same face find those where the edge is contained with different + // orientation + const TopoDS_Shape& aFOffset = aFSplitFOffset.Find (aFUnclassified); + const TopTools_ListOfShape& aLFSplits = theFImages.FindFromKey (aFOffset); + TopTools_ListOfShape::Iterator itLFSp (aLFSplits); + for (; itLFSp.More(); itLFSp.Next()) + { + const TopoDS_Shape& aFSp = itLFSp.Value(); + + if (!aFSp.IsSame (aFUnclassified) && aMFUnclassified.Contains (aFSp)) + { + TopoDS_Shape aEUnclassified; + FindShape (aE, aFSp, NULL, aEUnclassified); + + TopAbs_Orientation anOriUnclass = aEUnclassified.Orientation(); + if (!isSameOri) + anOriUnclass = TopAbs::Reverse (anOriUnclass); + + if (anOriClass != anOriUnclass) + { + // make the edge neutral for the face + TopTools_MapOfShape* pMENeutral = theNeutralEdges.ChangeSeek (aFOffset); + if (!pMENeutral) + pMENeutral = theNeutralEdges.Bound (aFOffset, TopTools_MapOfShape()); + pMENeutral->Add (aE); + + if (isInvalid && isSameOri) + { + // make edge invalid in aFUnclassified and valid in aFSp + addAsNeutral (aE, aFClassified, aFSp, theLocInvEdges, theLocValidEdges); + } + else + { + // make edge invalid in aFSp and valid in aFUnclassified + addAsNeutral (aE, aFSp, aFClassified, theLocInvEdges, theLocValidEdges); + } + } + } + } + if (itLFSp.More()) + break; + } + } + } + } +} + //======================================================================= //function : FindInvalidFaces //purpose : Looking for the invalid faces by analyzing their invalid edges @@ -4256,6 +4466,7 @@ void RebuildFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild const TopTools_MapOfShape& theFSelfRebAvoid, const TopoDS_Shape& theSolids, const TopTools_DataMapOfShapeListOfShape& theSSInterfs, + const BRepOffset_Analyse* theAnalyse, TopTools_IndexedDataMapOfShapeListOfShape& theFImages, TopTools_DataMapOfShapeListOfShape& theDMFNewHoles, TopTools_DataMapOfShapeListOfShape& theEdgesOrigins, @@ -4282,7 +4493,7 @@ void RebuildFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFToRebuild theInvFaces, theArtInvFaces, theVertsToAvoid, theETrimEInf, aModifiedEdges, theAsDes); // // 2. Repeat steps to build the correct faces - BuildSplitsOfInvFaces(theFToRebuild, aModifiedEdges, theFImages, theDMFNewHoles, theEdgesOrigins, + BuildSplitsOfInvFaces(theFToRebuild, aModifiedEdges, theAnalyse, theFImages, theDMFNewHoles, theEdgesOrigins, theFacesOrigins, theOEImages, theOEOrigins, theLastInvEdges, theEdgesToAvoid, theVertsToAvoid, theAlreadyInvFaces, theValidEdges, theETrimEInf, theAsDes); diff --git a/tests/offset/shape_type_i_c/XX1 b/tests/offset/shape_type_i_c/XX1 new file mode 100644 index 0000000000..d5a63b9af8 --- /dev/null +++ b/tests/offset/shape_type_i_c/XX1 @@ -0,0 +1,16 @@ +puts "========" +puts "0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes" +puts "========" +puts "" + +restore [locate_data_file bug31639_input.brep] s +offsetparameter 1e-7 c i r +offsetload s 7 +offsetperform result + +checkprops result -s 2.11103e+07 -v 1.43353e+09 + +unifysamedom result_unif result +checknbshapes result_unif -wire 45 -face 41 -shell 1 -solid 1 + +checkview -display result_unif -2d -path ${imagedir}/${test_image}.png diff --git a/tests/offset/shape_type_i_c/XX2 b/tests/offset/shape_type_i_c/XX2 new file mode 100644 index 0000000000..62e75d176b --- /dev/null +++ b/tests/offset/shape_type_i_c/XX2 @@ -0,0 +1,16 @@ +puts "========" +puts "0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes" +puts "========" +puts "" + +restore [locate_data_file bug31639_input_trim.brep] s +offsetparameter 1e-7 c i r +offsetload s 7 +offsetperform result + +checkprops result -s 7.22731e+06 -v 2.57323e+08 + +unifysamedom result_unif result +checknbshapes result_unif -wire 18 -face 17 -shell 1 -solid 1 + +checkview -display result_unif -2d -path ${imagedir}/${test_image}.png diff --git a/tests/offset/shape_type_i_c/XX3 b/tests/offset/shape_type_i_c/XX3 new file mode 100644 index 0000000000..f00bc69252 --- /dev/null +++ b/tests/offset/shape_type_i_c/XX3 @@ -0,0 +1,23 @@ +puts "========" +puts "0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes" +puts "========" +puts "" + +restore [locate_data_file bug31639_input.brep] s +offsetparameter 1e-7 c i r +offsetload s 0 +foreach f [explode s f] { + mksurface surf $f + regexp {Axis :([-0-9.+eE]*), ([-0-9.+eE]*), ([-0-9.+eE]*)} [dump surf] full x y z + if {abs($x) > 1.e-7 || abs($y) > 1.e-7} { + offsetonface $f 7 + } +} +offsetperform result + +checkprops result -s 2.10662e+07 -v 1.42886e+09 + +unifysamedom result_unif result +checknbshapes result_unif -wire 45 -face 41 -shell 1 -solid 1 + +checkview -display result_unif -2d -path ${imagedir}/${test_image}.png