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