675bbd99c97f11b241ef6bda7b4332bd5cc25dee
[occt.git] / src / BRepClass3d / BRepClass3d_SClassifier.cxx
1 // Created on: 1996-07-15
2 // Created by: Laurent BUCHARD
3 // Copyright (c) 1996-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 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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 //  Modified by skv - Thu Sep  4 11:22:05 2003 OCC578
18
19 #include <BRep_Tool.hxx>
20 #include <BRepClass3d_Intersector3d.hxx>
21 #include <BRepClass3d_SClassifier.hxx>
22 #include <BRepClass3d_SolidExplorer.hxx>
23 #include <BRepTopAdaptor_FClass2d.hxx>
24 #include <ElCLib.hxx>
25 #include <Geom_Surface.hxx>
26 #include <gp_Lin.hxx>
27 #include <gp_Pnt.hxx>
28 #include <gp_Vec.hxx>
29 #include <IntCurvesFace_Intersector.hxx>
30 #include <math_BullardGenerator.hxx>
31 #include <Standard_DomainError.hxx>
32 #include <TopoDS.hxx>
33 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
34 #include <TopTools_MapOfShape.hxx>
35 #include <TopExp.hxx>
36 #include <BRepAdaptor_Surface.hxx>
37 #include <Extrema_ExtPS.hxx>
38
39 #include <vector>
40
41 // modified by NIZHNY-MKK  Mon Jun 21 15:13:40 2004
42 static
43   Standard_Boolean FaceNormal (const TopoDS_Face& aF,
44                                const Standard_Real U,
45                                const Standard_Real V,
46                                gp_Dir& aDN);
47
48 static 
49   Standard_Real GetAddToParam(const gp_Lin& L,const Standard_Real P,const Bnd_Box& B);
50
51 //gets transition of line <L> passing through/near the edge <e> of faces <f1>, <f2>. <param> is
52 // a parameter on the edge where the minimum distance between <l> and <e> was found
53 static Standard_Integer GetTransi(const TopoDS_Face& f1, const TopoDS_Face& f2, const TopoDS_Edge e,
54                      Standard_Real param, const gp_Lin& L, IntCurveSurface_TransitionOnCurve& trans);
55
56 static Standard_Boolean GetNormalOnFaceBound(const TopoDS_Edge& E, const TopoDS_Face& F, Standard_Real param, gp_Dir& OutDir);
57
58 static void Trans(Standard_Real parmin, IntCurveSurface_TransitionOnCurve& tran, int& state);
59
60 //=======================================================================
61 //function : BRepClass3d_SClassifier
62 //purpose  : 
63 //=======================================================================
64 BRepClass3d_SClassifier::BRepClass3d_SClassifier()
65 : myState(0)
66
67 }
68
69
70 //=======================================================================
71 //function : BRepClass3d_SClassifier
72 //purpose  : 
73 //=======================================================================
74 BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S,
75                                                  const gp_Pnt&  P,
76                                                  const Standard_Real Tol) { 
77   if(S.Reject(P)) { 
78     myState=3; //-- in ds solid case without face 
79   }
80   else { 
81     Perform(S,P,Tol);
82   }
83 }
84
85
86 //=======================================================================
87 //function : PerformInfinitePoint
88 //purpose  : 
89 //=======================================================================
90 void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE,
91                                                    const Standard_Real /*Tol*/) {
92
93   //Take a normal to the first extracted face in its random inner point
94   //and intersect this reversed normal with the faces of the solid.
95   //If the min.par.-intersection point is
96   // a) inner point of a face
97   // b) transition is not TANGENT
98   //    (the line does not touch the face but pierces it)
99   //then set <myState> to IN or OUT according to transition
100   //else take the next random point inside the min.par.-intersected face
101   //and continue
102   
103   if(aSE.Reject(gp_Pnt(0,0,0))) { 
104     myState=3; //-- in ds solid case without face 
105     return;
106   }
107   //
108   //------------------------------------------------------------
109   // 1
110   Standard_Boolean bFound;
111   Standard_Real aParam, aU = 0., aV = 0.;
112   gp_Pnt aPoint;
113   gp_Dir aDN;
114
115   math_BullardGenerator aRandomGenerator;
116   myFace.Nullify();
117   myState=2;
118
119   // Collect faces in sequence to iterate
120   std::vector<TopoDS_Face> aFaces;
121   for (aSE.InitShell(); aSE.MoreShell(); aSE.NextShell())
122   {
123     for (aSE.InitFace(); aSE.MoreFace(); aSE.NextFace())
124     {
125       aFaces.push_back (aSE.CurrentFace());
126     }
127   }
128
129   // iteratively try up to 10 probing points from each face
130   const Standard_Integer NB_MAX_POINTS_PER_FACE = 10;
131   for (Standard_Integer itry = 0; itry < NB_MAX_POINTS_PER_FACE; itry++)
132   {
133     for (std::vector<TopoDS_Face>::iterator iFace = aFaces.begin(); iFace != aFaces.end(); ++iFace)
134     {
135       TopoDS_Face aF = *iFace;
136
137       TopAbs_State aState = TopAbs_OUT;
138       IntCurveSurface_TransitionOnCurve aTransition = IntCurveSurface_Tangent;
139
140       aParam = 0.1 + 0.8 * aRandomGenerator.NextReal(); // random number in range [0.1, 0.9]
141       bFound = aSE.FindAPointInTheFace(aF, aPoint, aU, aV, aParam);
142       if (!bFound || !FaceNormal(aF, aU, aV, aDN))
143         continue;
144
145       gp_Lin aLin(aPoint, -aDN);
146       Standard_Real parmin = RealLast();
147       for (aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { 
148         if (aSE.RejectShell(aLin) == Standard_False) { 
149           for (aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
150             if (aSE.RejectFace(aLin) == Standard_False) { 
151               TopoDS_Shape aLocalShape = aSE.CurrentFace();
152               TopoDS_Face CurFace = TopoDS::Face(aLocalShape);
153               IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(CurFace);
154               Intersector3d.Perform(aLin,-RealLast(),parmin); 
155
156               if(Intersector3d.IsDone()) {
157                 if(Intersector3d.NbPnt()) { 
158                   Standard_Integer imin = 1;
159                   for (Standard_Integer i = 2; i <= Intersector3d.NbPnt(); i++)
160                     if (Intersector3d.WParameter(i) < Intersector3d.WParameter(imin))
161                       imin = i;
162                   parmin = Intersector3d.WParameter(imin);
163                   aState = Intersector3d.State(imin);
164                   aTransition = Intersector3d.Transition(imin);
165                 }
166               }
167             }
168           }
169         }
170         else
171           myState = 1;
172       } //end of loop on the whole solid
173         
174       if (aState == TopAbs_IN)
175       {
176         if (aTransition == IntCurveSurface_Out) { 
177           //-- The line is going from inside the solid to outside 
178           //-- the solid.
179           myState = 3; //-- IN --
180           return;
181         }
182         else if (aTransition == IntCurveSurface_In) { 
183           myState = 4; //-- OUT --
184           return;
185         }
186       }
187     } // iteration by faces
188   } // iteration by points
189 }
190
191 //=======================================================================
192 //function : Perform
193 //purpose  : 
194 //=======================================================================
195 void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
196                                       const gp_Pnt&  P,
197                                       const Standard_Real Tol)
198
199   if(SolidExplorer.Reject(P))
200   {
201     // Solid without faces => the whole space. Always in.
202     myState = 3; // IN
203     return;
204   }
205
206   const BRepClass3d_BndBoxTree & aTree = SolidExplorer.GetTree();
207   const TopTools_IndexedMapOfShape & aMapEV = SolidExplorer.GetMapEV();
208
209   // Vertices/Edges vs Point.
210   BRepClass3d_BndBoxTreeSelectorPoint aSelectorPoint(aMapEV);
211   aSelectorPoint.SetCurrentPoint(P);
212
213   Standard_Integer SelsVE = 0;
214   SelsVE = aTree.Select(aSelectorPoint); 
215
216   if (SelsVE > 0)
217   {
218     // The point P lays inside the tolerance area of vertices/edges => return ON state.
219     myState = 2; // ON.
220     return;
221   }
222
223   TopTools_IndexedDataMapOfShapeListOfShape mapEF;
224   TopExp::MapShapesAndAncestors(SolidExplorer.GetShape(), TopAbs_EDGE, TopAbs_FACE, mapEF);
225   
226   BRepClass3d_BndBoxTreeSelectorLine aSelectorLine(aMapEV);
227
228   myFace.Nullify();
229   myState = 0;
230
231   gp_Lin L;
232   Standard_Real Par;
233
234   // We compute the intersection between the line built in the Solid Explorer and the shape.
235   //-- --------------------------------------------------------------------------------
236   // Calculate intersection with the face closest to the direction of bounding boxes 
237   // by priority so that to have the smallest possible parmin.
238   // Optimization to produce as much as possible rejections with other faces.
239   Standard_Integer iFlag;
240
241   // If found line passes through a bound of any face, it means that the line
242   // is not found properly and it is necessary to repeat whole procedure.
243   // That's why the main loop while is added.
244   Standard_Boolean isFaultyLine = Standard_True;
245   Standard_Integer anIndFace    = 0;
246   Standard_Real    parmin = 0.0;
247   while (isFaultyLine)
248   {
249     if (anIndFace == 0)
250       iFlag = SolidExplorer.Segment(P,L,Par);
251     else
252       iFlag = SolidExplorer.OtherSegment(P,L,Par);
253
254     Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex();
255
256     if (aCurInd > anIndFace)
257       anIndFace = aCurInd;
258     else
259     {
260       myState = 1; // Faulty.
261       return;
262     }
263
264     if (iFlag==1)
265     {
266       // IsOnFace iFlag==1 i.e face is Infinite
267       myState = 2; // ON.
268       return;
269     }
270     if (iFlag == 2) 
271     {
272       myState = 4; // OUT.
273       return;
274     }
275
276     // Check if the point is ON surface but OUT of the face.
277     // Just skip this face because it is bad for classification.
278     if (iFlag == 3)
279       continue;
280
281     isFaultyLine = Standard_False;
282     parmin = RealLast();
283
284     Standard_Real NearFaultPar = RealLast(); // Parameter on line.
285     aSelectorLine.ClearResults();
286     aSelectorLine.SetCurrentLine(L, Par);
287     Standard_Integer SelsEVL = 0;
288     SelsEVL = aTree.Select(aSelectorLine); //SelsEE > 0 => Line/Edges & Line/Vertex intersection
289      
290     if (SelsEVL > 0 )
291     {    
292       // Line and edges / vertices interference.
293       Standard_Integer VLInterNb = aSelectorLine.GetNbVertParam();
294       TopoDS_Vertex NearIntVert;
295       TopTools_MapOfShape LVInts;
296       for (Standard_Integer i = 1; i <= VLInterNb; i++)
297       {
298         // Line and vertex.
299         Standard_Real LP = 0;
300         TopoDS_Vertex V;
301         aSelectorLine.GetVertParam(i, V, LP);
302
303         LVInts.Add(V);
304         if (Abs(LP) < Abs(NearFaultPar))
305           NearFaultPar = LP;
306       }
307
308       Standard_Real param = 0.0;
309       TopoDS_Edge EE;
310       Standard_Real Lpar = RealLast();
311       for (Standard_Integer i = 1; i <= aSelectorLine.GetNbEdgeParam(); i++)
312       {
313         // Line and edge.
314         aSelectorLine.GetEdgeParam(i, EE, param, Lpar);
315         const TopTools_ListOfShape& ffs = mapEF.FindFromKey(EE); //ffs size == 2
316         if (ffs.Extent() != 2)
317           continue;
318         TopoDS_Face f1 = TopoDS::Face(ffs.First());
319         TopoDS_Face f2 = TopoDS::Face(ffs.Last());
320         TopoDS_Vertex V1, V2;
321         TopExp::Vertices(EE, V1, V2);
322         if (LVInts.Contains(V1) || LVInts.Contains(V2))
323         {
324           continue;
325         }
326
327         IntCurveSurface_TransitionOnCurve tran = IntCurveSurface_Tangent;
328         Standard_Integer Tst = GetTransi(f1, f2, EE, param, L, tran);
329         if (Tst == 1 && Abs(Lpar) < Abs(parmin))
330         {
331           parmin = Lpar;
332           Trans(parmin, tran, myState);
333         }
334         else if (Abs(Lpar) < Abs(NearFaultPar))
335           NearFaultPar = Lpar;
336       }
337     }
338
339     for(SolidExplorer.InitShell();
340         SolidExplorer.MoreShell() && !isFaultyLine;
341         SolidExplorer.NextShell())
342     {
343         if(SolidExplorer.RejectShell(L) == Standard_False)
344         {
345           for (SolidExplorer.InitFace();
346             SolidExplorer.MoreFace() && !isFaultyLine;
347             SolidExplorer.NextFace())
348           {
349             if (SolidExplorer.RejectFace(L) == Standard_False)
350             {
351               TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace();
352               TopoDS_Face f = TopoDS::Face(aLocalShape);
353               IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f);
354
355               // Prolong segment, since there are cases when
356               // the intersector does not find intersection points with the original
357               // segment due to rough triangulation of a parameterized surface.
358               Standard_Real addW = Max(10 * Tol, 0.01*Par);
359               Standard_Real AddW = addW;
360
361               Bnd_Box aBoxF = Intersector3d.Bounding();
362
363               // The box must be finite in order to correctly prolong the segment to its bounds.
364               if (!aBoxF.IsVoid() && !aBoxF.IsWhole())
365               {
366                 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
367                 aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
368
369                 Standard_Real boxaddW = GetAddToParam(L, Par, aBoxF);
370                 addW = Max(addW, boxaddW);
371               }
372
373               Standard_Real minW = -AddW;
374               Standard_Real maxW = Min(Par * 10, Par + addW);
375               Intersector3d.Perform(L, minW, maxW);
376               if (Intersector3d.IsDone())
377               {
378                 if (Intersector3d.NbPnt() == 0)
379                 {
380                   if (Intersector3d.IsParallel())
381                   {
382                     //Check distance between surface and point
383                     BRepAdaptor_Surface aBAS(f, Standard_False);
384                     Extrema_ExtPS aProj(P, aBAS, Precision::PConfusion(), Precision::PConfusion());
385                     if (aProj.IsDone() && aProj.NbExt() > 0)
386                     {
387                       Standard_Integer i, indmin = 0;
388                       Standard_Real d = RealLast();
389                       for (i = 1; i <= aProj.NbExt(); ++i)
390                       {
391                         if (aProj.SquareDistance(i) < d)
392                         {
393                           d = aProj.SquareDistance(i);
394                           indmin = i;
395                         }
396                       }
397                       if (indmin > 0)
398                       {
399                         if (d <= Tol * Tol)
400                         {
401                           const Extrema_POnSurf& aPonS = aProj.Point(indmin);
402                           Standard_Real anU, anV;
403                           aPonS.Parameter(anU, anV);
404                           gp_Pnt2d aP2d(anU, anV);
405                           TopAbs_State aSt = Intersector3d.ClassifyUVPoint(aP2d);
406                           if (aSt == TopAbs_IN || aSt == TopAbs_ON)
407                           {
408                             myState = 2;
409                             myFace = f;
410                             parmin = 0.;
411                             break;
412                           }
413                         }
414                       }
415                     }
416                   }
417                 }
418                 for (Standard_Integer i = 1; i <= Intersector3d.NbPnt(); i++)
419                 {
420                   if (Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion())
421                   {
422                     parmin = Intersector3d.WParameter(i);
423                     TopAbs_State aState = Intersector3d.State(i);
424                     if (Abs(parmin) <= Tol)
425                     {
426                       myState = 2;
427                       myFace = f;
428                       break;
429                     }
430                     //  Treatment of case TopAbs_ON separately.
431                     else if (aState == TopAbs_IN)
432                     {
433                       //-- The intersection point between the line and a face F 
434                       // -- of the solid is in the face F 
435
436                       IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i);
437                       if (tran == IntCurveSurface_Tangent)
438                       {
439 #ifdef OCCT_DEBUG
440                         std::cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<<std::endl;
441 #endif
442                         continue; // ignore this point
443                       }
444
445                       Trans(parmin, tran, myState);
446                       myFace = f;
447                     }
448                     // If the state is TopAbs_ON, it is necessary to chose
449                     // another line and to repeat the whole procedure.
450                     else if (aState == TopAbs_ON)
451                     {
452                       isFaultyLine = Standard_True;
453                       break;
454                     }
455                   }
456                   else
457                   {
458                     //-- No point has been found by the Intersector3d.
459                     //-- Or a Point has been found with a greater parameter.
460                   }
461                 } //-- loop by intersection points
462                 if (myState == 2)
463                 {
464                   break;
465                 }
466               } //-- Face has not been rejected
467               else
468                 myState = 1;
469             }
470           }//-- Exploration of the faces
471           if (myState == 2)
472           {
473             break;
474           }
475         } //-- Shell has not been rejected
476         else
477           myState = 1;
478     } //-- Exploration of the shells
479
480     if (NearFaultPar != RealLast() &&
481         Abs(parmin) >= Abs(NearFaultPar) - Precision::PConfusion())
482     {
483       isFaultyLine = Standard_True;
484     }
485   }
486
487 #ifdef OCCT_DEBUG
488   //#################################################
489   SolidExplorer.DumpSegment(P,L,parmin,State());
490   //#################################################
491 #endif
492 }
493
494
495 TopAbs_State BRepClass3d_SClassifier::State() const
496 {
497   if(myState == 2)
498     return(TopAbs_ON);
499   else if(myState == 3)
500     return(TopAbs_IN);
501   else if(myState == 4)
502     return(TopAbs_OUT);
503
504   // return OUT state when there is an error during execution.
505   return(TopAbs_OUT);
506 }
507
508 TopoDS_Face BRepClass3d_SClassifier::Face() const {  
509   return(myFace);
510 }
511
512 Standard_Boolean BRepClass3d_SClassifier::Rejected() const { 
513   return(myState==1); 
514 }
515
516   
517 Standard_Boolean BRepClass3d_SClassifier::IsOnAFace() const { 
518   return(myState==2);
519 }
520
521
522 void BRepClass3d_SClassifier::ForceIn() {
523   myState=3;
524 }
525
526 void BRepClass3d_SClassifier::ForceOut() { 
527   myState=4;
528 }
529
530 Standard_Real GetAddToParam(const gp_Lin&       L,
531                             const Standard_Real P,
532                             const Bnd_Box&      B)
533 {
534   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
535   B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
536   Standard_Real x[2] = {aXmin,aXmax}, y[2] = {aYmin,aYmax}, z[2] = {aZmin,aZmax};
537   Standard_Integer i = 0, j = 0, k = 0;
538   Standard_Real Par = P;
539   for(i = 0 ; i < 2; i++) {
540     for(j = 0; j < 2; j++) {
541       for(k = 0; k < 2; k++) {
542         Standard_Real X = fabs(x[i]-L.Location().X());
543         Standard_Real Y = fabs(y[j]-L.Location().Y());
544         Standard_Real Z = fabs(z[k]-L.Location().Z());
545         if(X < 1.e+20 && Y < 1.e+20 && Z < 1.e+20) {
546           gp_Pnt aP(x[i],y[j],z[k]);
547           Standard_Real par = ElCLib::Parameter(L,aP);
548           if(par > Par)
549             Par = par;
550         }
551         else
552           return 1.e+20;
553       }
554     }
555   }
556   return Par - P;
557 }
558 //=======================================================================
559 //function : FaceNormal
560 //purpose  : 
561 //=======================================================================
562 Standard_Boolean FaceNormal (const TopoDS_Face& aF,
563                              const Standard_Real U,
564                              const Standard_Real V,
565                              gp_Dir& aDN)
566 {
567   gp_Pnt aPnt ;
568   gp_Vec aD1U, aD1V, aN;
569   Handle(Geom_Surface) aS;
570
571   aS=BRep_Tool::Surface(aF);
572   aS->D1 (U, V, aPnt, aD1U, aD1V);
573   aN=aD1U.Crossed(aD1V);
574   if (aN.Magnitude() <= gp::Resolution())
575     return Standard_False;
576   
577   aN.Normalize();  
578   aDN.SetXYZ(aN.XYZ());
579   if (aF.Orientation() == TopAbs_REVERSED){
580     aDN.Reverse();
581   }
582   return Standard_True;
583 }
584
585 //=======================================================================
586 //function : GetNormalOnFaceBound
587 //purpose  : 
588 //=======================================================================
589 static Standard_Boolean GetNormalOnFaceBound(const TopoDS_Edge& E,
590                                              const TopoDS_Face& F,
591                                              const Standard_Real param,
592                                              gp_Dir& OutDir)
593
594   Standard_Real f = 0, l = 0;
595
596   gp_Pnt2d P2d;
597   Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface(E, F, f, l);
598   if (c2d.IsNull())
599     return Standard_False;
600   if (param < f || param > l)
601     return Standard_False;
602   c2d->D0(param, P2d);
603   if (!FaceNormal(F, P2d.X(), P2d.Y(), OutDir))
604     return Standard_False;
605   return Standard_True;
606 }
607
608 //=======================================================================
609 //function : GetTransi
610 //purpose  : 
611 //=======================================================================
612 static Standard_Integer GetTransi(const TopoDS_Face& f1,
613                                   const TopoDS_Face& f2,
614                                   const TopoDS_Edge e,
615                                   const Standard_Real param,
616                                   const gp_Lin& L,
617                                   IntCurveSurface_TransitionOnCurve& trans)
618 {
619   //return statuses:
620   //1 => OK
621   //0 => skip
622   //-1 => probably a faulty line
623   gp_Dir nf1, nf2;
624   if (!GetNormalOnFaceBound(e, f1, param, nf1))
625     return -1;
626   if (!GetNormalOnFaceBound(e, f2, param, nf2))
627     return -1;
628
629   const gp_Dir& LDir = L.Direction();
630
631   if(Abs(LDir.Dot(nf1)) < Precision::Angular() || Abs(LDir.Dot(nf2)) < Precision::Angular())
632   {
633     //line is orthogonal to normal(s)
634     //trans = IntCurveSurface_Tangent;
635     return -1;
636   }
637
638   if (nf1.IsParallel(nf2, Precision::Angular()))
639   {
640     Standard_Real angD = nf1.Dot(LDir);
641     if (Abs(angD) < Precision::Angular())
642       return -1;
643     else if (angD > 0)
644       trans = IntCurveSurface_Out;
645     else //angD < -Precision::Angular())
646       trans = IntCurveSurface_In;
647     return 1;
648   }
649
650   gp_Vec N = nf1^nf2;
651   gp_Dir ProjL = N.XYZ() ^ LDir.XYZ() ^ N.XYZ(); //proj LDir on the plane defined by nf1/nf2 directions
652
653   Standard_Real fAD = nf1.Dot(ProjL); 
654   Standard_Real sAD = nf2.Dot(ProjL);  
655
656   if (fAD < -Precision::Angular() && sAD < -Precision::Angular())
657     trans = IntCurveSurface_In;
658   else if (fAD > Precision::Angular() && sAD > Precision::Angular())
659     trans = IntCurveSurface_Out;
660   else
661     return 0;
662   return 1;
663 }
664
665 //=======================================================================
666 //function : Trans
667 //purpose  : 
668 //=======================================================================
669 static void Trans(const Standard_Real parmin, 
670                   IntCurveSurface_TransitionOnCurve& tran,
671                   int& state)
672 {
673   // if parmin is negative we should reverse transition
674   if (parmin < 0)
675     tran = (tran == IntCurveSurface_Out ? IntCurveSurface_In : IntCurveSurface_Out);
676
677   if(tran == IntCurveSurface_Out)
678     //-- The line is going from inside the solid to outside 
679     //-- the solid.
680     state = 3; // IN
681   else
682     state = 4; // OUT
683 }