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