0023024: Update headers of OCCT files
[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-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22
23 //  Modified by skv - Thu Sep  4 11:22:05 2003 OCC578
24
25 #include <BRepClass3d_SClassifier.ixx>
26
27 #include <gp_Pnt.hxx>
28 #include <gp_Lin.hxx>
29 #include <gp_Vec.hxx>
30 #include <BRepClass3d_Intersector3d.hxx>
31 #include <TopoDS.hxx>
32
33 #include <IntCurvesFace_Intersector.hxx>
34 // modified by NIZHNY-MKK  Mon Jun 21 15:13:40 2004
35 #include <Precision.hxx>
36 #include <ElCLib.hxx>
37 #include <Geom_Surface.hxx>
38 #include <BRep_Tool.hxx>
39
40 static
41   void FaceNormal (const TopoDS_Face& aF,
42                    const Standard_Real U,
43                    const Standard_Real V,
44                    gp_Dir& aDN);
45
46 static 
47   Standard_Real GetAddToParam(const gp_Lin& L,const Standard_Real P,const Bnd_Box& B);
48
49
50
51 //=======================================================================
52 //function : BRepClass3d_SClassifier
53 //purpose  : 
54 //=======================================================================
55 BRepClass3d_SClassifier::BRepClass3d_SClassifier() 
56
57 }
58
59
60 //=======================================================================
61 //function : BRepClass3d_SClassifier
62 //purpose  : 
63 //=======================================================================
64 BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S,
65                                                  const gp_Pnt&  P,
66                                                  const Standard_Real Tol) { 
67   if(S.Reject(P)) { 
68     myState=3; //-- in ds solid case without face 
69   }
70   else { 
71     Perform(S,P,Tol);
72   }
73 }
74
75
76 //=======================================================================
77 //function : PerformInfinitePoint
78 //purpose  : 
79 //=======================================================================
80 void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE,
81                                                    const Standard_Real /*Tol*/) {
82   //-- Idea : Take point A in face1 and point B in face B 
83   //-- (if there is only one face, take 2 points in the same face.)
84   //-- 
85   //-- Intersect straight line AB with the solid and produce transition of the 
86   //-- first point. If the solid has only one face and the straight line AB does not cut it 
87   //-- it is not possible to decide.
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, bFlag;
97   Standard_Integer nump;
98   Standard_Real aParam, aU1, aV1, aU2, aV2;
99   gp_Pnt A,B;
100   gp_Dir aDN1, aDN2;
101   TopoDS_Face aF1, aF2;
102   //
103   nump = 0;
104   aParam = 0.5;
105   myFace.Nullify();
106   myState=2; 
107   for(aSE.InitShell(); aSE.MoreShell() && nump<2;  aSE.NextShell()) { 
108     for(aSE.InitFace(); aSE.MoreFace()  && nump<2; ) {
109       TopoDS_Face aF = aSE.CurrentFace();
110       aSE.NextFace();
111       if(!nump) { 
112         nump++;
113         bFound=aSE.FindAPointInTheFace(aF, A, aU1, aV1, aParam);
114         if (!bFound) {
115           return;
116         }
117         aF1=aF;
118         if(!aSE.MoreFace()) { 
119           nump++;
120           bFound=aSE.FindAPointInTheFace(aF, B, aU2, aV2, aParam);
121           if (!bFound) {
122             return;
123           }
124           aF2=aF;
125         }
126       }// if(nump==0) {    
127       else if(nump==1) { 
128         bFound=aSE.FindAPointInTheFace(aF, B, aU2, aV2, aParam);
129         if(!bFound) { 
130           return;
131         } 
132         aF2=aF;
133         nump++;
134       }
135     }// for(aSE.InitFace();     aSE.MoreFace()  && nump<2; ) {
136   }// for(aSE.InitShell(); aSE.MoreShell() && nump<2;  aSE.NextShell()) { 
137   //
138   //------------------------------------------------------------
139   // 2
140   Standard_Integer cpasbon;
141   Standard_Real parmin, aD2, aSP;
142   IntCurveSurface_TransitionOnCurve aTC;    
143   TopAbs_State aState;
144   //
145   parmin = RealLast();
146   //
147   bFlag=Standard_False;
148   if (aF1!=aF2) {
149     FaceNormal(aF1, aU1, aV1, aDN1);
150     FaceNormal(aF2, aU2, aV2, aDN2);
151     aSP=1.-aDN1*aDN2;
152     if (aSP < 1.e-5) {
153       bFlag=!bFlag;
154     }
155   }
156   //
157   aD2=A.SquareDistance(B);
158   if(aD2<0.000001 || bFlag) { 
159     B.SetCoord(A.X()+1,A.Y()+1,A.Z()+1);
160   }
161   //
162   cpasbon = 0;
163   gp_Vec AB(A,B);
164   //
165   do { 
166     switch (cpasbon) 
167       {
168       case 1 : AB.SetX(-AB.X());break;
169       case 2 : AB.SetY(-AB.Y());break;
170       case 3 : AB.SetZ(-AB.Z());break;
171       case 4 : AB.SetY(-AB.Y());break;
172       case 5 : AB.SetX(-AB.X());break;
173       }
174     gp_Lin L(A,gp_Dir(AB));    
175     //-- cout<<"\npoint A "<<A.X()<<" "<<A.Y()<<" "<<A.Z()<<endl;
176     //-- cout<<"\npoint B "<<B.X()<<" "<<B.Y()<<" "<<B.Z()<<endl;
177     for(aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { 
178       if(aSE.RejectShell(L) == Standard_False) { 
179         for(aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
180           if(aSE.RejectFace(L) == Standard_False) { 
181             TopoDS_Shape aLocalShape = aSE.CurrentFace();
182             TopoDS_Face f = TopoDS::Face(aLocalShape);
183             IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(f);
184             Intersector3d.Perform(L,-RealLast(),parmin); 
185
186             if(Intersector3d.IsDone()) { 
187               if(Intersector3d.NbPnt()) { 
188                 if(Intersector3d.WParameter(1) < parmin) {
189                   aState=Intersector3d.State(1);
190                   parmin = Intersector3d.WParameter(1);
191                   if(aState==TopAbs_IN || aState==TopAbs_ON) { 
192                     aTC=Intersector3d.Transition(1);
193                     //-- The intersection point between the line and a face F 
194                     // -- of the solid is in the face F 
195                     if(aTC == IntCurveSurface_Out) { 
196                       //-- The line is going from inside the solid to outside 
197                       //-- the solid.
198                       myState = 3; //-- IN --
199                     }
200                     else if(aTC == IntCurveSurface_In) { 
201                       myState = 4; //-- OUT --
202                     }
203                     myFace  = f;
204                   }
205                   /*
206                   else if(Intersector3d.State(1)==TopAbs_ON)  {
207                     //-- The intersection point between the line and a face F 
208                     //-- of the solid is in the face F 
209                     if(Intersector3d.Transition(1) == IntCurveSurface_Out) { 
210                       //-- The line is going from inside the solid to outside 
211                       //-- the solid.
212                       myState = 3; //-- IN --
213                     }
214                     else if(Intersector3d.Transition(1) == IntCurveSurface_In) { 
215                       myState = 4; //-- OUT --
216                     }
217                     //-- myState = 2;
218                     myFace  = f;
219                   }
220                   */
221                 }
222                 
223                 else { 
224                   //-- No point has been found by the Intersector3d.
225                   //-- Or a Point has been found with a greater parameter.
226                 }
227               }
228             }
229           }
230         } //-- Exploration of the faces
231       } //-- Shell has not been rejected
232       else { 
233         myState=1; 
234       }
235     } //-- Exploration of the shells
236     cpasbon++;
237   }
238   while(cpasbon!=0 && cpasbon<5);
239 }
240 //=======================================================================
241 //function : Perform
242 //purpose  : 
243 //=======================================================================
244 void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
245                                       const gp_Pnt&  P,
246                                       const Standard_Real Tol) 
247
248
249
250   if(SolidExplorer.Reject(P)) { 
251     myState=3; //-- in ds solid case without face 
252     return;
253   }
254
255
256   myFace.Nullify();
257   myState = 0;
258   if(SolidExplorer.Reject(P) == Standard_False) { 
259     gp_Lin L;
260     Standard_Real Par;
261     //-- We compute the intersection betwwen the line builded in the Solid Explorer
262     //-- and the shape.
263
264     //-- --------------------------------------------------------------------------------
265     //-- Calculate intersection with the face closest to the direction of bounding boxes 
266     //-- by priority so that to have the smallest possible parmin. 
267     //-- optimization to produce as much as possible rejections with other faces. 
268     Standard_Integer iFlag;
269     //
270
271     //  Modified by skv - Thu Sep  4 11:22:05 2003 OCC578 Begin
272     //  If found line passes through a bound of any face, it means that the line
273     //  is not found properly and it is necessary to repeat whole procedure.
274     //  That's why the main loop while is added.
275     Standard_Boolean isFaultyLine = Standard_True;
276     Standard_Integer anIndFace    = 0;
277     Standard_Real    parmin;
278
279     while (isFaultyLine) {
280       if (anIndFace == 0) {
281         iFlag = SolidExplorer.Segment(P,L,Par);
282       } else {
283         iFlag = SolidExplorer.OtherSegment(P,L,Par);
284       }
285
286       Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex();
287
288       if (aCurInd > anIndFace) {
289         anIndFace = aCurInd;
290       } else {
291         myState = 1;
292
293         return;
294       }
295       //  Modified by skv - Thu Sep  4 11:22:10 2003 OCC578 End
296
297       if (iFlag==1) {
298         // IsOnFace
299         // iFlag==1 i.e face is Infinite
300         myState=2; 
301
302         return;
303       }
304       //SolidExplorer.Segment(P,L,Par);
305       //
306       //process results from uncorrected shells
307       //
308       //if(Par > 1.e+100 && L.Direction().IsParallel(gp_Dir(0.,0.,1.),1.e-8)) {
309       if (iFlag==2) {
310         myState = 4;
311         return;
312       }
313       //-- BRepClass3d_Intersector3d Intersector3d;
314     
315       //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 Begin
316       // Check if the point is ON surface but OUT of the face. 
317       // Just skip this face because it is bad for classification.
318       if (iFlag == 3)
319         continue;
320
321       isFaultyLine = Standard_False;
322 //       Standard_Real parmin = RealLast();
323
324 //       for(SolidExplorer.InitShell();
325 //        SolidExplorer.MoreShell();
326 //        SolidExplorer.NextShell()) { 
327       parmin = RealLast();
328
329       for(SolidExplorer.InitShell();
330           SolidExplorer.MoreShell() && !isFaultyLine;
331           SolidExplorer.NextShell()) { 
332 //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 End
333
334         if(SolidExplorer.RejectShell(L) == Standard_False) { 
335
336 //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 Begin
337 //        for(SolidExplorer.InitFace(); 
338 //            SolidExplorer.MoreFace(); 
339 //            SolidExplorer.NextFace()) {
340           for(SolidExplorer.InitFace(); 
341               SolidExplorer.MoreFace() && !isFaultyLine; 
342               SolidExplorer.NextFace()) {
343 //  Modified by skv - Thu Sep  4 13:48:27 2003 OCC578 End
344           
345             if(SolidExplorer.RejectFace(L) == Standard_False) { 
346             
347               //-- Intersector3d.Perform(L,Par,Tol,SolidExplorer.CurrentFace());
348               TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace();
349               TopoDS_Face f = TopoDS::Face(aLocalShape);
350               //            TopoDS_Face f = TopoDS::Face(SolidExplorer.CurrentFace());
351               IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f);
352
353               // MSV Oct 25, 2001: prolong segment, since there are cases when
354               // the intersector does not find intersection points with the original
355               // segment due to rough triangulation of a parametrized surface
356               Standard_Real addW = Max(10*Tol, 0.01*Par);
357               Standard_Real AddW = addW;
358
359               Bnd_Box aBoxF = Intersector3d.Bounding();
360
361               // MSV 23.09.2004: the box must be finite in order to
362               // correctly prolong the segment to its bounds
363               if (!aBoxF.IsVoid() && !aBoxF.IsWhole()) {
364                 Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
365                 aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
366
367                 Standard_Real boxaddW = GetAddToParam(L,Par,aBoxF);
368                 addW = Max(addW,boxaddW);
369               }
370
371               Standard_Real minW = -AddW;//-addW;
372               Standard_Real maxW = Min(Par*10,Par+addW);//Par+addW;
373               //cout << "range [" << minW << "," << maxW << "]" << endl << endl;
374               Intersector3d.Perform(L,minW,maxW);
375               //Intersector3d.Perform(L,-Tol,Par+10.0*Tol);
376               if(Intersector3d.IsDone()) { 
377                 Standard_Integer i;
378                 for (i=1; i <= Intersector3d.NbPnt(); i++) { 
379                   if(Abs(Intersector3d.WParameter(i)) < Abs(parmin)) {
380  
381                     parmin = Intersector3d.WParameter(i);
382                     //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 Begin
383                     TopAbs_State aState = Intersector3d.State(i);
384                     //  Modified by skv - Thu Sep  4 12:46:33 2003 OCC578 End
385                     if(Abs(parmin)<=Tol) { 
386                       myState = 2;
387                       myFace  = f;
388                     }
389                     //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 Begin
390                     //  Treatment of case TopAbs_ON separately.
391
392                     else if(aState==TopAbs_IN) { 
393                     //  Modified by skv - Thu Sep  4 12:46:32 2003 OCC578 End
394
395                       //-- The intersection point between the line and a face F 
396                       // -- of the solid is in the face F 
397
398                       IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i);
399                       if (tran == IntCurveSurface_Tangent) {
400 #ifdef DEB
401                         cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<<endl;
402 #endif
403                         continue; // ignore this point
404                       }
405                       // if parmin is negative we should reverse transition
406                       if (parmin < 0)
407                         tran = (tran == IntCurveSurface_Out 
408                                 ? IntCurveSurface_In : IntCurveSurface_Out);
409                       if(tran == IntCurveSurface_Out) { 
410                         //-- The line is going from inside the solid to outside 
411                         //-- the solid.
412                         myState = 3; //-- IN --
413                       }
414                       else /* if(tran == IntCurveSurface_In) */ { 
415                         myState = 4; //-- OUT --
416                       }
417                       myFace  = f;
418                     }
419                     //  Modified by skv - Thu Sep  4 12:48:50 2003 OCC578 Begin
420                     // If the state is TopAbs_ON, it is necessary to chose
421                     // another line and to repeat the whole procedure.
422                     else if(aState==TopAbs_ON) {
423                       isFaultyLine = Standard_True;
424
425                       break;
426                     }
427                     //  Modified by skv - Thu Sep  4 12:48:50 2003 OCC578 End
428                   }
429                   else { 
430                     //-- No point has been found by the Intersector3d.
431                     //-- Or a Point has been found with a greater parameter.
432                   }
433                 } //-- loop by intersection points
434               } //-- Face has not been rejected
435               else { 
436                 myState = 1;
437               }
438             }
439           } //-- Exploration of the faces
440         } //-- Shell has not been rejected
441         else { 
442           myState=1; 
443         }
444       } //-- Exploration of the shells
445
446       //  Modified by skv - Thu Sep  4 11:42:03 2003 OCC578 Begin
447       // The end of main loop.
448     }
449     //  Modified by skv - Thu Sep  4 11:42:03 2003 OCC578 End
450
451 #ifdef DEB
452     //#################################################
453     SolidExplorer.DumpSegment(P,L,parmin,State());
454     //#################################################
455 #endif
456
457   } //-- Solid has not been rejected
458   else { 
459     myState = 1;
460   }
461 }
462
463
464 TopAbs_State BRepClass3d_SClassifier::State() const { 
465   if(myState==2)  return(TopAbs_ON);
466   if(myState==4)        return(TopAbs_OUT);          //--
467   else if(myState==3)   return(TopAbs_IN);           //-- 
468   return(TopAbs_OUT);             
469 }
470
471 TopoDS_Face BRepClass3d_SClassifier::Face() const {  
472   return(myFace);
473 }
474
475 Standard_Boolean BRepClass3d_SClassifier::Rejected() const { 
476   return(myState==1); 
477 }
478
479   
480 Standard_Boolean BRepClass3d_SClassifier::IsOnAFace() const { 
481   return(myState==2);
482 }
483
484
485 void BRepClass3d_SClassifier::ForceIn() {
486   myState=3;
487 }
488
489 void BRepClass3d_SClassifier::ForceOut() { 
490   myState=4;
491 }
492
493 Standard_Real GetAddToParam(const gp_Lin&       L,
494                             const Standard_Real P,
495                             const Bnd_Box&      B)
496 {
497   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
498   B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
499   Standard_Real x[2] = {aXmin,aXmax}, y[2] = {aYmin,aYmax}, z[2] = {aZmin,aZmax};
500   Standard_Integer i = 0, j = 0, k = 0;
501   Standard_Real Par = P;
502   for(i = 0 ; i < 2; i++) {
503     for(j = 0; j < 2; j++) {
504       for(k = 0; k < 2; k++) {
505         Standard_Real X = fabs(x[i]-L.Location().X());
506         Standard_Real Y = fabs(y[j]-L.Location().Y());
507         Standard_Real Z = fabs(z[k]-L.Location().Z());
508         if(X < 1.e+20 && Y < 1.e+20 && Z < 1.e+20) {
509           gp_Pnt aP(x[i],y[j],z[k]);
510           Standard_Real par = ElCLib::Parameter(L,aP);
511           if(par > Par)
512             Par = par;
513         }
514         else
515           return 1.e+20;
516       }
517     }
518   }
519   return Par - P;
520 }
521 //=======================================================================
522 //function : FaceNormal
523 //purpose  : 
524 //=======================================================================
525 void FaceNormal (const TopoDS_Face& aF,
526                  const Standard_Real U,
527                  const Standard_Real V,
528                  gp_Dir& aDN)
529 {
530   gp_Pnt aPnt ;
531   gp_Vec aD1U, aD1V, aN;
532   Handle(Geom_Surface) aS;
533
534   aS=BRep_Tool::Surface(aF);
535   aS->D1 (U, V, aPnt, aD1U, aD1V);
536   aN=aD1U.Crossed(aD1V);
537   aN.Normalize();  
538   aDN.SetXYZ(aN.XYZ());
539   if (aF.Orientation() == TopAbs_REVERSED){
540     aDN.Reverse();
541   }
542   return;
543 }