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 IMPLEMENT_STANDARD_RTTIEXT(BRepCheck_Shell,BRepCheck_Result)
42 //=======================================================================
43 //function : Propagate
45 //=======================================================================
46 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
47 const TopoDS_Shape& theFac,
48 TopTools_MapOfShape& mapF)
50 if (mapF.Contains(theFac))
54 mapF.Add(theFac); // attention, if oriented == Standard_True, fac should
55 // be FORWARD or REVERSED. It is not checked.
57 TopTools_MapIteratorOfMapOfShape itf(mapF);
60 Standard_Boolean hasBeenAdded = Standard_False;
61 const TopoDS_Shape& fac = itf.Key();
63 for (ex.Init(fac,TopAbs_EDGE); ex.More(); ex.Next())
65 const TopoDS_Edge& edg = TopoDS::Edge(ex.Current());
66 // test if the edge is in the map (only orienteed edges are present)
67 if (mapEF.Contains(edg))
69 for (TopTools_ListIteratorOfListOfShape itl(mapEF.FindFromKey(edg)); itl.More(); itl.Next())
71 if (!itl.Value().IsSame(fac) && !mapF.Contains(itl.Value()))
73 mapF.Add(itl.Value());
74 hasBeenAdded = Standard_True;
78 }//for (ex.Init(fac,TopAbs_EDGE); ex.More();)
92 //=======================================================================
93 //function : BRepCheck_Trace
95 //=======================================================================
96 Standard_EXPORT Standard_Integer BRepCheck_Trace(const Standard_Integer phase) {
97 static int BRC_Trace = 0;
98 if (phase < 0) BRC_Trace =0;
99 else if (phase > 0) BRC_Trace=phase;
103 void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
104 if (!theShape.IsNull()) {
105 Standard_Integer code = theShape.HashCode(upper);
107 switch (theShape.ShapeType()) {
108 case TopAbs_COMPOUND :
111 case TopAbs_COMPSOLID :
136 cout << " : " << code << " ";
137 switch (theShape.Orientation()) {
138 case TopAbs_FORWARD :
141 case TopAbs_REVERSED :
144 case TopAbs_INTERNAL :
147 case TopAbs_EXTERNAL :
155 //=======================================================================
156 //function : IsOriented
158 //=======================================================================
159 inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
161 return (S.Orientation() == TopAbs_FORWARD ||
162 S.Orientation() == TopAbs_REVERSED);
166 //=======================================================================
167 //function : BRepCheck_Shell
169 //=======================================================================
171 BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
177 //=======================================================================
180 //=======================================================================
181 void BRepCheck_Shell::Minimum()
183 myCdone = Standard_False;
184 myOdone = Standard_False;
188 BRepCheck_ListOfStatus thelist;
189 myMap.Bind(myShape, thelist);
190 BRepCheck_ListOfStatus& lst = myMap(myShape);
192 // it is checked if the shell is "connected"
193 TopExp_Explorer exp(myShape,TopAbs_FACE);
194 Standard_Integer nbface = 0;
196 for (; exp.More(); exp.Next())
199 TopExp_Explorer expe;
200 for (expe.Init(exp.Current(),TopAbs_EDGE);
201 expe.More(); expe.Next())
203 const TopoDS_Shape& edg = expe.Current();
204 Standard_Integer index = myMapEF.FindIndex(edg);
207 TopTools_ListOfShape thelist1;
208 index = myMapEF.Add(edg, thelist1);
211 myMapEF(index).Append(exp.Current());
213 }//for (; exp.More(); exp.Next())
217 BRepCheck::Add(lst,BRepCheck_EmptyShell);
219 else if (nbface >= 2)
221 TopTools_MapOfShape mapF;
224 Propagate(myMapEF,exp.Current(),mapF);
226 if (mapF.Extent() != nbface)
228 BRepCheck::Add(lst,BRepCheck_NotConnected);
230 }//else if (nbface >= 2)
234 lst.Append(BRepCheck_NoError);
238 myMin = Standard_True;
242 //=======================================================================
243 //function : InContext
245 //=======================================================================
247 void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
250 if (myMap.IsBound(S)) {
253 BRepCheck_ListOfStatus thelist;
254 myMap.Bind(S, thelist);
256 BRepCheck_ListOfStatus& lst = myMap(S);
258 // for (TopExp_Explorer exp(S,TopAbs_SHELL); exp.More(); exp.Next()) {
259 TopExp_Explorer exp(S,TopAbs_SHELL) ;
260 for ( ; exp.More(); exp.Next()) {
261 if (exp.Current().IsSame(myShape)) {
266 BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
270 TopAbs_ShapeEnum styp = S.ShapeType();
275 BRepCheck_Status fst = Closed();
276 if ((fst == BRepCheck_NotClosed && S.Closed()) ||
277 (fst != BRepCheck_NoError)) {
278 BRepCheck::Add(lst,fst);
280 else if (!IsUnorientable()) {
282 BRepCheck::Add(lst,fst);
293 lst.Append(BRepCheck_NoError);
298 //=======================================================================
301 //=======================================================================
303 void BRepCheck_Shell::Blind()
306 // nothing more than in the minimum
307 myBlind = Standard_True;
312 //=======================================================================
315 //=======================================================================
316 BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
322 BRepCheck::Add(myMap(myShape), myCstat);
328 myCdone = Standard_True; // it will be done...
330 BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
331 if (itl.Value() != BRepCheck_NoError)
333 myCstat = itl.Value();
334 return myCstat; // already saved
337 myCstat = BRepCheck_NoError;
339 Standard_Integer index, aNbF;
340 TopExp_Explorer exp, ede;
341 TopTools_MapOfShape mapS, aMEToAvoid;
345 // Checks if the oriented faces of the shell give a "closed" shell,
346 // i-e if each oriented edge on oriented faces is found 2 times.
348 //modified by NIZNHY-PKV Mon Jun 4 13:59:21 2007f
349 exp.Init(myShape,TopAbs_FACE);
350 for (; exp.More(); exp.Next())
352 const TopoDS_Shape& aF=exp.Current();
355 ede.Init(exp.Current(),TopAbs_EDGE);
356 for (; ede.More(); ede.Next())
358 const TopoDS_Shape& aE=ede.Current();
366 //modified by NIZNHY-PKV Mon Jun 4 13:59:23 2007t
368 exp.Init(myShape,TopAbs_FACE);
369 for (; exp.More(); exp.Next())
371 const TopoDS_Shape& aF=exp.Current();
376 myCstat = BRepCheck_RedundantFace;
380 BRepCheck::Add(myMap(myShape),myCstat);
387 ede.Init(exp.Current(),TopAbs_EDGE);
388 for (; ede.More(); ede.Next())
390 const TopoDS_Shape& aE=ede.Current();
391 //modified by NIZNHY-PKV Mon Jun 4 14:07:57 2007f
392 //if (IsOriented(aE)) {
393 if (!aMEToAvoid.Contains(aE))
395 //modified by NIZNHY-PKV Mon Jun 4 14:08:01 2007
396 index = myMapEF.FindIndex(aE);
400 TopTools_ListOfShape thelist;
401 index = myMapEF.Add(aE, thelist);
404 myMapEF(index).Append(aF);
411 myNbori = mapS.Extent();
415 // Search for the first oriented face
417 exp.Init(myShape, TopAbs_FACE);
418 for (;exp.More(); exp.Next())
427 Propagate(myMapEF, aF, mapS);
435 myCstat = BRepCheck_NotConnected;
438 BRepCheck::Add(myMap(myShape),myCstat);
444 Standard_Integer i, Nbedges, nboc, nbSet;
446 Nbedges = myMapEF.Extent();
447 for (i = 1; i<=Nbedges; ++i)
449 nboc = myMapEF(i).Extent();
450 if (nboc == 0 || nboc >= 3)
452 TopTools_ListOfShape theSet;
453 nbSet=NbConnectedSet(theSet);
454 // If there is more than one closed cavity the shell is considered invalid
455 // this corresponds to the criteria of a solid (not those of a shell)
458 myCstat = BRepCheck_InvalidMultiConnexity;
461 BRepCheck::Add(myMap(myShape),myCstat);
469 if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i))))
471 myCstat=BRepCheck_NotClosed;
474 BRepCheck::Add(myMap(myShape),myCstat);
483 BRepCheck::Add(myMap(myShape),myCstat);
489 //=======================================================================
490 //function : Orientation
492 //=======================================================================
494 BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
498 BRepCheck::Add(myMap(myShape), myOstat);
502 myOdone = Standard_True;
505 if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
507 BRepCheck::Add(myMap(myShape), myOstat);
512 myOstat = BRepCheck_NoError;
515 // First the orientation of each face in relation to the shell is found.
516 // It is used to check BRepCheck_RedundantFace
518 TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
519 TopExp_Explorer exp,ede;
521 for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
522 if (!MapOfShapeOrientation.Bind(exp.Current(), (Standard_Integer)(exp.Current().Orientation()))) {
523 myOstat = BRepCheck_RedundantFace;
525 BRepCheck::Add(myMap(myShape), myOstat);
534 if (BRepCheck_Trace(0) > 1) {
535 TopTools_DataMapIteratorOfDataMapOfShapeInteger itt(MapOfShapeOrientation);
536 Standard_Integer upper = MapOfShapeOrientation.NbBuckets();
537 cout << "La map shape Orientation :" << endl;
538 for (; itt.More(); itt.Next()) {
539 PrintShape(itt.Key(), upper);
546 // Then the orientation of faces by their connectivity is checked
547 // BRepCheck_BadOrientationOfSubshape and
548 // BRepCheck_SubshapeNotInShape are checked;
550 Standard_Integer Nbedges = myMapEF.Extent();
552 TopAbs_Orientation orf;
554 for (Standard_Integer i = 1; i<= Nbedges; i++) {
556 const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(i));
557 if (BRep_Tool::Degenerated(edg)) continue;
558 TopTools_ListOfShape& lface = myMapEF(i);
559 TopTools_ListIteratorOfListOfShape lite(lface);
561 if (lface.Extent() <= 2)
563 lite.Initialize(lface);
564 Fref = TopoDS::Face(lite.Value());
566 if (!MapOfShapeOrientation.IsBound(Fref)) {
567 myOstat = BRepCheck_SubshapeNotInShape;
569 BRepCheck::Add(myMap(myShape), myOstat);
571 // quit because no workaround for the incoherence is possible
576 if (lite.More()) { // Edge of connectivity
578 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
579 orf = (TopAbs_Orientation) iorf;
580 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
581 Fref.Orientation(orf);
584 if (!lite.Value().IsSame(Fref)) { // edge non "closed"
585 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
586 if (ede.Current().IsSame(edg)) {
590 TopAbs_Orientation orient = ede.Current().Orientation();
591 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
593 if (!MapOfShapeOrientation.IsBound(Fcur)) {
594 myOstat = BRepCheck_SubshapeNotInShape;
596 BRepCheck::Add(myMap(myShape), myOstat);
598 // quit because no workaround for the incoherence is possible
603 Standard_Integer anOriFCur = MapOfShapeOrientation.Find(Fcur) ;
604 orf = (TopAbs_Orientation)anOriFCur;
605 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
606 Fcur.Orientation(orf);
608 for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
609 if (ede.Current().IsSame(edg)) {
613 if (ede.Current().Orientation() == orient) {
614 // The loop is continued on the edges as many times
615 // as the same edge is present in the wire
617 // modified by NIZHNY-MKK Tue Sep 30 11:11:42 2003
618 Standard_Boolean bfound = Standard_False;
620 for (; ede.More(); ede.Next()) {
621 if (ede.Current().IsSame(edg)) {
622 // modified by NIZHNY-MKK Tue Sep 30 11:12:03 2003
623 bfound = Standard_True;
627 // if (ede.Current().Orientation() == orient) {
628 // modified by NIZHNY-MKK Thu Oct 2 17:56:47 2003
629 if (!bfound || (ede.Current().Orientation() == orient)) {
630 myOstat = BRepCheck_BadOrientationOfSubshape;
632 BRepCheck::Add(myMap(myShape), myOstat);
641 else //more than two faces
643 Standard_Integer numF = 0, numR = 0;
644 TopTools_MapOfShape Fmap;
646 for (lite.Initialize(lface); lite.More(); lite.Next())
648 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
649 if (!MapOfShapeOrientation.IsBound(Fcur))
651 myOstat = BRepCheck_SubshapeNotInShape;
653 BRepCheck::Add(myMap(myShape), myOstat);
654 // quit because no workaround for the incoherence is possible
658 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
659 orf = (TopAbs_Orientation) iorf;
660 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
661 Fcur.Orientation(orf);
663 for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
664 if (ede.Current().IsSame(edg))
666 if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
669 for (; ede.More(); ede.Next())
670 if (ede.Current().IsSame(edg))
673 TopAbs_Orientation orient = ede.Current().Orientation();
674 if (orient == TopAbs_FORWARD)
684 myOstat = BRepCheck_BadOrientationOfSubshape;
687 BRepCheck::Add(myMap(myShape), myOstat);
695 // If at least one incorrectly oriented face has been found, it is checked if the shell can be oriented.
696 // i.e. : if by modification of the orientation of a face it is possible to find
697 // a coherent orientation. (it is not possible on a Moebius band)
698 // BRepCheck_UnorientableShape is checked
700 if (myOstat == BRepCheck_BadOrientationOfSubshape) {
701 if (!Fref.IsNull()) {
703 TopTools_MapOfShape alre;
704 TopTools_ListOfShape voisin;
707 while (!voisin.IsEmpty()) {
708 Fref=TopoDS::Face(voisin.First());
709 voisin.RemoveFirst();
710 if (!MapOfShapeOrientation.IsBound(Fref)) {
711 myOstat = BRepCheck_SubshapeNotInShape;
713 BRepCheck::Add(myMap(myShape), myOstat);
715 // quit because no workaround for the incoherence is possible
719 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
720 orf = (TopAbs_Orientation) iorf ;
721 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
722 Fref.Orientation(orf);
725 if (BRepCheck_Trace(0) > 3) {
727 PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
731 TopExp_Explorer edFcur;
734 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
735 const TopoDS_Edge& edg = TopoDS::Edge(ede.Current());
736 TopAbs_Orientation orient = edg.Orientation();
737 TopTools_ListOfShape& lface = myMapEF.ChangeFromKey(edg);
738 TopTools_ListIteratorOfListOfShape lite(lface);
740 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
741 if (Fcur.IsSame(Fref)) {
744 Fcur=TopoDS::Face(lite.Value());
747 // from the free border one goes to the next edge
752 if (!MapOfShapeOrientation.IsBound(Fcur)) {
753 myOstat = BRepCheck_SubshapeNotInShape;
755 BRepCheck::Add(myMap(myShape), myOstat);
757 // quit because no workaround for the incoherence is possible
762 Standard_Integer anOriFCur = MapOfShapeOrientation.Find(Fcur) ;
763 orf = (TopAbs_Orientation)anOriFCur;
764 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
765 Fcur.Orientation(orf);
768 if (BRepCheck_Trace(0) > 3) {
770 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
773 for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
774 if (edFcur.Current().IsSame(edg)) {
778 if (edFcur.Current().Orientation() == orient) {
779 if (alre.Contains(Fcur)) {
780 // It is necessary to return a face that has been already examined or returned
781 // if one gets nowhere, the shell cannot be oriented.
782 myOstat = BRepCheck_UnorientableShape;
784 BRepCheck::Add(myMap(myShape), myOstat);
786 // quit, otherwise there is a risk of taking too much time.
788 if (BRepCheck_Trace(0) > 3) {
789 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
790 Fcur.Orientation(orf);
791 cout << " Error : this face has been already examined " << endl;
792 cout << " Imposible to return it ";
793 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
798 orf = TopAbs::Reverse(orf);
799 MapOfShapeOrientation(Fcur)=orf;
803 if (BRepCheck_Trace(0) > 3) {
804 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
805 Fcur.Orientation(orf);
806 cout << " Resulting Fcur is returned : " ;
807 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
812 if (alre.Add(Fcur)) {
822 BRepCheck::Add(myMap(myShape), myOstat);
827 //=======================================================================
828 //function : SetUnorientable
830 //=======================================================================
832 void BRepCheck_Shell::SetUnorientable()
834 BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
838 //=======================================================================
839 //function : IsUnorientable
841 //=======================================================================
843 Standard_Boolean BRepCheck_Shell::IsUnorientable() const
846 return (myOstat != BRepCheck_NoError);
848 for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
851 if (itl.Value() == BRepCheck_UnorientableShape) {
852 return Standard_True;
855 return Standard_False;
858 //=======================================================================
859 //function : NbConnectedSet
861 //=======================================================================
863 Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
865 // The connections are found
866 TopTools_IndexedDataMapOfShapeListOfShape parents;
867 TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, parents);
868 // All faces are taken
869 TopTools_MapOfShape theFaces;
870 TopExp_Explorer exsh(myShape, TopAbs_FACE);
871 for (; exsh.More(); exsh.Next()) theFaces.Add(exsh.Current());
872 // The edges that are not oriented or have more than 2 connections are missing
873 Standard_Integer iCur;
874 TopTools_MapOfShape theMultiEd;
875 TopTools_MapOfShape theUnOriEd;
876 for (iCur=1; iCur<=parents.Extent(); iCur++) {
877 const TopoDS_Edge& Ed = TopoDS::Edge(parents.FindKey(iCur));
878 if (parents(iCur).Extent()> 2) theMultiEd.Add(Ed);
879 if (Ed.Orientation()!=TopAbs_REVERSED &&
880 Ed.Orientation()!=TopAbs_FORWARD) theUnOriEd.Add(Ed);
882 // Starting from multiconnected edges propagation by simple connections
883 TopTools_ListIteratorOfListOfShape lconx1, lconx2;
884 TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
885 TopoDS_Shell CurShell;
887 TopTools_ListOfShape lesCur;
889 Standard_Boolean newCur=Standard_True;
890 BRB.MakeShell(CurShell);
891 for (; itmsh.More(); itmsh.Next()) {
892 const TopoDS_Shape& Ed = itmsh.Key();
893 if (!theUnOriEd.Contains(Ed)) {
894 for (lconx1.Initialize(parents.FindFromKey(Ed)); lconx1.More(); lconx1.Next()) {
895 if (theFaces.Contains(lconx1.Value())) {
896 adFac=lconx1.Value();
897 BRB.Add(CurShell, adFac);
898 theFaces.Remove(adFac);
899 newCur=Standard_False;
900 if (theFaces.IsEmpty()) break;
901 lesCur.Append(adFac);
902 while (!lesCur.IsEmpty()) {
903 adFac=lesCur.First();
904 lesCur.RemoveFirst();
905 for (exsh.Init(adFac, TopAbs_EDGE); exsh.More(); exsh.Next()) {
906 const TopoDS_Shape& ced = exsh.Current();
907 if (!theMultiEd.Contains(ced)) {
908 for (lconx2.Initialize(parents.FindFromKey(ced)); lconx2.More(); lconx2.Next()) {
909 if (theFaces.Contains(lconx2.Value())) {
910 adFac=lconx2.Value();
911 BRB.Add(CurShell, adFac);
912 theFaces.Remove(adFac);
913 newCur=Standard_False;
914 if (theFaces.IsEmpty()) break;
915 lesCur.Append(adFac);
919 if (theFaces.IsEmpty()) break;
923 CurShell.Closed (BRep_Tool::IsClosed (CurShell));
924 theSets.Append(CurShell);
926 newCur=Standard_True;
927 BRB.MakeShell(CurShell);
930 if (theFaces.IsEmpty()) break;
933 if (theFaces.IsEmpty()) break;
935 return theSets.Extent();