OCC22357 Hidden face selection
[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
96 //=======================================================================
97 //function : Select3D_SensitiveTriangulation
98 //purpose  :
99 //=======================================================================
100
101 Select3D_SensitiveTriangulation::
102 Select3D_SensitiveTriangulation(const Handle(SelectBasics_EntityOwner)& OwnerId,
103                                 const Handle(Poly_Triangulation)& Trg,
104                                 const TopLoc_Location& Loc,
105                                 const Standard_Boolean InteriorFlag):
106                                 Select3D_SensitiveEntity(OwnerId),
107 myTriangul(Trg),
108 myiniloc(Loc),
109 myIntFlag(InteriorFlag),
110 myNodes2d(1,Trg->NbNodes()),
111 myDetectedTr(-1)
112 {
113   // Code honteusement vole a DBRep_DrawableShape::Display...
114   // calcul des edges libres et du cdg 3d de la triangulation:
115   // Ce code devrait, pour plus de facilites etre integre dans la poly_triangulation...
116
117   Standard_Integer fr = 1;
118   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
119   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
120   Standard_Integer nbTriangles (myTriangul->NbTriangles());
121   gp_XYZ cdg(0,0,0);
122   Standard_Integer n[3];
123
124   // pour rechercher les connexions dans le cas ou on ne s'occupe de la frontiere...
125   if(!myIntFlag){
126     myFreeEdges = new TColStd_HArray1OfInteger(1,2*S3D_NumberOfFreeEdges(Trg));
127     TColStd_Array1OfInteger& FreeE = myFreeEdges->ChangeArray1();
128     Poly_Connect pc(myTriangul);
129     Standard_Integer t[3];
130     Standard_Integer i,j;
131     for ( i = 1; i <= nbTriangles; i++) {
132       pc.Triangles(i,t[0],t[1],t[2]);
133       triangles(i).Get(n[0],n[1],n[2]);
134       cdg += (Nodes(n[0]).XYZ() + Nodes(n[1]).XYZ()+ Nodes(n[2]).XYZ())/3.;
135       for (j = 0; j < 3; j++) {
136         Standard_Integer k = (j+1) % 3;
137         if (t[j] == 0) {
138           FreeE(fr)  = n[j];
139           FreeE(fr+1)= n[k];
140           fr += 2;
141         }
142       }
143     }
144   }
145   else{
146     for (Standard_Integer i = 1; i <= nbTriangles; i++) {
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     }
150   }
151
152
153   if(nbTriangles!=0) cdg /= nbTriangles;
154   myCDG3D = gp_Pnt(cdg);
155
156   ComputeTotalTrsf();
157
158   if(myTrsf.Form()!=gp_Identity)
159     myCDG3D.Transform(myTrsf);
160 }
161
162
163 //=======================================================================
164 //function : Select3D_SensitiveTriangulation
165 //purpose  :
166 //=======================================================================
167 Select3D_SensitiveTriangulation::
168 Select3D_SensitiveTriangulation(const Handle(SelectBasics_EntityOwner)& OwnerId,
169                                 const Handle(Poly_Triangulation)& Trg,
170                                 const TopLoc_Location& Loc,
171                                 const Handle(TColStd_HArray1OfInteger)& FreeEdges,
172                                 const gp_Pnt& TheCDG,
173                                 const Standard_Boolean InteriorFlag):
174 Select3D_SensitiveEntity(OwnerId),
175 myTriangul(Trg),
176 myiniloc(Loc),
177 myCDG3D(TheCDG),
178 myFreeEdges(FreeEdges),
179 myIntFlag(InteriorFlag),
180 myNodes2d(1,Trg->NbNodes()),
181 myDetectedTr(-1)
182 {
183 }
184 //=======================================================================
185 //function : Project
186 //purpose  :
187 //=======================================================================
188
189 void Select3D_SensitiveTriangulation::Project(const Handle(Select3D_Projector)& aPrj)
190 {
191   Select3D_SensitiveEntity::Project(aPrj); // to set the field last proj...
192
193   mybox2d.SetVoid();
194   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
195
196   gp_Pnt2d ProjPT;
197
198   for(Standard_Integer I=1;I<=myTriangul->NbNodes();I++){
199     if(myTrsf.Form()!=gp_Identity)
200       aPrj->Project(Nodes(I).Transformed(myTrsf),ProjPT);
201     else
202       aPrj->Project(Nodes(I),ProjPT);
203
204     myNodes2d.SetValue(I,ProjPT);
205     mybox2d.Add(ProjPT);
206   }
207
208   aPrj->Project(myCDG3D,myCDG2D);
209 }
210
211 //=======================================================================
212 //function : Areas
213 //purpose  :
214 //=======================================================================
215
216 void Select3D_SensitiveTriangulation::Areas(SelectBasics_ListOfBox2d& boxes)
217 {
218   boxes.Append(mybox2d);
219 }
220
221 //=======================================================================
222 //function : Matches
223 //purpose  :
224 //=======================================================================
225 Standard_Boolean Select3D_SensitiveTriangulation::Matches(const Standard_Real X,
226                                                           const Standard_Real Y,
227                                                           const Standard_Real aTol,
228                                                           Standard_Real& DMin)
229 {
230   // get view direction (necessary for calculation of depth) from field mylastprj of the base class
231   if (mylastprj.IsNull())
232     return Standard_False;
233
234   DMin = Precision::Infinite();
235   gp_XY BidPoint(X,Y);
236   myDetectedTr = -1;
237   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
238
239   // on regarde si on est a l'interieur d'1 triangle 2d.
240   if(myIntFlag)
241   {
242     gp_Lin EyeLine = mylastprj->Shoot(X,Y);
243     if ( myTrsf.Form()!=gp_Identity )
244       EyeLine.Transform (myTrsf.Inverted());
245
246     Standard_Real aMinDepth = Precision::Infinite();
247     const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
248     for (Standard_Integer itr=1; itr<=myTriangul->NbTriangles(); itr++)
249     {
250       Standard_Integer n1,n2,n3;
251       triangles(itr).Get(n1,n2,n3);
252       const gp_XY& aPnt2d1 = myNodes2d(n1).XY();
253       const gp_XY& aPnt2d2 = myNodes2d(n2).XY();
254       const gp_XY& aPnt2d3 = myNodes2d(n3).XY();
255       gp_XY aUV;
256       Standard_Real aDistSquare = Poly::PointOnTriangle (aPnt2d1, aPnt2d2, aPnt2d3, BidPoint, aUV);
257       if ( aDistSquare > aTol * aTol )
258         continue;
259
260       // compute depth on this triangle
261       Standard_Real aDepth1 = ElCLib::Parameter (EyeLine, Nodes(n1));
262       Standard_Real aDepth2 = ElCLib::Parameter (EyeLine, Nodes(n2));
263       Standard_Real aDepth3 = ElCLib::Parameter (EyeLine, Nodes(n3));
264       Standard_Real aDepth = aDepth1 + aUV.X() * (aDepth2 - aDepth1) +
265                                        aUV.Y() * (aDepth3 - aDepth1);
266
267       // take triangle with lowest depth and within defined depth interval
268       if (aDepth < aMinDepth &&
269           aDepth > mylastprj->DepthMin() &&
270           aDepth < mylastprj->DepthMax())
271       {
272         aMinDepth = aDepth;
273         myDetectedTr = itr;
274         DMin = Sqrt (aDistSquare);
275       }
276     }
277   }
278
279   //    Cas Uniquement Test sur Frontiere de la triangulation...
280   //
281   else
282   {
283     //Standard_Integer ifirst;
284     TColStd_Array1OfInteger& FreeE = myFreeEdges->ChangeArray1();
285     Standard_Integer nn = FreeE.Length(), Node1,Node2;
286     //Standard_Real LEdg;
287     //Standard_Real DMinDMin,TolTol = aTol*aTol;
288
289     for (Standard_Integer ifri =1; ifri <= nn && myDetectedTr < 0; ifri+=2)
290     {
291       Node1 = FreeE(ifri);
292       Node2 = FreeE(ifri+1);
293       if (S3D_STriangul_NearSegment (myNodes2d(Node1).XY(),
294                                      myNodes2d(Node2).XY(),
295                                      BidPoint, aTol, DMin) )
296       {
297         for(Standard_Integer itr=1; itr <= myTriangul->NbTriangles(); itr++)
298         {
299           Standard_Integer n1,n2,n3;
300           triangles(itr).Get(n1,n2,n3);
301           if(S3D_IsEdgeIn(Node1,Node2,n1,n2,n3))
302           {
303             myDetectedTr = itr;
304             break; // return first found; selection of closest is not implemented yet
305           }
306         }
307       }
308     }
309   }
310   if ( myDetectedTr <= 0 )
311     return Standard_False;
312
313   // compute and validate the depth (::Depth()) along the eyeline
314   return Select3D_SensitiveEntity::Matches(X,Y,aTol,DMin);
315 }
316
317
318 //=======================================================================
319 //function : Matches
320 //purpose  :
321 //=======================================================================
322
323 Standard_Boolean Select3D_SensitiveTriangulation::Matches(const Standard_Real XMin,
324                                                           const Standard_Real YMin,
325                                                           const Standard_Real XMax,
326                                                           const Standard_Real YMax,
327                                                           const Standard_Real aTol)
328 {
329   Bnd_Box2d B;
330   B.Update(Min(XMin,XMax)-aTol,
331            Min(YMin,YMax)-aTol,
332            Max(XMin,XMax)+aTol,
333            Max(YMin,YMax)+aTol);
334
335   for(Standard_Integer i=myNodes2d.Lower();i<=myNodes2d.Upper();i++){
336     if(B.IsOut(myNodes2d(i)))
337       return Standard_False;
338   }
339   return Standard_True;
340 }
341
342
343 //=======================================================================
344 //function : Matches
345 //purpose  :
346 //=======================================================================
347
348 Standard_Boolean Select3D_SensitiveTriangulation::
349 Matches (const TColgp_Array1OfPnt2d& aPoly,
350          const Bnd_Box2d& aBox,
351          const Standard_Real aTol)
352 {
353   Standard_Real Umin,Vmin,Umax,Vmax;
354   aBox.Get(Umin,Vmin,Umax,Vmax);
355   Standard_Real Tolu,Tolv;
356   Tolu = 1e-7;
357   Tolv = 1e-7;
358   CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
359
360   for(Standard_Integer j=1;j<=myNodes2d.Length();j++){
361     Standard_Integer RES = aClassifier2d.SiDans(myNodes2d(j));
362     if(RES!=1) return Standard_False;
363   }
364   return Standard_True;
365 }
366
367
368
369 Standard_Integer Select3D_SensitiveTriangulation::Status (const gp_XY& TheP,
370                                                           const gp_XY& Proj0,
371                                                           const gp_XY& Proj1,
372                                                           const gp_XY& Proj2,
373                                                           const Standard_Real aTol,
374                                                           Standard_Real& DD) const
375 {
376   return Select3D_SensitiveTriangle::Status(Proj0,Proj1,Proj2,TheP,aTol,DD);
377 }
378
379 //=======================================================================
380 //function : IsFree
381 //purpose  :
382 //=======================================================================
383
384 Standard_Boolean Select3D_SensitiveTriangulation::IsFree(const Standard_Integer IndexOfTriangle,
385                                                          Standard_Integer& FoundIndex) const
386 {
387
388   FoundIndex=-1;
389   Standard_Integer n[3];
390   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
391   triangles(IndexOfTriangle).Get(n[0],n[1],n[2]);
392     TColStd_Array1OfInteger& FreeE = myFreeEdges->ChangeArray1();
393
394   for(Standard_Integer I=1;I<=FreeE.Length() && FoundIndex==-1;I+=2){
395
396     if(FreeE(I) == n[0]){
397
398       if(FreeE(I+1)== n[1] || FreeE(I+1)== n[2]) FoundIndex=I;}
399     else if(FreeE(I) == n[1]){
400       if(FreeE(I+1)== n[0] || FreeE(I+1)== n[2]) FoundIndex=I;}
401     else if(FreeE(I) == n[2]){
402       if(FreeE(I+1)== n[0] || FreeE(I+1)== n[1]) FoundIndex=I;}
403   }
404
405   return FoundIndex!=-1;
406 }
407
408
409 //=======================================================================
410 //function : GetConnected
411 //purpose  :
412 //=======================================================================
413 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::
414 GetConnected(const TopLoc_Location& aLoc)
415 {
416
417   Handle(Select3D_SensitiveTriangulation) NiouEnt =
418     new Select3D_SensitiveTriangulation(myOwnerId,myTriangul,myiniloc,myFreeEdges,myCDG3D,myIntFlag);
419
420   if(HasLocation()) NiouEnt->SetLocation(Location());
421 //  TopLoc_Location TheLocToApply = HasLocation() ?  Location()*aLoc : aLoc;
422 //  if(!TheLocToApply.IsIdentity())
423   NiouEnt->UpdateLocation(aLoc);
424
425
426   return NiouEnt;
427 }
428
429
430 //=======================================================================
431 //function : ResetLocation
432 //purpose  :
433 //=======================================================================
434 void Select3D_SensitiveTriangulation::ResetLocation()
435 {
436   Select3D_SensitiveEntity::ResetLocation();
437   ComputeTotalTrsf();
438 }
439 void Select3D_SensitiveTriangulation::SetLocation(const TopLoc_Location& aLoc)
440 {
441   Select3D_SensitiveEntity::SetLocation(aLoc);
442   ComputeTotalTrsf();
443 }
444
445
446 //=======================================================================
447 //function : Dump
448 //purpose  :
449 //=======================================================================
450 void Select3D_SensitiveTriangulation::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
451 {
452   S<<"\tSensitiveTriangulation 3D :"<<endl;
453   if(myiniloc.IsIdentity())
454     S<<"\t\tNo Initial Location"<<endl;
455   else
456     S<<"\t\tExisting Initial Location"<<endl;
457   if(HasLocation())
458     S<<"\t\tExisting Location"<<endl;
459
460   S<<"\t\tNb Triangles : "<<myTriangul->NbTriangles()<<endl;
461   S<<"\t\tNb Nodes     : "<<myTriangul->NbNodes()<<endl;
462   S<<"\t\tNb Free Edges: "<<myFreeEdges->Length()/2<<endl;
463
464   if(FullDump){
465 //    S<<"\t\t\tOwner:"<<myOwnerId<<endl;
466     Select3D_SensitiveEntity::DumpBox(S,mybox2d);
467   }
468 }
469
470 //=======================================================================
471 //function : ComputeDepth
472 //purpose  :
473 //=======================================================================
474 Standard_Real Select3D_SensitiveTriangulation::ComputeDepth(const gp_Lin& EyeLine) const
475 {
476   if(myDetectedTr==-1) return Precision::Infinite(); // non implemente actuellement...
477   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
478   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
479
480   Standard_Integer n1,n2,n3;
481   triangles(myDetectedTr).Get(n1,n2,n3);
482   gp_Pnt P[3]={Nodes(n1),Nodes(n2),Nodes(n3)};
483
484   if(myTrsf.Form()!=gp_Identity){
485     for(Standard_Integer i =0;i<=2;i++){
486       P[i].Transform(myTrsf);
487     }
488   }
489
490   // formule calcul du parametre du point sur l'intersection
491   // t = (P1P2 ^P1P3)* OP1  / ((P1P2^P1P3)*Dir)
492   Standard_Real prof(Precision::Infinite());
493   gp_Pnt Oye  = EyeLine.Location(); // origine de la ligne oeil/point vise...
494   gp_Dir Dir  = EyeLine.Direction();
495
496   gp_Vec Vtr[3];
497   for(Standard_Integer i=0;i<=2;i++)
498     Vtr[i] = gp_Vec(P[i%3],P[(i+1)%3]);
499   Vtr[2] = -Vtr[2];
500
501   // eliminons tout de suite les cas singuliers...
502   Standard_Integer SingularCase(-1);
503   if(Vtr[0].SquareMagnitude()<= Precision::Confusion())
504     SingularCase = 0;
505   if(Vtr[1].SquareMagnitude()<= Precision::Confusion())
506     SingularCase = (SingularCase == -1) ? 1 : 2;
507 #ifdef BUC60858
508   if(Vtr[2].SquareMagnitude()<= Precision::Confusion())
509     if( SingularCase < 0 ) SingularCase = 1;
510 #endif
511
512   // 3 pts confondus...
513   if(SingularCase ==2){
514     prof= ElCLib::Parameter(EyeLine,P[0]);
515     return prof;
516   }
517
518   if(SingularCase!=0)
519     Vtr[0].Normalize();
520   if(SingularCase!=1 &&
521      SingularCase!=2)
522     Vtr[2].Normalize();
523   gp_Vec OPo(Oye,P[0]);
524   // 2 points confondus... on recherche l'intersection entre le segment et la ligne oeil/point vise.
525   //
526   if(SingularCase!=-1){
527     gp_Vec V = SingularCase==0 ? Vtr[2] : Vtr[0];
528     gp_Vec Det = Dir^V;
529     gp_Vec VSM = OPo^V;
530     if(Det.X()> Precision::Confusion())
531       prof = VSM.X()/Det.X();
532     else if (Det.Y()> Precision::Confusion())
533       prof = VSM.Y()/Det.Y();
534     else if(Det.Z()> Precision::Confusion())
535       prof = VSM.Z()/Det.Z();
536   }
537   else{
538
539     Standard_Real val1 = OPo.DotCross(Vtr[0],Vtr[2]);
540     Standard_Real val2 = Dir.DotCross(Vtr[0],Vtr[2]);
541
542     if(Abs(val2)>Precision::Confusion())
543       prof =val1/val2;
544   }
545   if (prof==Precision::Infinite()){
546     prof= ElCLib::Parameter(EyeLine,P[0]);
547     prof = Min (prof, ElCLib::Parameter(EyeLine,P[1]));
548     prof = Min (prof, ElCLib::Parameter(EyeLine,P[2]));
549   }
550
551   return prof;
552 }
553
554 //=======================================================================
555 //function : DetectedTriangle
556 //purpose  :
557 //=======================================================================
558 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle(gp_Pnt& P1,
559                                                                    gp_Pnt& P2,
560                                                                    gp_Pnt& P3) const
561 {
562   if(myDetectedTr==-1) return Standard_False; // non implemente actuellement...
563   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
564   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
565   Standard_Integer n1,n2,n3;
566   triangles(myDetectedTr).Get(n1,n2,n3);
567
568   P1 = Nodes(n1);
569   P2 = Nodes(n2);
570   P3 = Nodes(n3);
571   if(myTrsf.Form()!=gp_Identity){
572     P1.Transform(myTrsf);
573     P2.Transform(myTrsf);
574     P3.Transform(myTrsf);
575   }
576
577   return Standard_True;
578 }
579
580 //=============================================================================
581 // Function : DetectedTriangle2d
582 // Purpose  :
583 //=============================================================================
584 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle2d(
585   gp_Pnt2d& P1, gp_Pnt2d& P2, gp_Pnt2d& P3) const
586 {
587   if(myDetectedTr==-1)
588     return Standard_False; // non implemente actuellement...
589   const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
590   const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
591   Standard_Integer n1,n2,n3;
592   triangles( myDetectedTr ).Get(n1,n2,n3);
593
594   int aLower = myNodes2d.Lower();
595   int anUpper = myNodes2d.Upper();
596   if ( n1 >= aLower && n1 <= anUpper &&
597        n2 >= aLower && n2 <= anUpper &&
598        n3 >= aLower && n3 <= anUpper )
599   {
600     P1 = myNodes2d.Value( n1 );
601     P2 = myNodes2d.Value( n2 );
602     P3 = myNodes2d.Value( n3 );
603     return Standard_True;
604   }
605   else
606     return Standard_False;
607
608 }
609
610 void Select3D_SensitiveTriangulation::ComputeTotalTrsf()
611 {
612   Standard_Boolean hasloc = (HasLocation() || !myiniloc.IsIdentity());
613
614   if(hasloc){
615     if(myiniloc.IsIdentity())
616       myTrsf = Location().Transformation();
617     else if(HasLocation()){
618       myTrsf = (Location()*myiniloc).Transformation();
619     }
620     else
621       myTrsf = myiniloc.Transformation();
622   }
623   else{
624     gp_Trsf TheId;
625     myTrsf = TheId;
626   }
627 }