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>
14 #include <Poly_Connect.hxx>
15 #include <CSLib_Class2d.hxx>
16 #include <TColStd_Array1OfInteger.hxx>
17 #include <Select3D_SensitiveTriangle.hxx>
18 #include <Precision.hxx>
20 #include <CSLib_Class2d.hxx>
23 static Standard_Integer S3D_NumberOfFreeEdges(const Handle(Poly_Triangulation)& Trg)
25 Standard_Integer nFree = 0;
27 Standard_Integer t[3];
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++;
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)
42 B.Update(p1.X(),p1.Y());
44 if(B.IsOut(TheP)) return Standard_False;
46 gp_XY V01(p1);V01-=p0;
47 gp_XY Vec(TheP);Vec -= p0;
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;
55 gp_XY N01 (-V01.Y(),V01.X());
57 aDMin = Abs (Vec * N01);
61 // static Standard_Real S3D_SquareDistanceFromEdge(gp_Pnt2d PCur,
64 // const Standard_Real TolTol)
66 // gp_XY VEdg (PEdg1.XY());
67 // gp_XY VCur (PEdg1.XY());
70 // Standard_Real long1 = VEdg.SquareModulus();
73 // return VCur.SquareModulus();
74 // Standard_Real Val = VEdg^VCur;
75 // return Val*Val/long1;
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)
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));
89 if(bid2==0 || bid2 ==bid1) return Standard_False;
95 //=======================================================================
96 //function : Select3D_SensitiveTriangulation
98 //=======================================================================
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),
108 myIntFlag(InteriorFlag),
109 myNodes2d(1,Trg->NbNodes()),
112 // calculate free edges and cdg 3d of the triangulation:
113 // This code should have been integrated in poly_triangulation...
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());
120 Standard_Integer n[3];
122 // to find connections in case when the border is not concerned...
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;
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.;
151 if(nbTriangles!=0) cdg /= nbTriangles;
152 myCDG3D = gp_Pnt(cdg);
156 if(myTrsf.Form()!=gp_Identity)
157 myCDG3D.Transform(myTrsf);
161 //=======================================================================
162 //function : Select3D_SensitiveTriangulation
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),
176 myFreeEdges(FreeEdges),
177 myIntFlag(InteriorFlag),
178 myNodes2d(1,Trg->NbNodes()),
182 //=======================================================================
185 //=======================================================================
187 void Select3D_SensitiveTriangulation::Project(const Select3D_Projector& aPrj)
189 Select3D_SensitiveEntity::Project(aPrj); // to set the field last proj...
192 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
196 for(Standard_Integer I=1;I<=myTriangul->NbNodes();I++){
197 if(myTrsf.Form()!=gp_Identity)
198 aPrj.Project(Nodes(I).Transformed(myTrsf),ProjPT);
200 aPrj.Project(Nodes(I),ProjPT);
202 myNodes2d.SetValue(I,ProjPT);
206 aPrj.Project(myCDG3D,myCDG2D);
209 //=======================================================================
212 //=======================================================================
214 void Select3D_SensitiveTriangulation::Areas(SelectBasics_ListOfBox2d& boxes)
216 boxes.Append(mybox2d);
219 //=======================================================================
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 //=======================================================================
227 static gp_XY getUV (const gp_XY& aP2d1, const gp_XY& aP2d2, const gp_XY& aP2d3,
230 gp_XY aDU = aP2d2 - aP2d1;
231 gp_XY aDV = aP2d3 - aP2d1;
232 Standard_Real aDet = aDU ^ aDV;
234 // case of non-degenerated triangle
235 gp_XY aDP = aPick - aP2d1;
236 if ( Abs (aDet) > gp::Resolution() )
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);
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
251 if ( aL2V < gp::Resolution() ) // whole triangle is degenerated to point
252 return gp_XY (0., 0.);
254 return gp_XY (0., (aDP * aDV) / aL2V);
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
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.);
268 return gp_XY (0., (aDP * aDV) / aL2V);
272 //=======================================================================
275 //=======================================================================
276 Standard_Boolean Select3D_SensitiveTriangulation::Matches(const Standard_Real X,
277 const Standard_Real Y,
278 const Standard_Real aTol,
281 // get view direction (necessary for calculation of depth) from field mylastprj of the base class
283 return Standard_False;
285 DMin = Precision::Infinite();
288 const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
290 // it is checked if we are inside the triangle 2d.
293 gp_Lin EyeLine = (*((Select3D_Projector*)mylastprj)).Shoot(X,Y);
294 if ( myTrsf.Form()!=gp_Identity )
295 EyeLine.Transform (myTrsf.Inverted());
297 Standard_Real aMinDepth = Precision::Infinite();
298 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
299 for (Standard_Integer itr=1; itr<=myTriangul->NbTriangles(); itr++)
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)
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);
318 // take triangle with lowest depth
319 if ( aDepth < aMinDepth )
328 // Case only Test on Border of the triangulation...
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;
338 for (Standard_Integer ifri =1; ifri <= nn && myDetectedTr < 0; ifri+=2)
341 Node2 = FreeE(ifri+1);
342 if (S3D_STriangul_NearSegment (myNodes2d(Node1).XY(),
343 myNodes2d(Node2).XY(),
344 BidPoint, aTol, DMin) )
346 for(Standard_Integer itr=1; itr <= myTriangul->NbTriangles(); itr++)
348 Standard_Integer n1,n2,n3;
349 triangles(itr).Get(n1,n2,n3);
350 if(S3D_IsEdgeIn(Node1,Node2,n1,n2,n3))
353 break; // return first found; selection of closest is not implemented yet
359 if ( myDetectedTr <= 0 )
360 return Standard_False;
361 Select3D_SensitiveEntity::Matches(X,Y,aTol,DMin);
362 return Standard_True;
366 //=======================================================================
369 //=======================================================================
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)
378 B.Update(Min(XMin,XMax)-aTol,
381 Max(YMin,YMax)+aTol);
383 for(Standard_Integer i=myNodes2d.Lower();i<=myNodes2d.Upper();i++){
384 if(B.IsOut(myNodes2d(i)))
385 return Standard_False;
387 return Standard_True;
391 //=======================================================================
394 //=======================================================================
396 Standard_Boolean Select3D_SensitiveTriangulation::
397 Matches (const TColgp_Array1OfPnt2d& aPoly,
398 const Bnd_Box2d& aBox,
399 const Standard_Real aTol)
401 Standard_Real Umin,Vmin,Umax,Vmax;
402 aBox.Get(Umin,Vmin,Umax,Vmax);
403 Standard_Real Tolu,Tolv;
406 CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
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;
412 return Standard_True;
417 Standard_Integer Select3D_SensitiveTriangulation::Status (const gp_XY& TheP,
421 const Standard_Real aTol,
422 Standard_Real& DD) const
424 return Select3D_SensitiveTriangle::Status(Proj0,Proj1,Proj2,TheP,aTol,DD);
427 //=======================================================================
430 //=======================================================================
432 Standard_Boolean Select3D_SensitiveTriangulation::IsFree(const Standard_Integer IndexOfTriangle,
433 Standard_Integer& FoundIndex) const
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();
442 for(Standard_Integer I=1;I<=FreeE.Length() && FoundIndex==-1;I+=2){
444 if(FreeE(I) == n[0]){
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;}
453 return FoundIndex!=-1;
457 //=======================================================================
458 //function : GetConnected
460 //=======================================================================
461 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::
462 GetConnected(const TopLoc_Location& aLoc)
465 Handle(Select3D_SensitiveTriangulation) NiouEnt =
466 new Select3D_SensitiveTriangulation(myOwnerId,myTriangul,myiniloc,myFreeEdges,myCDG3D,myIntFlag);
468 if(HasLocation()) NiouEnt->SetLocation(Location());
469 // TopLoc_Location TheLocToApply = HasLocation() ? Location()*aLoc : aLoc;
470 // if(!TheLocToApply.IsIdentity())
471 NiouEnt->UpdateLocation(aLoc);
478 //=======================================================================
479 //function : ResetLocation
481 //=======================================================================
482 void Select3D_SensitiveTriangulation::ResetLocation()
484 Select3D_SensitiveEntity::ResetLocation();
487 void Select3D_SensitiveTriangulation::SetLocation(const TopLoc_Location& aLoc)
489 Select3D_SensitiveEntity::SetLocation(aLoc);
494 //=======================================================================
497 //=======================================================================
498 void Select3D_SensitiveTriangulation::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
500 S<<"\tSensitiveTriangulation 3D :"<<endl;
501 if(myiniloc.IsIdentity())
502 S<<"\t\tNo Initial Location"<<endl;
504 S<<"\t\tExisting Initial Location"<<endl;
506 S<<"\t\tExisting Location"<<endl;
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;
513 // S<<"\t\t\tOwner:"<<myOwnerId<<endl;
514 Select3D_SensitiveEntity::DumpBox(S,mybox2d);
518 //=======================================================================
519 //function : ComputeDepth
521 //=======================================================================
522 Standard_Real Select3D_SensitiveTriangulation::ComputeDepth(const gp_Lin& EyeLine) const
524 if(myDetectedTr==-1) return Precision::Infinite(); // currently not implemented...
525 const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
526 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
528 Standard_Integer n1,n2,n3;
529 triangles(myDetectedTr).Get(n1,n2,n3);
530 gp_Pnt P[3]={Nodes(n1),Nodes(n2),Nodes(n3)};
532 if(myTrsf.Form()!=gp_Identity){
533 for(Standard_Integer i =0;i<=2;i++){
534 P[i].Transform(myTrsf);
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();
545 for(Standard_Integer i=0;i<=2;i++)
546 Vtr[i] = gp_Vec(P[i%3],P[(i+1)%3]);
549 // remove singular cases immediately...
550 Standard_Integer SingularCase(-1);
551 if(Vtr[0].SquareMagnitude()<= Precision::Confusion())
553 if(Vtr[1].SquareMagnitude()<= Precision::Confusion())
554 SingularCase = (SingularCase == -1) ? 1 : 2;
556 if(Vtr[2].SquareMagnitude()<= Precision::Confusion())
557 if( SingularCase < 0 ) SingularCase = 1;
561 if(SingularCase ==2){
562 prof= ElCLib::Parameter(EyeLine,P[0]);
568 if(SingularCase!=1 &&
571 gp_Vec OPo(Oye,P[0]);
572 // 2 points mixed... the intersection between the segment and the target line eye/point.
574 if(SingularCase!=-1){
575 gp_Vec V = SingularCase==0 ? Vtr[2] : Vtr[0];
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();
587 Standard_Real val1 = OPo.DotCross(Vtr[0],Vtr[2]);
588 Standard_Real val2 = Dir.DotCross(Vtr[0],Vtr[2]);
590 if(Abs(val2)>Precision::Confusion())
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]));
602 //=======================================================================
603 //function : DetectedTriangle
605 //=======================================================================
606 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle(gp_Pnt& P1,
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);
619 if(myTrsf.Form()!=gp_Identity){
620 P1.Transform(myTrsf);
621 P2.Transform(myTrsf);
622 P3.Transform(myTrsf);
625 return Standard_True;
628 //=============================================================================
629 // Function : DetectedTriangle2d
631 //=============================================================================
632 Standard_Boolean Select3D_SensitiveTriangulation::DetectedTriangle2d(
633 gp_Pnt2d& P1, gp_Pnt2d& P2, gp_Pnt2d& P3) const
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);
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 )
648 P1 = myNodes2d.Value( n1 );
649 P2 = myNodes2d.Value( n2 );
650 P3 = myNodes2d.Value( n3 );
651 return Standard_True;
654 return Standard_False;
658 void Select3D_SensitiveTriangulation::ComputeTotalTrsf()
660 Standard_Boolean hasloc = (HasLocation() || !myiniloc.IsIdentity());
663 if(myiniloc.IsIdentity())
664 myTrsf = Location().Transformation();
665 else if(HasLocation()){
666 myTrsf = (Location()*myiniloc).Transformation();
669 myTrsf = myiniloc.Transformation();