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
9 #define BUC60858 //GG 27/03/01 Avoid to crash when selecting
10 // a triangle containing confused or aligned points.
12 #include <Select3D_SensitiveTriangulation.ixx>
13 #include <gp_Pnt2d.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>
21 #include <CSLib_Class2d.hxx>
24 static Standard_Integer S3D_NumberOfFreeEdges(const Handle(Poly_Triangulation)& Trg)
26 Standard_Integer nFree = 0;
28 Standard_Integer t[3];
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++;
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)
43 B.Update(p1.X(),p1.Y());
45 if(B.IsOut(TheP)) return Standard_False;
47 gp_XY V01(p1);V01-=p0;
48 gp_XY Vec(TheP);Vec -= p0;
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;
56 gp_XY N01 (-V01.Y(),V01.X());
58 aDMin = Abs (Vec * N01);
62 // static Standard_Real S3D_SquareDistanceFromEdge(gp_Pnt2d PCur,
65 // const Standard_Real TolTol)
67 // gp_XY VEdg (PEdg1.XY());
68 // gp_XY VCur (PEdg1.XY());
71 // Standard_Real long1 = VEdg.SquareModulus();
74 // return VCur.SquareModulus();
75 // Standard_Real Val = VEdg^VCur;
76 // return Val*Val/long1;
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)
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));
90 if(bid2==0 || bid2 ==bid1) return Standard_False;
96 //=======================================================================
97 //function : Select3D_SensitiveTriangulation
99 //=======================================================================
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),
109 myIntFlag(InteriorFlag),
110 myNodes2d(1,Trg->NbNodes()),
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...
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());
122 Standard_Integer n[3];
124 // pour rechercher les connexions dans le cas ou on ne s'occupe de la frontiere...
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;
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.;
153 if(nbTriangles!=0) cdg /= nbTriangles;
154 myCDG3D = gp_Pnt(cdg);
158 if(myTrsf.Form()!=gp_Identity)
159 myCDG3D.Transform(myTrsf);
163 //=======================================================================
164 //function : Select3D_SensitiveTriangulation
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),
178 myFreeEdges(FreeEdges),
179 myIntFlag(InteriorFlag),
180 myNodes2d(1,Trg->NbNodes()),
184 //=======================================================================
187 //=======================================================================
189 void Select3D_SensitiveTriangulation::Project(const Handle(Select3D_Projector)& aPrj)
191 Select3D_SensitiveEntity::Project(aPrj); // to set the field last proj...
194 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
198 for(Standard_Integer I=1;I<=myTriangul->NbNodes();I++){
199 if(myTrsf.Form()!=gp_Identity)
200 aPrj->Project(Nodes(I).Transformed(myTrsf),ProjPT);
202 aPrj->Project(Nodes(I),ProjPT);
204 myNodes2d.SetValue(I,ProjPT);
208 aPrj->Project(myCDG3D,myCDG2D);
211 //=======================================================================
214 //=======================================================================
216 void Select3D_SensitiveTriangulation::Areas(SelectBasics_ListOfBox2d& boxes)
218 boxes.Append(mybox2d);
221 //=======================================================================
224 //=======================================================================
225 Standard_Boolean Select3D_SensitiveTriangulation::Matches(const Standard_Real X,
226 const Standard_Real Y,
227 const Standard_Real aTol,
230 // get view direction (necessary for calculation of depth) from field mylastprj of the base class
231 if (mylastprj.IsNull())
232 return Standard_False;
234 DMin = Precision::Infinite();
237 const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
239 // on regarde si on est a l'interieur d'1 triangle 2d.
242 gp_Lin EyeLine = mylastprj->Shoot(X,Y);
243 if ( myTrsf.Form()!=gp_Identity )
244 EyeLine.Transform (myTrsf.Inverted());
246 Standard_Real aMinDepth = Precision::Infinite();
247 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
248 for (Standard_Integer itr=1; itr<=myTriangul->NbTriangles(); itr++)
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();
256 Standard_Real aDistSquare = Poly::PointOnTriangle (aPnt2d1, aPnt2d2, aPnt2d3, BidPoint, aUV);
257 if ( aDistSquare > aTol * aTol )
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);
267 // take triangle with lowest depth and within defined depth interval
268 if (aDepth < aMinDepth &&
269 aDepth > mylastprj->DepthMin() &&
270 aDepth < mylastprj->DepthMax())
274 DMin = Sqrt (aDistSquare);
279 // Cas Uniquement Test sur Frontiere de la triangulation...
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;
289 for (Standard_Integer ifri =1; ifri <= nn && myDetectedTr < 0; ifri+=2)
292 Node2 = FreeE(ifri+1);
293 if (S3D_STriangul_NearSegment (myNodes2d(Node1).XY(),
294 myNodes2d(Node2).XY(),
295 BidPoint, aTol, DMin) )
297 for(Standard_Integer itr=1; itr <= myTriangul->NbTriangles(); itr++)
299 Standard_Integer n1,n2,n3;
300 triangles(itr).Get(n1,n2,n3);
301 if(S3D_IsEdgeIn(Node1,Node2,n1,n2,n3))
304 break; // return first found; selection of closest is not implemented yet
310 if ( myDetectedTr <= 0 )
311 return Standard_False;
313 // compute and validate the depth (::Depth()) along the eyeline
314 return Select3D_SensitiveEntity::Matches(X,Y,aTol,DMin);
318 //=======================================================================
321 //=======================================================================
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)
330 B.Update(Min(XMin,XMax)-aTol,
333 Max(YMin,YMax)+aTol);
335 for(Standard_Integer i=myNodes2d.Lower();i<=myNodes2d.Upper();i++){
336 if(B.IsOut(myNodes2d(i)))
337 return Standard_False;
339 return Standard_True;
343 //=======================================================================
346 //=======================================================================
348 Standard_Boolean Select3D_SensitiveTriangulation::
349 Matches (const TColgp_Array1OfPnt2d& aPoly,
350 const Bnd_Box2d& aBox,
351 const Standard_Real aTol)
353 Standard_Real Umin,Vmin,Umax,Vmax;
354 aBox.Get(Umin,Vmin,Umax,Vmax);
355 Standard_Real Tolu,Tolv;
358 CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
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;
364 return Standard_True;
369 Standard_Integer Select3D_SensitiveTriangulation::Status (const gp_XY& TheP,
373 const Standard_Real aTol,
374 Standard_Real& DD) const
376 return Select3D_SensitiveTriangle::Status(Proj0,Proj1,Proj2,TheP,aTol,DD);
379 //=======================================================================
382 //=======================================================================
384 Standard_Boolean Select3D_SensitiveTriangulation::IsFree(const Standard_Integer IndexOfTriangle,
385 Standard_Integer& FoundIndex) const
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();
394 for(Standard_Integer I=1;I<=FreeE.Length() && FoundIndex==-1;I+=2){
396 if(FreeE(I) == n[0]){
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;}
405 return FoundIndex!=-1;
409 //=======================================================================
410 //function : GetConnected
412 //=======================================================================
413 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::
414 GetConnected(const TopLoc_Location& aLoc)
417 Handle(Select3D_SensitiveTriangulation) NiouEnt =
418 new Select3D_SensitiveTriangulation(myOwnerId,myTriangul,myiniloc,myFreeEdges,myCDG3D,myIntFlag);
420 if(HasLocation()) NiouEnt->SetLocation(Location());
421 // TopLoc_Location TheLocToApply = HasLocation() ? Location()*aLoc : aLoc;
422 // if(!TheLocToApply.IsIdentity())
423 NiouEnt->UpdateLocation(aLoc);
430 //=======================================================================
431 //function : ResetLocation
433 //=======================================================================
434 void Select3D_SensitiveTriangulation::ResetLocation()
436 Select3D_SensitiveEntity::ResetLocation();
439 void Select3D_SensitiveTriangulation::SetLocation(const TopLoc_Location& aLoc)
441 Select3D_SensitiveEntity::SetLocation(aLoc);
446 //=======================================================================
449 //=======================================================================
450 void Select3D_SensitiveTriangulation::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
452 S<<"\tSensitiveTriangulation 3D :"<<endl;
453 if(myiniloc.IsIdentity())
454 S<<"\t\tNo Initial Location"<<endl;
456 S<<"\t\tExisting Initial Location"<<endl;
458 S<<"\t\tExisting Location"<<endl;
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;
465 // S<<"\t\t\tOwner:"<<myOwnerId<<endl;
466 Select3D_SensitiveEntity::DumpBox(S,mybox2d);
470 //=======================================================================
471 //function : ComputeDepth
473 //=======================================================================
474 Standard_Real Select3D_SensitiveTriangulation::ComputeDepth(const gp_Lin& EyeLine) const
476 if(myDetectedTr==-1) return Precision::Infinite(); // non implemente actuellement...
477 const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
478 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
480 Standard_Integer n1,n2,n3;
481 triangles(myDetectedTr).Get(n1,n2,n3);
482 gp_Pnt P[3]={Nodes(n1),Nodes(n2),Nodes(n3)};
484 if(myTrsf.Form()!=gp_Identity){
485 for(Standard_Integer i =0;i<=2;i++){
486 P[i].Transform(myTrsf);
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();
497 for(Standard_Integer i=0;i<=2;i++)
498 Vtr[i] = gp_Vec(P[i%3],P[(i+1)%3]);
501 // eliminons tout de suite les cas singuliers...
502 Standard_Integer SingularCase(-1);
503 if(Vtr[0].SquareMagnitude()<= Precision::Confusion())
505 if(Vtr[1].SquareMagnitude()<= Precision::Confusion())
506 SingularCase = (SingularCase == -1) ? 1 : 2;
508 if(Vtr[2].SquareMagnitude()<= Precision::Confusion())
509 if( SingularCase < 0 ) SingularCase = 1;
512 // 3 pts confondus...
513 if(SingularCase ==2){
514 prof= ElCLib::Parameter(EyeLine,P[0]);
520 if(SingularCase!=1 &&
523 gp_Vec OPo(Oye,P[0]);
524 // 2 points confondus... on recherche l'intersection entre le segment et la ligne oeil/point vise.
526 if(SingularCase!=-1){
527 gp_Vec V = SingularCase==0 ? Vtr[2] : Vtr[0];
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();
539 Standard_Real val1 = OPo.DotCross(Vtr[0],Vtr[2]);
540 Standard_Real val2 = Dir.DotCross(Vtr[0],Vtr[2]);
542 if(Abs(val2)>Precision::Confusion())
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]));
554 //=======================================================================
555 //function : DetectedTriangle
557 //=======================================================================
558 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle(gp_Pnt& P1,
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);
571 if(myTrsf.Form()!=gp_Identity){
572 P1.Transform(myTrsf);
573 P2.Transform(myTrsf);
574 P3.Transform(myTrsf);
577 return Standard_True;
580 //=============================================================================
581 // Function : DetectedTriangle2d
583 //=============================================================================
584 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle2d(
585 gp_Pnt2d& P1, gp_Pnt2d& P2, gp_Pnt2d& P3) const
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);
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 )
600 P1 = myNodes2d.Value( n1 );
601 P2 = myNodes2d.Value( n2 );
602 P3 = myNodes2d.Value( n3 );
603 return Standard_True;
606 return Standard_False;
610 void Select3D_SensitiveTriangulation::ComputeTotalTrsf()
612 Standard_Boolean hasloc = (HasLocation() || !myiniloc.IsIdentity());
615 if(myiniloc.IsIdentity())
616 myTrsf = Location().Transformation();
617 else if(HasLocation()){
618 myTrsf = (Location()*myiniloc).Transformation();
621 myTrsf = myiniloc.Transformation();