0022746: Progress indicator in ShapeHealing
[occt.git] / src / ShapeFix / ShapeFix_Shell.cxx
1 // File:        ShapeFix_Shell.cxx
2 // Created:     Wed Aug 12 11:07:12 1998
3 // Author:      Galina KULIKOVA
4 //              <gka@nnov.matra-dtv.fr>
5 // pdn 17.12.98 ie_exhaust-A.stp
6
7 #include <ShapeFix_Shell.ixx>
8
9 #include <Precision.hxx>
10 #include <TopAbs.hxx>
11 #include <TopoDS_Iterator.hxx>
12 #include <TopoDS_Shape.hxx>
13 #include <TopoDS_Face.hxx>
14 #include <TopoDS_Edge.hxx>
15 #include <TopoDS_Shell.hxx>
16 #include <TopoDS.hxx>
17 #include <TopExp_Explorer.hxx>
18 #include <TopExp.hxx>
19
20 #include <TColStd_SequenceOfInteger.hxx>
21 #include <TopTools_SequenceOfShape.hxx>
22 #include <TopTools_MapOfShape.hxx>
23 #include <TopTools_MapIteratorOfMapOfShape.hxx>
24 #include <TopTools_IndexedMapOfShape.hxx>
25 #include <TopTools_DataMapOfShapeShape.hxx>
26 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
27 #include <TopTools_ListOfShape.hxx>
28 #include <TopTools_ListIteratorOfListOfShape.hxx>
29
30 #include <BRep_Builder.hxx>
31 #include <BRep_Tool.hxx>
32
33 #include <ShapeExtend.hxx>
34 #include <ShapeBuild_ReShape.hxx> 
35 #include <Message_Msg.hxx>
36 #include <Message_ProgressSentry.hxx>
37 #include <TopTools_DataMapOfShapeInteger.hxx>
38 #include <TopTools_DataMapOfShapeInteger.hxx>
39 #include <TopTools_DataMapOfShapeInteger.hxx>
40 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
41 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
42 #include <TColStd_DataMapOfIntegerListOfInteger.hxx>
43 #include <Bnd_Box.hxx>
44 #include <BRepBndLib.hxx>
45 #include <Bnd_Array1OfBox.hxx>
46 #include <TColStd_MapOfInteger.hxx>
47 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
48 #include <TopoDS_Iterator.hxx>
49 #include <TopTools_IndexedMapOfShape.hxx>
50 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
51
52 //=======================================================================
53 //function : ShapeFix_Shell
54 //purpose  : 
55 //=======================================================================
56
57 ShapeFix_Shell::ShapeFix_Shell()
58 {    
59   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
60   myFixFaceMode = -1;
61   myFixOrientationMode = -1;
62   myFixFace = new ShapeFix_Face;
63   myNbShells =0;
64 }
65
66 //=======================================================================
67 //function : ShapeFix_Shell
68 //purpose  : 
69 //=======================================================================
70
71 ShapeFix_Shell::ShapeFix_Shell(const TopoDS_Shell& shape)
72 {
73   myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
74   myFixFaceMode = -1;
75   myFixOrientationMode = -1;
76   myFixFace = new ShapeFix_Face;
77   Init(shape);
78 }
79
80 //=======================================================================
81 //function : Init
82 //purpose  : 
83 //=======================================================================
84
85 void ShapeFix_Shell::Init(const TopoDS_Shell& shell) 
86 {
87   myShape = shell;
88   myShell = shell;
89   myNbShells =0;
90 }
91
92 //=======================================================================
93 //function : Perform
94 //purpose  : 
95 //=======================================================================
96
97 Standard_Boolean ShapeFix_Shell::Perform(const Handle(Message_ProgressIndicator)& theProgress) 
98 {
99   Standard_Boolean status = Standard_False;
100   if ( Context().IsNull() )
101     SetContext(new ShapeBuild_ReShape);
102   myFixFace->SetContext(Context());
103
104   if ( NeedFix(myFixFaceMode) )
105   {
106     TopoDS_Shape S = Context()->Apply(myShell);
107
108     // Get the number of faces for progress indication
109     Standard_Integer aNbFaces = 0;
110     for ( TopExp_Explorer aFaceExp(S, TopAbs_FACE); aFaceExp.More(); aFaceExp.Next() )
111       ++aNbFaces;
112
113     // Start progress scope (no need to check if progress exists -- it is safe)
114     Message_ProgressSentry aPSentry(theProgress, "Fixing face", 0, aNbFaces, 1);
115
116     for( TopoDS_Iterator iter(S); iter.More() && aPSentry.More(); iter.Next(), aPSentry.Next() )
117     { 
118       TopoDS_Shape sh = iter.Value();
119       TopoDS_Face tmpFace = TopoDS::Face(sh);
120       myFixFace->Init(tmpFace);
121       if ( myFixFace->Perform() )
122       {
123         status = Standard_True;
124         myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
125       }
126     }
127
128     // Halt algorithm in case of user's abort
129     if ( !aPSentry.More() )
130       return Standard_False;
131   }
132   TopoDS_Shape newsh = Context()->Apply(myShell);
133   if ( NeedFix ( myFixOrientationMode) )
134     FixFaceOrientation(TopoDS::Shell(newsh));
135   if ( status )
136     myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
137   if(Status(ShapeExtend_DONE2))
138     status = Standard_True;
139   return status;
140 }
141
142 //=======================================================================
143 // function : GetFreeEdges
144 // purpose  : 
145 //=======================================================================
146 static Standard_Boolean GetFreeEdges(const TopoDS_Shape& aShape,TopTools_MapOfShape& MapEdges)
147 {
148   for(TopExp_Explorer aExpF(aShape,TopAbs_FACE); aExpF.More(); aExpF.Next()) {
149     for(TopExp_Explorer aExpE(aExpF.Current(),TopAbs_EDGE); aExpE.More(); aExpE.Next()) {
150       TopoDS_Edge edge = TopoDS::Edge(aExpE.Current());
151       if(!MapEdges.Contains(edge))
152         MapEdges.Add(edge);
153       else  MapEdges.Remove(edge);
154     }
155   }
156   return (MapEdges.Extent());
157 }
158 //=======================================================================
159 // function : GetShells
160 // purpose  : If mode isMultiConnex = Standard_True gets max possible shell for 
161 //            exception of multiconnexity parts.
162 //            Else if this mode is equal to Standard_False maximum possible 
163 //            shell will be created without taking account of multiconnexity.
164 //            In this function map face - shell and sequence of mebius faces is formed.
165 //=======================================================================
166 static  Standard_Boolean GetShells(TopTools_SequenceOfShape& Lface,
167                                    const TopTools_MapOfShape& aMapMultiConnectEdges,
168                                    TopTools_SequenceOfShape& aSeqShells,
169                                    TopTools_DataMapOfShapeShape& aMapFaceShells,
170                                    TopTools_SequenceOfShape& ErrFaces) 
171 {
172   Standard_Boolean done = Standard_False;
173   if(!Lface.Length()) return Standard_False;
174   TopoDS_Shell nshell;
175   TopTools_MapOfShape dire, reve;
176   BRep_Builder B;
177   B.MakeShell(nshell);
178   Standard_Boolean isMultiConnex = !aMapMultiConnectEdges.IsEmpty();
179   Standard_Integer i=1, j=1;
180   TopTools_SequenceOfShape aSeqUnconnectFaces;
181   for( ; i<=Lface.Length(); i++)  {
182     TopTools_MapOfShape dtemp, rtemp;
183     Standard_Integer nbbe=0, nbe = 0;
184     TopoDS_Face F1 = TopoDS::Face(Lface.Value(i));
185     for(TopExp_Explorer expe(F1, TopAbs_EDGE); expe.More(); expe.Next()) {
186       TopoDS_Edge edge = TopoDS::Edge(expe.Current());
187       
188       // if multiconnexity mode is equal to Standard_True faces contains
189       // the same multiconnexity edges are not added to one shell.
190       if(isMultiConnex && aMapMultiConnectEdges.Contains(edge))
191         continue;
192       
193       if((edge.Orientation() == TopAbs_FORWARD && dire.Contains(edge))
194          || (edge.Orientation() == TopAbs_REVERSED && reve.Contains(edge))) 
195         nbbe++;
196       else if((edge.Orientation() == TopAbs_FORWARD && reve.Contains(edge))
197               || (edge.Orientation() == TopAbs_REVERSED && dire.Contains(edge)))   
198         nbe++;
199       
200       if(dire.Contains(edge)) dire.Remove(edge);
201       else 
202         if(reve.Contains(edge)) reve.Remove(edge);
203         else {
204           if(edge.Orientation() == TopAbs_FORWARD) dtemp.Add(edge);
205           if(edge.Orientation() == TopAbs_REVERSED) rtemp.Add(edge);
206         }
207     }
208     if(!nbbe && !nbe && dtemp.IsEmpty() && rtemp.IsEmpty()) 
209       continue;
210     
211     // if face can not be added to shell it added to sequence of error faces.
212     
213     if( nbe != 0 && nbbe != 0) {
214       ErrFaces.Append(F1);
215       Lface.Remove(i);
216       j++;
217       continue;
218     }
219     
220     // Addition of face to shell. In the dependance of orientation faces in the shell 
221     //  added face can be reversed.
222     
223     if((nbe != 0 || nbbe != 0) || j == 1) {
224       if(nbbe != 0) {
225         F1.Reverse();
226         for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next()) 
227           reve.Add(ite.Key());
228         for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
229           dire.Add(ite1.Key());
230         done = Standard_True;
231       }
232       else {
233         for(TopTools_MapIteratorOfMapOfShape ite(dtemp); ite.More(); ite.Next()) 
234           dire.Add(ite.Key());
235         for(TopTools_MapIteratorOfMapOfShape ite1(rtemp); ite1.More(); ite1.Next())
236           reve.Add(ite1.Key());
237       }
238       j++;
239       B.Add(nshell,F1);
240       aMapFaceShells.Bind(F1,nshell);
241       Lface.Remove(i);
242       
243       // if closed shell is obtained it adds to sequence of shells and new shell begin to construct.
244       if(isMultiConnex && BRep_Tool::IsClosed(nshell)) {
245         aSeqShells.Append(nshell);
246         TopoDS_Shell nshellnext;
247         B.MakeShell(nshellnext);
248         nshell = nshellnext;
249         j=1;
250       }
251         
252       i=0;
253     }
254     //if shell contains of one face. This face is added to sequence of faces.
255     // This shell is removed.
256     if(Lface.Length() && i == Lface.Length() && j <=2) {
257       TopoDS_Iterator aItf(nshell,Standard_False);
258       if(aItf.More()) {
259         aSeqUnconnectFaces.Append(aItf.Value());
260         aMapFaceShells.UnBind(aItf.Value());
261       }
262       TopoDS_Shell nshellnext;
263       B.MakeShell(nshellnext);
264       nshell = nshellnext;
265       i=0;
266       j=1;
267     }
268   }
269   Standard_Boolean isContains = Standard_False;
270   for(Standard_Integer k =1 ; k <= aSeqShells.Length() && !isContains; k++)
271     isContains = nshell.IsSame(aSeqShells.Value(k));
272   if(!isContains) {
273     Standard_Integer numFace =0;
274     TopoDS_Shape aFace;
275     for(TopoDS_Iterator aItf(nshell,Standard_False) ; aItf.More(); aItf.Next()) {
276       aFace = aItf.Value();
277       numFace++;
278     }
279     if(numFace >1)
280       aSeqShells.Append(nshell);
281     else if(numFace == 1) {
282       if(aMapFaceShells.IsBound(aFace))
283         aMapFaceShells.UnBind(aFace);
284       Lface.Append(aFace);
285     }
286   }
287   
288   //Sequence of faces Lface contains faces which can not be added to obtained shells.
289   for(Standard_Integer j1 =1; j1 <= aSeqUnconnectFaces.Length(); j1++) {
290     Lface.Append(aSeqUnconnectFaces);
291   }
292   
293   return done;
294 }
295 //=======================================================================
296 // function : AddMultiConexityFaces
297 // purpose  : In this function faces have only of multiconnexity boundary
298 //            are added to shells having free boundary contains the same 
299 //            multiconnexity edges as faces.
300 //=======================================================================
301 static Standard_Boolean AddMultiConexityFaces(TopTools_SequenceOfShape& Lface,
302                                               const TopTools_MapOfShape& aMapMultiConnectEdges,
303                                               TopTools_SequenceOfShape& SeqShells,
304                                               const TopTools_DataMapOfShapeShape& aMapFaceShells,
305                                               const TopTools_IndexedDataMapOfShapeListOfShape& aMapEdgeFaces,
306                                               TopTools_SequenceOfShape& ErrFaces,
307                                               const Standard_Boolean NonManifold)
308 {
309   Standard_Boolean done = Standard_False;
310 //  BRep_Builder aB;
311   TopTools_SequenceOfShape llPosibleShells;
312   TopTools_SequenceOfShape AddShapes; 
313   for(Standard_Integer i1 = 1 ; i1<=Lface.Length();i1++ )  {
314    
315     TopoDS_Shape aShape = Lface.Value(i1);
316     
317     Standard_Integer aNbMultEdges =0;
318     
319     //Finds faces having only multiconnexity boundary.
320     for(TopoDS_Iterator aItWires(aShape,Standard_False);  aItWires.More();  aItWires.Next()) {
321       Standard_Integer aNbEdges =0;
322       for(TopoDS_Iterator aItEdges(aItWires.Value(),Standard_False);  aItEdges.More();  aItEdges.Next(),aNbEdges++) {
323         TopoDS_Shape edge = aItEdges.Value();
324         if(!aMapMultiConnectEdges.Contains(edge)) continue;
325         aNbMultEdges++;
326       }
327       if(!aNbMultEdges) continue;
328     
329       if(aNbMultEdges == aNbEdges)
330         AddShapes.Append(aShape);
331       else llPosibleShells.Append(aShape);
332     }
333   }
334   
335   // Attemp to create shell from unconnected which have not only multiconnexity boundary.
336   TopTools_SequenceOfShape aTmpShells;
337   if(!llPosibleShells.IsEmpty()) {
338     TopTools_MapOfShape aMap;
339     TopTools_SequenceOfShape aTmp;
340     TopTools_DataMapOfShapeShape aTmpFaceShell;
341     if(GetShells(llPosibleShells,aMap,aTmpShells,aTmpFaceShell,aTmp)) {
342       for(Standard_Integer kk =1; kk <= aTmpShells.Length(); kk++) {
343         TopoDS_Shape aSh = aTmpShells.Value(kk);
344         TopTools_MapOfShape mapEdges;
345         if(GetFreeEdges(aSh,mapEdges)) {
346           Standard_Integer nbedge =0;
347           for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
348             if( aMapMultiConnectEdges.Contains(amapIter.Key()))
349               nbedge++;
350           }
351           if(nbedge && nbedge == mapEdges.Extent())
352             AddShapes.Append(aSh);
353         }
354       }
355     }
356   }
357   
358   //Add choosen faces to shells.
359   for(Standard_Integer k1 =1; k1 <= AddShapes.Length(); k1++) {
360     TopTools_DataMapOfShapeInteger MapOtherShells;
361     TopTools_MapOfShape dire,reve;
362     TopoDS_Shape aSh = AddShapes.Value(k1);
363     TopTools_MapOfShape mapEdges;
364     if(!GetFreeEdges(aSh,mapEdges)) continue;
365     TopTools_ListOfShape lfaces;
366     
367     //Fill MapOtherShells which will contain shells with orientation in which selected shape aSh will be add.
368     
369     for(TopTools_MapIteratorOfMapOfShape amapIter(mapEdges);amapIter.More(); amapIter.Next()) {
370       if(!aMapMultiConnectEdges.Contains(amapIter.Key())) continue;
371       TopoDS_Edge edge = TopoDS::Edge(amapIter.Key());
372       if( edge.Orientation() == TopAbs_FORWARD) dire.Add(edge);
373       else reve.Add(edge);
374       TopTools_ListOfShape lf;
375       lf = aMapEdgeFaces.FindFromKey(edge);
376       lfaces.Append(lf);
377     }
378     for(TopTools_ListIteratorOfListOfShape aItl(lfaces) ; aItl.More(); aItl.Next()) {
379       TopoDS_Shape aF = aItl.Value();
380       if(!aMapFaceShells.IsBound( aF)) continue;
381      
382       TopoDS_Shape aOthershell;
383       aOthershell = aMapFaceShells.Find(aF);
384       if(MapOtherShells.IsBound(aOthershell)) continue;
385       if(!NonManifold && BRep_Tool::IsClosed(aOthershell))
386         continue;
387       
388       TopTools_MapOfShape mapShellEdges;
389       GetFreeEdges(aOthershell,mapShellEdges);
390       Standard_Boolean isAdd = Standard_True;
391       for(TopTools_MapIteratorOfMapOfShape amapIter1(mapEdges);amapIter1.More() && isAdd ; amapIter1.Next()) 
392         isAdd = mapShellEdges.Contains(amapIter1.Key());
393       
394       if(!isAdd) continue;
395       Standard_Integer nbdir =0, nbrev=0;
396       
397       //add only free face whome all edges contains in the shell as open boundary.
398       for(TopTools_MapIteratorOfMapOfShape aIte( mapShellEdges);aIte.More() ;aIte.Next()) {
399         TopoDS_Edge edgeS = TopoDS::Edge(aIte.Key());
400         if(!aMapMultiConnectEdges.Contains(edgeS)) continue;
401         if( (edgeS.Orientation() == TopAbs_FORWARD && dire.Contains(edgeS)) || (edgeS.Orientation() == TopAbs_REVERSED && reve.Contains(edgeS)))  nbrev++;
402         else if((edgeS.Orientation() == TopAbs_FORWARD && reve.Contains(edgeS))
403                 || (edgeS.Orientation() == TopAbs_REVERSED && dire.Contains(edgeS))) nbdir++;
404       }
405       if(nbdir && nbrev) {
406         ErrFaces.Append(aSh);
407         continue;
408       }
409       if(nbdir || nbrev) {
410         Standard_Integer isReverse =(nbrev ? 1: 0);
411         MapOtherShells.Bind(aOthershell,isReverse);
412       }
413       
414     }
415     if(MapOtherShells.IsEmpty()) {
416 //      i1++;
417       continue;
418     }
419     
420     //Adds face to open shells containg the same multishared edges.
421     //For nonmanifold mode creation ine shell from face and shells containing the same multishared edges.
422     // If one face can be added to a few shells (case of compsolid) face will be added to each shell.
423     done = Standard_True;
424     Standard_Integer FirstRev = 0,FirstInd =0;
425     Standard_Integer ind =0;
426     for(Standard_Integer l =1; l <= SeqShells.Length(); l++) {
427       if(!MapOtherShells.IsBound(SeqShells.Value(l))) continue;
428       ind++;
429       Standard_Integer isRev = MapOtherShells.Find(SeqShells.Value(l));
430       TopoDS_Shape anewShape = (isRev ? aSh.Reversed() :aSh);
431      
432       BRep_Builder aB1;
433       TopoDS_Shape aShell = SeqShells.Value(l);
434       if(ind ==1 || !NonManifold) {
435         if(ind ==1) {
436           FirstRev = isRev;
437           FirstInd = l;
438         }
439         for(TopExp_Explorer aE(anewShape,TopAbs_FACE); aE.More(); aE.Next())
440           aB1.Add(aShell,aE.Current());
441         SeqShells.ChangeValue(l) = aShell;
442       }
443       else if(NonManifold) {
444         Standard_Boolean isReversed = !((!(isRev) && !FirstRev) || ((isRev) && FirstRev));
445         aShell = SeqShells.Value(FirstInd);
446         for(TopoDS_Iterator aItF(SeqShells.Value(l),Standard_False); aItF.More(); aItF.Next()) {
447           TopoDS_Shape nF = ( isReversed ? aItF.Value().Reversed() : aItF.Value());
448           aB1.Add(aShell,nF);
449         }
450         SeqShells.ChangeValue(FirstInd) = aShell;
451         SeqShells.Remove(l--);
452       }
453     }
454       
455     dire.Clear();
456     reve.Clear();
457     for(TopExp_Explorer aEt(aSh,TopAbs_FACE); aEt.More(); aEt.Next()) {
458       for(Standard_Integer kk =1 ; kk <= Lface.Length(); kk++) {
459         if(aEt.Current().IsSame(Lface.Value(kk)))
460           Lface.Remove(kk--);
461       }
462     }
463   }
464   return done;
465 }
466
467 //=======================================================================
468 // function : BoxIn
469 // purpose  : Check if one face contains inside other.
470 //=======================================================================
471 static Standard_Integer BoxIn(const Bnd_Box& theBox1,const Bnd_Box& theBox2)
472 {
473      Standard_Integer aNumIn = 0;
474      Standard_Real aXmin1,aYmin1,aXmax1,aYmax1,aXmin2,aYmin2,aXmax2,aYmax2,aZmin1,aZmax1,aZmin2,aZmax2;
475      theBox1.Get(aXmin1,aYmin1,aZmin1,aXmax1,aYmax1,aZmax1);
476      theBox2.Get(aXmin2,aYmin2,aZmin2,aXmax2,aYmax2,aZmax2);
477      if(aXmin1 == aXmin2 && aXmax1 == aXmax2 && aYmin1 == aYmin2 && aYmax1 == aYmax2 &&
478         aZmin1 == aZmin2 && aZmax1 == aZmax2)
479        aNumIn = 0;
480      else if( aXmin1 >= aXmin2 && aXmax1 <= aXmax2 && aYmin1 >= aYmin2 && aYmax1 <= aYmax2 &&
481         aZmin1 >= aZmin2 && aZmax1 <= aZmax2)  
482         aNumIn = 1;
483      else if( aXmin1 <= aXmin2 && aXmax1 >= aXmax2 && aYmin1 <= aYmin2 && aYmax1 >= aYmax2 && aZmin1 <= aZmin2 && aZmax1 >= aZmax2)
484        aNumIn = 2;
485      return aNumIn;
486 }
487 //=======================================================================
488 // function : GetClosedShells
489 // purpose  : Check if one shell is a part from other shell.
490 //            For case of compsolid when afew shells are created from
491 //            the same set of faces.
492 //=======================================================================
493 static void GetClosedShells(TopTools_SequenceOfShape& Shells, TopTools_SequenceOfShape& aRemainShells)
494 {
495   Bnd_Array1OfBox aBoxes(1,Shells.Length());
496   for(Standard_Integer i =1; i <= Shells.Length(); i++) {
497     Bnd_Box Box;
498     BRepBndLib::AddClose(Shells.Value(i),Box);
499     aBoxes.SetValue(i,Box);
500   }
501   TColStd_MapOfInteger aMapNum;
502   for(Standard_Integer j = 1; j <= aBoxes.Length(); j++) {
503     for(Standard_Integer k = j+1; k <= aBoxes.Length(); k++) {
504       Standard_Integer NumIn = BoxIn(aBoxes.Value(j),aBoxes.Value(k));
505       switch(NumIn) {
506       case 1:aMapNum.Add(k); break;
507       case 2: aMapNum.Add(j); break;
508         default : break;
509       }
510     }
511   }
512   for(Standard_Integer i1 =1; i1 <= Shells.Length(); i1++) {
513     if(!aMapNum.Contains(i1))
514       aRemainShells.Append(Shells.Value(i1));
515   }
516   
517 }
518 //=======================================================================
519 // function : GlueClosedCandidate
520 // purpose  :Attemt firstly to create closed shells from sequence of open shells.
521 //=======================================================================
522 static void GlueClosedCandidate(TopTools_SequenceOfShape& OpenShells,
523                                                     const TopTools_MapOfShape& aMapMultiConnectEdges,
524                                                     TopTools_SequenceOfShape& aSeqNewShells)
525                                                     
526 {
527   // Creating new shells if some open shells contain the same free boundary.
528   for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ )  {
529     TopoDS_Shape aShell = OpenShells.Value(i);
530     TopTools_MapOfShape mapEdges1;
531     TopTools_MapOfShape dire,reve;
532     if(!GetFreeEdges(aShell,mapEdges1)) continue;
533     
534     for(TopTools_MapIteratorOfMapOfShape aIte( mapEdges1);aIte.More() ;aIte.Next()) {
535       TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
536       if(!aMapMultiConnectEdges.Contains(edge1)) break;
537       if(edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1);
538       else if(edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1);
539     }
540     if(mapEdges1.Extent() >(dire.Extent() + reve.Extent())) continue;
541     
542     //Filling map MapOtherShells which contains candidate to creation of closed shell
543     // with aShell.
544     
545     TopTools_DataMapOfShapeInteger MapOtherShells;
546     
547     for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ )  {
548       Standard_Boolean isAddShell = Standard_True;
549       Standard_Boolean isReversed = Standard_False;
550       Standard_Integer nbedge =0;
551       TopTools_MapOfShape mapEdges2;
552       TopoDS_Shape aShell2 = OpenShells.Value(j);
553       if(!GetFreeEdges(aShell2,mapEdges2)) continue;
554       for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() && isAddShell;aIte2.Next()) {
555         TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
556         if(!aMapMultiConnectEdges.Contains(edge2)) {
557           isAddShell = Standard_False;
558           break;
559           //continue;
560         }
561         isAddShell = (dire.Contains(edge2) || reve.Contains(edge2)); 
562         if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
563            || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
564           isReversed = Standard_True;
565         nbedge++;
566       }
567       
568       if(!isAddShell) continue;
569       MapOtherShells.Bind(OpenShells.Value(j),isReversed);
570     }
571     if(!MapOtherShells.Extent()) continue;
572     
573     
574     if(MapOtherShells.Extent() >1) {
575       
576       // Case of compsolid when more than two shells have the same free boundary.
577       TopTools_SequenceOfShape aSeqCandidate;
578       aSeqCandidate.Append(OpenShells.Value(i));
579       
580       for(TopTools_DataMapIteratorOfDataMapOfShapeInteger aIt(MapOtherShells); aIt.More(); aIt.Next())
581        aSeqCandidate.Append(aIt.Key());
582       
583       //Creation all possibly shells from choosen candidate.And
584       // addition of them to temporary sequence.
585       
586       TopTools_SequenceOfShape aTmpSeq;
587       for(Standard_Integer k =1; k <= aSeqCandidate.Length(); k++) {
588         
589         for(Standard_Integer l = k+1; l <= aSeqCandidate.Length(); l++) {
590           TopoDS_Shell aNewSh;
591           BRep_Builder aB;
592           aB.MakeShell(aNewSh);
593           for(TopoDS_Iterator aIt1(aSeqCandidate.Value(k),Standard_False); aIt1.More(); aIt1.Next())
594             aB.Add(aNewSh,aIt1.Value());
595           Standard_Integer isRev = MapOtherShells.Find(aSeqCandidate.Value(l));
596           if(k !=1) {
597             isRev = ((isRev == MapOtherShells.Find(aSeqCandidate.Value(k))) ? 1 : 0);
598           }
599           for(TopExp_Explorer aExp(aSeqCandidate.Value(l),TopAbs_FACE); aExp.More(); aExp.Next()) {
600             TopoDS_Shape aFace = (isRev ? aExp.Current().Reversed(): aExp.Current());
601             aB.Add(aNewSh,aFace);
602           }
603           aTmpSeq.Append(aNewSh);
604         }
605       }
606       
607       //Choice from temporary sequence shells contains different set of faces (case of compsolid) 
608       TopTools_SequenceOfShape aRemainShells;
609       GetClosedShells(aTmpSeq,aRemainShells);
610       aSeqNewShells.Append(aRemainShells);
611       
612       for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ )  {
613         if(!MapOtherShells.IsBound(OpenShells.Value(j1))) continue;
614         OpenShells.Remove(j1--);
615       }
616       
617     }
618     else {
619       BRep_Builder aB;
620       TopoDS_Shape aNewShell = aShell;
621       TopoDS_Shape addShell;
622       Standard_Boolean isReversed = Standard_False;
623       for(Standard_Integer j1 = i+1 ; j1 <= OpenShells.Length();j1++ )  {
624         if(!MapOtherShells.IsBound(OpenShells.Value(j1))) continue;
625         addShell = OpenShells.Value(j1);
626         isReversed = MapOtherShells.Find(addShell);
627         OpenShells.Remove(j1);
628         break;
629       }
630       
631       for(TopExp_Explorer aExpF(addShell,TopAbs_FACE); aExpF.More(); aExpF.Next()) {
632         TopoDS_Shape aFace = aExpF.Current();
633         if(isReversed)
634           aFace.Reverse();
635         aB.Add(aNewShell,aFace);
636       }
637       aSeqNewShells.Append(aNewShell);
638     }
639     
640     //OpenShells.ChangeValue(i) = aShell;
641     OpenShells.Remove(i--);
642   }
643 }
644 //=======================================================================
645 // function : CreateNonManifoldShells
646 // purpose  : Attempt to create max possible shells from open shells.
647 //=======================================================================
648
649 static void CreateNonManifoldShells(TopTools_SequenceOfShape& SeqShells,
650                               const TopTools_MapOfShape& aMapMultiConnectEdges)
651 {
652   TopTools_IndexedDataMapOfShapeListOfShape aMap;
653   for(Standard_Integer i =1 ; i <= SeqShells.Length(); i++) {
654     TopoDS_Shape aShell = SeqShells.Value(i);
655     TopTools_IndexedMapOfShape medeg;
656     TopExp::MapShapes(aShell,TopAbs_EDGE,medeg);
657     for(TopTools_MapIteratorOfMapOfShape mit(aMapMultiConnectEdges); mit.More(); mit.Next()) {
658     //for(TopExp_Explorer aExp(aShell,TopAbs_EDGE); aExp.More(); aExp.Next(),nbe++) {
659       //TopoDS_Shape ae = aExp.Current();
660       TopoDS_Shape ae =mit.Key();
661       //if( aMapMultiConnectEdges.Contains(aExp.Current())) {
662       if(medeg.Contains(ae)) {
663         if(aMap.Contains(ae))
664          aMap.ChangeFromKey(ae).Append(aShell);
665         else {
666           TopTools_ListOfShape al;
667           al.Append(aShell);
668           aMap.Add(ae,al);
669         }
670       }
671     }
672   }
673   TopTools_IndexedDataMapOfShapeShape aMapShells;
674   for(Standard_Integer j =1; j <= aMap.Extent(); j++) {
675     const TopTools_ListOfShape& LShells = aMap.FindFromIndex(j);
676     TopoDS_Shell aNewShell;
677     BRep_Builder aB;
678     aB.MakeShell(aNewShell);
679     TopTools_MapOfShape mapmerge;
680     Standard_Boolean ismerged = Standard_False;
681     Standard_Integer num = 1;
682     for(TopTools_ListIteratorOfListOfShape alit(LShells); alit.More();alit.Next(),num++) { 
683       if(!aMapShells.Contains(alit.Value())) {
684         for(TopExp_Explorer aEf(alit.Value(),TopAbs_FACE); aEf.More(); aEf.Next()) {
685           aB.Add(aNewShell,aEf.Current());
686         }
687         ismerged = Standard_True;
688         mapmerge.Add(alit.Value());
689       }
690       else if(ismerged) {
691         TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
692         while(aMapShells.Contains(arshell)){
693           TopoDS_Shape ss = aMapShells.FindFromKey(arshell);
694           if(ss.IsSame(arshell)) break;
695           arshell = ss;
696         }
697          
698         if(!mapmerge.Contains(arshell)) {
699           for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) {
700             aB.Add(aNewShell,aEf.Current());
701           }
702           mapmerge.Add(arshell);
703         }
704       }
705       else {
706         TopoDS_Shape arshell = aMapShells.FindFromKey(alit.Value());
707          while(aMapShells.Contains(arshell)) {
708           TopoDS_Shape ss = aMapShells.FindFromKey(arshell);
709           if(ss.IsSame(arshell)) break;
710           arshell = ss;
711         }
712         if(num == 1) {
713           for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) 
714             aB.Add(aNewShell,aEf.Current());
715           
716           mapmerge.Add(arshell);
717         }
718         else if(!mapmerge.Contains(arshell)) {
719           for(TopExp_Explorer aEf(arshell,TopAbs_FACE); aEf.More(); aEf.Next()) {
720             aB.Add(aNewShell,aEf.Current());
721           }
722           mapmerge.Add(arshell);
723         }
724       }
725     }
726     if(mapmerge.Extent() >1 || ismerged) {
727       for(TopTools_MapIteratorOfMapOfShape alit1(mapmerge); alit1.More();alit1.Next()) {
728         TopoDS_Shape oldShell = alit1.Key();
729          //while(aMapShells.Contains(oldShell)) {
730          //  TopoDS_Shape ss = aMapShells.FindFromKey(oldShell);
731          //  if(ss.IsSame(oldShell)) break;
732          //  oldShell = ss;
733          //}
734         aMapShells.Add(oldShell,aNewShell);
735       }
736     }
737   }
738   TopTools_IndexedMapOfShape MapNewShells;
739   for(Standard_Integer nn = 1;nn <= SeqShells.Length(); nn++) {
740     if(aMapShells.Contains(SeqShells.Value(nn))) {
741       TopoDS_Shape aNewShell = aMapShells.FindFromKey(SeqShells.Value(nn));
742       while(aMapShells.Contains(aNewShell)) {
743         TopoDS_Shape ss = aMapShells.FindFromKey(aNewShell);
744         if(ss.IsSame(aNewShell)) break;
745         aNewShell = ss;
746       }
747       MapNewShells.Add(aNewShell);
748       
749       SeqShells.Remove(nn--);
750     }
751     
752   }
753   for(Standard_Integer ii =1; ii <= MapNewShells.Extent(); ii++)
754     SeqShells.Append(MapNewShells.FindKey(ii));
755 }
756 //=======================================================================
757 // function : CreateClosedShell
758 // purpose  : Attempt to create max possible shells from open shells.
759 //=======================================================================
760
761 static void CreateClosedShell(TopTools_SequenceOfShape& OpenShells,
762                               const TopTools_MapOfShape& aMapMultiConnectEdges)
763 {
764   TopTools_SequenceOfShape aNewShells;
765   //Attemt firstly to create closed shells.
766   GlueClosedCandidate(OpenShells,aMapMultiConnectEdges,aNewShells);
767   
768   // Creating new shells if some open shells contain the multishared same edges.
769   for(Standard_Integer i = 1 ; i < OpenShells.Length();i++ )  {
770     Standard_Boolean isAddShell = Standard_False;
771     TopoDS_Shape aShell = OpenShells.Value(i);
772     Standard_Boolean isReversed = Standard_False;
773     for(Standard_Integer j = i+1 ; j <= OpenShells.Length();j++ )  {
774       TopTools_MapOfShape mapEdges1;
775       TopTools_MapOfShape dire,reve;
776       if(!GetFreeEdges(aShell,mapEdges1)) break;
777       for(TopTools_MapIteratorOfMapOfShape aIte( mapEdges1);aIte.More() ;aIte.Next()) {
778         TopoDS_Edge edge1 = TopoDS::Edge(aIte.Key());
779         if(!aMapMultiConnectEdges.Contains(edge1)) continue;
780         if(edge1.Orientation() == TopAbs_FORWARD) dire.Add(edge1);
781         else if(edge1.Orientation() == TopAbs_REVERSED) reve.Add(edge1);
782       }
783       if(dire.IsEmpty() &&  reve.IsEmpty()) break;
784       TopTools_MapOfShape mapEdges2;
785       TopoDS_Shape aShell2 = OpenShells.Value(j);
786       if(!GetFreeEdges(aShell2,mapEdges2)) continue;
787       for(TopTools_MapIteratorOfMapOfShape aIte2( mapEdges2);aIte2.More() ;aIte2.Next()) {
788         TopoDS_Edge edge2 = TopoDS::Edge(aIte2.Key());
789         if(!aMapMultiConnectEdges.Contains(edge2)) continue;
790         if(!dire.Contains(edge2) && !reve.Contains(edge2)) continue;
791         isAddShell = Standard_True;
792         if((edge2.Orientation() == TopAbs_FORWARD && dire.Contains(edge2))
793            || (edge2.Orientation() == TopAbs_REVERSED && reve.Contains(edge2)))
794           isReversed = Standard_True;
795       }
796       
797       if(!isAddShell) continue;
798       BRep_Builder aB;
799       
800       for(TopExp_Explorer aExpF21(OpenShells.Value(j),TopAbs_FACE); aExpF21.More(); aExpF21.Next()) {
801         TopoDS_Shape aFace = aExpF21.Current();
802         if(isReversed)
803           aFace.Reverse();
804         aB.Add( aShell,aFace);
805       }
806       
807       OpenShells.ChangeValue(i) = aShell;
808       OpenShells.Remove(j--);
809     }
810   }
811  
812   OpenShells.Append(aNewShells);
813   
814 }
815   
816
817 //=======================================================================
818 // function : FixFaceOrientation
819 // purpose  : 
820 //=======================================================================
821   
822 Standard_Boolean ShapeFix_Shell::FixFaceOrientation(const TopoDS_Shell& shell,const Standard_Boolean isAccountMultiConex,const Standard_Boolean NonManifold) 
823 {
824   //myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
825   Standard_Boolean done = Standard_False;
826   TopTools_SequenceOfShape aSeqShells;
827   TopTools_SequenceOfShape aErrFaces; // Compound of faces like to Mebiuce leaf.
828   TopTools_SequenceOfShape Lface;
829   TopTools_DataMapOfShapeShape aMapFaceShells;
830   myShell = shell;
831   myShape = shell;
832   Standard_Integer aNumMultShell =0;
833   for (TopoDS_Iterator iter(shell); iter.More(); iter.Next()) 
834     Lface.Append(iter.Value());
835   TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
836   TopExp::MapShapesAndAncestors(myShell,TopAbs_EDGE,TopAbs_FACE,aMapEdgeFaces);
837   TopTools_MapOfShape aMapMultiConnectEdges;
838   if(isAccountMultiConex) {
839     //Finds multishared edges
840     for(Standard_Integer k = 1; k <= aMapEdgeFaces.Extent(); k++) {
841       if(aMapEdgeFaces.FindFromIndex(k).Extent() >2)
842         aMapMultiConnectEdges.Add(aMapEdgeFaces.FindKey(k));
843     }
844   }
845   Standard_Boolean isGetShells = Standard_True;
846   //Gets possible shells with taking in account of multiconnexity.
847   while(isGetShells && Lface.Length()) {
848     TopTools_SequenceOfShape aTmpSeqShells;
849     if(GetShells(Lface, aMapMultiConnectEdges, aTmpSeqShells,aMapFaceShells,aErrFaces)) {
850       done = Standard_True;
851     }
852     isGetShells = !aTmpSeqShells.IsEmpty();
853     if(isGetShells) 
854       aSeqShells.Append(aTmpSeqShells);
855   }
856   if(!done)
857     done = (aSeqShells.Length() >1);
858   Standard_Boolean aIsDone = Standard_False;
859   if(Lface.Length() > 0 && aSeqShells.Length()) {
860     for(Standard_Integer jj =1; jj <= Lface.Length(); jj++) {
861       if(aMapFaceShells.IsBound(Lface.Value(jj)))
862         aMapFaceShells.UnBind(Lface.Value(jj));
863     }
864     
865     //Addition of faces having only multiconnexity boundary to shells having holes
866     // containing only the multiconnexity edges
867     aIsDone = AddMultiConexityFaces(Lface,aMapMultiConnectEdges,aSeqShells,aMapFaceShells,
868                                     aMapEdgeFaces,aErrFaces,NonManifold);
869   }
870   aNumMultShell = aSeqShells.Length();
871   if (!aErrFaces.IsEmpty())  {
872     
873     //if Shell contains of Mebius faces one shell will be created from each those face.
874     BRep_Builder B;
875     B.MakeCompound(myErrFaces);
876     TopoDS_Compound aCompShells;
877     B.MakeCompound(aCompShells);
878     for(Standard_Integer n =1; n <= aErrFaces.Length(); n++)
879       B.Add(myErrFaces,aErrFaces.Value(n));
880     if(aNumMultShell) {
881       if(aNumMultShell == 1) {
882         B.Add(aCompShells,aSeqShells.Value(1));
883         for(Standard_Integer n1 =1; n1 <= aErrFaces.Length(); n1++) {
884           TopoDS_Shell aSh;
885           B.MakeShell(aSh);
886           B.Add(aSh,aErrFaces.Value(n1));
887            B.Add(aCompShells,aSh);
888         }
889         myShape = aCompShells;
890       }
891       else {
892         for(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
893           B.Add(aCompShells,aSeqShells.Value(i));
894         for(Standard_Integer n1 =1; n1 <= aErrFaces.Length(); n1++) {
895           TopoDS_Shell aSh;
896           B.MakeShell(aSh);
897           B.Add(aSh,aErrFaces.Value(n1));
898            B.Add(aCompShells,aSh);
899         }
900         myShape = aCompShells;
901       }
902     }
903     
904     done = Standard_True;
905     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL);
906     SendWarning (Message_Msg ("FixAdvShell.FixOrientation.MSG20"));//Faces were incorrectly oriented in the shell, a few shells were created;
907     return Standard_True;
908   }
909   if(aNumMultShell >1) {
910     TopTools_SequenceOfShape OpenShells;
911     for(Standard_Integer i1 =1; i1 <= aSeqShells.Length(); i1++) {
912       TopoDS_Shape aShell = aSeqShells.Value(i1);
913       if(!BRep_Tool::IsClosed(aShell)) {
914         OpenShells.Append(aShell);
915         aSeqShells.Remove(i1--);
916        }
917     }
918     if(OpenShells.Length() >1) 
919       //Attempt of creation closed shell from open shells with taking into account multiconnexity.
920       CreateClosedShell(OpenShells,aMapMultiConnectEdges);
921     aSeqShells.Append(OpenShells);
922     
923   }
924   
925   // In the case if NonManifold is equal to Standard_True one non-manifold shell will be created.
926   //Else compound from shells will be created if length of sequence of shape >1.
927   if(Lface.Length()) {
928    
929     for(Standard_Integer i = 1; i <= Lface.Length();i++) {
930       BRep_Builder aB;
931       TopoDS_Shell OneShell;
932       aB.MakeShell(OneShell);
933       aB.Add(OneShell, Lface.Value(i));
934       aSeqShells.Append(OneShell);
935     }
936       
937   }
938   if(NonManifold && aSeqShells.Length() >1 ) {
939     CreateNonManifoldShells(aSeqShells,aMapMultiConnectEdges);
940   }
941   if(!done)
942     done = (aSeqShells.Length() >1 || aIsDone);
943   if(aSeqShells.Length() == 1) {
944     myShell = TopoDS::Shell(aSeqShells.Value(1));
945     myShape =myShell;
946     myNbShells =1;
947   }
948   else {
949     BRep_Builder B;
950     TopoDS_Compound aCompShells;
951     B.MakeCompound(aCompShells);
952     for(Standard_Integer i =1; i <= aSeqShells.Length(); i++)
953       B.Add(aCompShells,aSeqShells.Value(i));  
954     myShape = aCompShells;
955     myNbShells =  aSeqShells.Length();
956   }
957   if(done) {
958     myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE2);
959     if(!Context().IsNull())
960       Context()->Replace(shell, myShape);
961     if( myNbShells == 1)
962     SendWarning (Message_Msg ("FixAdvShell.FixOrientation.MSG0"));//Faces were incorrectly oriented in the shell, corrected
963     else
964       SendWarning (Message_Msg ("FixAdvShell.FixOrientation.MSG30"));//Bad connected shell ,a few shells were created.
965     return Standard_True;
966   }
967   else return Standard_False;
968 }
969
970 //=======================================================================
971 //function : Status
972 //purpose  : 
973 //=======================================================================
974
975 Standard_Boolean ShapeFix_Shell::Status(const ShapeExtend_Status status) const
976 {
977   return ShapeExtend::DecodeStatus (myStatus, status);
978 }
979
980 //=======================================================================
981 //function : Shell
982 //purpose  : 
983 //=======================================================================
984
985 TopoDS_Shell ShapeFix_Shell::Shell() 
986 {
987  return myShell; 
988 }
989 //=======================================================================
990 //function : Shell
991 //purpose  : 
992 //=======================================================================
993
994 TopoDS_Shape ShapeFix_Shell::Shape() 
995 {
996  return myShape; 
997 }
998
999 //=======================================================================
1000 //function : ErrorFaces
1001 //purpose  : 
1002 //=======================================================================
1003
1004 TopoDS_Compound ShapeFix_Shell::ErrorFaces() const
1005 {
1006   return myErrFaces;
1007 }
1008
1009 //=======================================================================
1010 //function : SetMsgRegistrator
1011 //purpose  : 
1012 //=======================================================================
1013
1014 void ShapeFix_Shell::SetMsgRegistrator(const Handle(ShapeExtend_BasicMsgRegistrator)& msgreg)
1015 {
1016   ShapeFix_Root::SetMsgRegistrator ( msgreg );
1017   myFixFace->SetMsgRegistrator ( msgreg );
1018 }
1019
1020 //=======================================================================
1021 //function : SetPrecision
1022 //purpose  : 
1023 //=======================================================================
1024
1025 void ShapeFix_Shell::SetPrecision (const Standard_Real preci) 
1026 {
1027   ShapeFix_Root::SetPrecision ( preci );
1028   myFixFace->SetPrecision ( preci );
1029 }
1030
1031 //=======================================================================
1032 //function : SetMinTolerance
1033 //purpose  : 
1034 //=======================================================================
1035
1036 void ShapeFix_Shell::SetMinTolerance (const Standard_Real mintol) 
1037 {
1038   ShapeFix_Root::SetMinTolerance ( mintol );
1039   myFixFace->SetMinTolerance ( mintol );
1040 }
1041
1042 //=======================================================================
1043 //function : SetMaxTolerance
1044 //purpose  : 
1045 //=======================================================================
1046
1047 void ShapeFix_Shell::SetMaxTolerance (const Standard_Real maxtol) 
1048 {
1049   ShapeFix_Root::SetMaxTolerance ( maxtol );
1050   myFixFace->SetMaxTolerance ( maxtol );
1051 }
1052 //=======================================================================
1053 //function : NbShells
1054 //purpose  : 
1055 //=======================================================================
1056
1057 Standard_Integer ShapeFix_Shell::NbShells() const
1058 {
1059   return myNbShells;
1060 }