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