0028956: Coding Rules - eliminate several trivial compiler warnings
[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 <Standard_DomainError.hxx>
32 #include <TopoDS.hxx>
33 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
34 #include <TopTools_MapOfShape.hxx>
35 #include <TopExp.hxx>
36
37 #include <vector>
38
39 // modified by NIZHNY-MKK  Mon Jun 21 15:13:40 2004
40 static
41   Standard_Boolean 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 //gets transition of line <L> passing through/near the edge <e> of faces <f1>, <f2>. <param> is
50 // a parameter on the edge where the minimum distance between <l> and <e> was found 
51 static Standard_Integer GetTransi(const TopoDS_Face& f1, const TopoDS_Face& f2, const TopoDS_Edge e, 
52                      Standard_Real param, const Geom_Line& L, IntCurveSurface_TransitionOnCurve& trans);
53
54 static Standard_Boolean GetNormalOnFaceBound(const TopoDS_Edge& E, const TopoDS_Face& F, Standard_Real param, gp_Dir& OutDir);
55
56 static void Trans(Standard_Real parmin, IntCurveSurface_TransitionOnCurve& tran, int& state);
57
58 //=======================================================================
59 //function : BRepClass3d_SClassifier
60 //purpose  : 
61 //=======================================================================
62 BRepClass3d_SClassifier::BRepClass3d_SClassifier() 
63
64 }
65
66
67 //=======================================================================
68 //function : BRepClass3d_SClassifier
69 //purpose  : 
70 //=======================================================================
71 BRepClass3d_SClassifier::BRepClass3d_SClassifier(BRepClass3d_SolidExplorer& S,
72                                                  const gp_Pnt&  P,
73                                                  const Standard_Real Tol) { 
74   if(S.Reject(P)) { 
75     myState=3; //-- in ds solid case without face 
76   }
77   else { 
78     Perform(S,P,Tol);
79   }
80 }
81
82
83 //=======================================================================
84 //function : PerformInfinitePoint
85 //purpose  : 
86 //=======================================================================
87 void BRepClass3d_SClassifier::PerformInfinitePoint(BRepClass3d_SolidExplorer& aSE,
88                                                    const Standard_Real /*Tol*/) {
89
90   //Take a normal to the first extracted face in its random inner point
91   //and intersect this reversed normal with the faces of the solid.
92   //If the min.par.-intersection point is
93   // a) inner point of a face
94   // b) transition is not TANGENT
95   //    (the line does not touch the face but pierces it)
96   //then set <myState> to IN or OUT according to transition
97   //else take the next random point inside the min.par.-intersected face
98   //and continue
99   
100   if(aSE.Reject(gp_Pnt(0,0,0))) { 
101     myState=3; //-- in ds solid case without face 
102     return;
103   }
104   //
105   //------------------------------------------------------------
106   // 1
107   Standard_Boolean bFound;
108   Standard_Real aParam, aU = 0., aV = 0.;
109   gp_Pnt aPoint;
110   gp_Dir aDN;
111
112   math_BullardGenerator aRandomGenerator;
113   myFace.Nullify();
114   myState=2;
115
116   // Collect faces in sequence to iterate
117   std::vector<TopoDS_Face> aFaces;
118   for (aSE.InitShell(); aSE.MoreShell(); aSE.NextShell())
119   {
120     for (aSE.InitFace(); aSE.MoreFace(); aSE.NextFace())
121     {
122       aFaces.push_back (aSE.CurrentFace());
123     }
124   }
125
126   // iteratively try up to 10 probing points from each face
127   const Standard_Integer NB_MAX_POINTS_PER_FACE = 10;
128   for (Standard_Integer itry = 0; itry < NB_MAX_POINTS_PER_FACE; itry++)
129   {
130     for (std::vector<TopoDS_Face>::iterator iFace = aFaces.begin(); iFace != aFaces.end(); ++iFace)
131     {
132       TopoDS_Face aF = *iFace;
133
134       TopAbs_State aState = TopAbs_OUT;
135       IntCurveSurface_TransitionOnCurve aTransition = IntCurveSurface_Tangent;
136
137       aParam = 0.1 + 0.8 * aRandomGenerator.NextReal(); // random number in range [0.1, 0.9]
138       bFound = aSE.FindAPointInTheFace(aF, aPoint, aU, aV, aParam);
139       if (!bFound || !FaceNormal(aF, aU, aV, aDN))
140         continue;
141
142       gp_Lin aLin(aPoint, -aDN);
143       Standard_Real parmin = RealLast();
144       for (aSE.InitShell();aSE.MoreShell();aSE.NextShell()) { 
145         if (aSE.RejectShell(aLin) == Standard_False) { 
146           for (aSE.InitFace();aSE.MoreFace(); aSE.NextFace()) {
147             if (aSE.RejectFace(aLin) == Standard_False) { 
148               TopoDS_Shape aLocalShape = aSE.CurrentFace();
149               TopoDS_Face CurFace = TopoDS::Face(aLocalShape);
150               IntCurvesFace_Intersector& Intersector3d = aSE.Intersector(CurFace);
151               Intersector3d.Perform(aLin,-RealLast(),parmin); 
152
153               if(Intersector3d.IsDone()) {
154                 if(Intersector3d.NbPnt()) { 
155                   Standard_Integer imin = 1;
156                   for (Standard_Integer i = 2; i <= Intersector3d.NbPnt(); i++)
157                     if (Intersector3d.WParameter(i) < Intersector3d.WParameter(imin))
158                       imin = i;
159                   parmin = Intersector3d.WParameter(imin);
160                   aState = Intersector3d.State(imin);
161                   aTransition = Intersector3d.Transition(imin);
162                 }
163               }
164             }
165           }
166         }
167         else
168           myState = 1;
169       } //end of loop on the whole solid
170         
171       if (aState == TopAbs_IN)
172       {
173         if (aTransition == IntCurveSurface_Out) { 
174           //-- The line is going from inside the solid to outside 
175           //-- the solid.
176           myState = 3; //-- IN --
177           return;
178         }
179         else if (aTransition == IntCurveSurface_In) { 
180           myState = 4; //-- OUT --
181           return;
182         }
183       }
184     } // iteration by faces
185   } // iteration by points
186 }
187
188 //=======================================================================
189 //function : Perform
190 //purpose  : 
191 //=======================================================================
192 void BRepClass3d_SClassifier::Perform(BRepClass3d_SolidExplorer& SolidExplorer,
193                                       const gp_Pnt&  P,
194                                       const Standard_Real Tol)
195
196   if(SolidExplorer.Reject(P))
197   {
198     // Solid without faces => the whole space. Always in.
199     myState = 3; // IN
200     return;
201   }
202
203   const BRepClass3d_BndBoxTree & aTree = SolidExplorer.GetTree();
204   const TopTools_IndexedMapOfShape & aMapEV = SolidExplorer.GetMapEV();
205
206   // Vertices/Edges vs Point.
207   BRepClass3d_BndBoxTreeSelectorPoint aSelectorPoint(aMapEV);
208   aSelectorPoint.SetCurrentPoint(P);
209
210   Standard_Integer SelsVE = 0;
211   SelsVE = aTree.Select(aSelectorPoint); 
212
213   if (SelsVE > 0)
214   {
215     // The point P lays inside the tolerance area of vertices/edges => return ON state.
216     myState = 2; // ON.
217     return;
218   }
219
220   TopTools_IndexedDataMapOfShapeListOfShape mapEF;
221   TopExp::MapShapesAndAncestors(SolidExplorer.GetShape(), TopAbs_EDGE, TopAbs_FACE, mapEF);
222   
223   BRepClass3d_BndBoxTreeSelectorLine aSelectorLine(aMapEV);
224
225   myFace.Nullify();
226   myState = 0;
227
228   gp_Lin L;
229   Standard_Real Par;
230
231   // We compute the intersection between the line built in the Solid Explorer and the shape.
232   //-- --------------------------------------------------------------------------------
233   // Calculate intersection with the face closest to the direction of bounding boxes 
234   // by priority so that to have the smallest possible parmin.
235   // Optimization to produce as much as possible rejections with other faces.
236   Standard_Integer iFlag;
237
238   // If found line passes through a bound of any face, it means that the line
239   // is not found properly and it is necessary to repeat whole procedure.
240   // That's why the main loop while is added.
241   Standard_Boolean isFaultyLine = Standard_True;
242   Standard_Integer anIndFace    = 0;
243   Standard_Real    parmin = 0.0;
244   while (isFaultyLine)
245   {
246     if (anIndFace == 0)
247       iFlag = SolidExplorer.Segment(P,L,Par);
248     else
249       iFlag = SolidExplorer.OtherSegment(P,L,Par);
250
251     Standard_Integer aCurInd = SolidExplorer.GetFaceSegmentIndex();
252
253     if (aCurInd > anIndFace)
254       anIndFace = aCurInd;
255     else
256     {
257       myState = 1; // Faulty.
258       return;
259     }
260
261     if (iFlag==1)
262     {
263       // IsOnFace iFlag==1 i.e face is Infinite
264       myState = 2; // ON.
265       return;
266     }
267     if (iFlag == 2) 
268     {
269       myState = 4; // OUT.
270       return;
271     }
272
273     // Check if the point is ON surface but OUT of the face.
274     // Just skip this face because it is bad for classification.
275     if (iFlag == 3)
276       continue;
277
278     isFaultyLine = Standard_False;
279     parmin = RealLast();
280
281     Standard_Real NearFaultPar = RealLast(); // Parameter on line.
282     aSelectorLine.ClearResults();
283     aSelectorLine.SetCurrentLine(L, Par);
284     Standard_Integer SelsEVL = 0;
285     SelsEVL = aTree.Select(aSelectorLine); //SelsEE > 0 => Line/Edges & Line/Vertex intersection
286     if (SelsEVL > 0 )
287     {    
288       // Line and edges / vertices interference.
289       Standard_Integer VLInterNb = aSelectorLine.GetNbVertParam();
290       TopoDS_Vertex NearIntVert;
291       TopTools_MapOfShape LVInts;
292       for (Standard_Integer i = 1; i <= VLInterNb; i++)
293       {
294         // Line and vertex.
295         Standard_Real LP = 0;
296         TopoDS_Vertex V;
297         aSelectorLine.GetVertParam(i, V, LP);
298
299         LVInts.Add(V);
300         if (Abs(LP) < Abs(NearFaultPar))
301           NearFaultPar = LP;
302       }
303
304       Standard_Real param = 0.0;
305       TopoDS_Edge EE;
306       Standard_Real Lpar = RealLast();
307       for (Standard_Integer i = 1; i <= aSelectorLine.GetNbEdgeParam(); i++)
308       {
309         // Line and edge.
310         aSelectorLine.GetEdgeParam(i, EE, param, Lpar);
311         const TopTools_ListOfShape& ffs = mapEF.FindFromKey(EE); //ffs size == 2
312         if (ffs.Extent() != 2)
313           continue;
314         TopoDS_Face f1 = TopoDS::Face(ffs.First());
315         TopoDS_Face f2 = TopoDS::Face(ffs.Last());
316         TopoDS_Vertex V1, V2;
317         TopExp::Vertices(EE, V1, V2);
318         if (LVInts.Contains(V1) || LVInts.Contains(V2))
319         {
320           continue;
321         }
322
323         IntCurveSurface_TransitionOnCurve tran = IntCurveSurface_Tangent;
324         Standard_Integer Tst = GetTransi(f1, f2, EE, param, L, tran);
325         if (Tst == 1 && Abs(Lpar) < Abs(parmin))
326         {
327           parmin = Lpar;
328           Trans(parmin, tran, myState);
329         }
330         else if (Abs(Lpar) < Abs(NearFaultPar))
331           NearFaultPar = Lpar;
332       }
333     }
334
335     for(SolidExplorer.InitShell();
336         SolidExplorer.MoreShell() && !isFaultyLine;
337         SolidExplorer.NextShell())
338     {
339         if(SolidExplorer.RejectShell(L) == Standard_False)
340         {
341           for(SolidExplorer.InitFace(); 
342               SolidExplorer.MoreFace() && !isFaultyLine; 
343               SolidExplorer.NextFace())
344           {
345               if(SolidExplorer.RejectFace(L) == Standard_False)
346               {
347                 TopoDS_Shape aLocalShape = SolidExplorer.CurrentFace();
348                 TopoDS_Face f = TopoDS::Face(aLocalShape);
349                 IntCurvesFace_Intersector& Intersector3d = SolidExplorer.Intersector(f);
350
351                 // Prolong segment, since there are cases when
352                 // the intersector does not find intersection points with the original
353                 // segment due to rough triangulation of a parameterized surface.
354                 Standard_Real addW = Max(10*Tol, 0.01*Par);
355                 Standard_Real AddW = addW;
356
357                 Bnd_Box aBoxF = Intersector3d.Bounding();
358
359                 // The box must be finite in order to correctly prolong the segment to its bounds.
360                 if (!aBoxF.IsVoid() && !aBoxF.IsWhole())
361                 {
362                   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
363                   aBoxF.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
364
365                   Standard_Real boxaddW = GetAddToParam(L,Par,aBoxF);
366                   addW = Max(addW,boxaddW);
367                 }
368
369                 Standard_Real minW = -AddW;
370                 Standard_Real maxW = Min(Par*10,Par+addW);
371                 Intersector3d.Perform(L,minW,maxW);
372                 if(Intersector3d.IsDone())
373                 {
374                   for (Standard_Integer i = 1; i <= Intersector3d.NbPnt(); i++)
375                   {
376                     if(Abs(Intersector3d.WParameter(i)) < Abs(parmin) - Precision::PConfusion())
377                     {
378                       parmin = Intersector3d.WParameter(i);
379                       TopAbs_State aState = Intersector3d.State(i);
380                       if(Abs(parmin)<=Tol) 
381                       { 
382                         myState = 2;
383                         myFace  = f;
384                       }
385                       //  Treatment of case TopAbs_ON separately.
386                       else if(aState==TopAbs_IN)
387                       {
388                         //-- The intersection point between the line and a face F 
389                         // -- of the solid is in the face F 
390
391                         IntCurveSurface_TransitionOnCurve tran = Intersector3d.Transition(i);
392                         if (tran == IntCurveSurface_Tangent)
393                         {
394                           #ifdef OCCT_DEBUG
395                             cout<<"*Problem ds BRepClass3d_SClassifier.cxx"<<endl;
396                           #endif
397                           continue; // ignore this point
398                         }
399
400                         Trans(parmin, tran, myState);
401                         myFace  = f;
402                       }
403                       // If the state is TopAbs_ON, it is necessary to chose
404                       // another line and to repeat the whole procedure.
405                       else if(aState==TopAbs_ON)
406                       {
407                         isFaultyLine = Standard_True;
408                         break;
409                       }
410                     }
411                     else
412                     {
413                       //-- No point has been found by the Intersector3d.
414                       //-- Or a Point has been found with a greater parameter.
415                     }
416                   } //-- loop by intersection points
417                 } //-- Face has not been rejected
418                 else
419                   myState = 1;
420               }
421           } //-- Exploration of the faces
422         } //-- Shell has not been rejected
423         else
424           myState = 1;
425     } //-- Exploration of the shells
426
427     if (NearFaultPar != RealLast() &&
428         Abs(parmin) >= Abs(NearFaultPar) - Precision::PConfusion())
429     {
430       isFaultyLine = Standard_True;
431     }
432   }
433
434 #ifdef OCCT_DEBUG
435   //#################################################
436   SolidExplorer.DumpSegment(P,L,parmin,State());
437   //#################################################
438 #endif
439 }
440
441
442 TopAbs_State BRepClass3d_SClassifier::State() const
443 {
444   if(myState == 2)
445     return(TopAbs_ON);
446   else if(myState == 3)
447     return(TopAbs_IN);
448   else if(myState == 4)
449     return(TopAbs_OUT);
450
451   // return OUT state when there is an error during execution.
452   return(TopAbs_OUT);
453 }
454
455 TopoDS_Face BRepClass3d_SClassifier::Face() const {  
456   return(myFace);
457 }
458
459 Standard_Boolean BRepClass3d_SClassifier::Rejected() const { 
460   return(myState==1); 
461 }
462
463   
464 Standard_Boolean BRepClass3d_SClassifier::IsOnAFace() const { 
465   return(myState==2);
466 }
467
468
469 void BRepClass3d_SClassifier::ForceIn() {
470   myState=3;
471 }
472
473 void BRepClass3d_SClassifier::ForceOut() { 
474   myState=4;
475 }
476
477 Standard_Real GetAddToParam(const gp_Lin&       L,
478                             const Standard_Real P,
479                             const Bnd_Box&      B)
480 {
481   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
482   B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
483   Standard_Real x[2] = {aXmin,aXmax}, y[2] = {aYmin,aYmax}, z[2] = {aZmin,aZmax};
484   Standard_Integer i = 0, j = 0, k = 0;
485   Standard_Real Par = P;
486   for(i = 0 ; i < 2; i++) {
487     for(j = 0; j < 2; j++) {
488       for(k = 0; k < 2; k++) {
489         Standard_Real X = fabs(x[i]-L.Location().X());
490         Standard_Real Y = fabs(y[j]-L.Location().Y());
491         Standard_Real Z = fabs(z[k]-L.Location().Z());
492         if(X < 1.e+20 && Y < 1.e+20 && Z < 1.e+20) {
493           gp_Pnt aP(x[i],y[j],z[k]);
494           Standard_Real par = ElCLib::Parameter(L,aP);
495           if(par > Par)
496             Par = par;
497         }
498         else
499           return 1.e+20;
500       }
501     }
502   }
503   return Par - P;
504 }
505 //=======================================================================
506 //function : FaceNormal
507 //purpose  : 
508 //=======================================================================
509 Standard_Boolean FaceNormal (const TopoDS_Face& aF,
510                              const Standard_Real U,
511                              const Standard_Real V,
512                              gp_Dir& aDN)
513 {
514   gp_Pnt aPnt ;
515   gp_Vec aD1U, aD1V, aN;
516   Handle(Geom_Surface) aS;
517
518   aS=BRep_Tool::Surface(aF);
519   aS->D1 (U, V, aPnt, aD1U, aD1V);
520   aN=aD1U.Crossed(aD1V);
521   if (aN.Magnitude() <= gp::Resolution())
522     return Standard_False;
523   
524   aN.Normalize();  
525   aDN.SetXYZ(aN.XYZ());
526   if (aF.Orientation() == TopAbs_REVERSED){
527     aDN.Reverse();
528   }
529   return Standard_True;
530 }
531
532 //=======================================================================
533 //function : GetNormalOnFaceBound
534 //purpose  : 
535 //=======================================================================
536 static Standard_Boolean GetNormalOnFaceBound(const TopoDS_Edge& E,
537                                              const TopoDS_Face& F,
538                                              const Standard_Real param,
539                                              gp_Dir& OutDir)
540
541   Standard_Real f = 0, l = 0;
542
543   gp_Pnt2d P2d;
544   Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface(E, F, f, l);
545   if (c2d.IsNull())
546     return Standard_False;
547   if (param < f || param > l)
548     return Standard_False;
549   c2d->D0(param, P2d);
550   if (!FaceNormal(F, P2d.X(), P2d.Y(), OutDir))
551     return Standard_False;
552   return Standard_True;
553 }
554
555 //=======================================================================
556 //function : GetTransi
557 //purpose  : 
558 //=======================================================================
559 static Standard_Integer GetTransi(const TopoDS_Face& f1,
560                                   const TopoDS_Face& f2,
561                                   const TopoDS_Edge e,
562                                   const Standard_Real param,
563                                   const Geom_Line& L,
564                                   IntCurveSurface_TransitionOnCurve& trans)
565 {
566   //return statuses:
567   //1 => OK
568   //0 => skip
569   //-1 => probably a faulty line
570   gp_Dir nf1, nf2;
571   if (!GetNormalOnFaceBound(e, f1, param, nf1))
572     return -1;
573   if (!GetNormalOnFaceBound(e, f2, param, nf2))
574     return -1;
575
576   const gp_Dir& LDir = L.Lin().Direction();
577
578   if(Abs(LDir.Dot(nf1)) < Precision::Angular() || Abs(LDir.Dot(nf2)) < Precision::Angular())
579   {
580     //line is orthogonal to normal(s)
581     //trans = IntCurveSurface_Tangent;
582     return -1;
583   }
584
585   if (nf1.IsParallel(nf2, Precision::Angular()))
586   {
587     Standard_Real angD = nf1.Dot(LDir);
588     if (Abs(angD) < Precision::Angular())
589       return -1;
590     else if (angD > 0)
591       trans = IntCurveSurface_Out;
592     else //angD < -Precision::Angular())
593       trans = IntCurveSurface_In;
594     return 1;
595   }
596
597   gp_Vec N = nf1^nf2;
598   gp_Dir ProjL = N.XYZ() ^ LDir.XYZ() ^ N.XYZ(); //proj LDir on the plane defined by nf1/nf2 directions
599
600   Standard_Real fAD = nf1.Dot(ProjL); 
601   Standard_Real sAD = nf2.Dot(ProjL);  
602
603   if (fAD < -Precision::Angular() && sAD < -Precision::Angular())
604     trans = IntCurveSurface_In;
605   else if (fAD > Precision::Angular() && sAD > Precision::Angular())
606     trans = IntCurveSurface_Out;
607   else
608     return 0;
609   return 1;
610 }
611
612 //=======================================================================
613 //function : Trans
614 //purpose  : 
615 //=======================================================================
616 static void Trans(const Standard_Real parmin, 
617                   IntCurveSurface_TransitionOnCurve& tran,
618                   int& state)
619 {
620   // if parmin is negative we should reverse transition
621   if (parmin < 0)
622     tran = (tran == IntCurveSurface_Out ? IntCurveSurface_In : IntCurveSurface_Out);
623
624   if(tran == IntCurveSurface_Out)
625     //-- The line is going from inside the solid to outside 
626     //-- the solid.
627     state = 3; // IN
628   else
629     state = 4; // OUT
630 }