1 // Created on: 1995-12-12
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <BRepCheck_Shell.ixx>
19 #include <BRepCheck_ListOfStatus.hxx>
20 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
22 #include <TopTools_MapOfShape.hxx>
23 #include <TopTools_MapIteratorOfMapOfShape.hxx>
24 #include <TopTools_ListOfShape.hxx>
25 #include <TopTools_ListIteratorOfListOfShape.hxx>
26 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
27 #include <BRep_Tool.hxx>
28 #include <BRep_Builder.hxx>
30 #include <TopExp_Explorer.hxx>
32 #include <BRepCheck.hxx>
34 #include <TopoDS_Edge.hxx>
35 #include <TopoDS_Face.hxx>
38 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
39 #include <TopTools_DataMapOfShapeInteger.hxx>
41 //=======================================================================
42 //function : Propagate
44 //=======================================================================
45 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
46 const TopoDS_Shape& fac,
47 TopTools_MapOfShape& mapF)
49 if (mapF.Contains(fac))
53 mapF.Add(fac); // attention, if oriented == Standard_True, fac should
54 // be FORWARD or REVERSED. It is not checked.
56 TopTools_MapIteratorOfMapOfShape itf(mapF);
59 Standard_Boolean hasBeenAdded = Standard_False;
60 const TopoDS_Shape& fac = itf.Key();
62 for (ex.Init(fac,TopAbs_EDGE); ex.More(); ex.Next())
64 const TopoDS_Edge& edg = TopoDS::Edge(ex.Current());
65 // test if the edge is in the map (only orienteed edges are present)
66 if (mapEF.Contains(edg))
68 for (TopTools_ListIteratorOfListOfShape itl(mapEF.FindFromKey(edg)); itl.More(); itl.Next())
70 if (!itl.Value().IsSame(fac) && !mapF.Contains(itl.Value()))
72 mapF.Add(itl.Value());
73 hasBeenAdded = Standard_True;
77 }//for (ex.Init(fac,TopAbs_EDGE); ex.More();)
91 //=======================================================================
92 //function : BRepCheck_Trace
94 //=======================================================================
95 Standard_EXPORT Standard_Integer BRepCheck_Trace(const Standard_Integer phase) {
96 static int BRC_Trace = 0;
97 if (phase < 0) BRC_Trace =0;
98 else if (phase > 0) BRC_Trace=phase;
102 void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
103 if (!theShape.IsNull()) {
104 Standard_Integer code = theShape.HashCode(upper);
106 switch (theShape.ShapeType()) {
107 case TopAbs_COMPOUND :
110 case TopAbs_COMPSOLID :
135 cout << " : " << code << " ";
136 switch (theShape.Orientation()) {
137 case TopAbs_FORWARD :
140 case TopAbs_REVERSED :
143 case TopAbs_INTERNAL :
146 case TopAbs_EXTERNAL :
154 //=======================================================================
155 //function : IsOriented
157 //=======================================================================
158 inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
160 return (S.Orientation() == TopAbs_FORWARD ||
161 S.Orientation() == TopAbs_REVERSED);
165 //=======================================================================
166 //function : BRepCheck_Shell
168 //=======================================================================
170 BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
176 //=======================================================================
179 //=======================================================================
180 void BRepCheck_Shell::Minimum()
182 myCdone = Standard_False;
183 myOdone = Standard_False;
187 BRepCheck_ListOfStatus thelist;
188 myMap.Bind(myShape, thelist);
189 BRepCheck_ListOfStatus& lst = myMap(myShape);
191 // it is checked if the shell is "connected"
192 TopExp_Explorer exp(myShape,TopAbs_FACE);
193 Standard_Integer nbface = 0;
195 for (; exp.More(); exp.Next())
198 TopExp_Explorer expe;
199 for (expe.Init(exp.Current(),TopAbs_EDGE);
200 expe.More(); expe.Next())
202 const TopoDS_Shape& edg = expe.Current();
203 Standard_Integer index = myMapEF.FindIndex(edg);
206 TopTools_ListOfShape thelist1;
207 index = myMapEF.Add(edg, thelist1);
210 myMapEF(index).Append(exp.Current());
212 }//for (; exp.More(); exp.Next())
216 BRepCheck::Add(lst,BRepCheck_EmptyShell);
218 else if (nbface >= 2)
220 TopTools_MapOfShape mapF;
223 Propagate(myMapEF,exp.Current(),mapF);
225 if (mapF.Extent() != nbface)
227 BRepCheck::Add(lst,BRepCheck_NotConnected);
229 }//else if (nbface >= 2)
233 lst.Append(BRepCheck_NoError);
237 myMin = Standard_True;
241 //=======================================================================
242 //function : InContext
244 //=======================================================================
246 void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
249 if (myMap.IsBound(S)) {
252 BRepCheck_ListOfStatus thelist;
253 myMap.Bind(S, thelist);
255 BRepCheck_ListOfStatus& lst = myMap(S);
257 // for (TopExp_Explorer exp(S,TopAbs_SHELL); exp.More(); exp.Next()) {
258 TopExp_Explorer exp(S,TopAbs_SHELL) ;
259 for ( ; exp.More(); exp.Next()) {
260 if (exp.Current().IsSame(myShape)) {
265 BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
269 TopAbs_ShapeEnum styp = S.ShapeType();
274 BRepCheck_Status fst = Closed();
275 if ((fst == BRepCheck_NotClosed && S.Closed()) ||
276 (fst != BRepCheck_NoError)) {
277 BRepCheck::Add(lst,fst);
279 else if (!IsUnorientable()) {
281 BRepCheck::Add(lst,fst);
292 lst.Append(BRepCheck_NoError);
297 //=======================================================================
300 //=======================================================================
302 void BRepCheck_Shell::Blind()
305 // nothing more than in the minimum
306 myBlind = Standard_True;
311 //=======================================================================
314 //=======================================================================
315 BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
321 BRepCheck::Add(myMap(myShape), myCstat);
327 myCdone = Standard_True; // it will be done...
329 BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
330 if (itl.Value() != BRepCheck_NoError)
332 myCstat = itl.Value();
333 return myCstat; // already saved
336 myCstat = BRepCheck_NoError;
338 Standard_Integer index, aNbF;
339 TopExp_Explorer exp, ede;
340 TopTools_MapOfShape mapS, aMEToAvoid;
344 // Checks if the oriented faces of the shell give a "closed" shell,
345 // i-e if each oriented edge on oriented faces is found 2 times.
347 //modified by NIZNHY-PKV Mon Jun 4 13:59:21 2007f
348 exp.Init(myShape,TopAbs_FACE);
349 for (; exp.More(); exp.Next())
351 const TopoDS_Shape& aF=exp.Current();
354 ede.Init(exp.Current(),TopAbs_EDGE);
355 for (; ede.More(); ede.Next())
357 const TopoDS_Shape& aE=ede.Current();
365 //modified by NIZNHY-PKV Mon Jun 4 13:59:23 2007t
367 exp.Init(myShape,TopAbs_FACE);
368 for (; exp.More(); exp.Next())
370 const TopoDS_Shape& aF=exp.Current();
375 myCstat = BRepCheck_RedundantFace;
379 BRepCheck::Add(myMap(myShape),myCstat);
386 ede.Init(exp.Current(),TopAbs_EDGE);
387 for (; ede.More(); ede.Next())
389 const TopoDS_Shape& aE=ede.Current();
390 //modified by NIZNHY-PKV Mon Jun 4 14:07:57 2007f
391 //if (IsOriented(aE)) {
392 if (!aMEToAvoid.Contains(aE))
394 //modified by NIZNHY-PKV Mon Jun 4 14:08:01 2007
395 index = myMapEF.FindIndex(aE);
399 TopTools_ListOfShape thelist;
400 index = myMapEF.Add(aE, thelist);
403 myMapEF(index).Append(aF);
410 myNbori = mapS.Extent();
414 // Search for the first oriented face
416 exp.Init(myShape, TopAbs_FACE);
417 for (;exp.More(); exp.Next())
426 Propagate(myMapEF, aF, mapS);
434 myCstat = BRepCheck_NotConnected;
437 BRepCheck::Add(myMap(myShape),myCstat);
443 Standard_Integer i, Nbedges, nboc, nbSet;
445 Nbedges = myMapEF.Extent();
446 for (i = 1; i<=Nbedges; ++i)
448 nboc = myMapEF(i).Extent();
449 if (nboc == 0 || nboc >= 3)
451 TopTools_ListOfShape theSet;
452 nbSet=NbConnectedSet(theSet);
453 // If there is more than one closed cavity the shell is considered invalid
454 // this corresponds to the criteria of a solid (not those of a shell)
457 myCstat = BRepCheck_InvalidMultiConnexity;
460 BRepCheck::Add(myMap(myShape),myCstat);
468 if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i))))
470 myCstat=BRepCheck_NotClosed;
473 BRepCheck::Add(myMap(myShape),myCstat);
482 BRepCheck::Add(myMap(myShape),myCstat);
488 //=======================================================================
489 //function : Orientation
491 //=======================================================================
493 BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
497 BRepCheck::Add(myMap(myShape), myOstat);
501 myOdone = Standard_True;
504 if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
506 BRepCheck::Add(myMap(myShape), myOstat);
511 myOstat = BRepCheck_NoError;
514 // First the orientation of each face in relation to the shell is found.
515 // It is used to check BRepCheck_RedundantFace
517 TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
518 TopExp_Explorer exp,ede;
520 for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
521 if (!MapOfShapeOrientation.Bind(exp.Current(), (Standard_Integer)(exp.Current().Orientation()))) {
522 myOstat = BRepCheck_RedundantFace;
524 BRepCheck::Add(myMap(myShape), myOstat);
533 if (BRepCheck_Trace(0) > 1) {
534 TopTools_DataMapIteratorOfDataMapOfShapeInteger itt(MapOfShapeOrientation);
535 Standard_Integer upper = MapOfShapeOrientation.NbBuckets();
536 cout << "La map shape Orientation :" << endl;
537 for (; itt.More(); itt.Next()) {
538 PrintShape(itt.Key(), upper);
545 // Then the orientation of faces by their connectivity is checked
546 // BRepCheck_BadOrientationOfSubshape and
547 // BRepCheck_SubshapeNotInShape are checked;
549 Standard_Integer Nbedges = myMapEF.Extent();
551 TopAbs_Orientation orf;
553 for (Standard_Integer i = 1; i<= Nbedges; i++) {
555 const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(i));
556 if (BRep_Tool::Degenerated(edg)) continue;
557 TopTools_ListOfShape& lface = myMapEF(i);
558 TopTools_ListIteratorOfListOfShape lite(lface);
560 if (lface.Extent() <= 2)
562 lite.Initialize(lface);
563 Fref = TopoDS::Face(lite.Value());
565 if (!MapOfShapeOrientation.IsBound(Fref)) {
566 myOstat = BRepCheck_SubshapeNotInShape;
568 BRepCheck::Add(myMap(myShape), myOstat);
570 // quit because no workaround for the incoherence is possible
575 if (lite.More()) { // Edge of connectivity
577 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
578 orf = (TopAbs_Orientation) iorf;
579 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
580 Fref.Orientation(orf);
583 if (!lite.Value().IsSame(Fref)) { // edge non "closed"
584 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
585 if (ede.Current().IsSame(edg)) {
589 TopAbs_Orientation orient = ede.Current().Orientation();
590 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
592 if (!MapOfShapeOrientation.IsBound(Fcur)) {
593 myOstat = BRepCheck_SubshapeNotInShape;
595 BRepCheck::Add(myMap(myShape), myOstat);
597 // quit because no workaround for the incoherence is possible
602 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
603 orf = (TopAbs_Orientation) iorf ;
604 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
605 Fcur.Orientation(orf);
607 for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
608 if (ede.Current().IsSame(edg)) {
612 if (ede.Current().Orientation() == orient) {
613 // The loop is continued on the edges as many times
614 // as the same edge is present in the wire
616 // modified by NIZHNY-MKK Tue Sep 30 11:11:42 2003
617 Standard_Boolean bfound = Standard_False;
619 for (; ede.More(); ede.Next()) {
620 if (ede.Current().IsSame(edg)) {
621 // modified by NIZHNY-MKK Tue Sep 30 11:12:03 2003
622 bfound = Standard_True;
626 // if (ede.Current().Orientation() == orient) {
627 // modified by NIZHNY-MKK Thu Oct 2 17:56:47 2003
628 if (!bfound || (ede.Current().Orientation() == orient)) {
629 myOstat = BRepCheck_BadOrientationOfSubshape;
631 BRepCheck::Add(myMap(myShape), myOstat);
640 else //more than two faces
642 Standard_Integer numF = 0, numR = 0;
643 TopTools_MapOfShape Fmap;
645 for (lite.Initialize(lface); lite.More(); lite.Next())
647 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
648 if (!MapOfShapeOrientation.IsBound(Fcur))
650 myOstat = BRepCheck_SubshapeNotInShape;
652 BRepCheck::Add(myMap(myShape), myOstat);
653 // quit because no workaround for the incoherence is possible
657 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
658 orf = (TopAbs_Orientation) iorf;
659 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
660 Fcur.Orientation(orf);
662 for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
663 if (ede.Current().IsSame(edg))
665 if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
668 for (; ede.More(); ede.Next())
669 if (ede.Current().IsSame(edg))
672 TopAbs_Orientation orient = ede.Current().Orientation();
673 if (orient == TopAbs_FORWARD)
683 myOstat = BRepCheck_BadOrientationOfSubshape;
686 BRepCheck::Add(myMap(myShape), myOstat);
694 // If at least one incorrectly oriented face has been found, it is checked if the shell can be oriented.
695 // i.e. : if by modification of the orientation of a face it is possible to find
696 // a coherent orientation. (it is not possible on a Moebius band)
697 // BRepCheck_UnorientableShape is checked
699 if (myOstat == BRepCheck_BadOrientationOfSubshape) {
700 if (!Fref.IsNull()) {
702 TopTools_MapOfShape alre;
703 TopTools_ListOfShape voisin;
706 while (!voisin.IsEmpty()) {
707 Fref=TopoDS::Face(voisin.First());
708 voisin.RemoveFirst();
709 if (!MapOfShapeOrientation.IsBound(Fref)) {
710 myOstat = BRepCheck_SubshapeNotInShape;
712 BRepCheck::Add(myMap(myShape), myOstat);
714 // quit because no workaround for the incoherence is possible
718 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
719 orf = (TopAbs_Orientation) iorf ;
720 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
721 Fref.Orientation(orf);
724 if (BRepCheck_Trace(0) > 3) {
726 PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
730 TopExp_Explorer edFcur;
733 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
734 const TopoDS_Edge& edg = TopoDS::Edge(ede.Current());
735 TopAbs_Orientation orient = edg.Orientation();
736 TopTools_ListOfShape& lface = myMapEF.ChangeFromKey(edg);
737 TopTools_ListIteratorOfListOfShape lite(lface);
739 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
740 if (Fcur.IsSame(Fref)) {
743 Fcur=TopoDS::Face(lite.Value());
746 // from the free border one goes to the next edge
751 if (!MapOfShapeOrientation.IsBound(Fcur)) {
752 myOstat = BRepCheck_SubshapeNotInShape;
754 BRepCheck::Add(myMap(myShape), myOstat);
756 // quit because no workaround for the incoherence is possible
761 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
762 orf = (TopAbs_Orientation) iorf ;
763 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
764 Fcur.Orientation(orf);
767 if (BRepCheck_Trace(0) > 3) {
769 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
772 for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
773 if (edFcur.Current().IsSame(edg)) {
777 if (edFcur.Current().Orientation() == orient) {
778 if (alre.Contains(Fcur)) {
779 // It is necessary to return a face that has been already examined or returned
780 // if one gets nowhere, the shell cannot be oriented.
781 myOstat = BRepCheck_UnorientableShape;
783 BRepCheck::Add(myMap(myShape), myOstat);
785 // quit, otherwise there is a risk of taking too much time.
787 if (BRepCheck_Trace(0) > 3) {
788 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
789 Fcur.Orientation(orf);
790 cout << " Error : this face has been already examined " << endl;
791 cout << " Imposible to return it ";
792 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
797 orf = TopAbs::Reverse(orf);
798 MapOfShapeOrientation(Fcur)=orf;
802 if (BRepCheck_Trace(0) > 3) {
803 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
804 Fcur.Orientation(orf);
805 cout << " Resulting Fcur is returned : " ;
806 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
811 if (alre.Add(Fcur)) {
821 BRepCheck::Add(myMap(myShape), myOstat);
826 //=======================================================================
827 //function : SetUnorientable
829 //=======================================================================
831 void BRepCheck_Shell::SetUnorientable()
833 BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
837 //=======================================================================
838 //function : IsUnorientable
840 //=======================================================================
842 Standard_Boolean BRepCheck_Shell::IsUnorientable() const
845 return (myOstat != BRepCheck_NoError);
847 for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
850 if (itl.Value() == BRepCheck_UnorientableShape) {
851 return Standard_True;
854 return Standard_False;
857 //=======================================================================
858 //function : NbConnectedSet
860 //=======================================================================
862 Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
864 // The connections are found
865 TopTools_IndexedDataMapOfShapeListOfShape parents;
866 TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, parents);
867 // All faces are taken
868 TopTools_MapOfShape theFaces;
869 TopExp_Explorer exsh(myShape, TopAbs_FACE);
870 for (; exsh.More(); exsh.Next()) theFaces.Add(exsh.Current());
871 // The edges that are not oriented or have more than 2 connections are missing
872 Standard_Integer iCur;
873 TopTools_MapOfShape theMultiEd;
874 TopTools_MapOfShape theUnOriEd;
875 for (iCur=1; iCur<=parents.Extent(); iCur++) {
876 const TopoDS_Edge& Ed = TopoDS::Edge(parents.FindKey(iCur));
877 if (parents(iCur).Extent()> 2) theMultiEd.Add(Ed);
878 if (Ed.Orientation()!=TopAbs_REVERSED &&
879 Ed.Orientation()!=TopAbs_FORWARD) theUnOriEd.Add(Ed);
881 // Starting from multiconnected edges propagation by simple connections
882 TopTools_ListIteratorOfListOfShape lconx1, lconx2;
883 TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
884 TopoDS_Shell CurShell;
886 TopTools_ListOfShape lesCur;
888 Standard_Boolean newCur=Standard_True;
889 BRB.MakeShell(CurShell);
890 for (; itmsh.More(); itmsh.Next()) {
891 const TopoDS_Shape& Ed = itmsh.Key();
892 if (!theUnOriEd.Contains(Ed)) {
893 for (lconx1.Initialize(parents.FindFromKey(Ed)); lconx1.More(); lconx1.Next()) {
894 if (theFaces.Contains(lconx1.Value())) {
895 adFac=lconx1.Value();
896 BRB.Add(CurShell, adFac);
897 theFaces.Remove(adFac);
898 newCur=Standard_False;
899 if (theFaces.IsEmpty()) break;
900 lesCur.Append(adFac);
901 while (!lesCur.IsEmpty()) {
902 adFac=lesCur.First();
903 lesCur.RemoveFirst();
904 for (exsh.Init(adFac, TopAbs_EDGE); exsh.More(); exsh.Next()) {
905 const TopoDS_Shape& ced = exsh.Current();
906 if (!theMultiEd.Contains(ced)) {
907 for (lconx2.Initialize(parents.FindFromKey(ced)); lconx2.More(); lconx2.Next()) {
908 if (theFaces.Contains(lconx2.Value())) {
909 adFac=lconx2.Value();
910 BRB.Add(CurShell, adFac);
911 theFaces.Remove(adFac);
912 newCur=Standard_False;
913 if (theFaces.IsEmpty()) break;
914 lesCur.Append(adFac);
918 if (theFaces.IsEmpty()) break;
922 theSets.Append(CurShell);
924 newCur=Standard_True;
925 BRB.MakeShell(CurShell);
928 if (theFaces.IsEmpty()) break;
931 if (theFaces.IsEmpty()) break;
933 return theSets.Extent();