0024070: OpenGL capped object-level clipping planes
[occt.git] / src / Select3D / Select3D_SensitiveTriangle.cxx
1 // Created on: 1997-05-14
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1997-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22
23 #include <Select3D_SensitiveTriangle.ixx>
24
25
26 #include <SelectBasics_BasicTool.hxx>
27 #include <gp_Pnt2d.hxx>
28 #include <gp_Pnt.hxx>
29 #include <gp_Dir2d.hxx>
30 #include <Precision.hxx>
31 #include <Bnd_Box.hxx>
32 #include <ElCLib.hxx>
33 #include <TopLoc_Location.hxx>
34
35 #include <CSLib_Class2d.hxx>
36
37 static Standard_Boolean S3D_Str_NearSegment (const gp_XY& p0, const gp_XY& p1, const gp_XY& TheP,
38                                              const Standard_Real aTol, Standard_Real& aDMin)
39 {
40   gp_XY V01(p1);
41   V01 -= p0;
42
43   gp_XY Vec(TheP);
44   Vec -= p0;
45
46   Standard_Real u = Vec*V01.Normalized();
47   if(u<-aTol) return Standard_False;
48   Standard_Real u1 = u-aTol;
49   Standard_Real modmod = V01.SquareModulus();
50   if(u1*u1> modmod) return Standard_False;
51
52   gp_XY N01 (-V01.Y(),V01.X());
53   N01.Normalize();
54   aDMin = Abs (Vec * N01);
55   return aDMin <= aTol;
56 }
57
58 //==================================================
59 // Function: Creation
60 // Purpose :
61 //==================================================
62
63 Select3D_SensitiveTriangle::
64 Select3D_SensitiveTriangle(const Handle(SelectBasics_EntityOwner)& OwnerId,
65                            const gp_Pnt& P0,
66                            const gp_Pnt& P1,
67                            const gp_Pnt& P2,
68                            const Select3D_TypeOfSensitivity aType):
69 Select3D_SensitivePoly(OwnerId,3),
70 mytype (aType)
71 {
72   mypolyg.SetPnt(0, P0);
73   mypolyg.SetPnt(1, P1);
74   mypolyg.SetPnt(2, P2);
75 }
76
77 //==================================================
78 // Function: Matches
79 // Purpose :
80 //==================================================
81
82 Standard_Boolean Select3D_SensitiveTriangle::Matches (const SelectBasics_PickArgs& thePickArgs,
83                                                       Standard_Real& theMatchDMin,
84                                                       Standard_Real& theMatchDepth)
85 {
86   Standard_Real aDepth = ComputeDepth (thePickArgs.PickLine());
87   if (thePickArgs.IsClipped (aDepth))
88   {
89     return Standard_False;
90   }
91
92   theMatchDepth = aDepth;
93
94   if (Bnd_Box2d (mybox2d).IsOut (gp_Pnt2d (thePickArgs.X(), thePickArgs.Y())))
95   {
96     return Standard_False;
97   }
98
99   Standard_Integer Res;
100   switch (mytype)
101   {
102   case Select3D_TOS_BOUNDARY:
103     Res = Status (thePickArgs.X(), thePickArgs.Y(), thePickArgs.Tolerance(), theMatchDMin);
104     return Res== 1;
105     break;
106   case Select3D_TOS_INTERIOR:
107     Res = Status (thePickArgs.X(), thePickArgs.Y(), thePickArgs.Tolerance(), theMatchDMin);
108     return (Res==0 || Res == 1);
109   default:
110     break;
111   }
112
113   return Standard_True;
114 }
115
116 //==================================================
117 // Function: Matches
118 // Purpose :
119 //==================================================
120
121 Standard_Boolean Select3D_SensitiveTriangle::
122 Matches (const Standard_Real XMin,
123          const Standard_Real YMin,
124          const Standard_Real XMax,
125          const Standard_Real YMax,
126          const Standard_Real aTol)
127 {
128   Bnd_Box2d B;
129   B.Update(Min(XMin,XMax)-aTol,
130            Min(YMin,YMax)-aTol,
131            Max(XMin,XMax)+aTol,
132            Max(YMin,YMax)+aTol);
133   for(Standard_Integer anIndex=0;anIndex<=2;++anIndex)
134   {
135     if(B.IsOut(mypolyg.Pnt2d(anIndex)))
136       return Standard_False;
137   }
138   return Standard_True;
139 }
140
141 //=======================================================================
142 //function : Matches
143 //purpose  :
144 //=======================================================================
145
146 Standard_Boolean Select3D_SensitiveTriangle::
147 Matches (const TColgp_Array1OfPnt2d& aPoly,
148          const Bnd_Box2d& aBox,
149          const Standard_Real aTol)
150 {
151   Standard_Real Umin,Vmin,Umax,Vmax;
152   aBox.Get(Umin,Vmin,Umax,Vmax);
153   CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
154
155   for(Standard_Integer anIndex=0;anIndex<=2;++anIndex)
156   {
157     Standard_Integer RES = aClassifier2d.SiDans(mypolyg.Pnt2d(anIndex));
158     if(RES!=1)
159       return Standard_False;
160   }
161   return Standard_True;
162 }
163
164 //==================================================
165 // Function: Points3D
166 // Purpose :
167 //==================================================
168
169 void Select3D_SensitiveTriangle::Points3D(gp_Pnt& P0,gp_Pnt& P1,gp_Pnt& P2) const
170 {
171   P0 = mypolyg.Pnt(0);
172   P1 = mypolyg.Pnt(1);
173   P2 = mypolyg.Pnt(2);
174 }
175
176 //==================================================
177 // Function: Center3D
178 // Purpose :
179 //==================================================
180
181 gp_Pnt Select3D_SensitiveTriangle::Center3D() const
182 {
183   gp_XYZ aPnt1, aPnt2, aPnt3;
184   aPnt1 = mypolyg.Pnt(0);
185   aPnt2 = mypolyg.Pnt(1);
186   aPnt3 = mypolyg.Pnt(2);
187   return gp_Pnt((aPnt1+aPnt2+aPnt3)/3.);
188 }
189
190 //==================================================
191 // Function: Center2D
192 // Purpose :
193 //==================================================
194
195 gp_XY Select3D_SensitiveTriangle::Center2D() const
196 {
197   gp_XY aPnt1, aPnt2, aPnt3;
198   aPnt1 = mypolyg.Pnt2d(0);
199   aPnt2 = mypolyg.Pnt2d(1);
200   aPnt3 = mypolyg.Pnt2d(2);
201   return (aPnt1+aPnt2+aPnt3)/3.;
202 }
203
204 //=======================================================================
205 //function : Status
206 //purpose  : 0 = inside /1 = Boundary/ 2 = outside
207 //=======================================================================
208
209 Standard_Integer  Select3D_SensitiveTriangle::Status(const Standard_Real X,
210                                                      const Standard_Real Y,
211                                                      const Standard_Real aTol,
212                                                      Standard_Real& DMin) const
213 {
214   return Status(mypolyg.Pnt2d(0), mypolyg.Pnt2d(1), mypolyg.Pnt2d(2),
215                 gp_XY(X,Y), aTol, DMin);
216 }
217
218 //=======================================================================
219 //function : Status
220 //purpose  :
221 //=======================================================================
222
223 Standard_Integer  Select3D_SensitiveTriangle::Status(const gp_XY& p0,
224                                                      const gp_XY& p1,
225                                                      const gp_XY& p2,
226                                                      const gp_XY& TheP,
227                                                      const Standard_Real aTol,
228                                                      Standard_Real& DMin)
229 {
230   Bnd_Box2d B;
231   B.Update(p0.X(),p0.Y());B.Update(p1.X(),p1.Y());B.Update(p2.X(),p2.Y());
232   B.Enlarge(aTol);
233   if(B.IsOut(TheP)) return 2;
234
235   // the point is classified corresponding to demi-spaces limited
236   // by each side of the triangle (with tolerance)
237   gp_XY V01(p1);V01-=p0;
238   gp_XY V02(p2);V02-=p0;
239   gp_XY V12(p2);V12-=p1;
240
241   // check these particular cases...
242   // if one of vectors is almost null (2 points are mixed),
243   // leave at once (it is already in the bounding box, which is good...)
244
245   DMin = aTol;
246
247   if ( V01.SquareModulus() <= gp::Resolution() )
248   {
249     Standard_Real LV = V02.SquareModulus();
250     if ( LV <= gp::Resolution())
251       return 0; // 3 points are mixed, and TheP is in the bounding box B...
252
253     if ( S3D_Str_NearSegment (p0, p2, TheP, aTol, DMin) )
254       return 0;
255     return 2;
256   }
257   if ( V02.SquareModulus() <= gp::Resolution() )
258   {
259     if ( S3D_Str_NearSegment (p0, p1, TheP, aTol, DMin) )
260       return 0;
261     return 2;
262   }
263   if ( V12.SquareModulus() <= gp::Resolution() )
264   {
265     if ( S3D_Str_NearSegment (p0, p1, TheP, aTol, DMin) )
266       return 0;
267     return 2;
268   }
269   if ( V01.CrossMagnitude(V02) <= gp::Resolution() )
270   {
271     if ( S3D_Str_NearSegment (p0, p1, TheP, aTol, DMin) )
272       return 0;
273     return 2;
274   }
275
276   // oriented normal to p0p1...
277   gp_Dir2d N (-V01.Y(), V01.X());
278   Standard_Boolean Neg = (N * V02 < 0.);
279   if ( Neg )
280     N.Reverse();
281
282   gp_XY Vec(TheP);
283   Vec -= p0;
284
285   Standard_Real aD1 = Vec * N.XY();
286   if ( aD1 < -aTol )
287     return 2;
288
289   // oriented normal to p1p2...
290   if(Neg)
291     N.SetCoord(p2.Y()-p1.Y(),p1.X()-p2.X());
292   else
293     N.SetCoord(p1.Y()-p2.Y(),p2.X()-p1.X());
294
295   Vec.SetCoord(TheP.X()-p1.X(),TheP.Y()-p1.Y());
296   Standard_Real aD2 = Vec * N.XY();
297   if ( aD2 < -aTol )
298     return 2;   // outside
299
300   // oriented normal to p2p0...
301   // attention v20 (x0-x2)    =>   N y2-y0   => -N  y0-y2
302   //               (y0-y2)           x0-x2          x2-x0
303   if(Neg)
304     N.SetCoord(p0.Y()-p2.Y(),p2.X()-p0.X());
305   else
306     N.SetCoord(p2.Y()-p0.Y(),p0.X()-p2.X());
307
308   Vec.SetCoord(TheP.X()-p2.X(),TheP.Y()-p2.Y());
309   Standard_Real aD3 = Vec * N.XY();
310   if ( aD3 < -aTol )
311     return 2;  // outside
312
313   // compute 2d distance to triangle
314   Standard_Real aD = Min (aD1, Min (aD2, aD3));
315   DMin = ( aD < 0 ? -aD : 0. );
316   return 0;
317 }
318
319 //=======================================================================
320 //function : Dump
321 //purpose  :
322 //=======================================================================
323
324 void Select3D_SensitiveTriangle::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
325 {
326   // general information....
327
328   S<<"\tSensitiveTriangle 3D :\n";
329   if(HasLocation())
330     S<<"\t\tExisting Location"<<endl;
331
332   gp_Pnt aPnt1, aPnt2, aPnt3;
333   aPnt1 = mypolyg.Pnt(0);
334   aPnt2 = mypolyg.Pnt(1);
335   aPnt3 = mypolyg.Pnt(2);
336   S<<"\t\t P0 [ "<<aPnt1.X()<<" , "<<aPnt1.Y()<<" , "<<aPnt1.Z()<<" ]"<<endl;
337   S<<"\t\t P1 [ "<<aPnt2.X()<<" , "<<aPnt2.Y()<<" , "<<aPnt2.Z()<<" ]"<<endl;
338   S<<"\t\t P2 [ "<<aPnt3.X()<<" , "<<aPnt3.Y()<<" , "<<aPnt3.Z()<<" ]"<<endl;
339
340   if(FullDump)
341   {
342     S<<"\t\tProjected Points"<<endl;
343
344     gp_Pnt2d aPnt1, aPnt2, aPnt3;
345     aPnt1 = mypolyg.Pnt2d(0);
346     aPnt2 = mypolyg.Pnt2d(1);
347     aPnt3 = mypolyg.Pnt2d(2);
348     S<<"\t\t  0.[ "<<aPnt1.X()<<" , "<<aPnt1.Y()<<" ]"<<endl;
349     S<<"\t\t  1.[ "<<aPnt2.X()<<" , "<<aPnt2.Y()<<" ]"<<endl;
350     S<<"\t\t  2.[ "<<aPnt3.X()<<" , "<<aPnt3.Y()<<" ]"<<endl;
351     Select3D_SensitiveEntity::DumpBox(S,mybox2d);
352   }
353 }
354
355 //=======================================================================
356 //function : ComputeDepth
357 //purpose  :
358 //=======================================================================
359
360 Standard_Real Select3D_SensitiveTriangle::ComputeDepth(const gp_Lin& EyeLine) const
361 {
362   Standard_Real prof(Precision::Infinite());
363
364   gp_Pnt P1, P2, P3;
365   P1 = mypolyg.Pnt(0);
366   P2 = mypolyg.Pnt(1);
367   P3 = mypolyg.Pnt(2);
368
369   gp_Trsf TheTrsf ;
370   if(HasLocation())
371     TheTrsf = Location().Transformation();
372
373   if(TheTrsf.Form()!=gp_Identity)
374   {
375     P1.Transform(TheTrsf);
376     P2.Transform(TheTrsf);
377     P3.Transform(TheTrsf);
378   }
379
380   // formula calculation of the point parameters on intersection
381   // t = (P1P2 ^P1P3)* OP1  / ((P1P2^P1P3)*Dir)
382
383   gp_Pnt Oye  = EyeLine.Location(); // origin of the target line eye/point...
384   gp_Dir Dir  = EyeLine.Direction();
385
386   gp_Vec P1P2 (P1,P2), P1P3(P1,P3);
387   P1P2.Normalize();
388   P1P3.Normalize();
389
390   gp_Vec oP1(Oye,P1);
391   Standard_Real val1 = oP1.DotCross(P1P2,P1P3);
392   Standard_Real val2 = Dir.DotCross(P1P2,P1P3);
393
394   if(Abs(val2)>Precision::Confusion())
395     prof =val1/val2;
396
397   if (prof==Precision::Infinite())
398   {
399     prof= ElCLib::Parameter(EyeLine,P1);
400     prof = Min (prof, ElCLib::Parameter(EyeLine,P2));
401     prof = Min (prof, ElCLib::Parameter(EyeLine,P3));
402   }
403   return prof;
404 }
405
406 //==================================================
407 // Function: GetConnected
408 // Purpose :
409 //==================================================
410
411 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangle::
412 GetConnected(const TopLoc_Location &theLocation)
413 {
414   // Create a copy of this
415   Handle(Select3D_SensitiveEntity) aNewEntity =
416     new Select3D_SensitiveTriangle(myOwnerId, mypolyg.Pnt(0), mypolyg.Pnt(1), mypolyg.Pnt(2), mytype);
417
418   if (HasLocation())
419     aNewEntity->SetLocation(Location());
420
421   aNewEntity->UpdateLocation(theLocation);
422
423   return aNewEntity;
424 }