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