b073b5c5062cd2207c3478c003361fdac572088b
[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::
83 Matches(const Standard_Real X,
84         const Standard_Real Y,
85         const Standard_Real aTol,
86         Standard_Real& DMin)
87 {
88   Select3D_SensitiveEntity::Matches(X,Y,aTol,DMin);
89   if(Bnd_Box2d(mybox2d).IsOut(gp_Pnt2d(X,Y))) return Standard_False;
90
91   Standard_Integer Res;
92   switch (mytype)
93   {
94   case Select3D_TOS_BOUNDARY:
95     Res = Status(X,Y,aTol,DMin);
96     return Res== 1;
97     break;
98   case Select3D_TOS_INTERIOR:
99     Res = Status(X,Y,aTol,DMin);
100     return (Res==0 || Res == 1);
101   default:
102     break;
103   }
104   return Standard_True;
105 }
106
107 //==================================================
108 // Function: Matches
109 // Purpose :
110 //==================================================
111
112 Standard_Boolean Select3D_SensitiveTriangle::
113 Matches (const Standard_Real XMin,
114          const Standard_Real YMin,
115          const Standard_Real XMax,
116          const Standard_Real YMax,
117          const Standard_Real aTol)
118 {
119   Bnd_Box2d B;
120   B.Update(Min(XMin,XMax)-aTol,
121            Min(YMin,YMax)-aTol,
122            Max(XMin,XMax)+aTol,
123            Max(YMin,YMax)+aTol);
124   for(Standard_Integer anIndex=0;anIndex<=2;++anIndex)
125   {
126     if(B.IsOut(mypolyg.Pnt2d(anIndex)))
127       return Standard_False;
128   }
129   return Standard_True;
130 }
131
132 //=======================================================================
133 //function : Matches
134 //purpose  :
135 //=======================================================================
136
137 Standard_Boolean Select3D_SensitiveTriangle::
138 Matches (const TColgp_Array1OfPnt2d& aPoly,
139          const Bnd_Box2d& aBox,
140          const Standard_Real aTol)
141 {
142   Standard_Real Umin,Vmin,Umax,Vmax;
143   aBox.Get(Umin,Vmin,Umax,Vmax);
144   CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
145
146   for(Standard_Integer anIndex=0;anIndex<=2;++anIndex)
147   {
148     Standard_Integer RES = aClassifier2d.SiDans(mypolyg.Pnt2d(anIndex));
149     if(RES!=1)
150       return Standard_False;
151   }
152   return Standard_True;
153 }
154
155 //==================================================
156 // Function: Points3D
157 // Purpose :
158 //==================================================
159
160 void Select3D_SensitiveTriangle::Points3D(gp_Pnt& P0,gp_Pnt& P1,gp_Pnt& P2) const
161 {
162   P0 = mypolyg.Pnt(0);
163   P1 = mypolyg.Pnt(1);
164   P2 = mypolyg.Pnt(2);
165 }
166
167 //==================================================
168 // Function: Center3D
169 // Purpose :
170 //==================================================
171
172 gp_Pnt Select3D_SensitiveTriangle::Center3D() const
173 {
174   gp_XYZ aPnt1, aPnt2, aPnt3;
175   aPnt1 = mypolyg.Pnt(0);
176   aPnt2 = mypolyg.Pnt(1);
177   aPnt3 = mypolyg.Pnt(2);
178   return gp_Pnt((aPnt1+aPnt2+aPnt3)/3.);
179 }
180
181 //==================================================
182 // Function: Center2D
183 // Purpose :
184 //==================================================
185
186 gp_XY Select3D_SensitiveTriangle::Center2D() const
187 {
188   gp_XY aPnt1, aPnt2, aPnt3;
189   aPnt1 = mypolyg.Pnt2d(0);
190   aPnt2 = mypolyg.Pnt2d(1);
191   aPnt3 = mypolyg.Pnt2d(2);
192   return (aPnt1+aPnt2+aPnt3)/3.;
193 }
194
195 //=======================================================================
196 //function : Status
197 //purpose  : 0 = inside /1 = Boundary/ 2 = outside
198 //=======================================================================
199
200 Standard_Integer  Select3D_SensitiveTriangle::Status(const Standard_Real X,
201                                                      const Standard_Real Y,
202                                                      const Standard_Real aTol,
203                                                      Standard_Real& DMin) const
204 {
205   return Status(mypolyg.Pnt2d(0), mypolyg.Pnt2d(1), mypolyg.Pnt2d(2),
206                 gp_XY(X,Y), aTol, DMin);
207 }
208
209 //=======================================================================
210 //function : Status
211 //purpose  :
212 //=======================================================================
213
214 Standard_Integer  Select3D_SensitiveTriangle::Status(const gp_XY& p0,
215                                                      const gp_XY& p1,
216                                                      const gp_XY& p2,
217                                                      const gp_XY& TheP,
218                                                      const Standard_Real aTol,
219                                                      Standard_Real& DMin)
220 {
221   Bnd_Box2d B;
222   B.Update(p0.X(),p0.Y());B.Update(p1.X(),p1.Y());B.Update(p2.X(),p2.Y());
223   B.Enlarge(aTol);
224   if(B.IsOut(TheP)) return 2;
225
226   // the point is classified corresponding to demi-spaces limited
227   // by each side of the triangle (with tolerance)
228   gp_XY V01(p1);V01-=p0;
229   gp_XY V02(p2);V02-=p0;
230   gp_XY V12(p2);V12-=p1;
231
232   // check these particular cases...
233   // if one of vectors is almost null (2 points are mixed),
234   // leave at once (it is already in the bounding box, which is good...)
235
236   DMin = aTol;
237
238   if ( V01.SquareModulus() <= gp::Resolution() )
239   {
240     Standard_Real LV = V02.SquareModulus();
241     if ( LV <= gp::Resolution())
242       return 0; // 3 points are mixed, and TheP is in the bounding box B...
243
244     if ( S3D_Str_NearSegment (p0, p2, TheP, aTol, DMin) )
245       return 0;
246     return 2;
247   }
248   if ( V02.SquareModulus() <= gp::Resolution() )
249   {
250     if ( S3D_Str_NearSegment (p0, p1, TheP, aTol, DMin) )
251       return 0;
252     return 2;
253   }
254   if ( V12.SquareModulus() <= gp::Resolution() )
255   {
256     if ( S3D_Str_NearSegment (p0, p1, TheP, aTol, DMin) )
257       return 0;
258     return 2;
259   }
260   if ( V01.CrossMagnitude(V02) <= gp::Resolution() )
261   {
262     if ( S3D_Str_NearSegment (p0, p1, TheP, aTol, DMin) )
263       return 0;
264     return 2;
265   }
266
267   // oriented normal to p0p1...
268   gp_Dir2d N (-V01.Y(), V01.X());
269   Standard_Boolean Neg = (N * V02 < 0.);
270   if ( Neg )
271     N.Reverse();
272
273   gp_XY Vec(TheP);
274   Vec -= p0;
275
276   Standard_Real aD1 = Vec * N.XY();
277   if ( aD1 < -aTol )
278     return 2;
279
280   // oriented normal to p1p2...
281   if(Neg)
282     N.SetCoord(p2.Y()-p1.Y(),p1.X()-p2.X());
283   else
284     N.SetCoord(p1.Y()-p2.Y(),p2.X()-p1.X());
285
286   Vec.SetCoord(TheP.X()-p1.X(),TheP.Y()-p1.Y());
287   Standard_Real aD2 = Vec * N.XY();
288   if ( aD2 < -aTol )
289     return 2;   // outside
290
291   // oriented normal to p2p0...
292   // attention v20 (x0-x2)    =>   N y2-y0   => -N  y0-y2
293   //               (y0-y2)           x0-x2          x2-x0
294   if(Neg)
295     N.SetCoord(p0.Y()-p2.Y(),p2.X()-p0.X());
296   else
297     N.SetCoord(p2.Y()-p0.Y(),p0.X()-p2.X());
298
299   Vec.SetCoord(TheP.X()-p2.X(),TheP.Y()-p2.Y());
300   Standard_Real aD3 = Vec * N.XY();
301   if ( aD3 < -aTol )
302     return 2;  // outside
303
304   // compute 2d distance to triangle
305   Standard_Real aD = Min (aD1, Min (aD2, aD3));
306   DMin = ( aD < 0 ? -aD : 0. );
307   return 0;
308 }
309
310 //=======================================================================
311 //function : Dump
312 //purpose  :
313 //=======================================================================
314
315 void Select3D_SensitiveTriangle::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
316 {
317   // general information....
318
319   S<<"\tSensitiveTriangle 3D :\n";
320   if(HasLocation())
321     S<<"\t\tExisting Location"<<endl;
322
323   gp_Pnt aPnt1, aPnt2, aPnt3;
324   aPnt1 = mypolyg.Pnt(0);
325   aPnt2 = mypolyg.Pnt(1);
326   aPnt3 = mypolyg.Pnt(2);
327   S<<"\t\t P0 [ "<<aPnt1.X()<<" , "<<aPnt1.Y()<<" , "<<aPnt1.Z()<<" ]"<<endl;
328   S<<"\t\t P1 [ "<<aPnt2.X()<<" , "<<aPnt2.Y()<<" , "<<aPnt2.Z()<<" ]"<<endl;
329   S<<"\t\t P2 [ "<<aPnt3.X()<<" , "<<aPnt3.Y()<<" , "<<aPnt3.Z()<<" ]"<<endl;
330
331   if(FullDump)
332   {
333     S<<"\t\tProjected Points"<<endl;
334
335     gp_Pnt2d aPnt1, aPnt2, aPnt3;
336     aPnt1 = mypolyg.Pnt2d(0);
337     aPnt2 = mypolyg.Pnt2d(1);
338     aPnt3 = mypolyg.Pnt2d(2);
339     S<<"\t\t  0.[ "<<aPnt1.X()<<" , "<<aPnt1.Y()<<" ]"<<endl;
340     S<<"\t\t  1.[ "<<aPnt2.X()<<" , "<<aPnt2.Y()<<" ]"<<endl;
341     S<<"\t\t  2.[ "<<aPnt3.X()<<" , "<<aPnt3.Y()<<" ]"<<endl;
342     Select3D_SensitiveEntity::DumpBox(S,mybox2d);
343   }
344 }
345
346 //=======================================================================
347 //function : ComputeDepth
348 //purpose  :
349 //=======================================================================
350
351 Standard_Real Select3D_SensitiveTriangle::ComputeDepth(const gp_Lin& EyeLine) const
352 {
353   Standard_Real prof(Precision::Infinite());
354
355   gp_Pnt P1, P2, P3;
356   P1 = mypolyg.Pnt(0);
357   P2 = mypolyg.Pnt(1);
358   P3 = mypolyg.Pnt(2);
359
360   gp_Trsf TheTrsf ;
361   if(HasLocation())
362     TheTrsf = Location().Transformation();
363
364   if(TheTrsf.Form()!=gp_Identity)
365   {
366     P1.Transform(TheTrsf);
367     P2.Transform(TheTrsf);
368     P3.Transform(TheTrsf);
369   }
370
371   // formula calculation of the point parameters on intersection
372   // t = (P1P2 ^P1P3)* OP1  / ((P1P2^P1P3)*Dir)
373
374   gp_Pnt Oye  = EyeLine.Location(); // origin of the target line eye/point...
375   gp_Dir Dir  = EyeLine.Direction();
376
377   gp_Vec P1P2 (P1,P2), P1P3(P1,P3);
378   P1P2.Normalize();
379   P1P3.Normalize();
380
381   gp_Vec oP1(Oye,P1);
382   Standard_Real val1 = oP1.DotCross(P1P2,P1P3);
383   Standard_Real val2 = Dir.DotCross(P1P2,P1P3);
384
385   if(Abs(val2)>Precision::Confusion())
386     prof =val1/val2;
387
388   if (prof==Precision::Infinite())
389   {
390     prof= ElCLib::Parameter(EyeLine,P1);
391     prof = Min (prof, ElCLib::Parameter(EyeLine,P2));
392     prof = Min (prof, ElCLib::Parameter(EyeLine,P3));
393   }
394   return prof;
395 }
396
397 //==================================================
398 // Function: GetConnected
399 // Purpose :
400 //==================================================
401
402 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangle::
403 GetConnected(const TopLoc_Location &theLocation)
404 {
405   // Create a copy of this
406   Handle(Select3D_SensitiveEntity) aNewEntity =
407     new Select3D_SensitiveTriangle(myOwnerId, mypolyg.Pnt(0), mypolyg.Pnt(1), mypolyg.Pnt(2), mytype);
408
409   if (HasLocation())
410     aNewEntity->SetLocation(Location());
411
412   aNewEntity->UpdateLocation(theLocation);
413
414   return aNewEntity;
415 }