0026394: Visualization - eliminate unused variable in SelectMgr_RectangularFrustum
[occt.git] / src / SelectMgr / SelectMgr_RectangularFrustum.cxx
1 // Created on: 2014-05-22
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <NCollection_Vector.hxx>
17 #include <Poly_Array1OfTriangle.hxx>
18
19 #include <SelectMgr_RectangularFrustum.hxx>
20
21 #define DOT(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z())
22 #define DOTp(A, B) (A.x() * B.X() + A.y() * B.Y() + A.z() * B.Z())
23 #define DISTANCE(A, B) (std::sqrt ((A.x() - B.x()) * (A.x() - B.x()) + (A.y() - B.y()) * (A.y() - B.y()) + (A.z() - B.z()) * (A.z() - B.z())))
24 #define DISTANCEp(A, B) (std::sqrt ((A.x() - B.X()) * (A.x() - B.X()) + (A.y() - B.Y()) * (A.y() - B.Y()) + (A.z() - B.Z()) * (A.z() - B.Z())))
25
26 // =======================================================================
27 // function : segmentSegmentDistance
28 // purpose  :
29 // =======================================================================
30 void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1,
31                                                            const gp_Pnt& theSegPnt2,
32                                                            Standard_Real& theDepth)
33 {
34   SelectMgr_Vec3 anU = SelectMgr_Vec3 (theSegPnt2.X() - theSegPnt1.X(),
35                                        theSegPnt2.Y() - theSegPnt1.Y(),
36                                        theSegPnt2.Z() - theSegPnt1.Z());
37   SelectMgr_Vec3 aV = myViewRayDir;
38   SelectMgr_Vec3 aW = SelectMgr_Vec3 (theSegPnt1.X() - myNearPickedPnt.x(),
39                                       theSegPnt1.Y() - myNearPickedPnt.y(),
40                                       theSegPnt1.Z() - myNearPickedPnt.z());
41   Standard_Real anA = DOT (anU, anU);
42   Standard_Real aB = DOT (anU, aV);
43   Standard_Real aC = DOT (aV, aV);
44   Standard_Real aD = DOT (anU, aW);
45   Standard_Real anE = DOT (aV, aW);
46   Standard_Real aCoef = anA * aC - aB * aB;
47   Standard_Real aSn = aCoef;
48   Standard_Real aTc, aTn, aTd = aCoef;
49
50   if (aCoef < Precision::Confusion())
51   {
52     aTn = anE;
53     aTd = aC;
54   }
55   else
56   {
57     aSn = (aB * anE - aC * aD);
58     aTn = (anA * anE - aB * aD);
59     if (aSn < 0.0)
60     {
61       aTn = anE;
62       aTd = aC;
63     }
64     else if (aSn > aCoef)
65     {
66       aTn = anE + aB;
67       aTd = aC;
68     }
69   }
70
71   if (aTn < 0.0)
72   {
73     aTn = 0.0;
74   }
75   else if (aTn > aTd)
76   {
77     aTn = aTd;
78   }
79   aTc = (Abs (aTn) < Precision::Confusion() ? 0.0 : aTn / aTd);
80
81   SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + myViewRayDir * aTc;
82   theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
83 }
84
85 // =======================================================================
86 // function : segmentPlaneIntersection
87 // purpose  :
88 // =======================================================================
89 void SelectMgr_RectangularFrustum::segmentPlaneIntersection (const SelectMgr_Vec3& thePlane,
90                                                              const gp_Pnt& thePntOnPlane,
91                                                              Standard_Real& theDepth)
92 {
93   SelectMgr_Vec3 anU = myViewRayDir;
94   SelectMgr_Vec3 aW = SelectMgr_Vec3 (myNearPickedPnt.x() - thePntOnPlane.X(),
95                                       myNearPickedPnt.y() - thePntOnPlane.Y(),
96                                       myNearPickedPnt.z() - thePntOnPlane.Z());
97   Standard_Real aD = DOT (thePlane, anU);
98   Standard_Real aN = -DOT (thePlane, aW);
99
100   if (Abs (aD) < Precision::Confusion())
101   {
102     if (Abs (aN) < Precision::Angular())
103     {
104       theDepth = DBL_MAX;
105       return;
106     }
107     else
108     {
109       theDepth = DBL_MAX;
110       return;
111     }
112   }
113
114   Standard_Real aParam = aN / aD;
115   if (aParam < 0.0 || aParam > 1.0)
116   {
117     theDepth = DBL_MAX;
118     return;
119   }
120
121   SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + anU * aParam;
122   theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
123 }
124
125 namespace
126 {
127   // =======================================================================
128   // function : computeNormals
129   // purpose  : Computes normals to frustum faces
130   // =======================================================================
131   void computeNormals (const SelectMgr_Vec3* theVertices, SelectMgr_Vec3* theNormals)
132   {
133     // Top
134     theNormals[0] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0],
135                                            theVertices[4] - theVertices[0]);
136     // Bottom
137     theNormals[1] = SelectMgr_Vec3::Cross (theVertices[3] - theVertices[2],
138                                            theVertices[6] - theVertices[2]);
139     // Left
140     theNormals[2] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0],
141                                            theVertices[2] - theVertices[0]);
142     // Right
143     theNormals[3] = SelectMgr_Vec3::Cross (theVertices[5] - theVertices[4],
144                                            theVertices[6] - theVertices[4]);
145     // Near
146     theNormals[4] = SelectMgr_Vec3::Cross (theVertices[6] - theVertices[4],
147                                            theVertices[0] - theVertices[4]);
148     // Far
149     theNormals[5] = SelectMgr_Vec3::Cross (theVertices[7] - theVertices[5],
150                                            theVertices[1] - theVertices[5]);
151   }
152 }
153
154 // =======================================================================
155 // function : Build
156 // purpose  : Build volume according to the point and given pixel
157 //            tolerance
158 // =======================================================================
159 void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint)
160 {
161   myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 0.0);
162   myFarPickedPnt  = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 1.0);
163   myViewRayDir = myFarPickedPnt - myNearPickedPnt;
164   myMousePos = thePoint;
165
166   // LeftTopNear
167   myVertices[0] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
168                                                     thePoint.Y() + myPixelTolerance / 2.0,
169                                                     0.0);
170   // LeftTopFar
171   myVertices[1] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
172                                                     thePoint.Y() + myPixelTolerance / 2.0,
173                                                     1.0);
174   // LeftBottomNear
175   myVertices[2] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
176                                                     thePoint.Y() - myPixelTolerance / 2.0,
177                                                     0.0);
178   // LeftBottomFar
179   myVertices[3] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
180                                                     thePoint.Y() - myPixelTolerance / 2.0,
181                                                     1.0);
182   // RightTopNear
183   myVertices[4] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
184                                                     thePoint.Y() + myPixelTolerance / 2.0,
185                                                     0.0);
186   // RightTopFar
187   myVertices[5] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
188                                                     thePoint.Y() + myPixelTolerance / 2.0,
189                                                     1.0);
190   // RightBottomNear
191   myVertices[6] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
192                                                     thePoint.Y() - myPixelTolerance / 2.0,
193                                                     0.0);
194   // RightBottomFar
195   myVertices[7] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
196                                                     thePoint.Y() - myPixelTolerance / 2.0,
197                                                     1.0);
198
199   // compute frustum normals
200   computeNormals (myVertices, myPlanes);
201
202   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
203   {
204     Standard_Real aMax = -DBL_MAX;
205     Standard_Real aMin =  DBL_MAX;
206     const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
207     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
208     {
209       Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
210       aMax = Max (aMax, aProjection);
211       aMin = Min (aMin, aProjection);
212     }
213     myMaxVertsProjections[aPlaneIdx] = aMax;
214     myMinVertsProjections[aPlaneIdx] = aMin;
215   }
216
217   SelectMgr_Vec3 aDimensions[3] =
218   {
219     SelectMgr_Vec3 (1.0, 0.0, 0.0),
220     SelectMgr_Vec3 (0.0, 1.0, 0.0),
221     SelectMgr_Vec3 (0.0, 0.0, 1.0)
222   };
223
224   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
225   {
226     Standard_Real aMax = -DBL_MAX;
227     Standard_Real aMin =  DBL_MAX;
228     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
229     {
230       Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
231       aMax = Max (aProjection, aMax);
232       aMin = Min (aProjection, aMin);
233     }
234     myMaxOrthoVertsProjections[aDim] = aMax;
235     myMinOrthoVertsProjections[aDim] = aMin;
236   }
237
238   // Horizontal
239   myEdgeDirs[0] = myVertices[4] - myVertices[0];
240   // Vertical
241   myEdgeDirs[1] = myVertices[2] - myVertices[0];
242   // LeftLower
243   myEdgeDirs[2] = myVertices[2] - myVertices[3];
244   // RightLower
245   myEdgeDirs[3] = myVertices[6] - myVertices[7];
246   // LeftUpper
247   myEdgeDirs[4] = myVertices[0] - myVertices[1];
248   // RightUpper
249   myEdgeDirs[5] = myVertices[4] - myVertices[5];
250 }
251
252 // =======================================================================
253 // function : Build
254 // purpose  : Build volume according to the selected rectangle
255 // =======================================================================
256 void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d& theMinPnt,
257                                           const gp_Pnt2d& theMaxPnt)
258 {
259   myNearPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5,
260                                                       (theMinPnt.Y() + theMaxPnt.Y()) * 0.5,
261                                                       0.0);
262   myFarPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5,
263                                                      (theMinPnt.Y() + theMaxPnt.Y()) * 0.5,
264                                                      1.0);
265   myViewRayDir = myFarPickedPnt - myNearPickedPnt;
266
267   // LeftTopNear
268   myVertices[0] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
269                                                     theMaxPnt.Y(),
270                                                     0.0);
271   // LeftTopFar
272   myVertices[1] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
273                                                     theMaxPnt.Y(),
274                                                     1.0);
275   // LeftBottomNear
276   myVertices[2] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
277                                                     theMinPnt.Y(),
278                                                     0.0);
279   // LeftBottomFar
280   myVertices[3] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
281                                                     theMinPnt.Y(),
282                                                     1.0);
283   // RightTopNear
284   myVertices[4] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
285                                                     theMaxPnt.Y(),
286                                                     0.0);
287   // RightTopFar
288   myVertices[5] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
289                                                     theMaxPnt.Y(),
290                                                     1.0);
291   // RightBottomNear
292   myVertices[6] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
293                                                     theMinPnt.Y(),
294                                                     0.0);
295   // RightBottomFar
296   myVertices[7] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
297                                                     theMinPnt.Y(),
298                                                     1.0);
299
300   // compute frustum normals
301   computeNormals (myVertices, myPlanes);
302
303   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
304   {
305     Standard_Real aMax = -DBL_MAX;
306     Standard_Real aMin =  DBL_MAX;
307     const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
308     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
309     {
310       Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
311       aMax = Max (aMax, aProjection);
312       aMin = Min (aMin, aProjection);
313     }
314     myMaxVertsProjections[aPlaneIdx] = aMax;
315     myMinVertsProjections[aPlaneIdx] = aMin;
316   }
317
318   SelectMgr_Vec3 aDimensions[3] =
319   {
320     SelectMgr_Vec3 (1.0, 0.0, 0.0),
321     SelectMgr_Vec3 (0.0, 1.0, 0.0),
322     SelectMgr_Vec3 (0.0, 0.0, 1.0)
323   };
324
325   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
326   {
327     Standard_Real aMax = -DBL_MAX;
328     Standard_Real aMin =  DBL_MAX;
329     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
330     {
331       Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
332       aMax = Max (aMax, aProjection);
333       aMin = Min (aMin, aProjection);
334     }
335     myMaxOrthoVertsProjections[aDim] = aMax;
336     myMinOrthoVertsProjections[aDim] = aMin;
337   }
338
339   // Horizontal
340   myEdgeDirs[0] = myVertices[4] - myVertices[0];
341   // Vertical
342   myEdgeDirs[1] = myVertices[2] - myVertices[0];
343   // LeftLower
344   myEdgeDirs[2] = myVertices[2] - myVertices[3];
345   // RightLower
346   myEdgeDirs[3] = myVertices[6] - myVertices[7];
347   // LeftUpper
348   myEdgeDirs[4] = myVertices[0] - myVertices[1];
349   // RightUpper
350   myEdgeDirs[5] = myVertices[4] - myVertices[5];
351 }
352
353 // =======================================================================
354 // function : Transform
355 // purpose  : Returns a copy of the frustum transformed according to the matrix given
356 // =======================================================================
357 NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Transform (const gp_Trsf& theTrsf)
358 {
359   SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum();
360
361   aRes->myNearPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myNearPickedPnt);
362   aRes->myFarPickedPnt  = SelectMgr_MatOp::Transform (theTrsf, myFarPickedPnt);
363   aRes->myViewRayDir    = aRes->myFarPickedPnt - aRes->myNearPickedPnt;
364
365   aRes->myIsOrthographic = myIsOrthographic;
366
367   // LeftTopNear
368   aRes->myVertices[0] = SelectMgr_MatOp::Transform (theTrsf, myVertices[0]);
369   // LeftTopFar
370   aRes->myVertices[1] = SelectMgr_MatOp::Transform (theTrsf, myVertices[1]);
371   // LeftBottomNear
372   aRes->myVertices[2] = SelectMgr_MatOp::Transform (theTrsf, myVertices[2]);
373   // LeftBottomFar
374   aRes->myVertices[3] = SelectMgr_MatOp::Transform (theTrsf, myVertices[3]);
375   // RightTopNear
376   aRes->myVertices[4] = SelectMgr_MatOp::Transform (theTrsf, myVertices[4]);
377   // RightTopFar
378   aRes->myVertices[5] = SelectMgr_MatOp::Transform (theTrsf, myVertices[5]);
379   // RightBottomNear
380   aRes->myVertices[6] = SelectMgr_MatOp::Transform (theTrsf, myVertices[6]);
381   // RightBottomFar
382   aRes->myVertices[7] = SelectMgr_MatOp::Transform (theTrsf, myVertices[7]);
383
384   // compute frustum normals
385   computeNormals (aRes->myVertices, aRes->myPlanes);
386
387   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
388   {
389     Standard_Real aMax = -DBL_MAX;
390     Standard_Real aMin =  DBL_MAX;
391     const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx];
392     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
393     {
394       Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]);
395       aMax = Max (aMax, aProjection);
396       aMin = Min (aMin, aProjection);
397     }
398     aRes->myMaxVertsProjections[aPlaneIdx] = aMax;
399     aRes->myMinVertsProjections[aPlaneIdx] = aMin;
400   }
401
402   SelectMgr_Vec3 aDimensions[3] =
403   {
404     SelectMgr_Vec3 (1.0, 0.0, 0.0),
405     SelectMgr_Vec3 (0.0, 1.0, 0.0),
406     SelectMgr_Vec3 (0.0, 0.0, 1.0)
407   };
408
409   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
410   {
411     Standard_Real aMax = -DBL_MAX;
412     Standard_Real aMin =  DBL_MAX;
413     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
414     {
415       Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]);
416       aMax = Max (aMax, aProjection);
417       aMin = Min (aMin, aProjection);
418     }
419     aRes->myMaxOrthoVertsProjections[aDim] = aMax;
420     aRes->myMinOrthoVertsProjections[aDim] = aMin;
421   }
422
423   // Horizontal
424   aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0];
425   // Vertical
426   aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0];
427   // LeftLower
428   aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3];
429   // RightLower
430   aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7];
431   // LeftUpper
432   aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1];
433   // RightUpper
434   aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5];
435
436   return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
437 }
438
439 // =======================================================================
440 // function : Scale
441 // purpose  : IMPORTANT: Makes sense only for frustum built on a single point!
442 //            Returns a copy of the frustum resized according to the scale factor given
443 // =======================================================================
444 NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Scale (const Standard_Real theScaleFactor)
445 {
446   SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum();
447
448   aRes->myNearPickedPnt = myNearPickedPnt;
449   aRes->myFarPickedPnt  = myFarPickedPnt;
450   aRes->myViewRayDir    = myViewRayDir;
451
452   aRes->myIsOrthographic = myIsOrthographic;
453
454     // LeftTopNear
455   aRes->myVertices[0] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
456                                                           myMousePos.Y() + theScaleFactor / 2.0,
457                                                           0.0);
458   // LeftTopFar
459   aRes->myVertices[1] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
460                                                           myMousePos.Y() + theScaleFactor / 2.0,
461                                                           1.0);
462   // LeftBottomNear
463   aRes->myVertices[2] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
464                                                           myMousePos.Y() - theScaleFactor / 2.0,
465                                                           0.0);
466   // LeftBottomFar
467   aRes->myVertices[3] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
468                                                           myMousePos.Y() - theScaleFactor / 2.0,
469                                                           1.0);
470   // RightTopNear
471   aRes->myVertices[4] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
472                                                           myMousePos.Y() + theScaleFactor / 2.0,
473                                                           0.0);
474   // RightTopFar
475   aRes->myVertices[5] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
476                                                           myMousePos.Y() + theScaleFactor / 2.0,
477                                                           1.0);
478   // RightBottomNear
479   aRes->myVertices[6] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
480                                                           myMousePos.Y() - theScaleFactor / 2.0,
481                                                           0.0);
482   // RightBottomFar
483   aRes->myVertices[7] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
484                                                           myMousePos.Y() - theScaleFactor / 2.0,
485                                                           1.0);
486   // compute frustum normals
487   computeNormals (aRes->myVertices, aRes->myPlanes);
488
489   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
490   {
491     Standard_Real aMax = -DBL_MAX;
492     Standard_Real aMin =  DBL_MAX;
493     const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx];
494     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
495     {
496       Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]);
497       aMax = Max (aMax, aProjection);
498       aMin = Min (aMin, aProjection);
499     }
500     aRes->myMaxVertsProjections[aPlaneIdx] = aMax;
501     aRes->myMinVertsProjections[aPlaneIdx] = aMin;
502   }
503
504   SelectMgr_Vec3 aDimensions[3] =
505   {
506     SelectMgr_Vec3 (1.0, 0.0, 0.0),
507     SelectMgr_Vec3 (0.0, 1.0, 0.0),
508     SelectMgr_Vec3 (0.0, 0.0, 1.0)
509   };
510
511   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
512   {
513     Standard_Real aMax = -DBL_MAX;
514     Standard_Real aMin =  DBL_MAX;
515     for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
516     {
517       Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]);
518       aMax = Max (aMax, aProjection);
519       aMin = Min (aMin, aProjection);
520     }
521     aRes->myMaxOrthoVertsProjections[aDim] = aMax;
522     aRes->myMinOrthoVertsProjections[aDim] = aMin;
523   }
524
525   // Horizontal
526   aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0];
527   // Vertical
528   aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0];
529   // LeftLower
530   aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3];
531   // RightLower
532   aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7];
533   // LeftUpper
534   aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1];
535   // RightUpper
536   aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5];
537
538   return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
539 }
540
541 // =======================================================================
542 // function : Overlaps
543 // purpose  : Returns true if selecting volume is overlapped by
544 //            axis-aligned bounding box with minimum corner at point
545 //            theMinPnt and maximum at point theMaxPnt
546 // =======================================================================
547 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin,
548                                                          const SelectMgr_Vec3& theBoxMax,
549                                                          Standard_Boolean*     theInside)
550 {
551   return hasOverlap (theBoxMin, theBoxMax, theInside);
552 }
553
554 // =======================================================================
555 // function : Overlaps
556 // purpose  : SAT intersection test between defined volume and
557 //            given axis-aligned box
558 // =======================================================================
559 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const BVH_Box<Standard_Real, 3>& theBox,
560                                                          Standard_Real& theDepth)
561 {
562   const SelectMgr_Vec3& aMinPnt = theBox.CornerMin();
563   const SelectMgr_Vec3& aMaxPnt = theBox.CornerMax();
564   if (!hasOverlap (aMinPnt, aMaxPnt))
565     return Standard_False;
566
567   SelectMgr_Vec3 aNearestPnt = SelectMgr_Vec3 (RealLast(), RealLast(), RealLast());
568   aNearestPnt.x() = Max (Min (myNearPickedPnt.x(), aMaxPnt.x()), aMinPnt.x());
569   aNearestPnt.y() = Max (Min (myNearPickedPnt.y(), aMaxPnt.y()), aMinPnt.y());
570   aNearestPnt.z() = Max (Min (myNearPickedPnt.z(), aMaxPnt.z()), aMinPnt.z());
571
572   theDepth = DISTANCE (aNearestPnt, myNearPickedPnt);
573
574   return Standard_True;
575 }
576
577 // =======================================================================
578 // function : Overlaps
579 // purpose  : Intersection test between defined volume and given point
580 // =======================================================================
581 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
582                                                          Standard_Real& theDepth)
583 {
584   if (!hasOverlap (thePnt))
585     return Standard_False;
586
587   SelectMgr_Vec3 aPnt (thePnt.X(), thePnt.Y(), thePnt.Z());
588   SelectMgr_Vec3 aV = aPnt - myNearPickedPnt;
589   SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * (DOT (aV, myViewRayDir) / DOT (myViewRayDir, myViewRayDir));
590
591   theDepth = DISTANCE (aDetectedPnt, myNearPickedPnt);
592
593   return Standard_True;
594 }
595
596 // =======================================================================
597 // function : Overlaps
598 // purpose  : Checks if line segment overlaps selecting frustum
599 // =======================================================================
600 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
601                                                          const gp_Pnt& thePnt2,
602                                                          Standard_Real& theDepth)
603 {
604   theDepth = -DBL_MAX;
605   if (!hasOverlap (thePnt1, thePnt2))
606     return Standard_False;
607
608   segmentSegmentDistance (thePnt1, thePnt2, theDepth);
609   return Standard_True;
610 }
611
612 // =======================================================================
613 // function : Overlaps
614 // purpose  : SAT intersection test between defined volume and given
615 //            ordered set of points, representing line segments. The test
616 //            may be considered of interior part or boundary line defined
617 //            by segments depending on given sensitivity type
618 // =======================================================================
619 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
620                                                          Select3D_TypeOfSensitivity theSensType,
621                                                          Standard_Real& theDepth)
622 {
623   if (theSensType == Select3D_TOS_BOUNDARY)
624   {
625     Standard_Integer aMatchingSegmentsNb = -1;
626     theDepth = DBL_MAX;
627     Standard_Integer aLower = theArrayOfPnts->Lower();
628     Standard_Integer anUpper = theArrayOfPnts->Upper();
629
630     for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter)
631     {
632       const gp_Pnt& aStartPnt = theArrayOfPnts->Value (aPntIter);
633       const gp_Pnt& aEndPnt = aPntIter == anUpper ? theArrayOfPnts->Value (aLower)
634         : theArrayOfPnts->Value (aPntIter + 1);
635
636       if (hasOverlap (aStartPnt, aEndPnt))
637       {
638         aMatchingSegmentsNb++;
639         Standard_Real aSegmentDepth = RealLast();
640         segmentSegmentDistance (aStartPnt, aEndPnt, aSegmentDepth);
641         theDepth = Min (theDepth, aSegmentDepth);
642       }
643     }
644
645     if (aMatchingSegmentsNb == -1)
646       return Standard_False;
647   }
648   else if (theSensType == Select3D_TOS_INTERIOR)
649   {
650     SelectMgr_Vec3 aPolyNorm (RealLast());
651     if (!hasOverlap (theArrayOfPnts, aPolyNorm))
652       return Standard_False;
653
654     segmentPlaneIntersection (aPolyNorm,
655                               theArrayOfPnts->Value (theArrayOfPnts->Lower()),
656                               theDepth);
657   }
658
659   return Standard_True;
660 }
661
662 // =======================================================================
663 // function : Overlaps
664 // purpose  : SAT intersection test between defined volume and given
665 //            triangle. The test may be considered of interior part or
666 //            boundary line defined by triangle vertices depending on
667 //            given sensitivity type
668 // =======================================================================
669 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
670                                                          const gp_Pnt& thePnt2,
671                                                          const gp_Pnt& thePnt3,
672                                                          Select3D_TypeOfSensitivity theSensType,
673                                                          Standard_Real& theDepth)
674 {
675   if (theSensType == Select3D_TOS_BOUNDARY)
676   {
677     Handle(TColgp_HArray1OfPnt) aPntsArray = new TColgp_HArray1OfPnt(1, 4);
678     aPntsArray->SetValue (1, thePnt1);
679     aPntsArray->SetValue (2, thePnt2);
680     aPntsArray->SetValue (3, thePnt3);
681     aPntsArray->SetValue (4, thePnt1);
682     return Overlaps (aPntsArray, Select3D_TOS_BOUNDARY, theDepth);
683   }
684   else if (theSensType == Select3D_TOS_INTERIOR)
685   {
686     SelectMgr_Vec3 aTriangleNormal (RealLast());
687     if (!hasOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal))
688       return Standard_False;
689
690     // check if intersection point belongs to triangle's interior part
691     SelectMgr_Vec3 aPnt1 (thePnt1.X(), thePnt1.Y(), thePnt1.Z());
692     SelectMgr_Vec3 aTrEdges[3] = { SelectMgr_Vec3 (thePnt2.X() - thePnt1.X(), thePnt2.Y() - thePnt1.Y(), thePnt2.Z() - thePnt1.Z()),
693                                    SelectMgr_Vec3 (thePnt3.X() - thePnt2.X(), thePnt3.Y() - thePnt2.Y(), thePnt3.Z() - thePnt2.Z()),
694                                    SelectMgr_Vec3 (thePnt1.X() - thePnt3.X(), thePnt1.Y() - thePnt3.Y(), thePnt1.Z() - thePnt3.Z()) };
695     SelectMgr_Vec3 anEdge = (aPnt1 - myNearPickedPnt) * (1.0 / DOT (aTriangleNormal, myViewRayDir));
696
697     Standard_Real aTime = DOT (aTriangleNormal, anEdge);
698
699     SelectMgr_Vec3 aVec = SelectMgr_Vec3 (myViewRayDir.y() * anEdge.z() - myViewRayDir.z() * anEdge.y(),
700                                           myViewRayDir.z() * anEdge.x() - myViewRayDir.x() * anEdge.z(),
701                                           myViewRayDir.x() * anEdge.y() - myViewRayDir.y() * anEdge.x());
702
703     Standard_Real anU = DOT (aVec, aTrEdges[2]);
704     Standard_Real aV  = DOT (aVec, aTrEdges[0]);
705
706     Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
707
708     if (isInterior)
709     {
710       SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * aTime;
711       theDepth = DISTANCE (myNearPickedPnt, aDetectedPnt);
712       return Standard_True;
713     }
714
715     gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
716     Standard_Real aMinDist = RealLast();
717     Standard_Integer aNearestEdgeIdx = -1;
718     SelectMgr_Vec3 aPtOnPlane = myNearPickedPnt + myViewRayDir * aTime;
719     for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
720     {
721       SelectMgr_Vec3 aW = SelectMgr_Vec3 (aPtOnPlane.x() - aPnts[anEdgeIdx].X(),
722                                           aPtOnPlane.y() - aPnts[anEdgeIdx].Y(),
723                                           aPtOnPlane.z() - aPnts[anEdgeIdx].Z());
724       Standard_Real aCoef = DOT (aTrEdges[anEdgeIdx], aW) / DOT (aTrEdges[anEdgeIdx], aTrEdges[anEdgeIdx]);
725       Standard_Real aDist = DISTANCE (aPtOnPlane, SelectMgr_Vec3 (aPnts[anEdgeIdx].X() + aCoef * aTrEdges[anEdgeIdx].x(),
726                                                                   aPnts[anEdgeIdx].Y() + aCoef * aTrEdges[anEdgeIdx].y(),
727                                                                   aPnts[anEdgeIdx].Z() + aCoef * aTrEdges[anEdgeIdx].z()));
728       if (aMinDist > aDist)
729       {
730         aMinDist = aDist;
731         aNearestEdgeIdx = anEdgeIdx;
732       }
733     }
734     segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], theDepth);
735   }
736
737   return Standard_True;
738 }
739
740 // =======================================================================
741 // function : DistToGeometryCenter
742 // purpose  : Measures distance between 3d projection of user-picked
743 //            screen point and given point theCOG
744 // =======================================================================
745 Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG)
746 {
747   const SelectMgr_Vec3& aCOG = SelectMgr_Vec3 (theCOG.X(), theCOG.Y(), theCOG.Z());
748   return DISTANCE (aCOG, myNearPickedPnt);
749 }
750
751 // =======================================================================
752 // function : DetectedPoint
753 // purpose  : Calculates the point on a view ray that was detected during
754 //            the run of selection algo by given depth
755 // =======================================================================
756 SelectMgr_Vec3 SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const
757 {
758   return myNearPickedPnt + myViewRayDir.Normalized() * theDepth;
759 }
760
761 // =======================================================================
762 // function : IsClipped
763 // purpose  : Checks if the point of sensitive in which selection was
764 //            detected belongs to the region defined by clipping planes
765 // =======================================================================
766 Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes,
767                                                           const Standard_Real theDepth)
768 {
769   Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes);
770   Standard_Real aMaxDepth = DBL_MAX;
771   Standard_Real aMinDepth = -DBL_MAX;
772   Standard_Real aPlaneA, aPlaneB, aPlaneC, aPlaneD;
773   for ( ; aPlaneIt.More(); aPlaneIt.Next())
774   {
775     const Handle(Graphic3d_ClipPlane)& aClipPlane = aPlaneIt.Value();
776     if (!aClipPlane->IsOn())
777       continue;
778
779     gp_Pln aGeomPlane = aClipPlane->ToPlane();
780
781     aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD);
782
783     const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ();
784
785     Standard_Real aDotProduct = DOTp (myViewRayDir, aPlaneDirXYZ);
786     Standard_Real aDistance = - (DOTp (myNearPickedPnt, aPlaneDirXYZ) + aPlaneD);
787
788     // check whether the pick line is parallel to clip plane
789     if (Abs (aDotProduct) < Precision::Angular())
790     {
791       // line lies below the plane and is not clipped, skip
792       continue;
793     }
794
795     // compute distance to point of pick line intersection with the plane
796     Standard_Real aParam = aDistance / aDotProduct;
797
798     // check if ray intersects the plane, in case aIntDist < 0
799     // the plane is "behind" the ray
800     if (aParam < 0.0)
801     {
802       continue;
803     }
804
805     const SelectMgr_Vec3 anIntersectionPt = myNearPickedPnt + myViewRayDir * aParam;
806     const Standard_Real aDistToPln = DISTANCE (anIntersectionPt, myNearPickedPnt);
807
808     // change depth limits for case of opposite and directed planes
809     if (aDotProduct < 0.0)
810     {
811       aMaxDepth = Min (aDistToPln, aMaxDepth);
812     }
813     else if (aDistToPln > aMinDepth)
814     {
815       aMinDepth = Max (aDistToPln, aMinDepth);
816     }
817   }
818
819   return (theDepth <= aMinDepth || theDepth >= aMaxDepth);
820 }