// Created on: 1998-08-12 // Created by: Galina KULIKOVA // Copyright (c) 1998-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. // pdn 17.12.98 ie_exhaust-A.stp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Shell, ShapeFix_Root) //================================================================================================= ShapeFix_Shell::ShapeFix_Shell() { myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK); myFixFaceMode = -1; myFixOrientationMode = -1; myFixFace = new ShapeFix_Face; myNbShells = 0; myNonManifold = Standard_False; } //================================================================================================= ShapeFix_Shell::ShapeFix_Shell(const TopoDS_Shell& shape) { myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK); myFixFaceMode = -1; myFixOrientationMode = -1; myFixFace = new ShapeFix_Face; Init(shape); myNonManifold = Standard_False; } //================================================================================================= void ShapeFix_Shell::Init(const TopoDS_Shell& shell) { myShape = shell; myShell = shell; myNbShells = 0; } //================================================================================================= Standard_Boolean ShapeFix_Shell::Perform(const Message_ProgressRange& theProgress) { Standard_Boolean status = Standard_False; if (Context().IsNull()) SetContext(new ShapeBuild_ReShape); myFixFace->SetContext(Context()); if (NeedFix(myFixFaceMode)) { TopoDS_Shape S = Context()->Apply(myShell); // Get the number of faces for progress indication Standard_Integer aNbFaces = S.NbChildren(); // Start progress scope (no need to check if progress exists -- it is safe) Message_ProgressScope aPS(theProgress, "Fixing face", aNbFaces); for (TopoDS_Iterator iter(S); iter.More() && aPS.More(); iter.Next(), aPS.Next()) { TopoDS_Shape sh = iter.Value(); TopoDS_Face tmpFace = TopoDS::Face(sh); myFixFace->Init(tmpFace); if (myFixFace->Perform()) { status = Standard_True; myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE1); } } // Halt algorithm in case of user's abort if (!aPS.More()) return Standard_False; } TopoDS_Shape newsh = Context()->Apply(myShell); if (NeedFix(myFixOrientationMode)) FixFaceOrientation(TopoDS::Shell(newsh), Standard_True, myNonManifold); TopoDS_Shape aNewsh = Context()->Apply(newsh); ShapeAnalysis_Shell aSas; for (TopExp_Explorer aShellExp(aNewsh, TopAbs_SHELL); aShellExp.More(); aShellExp.Next()) { TopoDS_Shell aCurShell = TopoDS::Shell(aShellExp.Current()); if (aCurShell.Closed()) { aSas.LoadShells(aCurShell); aSas.CheckOrientedShells(aCurShell, Standard_True); if (aSas.HasFreeEdges()) { aCurShell.Closed(Standard_False); // clang-format off SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed // clang-format on } aSas.Clear(); } } if (status) myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_DONE1); if (Status(ShapeExtend_DONE2)) status = Standard_True; return status; } //================================================================================================= static Standard_Boolean GetFreeEdges(const TopoDS_Shape& aShape, TopTools_MapOfShape& MapEdges) { for (TopExp_Explorer aExpF(aShape, TopAbs_FACE); aExpF.More(); aExpF.Next()) { for (TopExp_Explorer aExpE(aExpF.Current(), TopAbs_EDGE); aExpE.More(); aExpE.Next()) { TopoDS_Edge edge = TopoDS::Edge(aExpE.Current()); if (!MapEdges.Contains(edge)) MapEdges.Add(edge); else MapEdges.Remove(edge); } } return !MapEdges.IsEmpty(); } //======================================================================= // function : GetShells // purpose : If mode isMultiConnex = Standard_True gets max possible shell for // exception of multiconnexity parts. // Else if this mode is equal to Standard_False maximum possible // shell will be created without taking account of multiconnexity. // In this function map face - shell and sequence of mebius faces is formed. //======================================================================= static Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface, const TopTools_MapOfShape& aMapMultiConnectEdges, TopTools_SequenceOfShape& aSeqShells, TopTools_DataMapOfShapeShape& aMapFaceShells, TopTools_SequenceOfShape& ErrFaces) { Standard_Boolean done = Standard_False; if (!Lface.Length()) return Standard_False; TopoDS_Shell nshell; TopTools_MapOfShape dire, reve; BRep_Builder B; B.MakeShell(nshell); Standard_Boolean isMultiConnex = !aMapMultiConnectEdges.IsEmpty(); Standard_Integer i = 1, j = 1; TopTools_SequenceOfShape aSeqUnconnectFaces; for (; i <= Lface.Length(); i++) { TopTools_MapOfShape dtemp, rtemp; Standard_Integer nbbe = 0, nbe = 0; TopoDS_Face F1 = TopoDS::Face(Lface.Value(i)); for (TopExp_Explorer expe(F1, TopAbs_EDGE); expe.More(); expe.Next()) { TopoDS_Edge edge = TopoDS::Edge(expe.Current()); // if multiconnexity mode is equal to Standard_True faces contains // the same multiconnexity edges are not added to one shell. if (isMultiConnex && aMapMultiConnectEdges.Contains(edge)) continue; if ((edge.Orientation() == TopAbs_FORWARD && dire.Contains(edge)) || (edge.Orientation() == TopAbs_REVERSED && reve.Contains(edge))) nbbe++; else if ((edge.Orientation() == TopAbs_FORWARD && reve.Contains(edge)) || (edge.Orientation() == TopAbs_REVERSED && dire.Contains(edge))) nbe++; if (dire.Contains(edge)) dire.Remove(edge); else if (reve.Contains(edge)) reve.Remove(edge); else { if (edge.Orientation() == TopAbs_FORWARD) dtemp.Add(edge); if (edge.Orientation() == TopAbs_REVERSED) rtemp.Add(edge); } } if (!nbbe && !nbe && dtemp.IsEmpty() && rtemp.IsEmpty()) continue; // if face can not be added to shell it added to sequence of error faces. if (nbe != 0 && nbbe != 0) { ErrFaces.Append(F1); Lface.Remove(i); j++; continue; } // Addition of face to shell. In the dependance of orientation faces in the shell // added face can be reversed. if ((nbe != 0 || nbbe != 0) || j == 1) { if (nbbe != 0) { F1.Reverse(); for (TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next()) reve.Add(ite.Key()); for (TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next()) dire.Add(ite1.Key()); done = Standard_True; } else { for (TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next()) dire.Add(ite.Key()); for (TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next()) reve.Add(ite1.Key()); } j++; B.Add(nshell, F1); aMapFaceShells.Bind(F1, nshell); Lface.Remove(i); // check if closed shell is obtained in multi connex mode and add to sequence of // shells and new shell begin to construct. // (check is n*2) if (isMultiConnex && BRep_Tool::IsClosed(nshell)) { nshell.Closed(Standard_True); aSeqShells.Append(nshell); TopoDS_Shell nshellnext; B.MakeShell(nshellnext); nshell = nshellnext; j = 1; } i = 0; } // if shell contains of one face. This face is added to sequence of faces. // This shell is removed. if (Lface.Length() && i == Lface.Length() && j <= 2) { TopoDS_Iterator aItf(nshell, Standard_False); if (aItf.More()) { aSeqUnconnectFaces.Append(aItf.Value()); aMapFaceShells.UnBind(aItf.Value()); } TopoDS_Shell nshellnext; B.MakeShell(nshellnext); nshell = nshellnext; i = 0; j = 1; } } Standard_Boolean isContains = Standard_False; for (Standard_Integer k = 1; k <= aSeqShells.Length() && !isContains; k++) isContains = nshell.IsSame(aSeqShells.Value(k)); if (!isContains) { Standard_Integer numFace = 0; TopoDS_Shape aFace; for (TopoDS_Iterator aItf(nshell, Standard_False); aItf.More(); aItf.Next()) { aFace = aItf.Value(); numFace++; } if (numFace > 1) { // close all closed shells in no multi connex mode if (!isMultiConnex) nshell.Closed(BRep_Tool::IsClosed(nshell)); aSeqShells.Append(nshell); } else if (numFace == 1) { if (aMapFaceShells.IsBound(aFace)) aMapFaceShells.UnBind(aFace); Lface.Append(aFace); } } // Sequence of faces Lface contains faces which can not be added to obtained shells. for (Standard_Integer j1 = 1; j1 <= aSeqUnconnectFaces.Length(); j1++) { Lface.Append(aSeqUnconnectFaces); } return done; } //======================================================================= // function : AddMultiConexityFaces // purpose : In this function faces have only of multiconnexity boundary // are added to shells having free boundary contains the same // multiconnexity edges as faces. //======================================================================= static Standard_Boolean AddMultiConexityFaces( TopTools_SequenceOfShape& Lface, const TopTools_MapOfShape& aMapMultiConnectEdges, TopTools_SequenceOfShape& SeqShells, const TopTools_DataMapOfShapeShape& aMapFaceShells, const TopTools_IndexedDataMapOfShapeListOfShape& aMapEdgeFaces, TopTools_SequenceOfShape& ErrFaces, const Standard_Boolean NonManifold) { Standard_Boolean done = Standard_False; // BRep_Builder aB; TopTools_SequenceOfShape llPosibleShells; TopTools_SequenceOfShape AddShapes; for (Standard_Integer i1 = 1; i1 <= Lface.Length(); i1++) { const TopoDS_Shape& aShape = Lface.Value(i1); Standard_Integer aNbMultEdges = 0; // Finds faces having only multiconnexity boundary. for (TopoDS_Iterator aItWires(aShape, Standard_False); aItWires.More(); aItWires.Next()) { Standard_Integer aNbEdges = 0; for (TopoDS_Iterator aItEdges(aItWires.Value(), Standard_False); aItEdges.More(); aItEdges.Next(), aNbEdges++) { const TopoDS_Shape& edge = aItEdges.Value(); if (!aMapMultiConnectEdges.Contains(edge)) continue; aNbMultEdges++; } if (!aNbMultEdges) continue; if (aNbMultEdges == aNbEdges) AddShapes.Append(aShape); else llPosibleShells.Append(aShape); } } // Attempt to create shell from unconnected which have not only multiconnexity boundary. TopTools_SequenceOfShape aTmpShells; if (!llPosibleShells.IsEmpty()) { TopTools_MapOfShape aMap; TopTools_SequenceOfShape aTmp; TopTools_DataMapOfShapeShape aTmpFaceShell; if (GetShells(llPosibleShells, aMap, aTmpShells, aTmpFaceShell, aTmp)) { for (Standard_Integer kk = 1; kk <= aTmpShells.Length(); kk++) { const TopoDS_Shape& aSh = aTmpShells.Value(kk); TopTools_MapOfShape mapEdges; if (GetFreeEdges(aSh, mapEdges)) { Standard_Integer nbedge = 0; for (TopTools_MapIteratorOfMapOfShape amapIter(mapEdges); amapIter.More(); amapIter.Next()) { if (aMapMultiConnectEdges.Contains(amapIter.Key())) nbedge++; } if (nbedge && nbedge == mapEdges.Extent()) AddShapes.Append(aSh); } } } } // Add chosen faces to shells. for (Standard_Integer k1 = 1; k1 <= AddShapes.Length(); k1++) { TopTools_DataMapOfShapeInteger MapOtherShells; TopTools_MapOfShape dire, reve; const TopoDS_Shape& aSh = AddShapes.Value(k1); TopTools_MapOfShape mapEdges; if (!GetFreeEdges(aSh, mapEdges)) continue; TopTools_ListOfShape lfaces; // Fill MapOtherShells which will contain shells with orientation in which selected shape aSh // will be add. for (TopTools_MapIteratorOfMapOfShape amapIter(mapEdges); amapIter.More(); amapIter.Next()) { if (!aMapMultiConnectEdges.Contains(amapIter.Key())) continue; TopoDS_Edge edge = TopoDS::Edge(amapIter.Key()); if (edge.Orientation() == TopAbs_FORWARD) dire.Add(edge); else reve.Add(edge); TopTools_ListOfShape lf; lf = aMapEdgeFaces.FindFromKey(edge); lfaces.Append(lf); } for (TopTools_ListIteratorOfListOfShape aItl(lfaces); aItl.More(); aItl.Next()) { TopoDS_Shape aF = aItl.Value(); if (!aMapFaceShells.IsBound(aF)) continue; TopoDS_Shape aOthershell; aOthershell = aMapFaceShells.Find(aF); if (MapOtherShells.IsBound(aOthershell)) continue; if (!NonManifold && BRep_Tool::IsClosed(aOthershell)) continue; TopTools_MapOfShape mapShellEdges; GetFreeEdges(aOthershell, mapShellEdges); Standard_Boolean isAdd = Standard_True; for (TopTools_MapIteratorOfMapOfShape amapIter1(mapEdges); amapIter1.More() && isAdd; amapIter1.Next()) isAdd = mapShellEdges.Contains(amapIter1.Key()); if (!isAdd) continue; Standard_Integer nbdir = 0, nbrev = 0; // add only free face whome all edges contains in the shell as open boundary. for (TopTools_MapIteratorOfMapOfShape aIte(mapShellEdges); aIte.More(); aIte.Next()) { TopoDS_Edge edgeS = TopoDS::Edge(aIte.Key()); if (!aMapMultiConnectEdges.Contains(edgeS)) continue; if ((edgeS.Orientation() == TopAbs_FORWARD && dire.Contains(edgeS)) || (edgeS.Orientation() == TopAbs_REVERSED && reve.Contains(edgeS))) nbrev++; else if ((edgeS.Orientation() == TopAbs_FORWARD && reve.Contains(edgeS)) || (edgeS.Orientation() == TopAbs_REVERSED && dire.Contains(edgeS))) nbdir++; } if (nbdir && nbrev) { ErrFaces.Append(aSh); continue; } if (nbdir || nbrev) { Standard_Integer isReverse = (nbrev ? 1 : 0); MapOtherShells.Bind(aOthershell, isReverse); } } if (MapOtherShells.IsEmpty()) { // i1++; continue; } // Adds face to open shells containing the same multishared edges. // For nonmanifold mode creation ine shell from face and shells containing the same multishared // edges. // If one face can be added to a few shells (case of compsolid) face will be added to each // shell. done = Standard_True; Standard_Integer FirstRev = 0, FirstInd = 0; Standard_Integer ind = 0; for (Standard_Integer l = 1; l <= SeqShells.Length(); l++) { if (!MapOtherShells.IsBound(SeqShells.Value(l))) continue; ind++; Standard_Integer isRev = MapOtherShells.Find(SeqShells.Value(l)); TopoDS_Shape anewShape = (isRev ? aSh.Reversed() : aSh); BRep_Builder aB1; TopoDS_Shape aShell = SeqShells.Value(l); if (ind == 1 || !NonManifold) { if (ind == 1) { FirstRev = isRev; FirstInd = l; } for (TopExp_Explorer aE(anewShape, TopAbs_FACE); aE.More(); aE.Next()) aB1.Add(aShell, aE.Current()); SeqShells.ChangeValue(l) = aShell; } else if (NonManifold) { Standard_Boolean isReversed = !((!(isRev) && !FirstRev) || ((isRev) && FirstRev)); aShell = SeqShells.Value(FirstInd); for (TopoDS_Iterator aItF(SeqShells.Value(l), Standard_False); aItF.More(); aItF.Next()) { TopoDS_Shape nF = (isReversed ? aItF.Value().Reversed() : aItF.Value()); aB1.Add(aShell, nF); } SeqShells.ChangeValue(FirstInd) = aShell; SeqShells.Remove(l--); } } dire.Clear(); reve.Clear(); for (TopExp_Explorer aEt(aSh, TopAbs_FACE); aEt.More(); aEt.Next()) { for (Standard_Integer kk = 1; kk <= Lface.Length(); kk++) { if (aEt.Current().IsSame(Lface.Value(kk))) Lface.Remove(kk--); } } } return done; } //======================================================================= // function : BoxIn // purpose : Check if one face contains inside other. //======================================================================= static Standard_Integer BoxIn(const Bnd_Box& theBox1, const Bnd_Box& theBox2) { Standard_Integer aNumIn = 0; Standard_Real aXmin1, aYmin1, aXmax1, aYmax1, aXmin2, aYmin2, aXmax2, aYmax2, aZmin1, aZmax1, aZmin2, aZmax2; theBox1.Get(aXmin1, aYmin1, aZmin1, aXmax1, aYmax1, aZmax1); theBox2.Get(aXmin2, aYmin2, aZmin2, aXmax2, aYmax2, aZmax2); if (aXmin1 == aXmin2 && aXmax1 == aXmax2 && aYmin1 == aYmin2 && aYmax1 == aYmax2 && aZmin1 == aZmin2 && aZmax1 == aZmax2) aNumIn = 0; else if (aXmin1 >= aXmin2 && aXmax1 <= aXmax2 && aYmin1 >= aYmin2 && aYmax1 <= aYmax2 && aZmin1 >= aZmin2 && aZmax1 <= aZmax2) aNumIn = 1; else if (aXmin1 <= aXmin2 && aXmax1 >= aXmax2 && aYmin1 <= aYmin2 && aYmax1 >= aYmax2 && aZmin1 <= aZmin2 && aZmax1 >= aZmax2) aNumIn = 2; return aNumIn; } //======================================================================= // function : GetClosedShells // purpose : Check if one shell is a part from other shell. // For case of compsolid when a few shells are created from // the same set of faces. //======================================================================= static void GetClosedShells(TopTools_SequenceOfShape& Shells, TopTools_SequenceOfShape& aRemainShells) { Bnd_Array1OfBox aBoxes(1, Shells.Length()); for (Standard_Integer i = 1; i <= Shells.Length(); i++) { Bnd_Box Box; BRepBndLib::AddClose(Shells.Value(i), Box); aBoxes.SetValue(i, Box); } TColStd_MapOfInteger aMapNum; for (Standard_Integer j = 1; j <= aBoxes.Length(); j++) { for (Standard_Integer k = j + 1; k <= aBoxes.Length(); k++) { Standard_Integer NumIn = BoxIn(aBoxes.Value(j), aBoxes.Value(k)); switch (NumIn) { case 1: aMapNum.Add(k); break; case 2: aMapNum.Add(j); break; default: break; } } } for (Standard_Integer i1 = 1; i1 <= Shells.Length(); i1++) { if (!aMapNum.Contains(i1)) aRemainShells.Append(Shells.Value(i1)); } } //======================================================================= // function : GlueClosedCandidate // purpose : First, attempt to create closed shells from sequence of open shells. //======================================================================= static void GlueClosedCandidate(TopTools_SequenceOfShape& OpenShells, const TopTools_MapOfShape& aMapMultiConnectEdges, TopTools_SequenceOfShape& aSeqNewShells) { // Creating new shells if some open shells contain the same free boundary. for (Standard_Integer i = 1; i < OpenShells.Length(); i++) { TopoDS_Shape aShell = OpenShells.Value(i); TopTools_MapOfShape mapEdges1; TopTools_MapOfShape dire, reve; if (!GetFreeEdges(aShell, mapEdges1)) continue; for (TopTools_MapIteratorOfMapOfShape aIte(mapEdges1); aIte.More(); aIte.Next()) { TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key()); if (!aMapMultiConnectEdges.Contains(edge1)) break; if (edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1); else if (edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1); } if (mapEdges1.Extent() > (dire.Extent() + reve.Extent())) continue; // Filling map MapOtherShells which contains candidate to creation of closed shell // with aShell. NCollection_DataMap MapOtherShells; for (Standard_Integer j = i + 1; j <= OpenShells.Length(); j++) { Standard_Boolean isAddShell = Standard_True; Standard_Boolean isReversed = Standard_False; TopTools_MapOfShape mapEdges2; const TopoDS_Shape& aShell2 = OpenShells.Value(j); if (!GetFreeEdges(aShell2, mapEdges2)) continue; for (TopTools_MapIteratorOfMapOfShape aIte2(mapEdges2); aIte2.More() && isAddShell; aIte2.Next()) { TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key()); if (!aMapMultiConnectEdges.Contains(edge2)) { isAddShell = Standard_False; break; // continue; } isAddShell = (dire.Contains(edge2) || reve.Contains(edge2)); if ((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2)) || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2))) isReversed = Standard_True; } if (!isAddShell) continue; MapOtherShells.Bind(OpenShells.Value(j), isReversed); } if (MapOtherShells.IsEmpty()) continue; if (!MapOtherShells.IsEmpty()) { // Case of compsolid when more than two shells have the same free boundary. TopTools_SequenceOfShape aSeqCandidate; aSeqCandidate.Append(OpenShells.Value(i)); for (NCollection_DataMap::Iterator aIt(MapOtherShells); aIt.More(); aIt.Next()) { aSeqCandidate.Append(aIt.Key()); } // Creation of all possible shells from chosen candidate. // And the addition of them to temporary sequence. TopTools_SequenceOfShape aTmpSeq; for (Standard_Integer k = 1; k <= aSeqCandidate.Length(); k++) { for (Standard_Integer l = k + 1; l <= aSeqCandidate.Length(); l++) { TopoDS_Shell aNewSh; BRep_Builder aB; aB.MakeShell(aNewSh); for (TopoDS_Iterator aIt1(aSeqCandidate.Value(k), Standard_False); aIt1.More(); aIt1.Next()) aB.Add(aNewSh, aIt1.Value()); Standard_Boolean isRev = MapOtherShells.Find(aSeqCandidate.Value(l)); if (k != 1) { isRev = (isRev == MapOtherShells.Find(aSeqCandidate.Value(k))); } for (TopExp_Explorer aExp(aSeqCandidate.Value(l), TopAbs_FACE); aExp.More(); aExp.Next()) { TopoDS_Shape aFace = (isRev ? aExp.Current().Reversed() : aExp.Current()); aB.Add(aNewSh, aFace); } aTmpSeq.Append(aNewSh); } } // Choice from temporary sequence shells contains different set of faces (case of compsolid) TopTools_SequenceOfShape aRemainShells; GetClosedShells(aTmpSeq, aRemainShells); aSeqNewShells.Append(aRemainShells); for (Standard_Integer j1 = i + 1; j1 <= OpenShells.Length(); j1++) { if (!MapOtherShells.IsBound(OpenShells.Value(j1))) continue; OpenShells.Remove(j1--); } } else { BRep_Builder aB; TopoDS_Shape aNewShell = aShell; TopoDS_Shape addShell; Standard_Boolean isReversed = Standard_False; for (Standard_Integer j1 = i + 1; j1 <= OpenShells.Length(); j1++) { if (!MapOtherShells.Find(OpenShells.Value(j1), isReversed)) continue; addShell = OpenShells.Value(j1); OpenShells.Remove(j1); break; } for (TopExp_Explorer aExpF(addShell, TopAbs_FACE); aExpF.More(); aExpF.Next()) { TopoDS_Shape aFace = aExpF.Current(); if (isReversed) aFace.Reverse(); aB.Add(aNewShell, aFace); } aSeqNewShells.Append(aNewShell); } // OpenShells.ChangeValue(i) = aShell; OpenShells.Remove(i--); } } //======================================================================= // function : CreateNonManifoldShells // purpose : Attempt to create max possible shells from open shells. //======================================================================= static void CreateNonManifoldShells(TopTools_SequenceOfShape& SeqShells, const TopTools_MapOfShape& aMapMultiConnectEdges) { TopTools_IndexedDataMapOfShapeListOfShape aMap; for (Standard_Integer i = 1; i <= SeqShells.Length(); i++) { const TopoDS_Shape& aShell = SeqShells.Value(i); TopTools_IndexedMapOfShape medeg; TopExp::MapShapes(aShell, TopAbs_EDGE, medeg); for (TopTools_MapIteratorOfMapOfShape mit(aMapMultiConnectEdges); mit.More(); mit.Next()) { // for(TopExp_Explorer aExp(aShell,TopAbs_EDGE); aExp.More(); aExp.Next(),nbe++) { // TopoDS_Shape ae = aExp.Current(); const TopoDS_Shape& ae = mit.Key(); // if( aMapMultiConnectEdges.Contains(aExp.Current())) { if (medeg.Contains(ae)) { if (aMap.Contains(ae)) aMap.ChangeFromKey(ae).Append(aShell); else { TopTools_ListOfShape al; al.Append(aShell); aMap.Add(ae, al); } } } } TopTools_IndexedDataMapOfShapeShape aMapShells; for (Standard_Integer j = 1; j <= aMap.Extent(); j++) { const TopTools_ListOfShape& LShells = aMap.FindFromIndex(j); TopoDS_Shell aNewShell; BRep_Builder aB; aB.MakeShell(aNewShell); TopTools_MapOfShape mapmerge; Standard_Boolean ismerged = Standard_False; Standard_Integer num = 1; for (TopTools_ListIteratorOfListOfShape alit(LShells); alit.More(); alit.Next(), num++) { if (!aMapShells.Contains(alit.Value())) { for (TopExp_Explorer aEf(alit.Value(), TopAbs_FACE); aEf.More(); aEf.Next()) { aB.Add(aNewShell, aEf.Current()); } ismerged = Standard_True; mapmerge.Add(alit.Value()); } else if (ismerged) { TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value()); while (aMapShells.Contains(arshell)) { const TopoDS_Shape& ss = aMapShells.FindFromKey(arshell); if (ss.IsSame(arshell)) break; arshell = ss; } if (!mapmerge.Contains(arshell)) { for (TopExp_Explorer aEf(arshell, TopAbs_FACE); aEf.More(); aEf.Next()) { aB.Add(aNewShell, aEf.Current()); } mapmerge.Add(arshell); } } else { TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value()); while (aMapShells.Contains(arshell)) { const TopoDS_Shape& ss = aMapShells.FindFromKey(arshell); if (ss.IsSame(arshell)) break; arshell = ss; } if (num == 1) { for (TopExp_Explorer aEf(arshell, TopAbs_FACE); aEf.More(); aEf.Next()) aB.Add(aNewShell, aEf.Current()); mapmerge.Add(arshell); } else if (!mapmerge.Contains(arshell)) { for (TopExp_Explorer aEf(arshell, TopAbs_FACE); aEf.More(); aEf.Next()) { aB.Add(aNewShell, aEf.Current()); } mapmerge.Add(arshell); } } } if (mapmerge.Extent() > 1 || ismerged) { for (TopTools_MapIteratorOfMapOfShape alit1(mapmerge); alit1.More(); alit1.Next()) { const TopoDS_Shape& oldShell = alit1.Key(); // while(aMapShells.Contains(oldShell)) { // TopoDS_Shape ss = aMapShells.FindFromKey(oldShell); // if(ss.IsSame(oldShell)) break; // oldShell = ss; // } aMapShells.Add(oldShell, aNewShell); } } } TopTools_IndexedMapOfShape MapNewShells; for (Standard_Integer nn = 1; nn <= SeqShells.Length(); nn++) { if (aMapShells.Contains(SeqShells.Value(nn))) { TopoDS_Shape aNewShell = aMapShells.FindFromKey(SeqShells.Value(nn)); while (aMapShells.Contains(aNewShell)) { const TopoDS_Shape& ss = aMapShells.FindFromKey(aNewShell); if (ss.IsSame(aNewShell)) break; aNewShell = ss; } MapNewShells.Add(aNewShell); SeqShells.Remove(nn--); } } for (Standard_Integer ii = 1; ii <= MapNewShells.Extent(); ii++) SeqShells.Append(MapNewShells.FindKey(ii)); } //======================================================================= // function : CreateClosedShell // purpose : Attempt to create max possible shells from open shells. //======================================================================= static void CreateClosedShell(TopTools_SequenceOfShape& OpenShells, const TopTools_MapOfShape& aMapMultiConnectEdges) { TopTools_SequenceOfShape aNewShells; // First, attempt to create closed shells. GlueClosedCandidate(OpenShells, aMapMultiConnectEdges, aNewShells); // Creating new shells if some open shells contain the multishared same edges. for (Standard_Integer i = 1; i < OpenShells.Length(); i++) { Standard_Boolean isAddShell = Standard_False; TopoDS_Shape aShell = OpenShells.Value(i); Standard_Boolean isReversed = Standard_False; for (Standard_Integer j = i + 1; j <= OpenShells.Length(); j++) { TopTools_MapOfShape mapEdges1; TopTools_MapOfShape dire, reve; if (!GetFreeEdges(aShell, mapEdges1)) break; for (TopTools_MapIteratorOfMapOfShape aIte(mapEdges1); aIte.More(); aIte.Next()) { TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key()); if (!aMapMultiConnectEdges.Contains(edge1)) continue; if (edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1); else if (edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1); } if (dire.IsEmpty() && reve.IsEmpty()) break; TopTools_MapOfShape mapEdges2; TopoDS_Shape aShell2 = OpenShells.Value(j); if (!GetFreeEdges(aShell2, mapEdges2)) continue; for (TopTools_MapIteratorOfMapOfShape aIte2(mapEdges2); aIte2.More(); aIte2.Next()) { TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key()); if (!aMapMultiConnectEdges.Contains(edge2)) continue; if (!dire.Contains(edge2) && !reve.Contains(edge2)) continue; isAddShell = Standard_True; if ((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2)) || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2))) isReversed = Standard_True; } if (!isAddShell) continue; BRep_Builder aB; for (TopExp_Explorer aExpF21(OpenShells.Value(j), TopAbs_FACE); aExpF21.More(); aExpF21.Next()) { TopoDS_Shape aFace = aExpF21.Current(); if (isReversed) aFace.Reverse(); aB.Add(aShell, aFace); } OpenShells.ChangeValue(i) = aShell; OpenShells.Remove(j--); } } OpenShells.Append(aNewShells); } //================================================================================================= Standard_Boolean ShapeFix_Shell::FixFaceOrientation(const TopoDS_Shell& shell, const Standard_Boolean isAccountMultiConex, const Standard_Boolean NonManifold) { // myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK); Standard_Boolean done = Standard_False; TopTools_SequenceOfShape aSeqShells; TopTools_SequenceOfShape aErrFaces; // Compound of faces like to Mebiuce leaf. TopTools_SequenceOfShape Lface; TopTools_DataMapOfShapeShape aMapFaceShells; myShell = shell; myShape = shell; Standard_Integer aNumMultShell = 0; Standard_Integer nbF = 0; TopTools_MapOfShape aMapAdded; for (TopoDS_Iterator iter(shell); iter.More(); iter.Next(), nbF++) { if (aMapAdded.Add(iter.Value())) Lface.Append(iter.Value()); } if (Lface.Length() < nbF) done = Standard_True; TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces; TopExp::MapShapesAndAncestors(myShell, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces); TopTools_MapOfShape aMapMultiConnectEdges; Standard_Boolean isFreeBoundaries = Standard_False; for (Standard_Integer k = 1; k <= aMapEdgeFaces.Extent(); k++) { const Standard_Integer aFaceCount = aMapEdgeFaces.FindFromIndex(k).Extent(); if (!isFreeBoundaries && aFaceCount == 1) { TopoDS_Edge E = TopoDS::Edge(aMapEdgeFaces.FindKey(k)); if (!BRep_Tool::Degenerated(E)) isFreeBoundaries = Standard_True; } // Finds multishared edges else if (isAccountMultiConex && aFaceCount > 2) aMapMultiConnectEdges.Add(aMapEdgeFaces.FindKey(k)); } if (BRep_Tool::IsClosed(myShell) ? isFreeBoundaries : !isFreeBoundaries) { myShell.Closed(!isFreeBoundaries); // clang-format off SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed // clang-format on } Standard_Boolean isGetShells = Standard_True; // Gets possible shells with taking in account of multiconnexity. while (isGetShells && Lface.Length()) { TopTools_SequenceOfShape aTmpSeqShells; if (GetShells(Lface, aMapMultiConnectEdges, aTmpSeqShells, aMapFaceShells, aErrFaces)) { done = Standard_True; } isGetShells = !aTmpSeqShells.IsEmpty(); if (isGetShells) aSeqShells.Append(aTmpSeqShells); } if (!done) done = (aSeqShells.Length() > 1); Standard_Boolean aIsDone = Standard_False; if (Lface.Length() > 0 && aSeqShells.Length()) { for (Standard_Integer jj = 1; jj <= Lface.Length(); jj++) { if (aMapFaceShells.IsBound(Lface.Value(jj))) aMapFaceShells.UnBind(Lface.Value(jj)); } // Addition of faces having only multiconnexity boundary to shells having holes // containing only the multiconnexity edges aIsDone = AddMultiConexityFaces(Lface, aMapMultiConnectEdges, aSeqShells, aMapFaceShells, aMapEdgeFaces, aErrFaces, NonManifold); } aNumMultShell = aSeqShells.Length(); if (!aErrFaces.IsEmpty()) { // if Shell contains of Mebius faces one shell will be created from each those face. BRep_Builder B; B.MakeCompound(myErrFaces); TopoDS_Compound aCompShells; B.MakeCompound(aCompShells); for (Standard_Integer n = 1; n <= aErrFaces.Length(); n++) B.Add(myErrFaces, aErrFaces.Value(n)); if (aNumMultShell) { if (aNumMultShell == 1) { B.Add(aCompShells, aSeqShells.Value(1)); for (Standard_Integer n1 = 1; n1 <= aErrFaces.Length(); n1++) { TopoDS_Shell aSh; B.MakeShell(aSh); B.Add(aSh, aErrFaces.Value(n1)); B.Add(aCompShells, aSh); } myShape = aCompShells; } else { for (Standard_Integer i = 1; i <= aSeqShells.Length(); i++) B.Add(aCompShells, aSeqShells.Value(i)); for (Standard_Integer n1 = 1; n1 <= aErrFaces.Length(); n1++) { TopoDS_Shell aSh; B.MakeShell(aSh); B.Add(aSh, aErrFaces.Value(n1)); B.Add(aCompShells, aSh); } myShape = aCompShells; } } done = Standard_True; myStatus = ShapeExtend::EncodeStatus(ShapeExtend_FAIL); // clang-format off SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG20" ) );// Impossible to orient faces in shell, several shells created // clang-format on return Standard_True; } if (aNumMultShell > 1) { TopTools_SequenceOfShape OpenShells; for (Standard_Integer i1 = 1; i1 <= aSeqShells.Length(); i1++) { TopoDS_Shape aShell = aSeqShells.Value(i1); if (!BRep_Tool::IsClosed(aShell)) { OpenShells.Append(aShell); aSeqShells.Remove(i1--); } } if (OpenShells.Length() > 1) // Attempt of creation closed shell from open shells with taking into account multiconnexity. CreateClosedShell(OpenShells, aMapMultiConnectEdges); aSeqShells.Append(OpenShells); } // In the case if NonManifold is equal to Standard_True one non-manifold shell will be created. // Else compound from shells will be created if length of sequence of shape >1. if (Lface.Length()) { for (Standard_Integer i = 1; i <= Lface.Length(); i++) { BRep_Builder aB; TopoDS_Shell OneShell; aB.MakeShell(OneShell); aB.Add(OneShell, Lface.Value(i)); aSeqShells.Append(OneShell); } } if (NonManifold && aSeqShells.Length() > 1) { CreateNonManifoldShells(aSeqShells, aMapMultiConnectEdges); } if (!done) done = (aSeqShells.Length() > 1 || aIsDone); if (aSeqShells.Length() == 1) { myShell = TopoDS::Shell(aSeqShells.Value(1)); myShape = myShell; myNbShells = 1; } else { BRep_Builder B; TopoDS_Compound aCompShells; B.MakeCompound(aCompShells); for (Standard_Integer i = 1; i <= aSeqShells.Length(); i++) B.Add(aCompShells, aSeqShells.Value(i)); myShape = aCompShells; myNbShells = aSeqShells.Length(); } if (done) { myStatus = ShapeExtend::EncodeStatus(ShapeExtend_DONE2); if (!Context().IsNull()) Context()->Replace(shell, myShape); if (myNbShells == 1) // clang-format off SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG0" ) );// Faces were incorrectly oriented in the shell, corrected else SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG30" ) );// Improperly connected shell split into parts // clang-format on return Standard_True; } else return Standard_False; } //================================================================================================= Standard_Boolean ShapeFix_Shell::Status(const ShapeExtend_Status status) const { return ShapeExtend::DecodeStatus(myStatus, status); } //================================================================================================= TopoDS_Shell ShapeFix_Shell::Shell() { return myShell; } //================================================================================================= TopoDS_Shape ShapeFix_Shell::Shape() { return myShape; } //================================================================================================= TopoDS_Compound ShapeFix_Shell::ErrorFaces() const { return myErrFaces; } //================================================================================================= void ShapeFix_Shell::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg) { ShapeFix_Root::SetMsgRegistrator(msgreg); myFixFace->SetMsgRegistrator(msgreg); } //================================================================================================= void ShapeFix_Shell::SetPrecision(const Standard_Real preci) { ShapeFix_Root::SetPrecision(preci); myFixFace->SetPrecision(preci); } //================================================================================================= void ShapeFix_Shell::SetMinTolerance(const Standard_Real mintol) { ShapeFix_Root::SetMinTolerance(mintol); myFixFace->SetMinTolerance(mintol); } //================================================================================================= void ShapeFix_Shell::SetMaxTolerance(const Standard_Real maxtol) { ShapeFix_Root::SetMaxTolerance(maxtol); myFixFace->SetMaxTolerance(maxtol); } //================================================================================================= Standard_Integer ShapeFix_Shell::NbShells() const { return myNbShells; } //================================================================================================= void ShapeFix_Shell::SetNonManifoldFlag(const Standard_Boolean isNonManifold) { myNonManifold = isNonManifold; }