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;
94 //=======================================================================
95 //function : Select3D_SensitiveTriangulation
97 //=======================================================================
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),
107 myIntFlag(InteriorFlag),
108 myNodes2d(1,Trg->NbNodes()),
111 // calculate free edges and cdg 3d of the triangulation:
112 // This code should have been integrated in poly_triangulation...
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());
119 Standard_Integer n[3];
121 // 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++)
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++)
136 Standard_Integer k = (j+1) % 3;
147 for (Standard_Integer i = 1; i <= nbTriangles; i++)
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.;
154 if(nbTriangles!=0) cdg /= nbTriangles;
155 myCDG3D = gp_Pnt(cdg);
159 if(myTrsf.Form()!=gp_Identity)
160 myCDG3D.Transform(myTrsf);
164 //=======================================================================
165 //function : Select3D_SensitiveTriangulation
167 //=======================================================================
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),
180 myFreeEdges(FreeEdges),
181 myIntFlag(InteriorFlag),
182 myNodes2d(1,Trg->NbNodes()),
187 //=======================================================================
190 //=======================================================================
192 void Select3D_SensitiveTriangulation::Project(const Handle(Select3D_Projector)& aPrj)
194 Select3D_SensitiveEntity::Project(aPrj); // to set the field last proj...
197 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
201 for(Standard_Integer I=1;I<=myTriangul->NbNodes();I++){
202 if(myTrsf.Form()!=gp_Identity)
203 aPrj->Project(Nodes(I).Transformed(myTrsf),ProjPT);
205 aPrj->Project(Nodes(I),ProjPT);
207 myNodes2d.SetValue(I,ProjPT);
211 aPrj->Project(myCDG3D,myCDG2D);
214 //=======================================================================
217 //=======================================================================
219 void Select3D_SensitiveTriangulation::Areas(SelectBasics_ListOfBox2d& boxes)
221 boxes.Append(mybox2d);
224 //=======================================================================
227 //=======================================================================
228 Standard_Boolean Select3D_SensitiveTriangulation::
229 Matches(const Standard_Real X,
230 const Standard_Real Y,
231 const Standard_Real aTol,
234 // get view direction (necessary for calculation of depth) from field mylastprj of the base class
235 if (mylastprj.IsNull())
236 return Standard_False;
238 DMin = Precision::Infinite();
241 const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
243 // it is checked if we are inside the triangle 2d.
246 gp_Lin EyeLine = mylastprj->Shoot(X,Y);
247 if ( myTrsf.Form()!=gp_Identity )
248 EyeLine.Transform (myTrsf.Inverted());
250 Standard_Real aMinDepth = Precision::Infinite();
251 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
252 for (Standard_Integer itr=1; itr<=myTriangul->NbTriangles(); itr++)
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();
260 Standard_Real aDistSquare = Poly::PointOnTriangle (aPnt2d1, aPnt2d2, aPnt2d3, BidPoint, aUV);
261 if ( aDistSquare > aTol * aTol )
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);
271 // take triangle with lowest depth and within defined depth interval
272 if (aDepth < aMinDepth &&
273 aDepth > mylastprj->DepthMin() &&
274 aDepth < mylastprj->DepthMax())
278 DMin = Sqrt (aDistSquare);
283 // Case only Test on Border of the triangulation...
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;
293 for (Standard_Integer ifri =1; ifri <= nn && myDetectedTr < 0; ifri+=2)
296 Node2 = FreeE(ifri+1);
297 if (S3D_STriangul_NearSegment (myNodes2d(Node1).XY(),
298 myNodes2d(Node2).XY(),
299 BidPoint, aTol, DMin) )
301 for(Standard_Integer itr=1; itr <= myTriangul->NbTriangles(); itr++)
303 Standard_Integer n1,n2,n3;
304 triangles(itr).Get(n1,n2,n3);
305 if(S3D_IsEdgeIn(Node1,Node2,n1,n2,n3))
308 break; // return first found; selection of closest is not implemented yet
314 if ( myDetectedTr <= 0 )
315 return Standard_False;
317 // compute and validate the depth (::Depth()) along the eyeline
318 return Select3D_SensitiveEntity::Matches(X,Y,aTol,DMin);
322 //=======================================================================
325 //=======================================================================
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)
335 B.Update(Min(XMin,XMax)-aTol,
338 Max(YMin,YMax)+aTol);
340 for(Standard_Integer i=myNodes2d.Lower();i<=myNodes2d.Upper();i++)
342 if(B.IsOut(myNodes2d(i)))
343 return Standard_False;
345 return Standard_True;
348 //=======================================================================
351 //=======================================================================
353 Standard_Boolean Select3D_SensitiveTriangulation::
354 Matches (const TColgp_Array1OfPnt2d& aPoly,
355 const Bnd_Box2d& aBox,
356 const Standard_Real aTol)
358 Standard_Real Umin,Vmin,Umax,Vmax;
359 aBox.Get(Umin,Vmin,Umax,Vmax);
360 Standard_Real Tolu,Tolv;
363 CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
365 for(Standard_Integer j=1;j<=myNodes2d.Length();j++)
367 Standard_Integer RES = aClassifier2d.SiDans(myNodes2d(j));
368 if(RES!=1) return Standard_False;
370 return Standard_True;
373 //=======================================================================
376 //=======================================================================
378 Standard_Integer Select3D_SensitiveTriangulation::
379 Status (const gp_XY& TheP,
383 const Standard_Real aTol,
384 Standard_Real& DD) const
386 return Select3D_SensitiveTriangle::Status(Proj0,Proj1,Proj2,TheP,aTol,DD);
389 //=======================================================================
392 //=======================================================================
394 Standard_Boolean Select3D_SensitiveTriangulation::IsFree(const Standard_Integer IndexOfTriangle,
395 Standard_Integer& FoundIndex) const
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();
403 for(Standard_Integer I=1;I<=FreeE.Length() && FoundIndex==-1;I+=2)
407 if(FreeE(I+1)== n[1] || FreeE(I+1)== n[2])
410 else if(FreeE(I) == n[1])
412 if(FreeE(I+1)== n[0] || FreeE(I+1)== n[2])
415 else if(FreeE(I) == n[2])
417 if(FreeE(I+1)== n[0] || FreeE(I+1)== n[1])
422 return FoundIndex!=-1;
426 //=======================================================================
427 //function : GetConnected
429 //=======================================================================
431 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::
432 GetConnected(const TopLoc_Location& aLoc)
434 Handle(Select3D_SensitiveTriangulation) NiouEnt =
435 new Select3D_SensitiveTriangulation(myOwnerId,myTriangul,myiniloc,myFreeEdges,myCDG3D,myIntFlag);
438 NiouEnt->SetLocation(Location());
439 // TopLoc_Location TheLocToApply = HasLocation() ? Location()*aLoc : aLoc;
440 // if(!TheLocToApply.IsIdentity())
441 NiouEnt->UpdateLocation(aLoc);
446 //=======================================================================
447 //function : ResetLocation
449 //=======================================================================
451 void Select3D_SensitiveTriangulation::ResetLocation()
453 Select3D_SensitiveEntity::ResetLocation();
457 //=======================================================================
458 //function : SetLocation
460 //=======================================================================
462 void Select3D_SensitiveTriangulation::SetLocation(const TopLoc_Location& aLoc)
464 Select3D_SensitiveEntity::SetLocation(aLoc);
469 //=======================================================================
472 //=======================================================================
473 void Select3D_SensitiveTriangulation::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
475 S<<"\tSensitiveTriangulation 3D :"<<endl;
476 if(myiniloc.IsIdentity())
477 S<<"\t\tNo Initial Location"<<endl;
479 S<<"\t\tExisting Initial Location"<<endl;
481 S<<"\t\tExisting Location"<<endl;
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;
489 // S<<"\t\t\tOwner:"<<myOwnerId<<endl;
490 Select3D_SensitiveEntity::DumpBox(S,mybox2d);
494 //=======================================================================
495 //function : ComputeDepth
497 //=======================================================================
499 Standard_Real Select3D_SensitiveTriangulation::ComputeDepth(const gp_Lin& EyeLine) const
501 if(myDetectedTr==-1) return Precision::Infinite(); // currently not implemented...
502 const Poly_Array1OfTriangle& triangles = myTriangul->Triangles();
503 const TColgp_Array1OfPnt& Nodes = myTriangul->Nodes();
505 Standard_Integer n1,n2,n3;
506 triangles(myDetectedTr).Get(n1,n2,n3);
507 gp_Pnt P[3]={Nodes(n1),Nodes(n2),Nodes(n3)};
509 if(myTrsf.Form()!=gp_Identity)
511 for(Standard_Integer i =0;i<=2;i++)
513 P[i].Transform(myTrsf);
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();
524 for(Standard_Integer i=0;i<=2;i++)
525 Vtr[i] = gp_Vec(P[i%3],P[(i+1)%3]);
528 // remove singular cases immediately...
529 Standard_Integer SingularCase(-1);
530 if(Vtr[0].SquareMagnitude()<= Precision::Confusion())
532 if(Vtr[1].SquareMagnitude()<= Precision::Confusion())
533 SingularCase = (SingularCase == -1) ? 1 : 2;
535 if(Vtr[2].SquareMagnitude()<= Precision::Confusion())
536 if( SingularCase < 0 ) SingularCase = 1;
542 prof= ElCLib::Parameter(EyeLine,P[0]);
548 if(SingularCase!=1 &&
551 gp_Vec OPo(Oye,P[0]);
552 // 2 points mixed... the intersection between the segment and the target line eye/point.
556 gp_Vec V = SingularCase==0 ? Vtr[2] : Vtr[0];
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();
568 Standard_Real val1 = OPo.DotCross(Vtr[0],Vtr[2]);
569 Standard_Real val2 = Dir.DotCross(Vtr[0],Vtr[2]);
571 if(Abs(val2)>Precision::Confusion())
574 if (prof==Precision::Infinite())
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]));
584 //=======================================================================
585 //function : DetectedTriangle
587 //=======================================================================
589 Standard_Boolean Select3D_SensitiveTriangulation::
590 DetectedTriangle(gp_Pnt& P1,
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);
603 if(myTrsf.Form()!=gp_Identity)
605 P1.Transform(myTrsf);
606 P2.Transform(myTrsf);
607 P3.Transform(myTrsf);
610 return Standard_True;
613 //=============================================================================
614 // Function : DetectedTriangle2d
616 //=============================================================================
618 Standard_Boolean Select3D_SensitiveTriangulation::
619 DetectedTriangle2d(gp_Pnt2d& P1,
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);
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 )
636 P1 = myNodes2d.Value( n1 );
637 P2 = myNodes2d.Value( n2 );
638 P3 = myNodes2d.Value( n3 );
639 return Standard_True;
642 return Standard_False;
645 //=============================================================================
646 // Function : ComputeTotalTrsf
648 //=============================================================================
650 void Select3D_SensitiveTriangulation::ComputeTotalTrsf()
652 Standard_Boolean hasloc = (HasLocation() || !myiniloc.IsIdentity());
656 if(myiniloc.IsIdentity())
657 myTrsf = Location().Transformation();
658 else if(HasLocation())
660 myTrsf = (Location()*myiniloc).Transformation();
663 myTrsf = myiniloc.Transformation();