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