1 // Created on: 1995-12-15
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_Face.ixx>
25 #include <BRepCheck_ListOfStatus.hxx>
26 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
28 #include <BRep_TFace.hxx>
29 #include <BRep_Builder.hxx>
30 #include <BRep_Tool.hxx>
33 #include <TopExp_Explorer.hxx>
35 #include <TopTools_ListOfShape.hxx>
36 #include <TopTools_ListIteratorOfListOfShape.hxx>
37 #include <TopTools_DataMapOfShapeListOfShape.hxx>
38 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
40 //#include <BRepAdaptor_Curve2d.hxx>
41 #include <BRepClass_FaceClassifier.hxx>
42 //#include <Geom2dInt_GInter.hxx>
43 #include <Geom2d_Curve.hxx>
44 #include <Geom_Curve.hxx>
45 #include <GProp_GProps.hxx>
47 #include <IntRes2d_Domain.hxx>
48 #include <Geom2dInt_GInter.hxx>
49 #include <Geom2dAdaptor_Curve.hxx>
50 #include <gp_Pnt2d.hxx>
54 #include <BRepCheck.hxx>
55 #include <Precision.hxx>
57 #include <TopoDS_Wire.hxx>
59 #include <BRepTopAdaptor_FClass2d.hxx>
60 #include <TopAbs_State.hxx>
62 #include <Bnd_Box2d.hxx>
63 #include <BndLib_Add2dCurve.hxx>
64 #include <TopTools_MapOfShape.hxx>
65 #include <TopTools_SequenceOfShape.hxx>
66 #include <TColgp_SequenceOfPnt.hxx>
67 #include <TopoDS_Vertex.hxx>
68 #include <IntRes2d_IntersectionPoint.hxx>
69 #include <IntRes2d_IntersectionSegment.hxx>
70 #include <BRepAdaptor_HSurface.hxx>
73 static Standard_Boolean Intersect(const TopoDS_Wire&,
78 static Standard_Boolean IsInside(const TopoDS_Wire& wir,
79 const Standard_Boolean Inside,
80 const BRepTopAdaptor_FClass2d& FClass2d,
81 const TopoDS_Face& F);
83 static Standard_Boolean CheckThin(const TopoDS_Shape& w,
84 const TopoDS_Shape& f);
86 //=======================================================================
87 //function : BRepCheck_Face
89 //=======================================================================
91 BRepCheck_Face::BRepCheck_Face (const TopoDS_Face& F)
94 myIntdone = Standard_False;
95 myImbdone = Standard_False;
96 myOridone = Standard_False;
97 myGctrl = Standard_True;
100 //=======================================================================
103 //=======================================================================
105 void BRepCheck_Face::Minimum()
108 BRepCheck_ListOfStatus thelist;
109 myMap.Bind(myShape, thelist);
110 BRepCheck_ListOfStatus& lst = myMap(myShape);
112 Handle(BRep_TFace)& TF = *((Handle(BRep_TFace)*) &myShape.TShape());
113 if (TF->Surface().IsNull()) {
114 BRepCheck::Add(lst,BRepCheck_NoSurface);
117 // Flag natural restriction???
120 lst.Append(BRepCheck_NoError);
122 myMin = Standard_True;
127 //=======================================================================
128 //function : InContext
130 //=======================================================================
132 void BRepCheck_Face::InContext(const TopoDS_Shape& S)
134 if (myMap.IsBound(S)) {
137 BRepCheck_ListOfStatus thelist;
138 myMap.Bind(S, thelist);
140 BRepCheck_ListOfStatus& lst = myMap(S);
142 TopExp_Explorer exp(S,TopAbs_FACE);
143 for (; exp.More(); exp.Next()) {
144 if (exp.Current().IsSame(myShape)) {
149 BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
154 lst.Append(BRepCheck_NoError);
159 //=======================================================================
162 //=======================================================================
164 void BRepCheck_Face::Blind()
167 // nothing more than in the minimum
168 myBlind = Standard_True;
173 //=======================================================================
174 //function : IntersectWires
176 //=======================================================================
178 BRepCheck_Status BRepCheck_Face::IntersectWires(const Standard_Boolean Update)
182 BRepCheck::Add(myMap(myShape),myIntres);
187 myIntdone = Standard_True;
188 myIntres = BRepCheck_NoError;
189 // This method has to be called by an analyzer. It is assumed that
190 // each edge has a correct 2d representation on the face.
192 TopExp_Explorer exp1,exp2;
194 // the wires are mapped
195 exp1.Init(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
196 TopTools_ListOfShape theListOfShape;
197 while (exp1.More()) {
198 if (!myMapImb.IsBound(exp1.Current())) {
199 myMapImb.Bind(exp1.Current(), theListOfShape);
201 else { // the same wire is met twice...
202 myIntres = BRepCheck_RedundantWire;
204 BRepCheck::Add(myMap(myShape),myIntres);
211 Standard_Integer Nbwire, Index,Indexbis;
212 Nbwire = myMapImb.Extent();
215 while (Index < Nbwire) {
216 for (exp1.Init(myShape,TopAbs_WIRE),Indexbis = 0;
217 exp1.More();exp1.Next()) {
219 if (Indexbis == Index) {
223 TopoDS_Wire wir1 = TopoDS::Wire(exp1.Current());
225 for (; exp1.More(); exp1.Next()) {
226 const TopoDS_Wire& wir2 = TopoDS::Wire(exp1.Current());
227 if (Intersect(wir1,wir2,TopoDS::Face(myShape))) {
228 myIntres = BRepCheck_IntersectingWires;
230 BRepCheck::Add(myMap(myShape),myIntres);
238 BRepCheck::Add(myMap(myShape),myIntres);
244 //=======================================================================
245 //function : ClassifyWires
247 //=======================================================================
249 BRepCheck_Status BRepCheck_Face::ClassifyWires(const Standard_Boolean Update)
251 // It is assumed that each wire does not intersect any other one.
254 BRepCheck::Add(myMap(myShape),myImbres);
259 myImbdone = Standard_True;
260 myImbres = IntersectWires();
261 if (myImbres != BRepCheck_NoError) {
263 BRepCheck::Add(myMap(myShape),myImbres);
268 Standard_Integer Nbwire = myMapImb.Extent();
271 BRepCheck::Add(myMap(myShape),myImbres);
277 TopExp_Explorer exp1,exp2;
278 TopTools_ListOfShape theListOfShape;
279 for (exp1.Init(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
280 exp1.More();exp1.Next()) {
282 const TopoDS_Wire& wir1 = TopoDS::Wire(exp1.Current());
283 TopoDS_Shape aLocalShape = myShape.EmptyCopied();
284 TopoDS_Face newFace = TopoDS::Face(aLocalShape);
285 // TopoDS_Face newFace = TopoDS::Face(myShape.EmptyCopied());
287 newFace.Orientation(TopAbs_FORWARD);
290 BRepTopAdaptor_FClass2d FClass2d(newFace,Precision::PConfusion());
291 Standard_Boolean WireBienOriente = Standard_False;
292 if(FClass2d.PerformInfinitePoint() != TopAbs_OUT) {
293 WireBienOriente=Standard_True;
294 // the given wire defines a hole
295 myMapImb.UnBind(wir1);
296 myMapImb.Bind(wir1.Reversed(), theListOfShape);
299 for (exp2.Init(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
300 exp2.More();exp2.Next()) {
301 const TopoDS_Wire& wir2 = TopoDS::Wire(exp2.Current());
302 if (!wir2.IsSame(wir1)) {
304 if (IsInside(wir2,WireBienOriente,FClass2d,newFace)) {
305 myMapImb(wir1).Append(wir2);
310 // It is required to have 1 wire that contains all others, and the others should not
311 // contain anything (case solid ended) or
312 // the wires do not contain anything : in this case the wires should be
313 // holes in an infinite face.
315 for (TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itm(myMapImb);
318 if (!itm.Value().IsEmpty()) {
320 Wext = TopoDS::Wire(itm.Key());
323 myImbres = BRepCheck_InvalidImbricationOfWires;
325 BRepCheck::Add(myMap(myShape),myImbres);
332 if (!Wext.IsNull()) {
333 // verifies that the list contains nbwire-1 elements
334 if (myMapImb(Wext).Extent() != Nbwire-1) {
335 myImbres = BRepCheck_InvalidImbricationOfWires;
337 BRepCheck::Add(myMap(myShape),myImbres);
342 // quit without errors
344 BRepCheck::Add(myMap(myShape),myImbres);
351 //=======================================================================
352 //function : OrientationOfWires
354 //=======================================================================
356 BRepCheck_Status BRepCheck_Face::OrientationOfWires
357 (const Standard_Boolean Update)
359 // WARNING : it is assumed that the edges of a wire are correctly oriented
362 Standard_Boolean Infinite = myShape.Infinite();
366 BRepCheck::Add(myMap(myShape),myOrires);
371 myOridone = Standard_True;
372 myOrires = ClassifyWires();
373 if (myOrires != BRepCheck_NoError) {
375 BRepCheck::Add(myMap(myShape),myOrires);
380 Standard_Integer Nbwire = myMapImb.Extent();
382 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itm(myMapImb);
385 Wext = TopoDS::Wire(itm.Key());
389 for (;itm.More();itm.Next()) {
390 if (!itm.Value().IsEmpty()) {
391 Wext = TopoDS::Wire(itm.Key());
396 if (Wext.IsNull() && !Infinite) {
397 if (Nbwire>0) myOrires = BRepCheck_InvalidImbricationOfWires;
399 BRepCheck::Add(myMap(myShape),myOrires);
405 TopExp_Explorer exp(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
406 for (; exp.More(); exp.Next()) {
407 const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
408 if (!Wext.IsNull() && wir.IsSame(Wext)) {
409 if (wir.Orientation() != Wext.Orientation()) {
410 //the exterior wire defines a hole
411 if( CheckThin(wir,myShape.Oriented(TopAbs_FORWARD)) )
413 myOrires = BRepCheck_BadOrientationOfSubshape;
415 BRepCheck::Add(myMap(myShape),myOrires);
421 for (itm.Reset(); itm.More(); itm.Next()) {
422 if (itm.Key().IsSame(wir)) {
426 // No control on More()
427 if (itm.Key().Orientation() == wir.Orientation()) {
428 // the given wire does not define a hole
429 myOrires = BRepCheck_BadOrientationOfSubshape;
431 BRepCheck::Add(myMap(myShape),myOrires);
437 // quit withour error
439 BRepCheck::Add(myMap(myShape),myOrires);
445 //=======================================================================
446 //function : SetUnorientable
448 //=======================================================================
450 void BRepCheck_Face::SetUnorientable()
452 BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
456 //=======================================================================
457 //function : IsUnorientable
459 //=======================================================================
461 Standard_Boolean BRepCheck_Face::IsUnorientable() const
464 return (myOrires != BRepCheck_NoError);
466 for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
469 if (itl.Value() == BRepCheck_UnorientableShape) {
470 return Standard_True;
473 return Standard_False;
476 //=======================================================================
477 //function : GeometricControls
479 //=======================================================================
481 void BRepCheck_Face::GeometricControls(const Standard_Boolean B)
485 myIntdone = Standard_False;
486 myImbdone = Standard_False;
487 myOridone = Standard_False;
494 //=======================================================================
495 //function : GeometricControls
497 //=======================================================================
499 Standard_Boolean BRepCheck_Face::GeometricControls() const
505 //=======================================================================
506 //function : Intersect
508 //=======================================================================
510 static Standard_Boolean Intersect(const TopoDS_Wire& wir1,
511 const TopoDS_Wire& wir2,
512 const TopoDS_Face& F)
514 Standard_Real Inter2dTol = 1.e-10;
515 TopExp_Explorer exp1,exp2;
516 // BRepAdaptor_Curve2d cur1,cur2;
518 //Find common vertices of two wires - non-manifold case
519 TopTools_MapOfShape MapW1;
520 TopTools_SequenceOfShape CommonVertices;
521 for (exp1.Init( wir1, TopAbs_VERTEX ); exp1.More(); exp1.Next())
522 MapW1.Add( exp1.Current() );
523 for (exp2.Init( wir2, TopAbs_VERTEX ); exp2.More(); exp2.Next())
525 TopoDS_Shape V = exp2.Current();
526 if (MapW1.Contains( V ))
527 CommonVertices.Append( V );
530 // MSV 03.04.2002: create pure surface adaptor to avoid UVBounds computation
531 // due to performance problem
532 BRepAdaptor_Surface Surf(F,Standard_False);
534 TColgp_SequenceOfPnt PntSeq;
536 for (i = 1; i <= CommonVertices.Length(); i++)
538 TopoDS_Vertex V = TopoDS::Vertex( CommonVertices(i) );
539 gp_Pnt2d P2d = BRep_Tool::Parameters( V, F );
540 gp_Pnt P = Surf.Value( P2d.X(), P2d.Y() );
544 Geom2dAdaptor_Curve C1,C2;
545 gp_Pnt2d pfirst1,plast1,pfirst2,plast2;
546 Standard_Real first1,last1,first2,last2;
547 Geom2dInt_GInter Inter;
548 IntRes2d_Domain myDomain1,myDomain2;
549 Bnd_Box2d Box1, Box2;
551 for (exp1.Init(wir1,TopAbs_EDGE); exp1.More(); exp1.Next())
553 const TopoDS_Edge& edg1 = TopoDS::Edge(exp1.Current());
554 // cur1.Initialize(edg1,F);
555 C1.Load( BRep_Tool::CurveOnSurface(edg1,F,first1,last1) );
556 // To avoid exeption in Segment if C1 is BSpline - IFV
557 if(C1.FirstParameter() > first1) first1 = C1.FirstParameter();
558 if(C1.LastParameter() < last1 ) last1 = C1.LastParameter();
560 BRep_Tool::UVPoints(edg1,F,pfirst1,plast1);
561 myDomain1.SetValues( pfirst1, first1, Inter2dTol, plast1, last1, Inter2dTol );
563 BndLib_Add2dCurve::Add( C1, first1, last1, 0., Box1 );
565 for (exp2.Init(wir2,TopAbs_EDGE); exp2.More(); exp2.Next())
567 const TopoDS_Edge& edg2 = TopoDS::Edge(exp2.Current());
568 if (!edg1.IsSame(edg2))
570 //cur2.Initialize(edg2,F);
571 C2.Load( BRep_Tool::CurveOnSurface(edg2,F,first2,last2) );
572 // To avoid exeption in Segment if C2 is BSpline - IFV
573 if(C2.FirstParameter() > first2) first2 = C2.FirstParameter();
574 if(C2.LastParameter() < last2 ) last2 = C2.LastParameter();
577 BndLib_Add2dCurve::Add( C2, first2, last2, 0., Box2 );
578 if (! Box1.IsOut( Box2 ))
580 BRep_Tool::UVPoints(edg2,F,pfirst2,plast2);
581 myDomain2.SetValues( pfirst2, first2, Inter2dTol, plast2, last2, Inter2dTol );
582 Inter.Perform( C1, myDomain1, C2, myDomain2, Inter2dTol, Inter2dTol );
584 return Standard_True;
585 if (Inter.NbSegments() > 0)
587 if (PntSeq.IsEmpty())
588 return Standard_True;
591 Standard_Integer NbCoinc = 0;
592 for (i = 1; i <= Inter.NbSegments(); i++)
594 if (!Inter.Segment(i).HasFirstPoint() || !Inter.Segment(i).HasLastPoint())
595 return Standard_True;
596 gp_Pnt2d FirstP2d = Inter.Segment(i).FirstPoint().Value();
597 gp_Pnt2d LastP2d = Inter.Segment(i).LastPoint().Value();
598 gp_Pnt FirstP = Surf.Value( FirstP2d.X(), FirstP2d.Y() );
599 gp_Pnt LastP = Surf.Value( LastP2d.X(), LastP2d.Y() );
600 for (Standard_Integer j = 1; j <= PntSeq.Length(); j++)
602 Standard_Real tolv = BRep_Tool::Tolerance( TopoDS::Vertex(CommonVertices(j)) );
603 if (FirstP.IsEqual( PntSeq(j), tolv ) || LastP.IsEqual( PntSeq(j), tolv ))
610 if (NbCoinc == Inter.NbSegments())
611 return Standard_False;
612 return Standard_True;
615 if (Inter.NbPoints() > 0)
617 if (PntSeq.IsEmpty())
618 return Standard_True;
621 Standard_Integer NbCoinc = 0;
622 for (i = 1; i <= Inter.NbPoints(); i++)
624 gp_Pnt2d P2d = Inter.Point(i).Value();
625 gp_Pnt P = Surf.Value( P2d.X(), P2d.Y() );
626 for (Standard_Integer j = 1; j <= PntSeq.Length(); j++)
628 Standard_Real tolv = BRep_Tool::Tolerance( TopoDS::Vertex(CommonVertices(j)) );
629 if (P.IsEqual( PntSeq(j), tolv ))
636 if (NbCoinc == Inter.NbPoints())
637 return Standard_False;
638 return Standard_True;
645 return Standard_False;
649 //=======================================================================
650 //function : IsInside
652 //=======================================================================
654 static Standard_Boolean IsInside(const TopoDS_Wire& theWire,
655 const Standard_Boolean WireBienOriente,
656 const BRepTopAdaptor_FClass2d& FClass2d,
657 const TopoDS_Face& theFace)
659 Standard_Real aParameter, aFirst, aLast;
661 TopExp_Explorer anExplorer(theWire, TopAbs_EDGE);
662 for( ; anExplorer.More(); anExplorer.Next() )
664 const TopoDS_Edge& anEdge = TopoDS::Edge( anExplorer.Current() );
665 Handle(Geom2d_Curve) aCurve2D =
666 BRep_Tool::CurveOnSurface( anEdge, theFace, aFirst, aLast );
668 // Selects the parameter of point on the curve
669 if( !Precision::IsNegativeInfinite(aFirst) &&
670 !Precision::IsPositiveInfinite(aLast) )
672 aParameter = (aFirst + aLast) * 0.5;
674 // Edge is skipped if its parametric range is too small
675 if( Abs(aParameter - aFirst) < Precision::PConfusion() )
680 //Edge is skipped if its length is too small
681 Standard_Real aFirst3D, aLast3D;
682 Handle(Geom_Curve) aCurve = BRep_Tool::Curve( anEdge, aFirst3D, aLast3D );
683 if ( aCurve.IsNull() )
689 // Compute start point of edge
690 aCurve->D0( aFirst, aPoints[0] );
691 // Compute middle point of edge
692 aCurve->D0( (aFirst3D+aLast3D)/2., aPoints[1] );
693 if( aPoints[0].Distance(aPoints[1]) < Precision::Confusion() )
700 if( Precision::IsNegativeInfinite(aFirst) &&
701 Precision::IsPositiveInfinite(aLast) )
705 else if( Precision::IsNegativeInfinite(aFirst) )
707 aParameter = aLast - 1.;
711 aParameter = aFirst + 1.;
715 // Find point on curve (edge)
716 gp_Pnt2d aPoint2D(aCurve2D->Value(aParameter));
717 // Compute the topological position of a point relative to face
718 TopAbs_State aState = FClass2d.Perform(aPoint2D, Standard_False);
720 if( WireBienOriente )
722 return aState == TopAbs_OUT;
726 return aState == TopAbs_IN;
729 return Standard_False;
731 Standard_Boolean CheckThin(const TopoDS_Shape& w, const TopoDS_Shape& f)
733 TopoDS_Face aF = TopoDS::Face(f);
734 TopoDS_Wire aW = TopoDS::Wire(w);
736 Standard_Integer nbE = 0;
737 TopTools_ListOfShape lE;
738 TopExp_Explorer exp(aW,TopAbs_EDGE);
739 for(; exp.More(); exp.Next()) {
740 const TopoDS_Shape& s = exp.Current();
745 if( nbE != 2 ) return Standard_False;
746 TopoDS_Edge e1 = TopoDS::Edge(lE.First());
747 TopoDS_Edge e2 = TopoDS::Edge(lE.Last());
749 TopoDS_Vertex v1, v2, v3, v4;
750 TopExp::Vertices(e1,v1,v2);
751 TopExp::Vertices(e2,v3,v4);
753 if( v1.IsNull() || v2.IsNull() ||
754 v3.IsNull() || v4.IsNull() ) return Standard_False;
756 if( v1.IsSame(v2) || v3.IsSame(v4) )
757 return Standard_False;
759 Standard_Boolean sF = Standard_False, sL = Standard_False;
760 if( v1.IsSame(v3) || v1.IsSame(v4) ) sF = Standard_True;
761 if( v2.IsSame(v3) || v2.IsSame(v4) ) sL = Standard_True;
763 if( !sF || !sL ) return Standard_False;
765 TopAbs_Orientation e1or = e1.Orientation();
766 TopAbs_Orientation e2or = e2.Orientation();
768 Standard_Real f1 = 0., l1 = 0., f2 = 0., l2 = 0.;
769 Handle(Geom2d_Curve) pc1 = BRep_Tool::CurveOnSurface(e1,aF,f1,l1);
770 Handle(Geom2d_Curve) pc2 = BRep_Tool::CurveOnSurface(e2,aF,f2,l2);
772 if( pc1.IsNull() || pc2.IsNull() ) return Standard_False;
774 Standard_Real d1 = Abs(l1-f1)/100.;
775 Standard_Real d2 = Abs(l2-f2)/100.;
776 Standard_Real m1 = (l1+f1)*0.5;
777 Standard_Real m2 = (l2+f2)*0.5;
779 gp_Pnt2d p1f(pc1->Value(m1-d1));
780 gp_Pnt2d p1l(pc1->Value(m1+d1));
781 gp_Pnt2d p2f(pc2->Value(m2-d2));
782 gp_Pnt2d p2l(pc2->Value(m2+d2));
784 gp_Vec2d vc1(p1f,p1l);
785 gp_Vec2d vc2(p2f,p2l);
787 if( (vc1*vc2) >= 0. && e1or == e2or ) return Standard_False;
789 return Standard_True;