Merging OCC22105, OCC22354, OCC22150 , OCC22199 , OCC22391 and OCC22108
[occt.git] / src / Select3D / Select3D_SensitiveTriangulation.cxx
1 // File:        Select3D_SensitiveTriangulation.cxx
2 // Created:     Thu May 15 17:47:05 1997
3 // Author:      Robert COUBLANC
4 //              <rob@robox.paris1.matra-dtv.fr>
5 //Modified      Thur Apr 09 98 by rob : No more computation of free edges.
6 //                                      fix bug on Compute Depth (don't forget
7 //                                      Location...)
8
9 #define BUC60858        //GG 27/03/01 Avoid to crash when selecting
10 //                      a triangle containing confused or aligned points.
11
12 #include <Select3D_SensitiveTriangulation.ixx>
13 #include <gp_Pnt2d.hxx>
14 #include <Poly_Connect.hxx>
15 #include <CSLib_Class2d.hxx>
16 #include <TColStd_Array1OfInteger.hxx>
17 #include <Select3D_SensitiveTriangle.hxx>
18 #include <Precision.hxx>
19 #include <ElCLib.hxx>
20 #include <CSLib_Class2d.hxx>
21
22
23 static Standard_Integer S3D_NumberOfFreeEdges(const Handle(Poly_Triangulation)& Trg)
24 {
25   Standard_Integer nFree = 0;
26   Poly_Connect pc(Trg);
27   Standard_Integer t[3];
28   Standard_Integer i,j;
29   for (i = 1; i <= Trg->NbTriangles(); i++) {
30     pc.Triangles(i,t[0],t[1],t[2]);
31     for (j = 0; j < 3; j++)
32       if (t[j] == 0) nFree++;
33   }
34   return nFree; 
35 }
36 static Standard_Boolean S3D_STriangul_NearSegment (const gp_XY& p0, const gp_XY& p1, const gp_XY& TheP,
37                                                    const Standard_Real aTol, Standard_Real& aDMin)
38 {
39   Bnd_Box2d B;
40   B.SetVoid();
41   B.Set(p0);
42   B.Update(p1.X(),p1.Y());
43   B.Enlarge(aTol*3);
44   if(B.IsOut(TheP)) return Standard_False;
45
46   gp_XY V01(p1);V01-=p0;
47   gp_XY Vec(TheP);Vec -= p0;
48   
49   Standard_Real u = Vec*V01.Normalized();
50   if(u<-aTol) return Standard_False;
51   Standard_Real u1 = u-aTol;
52   Standard_Real modmod = V01.SquareModulus();
53   if(u1*u1> modmod) return Standard_False;
54
55   gp_XY N01 (-V01.Y(),V01.X());
56   N01.Normalize();
57   aDMin = Abs (Vec * N01);
58   return aDMin <= aTol;
59 }
60
61 // static Standard_Real S3D_SquareDistanceFromEdge(gp_Pnt2d PCur,
62 //                                              gp_Pnt2d PEdg1,
63 //                                              gp_Pnt2d PEdg2,
64 //                                              const Standard_Real TolTol)
65 // {
66 //   gp_XY VEdg (PEdg1.XY());
67 //   gp_XY VCur (PEdg1.XY());
68 //   VEdg-= PEdg2.XY();
69 //   VCur-=PCur.XY();
70 //   Standard_Real long1 = VEdg.SquareModulus();
71   
72 //   if(long1<=TolTol)
73 //     return VCur.SquareModulus();
74 //   Standard_Real Val = VEdg^VCur;
75 //   return Val*Val/long1;
76   
77 // }
78
79 static Standard_Boolean S3D_IsEdgeIn(const Standard_Integer e1,
80                                      const Standard_Integer e2,
81                                      const Standard_Integer N1,
82                                      const Standard_Integer N2,
83                                      const Standard_Integer N3)
84 {
85   Standard_Integer bid1  = (e1 == N1) ? N1 : ((e1 == N2) ? N2 : ( e1==N3 ? N3 : 0));
86   if(bid1==0) return Standard_False;
87   Standard_Integer bid2  = (e2 == N1) ? N1 : ((e2 == N2) ? N2 : ( e2==N3 ? N3 : 0));
88
89   if(bid2==0 || bid2 ==bid1) return Standard_False;
90   return Standard_True;
91 }
92
93
94
95 //=======================================================================
96 //function : Select3D_SensitiveTriangulation
97 //purpose  : 
98 //=======================================================================
99
100 Select3D_SensitiveTriangulation::
101 Select3D_SensitiveTriangulation(const Handle(SelectBasics_EntityOwner)& OwnerId,
102                                 const Handle(Poly_Triangulation)& Trg,
103                                 const TopLoc_Location& Loc,
104                                 const Standard_Boolean InteriorFlag):
105                                 Select3D_SensitiveEntity(OwnerId),
106 myTriangul(Trg),
107 myiniloc(Loc),
108 myIntFlag(InteriorFlag),
109 myNodes2d(1,Trg->NbNodes()),
110 myDetectedTr(-1)
111 {
112   // calculate free edges and cdg 3d of the triangulation:
113   // This code should have been integrated in poly_triangulation...
114
115   Standard_Integer fr = 1;
116   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
117   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();  
118   Standard_Integer nbTriangles (myTriangul->NbTriangles());
119   gp_XYZ cdg(0,0,0);
120   Standard_Integer n[3];
121   
122   // to find connections in case when the border is not concerned...
123   if(!myIntFlag){
124     myFreeEdges = new TColStd_HArray1OfInteger(1,2*S3D_NumberOfFreeEdges(Trg));
125     TColStd_Array1OfInteger& FreeE = myFreeEdges->ChangeArray1();
126     Poly_Connect pc(myTriangul);
127     Standard_Integer t[3];
128     Standard_Integer i,j;
129     for ( i = 1; i <= nbTriangles; i++) {
130       pc.Triangles(i,t[0],t[1],t[2]);
131       triangles(i).Get(n[0],n[1],n[2]);
132       cdg += (Nodes(n[0]).XYZ() + Nodes(n[1]).XYZ()+ Nodes(n[2]).XYZ())/3.;
133       for (j = 0; j < 3; j++) {
134         Standard_Integer k = (j+1) % 3;
135         if (t[j] == 0) {
136           FreeE(fr)  = n[j];
137           FreeE(fr+1)= n[k];
138           fr += 2;
139         }
140       }
141     }
142   }
143   else{
144     for (Standard_Integer i = 1; i <= nbTriangles; i++) {
145       triangles(i).Get(n[0],n[1],n[2]);
146       cdg += (Nodes(n[0]).XYZ() + Nodes(n[1]).XYZ()+ Nodes(n[2]).XYZ())/3.;
147     }
148   }
149
150   
151   if(nbTriangles!=0) cdg /= nbTriangles;
152   myCDG3D = gp_Pnt(cdg);
153   
154   ComputeTotalTrsf();
155
156   if(myTrsf.Form()!=gp_Identity)
157     myCDG3D.Transform(myTrsf);
158 }
159
160
161 //=======================================================================
162 //function : Select3D_SensitiveTriangulation
163 //purpose  : 
164 //=======================================================================
165 Select3D_SensitiveTriangulation::
166 Select3D_SensitiveTriangulation(const Handle(SelectBasics_EntityOwner)& OwnerId,
167                                 const Handle(Poly_Triangulation)& Trg,
168                                 const TopLoc_Location& Loc,
169                                 const Handle(TColStd_HArray1OfInteger)& FreeEdges,
170                                 const gp_Pnt& TheCDG,
171                                 const Standard_Boolean InteriorFlag):
172 Select3D_SensitiveEntity(OwnerId),
173 myTriangul(Trg),
174 myiniloc(Loc),
175 myCDG3D(TheCDG),
176 myFreeEdges(FreeEdges),
177 myIntFlag(InteriorFlag),
178 myNodes2d(1,Trg->NbNodes()),
179 myDetectedTr(-1)
180 {
181 }
182 //=======================================================================
183 //function : Project
184 //purpose  : 
185 //=======================================================================
186
187 void Select3D_SensitiveTriangulation::Project(const Select3D_Projector& aPrj) 
188 {
189   Select3D_SensitiveEntity::Project(aPrj); // to set the field last proj...
190   
191   mybox2d.SetVoid();
192   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();  
193   
194   gp_Pnt2d ProjPT;
195   
196   for(Standard_Integer I=1;I<=myTriangul->NbNodes();I++){
197     if(myTrsf.Form()!=gp_Identity)
198       aPrj.Project(Nodes(I).Transformed(myTrsf),ProjPT);
199     else
200       aPrj.Project(Nodes(I),ProjPT);
201     
202     myNodes2d.SetValue(I,ProjPT);
203     mybox2d.Add(ProjPT);
204   }
205   
206   aPrj.Project(myCDG3D,myCDG2D);
207 }
208
209 //=======================================================================
210 //function : Areas
211 //purpose  : 
212 //=======================================================================
213
214 void Select3D_SensitiveTriangulation::Areas(SelectBasics_ListOfBox2d& boxes) 
215 {
216   boxes.Append(mybox2d);
217 }
218
219 //=======================================================================
220 //function : getUV
221 //purpose  : compute parameters of the picked point on triangle in 2d
222 //     Note: parameters of point P on triangle (P1, P2, P3) are defined 
223 //           as U and V such that P = P1 + U * (P2 - P1) + V * (P3 - P1);
224 //    Range: U >= 0, V >= 0, U + V <= 1
225 //=======================================================================
226
227 static gp_XY getUV (const gp_XY& aP2d1, const gp_XY& aP2d2, const gp_XY& aP2d3,
228                     const gp_XY& aPick)
229 {
230   gp_XY aDU = aP2d2 - aP2d1;
231   gp_XY aDV = aP2d3 - aP2d1;
232   Standard_Real aDet = aDU ^ aDV;
233
234   // case of non-degenerated triangle
235   gp_XY aDP = aPick - aP2d1;
236   if ( Abs (aDet) > gp::Resolution() )
237   {
238     Standard_Real aU =  (aDP ^ aDV) / aDet;
239     Standard_Real aV = -(aDP ^ aDU) / aDet;
240     if ( aU < 0. ) aU = 0.;
241     if ( aV < 0. ) aV = 0.;
242     if ( aU + aV > 1. ) { Standard_Real aD = aU + aV; aU /= aD; aV /= aD; }
243     return gp_XY (aU, aV);
244   }
245
246   // degenerated case (in 2d projection)
247   Standard_Real aL2U = aDU.SquareModulus();
248   Standard_Real aL2V = aDV.SquareModulus();
249   if ( aL2U < gp::Resolution() ) // side 1-2 is degenerated 
250   {
251     if ( aL2V < gp::Resolution() ) // whole triangle is degenerated to point
252       return gp_XY (0., 0.);
253     else
254       return gp_XY (0., (aDP * aDV) / aL2V);
255   }
256   else if ( aL2V < gp::Resolution() ) // side 1-3 is degenerated
257     return gp_XY ((aDP * aDU) / aL2U, 0.);
258   else // sides 1-2 and 1-3 are collinear
259   {
260     // select parameter on one of sides so as to have points closer to picked
261     Standard_Real aU = Min (1., Max (0., (aDP * aDU) / aL2U));
262     Standard_Real aV = Min (1., Max (0., (aDP * aDV) / aL2V));
263     gp_XY aP2dU = aP2d1 + aU * aDU;
264     gp_XY aP2dV = aP2d1 + aV * aDV;
265     if ( (aPick - aP2dU).SquareModulus() < (aPick - aP2dV).SquareModulus() )
266       return gp_XY ((aDP * aDU) / aL2U, 0.);
267     else
268       return gp_XY (0., (aDP * aDV) / aL2V);
269   }
270 }
271
272 //=======================================================================
273 //function : Matches
274 //purpose  : 
275 //=======================================================================
276 Standard_Boolean Select3D_SensitiveTriangulation::Matches(const Standard_Real X,
277                                                           const Standard_Real Y,
278                                                           const Standard_Real aTol,
279                                                           Standard_Real& DMin) 
280 {
281   // get view direction (necessary for calculation of depth) from field mylastprj of the base class
282   if ( ! mylastprj )
283     return Standard_False;
284
285   DMin = Precision::Infinite();
286   gp_XY BidPoint(X,Y);
287   myDetectedTr = -1;
288   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
289
290   // it is checked if we are inside the triangle 2d.
291   if(myIntFlag)
292   {
293     gp_Lin EyeLine = (*((Select3D_Projector*)mylastprj)).Shoot(X,Y);
294     if ( myTrsf.Form()!=gp_Identity )
295       EyeLine.Transform (myTrsf.Inverted());
296
297     Standard_Real aMinDepth = Precision::Infinite();
298     const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();  
299     for (Standard_Integer itr=1; itr<=myTriangul->NbTriangles(); itr++)
300     {
301       Standard_Integer n1,n2,n3;
302       triangles(itr).Get(n1,n2,n3);
303       const gp_XY& aPnt2d1 = myNodes2d(n1).XY();
304       const gp_XY& aPnt2d2 = myNodes2d(n2).XY();
305       const gp_XY& aPnt2d3 = myNodes2d(n3).XY();
306       Standard_Real DD = 0.;
307       if (Status (BidPoint, aPnt2d1, aPnt2d2, aPnt2d3, aTol, DD) == 2)
308         continue;
309
310       // compute depth on this triangle
311       gp_XY aUV = getUV (aPnt2d1, aPnt2d2, aPnt2d3, BidPoint);
312       Standard_Real aDepth1 = ElCLib::Parameter (EyeLine, Nodes(n1));
313       Standard_Real aDepth2 = ElCLib::Parameter (EyeLine, Nodes(n2));
314       Standard_Real aDepth3 = ElCLib::Parameter (EyeLine, Nodes(n3));
315       Standard_Real aDepth = aDepth1 + aUV.X() * (aDepth2 - aDepth1) + 
316                                        aUV.Y() * (aDepth3 - aDepth1);
317
318       // take triangle with lowest depth
319       if ( aDepth < aMinDepth )
320       {
321         aMinDepth = aDepth;
322         myDetectedTr = itr;
323         DMin = DD;
324       }
325     }
326   }
327   
328   //    Case only Test on Border of the triangulation...
329   //   
330   else
331   {
332     //Standard_Integer ifirst;
333     TColStd_Array1OfInteger& FreeE = myFreeEdges->ChangeArray1();
334     Standard_Integer nn = FreeE.Length(), Node1,Node2;
335     //Standard_Real LEdg;
336     //Standard_Real DMinDMin,TolTol = aTol*aTol;
337     
338     for (Standard_Integer ifri =1; ifri <= nn && myDetectedTr < 0; ifri+=2)
339     {
340       Node1 = FreeE(ifri);
341       Node2 = FreeE(ifri+1);
342       if (S3D_STriangul_NearSegment (myNodes2d(Node1).XY(),
343                                      myNodes2d(Node2).XY(),
344                                      BidPoint, aTol, DMin) )
345       {
346         for(Standard_Integer itr=1; itr <= myTriangul->NbTriangles(); itr++)
347         {
348           Standard_Integer n1,n2,n3;
349           triangles(itr).Get(n1,n2,n3);
350           if(S3D_IsEdgeIn(Node1,Node2,n1,n2,n3))
351           {
352             myDetectedTr = itr;
353             break; // return first found; selection of closest is not implemented yet
354           }
355         }
356       }
357     }
358   } 
359   if ( myDetectedTr <= 0 )
360     return Standard_False;
361   Select3D_SensitiveEntity::Matches(X,Y,aTol,DMin);
362   return Standard_True;
363 }
364
365
366 //=======================================================================
367 //function : Matches
368 //purpose  : 
369 //=======================================================================
370
371 Standard_Boolean Select3D_SensitiveTriangulation::Matches(const Standard_Real XMin,
372                                                           const Standard_Real YMin,
373                                                           const Standard_Real XMax,
374                                                           const Standard_Real YMax,
375                                                           const Standard_Real aTol) 
376 {
377   Bnd_Box2d B;
378   B.Update(Min(XMin,XMax)-aTol,
379            Min(YMin,YMax)-aTol,
380            Max(XMin,XMax)+aTol,
381            Max(YMin,YMax)+aTol);
382   
383   for(Standard_Integer i=myNodes2d.Lower();i<=myNodes2d.Upper();i++){
384     if(B.IsOut(myNodes2d(i)))
385       return Standard_False;
386   }
387   return Standard_True;
388 }
389
390
391 //=======================================================================
392 //function : Matches
393 //purpose  : 
394 //=======================================================================
395
396 Standard_Boolean Select3D_SensitiveTriangulation::
397 Matches (const TColgp_Array1OfPnt2d& aPoly,
398          const Bnd_Box2d& aBox,
399          const Standard_Real aTol)
400
401   Standard_Real Umin,Vmin,Umax,Vmax;
402   aBox.Get(Umin,Vmin,Umax,Vmax);
403   Standard_Real Tolu,Tolv;
404   Tolu = 1e-7;
405   Tolv = 1e-7;
406   CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
407
408   for(Standard_Integer j=1;j<=myNodes2d.Length();j++){
409     Standard_Integer RES = aClassifier2d.SiDans(myNodes2d(j));
410     if(RES!=1) return Standard_False;
411   }
412   return Standard_True;
413 }
414
415
416
417 Standard_Integer Select3D_SensitiveTriangulation::Status (const gp_XY& TheP,
418                                                           const gp_XY& Proj0,
419                                                           const gp_XY& Proj1,
420                                                           const gp_XY& Proj2,
421                                                           const Standard_Real aTol,
422                                                           Standard_Real& DD) const
423 {
424   return Select3D_SensitiveTriangle::Status(Proj0,Proj1,Proj2,TheP,aTol,DD);
425 }
426
427 //=======================================================================
428 //function : IsFree
429 //purpose  : 
430 //=======================================================================
431
432 Standard_Boolean Select3D_SensitiveTriangulation::IsFree(const Standard_Integer IndexOfTriangle,
433                                                          Standard_Integer& FoundIndex) const
434 {
435
436   FoundIndex=-1;
437   Standard_Integer n[3];
438   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
439   triangles(IndexOfTriangle).Get(n[0],n[1],n[2]);
440     TColStd_Array1OfInteger& FreeE = myFreeEdges->ChangeArray1();
441
442   for(Standard_Integer I=1;I<=FreeE.Length() && FoundIndex==-1;I+=2){
443     
444     if(FreeE(I) == n[0]){
445       
446       if(FreeE(I+1)== n[1] || FreeE(I+1)== n[2]) FoundIndex=I;}
447     else if(FreeE(I) == n[1]){
448       if(FreeE(I+1)== n[0] || FreeE(I+1)== n[2]) FoundIndex=I;}
449     else if(FreeE(I) == n[2]){
450       if(FreeE(I+1)== n[0] || FreeE(I+1)== n[1]) FoundIndex=I;}
451   }
452   
453   return FoundIndex!=-1;
454 }
455
456
457 //=======================================================================
458 //function : GetConnected
459 //purpose  : 
460 //=======================================================================
461 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::
462 GetConnected(const TopLoc_Location& aLoc)
463 {
464   
465   Handle(Select3D_SensitiveTriangulation) NiouEnt = 
466     new Select3D_SensitiveTriangulation(myOwnerId,myTriangul,myiniloc,myFreeEdges,myCDG3D,myIntFlag);
467   
468   if(HasLocation()) NiouEnt->SetLocation(Location());
469 //  TopLoc_Location TheLocToApply = HasLocation() ?  Location()*aLoc : aLoc;
470 //  if(!TheLocToApply.IsIdentity())
471   NiouEnt->UpdateLocation(aLoc);
472     
473
474   return NiouEnt;
475 }
476
477
478 //=======================================================================
479 //function : ResetLocation
480 //purpose  : 
481 //=======================================================================
482 void Select3D_SensitiveTriangulation::ResetLocation() 
483 {
484   Select3D_SensitiveEntity::ResetLocation();
485   ComputeTotalTrsf();
486 }
487 void Select3D_SensitiveTriangulation::SetLocation(const TopLoc_Location& aLoc)
488 {
489   Select3D_SensitiveEntity::SetLocation(aLoc);
490   ComputeTotalTrsf();
491 }
492
493
494 //=======================================================================
495 //function : Dump
496 //purpose  : 
497 //=======================================================================
498 void Select3D_SensitiveTriangulation::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const 
499 {
500   S<<"\tSensitiveTriangulation 3D :"<<endl;
501   if(myiniloc.IsIdentity())
502     S<<"\t\tNo Initial Location"<<endl;
503   else
504     S<<"\t\tExisting Initial Location"<<endl;
505   if(HasLocation())
506     S<<"\t\tExisting Location"<<endl;
507   
508   S<<"\t\tNb Triangles : "<<myTriangul->NbTriangles()<<endl;
509   S<<"\t\tNb Nodes     : "<<myTriangul->NbNodes()<<endl;
510   S<<"\t\tNb Free Edges: "<<myFreeEdges->Length()/2<<endl;
511
512   if(FullDump){
513 //    S<<"\t\t\tOwner:"<<myOwnerId<<endl;
514     Select3D_SensitiveEntity::DumpBox(S,mybox2d);
515   }
516 }
517
518 //=======================================================================
519 //function : ComputeDepth
520 //purpose  :  
521 //=======================================================================
522 Standard_Real Select3D_SensitiveTriangulation::ComputeDepth(const gp_Lin& EyeLine) const
523 {
524   if(myDetectedTr==-1) return Precision::Infinite(); // currently not implemented...
525   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
526   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();  
527   
528   Standard_Integer n1,n2,n3;
529   triangles(myDetectedTr).Get(n1,n2,n3);
530   gp_Pnt P[3]={Nodes(n1),Nodes(n2),Nodes(n3)};
531
532   if(myTrsf.Form()!=gp_Identity){
533     for(Standard_Integer i =0;i<=2;i++){
534       P[i].Transform(myTrsf);
535     }
536   }
537   
538   // formula calculate the parameter of the point on the intersection
539   // t = (P1P2 ^P1P3)* OP1  / ((P1P2^P1P3)*Dir)
540   Standard_Real prof(Precision::Infinite());
541   gp_Pnt Oye  = EyeLine.Location(); // origin of the target line eye/point...
542   gp_Dir Dir  = EyeLine.Direction();
543
544   gp_Vec Vtr[3]; 
545   for(Standard_Integer i=0;i<=2;i++)
546     Vtr[i] = gp_Vec(P[i%3],P[(i+1)%3]);
547   Vtr[2] = -Vtr[2];
548   
549   // remove singular cases immediately...
550   Standard_Integer SingularCase(-1);
551   if(Vtr[0].SquareMagnitude()<= Precision::Confusion())
552     SingularCase = 0;
553   if(Vtr[1].SquareMagnitude()<= Precision::Confusion())
554     SingularCase = (SingularCase == -1) ? 1 : 2;
555 #ifdef BUC60858
556   if(Vtr[2].SquareMagnitude()<= Precision::Confusion())
557     if( SingularCase < 0 ) SingularCase = 1;
558 #endif
559   
560   // 3 pts mixed...
561   if(SingularCase ==2){
562     prof= ElCLib::Parameter(EyeLine,P[0]);
563     return prof;
564   }
565   
566   if(SingularCase!=0)
567     Vtr[0].Normalize();
568   if(SingularCase!=1 &&
569      SingularCase!=2)
570     Vtr[2].Normalize();
571   gp_Vec OPo(Oye,P[0]);
572   // 2 points mixed... the intersection between the segment and the target line eye/point.
573   // 
574   if(SingularCase!=-1){
575     gp_Vec V = SingularCase==0 ? Vtr[2] : Vtr[0];
576     gp_Vec Det = Dir^V;
577     gp_Vec VSM = OPo^V;
578     if(Det.X()> Precision::Confusion())
579       prof = VSM.X()/Det.X();
580     else if (Det.Y()> Precision::Confusion())
581       prof = VSM.Y()/Det.Y();
582     else if(Det.Z()> Precision::Confusion())
583       prof = VSM.Z()/Det.Z();
584   }
585   else{
586     
587     Standard_Real val1 = OPo.DotCross(Vtr[0],Vtr[2]);
588     Standard_Real val2 = Dir.DotCross(Vtr[0],Vtr[2]);
589     
590     if(Abs(val2)>Precision::Confusion())
591       prof =val1/val2;
592   } 
593   if (prof==Precision::Infinite()){
594     prof= ElCLib::Parameter(EyeLine,P[0]);
595     prof = Min (prof, ElCLib::Parameter(EyeLine,P[1]));
596     prof = Min (prof, ElCLib::Parameter(EyeLine,P[2]));
597   }
598   
599   return prof;
600 }
601
602 //=======================================================================
603 //function : DetectedTriangle
604 //purpose  : 
605 //=======================================================================
606 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle(gp_Pnt& P1,
607                                                                    gp_Pnt& P2,
608                                                                    gp_Pnt& P3) const
609 {
610   if(myDetectedTr==-1) return Standard_False; // currently not implemented...
611   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
612   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();  
613   Standard_Integer n1,n2,n3;
614   triangles(myDetectedTr).Get(n1,n2,n3);
615   
616   P1 = Nodes(n1);
617   P2 = Nodes(n2);
618   P3 = Nodes(n3);
619   if(myTrsf.Form()!=gp_Identity){
620     P1.Transform(myTrsf);
621     P2.Transform(myTrsf);
622     P3.Transform(myTrsf);
623   }
624   
625   return Standard_True;
626 }
627
628 //=============================================================================
629 // Function : DetectedTriangle2d
630 // Purpose  : 
631 //=============================================================================
632 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle2d( 
633   gp_Pnt2d& P1, gp_Pnt2d& P2, gp_Pnt2d& P3) const
634 {
635   if(myDetectedTr==-1) 
636     return Standard_False; //  currently not implemented...
637   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
638   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();  
639   Standard_Integer n1,n2,n3;
640   triangles( myDetectedTr ).Get(n1,n2,n3);
641
642   int aLower = myNodes2d.Lower();
643   int anUpper = myNodes2d.Upper();
644   if ( n1 >= aLower && n1 <= anUpper && 
645        n2 >= aLower && n2 <= anUpper &&
646        n3 >= aLower && n3 <= anUpper )
647   {
648     P1 = myNodes2d.Value( n1 );
649     P2 = myNodes2d.Value( n2 );
650     P3 = myNodes2d.Value( n3 );
651     return Standard_True;
652   }
653   else 
654     return Standard_False;
655   
656 }
657
658 void Select3D_SensitiveTriangulation::ComputeTotalTrsf() 
659 {
660   Standard_Boolean hasloc = (HasLocation() || !myiniloc.IsIdentity());
661   
662   if(hasloc){
663     if(myiniloc.IsIdentity())
664       myTrsf = Location().Transformation();
665     else if(HasLocation()){
666       myTrsf = (Location()*myiniloc).Transformation();
667     }
668     else
669       myTrsf = myiniloc.Transformation();
670   }
671   else{
672     gp_Trsf TheId;
673     myTrsf = TheId;
674   }
675 }