0025717: Non reentrant (and hence non-thread-safe) math_RealRandom / _IntegerRandom
[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 <BRepClass3d_SClassifier.ixx>
20
21 #include <gp_Pnt.hxx>
22 #include <gp_Lin.hxx>
23 #include <gp_Vec.hxx>
24 #include <BRepClass3d_Intersector3d.hxx>
25 #include <TopoDS.hxx>
26
27 #include <IntCurvesFace_Intersector.hxx>
28 // modified by NIZHNY-MKK  Mon Jun 21 15:13:40 2004
29 #include <Precision.hxx>
30 #include <ElCLib.hxx>
31 #include <Geom_Surface.hxx>
32 #include <BRep_Tool.hxx>
33 #include <math_BullardGenerator.hxx>
34 #include <BRepTopAdaptor_FClass2d.hxx>
35
36 static
37   Standard_Boolean FaceNormal (const TopoDS_Face& aF,
38                                const Standard_Real U,
39                                const Standard_Real V,
40                                gp_Dir& aDN);
41
42 static 
43   Standard_Real GetAddToParam(const gp_Lin& L,const Standard_Real P,const Bnd_Box& B);
44
45
46
47 //=======================================================================
48 //function : BRepClass3d_SClassifier
49 //purpose  : 
50 //=======================================================================
51 BRepClass3d_SClassifier::BRepClass3d_SClassifier() 
52
53 }
54
55
56 //=======================================================================
57 //function : BRepClass3d_SClassifier
58 //purpose  : 
59 //=======================================================================
60 BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S,
61                                                  const gp_Pnt&  P,
62                                                  const Standard_Real Tol) { 
63   if(S.Reject(P)) { 
64     myState=3; //-- in ds solid case without face 
65   }
66   else { 
67     Perform(S,P,Tol);
68   }
69 }
70
71
72 //=======================================================================
73 //function : PerformInfinitePoint
74 //purpose  : 
75 //=======================================================================
76 void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE,
77                                                    const Standard_Real /*Tol*/) {
78
79   //Take a normal to the first extracted face in its random inner point
80   //and intersect this reversed normal with the faces of the solid.
81   //If the min.par.-intersection point is
82   // a) inner point of a face
83   // b) transition is not TANGENT
84   //    (the line does not touch the face but pierces it)
85   //then set <myState> to IN or OUT according to transition
86   //else take the next random point inside the min.par.-intersected face
87   //and continue
88   
89   if(aSE.Reject(gp_Pnt(0,0,0))) { 
90     myState=3; //-- in ds solid case without face 
91     return;
92   }
93   //
94   //------------------------------------------------------------
95   // 1
96   Standard_Boolean bFound;
97   Standard_Real aParam, aU = 0., aV = 0.;
98   gp_Pnt aPoint;
99   gp_Dir aDN;
100
101   math_BullardGenerator aRandomGenerator;
102   myFace.Nullify();
103   myState=2;
104
105   aSE.InitShell();
106   if (aSE.MoreShell())
107   {
108     aSE.InitFace();
109     if (aSE.MoreFace())
110     {
111       TopoDS_Face aF = aSE.CurrentFace();
112       TopAbs_State aState = TopAbs_OUT;
113       IntCurveSurface_TransitionOnCurve aTransition = IntCurveSurface_Tangent;
114       TopoDS_Face MinFace = aF;
115       for (;;)
116       {
117         aParam = 0.1 + 0.8 * aRandomGenerator.NextReal(); // random number in range [0.1, 0.9]
118         bFound = aSE.FindAPointInTheFace(aF, aPoint, aU, aV, aParam);
119         if (!bFound)
120           return;
121
122         if (!FaceNormal(aF, aU, aV, aDN))
123           continue;
124         gp_Lin aLin(aPoint, -aDN);
125         Standard_Real parmin = RealLast();
126         for (aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { 
127           if (aSE.RejectShell(aLin) == Standard_False) { 
128             for (aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
129               if (aSE.RejectFace(aLin) == Standard_False) { 
130                 TopoDS_Shape aLocalShape = aSE.CurrentFace();
131                 TopoDS_Face CurFace = TopoDS::Face(aLocalShape);
132                 IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(CurFace);
133                 Intersector3d.Perform(aLin,-RealLast(),parmin); 
134                 
135                 if(Intersector3d.IsDone()) {
136                   if(Intersector3d.NbPnt()) { 
137                     Standard_Integer imin = 1;
138                     for (Standard_Integer i = 2; i <= Intersector3d.NbPnt(); i++)
139                       if (Intersector3d.WParameter(i) < Intersector3d.WParameter(imin))
140                         imin = i;
141                     parmin = Intersector3d.WParameter(imin);
142                     aState = Intersector3d.State(imin);
143                     aTransition = Intersector3d.Transition(imin);
144                     MinFace = CurFace;
145                   }
146                 }
147               }
148             }
149           }
150           else
151             myState = 1;
152         } //end of loop on the whole solid
153         
154         if (aState == TopAbs_IN)
155         {
156           if (aTransition == IntCurveSurface_Out) { 
157             //-- The line is going from inside the solid to outside 
158             //-- the solid.
159             myState = 3; //-- IN --
160             return;
161           }
162           else if (aTransition == IntCurveSurface_In) { 
163             myState = 4; //-- OUT --
164             return;
165           }
166         }
167         aF = MinFace;
168       }
169     } //if (aSE.MoreFace())
170   } //if (aSE.MoreShell())
171 }
172
173 //=======================================================================
174 //function : Perform
175 //purpose  : 
176 //=======================================================================
177 void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
178                                       const gp_Pnt&  P,
179                                       const Standard_Real Tol) 
180
181
182
183   if(SolidExplorer.Reject(P)) { 
184     myState=3; //-- in ds solid case without face 
185     return;
186   }
187
188
189   myFace.Nullify();
190   myState = 0;
191   if(SolidExplorer.Reject(P) == Standard_False) { 
192     gp_Lin L;
193     Standard_Real Par;
194     //-- We compute the intersection betwwen the line builded in the Solid Explorer
195     //-- and the shape.
196
197     //-- --------------------------------------------------------------------------------
198     //-- Calculate intersection with the face closest to the direction of bounding boxes 
199     //-- by priority so that to have the smallest possible parmin. 
200     //-- optimization to produce as much as possible rejections with other faces. 
201     Standard_Integer iFlag;
202     //
203
204     //  Modified by skv - Thu Sep  4 11:22:05 2003 OCC578 Begin
205     //  If found line passes through a bound of any face, it means that the line
206     //  is not found properly and it is necessary to repeat whole procedure.
207     //  That's why the main loop while is added.
208     Standard_Boolean isFaultyLine = Standard_True;
209     Standard_Integer anIndFace    = 0;
210     Standard_Real    parmin = 0.;
211
212     while (isFaultyLine) {
213       if (anIndFace == 0) {
214         iFlag = SolidExplorer.Segment(P,L,Par);
215       } else {
216         iFlag = SolidExplorer.OtherSegment(P,L,Par);
217       }
218
219       Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex();
220
221       if (aCurInd > anIndFace) {
222         anIndFace = aCurInd;
223       } else {
224         myState = 1;
225
226         return;
227       }
228       //  Modified by skv - Thu Sep  4 11:22:10 2003 OCC578 End
229
230       if (iFlag==1) {
231         // IsOnFace
232         // iFlag==1 i.e face is Infinite
233         myState=2; 
234
235         return;
236       }
237       //SolidExplorer.Segment(P,L,Par);
238       //
239       //process results from uncorrected shells
240       //
241       //if(Par > 1.e+100 && L.Direction().IsParallel(gp_Dir(0.,0.,1.),1.e-8)) {
242       if (iFlag==2) {
243         myState = 4;
244         return;
245       }
246       //-- BRepClass3d_Intersector3d Intersector3d;
247     
248       //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 Begin
249       // Check if the point is ON surface but OUT of the face. 
250       // Just skip this face because it is bad for classification.
251       if (iFlag == 3)
252         continue;
253
254       isFaultyLine = Standard_False;
255 //       Standard_Real parmin = RealLast();
256
257 //       for(SolidExplorer.InitShell();
258 //        SolidExplorer.MoreShell();
259 //        SolidExplorer.NextShell()) { 
260       parmin = RealLast();
261
262       for(SolidExplorer.InitShell();
263           SolidExplorer.MoreShell() && !isFaultyLine;
264           SolidExplorer.NextShell()) { 
265 //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 End
266
267         if(SolidExplorer.RejectShell(L) == Standard_False) { 
268
269 //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 Begin
270 //        for(SolidExplorer.InitFace(); 
271 //            SolidExplorer.MoreFace(); 
272 //            SolidExplorer.NextFace()) {
273           for(SolidExplorer.InitFace(); 
274               SolidExplorer.MoreFace() && !isFaultyLine; 
275               SolidExplorer.NextFace()) {
276 //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 End
277           
278             if(SolidExplorer.RejectFace(L) == Standard_False) { 
279             
280               //-- Intersector3d.Perform(L,Par,Tol,SolidExplorer.CurrentFace());
281               TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace();
282               TopoDS_Face f = TopoDS::Face(aLocalShape);
283               //            TopoDS_Face f = TopoDS::Face(SolidExplorer.CurrentFace());
284               IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f);
285
286               // MSV Oct 25, 2001: prolong segment, since there are cases when
287               // the intersector does not find intersection points with the original
288               // segment due to rough triangulation of a parametrized surface
289               Standard_Real addW = Max(10*Tol, 0.01*Par);
290               Standard_Real AddW = addW;
291
292               Bnd_Box aBoxF = Intersector3d.Bounding();
293
294               // MSV 23.09.2004: the box must be finite in order to
295               // correctly prolong the segment to its bounds
296               if (!aBoxF.IsVoid() && !aBoxF.IsWhole()) {
297                 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
298                 aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
299
300                 Standard_Real boxaddW = GetAddToParam(L,Par,aBoxF);
301                 addW = Max(addW,boxaddW);
302               }
303
304               Standard_Real minW = -AddW;//-addW;
305               Standard_Real maxW = Min(Par*10,Par+addW);//Par+addW;
306               //cout << "range [" << minW << "," << maxW << "]" << endl << endl;
307               Intersector3d.Perform(L,minW,maxW);
308               //Intersector3d.Perform(L,-Tol,Par+10.0*Tol);
309               if(Intersector3d.IsDone()) { 
310                 Standard_Integer i;
311                 for (i=1; i <= Intersector3d.NbPnt(); i++) { 
312                   if(Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion()) {
313  
314                     parmin = Intersector3d.WParameter(i);
315                     //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 Begin
316                     TopAbs_State aState = Intersector3d.State(i);
317                     //  Modified by skv - Thu Sep  4 12:46:33 2003 OCC578 End
318                     if(Abs(parmin)<=Tol) { 
319                       myState = 2;
320                       myFace  = f;
321                     }
322                     //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 Begin
323                     //  Treatment of case TopAbs_ON separately.
324
325                     else if(aState==TopAbs_IN) { 
326                     //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 End
327
328                       //-- The intersection point between the line and a face F 
329                       // -- of the solid is in the face F 
330
331                       IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i);
332                       if (tran == IntCurveSurface_Tangent) {
333 #ifdef OCCT_DEBUG
334                         cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<<endl;
335 #endif
336                         continue; // ignore this point
337                       }
338                       // if parmin is negative we should reverse transition
339                       if (parmin < 0)
340                         tran = (tran == IntCurveSurface_Out 
341                                 ? IntCurveSurface_In : IntCurveSurface_Out);
342                       if(tran == IntCurveSurface_Out) { 
343                         //-- The line is going from inside the solid to outside 
344                         //-- the solid.
345                         myState = 3; //-- IN --
346                       }
347                       else /* if(tran == IntCurveSurface_In) */ { 
348                         myState = 4; //-- OUT --
349                       }
350                       myFace  = f;
351                     }
352                     //  Modified by skv - Thu Sep  4 12:48:50 2003 OCC578 Begin
353                     // If the state is TopAbs_ON, it is necessary to chose
354                     // another line and to repeat the whole procedure.
355                     else if(aState==TopAbs_ON) {
356                       isFaultyLine = Standard_True;
357
358                       break;
359                     }
360                     //  Modified by skv - Thu Sep  4 12:48:50 2003 OCC578 End
361                   }
362                   else { 
363                     //-- No point has been found by the Intersector3d.
364                     //-- Or a Point has been found with a greater parameter.
365                   }
366                 } //-- loop by intersection points
367               } //-- Face has not been rejected
368               else { 
369                 myState = 1;
370               }
371             }
372           } //-- Exploration of the faces
373         } //-- Shell has not been rejected
374         else { 
375           myState=1; 
376         }
377       } //-- Exploration of the shells
378
379       //  Modified by skv - Thu Sep  4 11:42:03 2003 OCC578 Begin
380       // The end of main loop.
381     }
382     //  Modified by skv - Thu Sep  4 11:42:03 2003 OCC578 End
383
384 #ifdef OCCT_DEBUG
385     //#################################################
386     SolidExplorer.DumpSegment(P,L,parmin,State());
387     //#################################################
388 #endif
389
390   } //-- Solid has not been rejected
391   else { 
392     myState = 1;
393   }
394 }
395
396
397 TopAbs_State BRepClass3d_SClassifier::State() const { 
398   if(myState==2)  return(TopAbs_ON);
399   if(myState==4)        return(TopAbs_OUT);          //--
400   else if(myState==3)   return(TopAbs_IN);           //-- 
401   return(TopAbs_OUT);             
402 }
403
404 TopoDS_Face BRepClass3d_SClassifier::Face() const {  
405   return(myFace);
406 }
407
408 Standard_Boolean BRepClass3d_SClassifier::Rejected() const { 
409   return(myState==1); 
410 }
411
412   
413 Standard_Boolean BRepClass3d_SClassifier::IsOnAFace() const { 
414   return(myState==2);
415 }
416
417
418 void BRepClass3d_SClassifier::ForceIn() {
419   myState=3;
420 }
421
422 void BRepClass3d_SClassifier::ForceOut() { 
423   myState=4;
424 }
425
426 Standard_Real GetAddToParam(const gp_Lin&       L,
427                             const Standard_Real P,
428                             const Bnd_Box&      B)
429 {
430   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
431   B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
432   Standard_Real x[2] = {aXmin,aXmax}, y[2] = {aYmin,aYmax}, z[2] = {aZmin,aZmax};
433   Standard_Integer i = 0, j = 0, k = 0;
434   Standard_Real Par = P;
435   for(i = 0 ; i < 2; i++) {
436     for(j = 0; j < 2; j++) {
437       for(k = 0; k < 2; k++) {
438         Standard_Real X = fabs(x[i]-L.Location().X());
439         Standard_Real Y = fabs(y[j]-L.Location().Y());
440         Standard_Real Z = fabs(z[k]-L.Location().Z());
441         if(X < 1.e+20 && Y < 1.e+20 && Z < 1.e+20) {
442           gp_Pnt aP(x[i],y[j],z[k]);
443           Standard_Real par = ElCLib::Parameter(L,aP);
444           if(par > Par)
445             Par = par;
446         }
447         else
448           return 1.e+20;
449       }
450     }
451   }
452   return Par - P;
453 }
454 //=======================================================================
455 //function : FaceNormal
456 //purpose  : 
457 //=======================================================================
458 Standard_Boolean FaceNormal (const TopoDS_Face& aF,
459                              const Standard_Real U,
460                              const Standard_Real V,
461                              gp_Dir& aDN)
462 {
463   gp_Pnt aPnt ;
464   gp_Vec aD1U, aD1V, aN;
465   Handle(Geom_Surface) aS;
466
467   aS=BRep_Tool::Surface(aF);
468   aS->D1 (U, V, aPnt, aD1U, aD1V);
469   aN=aD1U.Crossed(aD1V);
470   if (aN.Magnitude() <= gp::Resolution())
471     return Standard_False;
472   
473   aN.Normalize();  
474   aDN.SetXYZ(aN.XYZ());
475   if (aF.Orientation() == TopAbs_REVERSED){
476     aDN.Reverse();
477   }
478   return Standard_True;
479 }