1 // Created on: 1998-08-12
2 // Created by: Galina KULIKOVA
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 // pdn 17.12.98 ie_exhaust-A.stp
19 #include <Bnd_Array1OfBox.hxx>
20 #include <Bnd_Box.hxx>
21 #include <BRep_Builder.hxx>
22 #include <BRep_Tool.hxx>
23 #include <BRepBndLib.hxx>
24 #include <Message_Msg.hxx>
25 #include <Message_ProgressIndicator.hxx>
26 #include <Message_ProgressSentry.hxx>
27 #include <Precision.hxx>
28 #include <ShapeAnalysis_Shell.hxx>
29 #include <ShapeBuild_ReShape.hxx>
30 #include <ShapeExtend.hxx>
31 #include <ShapeExtend_BasicMsgRegistrator.hxx>
32 #include <ShapeFix_Face.hxx>
33 #include <ShapeFix_Shell.hxx>
34 #include <Standard_Type.hxx>
35 #include <TColStd_DataMapOfIntegerListOfInteger.hxx>
36 #include <TColStd_MapOfInteger.hxx>
37 #include <TColStd_SequenceOfInteger.hxx>
40 #include <TopExp_Explorer.hxx>
42 #include <TopoDS_Compound.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Face.hxx>
45 #include <TopoDS_Iterator.hxx>
46 #include <TopoDS_Shape.hxx>
47 #include <TopoDS_Shell.hxx>
48 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
49 #include <TopTools_DataMapOfShapeInteger.hxx>
50 #include <TopTools_DataMapOfShapeShape.hxx>
51 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
52 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
53 #include <TopTools_IndexedMapOfShape.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
55 #include <TopTools_ListOfShape.hxx>
56 #include <TopTools_MapIteratorOfMapOfShape.hxx>
57 #include <TopTools_MapOfShape.hxx>
58 #include <TopTools_SequenceOfShape.hxx>
60 IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Shell,ShapeFix_Root)
62 //=======================================================================
63 //function : ShapeFix_Shell
65 //=======================================================================
66 ShapeFix_Shell::ShapeFix_Shell()
68 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
70 myFixOrientationMode = -1;
71 myFixFace = new ShapeFix_Face;
73 myNonManifold = Standard_False;
76 //=======================================================================
77 //function : ShapeFix_Shell
79 //=======================================================================
81 ShapeFix_Shell::ShapeFix_Shell(const TopoDS_Shell& shape)
83 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
85 myFixOrientationMode = -1;
86 myFixFace = new ShapeFix_Face;
88 myNonManifold = Standard_False;
91 //=======================================================================
94 //=======================================================================
96 void ShapeFix_Shell::Init(const TopoDS_Shell& shell)
103 //=======================================================================
106 //=======================================================================
108 Standard_Boolean ShapeFix_Shell::Perform(const Handle(Message_ProgressIndicator)& theProgress)
110 Standard_Boolean status = Standard_False;
111 if ( Context().IsNull() )
112 SetContext(new ShapeBuild_ReShape);
113 myFixFace->SetContext(Context());
115 if ( NeedFix(myFixFaceMode) )
117 TopoDS_Shape S = Context()->Apply(myShell);
119 // Get the number of faces for progress indication
120 Standard_Integer aNbFaces = S.NbChildren();
122 // Start progress scope (no need to check if progress exists -- it is safe)
123 Message_ProgressSentry aPSentry(theProgress, "Fixing face", 0, aNbFaces, 1);
125 for( TopoDS_Iterator iter(S); iter.More() && aPSentry.More(); iter.Next(), aPSentry.Next() )
127 TopoDS_Shape sh = iter.Value();
128 TopoDS_Face tmpFace = TopoDS::Face(sh);
129 myFixFace->Init(tmpFace);
130 if ( myFixFace->Perform() )
132 status = Standard_True;
133 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
137 // Halt algorithm in case of user's abort
138 if ( !aPSentry.More() )
139 return Standard_False;
142 TopoDS_Shape newsh = Context()->Apply(myShell);
143 if ( NeedFix ( myFixOrientationMode) )
144 FixFaceOrientation(TopoDS::Shell(newsh), Standard_True, myNonManifold);
146 TopoDS_Shape aNewsh = Context()->Apply (newsh);
147 ShapeAnalysis_Shell aSas;
148 for (TopExp_Explorer aShellExp (aNewsh, TopAbs_SHELL); aShellExp.More(); aShellExp.Next())
150 TopoDS_Shell aCurShell = TopoDS::Shell (aShellExp.Current());
151 if (aCurShell.Closed())
153 aSas.LoadShells (aCurShell);
154 aSas.CheckOrientedShells (aCurShell, Standard_True);
155 if (aSas.HasFreeEdges())
157 aCurShell.Closed (Standard_False);
158 SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed
165 myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
166 if(Status(ShapeExtend_DONE2))
167 status = Standard_True;
171 //=======================================================================
172 // function : GetFreeEdges
174 //=======================================================================
175 static Standard_Boolean GetFreeEdges(const TopoDS_Shape& aShape,TopTools_MapOfShape& MapEdges)
177 for(TopExp_Explorer aExpF(aShape,TopAbs_FACE); aExpF.More(); aExpF.Next()) {
178 for(TopExp_Explorer aExpE(aExpF.Current(),TopAbs_EDGE); aExpE.More(); aExpE.Next()) {
179 TopoDS_Edge edge = TopoDS::Edge(aExpE.Current());
180 if(!MapEdges.Contains(edge))
182 else MapEdges.Remove(edge);
185 return !MapEdges.IsEmpty();
187 //=======================================================================
188 // function : GetShells
189 // purpose : If mode isMultiConnex = Standard_True gets max possible shell for
190 // exception of multiconnexity parts.
191 // Else if this mode is equal to Standard_False maximum possible
192 // shell will be created without taking account of multiconnexity.
193 // In this function map face - shell and sequence of mebius faces is formed.
194 //=======================================================================
195 static Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface,
196 const TopTools_MapOfShape& aMapMultiConnectEdges,
197 TopTools_SequenceOfShape& aSeqShells,
198 TopTools_DataMapOfShapeShape& aMapFaceShells,
199 TopTools_SequenceOfShape& ErrFaces)
201 Standard_Boolean done = Standard_False;
202 if(!Lface.Length()) return Standard_False;
204 TopTools_MapOfShape dire, reve;
207 Standard_Boolean isMultiConnex = !aMapMultiConnectEdges.IsEmpty();
208 Standard_Integer i=1, j=1;
209 TopTools_SequenceOfShape aSeqUnconnectFaces;
210 for( ; i<=Lface.Length(); i++) {
211 TopTools_MapOfShape dtemp, rtemp;
212 Standard_Integer nbbe=0, nbe = 0;
213 TopoDS_Face F1 = TopoDS::Face(Lface.Value(i));
214 for(TopExp_Explorer expe(F1, TopAbs_EDGE); expe.More(); expe.Next()) {
215 TopoDS_Edge edge = TopoDS::Edge(expe.Current());
217 // if multiconnexity mode is equal to Standard_True faces contains
218 // the same multiconnexity edges are not added to one shell.
219 if(isMultiConnex && aMapMultiConnectEdges.Contains(edge))
222 if((edge.Orientation() == TopAbs_FORWARD && dire.Contains(edge))
223 || (edge.Orientation() == TopAbs_REVERSED && reve.Contains(edge)))
225 else if((edge.Orientation() == TopAbs_FORWARD && reve.Contains(edge))
226 || (edge.Orientation() == TopAbs_REVERSED && dire.Contains(edge)))
229 if(dire.Contains(edge)) dire.Remove(edge);
231 if(reve.Contains(edge)) reve.Remove(edge);
233 if(edge.Orientation() == TopAbs_FORWARD) dtemp.Add(edge);
234 if(edge.Orientation() == TopAbs_REVERSED) rtemp.Add(edge);
237 if(!nbbe && !nbe && dtemp.IsEmpty() && rtemp.IsEmpty())
240 // if face can not be added to shell it added to sequence of error faces.
242 if( nbe != 0 && nbbe != 0) {
249 // Addition of face to shell. In the dependance of orientation faces in the shell
250 // added face can be reversed.
252 if((nbe != 0 || nbbe != 0) || j == 1) {
255 for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next())
257 for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
258 dire.Add(ite1.Key());
259 done = Standard_True;
262 for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next())
264 for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
265 reve.Add(ite1.Key());
269 aMapFaceShells.Bind(F1,nshell);
272 // check if closed shell is obtained in multy connex mode and add to sequence of
273 // shells and new shell begin to construct.
275 if(isMultiConnex && BRep_Tool::IsClosed (nshell)) {
276 nshell.Closed (Standard_True);
277 aSeqShells.Append(nshell);
278 TopoDS_Shell nshellnext;
279 B.MakeShell(nshellnext);
286 //if shell contains of one face. This face is added to sequence of faces.
287 // This shell is removed.
288 if(Lface.Length() && i == Lface.Length() && j <=2) {
289 TopoDS_Iterator aItf(nshell,Standard_False);
291 aSeqUnconnectFaces.Append(aItf.Value());
292 aMapFaceShells.UnBind(aItf.Value());
294 TopoDS_Shell nshellnext;
295 B.MakeShell(nshellnext);
301 Standard_Boolean isContains = Standard_False;
302 for(Standard_Integer k =1 ; k <= aSeqShells.Length() && !isContains; k++)
303 isContains = nshell.IsSame(aSeqShells.Value(k));
305 Standard_Integer numFace =0;
307 for(TopoDS_Iterator aItf(nshell,Standard_False) ; aItf.More(); aItf.Next()) {
308 aFace = aItf.Value();
312 // close all closed shells in no multy connex mode
314 nshell.Closed (BRep_Tool::IsClosed (nshell));
315 aSeqShells.Append(nshell);
317 else if(numFace == 1) {
318 if(aMapFaceShells.IsBound(aFace))
319 aMapFaceShells.UnBind(aFace);
324 //Sequence of faces Lface contains faces which can not be added to obtained shells.
325 for(Standard_Integer j1 =1; j1 <= aSeqUnconnectFaces.Length(); j1++) {
326 Lface.Append(aSeqUnconnectFaces);
331 //=======================================================================
332 // function : AddMultiConexityFaces
333 // purpose : In this function faces have only of multiconnexity boundary
334 // are added to shells having free boundary contains the same
335 // multiconnexity edges as faces.
336 //=======================================================================
337 static Standard_Boolean AddMultiConexityFaces(TopTools_SequenceOfShape& Lface,
338 const TopTools_MapOfShape& aMapMultiConnectEdges,
339 TopTools_SequenceOfShape& SeqShells,
340 const TopTools_DataMapOfShapeShape& aMapFaceShells,
341 const TopTools_IndexedDataMapOfShapeListOfShape& aMapEdgeFaces,
342 TopTools_SequenceOfShape& ErrFaces,
343 const Standard_Boolean NonManifold)
345 Standard_Boolean done = Standard_False;
347 TopTools_SequenceOfShape llPosibleShells;
348 TopTools_SequenceOfShape AddShapes;
349 for(Standard_Integer i1 = 1 ; i1<=Lface.Length();i1++ ) {
351 TopoDS_Shape aShape = Lface.Value(i1);
353 Standard_Integer aNbMultEdges =0;
355 //Finds faces having only multiconnexity boundary.
356 for(TopoDS_Iterator aItWires(aShape,Standard_False); aItWires.More(); aItWires.Next()) {
357 Standard_Integer aNbEdges =0;
358 for(TopoDS_Iterator aItEdges(aItWires.Value(),Standard_False); aItEdges.More(); aItEdges.Next(),aNbEdges++) {
359 TopoDS_Shape edge = aItEdges.Value();
360 if(!aMapMultiConnectEdges.Contains(edge)) continue;
363 if(!aNbMultEdges) continue;
365 if(aNbMultEdges == aNbEdges)
366 AddShapes.Append(aShape);
367 else llPosibleShells.Append(aShape);
371 // Attemp to create shell from unconnected which have not only multiconnexity boundary.
372 TopTools_SequenceOfShape aTmpShells;
373 if(!llPosibleShells.IsEmpty()) {
374 TopTools_MapOfShape aMap;
375 TopTools_SequenceOfShape aTmp;
376 TopTools_DataMapOfShapeShape aTmpFaceShell;
377 if(GetShells(llPosibleShells,aMap,aTmpShells,aTmpFaceShell,aTmp)) {
378 for(Standard_Integer kk =1; kk <= aTmpShells.Length(); kk++) {
379 TopoDS_Shape aSh = aTmpShells.Value(kk);
380 TopTools_MapOfShape mapEdges;
381 if(GetFreeEdges(aSh,mapEdges)) {
382 Standard_Integer nbedge =0;
383 for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
384 if( aMapMultiConnectEdges.Contains(amapIter.Key()))
387 if(nbedge && nbedge == mapEdges.Extent())
388 AddShapes.Append(aSh);
394 //Add choosen faces to shells.
395 for(Standard_Integer k1 =1; k1 <= AddShapes.Length(); k1++) {
396 TopTools_DataMapOfShapeInteger MapOtherShells;
397 TopTools_MapOfShape dire,reve;
398 TopoDS_Shape aSh = AddShapes.Value(k1);
399 TopTools_MapOfShape mapEdges;
400 if(!GetFreeEdges(aSh,mapEdges)) continue;
401 TopTools_ListOfShape lfaces;
403 //Fill MapOtherShells which will contain shells with orientation in which selected shape aSh will be add.
405 for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
406 if(!aMapMultiConnectEdges.Contains(amapIter.Key())) continue;
407 TopoDS_Edge edge = TopoDS::Edge(amapIter.Key());
408 if( edge.Orientation() == TopAbs_FORWARD) dire.Add(edge);
410 TopTools_ListOfShape lf;
411 lf = aMapEdgeFaces.FindFromKey(edge);
414 for(TopTools_ListIteratorOfListOfShape aItl(lfaces) ; aItl.More(); aItl.Next()) {
415 TopoDS_Shape aF = aItl.Value();
416 if(!aMapFaceShells.IsBound( aF)) continue;
418 TopoDS_Shape aOthershell;
419 aOthershell = aMapFaceShells.Find(aF);
420 if(MapOtherShells.IsBound(aOthershell)) continue;
421 if(!NonManifold && BRep_Tool::IsClosed(aOthershell))
424 TopTools_MapOfShape mapShellEdges;
425 GetFreeEdges(aOthershell,mapShellEdges);
426 Standard_Boolean isAdd = Standard_True;
427 for(TopTools_MapIteratorOfMapOfShape amapIter1(mapEdges);amapIter1.More() && isAdd ; amapIter1.Next())
428 isAdd = mapShellEdges.Contains(amapIter1.Key());
431 Standard_Integer nbdir =0, nbrev=0;
433 //add only free face whome all edges contains in the shell as open boundary.
434 for(TopTools_MapIteratorOfMapOfShape aIte( mapShellEdges);aIte.More() ;aIte.Next()) {
435 TopoDS_Edge edgeS = TopoDS::Edge(aIte.Key());
436 if(!aMapMultiConnectEdges.Contains(edgeS)) continue;
437 if( (edgeS.Orientation() == TopAbs_FORWARD && dire.Contains(edgeS)) || (edgeS.Orientation() == TopAbs_REVERSED && reve.Contains(edgeS))) nbrev++;
438 else if((edgeS.Orientation() == TopAbs_FORWARD && reve.Contains(edgeS))
439 || (edgeS.Orientation() == TopAbs_REVERSED && dire.Contains(edgeS))) nbdir++;
442 ErrFaces.Append(aSh);
446 Standard_Integer isReverse =(nbrev ? 1: 0);
447 MapOtherShells.Bind(aOthershell,isReverse);
451 if(MapOtherShells.IsEmpty()) {
456 //Adds face to open shells containg the same multishared edges.
457 //For nonmanifold mode creation ine shell from face and shells containing the same multishared edges.
458 // If one face can be added to a few shells (case of compsolid) face will be added to each shell.
459 done = Standard_True;
460 Standard_Integer FirstRev = 0,FirstInd =0;
461 Standard_Integer ind =0;
462 for(Standard_Integer l =1; l <= SeqShells.Length(); l++) {
463 if(!MapOtherShells.IsBound(SeqShells.Value(l))) continue;
465 Standard_Integer isRev = MapOtherShells.Find(SeqShells.Value(l));
466 TopoDS_Shape anewShape = (isRev ? aSh.Reversed() :aSh);
469 TopoDS_Shape aShell = SeqShells.Value(l);
470 if(ind ==1 || !NonManifold) {
475 for(TopExp_Explorer aE(anewShape,TopAbs_FACE); aE.More(); aE.Next())
476 aB1.Add(aShell,aE.Current());
477 SeqShells.ChangeValue(l) = aShell;
479 else if(NonManifold) {
480 Standard_Boolean isReversed = !((!(isRev) && !FirstRev) || ((isRev) && FirstRev));
481 aShell = SeqShells.Value(FirstInd);
482 for(TopoDS_Iterator aItF(SeqShells.Value(l),Standard_False); aItF.More(); aItF.Next()) {
483 TopoDS_Shape nF = ( isReversed ? aItF.Value().Reversed() : aItF.Value());
486 SeqShells.ChangeValue(FirstInd) = aShell;
487 SeqShells.Remove(l--);
493 for(TopExp_Explorer aEt(aSh,TopAbs_FACE); aEt.More(); aEt.Next()) {
494 for(Standard_Integer kk =1 ; kk <= Lface.Length(); kk++) {
495 if(aEt.Current().IsSame(Lface.Value(kk)))
503 //=======================================================================
505 // purpose : Check if one face contains inside other.
506 //=======================================================================
507 static Standard_Integer BoxIn(const Bnd_Box& theBox1,const Bnd_Box& theBox2)
509 Standard_Integer aNumIn = 0;
510 Standard_Real aXmin1,aYmin1,aXmax1,aYmax1,aXmin2,aYmin2,aXmax2,aYmax2,aZmin1,aZmax1,aZmin2,aZmax2;
511 theBox1.Get(aXmin1,aYmin1,aZmin1,aXmax1,aYmax1,aZmax1);
512 theBox2.Get(aXmin2,aYmin2,aZmin2,aXmax2,aYmax2,aZmax2);
513 if(aXmin1 == aXmin2 && aXmax1 == aXmax2 && aYmin1 == aYmin2 && aYmax1 == aYmax2 &&
514 aZmin1 == aZmin2 && aZmax1 == aZmax2)
516 else if( aXmin1 >= aXmin2 && aXmax1 <= aXmax2 && aYmin1 >= aYmin2 && aYmax1 <= aYmax2 &&
517 aZmin1 >= aZmin2 && aZmax1 <= aZmax2)
519 else if( aXmin1 <= aXmin2 && aXmax1 >= aXmax2 && aYmin1 <= aYmin2 && aYmax1 >= aYmax2 && aZmin1 <= aZmin2 && aZmax1 >= aZmax2)
523 //=======================================================================
524 // function : GetClosedShells
525 // purpose : Check if one shell is a part from other shell.
526 // For case of compsolid when afew shells are created from
527 // the same set of faces.
528 //=======================================================================
529 static void GetClosedShells(TopTools_SequenceOfShape& Shells, TopTools_SequenceOfShape& aRemainShells)
531 Bnd_Array1OfBox aBoxes(1,Shells.Length());
532 for(Standard_Integer i =1; i <= Shells.Length(); i++) {
534 BRepBndLib::AddClose(Shells.Value(i),Box);
535 aBoxes.SetValue(i,Box);
537 TColStd_MapOfInteger aMapNum;
538 for(Standard_Integer j = 1; j <= aBoxes.Length(); j++) {
539 for(Standard_Integer k = j+1; k <= aBoxes.Length(); k++) {
540 Standard_Integer NumIn = BoxIn(aBoxes.Value(j),aBoxes.Value(k));
542 case 1:aMapNum.Add(k); break;
543 case 2: aMapNum.Add(j); break;
548 for(Standard_Integer i1 =1; i1 <= Shells.Length(); i1++) {
549 if(!aMapNum.Contains(i1))
550 aRemainShells.Append(Shells.Value(i1));
554 //=======================================================================
555 // function : GlueClosedCandidate
556 // purpose :Attemt firstly to create closed shells from sequence of open shells.
557 //=======================================================================
558 static void GlueClosedCandidate(TopTools_SequenceOfShape& OpenShells,
559 const TopTools_MapOfShape& aMapMultiConnectEdges,
560 TopTools_SequenceOfShape& aSeqNewShells)
563 // Creating new shells if some open shells contain the same free boundary.
564 for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ ) {
565 TopoDS_Shape aShell = OpenShells.Value(i);
566 TopTools_MapOfShape mapEdges1;
567 TopTools_MapOfShape dire,reve;
568 if(!GetFreeEdges(aShell,mapEdges1)) continue;
570 for(TopTools_MapIteratorOfMapOfShape aIte( mapEdges1);aIte.More() ;aIte.Next()) {
571 TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
572 if(!aMapMultiConnectEdges.Contains(edge1)) break;
573 if(edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1);
574 else if(edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1);
576 if(mapEdges1.Extent() >(dire.Extent() + reve.Extent())) continue;
578 //Filling map MapOtherShells which contains candidate to creation of closed shell
580 NCollection_DataMap<TopoDS_Shape, Standard_Boolean, TopTools_ShapeMapHasher> MapOtherShells;
581 for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ ) {
582 Standard_Boolean isAddShell = Standard_True;
583 Standard_Boolean isReversed = Standard_False;
584 Standard_Integer nbedge =0;
585 TopTools_MapOfShape mapEdges2;
586 TopoDS_Shape aShell2 = OpenShells.Value(j);
587 if(!GetFreeEdges(aShell2,mapEdges2)) continue;
588 for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() && isAddShell;aIte2.Next()) {
589 TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
590 if(!aMapMultiConnectEdges.Contains(edge2)) {
591 isAddShell = Standard_False;
595 isAddShell = (dire.Contains(edge2) || reve.Contains(edge2));
596 if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
597 || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
598 isReversed = Standard_True;
602 if(!isAddShell) continue;
603 MapOtherShells.Bind(OpenShells.Value(j),isReversed);
605 if(MapOtherShells.IsEmpty()) continue;
608 if (!MapOtherShells.IsEmpty())
610 // Case of compsolid when more than two shells have the same free boundary.
611 TopTools_SequenceOfShape aSeqCandidate;
612 aSeqCandidate.Append(OpenShells.Value(i));
614 for (NCollection_DataMap<TopoDS_Shape, Standard_Boolean, TopTools_ShapeMapHasher>::Iterator aIt(MapOtherShells); aIt.More(); aIt.Next())
616 aSeqCandidate.Append(aIt.Key());
619 //Creation all possibly shells from choosen candidate.And
620 // addition of them to temporary sequence.
622 TopTools_SequenceOfShape aTmpSeq;
623 for(Standard_Integer k =1; k <= aSeqCandidate.Length(); k++) {
625 for(Standard_Integer l = k+1; l <= aSeqCandidate.Length(); l++) {
628 aB.MakeShell(aNewSh);
629 for(TopoDS_Iterator aIt1(aSeqCandidate.Value(k),Standard_False); aIt1.More(); aIt1.Next())
630 aB.Add(aNewSh,aIt1.Value());
631 Standard_Boolean isRev = MapOtherShells.Find(aSeqCandidate.Value(l));
633 isRev = (isRev == MapOtherShells.Find(aSeqCandidate.Value(k)));
635 for(TopExp_Explorer aExp(aSeqCandidate.Value(l),TopAbs_FACE); aExp.More(); aExp.Next()) {
636 TopoDS_Shape aFace = (isRev ? aExp.Current().Reversed(): aExp.Current());
637 aB.Add(aNewSh,aFace);
639 aTmpSeq.Append(aNewSh);
643 //Choice from temporary sequence shells contains different set of faces (case of compsolid)
644 TopTools_SequenceOfShape aRemainShells;
645 GetClosedShells(aTmpSeq,aRemainShells);
646 aSeqNewShells.Append(aRemainShells);
648 for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ ) {
649 if(!MapOtherShells.IsBound(OpenShells.Value(j1))) continue;
650 OpenShells.Remove(j1--);
656 TopoDS_Shape aNewShell = aShell;
657 TopoDS_Shape addShell;
658 Standard_Boolean isReversed = Standard_False;
659 for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ ) {
660 if(!MapOtherShells.Find (OpenShells.Value(j1), isReversed)) continue;
661 addShell = OpenShells.Value(j1);
662 OpenShells.Remove(j1);
666 for(TopExp_Explorer aExpF(addShell,TopAbs_FACE); aExpF.More(); aExpF.Next()) {
667 TopoDS_Shape aFace = aExpF.Current();
670 aB.Add(aNewShell,aFace);
672 aSeqNewShells.Append(aNewShell);
675 //OpenShells.ChangeValue(i) = aShell;
676 OpenShells.Remove(i--);
679 //=======================================================================
680 // function : CreateNonManifoldShells
681 // purpose : Attempt to create max possible shells from open shells.
682 //=======================================================================
684 static void CreateNonManifoldShells(TopTools_SequenceOfShape& SeqShells,
685 const TopTools_MapOfShape& aMapMultiConnectEdges)
687 TopTools_IndexedDataMapOfShapeListOfShape aMap;
688 for(Standard_Integer i =1 ; i <= SeqShells.Length(); i++) {
689 TopoDS_Shape aShell = SeqShells.Value(i);
690 TopTools_IndexedMapOfShape medeg;
691 TopExp::MapShapes(aShell,TopAbs_EDGE,medeg);
692 for(TopTools_MapIteratorOfMapOfShape mit(aMapMultiConnectEdges); mit.More(); mit.Next()) {
693 //for(TopExp_Explorer aExp(aShell,TopAbs_EDGE); aExp.More(); aExp.Next(),nbe++) {
694 //TopoDS_Shape ae = aExp.Current();
695 TopoDS_Shape ae =mit.Key();
696 //if( aMapMultiConnectEdges.Contains(aExp.Current())) {
697 if(medeg.Contains(ae)) {
698 if(aMap.Contains(ae))
699 aMap.ChangeFromKey(ae).Append(aShell);
701 TopTools_ListOfShape al;
708 TopTools_IndexedDataMapOfShapeShape aMapShells;
709 for(Standard_Integer j =1; j <= aMap.Extent(); j++) {
710 const TopTools_ListOfShape& LShells = aMap.FindFromIndex(j);
711 TopoDS_Shell aNewShell;
713 aB.MakeShell(aNewShell);
714 TopTools_MapOfShape mapmerge;
715 Standard_Boolean ismerged = Standard_False;
716 Standard_Integer num = 1;
717 for(TopTools_ListIteratorOfListOfShape alit(LShells); alit.More();alit.Next(),num++) {
718 if(!aMapShells.Contains(alit.Value())) {
719 for(TopExp_Explorer aEf(alit.Value(),TopAbs_FACE); aEf.More(); aEf.Next()) {
720 aB.Add(aNewShell,aEf.Current());
722 ismerged = Standard_True;
723 mapmerge.Add(alit.Value());
726 TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
727 while(aMapShells.Contains(arshell)){
728 TopoDS_Shape ss = aMapShells.FindFromKey(arshell);
729 if(ss.IsSame(arshell)) break;
733 if(!mapmerge.Contains(arshell)) {
734 for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) {
735 aB.Add(aNewShell,aEf.Current());
737 mapmerge.Add(arshell);
741 TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
742 while(aMapShells.Contains(arshell)) {
743 TopoDS_Shape ss = aMapShells.FindFromKey(arshell);
744 if(ss.IsSame(arshell)) break;
748 for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next())
749 aB.Add(aNewShell,aEf.Current());
751 mapmerge.Add(arshell);
753 else if(!mapmerge.Contains(arshell)) {
754 for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) {
755 aB.Add(aNewShell,aEf.Current());
757 mapmerge.Add(arshell);
761 if(mapmerge.Extent() >1 || ismerged) {
762 for(TopTools_MapIteratorOfMapOfShape alit1(mapmerge); alit1.More();alit1.Next()) {
763 TopoDS_Shape oldShell = alit1.Key();
764 //while(aMapShells.Contains(oldShell)) {
765 // TopoDS_Shape ss = aMapShells.FindFromKey(oldShell);
766 // if(ss.IsSame(oldShell)) break;
769 aMapShells.Add(oldShell,aNewShell);
773 TopTools_IndexedMapOfShape MapNewShells;
774 for(Standard_Integer nn = 1;nn <= SeqShells.Length(); nn++) {
775 if(aMapShells.Contains(SeqShells.Value(nn))) {
776 TopoDS_Shape aNewShell = aMapShells.FindFromKey(SeqShells.Value(nn));
777 while(aMapShells.Contains(aNewShell)) {
778 TopoDS_Shape ss = aMapShells.FindFromKey(aNewShell);
779 if(ss.IsSame(aNewShell)) break;
782 MapNewShells.Add(aNewShell);
784 SeqShells.Remove(nn--);
788 for(Standard_Integer ii =1; ii <= MapNewShells.Extent(); ii++)
789 SeqShells.Append(MapNewShells.FindKey(ii));
791 //=======================================================================
792 // function : CreateClosedShell
793 // purpose : Attempt to create max possible shells from open shells.
794 //=======================================================================
796 static void CreateClosedShell(TopTools_SequenceOfShape& OpenShells,
797 const TopTools_MapOfShape& aMapMultiConnectEdges)
799 TopTools_SequenceOfShape aNewShells;
800 //Attemt firstly to create closed shells.
801 GlueClosedCandidate(OpenShells,aMapMultiConnectEdges,aNewShells);
803 // Creating new shells if some open shells contain the multishared same edges.
804 for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ ) {
805 Standard_Boolean isAddShell = Standard_False;
806 TopoDS_Shape aShell = OpenShells.Value(i);
807 Standard_Boolean isReversed = Standard_False;
808 for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ ) {
809 TopTools_MapOfShape mapEdges1;
810 TopTools_MapOfShape dire,reve;
811 if(!GetFreeEdges(aShell,mapEdges1)) break;
812 for(TopTools_MapIteratorOfMapOfShape aIte( mapEdges1);aIte.More() ;aIte.Next()) {
813 TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
814 if(!aMapMultiConnectEdges.Contains(edge1)) continue;
815 if(edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1);
816 else if(edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1);
818 if(dire.IsEmpty() && reve.IsEmpty()) break;
819 TopTools_MapOfShape mapEdges2;
820 TopoDS_Shape aShell2 = OpenShells.Value(j);
821 if(!GetFreeEdges(aShell2,mapEdges2)) continue;
822 for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() ;aIte2.Next()) {
823 TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
824 if(!aMapMultiConnectEdges.Contains(edge2)) continue;
825 if(!dire.Contains(edge2) && !reve.Contains(edge2)) continue;
826 isAddShell = Standard_True;
827 if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
828 || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
829 isReversed = Standard_True;
832 if(!isAddShell) continue;
835 for(TopExp_Explorer aExpF21(OpenShells.Value(j),TopAbs_FACE); aExpF21.More(); aExpF21.Next()) {
836 TopoDS_Shape aFace = aExpF21.Current();
839 aB.Add( aShell,aFace);
842 OpenShells.ChangeValue(i) = aShell;
843 OpenShells.Remove(j--);
847 OpenShells.Append(aNewShells);
852 //=======================================================================
853 // function : FixFaceOrientation
855 //=======================================================================
857 Standard_Boolean ShapeFix_Shell::FixFaceOrientation(
858 const TopoDS_Shell& shell,
859 const Standard_Boolean isAccountMultiConex,
860 const Standard_Boolean NonManifold)
862 //myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
863 Standard_Boolean done = Standard_False;
864 TopTools_SequenceOfShape aSeqShells;
865 TopTools_SequenceOfShape aErrFaces; // Compound of faces like to Mebiuce leaf.
866 TopTools_SequenceOfShape Lface;
867 TopTools_DataMapOfShapeShape aMapFaceShells;
870 Standard_Integer aNumMultShell =0;
871 Standard_Integer nbF = 0;
872 TopTools_MapOfShape aMapAdded;
873 for (TopoDS_Iterator iter(shell); iter.More(); iter.Next(),nbF++)
875 if(aMapAdded.Add(iter.Value()))
876 Lface.Append(iter.Value());
878 if(Lface.Length() < nbF)
879 done = Standard_True;
881 TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
882 TopExp::MapShapesAndAncestors(myShell,TopAbs_EDGE,TopAbs_FACE,aMapEdgeFaces);
883 TopTools_MapOfShape aMapMultiConnectEdges;
884 Standard_Boolean isFreeBoundaries = Standard_False;
885 for(Standard_Integer k = 1; k <= aMapEdgeFaces.Extent(); k++) {
886 const Standard_Integer aFaceCount = aMapEdgeFaces.FindFromIndex(k).Extent();
887 if (!isFreeBoundaries && aFaceCount == 1) {
888 TopoDS_Edge E = TopoDS::Edge(aMapEdgeFaces.FindKey(k));
889 if (!BRep_Tool::Degenerated(E))
890 isFreeBoundaries = Standard_True;
892 //Finds multishared edges
893 else if (isAccountMultiConex && aFaceCount > 2)
894 aMapMultiConnectEdges.Add(aMapEdgeFaces.FindKey(k));
896 if (BRep_Tool::IsClosed(myShell)? isFreeBoundaries : !isFreeBoundaries)
898 myShell.Closed (!isFreeBoundaries);
899 SendWarning (Message_Msg ("FixAdvShell.FixClosedFlag.MSG0"));//Shell has incorrect flag isClosed
901 Standard_Boolean isGetShells = Standard_True;
902 //Gets possible shells with taking in account of multiconnexity.
903 while(isGetShells && Lface.Length()) {
904 TopTools_SequenceOfShape aTmpSeqShells;
905 if(GetShells(Lface, aMapMultiConnectEdges, aTmpSeqShells,aMapFaceShells,aErrFaces)) {
906 done = Standard_True;
908 isGetShells = !aTmpSeqShells.IsEmpty();
910 aSeqShells.Append(aTmpSeqShells);
913 done = (aSeqShells.Length() >1);
914 Standard_Boolean aIsDone = Standard_False;
915 if(Lface.Length() > 0 && aSeqShells.Length()) {
916 for(Standard_Integer jj =1; jj <= Lface.Length(); jj++) {
917 if(aMapFaceShells.IsBound(Lface.Value(jj)))
918 aMapFaceShells.UnBind(Lface.Value(jj));
921 //Addition of faces having only multiconnexity boundary to shells having holes
922 // containing only the multiconnexity edges
923 aIsDone = AddMultiConexityFaces(Lface,aMapMultiConnectEdges,aSeqShells,aMapFaceShells,
924 aMapEdgeFaces,aErrFaces,NonManifold);
926 aNumMultShell = aSeqShells.Length();
927 if (!aErrFaces.IsEmpty()) {
929 //if Shell contains of Mebius faces one shell will be created from each those face.
931 B.MakeCompound(myErrFaces);
932 TopoDS_Compound aCompShells;
933 B.MakeCompound(aCompShells);
934 for(Standard_Integer n =1; n <= aErrFaces.Length(); n++)
935 B.Add(myErrFaces,aErrFaces.Value(n));
937 if(aNumMultShell == 1) {
938 B.Add(aCompShells,aSeqShells.Value(1));
939 for(Standard_Integer n1 =1; n1 <= aErrFaces.Length(); n1++) {
942 B.Add(aSh,aErrFaces.Value(n1));
943 B.Add(aCompShells,aSh);
945 myShape = aCompShells;
948 for(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
949 B.Add(aCompShells,aSeqShells.Value(i));
950 for(Standard_Integer n1 =1; n1 <= aErrFaces.Length(); n1++) {
953 B.Add(aSh,aErrFaces.Value(n1));
954 B.Add(aCompShells,aSh);
956 myShape = aCompShells;
960 done = Standard_True;
961 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL);
962 SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG20" ) );// Impossible to orient faces in shell, several shells created
963 return Standard_True;
965 if(aNumMultShell >1) {
966 TopTools_SequenceOfShape OpenShells;
967 for(Standard_Integer i1 =1; i1 <= aSeqShells.Length(); i1++) {
968 TopoDS_Shape aShell = aSeqShells.Value(i1);
969 if(!BRep_Tool::IsClosed(aShell)) {
970 OpenShells.Append(aShell);
971 aSeqShells.Remove(i1--);
974 if(OpenShells.Length() >1)
975 //Attempt of creation closed shell from open shells with taking into account multiconnexity.
976 CreateClosedShell(OpenShells,aMapMultiConnectEdges);
977 aSeqShells.Append(OpenShells);
981 // In the case if NonManifold is equal to Standard_True one non-manifold shell will be created.
982 //Else compound from shells will be created if length of sequence of shape >1.
985 for(Standard_Integer i = 1; i <= Lface.Length();i++) {
987 TopoDS_Shell OneShell;
988 aB.MakeShell(OneShell);
989 aB.Add(OneShell, Lface.Value(i));
990 aSeqShells.Append(OneShell);
994 if(NonManifold && aSeqShells.Length() >1 ) {
995 CreateNonManifoldShells(aSeqShells,aMapMultiConnectEdges);
998 done = (aSeqShells.Length() >1 || aIsDone);
999 if(aSeqShells.Length() == 1) {
1000 myShell = TopoDS::Shell(aSeqShells.Value(1));
1006 TopoDS_Compound aCompShells;
1007 B.MakeCompound(aCompShells);
1008 for(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
1009 B.Add(aCompShells,aSeqShells.Value(i));
1010 myShape = aCompShells;
1011 myNbShells = aSeqShells.Length();
1014 myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
1015 if(!Context().IsNull())
1016 Context()->Replace(shell, myShape);
1017 if ( myNbShells == 1 )
1018 SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG0" ) );// Faces were incorrectly oriented in the shell, corrected
1020 SendWarning ( Message_Msg ( "FixAdvShell.FixOrientation.MSG30" ) );// Improperly connected shell split into parts
1021 return Standard_True;
1023 else return Standard_False;
1026 //=======================================================================
1029 //=======================================================================
1031 Standard_Boolean ShapeFix_Shell::Status(const ShapeExtend_Status status) const
1033 return ShapeExtend::DecodeStatus (myStatus, status);
1036 //=======================================================================
1039 //=======================================================================
1041 TopoDS_Shell ShapeFix_Shell::Shell()
1045 //=======================================================================
1048 //=======================================================================
1050 TopoDS_Shape ShapeFix_Shell::Shape()
1055 //=======================================================================
1056 //function : ErrorFaces
1058 //=======================================================================
1060 TopoDS_Compound ShapeFix_Shell::ErrorFaces() const
1065 //=======================================================================
1066 //function : SetMsgRegistrator
1068 //=======================================================================
1070 void ShapeFix_Shell::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
1072 ShapeFix_Root::SetMsgRegistrator ( msgreg );
1073 myFixFace->SetMsgRegistrator ( msgreg );
1076 //=======================================================================
1077 //function : SetPrecision
1079 //=======================================================================
1081 void ShapeFix_Shell::SetPrecision (const Standard_Real preci)
1083 ShapeFix_Root::SetPrecision ( preci );
1084 myFixFace->SetPrecision ( preci );
1087 //=======================================================================
1088 //function : SetMinTolerance
1090 //=======================================================================
1092 void ShapeFix_Shell::SetMinTolerance (const Standard_Real mintol)
1094 ShapeFix_Root::SetMinTolerance ( mintol );
1095 myFixFace->SetMinTolerance ( mintol );
1098 //=======================================================================
1099 //function : SetMaxTolerance
1101 //=======================================================================
1103 void ShapeFix_Shell::SetMaxTolerance (const Standard_Real maxtol)
1105 ShapeFix_Root::SetMaxTolerance ( maxtol );
1106 myFixFace->SetMaxTolerance ( maxtol );
1109 //=======================================================================
1110 //function : NbShells
1112 //=======================================================================
1114 Standard_Integer ShapeFix_Shell::NbShells() const
1119 //=======================================================================
1120 //function : SetNonManifoldFlag
1122 //=======================================================================
1124 void ShapeFix_Shell::SetNonManifoldFlag(const Standard_Boolean isNonManifold)
1126 myNonManifold = isNonManifold;