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.
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <BRepCheck.hxx>
21 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
22 #include <BRepCheck_ListOfStatus.hxx>
23 #include <BRepCheck_Shell.hxx>
24 #include <Standard_Type.hxx>
26 #include <TopExp_Explorer.hxx>
28 #include <TopoDS_Edge.hxx>
29 #include <TopoDS_Face.hxx>
30 #include <TopoDS_Shape.hxx>
31 #include <TopoDS_Shell.hxx>
32 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
33 #include <TopTools_DataMapOfShapeInteger.hxx>
34 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
35 #include <TopTools_ListIteratorOfListOfShape.hxx>
36 #include <TopTools_ListOfShape.hxx>
37 #include <TopTools_MapIteratorOfMapOfShape.hxx>
38 #include <TopTools_MapOfShape.hxx>
40 //=======================================================================
41 //function : Propagate
43 //=======================================================================
44 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
45 const TopoDS_Shape& theFac,
46 TopTools_MapOfShape& mapF)
48 if (mapF.Contains(theFac))
52 mapF.Add(theFac); // attention, if oriented == Standard_True, fac should
53 // be FORWARD or REVERSED. It is not checked.
55 TopTools_MapIteratorOfMapOfShape itf(mapF);
58 Standard_Boolean hasBeenAdded = Standard_False;
59 const TopoDS_Shape& fac = itf.Key();
61 for (ex.Init(fac,TopAbs_EDGE); ex.More(); ex.Next())
63 const TopoDS_Edge& edg = TopoDS::Edge(ex.Current());
64 // test if the edge is in the map (only orienteed edges are present)
65 if (mapEF.Contains(edg))
67 for (TopTools_ListIteratorOfListOfShape itl(mapEF.FindFromKey(edg)); itl.More(); itl.Next())
69 if (!itl.Value().IsSame(fac) && !mapF.Contains(itl.Value()))
71 mapF.Add(itl.Value());
72 hasBeenAdded = Standard_True;
76 }//for (ex.Init(fac,TopAbs_EDGE); ex.More();)
90 //=======================================================================
91 //function : BRepCheck_Trace
93 //=======================================================================
94 Standard_EXPORT Standard_Integer BRepCheck_Trace(const Standard_Integer phase) {
95 static int BRC_Trace = 0;
96 if (phase < 0) BRC_Trace =0;
97 else if (phase > 0) BRC_Trace=phase;
101 void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
102 if (!theShape.IsNull()) {
103 Standard_Integer code = theShape.HashCode(upper);
105 switch (theShape.ShapeType()) {
106 case TopAbs_COMPOUND :
109 case TopAbs_COMPSOLID :
134 cout << " : " << code << " ";
135 switch (theShape.Orientation()) {
136 case TopAbs_FORWARD :
139 case TopAbs_REVERSED :
142 case TopAbs_INTERNAL :
145 case TopAbs_EXTERNAL :
153 //=======================================================================
154 //function : IsOriented
156 //=======================================================================
157 inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
159 return (S.Orientation() == TopAbs_FORWARD ||
160 S.Orientation() == TopAbs_REVERSED);
164 //=======================================================================
165 //function : BRepCheck_Shell
167 //=======================================================================
169 BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
175 //=======================================================================
178 //=======================================================================
179 void BRepCheck_Shell::Minimum()
181 myCdone = Standard_False;
182 myOdone = Standard_False;
186 BRepCheck_ListOfStatus thelist;
187 myMap.Bind(myShape, thelist);
188 BRepCheck_ListOfStatus& lst = myMap(myShape);
190 // it is checked if the shell is "connected"
191 TopExp_Explorer exp(myShape,TopAbs_FACE);
192 Standard_Integer nbface = 0;
194 for (; exp.More(); exp.Next())
197 TopExp_Explorer expe;
198 for (expe.Init(exp.Current(),TopAbs_EDGE);
199 expe.More(); expe.Next())
201 const TopoDS_Shape& edg = expe.Current();
202 Standard_Integer index = myMapEF.FindIndex(edg);
205 TopTools_ListOfShape thelist1;
206 index = myMapEF.Add(edg, thelist1);
209 myMapEF(index).Append(exp.Current());
211 }//for (; exp.More(); exp.Next())
215 BRepCheck::Add(lst,BRepCheck_EmptyShell);
217 else if (nbface >= 2)
219 TopTools_MapOfShape mapF;
222 Propagate(myMapEF,exp.Current(),mapF);
224 if (mapF.Extent() != nbface)
226 BRepCheck::Add(lst,BRepCheck_NotConnected);
228 }//else if (nbface >= 2)
232 lst.Append(BRepCheck_NoError);
236 myMin = Standard_True;
240 //=======================================================================
241 //function : InContext
243 //=======================================================================
245 void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
248 if (myMap.IsBound(S)) {
251 BRepCheck_ListOfStatus thelist;
252 myMap.Bind(S, thelist);
254 BRepCheck_ListOfStatus& lst = myMap(S);
256 // for (TopExp_Explorer exp(S,TopAbs_SHELL); exp.More(); exp.Next()) {
257 TopExp_Explorer exp(S,TopAbs_SHELL) ;
258 for ( ; exp.More(); exp.Next()) {
259 if (exp.Current().IsSame(myShape)) {
264 BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
268 TopAbs_ShapeEnum styp = S.ShapeType();
273 BRepCheck_Status fst = Closed();
274 if ((fst == BRepCheck_NotClosed && S.Closed()) ||
275 (fst != BRepCheck_NoError)) {
276 BRepCheck::Add(lst,fst);
278 else if (!IsUnorientable()) {
280 BRepCheck::Add(lst,fst);
291 lst.Append(BRepCheck_NoError);
296 //=======================================================================
299 //=======================================================================
301 void BRepCheck_Shell::Blind()
304 // nothing more than in the minimum
305 myBlind = Standard_True;
310 //=======================================================================
313 //=======================================================================
314 BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
320 BRepCheck::Add(myMap(myShape), myCstat);
326 myCdone = Standard_True; // it will be done...
328 BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
329 if (itl.Value() != BRepCheck_NoError)
331 myCstat = itl.Value();
332 return myCstat; // already saved
335 myCstat = BRepCheck_NoError;
337 Standard_Integer index, aNbF;
338 TopExp_Explorer exp, ede;
339 TopTools_MapOfShape mapS, aMEToAvoid;
343 // Checks if the oriented faces of the shell give a "closed" shell,
344 // i-e if each oriented edge on oriented faces is found 2 times.
346 //modified by NIZNHY-PKV Mon Jun 4 13:59:21 2007f
347 exp.Init(myShape,TopAbs_FACE);
348 for (; exp.More(); exp.Next())
350 const TopoDS_Shape& aF=exp.Current();
353 ede.Init(exp.Current(),TopAbs_EDGE);
354 for (; ede.More(); ede.Next())
356 const TopoDS_Shape& aE=ede.Current();
364 //modified by NIZNHY-PKV Mon Jun 4 13:59:23 2007t
366 exp.Init(myShape,TopAbs_FACE);
367 for (; exp.More(); exp.Next())
369 const TopoDS_Shape& aF=exp.Current();
374 myCstat = BRepCheck_RedundantFace;
378 BRepCheck::Add(myMap(myShape),myCstat);
385 ede.Init(exp.Current(),TopAbs_EDGE);
386 for (; ede.More(); ede.Next())
388 const TopoDS_Shape& aE=ede.Current();
389 //modified by NIZNHY-PKV Mon Jun 4 14:07:57 2007f
390 //if (IsOriented(aE)) {
391 if (!aMEToAvoid.Contains(aE))
393 //modified by NIZNHY-PKV Mon Jun 4 14:08:01 2007
394 index = myMapEF.FindIndex(aE);
398 TopTools_ListOfShape thelist;
399 index = myMapEF.Add(aE, thelist);
402 myMapEF(index).Append(aF);
409 myNbori = mapS.Extent();
413 // Search for the first oriented face
415 exp.Init(myShape, TopAbs_FACE);
416 for (;exp.More(); exp.Next())
425 Propagate(myMapEF, aF, mapS);
433 myCstat = BRepCheck_NotConnected;
436 BRepCheck::Add(myMap(myShape),myCstat);
442 Standard_Integer i, Nbedges, nboc, nbSet;
444 Nbedges = myMapEF.Extent();
445 for (i = 1; i<=Nbedges; ++i)
447 nboc = myMapEF(i).Extent();
448 if (nboc == 0 || nboc >= 3)
450 TopTools_ListOfShape theSet;
451 nbSet=NbConnectedSet(theSet);
452 // If there is more than one closed cavity the shell is considered invalid
453 // this corresponds to the criteria of a solid (not those of a shell)
456 myCstat = BRepCheck_InvalidMultiConnexity;
459 BRepCheck::Add(myMap(myShape),myCstat);
467 if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i))))
469 myCstat=BRepCheck_NotClosed;
472 BRepCheck::Add(myMap(myShape),myCstat);
481 BRepCheck::Add(myMap(myShape),myCstat);
487 //=======================================================================
488 //function : Orientation
490 //=======================================================================
492 BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
496 BRepCheck::Add(myMap(myShape), myOstat);
500 myOdone = Standard_True;
503 if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
505 BRepCheck::Add(myMap(myShape), myOstat);
510 myOstat = BRepCheck_NoError;
513 // First the orientation of each face in relation to the shell is found.
514 // It is used to check BRepCheck_RedundantFace
516 TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
517 TopExp_Explorer exp,ede;
519 for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
520 if (!MapOfShapeOrientation.Bind(exp.Current(), (Standard_Integer)(exp.Current().Orientation()))) {
521 myOstat = BRepCheck_RedundantFace;
523 BRepCheck::Add(myMap(myShape), myOstat);
532 if (BRepCheck_Trace(0) > 1) {
533 TopTools_DataMapIteratorOfDataMapOfShapeInteger itt(MapOfShapeOrientation);
534 Standard_Integer upper = MapOfShapeOrientation.NbBuckets();
535 cout << "La map shape Orientation :" << endl;
536 for (; itt.More(); itt.Next()) {
537 PrintShape(itt.Key(), upper);
544 // Then the orientation of faces by their connectivity is checked
545 // BRepCheck_BadOrientationOfSubshape and
546 // BRepCheck_SubshapeNotInShape are checked;
548 Standard_Integer Nbedges = myMapEF.Extent();
550 TopAbs_Orientation orf;
552 for (Standard_Integer i = 1; i<= Nbedges; i++) {
554 const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(i));
555 if (BRep_Tool::Degenerated(edg)) continue;
556 TopTools_ListOfShape& lface = myMapEF(i);
557 TopTools_ListIteratorOfListOfShape lite(lface);
559 if (lface.Extent() <= 2)
561 lite.Initialize(lface);
562 Fref = TopoDS::Face(lite.Value());
564 if (!MapOfShapeOrientation.IsBound(Fref)) {
565 myOstat = BRepCheck_SubshapeNotInShape;
567 BRepCheck::Add(myMap(myShape), myOstat);
569 // quit because no workaround for the incoherence is possible
574 if (lite.More()) { // Edge of connectivity
576 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
577 orf = (TopAbs_Orientation) iorf;
578 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
579 Fref.Orientation(orf);
582 if (!lite.Value().IsSame(Fref)) { // edge non "closed"
583 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
584 if (ede.Current().IsSame(edg)) {
588 TopAbs_Orientation orient = ede.Current().Orientation();
589 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
591 if (!MapOfShapeOrientation.IsBound(Fcur)) {
592 myOstat = BRepCheck_SubshapeNotInShape;
594 BRepCheck::Add(myMap(myShape), myOstat);
596 // quit because no workaround for the incoherence is possible
601 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
602 orf = (TopAbs_Orientation) iorf ;
603 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
604 Fcur.Orientation(orf);
606 for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
607 if (ede.Current().IsSame(edg)) {
611 if (ede.Current().Orientation() == orient) {
612 // The loop is continued on the edges as many times
613 // as the same edge is present in the wire
615 // modified by NIZHNY-MKK Tue Sep 30 11:11:42 2003
616 Standard_Boolean bfound = Standard_False;
618 for (; ede.More(); ede.Next()) {
619 if (ede.Current().IsSame(edg)) {
620 // modified by NIZHNY-MKK Tue Sep 30 11:12:03 2003
621 bfound = Standard_True;
625 // if (ede.Current().Orientation() == orient) {
626 // modified by NIZHNY-MKK Thu Oct 2 17:56:47 2003
627 if (!bfound || (ede.Current().Orientation() == orient)) {
628 myOstat = BRepCheck_BadOrientationOfSubshape;
630 BRepCheck::Add(myMap(myShape), myOstat);
639 else //more than two faces
641 Standard_Integer numF = 0, numR = 0;
642 TopTools_MapOfShape Fmap;
644 for (lite.Initialize(lface); lite.More(); lite.Next())
646 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
647 if (!MapOfShapeOrientation.IsBound(Fcur))
649 myOstat = BRepCheck_SubshapeNotInShape;
651 BRepCheck::Add(myMap(myShape), myOstat);
652 // quit because no workaround for the incoherence is possible
656 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
657 orf = (TopAbs_Orientation) iorf;
658 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
659 Fcur.Orientation(orf);
661 for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
662 if (ede.Current().IsSame(edg))
664 if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
667 for (; ede.More(); ede.Next())
668 if (ede.Current().IsSame(edg))
671 TopAbs_Orientation orient = ede.Current().Orientation();
672 if (orient == TopAbs_FORWARD)
682 myOstat = BRepCheck_BadOrientationOfSubshape;
685 BRepCheck::Add(myMap(myShape), myOstat);
693 // If at least one incorrectly oriented face has been found, it is checked if the shell can be oriented.
694 // i.e. : if by modification of the orientation of a face it is possible to find
695 // a coherent orientation. (it is not possible on a Moebius band)
696 // BRepCheck_UnorientableShape is checked
698 if (myOstat == BRepCheck_BadOrientationOfSubshape) {
699 if (!Fref.IsNull()) {
701 TopTools_MapOfShape alre;
702 TopTools_ListOfShape voisin;
705 while (!voisin.IsEmpty()) {
706 Fref=TopoDS::Face(voisin.First());
707 voisin.RemoveFirst();
708 if (!MapOfShapeOrientation.IsBound(Fref)) {
709 myOstat = BRepCheck_SubshapeNotInShape;
711 BRepCheck::Add(myMap(myShape), myOstat);
713 // quit because no workaround for the incoherence is possible
717 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
718 orf = (TopAbs_Orientation) iorf ;
719 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
720 Fref.Orientation(orf);
723 if (BRepCheck_Trace(0) > 3) {
725 PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
729 TopExp_Explorer edFcur;
732 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
733 const TopoDS_Edge& edg = TopoDS::Edge(ede.Current());
734 TopAbs_Orientation orient = edg.Orientation();
735 TopTools_ListOfShape& lface = myMapEF.ChangeFromKey(edg);
736 TopTools_ListIteratorOfListOfShape lite(lface);
738 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
739 if (Fcur.IsSame(Fref)) {
742 Fcur=TopoDS::Face(lite.Value());
745 // from the free border one goes to the next edge
750 if (!MapOfShapeOrientation.IsBound(Fcur)) {
751 myOstat = BRepCheck_SubshapeNotInShape;
753 BRepCheck::Add(myMap(myShape), myOstat);
755 // quit because no workaround for the incoherence is possible
760 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
761 orf = (TopAbs_Orientation) iorf ;
762 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
763 Fcur.Orientation(orf);
766 if (BRepCheck_Trace(0) > 3) {
768 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
771 for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
772 if (edFcur.Current().IsSame(edg)) {
776 if (edFcur.Current().Orientation() == orient) {
777 if (alre.Contains(Fcur)) {
778 // It is necessary to return a face that has been already examined or returned
779 // if one gets nowhere, the shell cannot be oriented.
780 myOstat = BRepCheck_UnorientableShape;
782 BRepCheck::Add(myMap(myShape), myOstat);
784 // quit, otherwise there is a risk of taking too much time.
786 if (BRepCheck_Trace(0) > 3) {
787 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
788 Fcur.Orientation(orf);
789 cout << " Error : this face has been already examined " << endl;
790 cout << " Imposible to return it ";
791 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
796 orf = TopAbs::Reverse(orf);
797 MapOfShapeOrientation(Fcur)=orf;
801 if (BRepCheck_Trace(0) > 3) {
802 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
803 Fcur.Orientation(orf);
804 cout << " Resulting Fcur is returned : " ;
805 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
810 if (alre.Add(Fcur)) {
820 BRepCheck::Add(myMap(myShape), myOstat);
825 //=======================================================================
826 //function : SetUnorientable
828 //=======================================================================
830 void BRepCheck_Shell::SetUnorientable()
832 BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
836 //=======================================================================
837 //function : IsUnorientable
839 //=======================================================================
841 Standard_Boolean BRepCheck_Shell::IsUnorientable() const
844 return (myOstat != BRepCheck_NoError);
846 for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
849 if (itl.Value() == BRepCheck_UnorientableShape) {
850 return Standard_True;
853 return Standard_False;
856 //=======================================================================
857 //function : NbConnectedSet
859 //=======================================================================
861 Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
863 // The connections are found
864 TopTools_IndexedDataMapOfShapeListOfShape parents;
865 TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, parents);
866 // All faces are taken
867 TopTools_MapOfShape theFaces;
868 TopExp_Explorer exsh(myShape, TopAbs_FACE);
869 for (; exsh.More(); exsh.Next()) theFaces.Add(exsh.Current());
870 // The edges that are not oriented or have more than 2 connections are missing
871 Standard_Integer iCur;
872 TopTools_MapOfShape theMultiEd;
873 TopTools_MapOfShape theUnOriEd;
874 for (iCur=1; iCur<=parents.Extent(); iCur++) {
875 const TopoDS_Edge& Ed = TopoDS::Edge(parents.FindKey(iCur));
876 if (parents(iCur).Extent()> 2) theMultiEd.Add(Ed);
877 if (Ed.Orientation()!=TopAbs_REVERSED &&
878 Ed.Orientation()!=TopAbs_FORWARD) theUnOriEd.Add(Ed);
880 // Starting from multiconnected edges propagation by simple connections
881 TopTools_ListIteratorOfListOfShape lconx1, lconx2;
882 TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
883 TopoDS_Shell CurShell;
885 TopTools_ListOfShape lesCur;
887 Standard_Boolean newCur=Standard_True;
888 BRB.MakeShell(CurShell);
889 for (; itmsh.More(); itmsh.Next()) {
890 const TopoDS_Shape& Ed = itmsh.Key();
891 if (!theUnOriEd.Contains(Ed)) {
892 for (lconx1.Initialize(parents.FindFromKey(Ed)); lconx1.More(); lconx1.Next()) {
893 if (theFaces.Contains(lconx1.Value())) {
894 adFac=lconx1.Value();
895 BRB.Add(CurShell, adFac);
896 theFaces.Remove(adFac);
897 newCur=Standard_False;
898 if (theFaces.IsEmpty()) break;
899 lesCur.Append(adFac);
900 while (!lesCur.IsEmpty()) {
901 adFac=lesCur.First();
902 lesCur.RemoveFirst();
903 for (exsh.Init(adFac, TopAbs_EDGE); exsh.More(); exsh.Next()) {
904 const TopoDS_Shape& ced = exsh.Current();
905 if (!theMultiEd.Contains(ced)) {
906 for (lconx2.Initialize(parents.FindFromKey(ced)); lconx2.More(); lconx2.Next()) {
907 if (theFaces.Contains(lconx2.Value())) {
908 adFac=lconx2.Value();
909 BRB.Add(CurShell, adFac);
910 theFaces.Remove(adFac);
911 newCur=Standard_False;
912 if (theFaces.IsEmpty()) break;
913 lesCur.Append(adFac);
917 if (theFaces.IsEmpty()) break;
921 CurShell.Closed (BRep_Tool::IsClosed (CurShell));
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();