0024428: Implementation of LGPL license
[occt.git] / src / BRepCheck / BRepCheck_Face.cxx
1 // Created on: 1995-12-15
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and / or modify it
9 // under the terms of the GNU Lesser General Public 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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <BRepCheck_Face.ixx>
18
19 #include <BRepCheck_ListOfStatus.hxx>
20 #include <BRepCheck_ListIteratorOfListOfStatus.hxx>
21
22 #include <BRep_TFace.hxx>
23 #include <BRep_Builder.hxx>
24 #include <BRep_Tool.hxx>
25
26 #include <TopExp.hxx>
27 #include <TopExp_Explorer.hxx>
28
29 #include <TopTools_ListOfShape.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx>
31 #include <TopTools_DataMapOfShapeListOfShape.hxx>
32 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
33
34 //#include <BRepAdaptor_Curve2d.hxx>
35 #include <BRepClass_FaceClassifier.hxx>
36 //#include <Geom2dInt_GInter.hxx>
37 #include <Geom2d_Curve.hxx>
38 #include <Geom_Curve.hxx>
39 #include <GProp_GProps.hxx>
40
41 #include <IntRes2d_Domain.hxx>
42 #include <Geom2dInt_GInter.hxx>
43 #include <Geom2dAdaptor_Curve.hxx>
44 #include <gp_Pnt2d.hxx>
45
46
47
48 #include <BRepCheck.hxx>
49 #include <Precision.hxx>
50 #include <TopoDS.hxx>
51 #include <TopoDS_Wire.hxx>
52
53 #include <BRepTopAdaptor_FClass2d.hxx>
54 #include <TopAbs_State.hxx>
55
56 #include <Bnd_Box2d.hxx>
57 #include <BndLib_Add2dCurve.hxx>
58 #include <TopTools_MapOfShape.hxx>
59 #include <TopTools_SequenceOfShape.hxx>
60 #include <TColgp_SequenceOfPnt.hxx>
61 #include <TopoDS_Vertex.hxx>
62 #include <IntRes2d_IntersectionPoint.hxx>
63 #include <IntRes2d_IntersectionSegment.hxx>
64 #include <BRepAdaptor_HSurface.hxx>
65
66
67 static Standard_Boolean Intersect(const TopoDS_Wire&,
68                                   const TopoDS_Wire&,
69                                   const TopoDS_Face&);
70                                   
71
72 static Standard_Boolean IsInside(const TopoDS_Wire& wir,
73                                  const Standard_Boolean Inside,
74                                  const BRepTopAdaptor_FClass2d& FClass2d,
75                                  const TopoDS_Face& F);
76
77 static Standard_Boolean CheckThin(const TopoDS_Shape& w,
78                                   const TopoDS_Shape& f);
79
80 //=======================================================================
81 //function : BRepCheck_Face
82 //purpose  : 
83 //=======================================================================
84
85 BRepCheck_Face::BRepCheck_Face (const TopoDS_Face& F)
86 {
87   Init(F);
88   myIntdone = Standard_False;
89   myImbdone = Standard_False;
90   myOridone = Standard_False;
91   myGctrl   = Standard_True;
92 }
93
94 //=======================================================================
95 //function : Minimum
96 //purpose  : 
97 //=======================================================================
98
99 void BRepCheck_Face::Minimum()
100 {
101   if (!myMin) {
102     BRepCheck_ListOfStatus thelist;
103     myMap.Bind(myShape, thelist);
104     BRepCheck_ListOfStatus& lst = myMap(myShape);
105
106     Handle(BRep_TFace)& TF = *((Handle(BRep_TFace)*) &myShape.TShape());
107     if (TF->Surface().IsNull()) {
108       BRepCheck::Add(lst,BRepCheck_NoSurface);
109     }
110     else {
111       // Flag natural restriction???
112     }
113     if (lst.IsEmpty()) {
114       lst.Append(BRepCheck_NoError);
115     }
116     myMin = Standard_True;
117   }
118 }
119
120
121 //=======================================================================
122 //function : InContext
123 //purpose  : 
124 //=======================================================================
125
126 void BRepCheck_Face::InContext(const TopoDS_Shape& S)
127 {
128   if (myMap.IsBound(S)) {
129     return;
130   }
131   BRepCheck_ListOfStatus thelist;
132   myMap.Bind(S, thelist);
133
134   BRepCheck_ListOfStatus& lst = myMap(S);
135   
136   TopExp_Explorer exp(S,TopAbs_FACE);
137   for (; exp.More(); exp.Next()) {
138     if (exp.Current().IsSame(myShape)) {
139       break;
140     }
141   }
142   if (!exp.More()) {
143     BRepCheck::Add(lst,BRepCheck_SubshapeNotInShape);
144     return;
145   }
146
147   if (lst.IsEmpty()) {
148     lst.Append(BRepCheck_NoError);
149   }
150 }
151
152
153 //=======================================================================
154 //function : Blind
155 //purpose  : 
156 //=======================================================================
157
158 void BRepCheck_Face::Blind()
159 {
160   if (!myBlind) {
161     // nothing more than in the minimum
162     myBlind = Standard_True;
163   }
164 }
165
166
167 //=======================================================================
168 //function : IntersectWires
169 //purpose  : 
170 //=======================================================================
171
172 BRepCheck_Status BRepCheck_Face::IntersectWires(const Standard_Boolean Update)
173 {
174   if (myIntdone) {
175     if (Update) {
176       BRepCheck::Add(myMap(myShape),myIntres);
177     }
178     return myIntres;
179   }
180
181   myIntdone = Standard_True;
182   myIntres = BRepCheck_NoError;
183   // This method has to be called by an analyzer. It is assumed that
184   // each edge has a correct 2d representation on the face.
185
186   TopExp_Explorer exp1,exp2;
187
188   // the wires are mapped
189   exp1.Init(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
190   TopTools_ListOfShape theListOfShape;
191   while (exp1.More()) {
192     if (!myMapImb.IsBound(exp1.Current())) {
193       myMapImb.Bind(exp1.Current(), theListOfShape);
194     }
195     else { // the same wire is met twice...
196       myIntres = BRepCheck_RedundantWire;
197       if (Update) {
198         BRepCheck::Add(myMap(myShape),myIntres);
199       }
200       return myIntres;
201     }
202     exp1.Next();
203   }
204   
205   Standard_Integer Nbwire, Index,Indexbis;
206   Nbwire = myMapImb.Extent();
207
208   Index = 1;
209   while (Index < Nbwire) {
210     for (exp1.Init(myShape,TopAbs_WIRE),Indexbis = 0;
211          exp1.More();exp1.Next()) {
212       Indexbis++;
213       if (Indexbis == Index) {
214         break;
215       }
216     }
217     TopoDS_Wire wir1 = TopoDS::Wire(exp1.Current());
218     exp1.Next();
219     for (; exp1.More(); exp1.Next()) {
220       const TopoDS_Wire& wir2 = TopoDS::Wire(exp1.Current());
221       if (Intersect(wir1,wir2,TopoDS::Face(myShape))) {
222         myIntres = BRepCheck_IntersectingWires;
223         if (Update) {
224           BRepCheck::Add(myMap(myShape),myIntres);
225         }
226         return myIntres;
227       }
228     }
229     Index++;
230   }
231   if (Update) {
232     BRepCheck::Add(myMap(myShape),myIntres);
233   }
234   return myIntres;
235 }
236
237
238 //=======================================================================
239 //function : ClassifyWires
240 //purpose  : 
241 //=======================================================================
242
243 BRepCheck_Status BRepCheck_Face::ClassifyWires(const Standard_Boolean Update)
244 {
245   // It is assumed that each wire does not intersect any other one.
246   if (myImbdone) {
247     if (Update) {
248       BRepCheck::Add(myMap(myShape),myImbres);
249     }
250     return myImbres;
251   }
252
253   myImbdone = Standard_True;
254   myImbres = IntersectWires();
255   if (myImbres != BRepCheck_NoError) {
256     if (Update) {
257       BRepCheck::Add(myMap(myShape),myImbres);
258     }
259     return myImbres;
260   }
261
262   Standard_Integer Nbwire = myMapImb.Extent();
263   if (Nbwire < 1) {
264     if (Update) {
265       BRepCheck::Add(myMap(myShape),myImbres);
266     }
267     return myImbres;
268   }
269
270   BRep_Builder B;
271   TopExp_Explorer exp1,exp2;
272   TopTools_ListOfShape theListOfShape;
273   for (exp1.Init(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
274        exp1.More();exp1.Next()) {
275
276     const TopoDS_Wire& wir1 = TopoDS::Wire(exp1.Current());
277     TopoDS_Shape aLocalShape = myShape.EmptyCopied();
278     TopoDS_Face newFace = TopoDS::Face(aLocalShape);
279 //    TopoDS_Face newFace = TopoDS::Face(myShape.EmptyCopied());
280
281     newFace.Orientation(TopAbs_FORWARD);
282     B.Add(newFace,wir1);
283
284     BRepTopAdaptor_FClass2d FClass2d(newFace,Precision::PConfusion());
285     Standard_Boolean WireBienOriente = Standard_False;
286     if(FClass2d.PerformInfinitePoint() != TopAbs_OUT) { 
287       WireBienOriente=Standard_True;
288       // the given wire defines a hole
289       myMapImb.UnBind(wir1);
290       myMapImb.Bind(wir1.Reversed(), theListOfShape);
291     }
292
293     for (exp2.Init(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
294          exp2.More();exp2.Next()) {
295       const TopoDS_Wire& wir2 = TopoDS::Wire(exp2.Current());
296       if (!wir2.IsSame(wir1)) {
297         
298         if (IsInside(wir2,WireBienOriente,FClass2d,newFace)) { 
299           myMapImb(wir1).Append(wir2);
300         }
301       }
302     }
303   }
304   // It is required to have 1 wire that contains all others, and the others should not  
305   // contain anything (case solid ended) or
306   // the wires do not contain anything : in this case the wires should be
307   // holes in an infinite face.
308   TopoDS_Wire Wext;
309   for (TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itm(myMapImb);
310        itm.More();
311        itm.Next()) {
312     if (!itm.Value().IsEmpty()) {
313       if (Wext.IsNull()) {
314         Wext = TopoDS::Wire(itm.Key());
315       }
316       else {
317         myImbres = BRepCheck_InvalidImbricationOfWires;
318         if (Update) {
319           BRepCheck::Add(myMap(myShape),myImbres);
320         }
321         return myImbres;
322       }
323     }
324   }
325
326   if (!Wext.IsNull()) {
327     // verifies that the list contains nbwire-1 elements
328     if (myMapImb(Wext).Extent() != Nbwire-1) {
329       myImbres = BRepCheck_InvalidImbricationOfWires;
330       if (Update) {
331         BRepCheck::Add(myMap(myShape),myImbres);
332       }
333       return myImbres;
334     }
335   }
336   // quit without errors
337   if (Update) {
338     BRepCheck::Add(myMap(myShape),myImbres);
339   }
340   return myImbres;
341   
342 }
343
344
345 //=======================================================================
346 //function : OrientationOfWires
347 //purpose  : 
348 //=======================================================================
349
350 BRepCheck_Status BRepCheck_Face::OrientationOfWires
351    (const Standard_Boolean Update)
352 {
353   // WARNING : it is assumed that the edges of a wire are correctly oriented
354
355
356   Standard_Boolean Infinite = myShape.Infinite();
357
358   if (myOridone) {
359     if (Update) {
360       BRepCheck::Add(myMap(myShape),myOrires);
361     }
362     return myOrires;
363   }
364
365   myOridone = Standard_True;
366   myOrires = ClassifyWires();
367   if (myOrires != BRepCheck_NoError) {
368     if (Update) {
369       BRepCheck::Add(myMap(myShape),myOrires);
370     }
371     return myOrires;
372   }
373
374   Standard_Integer Nbwire = myMapImb.Extent();
375   TopoDS_Wire Wext;
376   TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itm(myMapImb);
377   if (Nbwire == 1) {
378     if (!Infinite) {
379       Wext = TopoDS::Wire(itm.Key());
380     }
381   }
382   else {
383     for (;itm.More();itm.Next()) {
384       if (!itm.Value().IsEmpty()) {
385         Wext = TopoDS::Wire(itm.Key());
386       }
387     }
388   }
389
390   if (Wext.IsNull() && !Infinite) {
391     if (Nbwire>0) myOrires = BRepCheck_InvalidImbricationOfWires;
392     if (Update) {
393       BRepCheck::Add(myMap(myShape),myOrires);
394     }
395     return myOrires;
396   }
397
398   // BRep_Builder B;
399   TopExp_Explorer exp(myShape.Oriented(TopAbs_FORWARD),TopAbs_WIRE);
400   for (; exp.More(); exp.Next()) {
401     const TopoDS_Wire& wir = TopoDS::Wire(exp.Current());
402     if (!Wext.IsNull() && wir.IsSame(Wext)) {
403       if (wir.Orientation() != Wext.Orientation()) {
404         //the exterior wire defines a hole 
405         if( CheckThin(wir,myShape.Oriented(TopAbs_FORWARD)) )
406           return myOrires;
407         myOrires = BRepCheck_BadOrientationOfSubshape;
408         if (Update) {
409           BRepCheck::Add(myMap(myShape),myOrires);
410         }
411         return myOrires;
412       }
413     }
414     else {
415       for (itm.Reset(); itm.More(); itm.Next()) {
416         if (itm.Key().IsSame(wir)) {
417           break;
418         }
419       }
420       // No control on More()
421       if (itm.Key().Orientation() == wir.Orientation()) {
422         // the given wire does not define a hole
423         myOrires = BRepCheck_BadOrientationOfSubshape;
424         if (Update) {
425           BRepCheck::Add(myMap(myShape),myOrires);
426         }
427         return myOrires;
428       }
429     }
430   }
431   // quit withour error
432   if (Update) {
433     BRepCheck::Add(myMap(myShape),myOrires);
434   }
435   return myOrires;
436 }
437
438
439 //=======================================================================
440 //function : SetUnorientable
441 //purpose  : 
442 //=======================================================================
443
444 void BRepCheck_Face::SetUnorientable()
445 {
446   BRepCheck::Add(myMap(myShape),BRepCheck_UnorientableShape);
447 }
448
449
450 //=======================================================================
451 //function : IsUnorientable
452 //purpose  : 
453 //=======================================================================
454
455 Standard_Boolean BRepCheck_Face::IsUnorientable() const
456 {
457   if (myOridone) {
458     return (myOrires != BRepCheck_NoError);
459   }
460   for (BRepCheck_ListIteratorOfListOfStatus itl(myMap(myShape));
461        itl.More();
462        itl.Next()) {
463     if (itl.Value() == BRepCheck_UnorientableShape) {
464       return Standard_True;
465     }
466   }
467   return Standard_False;
468 }
469
470 //=======================================================================
471 //function : GeometricControls
472 //purpose  : 
473 //=======================================================================
474
475 void BRepCheck_Face::GeometricControls(const Standard_Boolean B)
476 {
477   if (myGctrl != B) {
478     if (B) {
479       myIntdone = Standard_False; 
480       myImbdone = Standard_False; 
481       myOridone = Standard_False; 
482     }
483     myGctrl = B;
484   }
485 }
486
487
488 //=======================================================================
489 //function : GeometricControls
490 //purpose  : 
491 //=======================================================================
492
493 Standard_Boolean BRepCheck_Face::GeometricControls() const
494 {
495   return myGctrl;
496 }
497
498
499 //=======================================================================
500 //function : Intersect
501 //purpose  : 
502 //=======================================================================
503
504 static Standard_Boolean Intersect(const TopoDS_Wire& wir1,
505                                   const TopoDS_Wire& wir2,
506                                   const TopoDS_Face& F)
507 {
508   Standard_Real Inter2dTol = 1.e-10;
509   TopExp_Explorer exp1,exp2;
510 //  BRepAdaptor_Curve2d cur1,cur2;
511
512   //Find common vertices of two wires - non-manifold case
513   TopTools_MapOfShape MapW1;
514   TopTools_SequenceOfShape CommonVertices;
515   for (exp1.Init( wir1, TopAbs_VERTEX ); exp1.More(); exp1.Next())
516     MapW1.Add( exp1.Current() );
517   for (exp2.Init( wir2, TopAbs_VERTEX ); exp2.More(); exp2.Next())
518     {
519       TopoDS_Shape V = exp2.Current();
520       if (MapW1.Contains( V ))
521         CommonVertices.Append( V );
522     }
523
524   // MSV 03.04.2002: create pure surface adaptor to avoid UVBounds computation
525   //                 due to performance problem
526   BRepAdaptor_Surface Surf(F,Standard_False);
527
528   TColgp_SequenceOfPnt PntSeq;
529   Standard_Integer i;
530   for (i = 1; i <= CommonVertices.Length(); i++)
531     {
532       TopoDS_Vertex V = TopoDS::Vertex( CommonVertices(i) );
533       gp_Pnt2d P2d = BRep_Tool::Parameters( V, F );
534       gp_Pnt P = Surf.Value( P2d.X(), P2d.Y() );
535       PntSeq.Append( P );
536     }
537
538   Geom2dAdaptor_Curve   C1,C2;
539   gp_Pnt2d              pfirst1,plast1,pfirst2,plast2;
540   Standard_Real         first1,last1,first2,last2;
541   Geom2dInt_GInter      Inter;
542   IntRes2d_Domain myDomain1,myDomain2;
543   Bnd_Box2d Box1, Box2;
544
545   for (exp1.Init(wir1,TopAbs_EDGE); exp1.More(); exp1.Next())
546     {
547       const TopoDS_Edge& edg1 = TopoDS::Edge(exp1.Current());
548       //    cur1.Initialize(edg1,F);
549       C1.Load( BRep_Tool::CurveOnSurface(edg1,F,first1,last1) );
550       // To avoid exeption in Segment if C1 is BSpline - IFV
551       if(C1.FirstParameter() > first1) first1 = C1.FirstParameter();
552       if(C1.LastParameter()  < last1 ) last1  = C1.LastParameter();
553
554       BRep_Tool::UVPoints(edg1,F,pfirst1,plast1);
555       myDomain1.SetValues( pfirst1, first1, Inter2dTol, plast1, last1, Inter2dTol );
556       Box1.SetVoid();
557       BndLib_Add2dCurve::Add( C1, first1, last1, 0., Box1 );
558       
559       for (exp2.Init(wir2,TopAbs_EDGE); exp2.More(); exp2.Next())
560         {
561           const TopoDS_Edge& edg2 = TopoDS::Edge(exp2.Current());
562           if (!edg1.IsSame(edg2))
563             {
564               //cur2.Initialize(edg2,F);
565               C2.Load( BRep_Tool::CurveOnSurface(edg2,F,first2,last2) );
566               // To avoid exeption in Segment if C2 is BSpline - IFV
567               if(C2.FirstParameter() > first2) first2 = C2.FirstParameter();
568               if(C2.LastParameter()  < last2 ) last2  = C2.LastParameter();
569
570               Box2.SetVoid();
571               BndLib_Add2dCurve::Add( C2, first2, last2, 0., Box2 );
572               if (! Box1.IsOut( Box2 ))
573                 {
574                   BRep_Tool::UVPoints(edg2,F,pfirst2,plast2);
575                   myDomain2.SetValues( pfirst2, first2, Inter2dTol, plast2, last2, Inter2dTol );
576                   Inter.Perform( C1, myDomain1, C2, myDomain2, Inter2dTol, Inter2dTol );
577                   if (!Inter.IsDone())
578                     return Standard_True;
579                   if (Inter.NbSegments() > 0)
580                     {
581                       if (PntSeq.IsEmpty())
582                         return Standard_True;
583                       else
584                         {
585                           Standard_Integer NbCoinc = 0;
586                           for (i = 1; i <= Inter.NbSegments(); i++)
587                             {
588                               if (!Inter.Segment(i).HasFirstPoint() || !Inter.Segment(i).HasLastPoint())
589                                 return Standard_True;
590                               gp_Pnt2d FirstP2d = Inter.Segment(i).FirstPoint().Value();
591                               gp_Pnt2d LastP2d = Inter.Segment(i).LastPoint().Value();
592                               gp_Pnt FirstP = Surf.Value( FirstP2d.X(), FirstP2d.Y() );
593                               gp_Pnt LastP = Surf.Value( LastP2d.X(), LastP2d.Y() );
594                               for (Standard_Integer j = 1; j <= PntSeq.Length(); j++)
595                                 {
596                                   Standard_Real tolv = BRep_Tool::Tolerance( TopoDS::Vertex(CommonVertices(j)) );
597                                   if (FirstP.IsEqual( PntSeq(j), tolv ) || LastP.IsEqual( PntSeq(j), tolv ))
598                                     {
599                                       NbCoinc++;
600                                       break;
601                                     }
602                                 }
603                             }
604                           if (NbCoinc == Inter.NbSegments())
605                             return Standard_False;
606                           return Standard_True;
607                         }
608                     }
609                   if (Inter.NbPoints() > 0)
610                     {
611                       if (PntSeq.IsEmpty())
612                         return Standard_True;
613                       else
614                         {
615                           Standard_Integer NbCoinc = 0;
616                           for (i = 1; i <= Inter.NbPoints(); i++)
617                             {
618                               gp_Pnt2d P2d = Inter.Point(i).Value();
619                               gp_Pnt P = Surf.Value( P2d.X(), P2d.Y() );
620                               for (Standard_Integer j = 1; j <= PntSeq.Length(); j++)
621                                 {
622                                   Standard_Real tolv = BRep_Tool::Tolerance( TopoDS::Vertex(CommonVertices(j)) );
623                                   if (P.IsEqual( PntSeq(j), tolv ))
624                                     {
625                                       NbCoinc++;
626                                       break;
627                                     }
628                                 }
629                             }
630                           if (NbCoinc == Inter.NbPoints())
631                             return Standard_False;
632                           return Standard_True;
633                         }
634                     }
635                 }
636             }
637         }
638     }
639   return Standard_False;
640 }
641
642
643 //=======================================================================
644 //function : IsInside
645 //purpose  : 
646 //=======================================================================
647
648 static Standard_Boolean IsInside(const TopoDS_Wire& theWire,
649                                  const Standard_Boolean WireBienOriente,
650                                  const BRepTopAdaptor_FClass2d& FClass2d,
651                                  const TopoDS_Face& theFace)
652 {
653   Standard_Real aParameter, aFirst, aLast;
654
655   TopExp_Explorer anExplorer(theWire, TopAbs_EDGE);
656   for( ; anExplorer.More(); anExplorer.Next() )
657   {
658     const TopoDS_Edge& anEdge = TopoDS::Edge( anExplorer.Current() );
659     Handle(Geom2d_Curve) aCurve2D =
660       BRep_Tool::CurveOnSurface( anEdge, theFace, aFirst, aLast );
661
662     // Selects the parameter of point on the curve
663     if( !Precision::IsNegativeInfinite(aFirst) &&
664         !Precision::IsPositiveInfinite(aLast) )
665     {
666       aParameter = (aFirst + aLast) * 0.5;
667
668       // Edge is skipped if its parametric range is too small
669       if( Abs(aParameter - aFirst) < Precision::PConfusion() )
670       {
671         continue;
672       }
673
674           //Edge is skipped if its length is too small
675           Standard_Real aFirst3D, aLast3D;
676           Handle(Geom_Curve) aCurve = BRep_Tool::Curve( anEdge, aFirst3D, aLast3D );      
677       if ( aCurve.IsNull() )
678       {
679         continue;
680       }
681
682       gp_Pnt aPoints[2];
683       // Compute start point of edge
684       aCurve->D0( aFirst, aPoints[0] );
685       // Compute middle point of edge 
686       aCurve->D0( (aFirst3D+aLast3D)/2., aPoints[1] );
687       if( aPoints[0].Distance(aPoints[1]) < Precision::Confusion() )
688       {
689         continue;
690       }
691     }
692     else
693     {
694       if( Precision::IsNegativeInfinite(aFirst) &&
695           Precision::IsPositiveInfinite(aLast) )
696       {
697         aParameter = 0.;
698       }
699       else if( Precision::IsNegativeInfinite(aFirst) )
700       {
701         aParameter = aLast - 1.;
702       }
703       else
704       {
705         aParameter = aFirst + 1.;
706       }
707     }
708
709     // Find point on curve (edge)
710     gp_Pnt2d aPoint2D(aCurve2D->Value(aParameter));
711     // Compute the topological position of a point relative to face
712     TopAbs_State aState = FClass2d.Perform(aPoint2D, Standard_False);
713
714     if( WireBienOriente )
715     {
716       return aState == TopAbs_OUT;
717     }
718     else
719     {
720       return aState == TopAbs_IN;
721     }
722   }
723   return Standard_False;
724 }
725 Standard_Boolean CheckThin(const TopoDS_Shape& w, const TopoDS_Shape& f)
726 {
727   TopoDS_Face aF = TopoDS::Face(f);
728   TopoDS_Wire aW = TopoDS::Wire(w);
729
730   Standard_Integer nbE = 0;
731   TopTools_ListOfShape lE;
732   TopExp_Explorer exp(aW,TopAbs_EDGE);
733   for(; exp.More(); exp.Next()) {
734     const TopoDS_Shape& s = exp.Current();
735     lE.Append(s);
736     nbE++;
737   }
738
739   if( nbE != 2 ) return Standard_False;
740   TopoDS_Edge e1 = TopoDS::Edge(lE.First());
741   TopoDS_Edge e2 = TopoDS::Edge(lE.Last());
742
743   TopoDS_Vertex v1, v2, v3, v4;
744   TopExp::Vertices(e1,v1,v2);
745   TopExp::Vertices(e2,v3,v4);
746
747   if( v1.IsNull() || v2.IsNull() || 
748       v3.IsNull() || v4.IsNull() ) return Standard_False;
749
750   if( v1.IsSame(v2) || v3.IsSame(v4) )
751     return Standard_False;
752
753   Standard_Boolean sF = Standard_False, sL = Standard_False;
754   if( v1.IsSame(v3) || v1.IsSame(v4) ) sF = Standard_True;
755   if( v2.IsSame(v3) || v2.IsSame(v4) ) sL = Standard_True;
756
757   if( !sF || !sL ) return Standard_False;
758
759   TopAbs_Orientation e1or = e1.Orientation();
760   TopAbs_Orientation e2or = e2.Orientation();
761  
762   Standard_Real f1 = 0., l1 = 0., f2 = 0., l2 = 0.;
763   Handle(Geom2d_Curve) pc1 = BRep_Tool::CurveOnSurface(e1,aF,f1,l1);
764   Handle(Geom2d_Curve) pc2 = BRep_Tool::CurveOnSurface(e2,aF,f2,l2);
765   
766   if( pc1.IsNull() || pc2.IsNull() ) return Standard_False;
767
768   Standard_Real d1 = Abs(l1-f1)/100.;
769   Standard_Real d2 = Abs(l2-f2)/100.;
770   Standard_Real m1 = (l1+f1)*0.5;
771   Standard_Real m2 = (l2+f2)*0.5;
772
773   gp_Pnt2d p1f(pc1->Value(m1-d1));
774   gp_Pnt2d p1l(pc1->Value(m1+d1));
775   gp_Pnt2d p2f(pc2->Value(m2-d2));
776   gp_Pnt2d p2l(pc2->Value(m2+d2));
777
778   gp_Vec2d vc1(p1f,p1l);
779   gp_Vec2d vc2(p2f,p2l);
780   
781   if( (vc1*vc2) >= 0. && e1or == e2or ) return Standard_False;
782
783   return Standard_True;
784 }