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