34c42b29fa15bc8f7913868f35521e0b4f731892
[occt.git] / src / BRepCheck / BRepCheck_Shell.cxx
1 // File:        BRepCheck_Shell.cxx
2 // Created:     Tue Dec 12 17:49:08 1995
3 // Author:      Jacques GOUSSARD
4 //              <jag@bravox>
5
6
7 #include <BRepCheck_Shell.ixx>
8
9 #include <BRepCheck_ListOfStatus.hxx>
10 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
11
12 #include <TopTools_MapOfShape.hxx>
13 #include <TopTools_MapIteratorOfMapOfShape.hxx>
14 #include <TopTools_ListOfShape.hxx>
15 #include <TopTools_ListIteratorOfListOfShape.hxx>
16 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
17 #include <BRep_Tool.hxx>
18 #include <BRep_Builder.hxx>
19
20 #include <TopExp_Explorer.hxx>
21
22 #include <BRepCheck.hxx>
23 #include <TopoDS.hxx>
24 #include <TopoDS_Edge.hxx>
25 #include <TopoDS_Face.hxx>
26 #include <TopExp.hxx>
27
28 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
29 #include <TopTools_DataMapOfShapeInteger.hxx>
30
31
32 Standard_EXPORT Standard_Integer BRepCheck_Trace(const Standard_Integer phase) {
33   static int BRC_Trace = 0;
34   if (phase < 0) BRC_Trace =0;
35   else if (phase > 0) BRC_Trace=phase;
36   return BRC_Trace;
37 }
38
39 void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
40   if (!theShape.IsNull()) {
41     Standard_Integer code = theShape.HashCode(upper);
42     
43     switch (theShape.ShapeType()) {
44     case TopAbs_COMPOUND :
45       cout << "COMPOUND";
46       break;
47     case TopAbs_COMPSOLID :
48       cout << "COMPSOLID";
49       break;
50     case TopAbs_SOLID :
51       cout << "SOLID";
52       break;
53     case TopAbs_SHELL :
54       cout << "SHELL";
55       break;
56     case TopAbs_FACE :
57       cout << "FACE";
58       break;
59     case TopAbs_WIRE :
60       cout << "WIRE";
61       break;
62     case TopAbs_EDGE :
63       cout << "EDGE";
64       break;
65     case TopAbs_VERTEX :
66       cout << "VERTEX";
67       break;
68     case TopAbs_SHAPE :
69       cout << "SHAPE";
70       break;
71     }
72     cout << " : " << code << " ";
73     switch (theShape.Orientation()) {
74     case TopAbs_FORWARD :
75       cout << "FORWARD";
76       break;
77     case TopAbs_REVERSED :
78       cout << "REVERSED";
79       break;
80     case TopAbs_INTERNAL :
81       cout << "INTERNAL";
82       break;
83     case TopAbs_EXTERNAL :
84       cout << "EXTERNAL";
85       break;
86     }
87     cout << endl;
88   }
89 }
90     
91 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape&,
92                       const TopoDS_Shape&,   // Face
93                       TopTools_MapOfShape&);  // mapofface
94
95
96 #ifdef DEB
97 static TopAbs_Orientation GetOrientation(const TopoDS_Face&,
98                                          const TopoDS_Shape&);
99 #endif
100
101
102 inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
103 {
104   return (S.Orientation() == TopAbs_FORWARD ||
105           S.Orientation() == TopAbs_REVERSED);
106 }
107
108
109 //=======================================================================
110 //function : BRepCheck_Shell
111 //purpose  : 
112 //=======================================================================
113
114 BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
115 {
116   Init(S);
117 }
118
119
120 //=======================================================================
121 //function : Minimum
122 //purpose  : 
123 //=======================================================================
124
125 void BRepCheck_Shell::Minimum()
126 {
127   myCdone = Standard_False;
128   myOdone = Standard_False;
129
130   if (!myMin) {
131     BRepCheck_ListOfStatus thelist;
132     myMap.Bind(myShape, thelist);
133     BRepCheck_ListOfStatus& lst = myMap(myShape);
134
135     // it is checked if the shell is "connected"
136     TopExp_Explorer exp(myShape,TopAbs_FACE);
137     Standard_Integer nbface = 0;
138     myMapEF.Clear();
139     for (; exp.More(); exp.Next()) {
140       nbface++;
141       TopExp_Explorer expe;
142       for (expe.Init(exp.Current(),TopAbs_EDGE); 
143            expe.More(); expe.Next()) {
144         const TopoDS_Shape& edg = expe.Current();
145         Standard_Integer index = myMapEF.FindIndex(edg);
146         if (index == 0) {
147           TopTools_ListOfShape thelist1;
148           index = myMapEF.Add(edg, thelist1);
149         }
150         myMapEF(index).Append(exp.Current());
151       }
152     }
153
154     if (nbface == 0) {
155       BRepCheck::Add(lst,BRepCheck_EmptyShell);
156     }
157     else if (nbface >= 2) {
158       TopTools_MapOfShape mapF;
159       exp.ReInit();
160       Propagate(myMapEF,exp.Current(),mapF);
161       if (mapF.Extent() != nbface)  {
162         BRepCheck::Add(lst,BRepCheck_NotConnected);
163       }
164     }
165     if (lst.IsEmpty()) {
166       lst.Append(BRepCheck_NoError);
167     }
168     myMapEF.Clear();
169     myMin = Standard_True;
170   }
171 }
172
173
174
175 //=======================================================================
176 //function : InContext
177 //purpose  : 
178 //=======================================================================
179
180 void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
181 {
182
183   if (myMap.IsBound(S)) {
184     return;
185   }
186   BRepCheck_ListOfStatus thelist;
187   myMap.Bind(S, thelist);
188
189   BRepCheck_ListOfStatus& lst = myMap(S);
190
191 //  for (TopExp_Explorer exp(S,TopAbs_SHELL); exp.More(); exp.Next()) {
192   TopExp_Explorer exp(S,TopAbs_SHELL) ;
193   for ( ; exp.More(); exp.Next()) {
194     if (exp.Current().IsSame(myShape)) {
195       break;
196     }
197   }
198   if (!exp.More()) {
199     BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
200     return;
201   }
202
203   TopAbs_ShapeEnum styp = S.ShapeType();
204   switch (styp) {
205
206   case TopAbs_SOLID:
207     {
208       BRepCheck_Status fst = Closed();
209       if ((fst == BRepCheck_NotClosed && S.Closed()) ||
210           (fst != BRepCheck_NoError)) {
211         BRepCheck::Add(lst,fst);
212       }
213       else if (!IsUnorientable()) {
214         fst = Orientation();
215         BRepCheck::Add(lst,fst);
216       }
217     }
218     break;
219
220   default:
221     break;
222   }
223
224
225   if (lst.IsEmpty()) {
226     lst.Append(BRepCheck_NoError);
227   }
228 }
229
230
231 //=======================================================================
232 //function : Blind
233 //purpose  : 
234 //=======================================================================
235
236 void BRepCheck_Shell::Blind()
237 {
238   if (!myBlind) {
239     // nothing more than in the minimum
240     myBlind = Standard_True;
241   }
242 }
243
244
245 //=======================================================================
246 //function : Closed
247 //purpose  : 
248 //=======================================================================
249
250 BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
251 {
252
253   if (myCdone) {
254     if (Update) {
255       BRepCheck::Add(myMap(myShape), myCstat);
256     }
257     return myCstat;
258   }
259
260   myCdone = Standard_True; // it will be done...
261
262   BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
263   if (itl.Value() != BRepCheck_NoError) {
264     myCstat = itl.Value();
265     return myCstat; // already saved
266   }
267
268   myCstat = BRepCheck_NoError;
269   //
270   Standard_Integer index, aNbF;
271   TopExp_Explorer exp, ede;
272   TopTools_MapOfShape mapS, aMEToAvoid;
273   myMapEF.Clear();
274   
275
276   // Checks if the oriented faces of the shell give a "closed" shell,
277   // i-e if each oriented edge on oriented faces is found 2 times.
278   //
279   //modified by NIZNHY-PKV Mon Jun  4 13:59:21 2007f
280   exp.Init(myShape,TopAbs_FACE);
281   for (; exp.More(); exp.Next()) {
282     const TopoDS_Shape& aF=exp.Current();
283     if (IsOriented(aF)) {
284       ede.Init(exp.Current(),TopAbs_EDGE);
285       for (; ede.More(); ede.Next()) {
286         const TopoDS_Shape& aE=ede.Current();
287         if (!IsOriented(aE)) {
288           aMEToAvoid.Add(aE);
289         }
290       }
291     }
292   }
293   //modified by NIZNHY-PKV Mon Jun  4 13:59:23 2007t
294   //
295   exp.Init(myShape,TopAbs_FACE);
296   for (; exp.More(); exp.Next()) {
297     const TopoDS_Shape& aF=exp.Current();
298     if (IsOriented(aF)) {
299       if (!mapS.Add(aF)) {
300         myCstat = BRepCheck_RedundantFace;
301         if (Update) {
302           BRepCheck::Add(myMap(myShape),myCstat);
303         }
304         return myCstat;
305       }
306       //
307       ede.Init(exp.Current(),TopAbs_EDGE);
308       for (; ede.More(); ede.Next()) {
309         const TopoDS_Shape& aE=ede.Current();
310         //modified by NIZNHY-PKV Mon Jun  4 14:07:57 2007f
311         //if (IsOriented(aE)) {
312         if (!aMEToAvoid.Contains(aE)) {
313           //modified by NIZNHY-PKV Mon Jun  4 14:08:01 2007
314           index = myMapEF.FindIndex(aE);
315           if (!index) {
316             TopTools_ListOfShape thelist;
317             index = myMapEF.Add(aE, thelist);
318           }
319           myMapEF(index).Append(aF);
320         }
321       }
322     }
323   }
324   //
325   myNbori = mapS.Extent();
326   if (myNbori >= 2) {
327     mapS.Clear();
328     // Search for the first oriented face
329     TopoDS_Shape aF;
330     exp.Init(myShape, TopAbs_FACE);
331     for (;exp.More(); exp.Next()) {
332       aF=exp.Current();
333       if (IsOriented(aF)) {
334         break;
335       }
336     }
337     //
338     Propagate(myMapEF, aF, mapS);
339   }
340   //
341   //
342   aNbF=mapS.Extent();
343   if (myNbori != aNbF) {
344     myCstat = BRepCheck_NotConnected;
345     if (Update) {
346       BRepCheck::Add(myMap(myShape),myCstat);
347     }
348     return myCstat;
349   }
350   //
351   //
352   Standard_Integer i, Nbedges, nboc, nbSet;
353   //
354   Nbedges = myMapEF.Extent();
355   for (i = 1; i<=Nbedges; ++i) {
356     nboc = myMapEF(i).Extent();
357     if (nboc == 0 || nboc >= 3) {
358       TopTools_ListOfShape theSet;
359       nbSet=NbConnectedSet(theSet);
360       // If there is more than one closed cavity the shell is considered invalid
361       // this corresponds to the criteria of a solid (not those of a shell)
362       if (nbSet>1) {
363         myCstat = BRepCheck_InvalidMultiConnexity;
364         if (Update) {
365           BRepCheck::Add(myMap(myShape),myCstat);
366         }
367         return myCstat;
368       }
369     }
370     else if (nboc == 1) {
371       if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i)))) {
372         myCstat=BRepCheck_NotClosed;
373         if (Update) {
374           BRepCheck::Add(myMap(myShape),myCstat);
375         }
376         return myCstat;
377       }
378     }
379   }
380   
381   if (Update) {
382     BRepCheck::Add(myMap(myShape),myCstat);
383   }
384   return myCstat;
385 }
386
387
388 //=======================================================================
389 //function : Orientation
390 //purpose  : 
391 //=======================================================================
392
393 BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
394 {
395   if (myOdone) {
396     if (Update) {
397       BRepCheck::Add(myMap(myShape), myOstat);
398     }
399     return myOstat;
400   }
401   myOdone = Standard_True;
402
403   myOstat = Closed();
404   if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
405     if (Update) {
406       BRepCheck::Add(myMap(myShape), myOstat);
407     }
408     return myOstat;
409   }
410
411   myOstat = BRepCheck_NoError;
412
413
414 // First the orientation of each face in relation to the shell is found.
415 // It is used to check BRepCheck_RedundantFace
416
417   TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
418   TopExp_Explorer exp,ede;
419
420   for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
421     if (!MapOfShapeOrientation.Bind(exp.Current(), (Standard_Integer)(exp.Current().Orientation()))) {
422       myOstat = BRepCheck_RedundantFace;
423       if (Update) {
424         BRepCheck::Add(myMap(myShape), myOstat);
425       }
426       else {
427         return myOstat;
428       }
429     }
430   }
431
432 #ifdef DEB
433   if (BRepCheck_Trace(0) > 1) {
434     TopTools_DataMapIteratorOfDataMapOfShapeInteger itt(MapOfShapeOrientation);
435     Standard_Integer upper = MapOfShapeOrientation.NbBuckets();
436     cout << "La map shape Orientation :" << endl;
437     for (; itt.More(); itt.Next()) {
438       PrintShape(itt.Key(), upper);
439     }
440     cout << endl;
441   }
442 #endif
443
444
445 // Then the orientation of faces by their connectivity is checked
446 // BRepCheck_BadOrientationOfSubshape and 
447 //         BRepCheck_SubshapeNotInShape are checked;
448
449   Standard_Integer Nbedges = myMapEF.Extent();
450   TopoDS_Face Fref;
451   TopAbs_Orientation orf;
452
453   for (Standard_Integer i = 1; i<= Nbedges; i++) {
454
455     const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(i));
456     if (BRep_Tool::Degenerated(edg)) continue;
457     TopTools_ListOfShape& lface = myMapEF(i);
458     TopTools_ListIteratorOfListOfShape lite(lface);
459
460     if (lface.Extent() <= 2)
461       {
462         lite.Initialize(lface);
463         Fref = TopoDS::Face(lite.Value());
464         
465         if (!MapOfShapeOrientation.IsBound(Fref)) {
466           myOstat = BRepCheck_SubshapeNotInShape;
467           if (Update) {
468             BRepCheck::Add(myMap(myShape), myOstat);
469             }
470           // quit because no workaround for the incoherence is possible
471           return myOstat;
472         }
473         lite.Next();
474         
475         if (lite.More()) { // Edge of connectivity
476           //JR/Hp :
477           Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
478           orf = (TopAbs_Orientation) iorf;
479           //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
480           Fref.Orientation(orf);
481           
482           // edge is examined
483           if (!lite.Value().IsSame(Fref)) { // edge non "closed"
484             for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
485               if (ede.Current().IsSame(edg)) {
486                 break;
487               }
488             }
489             TopAbs_Orientation orient = ede.Current().Orientation();
490             TopoDS_Face Fcur= TopoDS::Face(lite.Value());
491             
492             if (!MapOfShapeOrientation.IsBound(Fcur)) {
493               myOstat = BRepCheck_SubshapeNotInShape;
494               if (Update) {
495                 BRepCheck::Add(myMap(myShape), myOstat);
496                 }
497               // quit because no workaround for the incoherence is possible
498               return myOstat;
499             }
500             
501             //JR/Hp :
502             Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
503             orf = (TopAbs_Orientation) iorf ;
504             //  orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
505             Fcur.Orientation(orf);
506             
507             for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
508               if (ede.Current().IsSame(edg)) {
509                 break;
510               }
511             }
512             if (ede.Current().Orientation() == orient) {
513               // The loop is continued on the edges as many times 
514               // as the same edge is present in the wire
515
516               // modified by NIZHNY-MKK  Tue Sep 30 11:11:42 2003
517               Standard_Boolean bfound = Standard_False;
518               ede.Next();
519               for (; ede.More(); ede.Next()) {
520                 if (ede.Current().IsSame(edg)) {
521                   // modified by NIZHNY-MKK  Tue Sep 30 11:12:03 2003
522                   bfound = Standard_True;
523                   break;
524                 }
525               }
526               //              if (ede.Current().Orientation() == orient) {
527               // modified by NIZHNY-MKK  Thu Oct  2 17:56:47 2003
528               if (!bfound || (ede.Current().Orientation() == orient)) {
529                 myOstat = BRepCheck_BadOrientationOfSubshape;
530                 if (Update) {
531                   BRepCheck::Add(myMap(myShape), myOstat);
532                     break;
533                   }
534                 return myOstat;
535               }
536             }
537           }
538         }
539       }
540     else //more than two faces
541       {
542         Standard_Integer numF = 0, numR = 0;
543         TopTools_MapOfShape Fmap;
544
545         for (lite.Initialize(lface); lite.More(); lite.Next())
546           {
547             TopoDS_Face Fcur= TopoDS::Face(lite.Value());
548             if (!MapOfShapeOrientation.IsBound(Fcur))
549               {
550                 myOstat = BRepCheck_SubshapeNotInShape;
551                 if (Update)
552                   BRepCheck::Add(myMap(myShape), myOstat);
553               // quit because no workaround for the incoherence is possible
554                 return myOstat;
555               }
556
557             Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
558             orf = (TopAbs_Orientation) iorf;
559             //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
560             Fcur.Orientation(orf);
561
562             for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
563               if (ede.Current().IsSame(edg))
564                 break;
565             if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
566               {
567                 ede.Next();
568                 for (; ede.More(); ede.Next())
569                   if (ede.Current().IsSame(edg))
570                     break;
571               }
572             TopAbs_Orientation orient = ede.Current().Orientation();
573             if (orient == TopAbs_FORWARD)
574               numF++;
575             else
576               numR++;
577
578             Fmap.Add(Fcur);
579           }
580
581         if (numF != numR)
582           {
583             myOstat = BRepCheck_BadOrientationOfSubshape;
584             if (Update)
585               {
586                 BRepCheck::Add(myMap(myShape), myOstat);
587                 break;
588               }
589             return myOstat;
590           }
591       }
592   }
593
594 // If at least one incorrectly oriented face has been found, it is checked if the shell can be oriented. 
595 //          i.e. : if by modification of the orientation of a face it is possible to find 
596 //          a coherent orientation. (it is not possible on a Moebius band)
597 //          BRepCheck_UnorientableShape is checked
598
599   if (myOstat == BRepCheck_BadOrientationOfSubshape) {
600     if (!Fref.IsNull()) {
601       if (Nbedges > 0) {
602         TopTools_MapOfShape alre;
603         TopTools_ListOfShape voisin;
604         voisin.Append(Fref);
605         alre.Clear();
606         while (!voisin.IsEmpty()) {
607           Fref=TopoDS::Face(voisin.First());
608           voisin.RemoveFirst();
609           if (!MapOfShapeOrientation.IsBound(Fref)) {
610             myOstat = BRepCheck_SubshapeNotInShape;
611             if (Update) {
612               BRepCheck::Add(myMap(myShape), myOstat);
613             }
614             // quit because no workaround for the incoherence is possible
615             return myOstat;
616           }
617 //JR/Hp :
618           Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
619           orf = (TopAbs_Orientation) iorf ;
620 //        orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
621           Fref.Orientation(orf);
622
623 #ifdef DEB
624   if (BRepCheck_Trace(0) > 3) {
625     cout << "Fref : " ;
626     PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
627   }
628 #endif
629
630           TopExp_Explorer edFcur;
631           alre.Add(Fref);
632
633           for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
634             const TopoDS_Edge& edg = TopoDS::Edge(ede.Current());
635             TopAbs_Orientation orient = edg.Orientation();
636             TopTools_ListOfShape& lface = myMapEF.ChangeFromKey(edg);
637             TopTools_ListIteratorOfListOfShape lite(lface);
638           
639             TopoDS_Face Fcur= TopoDS::Face(lite.Value());
640             if (Fcur.IsSame(Fref)) {
641               lite.Next();
642               if (lite.More()) {
643                 Fcur=TopoDS::Face(lite.Value());
644               }
645               else {
646                 // from the free border one goes to the next edge
647                 continue;
648               }
649             }
650
651             if (!MapOfShapeOrientation.IsBound(Fcur)) {
652               myOstat = BRepCheck_SubshapeNotInShape;
653               if (Update) {
654                 BRepCheck::Add(myMap(myShape), myOstat);
655               }
656               // quit because no workaround for the incoherence is possible
657               return myOstat;
658             }
659
660 //JR/Hp :
661             Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
662             orf = (TopAbs_Orientation) iorf ;
663 //          orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
664             Fcur.Orientation(orf);
665
666 #ifdef DEB
667   if (BRepCheck_Trace(0) > 3) {
668     cout << "    Fcur : " ;
669     PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
670   }
671 #endif
672             for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
673               if (edFcur.Current().IsSame(edg)) {
674                 break;
675               }
676             }
677             if (edFcur.Current().Orientation() == orient) {
678               if (alre.Contains(Fcur)) {
679                 // It is necessary to return a face that has been already examined or returned
680                 // if one gets nowhere, the shell cannot be oriented.
681                 myOstat = BRepCheck_UnorientableShape;
682                 if (Update) {
683                   BRepCheck::Add(myMap(myShape), myOstat);
684                 }
685                 // quit, otherwise there is a risk of taking too much time.
686 #ifdef DEB
687   if (BRepCheck_Trace(0) > 3) {
688     orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
689     Fcur.Orientation(orf);
690     cout << "    Error : this face has been already examined " << endl;
691     cout << "    Imposible to return it ";
692     PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
693   }
694 #endif
695                 return myOstat;
696               }
697               orf = TopAbs::Reverse(orf);
698               MapOfShapeOrientation(Fcur)=orf;
699
700
701 #ifdef DEB
702   if (BRepCheck_Trace(0) > 3) {
703     orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
704     Fcur.Orientation(orf);
705     cout << "    Resulting Fcur is returned : " ;
706     PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
707   }
708 #endif
709
710             }
711             if (alre.Add(Fcur)) {
712               voisin.Append(Fcur);
713             }
714           }
715         }
716       }
717     }
718   }
719
720   if (Update) {
721     BRepCheck::Add(myMap(myShape), myOstat);
722   }
723   return myOstat;
724 }
725
726 //=======================================================================
727 //function : SetUnorientable
728 //purpose  : 
729 //=======================================================================
730
731 void BRepCheck_Shell::SetUnorientable()
732 {
733   BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
734 }
735
736
737 //=======================================================================
738 //function : IsUnorientable
739 //purpose  : 
740 //=======================================================================
741
742 Standard_Boolean BRepCheck_Shell::IsUnorientable() const
743 {
744   if (myOdone) {
745     return (myOstat != BRepCheck_NoError);
746   }
747   for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
748        itl.More();
749        itl.Next()) {
750     if (itl.Value() == BRepCheck_UnorientableShape) {
751       return Standard_True;
752     }
753   }
754   return Standard_False;
755 }
756
757 //=======================================================================
758 //function : NbConnectedSet
759 //purpose  : 
760 //=======================================================================
761
762 Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
763 {
764   // The connections are found 
765   TopTools_IndexedDataMapOfShapeListOfShape parents;
766   TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, parents);
767   // All faces are taken
768   TopTools_MapOfShape theFaces;
769   TopExp_Explorer exsh(myShape, TopAbs_FACE);
770   for (; exsh.More(); exsh.Next()) theFaces.Add(exsh.Current());
771   // The edges that are not oriented or have more than 2 connections are missing
772   Standard_Integer iCur;
773   TopTools_MapOfShape theMultiEd;
774   TopTools_MapOfShape theUnOriEd;
775   for (iCur=1; iCur<=parents.Extent(); iCur++) {
776     const TopoDS_Edge& Ed = TopoDS::Edge(parents.FindKey(iCur));
777     if (parents(iCur).Extent()> 2) theMultiEd.Add(Ed);
778     if (Ed.Orientation()!=TopAbs_REVERSED &&
779         Ed.Orientation()!=TopAbs_FORWARD) theUnOriEd.Add(Ed);
780   }
781   // Starting from multiconnected edges propagation by simple connections
782   TopTools_ListIteratorOfListOfShape lconx1, lconx2;
783   TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
784   TopoDS_Shell CurShell;
785   TopoDS_Shape adFac;
786   TopTools_ListOfShape lesCur;
787   BRep_Builder BRB;
788   Standard_Boolean newCur=Standard_True;
789   BRB.MakeShell(CurShell);
790   for (; itmsh.More(); itmsh.Next()) {
791     const TopoDS_Shape& Ed = itmsh.Key();
792     if (!theUnOriEd.Contains(Ed)) {
793       for (lconx1.Initialize(parents.FindFromKey(Ed)); lconx1.More(); lconx1.Next()) {
794         if (theFaces.Contains(lconx1.Value())) {
795           adFac=lconx1.Value();
796           BRB.Add(CurShell, adFac);
797           theFaces.Remove(adFac);
798           newCur=Standard_False;
799           if (theFaces.IsEmpty()) break;
800           lesCur.Append(adFac);
801           while (!lesCur.IsEmpty()) {
802             adFac=lesCur.First();
803             lesCur.RemoveFirst();
804             for (exsh.Init(adFac, TopAbs_EDGE); exsh.More(); exsh.Next()) {
805               const TopoDS_Shape& ced = exsh.Current();
806               if (!theMultiEd.Contains(ced)) {
807                 for (lconx2.Initialize(parents.FindFromKey(ced)); lconx2.More(); lconx2.Next()) {
808                   if (theFaces.Contains(lconx2.Value())) {
809                     adFac=lconx2.Value();
810                     BRB.Add(CurShell, adFac);
811                     theFaces.Remove(adFac);
812                     newCur=Standard_False;
813                     if (theFaces.IsEmpty()) break;
814                     lesCur.Append(adFac);
815                   }
816                 }
817               }
818               if (theFaces.IsEmpty()) break;
819             }
820           }
821           if (!newCur) {
822            theSets.Append(CurShell);
823            CurShell.Nullify();
824            newCur=Standard_True;
825            BRB.MakeShell(CurShell);
826           }
827         }
828         if (theFaces.IsEmpty()) break;
829       }
830     }
831     if (theFaces.IsEmpty()) break;
832   }
833   return theSets.Extent();
834 }
835
836 //=======================================================================
837 //function : GetOrientation
838 //purpose  : 
839 //=======================================================================
840
841 #ifdef DEB
842 static TopAbs_Orientation GetOrientation(const TopoDS_Face& F,
843                                          const TopoDS_Shape& S)
844
845 {
846   TopExp_Explorer exp;
847   for (exp.Init(S,TopAbs_FACE); exp.More(); exp.Next()) {
848     if (exp.Current().IsSame(F)) {
849       return exp.Current().Orientation();
850     }
851   }
852   return TopAbs_FORWARD; // for compilation
853 }
854 #endif
855
856
857 //=======================================================================
858 //function : Propagate
859 //purpose  : 
860 //=======================================================================
861
862 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
863                       const TopoDS_Shape& fac,
864                       TopTools_MapOfShape& mapF)
865 {
866   if (mapF.Contains(fac)) {
867     return;
868   }
869   mapF.Add(fac); // attention, if oriented == Standard_True, fac should
870                  // be FORWARD or REVERSED. It is not checked.
871
872   TopExp_Explorer ex;
873   for (ex.Init(fac,TopAbs_EDGE); ex.More(); ex.Next()) {
874     const TopoDS_Edge& edg = TopoDS::Edge(ex.Current());
875 // test if the edge is in the map (only orienteed edges are present)
876     if (mapEF.Contains(edg)) {
877       for (TopTools_ListIteratorOfListOfShape itl(mapEF.FindFromKey(edg));
878            itl.More(); itl.Next()) {
879         if (!itl.Value().IsSame(fac) &&
880             !mapF.Contains(itl.Value())) {
881           Propagate(mapEF,itl.Value(),mapF);
882         }
883       }
884     }
885   }
886 }