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