From bea10656938ebfd5fe7ed576dd21cce56282e031 Mon Sep 17 00:00:00 2001 From: emv Date: Fri, 26 Jun 2020 14:20:52 +0300 Subject: [PATCH] 0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes Check if unclassified edge may be added as neutral (invalid in one split, valid in other) by checking the SD faces in which the edge was classified. --- src/BRepOffset/BRepOffset_MakeOffset_1.cxx | 221 ++++++++++++++++++++- tests/offset/shape_type_i_c/XX1 | 16 ++ tests/offset/shape_type_i_c/XX2 | 16 ++ tests/offset/shape_type_i_c/XX3 | 23 +++ 4 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 tests/offset/shape_type_i_c/XX1 create mode 100644 tests/offset/shape_type_i_c/XX2 create mode 100644 tests/offset/shape_type_i_c/XX3 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 -- 2.20.1