From: emv Date: Fri, 26 Jun 2020 11:20:52 +0000 (+0300) Subject: 0031639: Modeling Algorithms - Offset algorithm incorrectly fills one of the holes X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=be42027f6411eb56f8ff9675e6bed539386949a8;p=occt-copy.git 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. --- diff --git a/src/BRepOffset/BRepOffset_MakeOffset_1.cxx b/src/BRepOffset/BRepOffset_MakeOffset_1.cxx index 1f549670ce..9d26ee1c89 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 @@ -170,6 +171,15 @@ static TopTools_MapOfShape& theEdgesInvalidByVertex, TopTools_MapOfShape& theEdgesValidByVertex); +static + void FindInvalidEdges (const TopTools_ListOfShape& theLFOffset, + const TopTools_IndexedDataMapOfShapeListOfShape& theFImages, + 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, @@ -994,7 +1004,11 @@ 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, theInvEdges, theValidEdges, aDMFMIE, aDMFMVE, aDMFMNE); + #ifdef OFFSET_DEBUG // show invalid edges TopoDS_Compound aCEInv1; @@ -1918,6 +1932,175 @@ 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_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; + + TopTools_IndexedDataMapOfShapeListOfShape anEFMap; + for (TopTools_ListOfShape::Iterator itLFO (theLFOffset); itLFO.More(); itLFO.Next()) + { + const TopoDS_Shape& aF = itLFO.Value(); + 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, 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, 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 @@ -2014,7 +2197,7 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages, // bValidLoc = pMVE && pMVE->Contains(aEIm); bInverted = theMEInverted.Contains(aEIm); - if (!bInvalid && bTreatInvertedAsInvalid) { + if (!bInvalid && !bInvalidLoc && bTreatInvertedAsInvalid) { bInvalid = bInverted; } // @@ -2023,7 +2206,7 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages, } // bAllValid &= bValidLoc; - bAllInvalid &= bInvalid; + bAllInvalid &= (bInvalid || bInvalidLoc); bAllInvNeutral &= (bAllInvalid && bNeutral); bIsInvalidByInverted &= (bInvalidLoc || bInverted); } 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