1 // File: BRepCheck_Shell.cxx
2 // Created: Tue Dec 12 17:49:08 1995
3 // Author: Jacques GOUSSARD
7 #include <BRepCheck_Shell.ixx>
9 #include <BRepCheck_ListOfStatus.hxx>
10 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
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>
20 #include <TopExp_Explorer.hxx>
22 #include <BRepCheck.hxx>
24 #include <TopoDS_Edge.hxx>
25 #include <TopoDS_Face.hxx>
28 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
29 #include <TopTools_DataMapOfShapeInteger.hxx>
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;
39 void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
40 if (!theShape.IsNull()) {
41 Standard_Integer code = theShape.HashCode(upper);
43 switch (theShape.ShapeType()) {
44 case TopAbs_COMPOUND :
47 case TopAbs_COMPSOLID :
72 cout << " : " << code << " ";
73 switch (theShape.Orientation()) {
77 case TopAbs_REVERSED :
80 case TopAbs_INTERNAL :
83 case TopAbs_EXTERNAL :
91 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape&,
92 const TopoDS_Shape&, // Face
93 TopTools_MapOfShape&); // mapofface
97 static TopAbs_Orientation GetOrientation(const TopoDS_Face&,
102 inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
104 return (S.Orientation() == TopAbs_FORWARD ||
105 S.Orientation() == TopAbs_REVERSED);
109 //=======================================================================
110 //function : BRepCheck_Shell
112 //=======================================================================
114 BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
120 //=======================================================================
123 //=======================================================================
125 void BRepCheck_Shell::Minimum()
127 myCdone = Standard_False;
128 myOdone = Standard_False;
131 BRepCheck_ListOfStatus thelist;
132 myMap.Bind(myShape, thelist);
133 BRepCheck_ListOfStatus& lst = myMap(myShape);
135 // it is checked if the shell is "connected"
136 TopExp_Explorer exp(myShape,TopAbs_FACE);
137 Standard_Integer nbface = 0;
139 for (; exp.More(); exp.Next()) {
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);
147 TopTools_ListOfShape thelist1;
148 index = myMapEF.Add(edg, thelist1);
150 myMapEF(index).Append(exp.Current());
155 BRepCheck::Add(lst,BRepCheck_EmptyShell);
157 else if (nbface >= 2) {
158 TopTools_MapOfShape mapF;
160 Propagate(myMapEF,exp.Current(),mapF);
161 if (mapF.Extent() != nbface) {
162 BRepCheck::Add(lst,BRepCheck_NotConnected);
166 lst.Append(BRepCheck_NoError);
169 myMin = Standard_True;
175 //=======================================================================
176 //function : InContext
178 //=======================================================================
180 void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
183 if (myMap.IsBound(S)) {
186 BRepCheck_ListOfStatus thelist;
187 myMap.Bind(S, thelist);
189 BRepCheck_ListOfStatus& lst = myMap(S);
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)) {
199 BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
203 TopAbs_ShapeEnum styp = S.ShapeType();
208 BRepCheck_Status fst = Closed();
209 if ((fst == BRepCheck_NotClosed && S.Closed()) ||
210 (fst != BRepCheck_NoError)) {
211 BRepCheck::Add(lst,fst);
213 else if (!IsUnorientable()) {
215 BRepCheck::Add(lst,fst);
226 lst.Append(BRepCheck_NoError);
231 //=======================================================================
234 //=======================================================================
236 void BRepCheck_Shell::Blind()
239 // nothing more than in the minimum
240 myBlind = Standard_True;
245 //=======================================================================
248 //=======================================================================
250 BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
255 BRepCheck::Add(myMap(myShape), myCstat);
260 myCdone = Standard_True; // it will be done...
262 BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
263 if (itl.Value() != BRepCheck_NoError) {
264 myCstat = itl.Value();
265 return myCstat; // already saved
268 myCstat = BRepCheck_NoError;
270 Standard_Integer index, aNbF;
271 TopExp_Explorer exp, ede;
272 TopTools_MapOfShape mapS, aMEToAvoid;
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.
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)) {
293 //modified by NIZNHY-PKV Mon Jun 4 13:59:23 2007t
295 exp.Init(myShape,TopAbs_FACE);
296 for (; exp.More(); exp.Next()) {
297 const TopoDS_Shape& aF=exp.Current();
298 if (IsOriented(aF)) {
300 myCstat = BRepCheck_RedundantFace;
302 BRepCheck::Add(myMap(myShape),myCstat);
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);
316 TopTools_ListOfShape thelist;
317 index = myMapEF.Add(aE, thelist);
319 myMapEF(index).Append(aF);
325 myNbori = mapS.Extent();
328 // Search for the first oriented face
330 exp.Init(myShape, TopAbs_FACE);
331 for (;exp.More(); exp.Next()) {
333 if (IsOriented(aF)) {
338 Propagate(myMapEF, aF, mapS);
343 if (myNbori != aNbF) {
344 myCstat = BRepCheck_NotConnected;
346 BRepCheck::Add(myMap(myShape),myCstat);
352 Standard_Integer i, Nbedges, nboc, nbSet;
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)
363 myCstat = BRepCheck_InvalidMultiConnexity;
365 BRepCheck::Add(myMap(myShape),myCstat);
370 else if (nboc == 1) {
371 if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i)))) {
372 myCstat=BRepCheck_NotClosed;
374 BRepCheck::Add(myMap(myShape),myCstat);
382 BRepCheck::Add(myMap(myShape),myCstat);
388 //=======================================================================
389 //function : Orientation
391 //=======================================================================
393 BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
397 BRepCheck::Add(myMap(myShape), myOstat);
401 myOdone = Standard_True;
404 if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
406 BRepCheck::Add(myMap(myShape), myOstat);
411 myOstat = BRepCheck_NoError;
414 // First the orientation of each face in relation to the shell is found.
415 // It is used to check BRepCheck_RedundantFace
417 TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
418 TopExp_Explorer exp,ede;
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;
424 BRepCheck::Add(myMap(myShape), myOstat);
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);
445 // Then the orientation of faces by their connectivity is checked
446 // BRepCheck_BadOrientationOfSubshape and
447 // BRepCheck_SubshapeNotInShape are checked;
449 Standard_Integer Nbedges = myMapEF.Extent();
451 TopAbs_Orientation orf;
453 for (Standard_Integer i = 1; i<= Nbedges; i++) {
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);
460 if (lface.Extent() <= 2)
462 lite.Initialize(lface);
463 Fref = TopoDS::Face(lite.Value());
465 if (!MapOfShapeOrientation.IsBound(Fref)) {
466 myOstat = BRepCheck_SubshapeNotInShape;
468 BRepCheck::Add(myMap(myShape), myOstat);
470 // quit because no workaround for the incoherence is possible
475 if (lite.More()) { // Edge of connectivity
477 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
478 orf = (TopAbs_Orientation) iorf;
479 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
480 Fref.Orientation(orf);
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)) {
489 TopAbs_Orientation orient = ede.Current().Orientation();
490 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
492 if (!MapOfShapeOrientation.IsBound(Fcur)) {
493 myOstat = BRepCheck_SubshapeNotInShape;
495 BRepCheck::Add(myMap(myShape), myOstat);
497 // quit because no workaround for the incoherence is possible
502 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
503 orf = (TopAbs_Orientation) iorf ;
504 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
505 Fcur.Orientation(orf);
507 for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
508 if (ede.Current().IsSame(edg)) {
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
516 // modified by NIZHNY-MKK Tue Sep 30 11:11:42 2003
517 Standard_Boolean bfound = Standard_False;
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;
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;
531 BRepCheck::Add(myMap(myShape), myOstat);
540 else //more than two faces
542 Standard_Integer numF = 0, numR = 0;
543 TopTools_MapOfShape Fmap;
545 for (lite.Initialize(lface); lite.More(); lite.Next())
547 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
548 if (!MapOfShapeOrientation.IsBound(Fcur))
550 myOstat = BRepCheck_SubshapeNotInShape;
552 BRepCheck::Add(myMap(myShape), myOstat);
553 // quit because no workaround for the incoherence is possible
557 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
558 orf = (TopAbs_Orientation) iorf;
559 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
560 Fcur.Orientation(orf);
562 for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
563 if (ede.Current().IsSame(edg))
565 if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
568 for (; ede.More(); ede.Next())
569 if (ede.Current().IsSame(edg))
572 TopAbs_Orientation orient = ede.Current().Orientation();
573 if (orient == TopAbs_FORWARD)
583 myOstat = BRepCheck_BadOrientationOfSubshape;
586 BRepCheck::Add(myMap(myShape), myOstat);
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
599 if (myOstat == BRepCheck_BadOrientationOfSubshape) {
600 if (!Fref.IsNull()) {
602 TopTools_MapOfShape alre;
603 TopTools_ListOfShape voisin;
606 while (!voisin.IsEmpty()) {
607 Fref=TopoDS::Face(voisin.First());
608 voisin.RemoveFirst();
609 if (!MapOfShapeOrientation.IsBound(Fref)) {
610 myOstat = BRepCheck_SubshapeNotInShape;
612 BRepCheck::Add(myMap(myShape), myOstat);
614 // quit because no workaround for the incoherence is possible
618 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
619 orf = (TopAbs_Orientation) iorf ;
620 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
621 Fref.Orientation(orf);
624 if (BRepCheck_Trace(0) > 3) {
626 PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
630 TopExp_Explorer edFcur;
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);
639 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
640 if (Fcur.IsSame(Fref)) {
643 Fcur=TopoDS::Face(lite.Value());
646 // from the free border one goes to the next edge
651 if (!MapOfShapeOrientation.IsBound(Fcur)) {
652 myOstat = BRepCheck_SubshapeNotInShape;
654 BRepCheck::Add(myMap(myShape), myOstat);
656 // quit because no workaround for the incoherence is possible
661 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
662 orf = (TopAbs_Orientation) iorf ;
663 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
664 Fcur.Orientation(orf);
667 if (BRepCheck_Trace(0) > 3) {
669 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
672 for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
673 if (edFcur.Current().IsSame(edg)) {
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;
683 BRepCheck::Add(myMap(myShape), myOstat);
685 // quit, otherwise there is a risk of taking too much time.
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());
697 orf = TopAbs::Reverse(orf);
698 MapOfShapeOrientation(Fcur)=orf;
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());
711 if (alre.Add(Fcur)) {
721 BRepCheck::Add(myMap(myShape), myOstat);
726 //=======================================================================
727 //function : SetUnorientable
729 //=======================================================================
731 void BRepCheck_Shell::SetUnorientable()
733 BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
737 //=======================================================================
738 //function : IsUnorientable
740 //=======================================================================
742 Standard_Boolean BRepCheck_Shell::IsUnorientable() const
745 return (myOstat != BRepCheck_NoError);
747 for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
750 if (itl.Value() == BRepCheck_UnorientableShape) {
751 return Standard_True;
754 return Standard_False;
757 //=======================================================================
758 //function : NbConnectedSet
760 //=======================================================================
762 Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
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);
781 // Starting from multiconnected edges propagation by simple connections
782 TopTools_ListIteratorOfListOfShape lconx1, lconx2;
783 TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
784 TopoDS_Shell CurShell;
786 TopTools_ListOfShape lesCur;
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);
818 if (theFaces.IsEmpty()) break;
822 theSets.Append(CurShell);
824 newCur=Standard_True;
825 BRB.MakeShell(CurShell);
828 if (theFaces.IsEmpty()) break;
831 if (theFaces.IsEmpty()) break;
833 return theSets.Extent();
836 //=======================================================================
837 //function : GetOrientation
839 //=======================================================================
842 static TopAbs_Orientation GetOrientation(const TopoDS_Face& F,
843 const TopoDS_Shape& S)
847 for (exp.Init(S,TopAbs_FACE); exp.More(); exp.Next()) {
848 if (exp.Current().IsSame(F)) {
849 return exp.Current().Orientation();
852 return TopAbs_FORWARD; // for compilation
857 //=======================================================================
858 //function : Propagate
860 //=======================================================================
862 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
863 const TopoDS_Shape& fac,
864 TopTools_MapOfShape& mapF)
866 if (mapF.Contains(fac)) {
869 mapF.Add(fac); // attention, if oriented == Standard_True, fac should
870 // be FORWARD or REVERSED. It is not checked.
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);