1 // Created on: 1995-12-12
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
23 #include <BRepCheck_Shell.ixx>
25 #include <BRepCheck_ListOfStatus.hxx>
26 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
28 #include <TopTools_MapOfShape.hxx>
29 #include <TopTools_MapIteratorOfMapOfShape.hxx>
30 #include <TopTools_ListOfShape.hxx>
31 #include <TopTools_ListIteratorOfListOfShape.hxx>
32 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
33 #include <BRep_Tool.hxx>
34 #include <BRep_Builder.hxx>
36 #include <TopExp_Explorer.hxx>
38 #include <BRepCheck.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Face.hxx>
44 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
45 #include <TopTools_DataMapOfShapeInteger.hxx>
48 Standard_EXPORT Standard_Integer BRepCheck_Trace(const Standard_Integer phase) {
49 static int BRC_Trace = 0;
50 if (phase < 0) BRC_Trace =0;
51 else if (phase > 0) BRC_Trace=phase;
55 void PrintShape(const TopoDS_Shape& theShape, const Standard_Integer upper) {
56 if (!theShape.IsNull()) {
57 Standard_Integer code = theShape.HashCode(upper);
59 switch (theShape.ShapeType()) {
60 case TopAbs_COMPOUND :
63 case TopAbs_COMPSOLID :
88 cout << " : " << code << " ";
89 switch (theShape.Orientation()) {
93 case TopAbs_REVERSED :
96 case TopAbs_INTERNAL :
99 case TopAbs_EXTERNAL :
107 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape&,
108 const TopoDS_Shape&, // Face
109 TopTools_MapOfShape&); // mapofface
111 inline Standard_Boolean IsOriented(const TopoDS_Shape& S)
113 return (S.Orientation() == TopAbs_FORWARD ||
114 S.Orientation() == TopAbs_REVERSED);
118 //=======================================================================
119 //function : BRepCheck_Shell
121 //=======================================================================
123 BRepCheck_Shell::BRepCheck_Shell(const TopoDS_Shell& S)
129 //=======================================================================
132 //=======================================================================
134 void BRepCheck_Shell::Minimum()
136 myCdone = Standard_False;
137 myOdone = Standard_False;
140 BRepCheck_ListOfStatus thelist;
141 myMap.Bind(myShape, thelist);
142 BRepCheck_ListOfStatus& lst = myMap(myShape);
144 // it is checked if the shell is "connected"
145 TopExp_Explorer exp(myShape,TopAbs_FACE);
146 Standard_Integer nbface = 0;
148 for (; exp.More(); exp.Next()) {
150 TopExp_Explorer expe;
151 for (expe.Init(exp.Current(),TopAbs_EDGE);
152 expe.More(); expe.Next()) {
153 const TopoDS_Shape& edg = expe.Current();
154 Standard_Integer index = myMapEF.FindIndex(edg);
156 TopTools_ListOfShape thelist1;
157 index = myMapEF.Add(edg, thelist1);
159 myMapEF(index).Append(exp.Current());
164 BRepCheck::Add(lst,BRepCheck_EmptyShell);
166 else if (nbface >= 2) {
167 TopTools_MapOfShape mapF;
169 Propagate(myMapEF,exp.Current(),mapF);
170 if (mapF.Extent() != nbface) {
171 BRepCheck::Add(lst,BRepCheck_NotConnected);
175 lst.Append(BRepCheck_NoError);
178 myMin = Standard_True;
184 //=======================================================================
185 //function : InContext
187 //=======================================================================
189 void BRepCheck_Shell::InContext(const TopoDS_Shape& S)
192 if (myMap.IsBound(S)) {
195 BRepCheck_ListOfStatus thelist;
196 myMap.Bind(S, thelist);
198 BRepCheck_ListOfStatus& lst = myMap(S);
200 // for (TopExp_Explorer exp(S,TopAbs_SHELL); exp.More(); exp.Next()) {
201 TopExp_Explorer exp(S,TopAbs_SHELL) ;
202 for ( ; exp.More(); exp.Next()) {
203 if (exp.Current().IsSame(myShape)) {
208 BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
212 TopAbs_ShapeEnum styp = S.ShapeType();
217 BRepCheck_Status fst = Closed();
218 if ((fst == BRepCheck_NotClosed && S.Closed()) ||
219 (fst != BRepCheck_NoError)) {
220 BRepCheck::Add(lst,fst);
222 else if (!IsUnorientable()) {
224 BRepCheck::Add(lst,fst);
235 lst.Append(BRepCheck_NoError);
240 //=======================================================================
243 //=======================================================================
245 void BRepCheck_Shell::Blind()
248 // nothing more than in the minimum
249 myBlind = Standard_True;
254 //=======================================================================
257 //=======================================================================
259 BRepCheck_Status BRepCheck_Shell::Closed(const Standard_Boolean Update)
264 BRepCheck::Add(myMap(myShape), myCstat);
269 myCdone = Standard_True; // it will be done...
271 BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
272 if (itl.Value() != BRepCheck_NoError) {
273 myCstat = itl.Value();
274 return myCstat; // already saved
277 myCstat = BRepCheck_NoError;
279 Standard_Integer index, aNbF;
280 TopExp_Explorer exp, ede;
281 TopTools_MapOfShape mapS, aMEToAvoid;
285 // Checks if the oriented faces of the shell give a "closed" shell,
286 // i-e if each oriented edge on oriented faces is found 2 times.
288 //modified by NIZNHY-PKV Mon Jun 4 13:59:21 2007f
289 exp.Init(myShape,TopAbs_FACE);
290 for (; exp.More(); exp.Next()) {
291 const TopoDS_Shape& aF=exp.Current();
292 if (IsOriented(aF)) {
293 ede.Init(exp.Current(),TopAbs_EDGE);
294 for (; ede.More(); ede.Next()) {
295 const TopoDS_Shape& aE=ede.Current();
296 if (!IsOriented(aE)) {
302 //modified by NIZNHY-PKV Mon Jun 4 13:59:23 2007t
304 exp.Init(myShape,TopAbs_FACE);
305 for (; exp.More(); exp.Next()) {
306 const TopoDS_Shape& aF=exp.Current();
307 if (IsOriented(aF)) {
309 myCstat = BRepCheck_RedundantFace;
311 BRepCheck::Add(myMap(myShape),myCstat);
316 ede.Init(exp.Current(),TopAbs_EDGE);
317 for (; ede.More(); ede.Next()) {
318 const TopoDS_Shape& aE=ede.Current();
319 //modified by NIZNHY-PKV Mon Jun 4 14:07:57 2007f
320 //if (IsOriented(aE)) {
321 if (!aMEToAvoid.Contains(aE)) {
322 //modified by NIZNHY-PKV Mon Jun 4 14:08:01 2007
323 index = myMapEF.FindIndex(aE);
325 TopTools_ListOfShape thelist;
326 index = myMapEF.Add(aE, thelist);
328 myMapEF(index).Append(aF);
334 myNbori = mapS.Extent();
337 // Search for the first oriented face
339 exp.Init(myShape, TopAbs_FACE);
340 for (;exp.More(); exp.Next()) {
342 if (IsOriented(aF)) {
347 Propagate(myMapEF, aF, mapS);
352 if (myNbori != aNbF) {
353 myCstat = BRepCheck_NotConnected;
355 BRepCheck::Add(myMap(myShape),myCstat);
361 Standard_Integer i, Nbedges, nboc, nbSet;
363 Nbedges = myMapEF.Extent();
364 for (i = 1; i<=Nbedges; ++i) {
365 nboc = myMapEF(i).Extent();
366 if (nboc == 0 || nboc >= 3) {
367 TopTools_ListOfShape theSet;
368 nbSet=NbConnectedSet(theSet);
369 // If there is more than one closed cavity the shell is considered invalid
370 // this corresponds to the criteria of a solid (not those of a shell)
372 myCstat = BRepCheck_InvalidMultiConnexity;
374 BRepCheck::Add(myMap(myShape),myCstat);
379 else if (nboc == 1) {
380 if (!BRep_Tool::Degenerated(TopoDS::Edge(myMapEF.FindKey(i)))) {
381 myCstat=BRepCheck_NotClosed;
383 BRepCheck::Add(myMap(myShape),myCstat);
391 BRepCheck::Add(myMap(myShape),myCstat);
397 //=======================================================================
398 //function : Orientation
400 //=======================================================================
402 BRepCheck_Status BRepCheck_Shell::Orientation(const Standard_Boolean Update)
406 BRepCheck::Add(myMap(myShape), myOstat);
410 myOdone = Standard_True;
413 if (myOstat != BRepCheck_NotClosed && myOstat != BRepCheck_NoError) {
415 BRepCheck::Add(myMap(myShape), myOstat);
420 myOstat = BRepCheck_NoError;
423 // First the orientation of each face in relation to the shell is found.
424 // It is used to check BRepCheck_RedundantFace
426 TopTools_DataMapOfShapeInteger MapOfShapeOrientation;
427 TopExp_Explorer exp,ede;
429 for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
430 if (!MapOfShapeOrientation.Bind(exp.Current(), (Standard_Integer)(exp.Current().Orientation()))) {
431 myOstat = BRepCheck_RedundantFace;
433 BRepCheck::Add(myMap(myShape), myOstat);
442 if (BRepCheck_Trace(0) > 1) {
443 TopTools_DataMapIteratorOfDataMapOfShapeInteger itt(MapOfShapeOrientation);
444 Standard_Integer upper = MapOfShapeOrientation.NbBuckets();
445 cout << "La map shape Orientation :" << endl;
446 for (; itt.More(); itt.Next()) {
447 PrintShape(itt.Key(), upper);
454 // Then the orientation of faces by their connectivity is checked
455 // BRepCheck_BadOrientationOfSubshape and
456 // BRepCheck_SubshapeNotInShape are checked;
458 Standard_Integer Nbedges = myMapEF.Extent();
460 TopAbs_Orientation orf;
462 for (Standard_Integer i = 1; i<= Nbedges; i++) {
464 const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(i));
465 if (BRep_Tool::Degenerated(edg)) continue;
466 TopTools_ListOfShape& lface = myMapEF(i);
467 TopTools_ListIteratorOfListOfShape lite(lface);
469 if (lface.Extent() <= 2)
471 lite.Initialize(lface);
472 Fref = TopoDS::Face(lite.Value());
474 if (!MapOfShapeOrientation.IsBound(Fref)) {
475 myOstat = BRepCheck_SubshapeNotInShape;
477 BRepCheck::Add(myMap(myShape), myOstat);
479 // quit because no workaround for the incoherence is possible
484 if (lite.More()) { // Edge of connectivity
486 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref);
487 orf = (TopAbs_Orientation) iorf;
488 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
489 Fref.Orientation(orf);
492 if (!lite.Value().IsSame(Fref)) { // edge non "closed"
493 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
494 if (ede.Current().IsSame(edg)) {
498 TopAbs_Orientation orient = ede.Current().Orientation();
499 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
501 if (!MapOfShapeOrientation.IsBound(Fcur)) {
502 myOstat = BRepCheck_SubshapeNotInShape;
504 BRepCheck::Add(myMap(myShape), myOstat);
506 // quit because no workaround for the incoherence is possible
511 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
512 orf = (TopAbs_Orientation) iorf ;
513 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
514 Fcur.Orientation(orf);
516 for (ede.Init(Fcur, TopAbs_EDGE); ede.More(); ede.Next()) {
517 if (ede.Current().IsSame(edg)) {
521 if (ede.Current().Orientation() == orient) {
522 // The loop is continued on the edges as many times
523 // as the same edge is present in the wire
525 // modified by NIZHNY-MKK Tue Sep 30 11:11:42 2003
526 Standard_Boolean bfound = Standard_False;
528 for (; ede.More(); ede.Next()) {
529 if (ede.Current().IsSame(edg)) {
530 // modified by NIZHNY-MKK Tue Sep 30 11:12:03 2003
531 bfound = Standard_True;
535 // if (ede.Current().Orientation() == orient) {
536 // modified by NIZHNY-MKK Thu Oct 2 17:56:47 2003
537 if (!bfound || (ede.Current().Orientation() == orient)) {
538 myOstat = BRepCheck_BadOrientationOfSubshape;
540 BRepCheck::Add(myMap(myShape), myOstat);
549 else //more than two faces
551 Standard_Integer numF = 0, numR = 0;
552 TopTools_MapOfShape Fmap;
554 for (lite.Initialize(lface); lite.More(); lite.Next())
556 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
557 if (!MapOfShapeOrientation.IsBound(Fcur))
559 myOstat = BRepCheck_SubshapeNotInShape;
561 BRepCheck::Add(myMap(myShape), myOstat);
562 // quit because no workaround for the incoherence is possible
566 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur);
567 orf = (TopAbs_Orientation) iorf;
568 //orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
569 Fcur.Orientation(orf);
571 for (ede.Init(Fcur,TopAbs_EDGE); ede.More(); ede.Next())
572 if (ede.Current().IsSame(edg))
574 if (Fmap.Contains(Fcur)) //edge is "closed" on Fcur, we meet Fcur twice
577 for (; ede.More(); ede.Next())
578 if (ede.Current().IsSame(edg))
581 TopAbs_Orientation orient = ede.Current().Orientation();
582 if (orient == TopAbs_FORWARD)
592 myOstat = BRepCheck_BadOrientationOfSubshape;
595 BRepCheck::Add(myMap(myShape), myOstat);
603 // If at least one incorrectly oriented face has been found, it is checked if the shell can be oriented.
604 // i.e. : if by modification of the orientation of a face it is possible to find
605 // a coherent orientation. (it is not possible on a Moebius band)
606 // BRepCheck_UnorientableShape is checked
608 if (myOstat == BRepCheck_BadOrientationOfSubshape) {
609 if (!Fref.IsNull()) {
611 TopTools_MapOfShape alre;
612 TopTools_ListOfShape voisin;
615 while (!voisin.IsEmpty()) {
616 Fref=TopoDS::Face(voisin.First());
617 voisin.RemoveFirst();
618 if (!MapOfShapeOrientation.IsBound(Fref)) {
619 myOstat = BRepCheck_SubshapeNotInShape;
621 BRepCheck::Add(myMap(myShape), myOstat);
623 // quit because no workaround for the incoherence is possible
627 Standard_Integer iorf = MapOfShapeOrientation.Find(Fref) ;
628 orf = (TopAbs_Orientation) iorf ;
629 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fref);
630 Fref.Orientation(orf);
633 if (BRepCheck_Trace(0) > 3) {
635 PrintShape(Fref, MapOfShapeOrientation.NbBuckets());
639 TopExp_Explorer edFcur;
642 for (ede.Init(Fref,TopAbs_EDGE); ede.More(); ede.Next()) {
643 const TopoDS_Edge& edg = TopoDS::Edge(ede.Current());
644 TopAbs_Orientation orient = edg.Orientation();
645 TopTools_ListOfShape& lface = myMapEF.ChangeFromKey(edg);
646 TopTools_ListIteratorOfListOfShape lite(lface);
648 TopoDS_Face Fcur= TopoDS::Face(lite.Value());
649 if (Fcur.IsSame(Fref)) {
652 Fcur=TopoDS::Face(lite.Value());
655 // from the free border one goes to the next edge
660 if (!MapOfShapeOrientation.IsBound(Fcur)) {
661 myOstat = BRepCheck_SubshapeNotInShape;
663 BRepCheck::Add(myMap(myShape), myOstat);
665 // quit because no workaround for the incoherence is possible
670 Standard_Integer iorf = MapOfShapeOrientation.Find(Fcur) ;
671 orf = (TopAbs_Orientation) iorf ;
672 // orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
673 Fcur.Orientation(orf);
676 if (BRepCheck_Trace(0) > 3) {
678 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
681 for (edFcur.Init(Fcur, TopAbs_EDGE); edFcur.More(); edFcur.Next()) {
682 if (edFcur.Current().IsSame(edg)) {
686 if (edFcur.Current().Orientation() == orient) {
687 if (alre.Contains(Fcur)) {
688 // It is necessary to return a face that has been already examined or returned
689 // if one gets nowhere, the shell cannot be oriented.
690 myOstat = BRepCheck_UnorientableShape;
692 BRepCheck::Add(myMap(myShape), myOstat);
694 // quit, otherwise there is a risk of taking too much time.
696 if (BRepCheck_Trace(0) > 3) {
697 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
698 Fcur.Orientation(orf);
699 cout << " Error : this face has been already examined " << endl;
700 cout << " Imposible to return it ";
701 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
706 orf = TopAbs::Reverse(orf);
707 MapOfShapeOrientation(Fcur)=orf;
711 if (BRepCheck_Trace(0) > 3) {
712 orf = (TopAbs_Orientation)MapOfShapeOrientation.Find(Fcur);
713 Fcur.Orientation(orf);
714 cout << " Resulting Fcur is returned : " ;
715 PrintShape(Fcur, MapOfShapeOrientation.NbBuckets());
720 if (alre.Add(Fcur)) {
730 BRepCheck::Add(myMap(myShape), myOstat);
735 //=======================================================================
736 //function : SetUnorientable
738 //=======================================================================
740 void BRepCheck_Shell::SetUnorientable()
742 BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
746 //=======================================================================
747 //function : IsUnorientable
749 //=======================================================================
751 Standard_Boolean BRepCheck_Shell::IsUnorientable() const
754 return (myOstat != BRepCheck_NoError);
756 for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
759 if (itl.Value() == BRepCheck_UnorientableShape) {
760 return Standard_True;
763 return Standard_False;
766 //=======================================================================
767 //function : NbConnectedSet
769 //=======================================================================
771 Standard_Integer BRepCheck_Shell::NbConnectedSet(TopTools_ListOfShape& theSets)
773 // The connections are found
774 TopTools_IndexedDataMapOfShapeListOfShape parents;
775 TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, parents);
776 // All faces are taken
777 TopTools_MapOfShape theFaces;
778 TopExp_Explorer exsh(myShape, TopAbs_FACE);
779 for (; exsh.More(); exsh.Next()) theFaces.Add(exsh.Current());
780 // The edges that are not oriented or have more than 2 connections are missing
781 Standard_Integer iCur;
782 TopTools_MapOfShape theMultiEd;
783 TopTools_MapOfShape theUnOriEd;
784 for (iCur=1; iCur<=parents.Extent(); iCur++) {
785 const TopoDS_Edge& Ed = TopoDS::Edge(parents.FindKey(iCur));
786 if (parents(iCur).Extent()> 2) theMultiEd.Add(Ed);
787 if (Ed.Orientation()!=TopAbs_REVERSED &&
788 Ed.Orientation()!=TopAbs_FORWARD) theUnOriEd.Add(Ed);
790 // Starting from multiconnected edges propagation by simple connections
791 TopTools_ListIteratorOfListOfShape lconx1, lconx2;
792 TopTools_MapIteratorOfMapOfShape itmsh(theMultiEd);
793 TopoDS_Shell CurShell;
795 TopTools_ListOfShape lesCur;
797 Standard_Boolean newCur=Standard_True;
798 BRB.MakeShell(CurShell);
799 for (; itmsh.More(); itmsh.Next()) {
800 const TopoDS_Shape& Ed = itmsh.Key();
801 if (!theUnOriEd.Contains(Ed)) {
802 for (lconx1.Initialize(parents.FindFromKey(Ed)); lconx1.More(); lconx1.Next()) {
803 if (theFaces.Contains(lconx1.Value())) {
804 adFac=lconx1.Value();
805 BRB.Add(CurShell, adFac);
806 theFaces.Remove(adFac);
807 newCur=Standard_False;
808 if (theFaces.IsEmpty()) break;
809 lesCur.Append(adFac);
810 while (!lesCur.IsEmpty()) {
811 adFac=lesCur.First();
812 lesCur.RemoveFirst();
813 for (exsh.Init(adFac, TopAbs_EDGE); exsh.More(); exsh.Next()) {
814 const TopoDS_Shape& ced = exsh.Current();
815 if (!theMultiEd.Contains(ced)) {
816 for (lconx2.Initialize(parents.FindFromKey(ced)); lconx2.More(); lconx2.Next()) {
817 if (theFaces.Contains(lconx2.Value())) {
818 adFac=lconx2.Value();
819 BRB.Add(CurShell, adFac);
820 theFaces.Remove(adFac);
821 newCur=Standard_False;
822 if (theFaces.IsEmpty()) break;
823 lesCur.Append(adFac);
827 if (theFaces.IsEmpty()) break;
831 theSets.Append(CurShell);
833 newCur=Standard_True;
834 BRB.MakeShell(CurShell);
837 if (theFaces.IsEmpty()) break;
840 if (theFaces.IsEmpty()) break;
842 return theSets.Extent();
845 //=======================================================================
846 //function : Propagate
848 //=======================================================================
850 static void Propagate(const TopTools_IndexedDataMapOfShapeListOfShape& mapEF,
851 const TopoDS_Shape& fac,
852 TopTools_MapOfShape& mapF)
854 if (mapF.Contains(fac)) {
857 mapF.Add(fac); // attention, if oriented == Standard_True, fac should
858 // be FORWARD or REVERSED. It is not checked.
861 for (ex.Init(fac,TopAbs_EDGE); ex.More(); ex.Next()) {
862 const TopoDS_Edge& edg = TopoDS::Edge(ex.Current());
863 // test if the edge is in the map (only orienteed edges are present)
864 if (mapEF.Contains(edg)) {
865 for (TopTools_ListIteratorOfListOfShape itl(mapEF.FindFromKey(edg));
866 itl.More(); itl.Next()) {
867 if (!itl.Value().IsSame(fac) &&
868 !mapF.Contains(itl.Value())) {
869 Propagate(mapEF,itl.Value(),mapF);