0026249: Visualization, TKV3d - fix possible division by zero in SelectMgr_Rectangula...
[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;
a52c06d5 47 Standard_Real aSn = aCoef;
f751596e 48 Standard_Real aTc, aTn, aTd = aCoef;
49
50 if (aCoef < Precision::Confusion())
51 {
f751596e 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 {
f751596e 61 aTn = anE;
62 aTd = aC;
63 }
a52c06d5 64 else if (aSn > aCoef)
f751596e 65 {
f751596e 66 aTn = anE + aB;
67 aTd = aC;
68 }
69 }
70
71 if (aTn < 0.0)
72 {
73 aTn = 0.0;
f751596e 74 }
75 else if (aTn > aTd)
76 {
77 aTn = aTd;
f751596e 78 }
f751596e 79 aTc = (Abs (aTn) < Precision::Confusion() ? 0.0 : aTn / aTd);
80
f751596e 81 SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + myViewRayDir * aTc;
82 theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
83}
84
85// =======================================================================
86// function : segmentPlaneIntersection
87// purpose :
88// =======================================================================
89void 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
2157d6ac 125namespace
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
f751596e 154// =======================================================================
155// function : Build
156// purpose : Build volume according to the point and given pixel
157// tolerance
158// =======================================================================
159void 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;
28ee613b 164 myMousePos = thePoint;
f751596e 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);
2157d6ac 198
199 // compute frustum normals
200 computeNormals (myVertices, myPlanes);
f751596e 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// =======================================================================
256void 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
2157d6ac 296 myVertices[7] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
f751596e 297 theMinPnt.Y(),
298 1.0);
299
2157d6ac 300 // compute frustum normals
301 computeNormals (myVertices, myPlanes);
f751596e 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// =======================================================================
357NCollection_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
2157d6ac 384 // compute frustum normals
385 computeNormals (aRes->myVertices, aRes->myPlanes);
28ee613b 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// =======================================================================
444NCollection_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);
2157d6ac 486 // compute frustum normals
487 computeNormals (aRes->myVertices, aRes->myPlanes);
f751596e 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// =======================================================================
2157d6ac 547Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin,
548 const SelectMgr_Vec3& theBoxMax,
549 Standard_Boolean* theInside)
f751596e 550{
2157d6ac 551 return hasOverlap (theBoxMin, theBoxMax, theInside);
f751596e 552}
553
554// =======================================================================
555// function : Overlaps
556// purpose : SAT intersection test between defined volume and
557// given axis-aligned box
558// =======================================================================
7ab15952 559Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const BVH_Box<Standard_Real, 3>& theBox,
560 Standard_Real& theDepth)
f751596e 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// =======================================================================
7ab15952 581Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
582 Standard_Real& theDepth)
f751596e 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// =======================================================================
7ab15952 600Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
601 const gp_Pnt& thePnt2,
602 Standard_Real& theDepth)
f751596e 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// =======================================================================
7ab15952 619Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
620 Select3D_TypeOfSensitivity theSensType,
621 Standard_Real& theDepth)
f751596e 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// =======================================================================
7ab15952 669Standard_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)
f751596e 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()) };
7e17e8f0 695
696 Standard_Real anAlpha = DOT (aTriangleNormal, myViewRayDir);
697 if (Abs (anAlpha) < gp::Resolution())
698 {
699 // handle degenerated triangles: in this case, there is no possible way to detect overlap correctly.
700 if (aTriangleNormal.SquareModulus() < gp::Resolution())
701 {
702 theDepth = std::numeric_limits<Standard_Real>::max();
703 return Standard_False;
704 }
705
706 // handle the case when triangle normal and selecting frustum direction are orthogonal: for this case, overlap
707 // is detected correctly, and distance to triangle's plane can be measured as distance to its arbitrary vertex.
708 const SelectMgr_Vec3 aDiff = myNearPickedPnt - aPnt1;
709 theDepth = DOT (aTriangleNormal, aDiff);
710 return Standard_True;
711 }
712
713 SelectMgr_Vec3 anEdge = (aPnt1 - myNearPickedPnt) * (1.0 / anAlpha);
f751596e 714
715 Standard_Real aTime = DOT (aTriangleNormal, anEdge);
716
717 SelectMgr_Vec3 aVec = SelectMgr_Vec3 (myViewRayDir.y() * anEdge.z() - myViewRayDir.z() * anEdge.y(),
718 myViewRayDir.z() * anEdge.x() - myViewRayDir.x() * anEdge.z(),
719 myViewRayDir.x() * anEdge.y() - myViewRayDir.y() * anEdge.x());
720
721 Standard_Real anU = DOT (aVec, aTrEdges[2]);
722 Standard_Real aV = DOT (aVec, aTrEdges[0]);
723
724 Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
725
726 if (isInterior)
727 {
728 SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * aTime;
729 theDepth = DISTANCE (myNearPickedPnt, aDetectedPnt);
730 return Standard_True;
731 }
732
733 gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
734 Standard_Real aMinDist = RealLast();
735 Standard_Integer aNearestEdgeIdx = -1;
736 SelectMgr_Vec3 aPtOnPlane = myNearPickedPnt + myViewRayDir * aTime;
737 for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
738 {
739 SelectMgr_Vec3 aW = SelectMgr_Vec3 (aPtOnPlane.x() - aPnts[anEdgeIdx].X(),
740 aPtOnPlane.y() - aPnts[anEdgeIdx].Y(),
741 aPtOnPlane.z() - aPnts[anEdgeIdx].Z());
742 Standard_Real aCoef = DOT (aTrEdges[anEdgeIdx], aW) / DOT (aTrEdges[anEdgeIdx], aTrEdges[anEdgeIdx]);
743 Standard_Real aDist = DISTANCE (aPtOnPlane, SelectMgr_Vec3 (aPnts[anEdgeIdx].X() + aCoef * aTrEdges[anEdgeIdx].x(),
744 aPnts[anEdgeIdx].Y() + aCoef * aTrEdges[anEdgeIdx].y(),
745 aPnts[anEdgeIdx].Z() + aCoef * aTrEdges[anEdgeIdx].z()));
746 if (aMinDist > aDist)
747 {
748 aMinDist = aDist;
749 aNearestEdgeIdx = anEdgeIdx;
750 }
751 }
752 segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], theDepth);
753 }
754
755 return Standard_True;
756}
757
758// =======================================================================
759// function : DistToGeometryCenter
760// purpose : Measures distance between 3d projection of user-picked
761// screen point and given point theCOG
762// =======================================================================
7ab15952 763Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG)
f751596e 764{
765 const SelectMgr_Vec3& aCOG = SelectMgr_Vec3 (theCOG.X(), theCOG.Y(), theCOG.Z());
766 return DISTANCE (aCOG, myNearPickedPnt);
767}
768
769// =======================================================================
770// function : DetectedPoint
771// purpose : Calculates the point on a view ray that was detected during
772// the run of selection algo by given depth
773// =======================================================================
774SelectMgr_Vec3 SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const
775{
95ab7717 776 return myNearPickedPnt + myViewRayDir.Normalized() * theDepth;
f751596e 777}
778
779// =======================================================================
780// function : IsClipped
781// purpose : Checks if the point of sensitive in which selection was
782// detected belongs to the region defined by clipping planes
783// =======================================================================
7ab15952 784Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes,
785 const Standard_Real theDepth)
f751596e 786{
787 Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes);
788 Standard_Real aMaxDepth = DBL_MAX;
789 Standard_Real aMinDepth = -DBL_MAX;
790 Standard_Real aPlaneA, aPlaneB, aPlaneC, aPlaneD;
791 for ( ; aPlaneIt.More(); aPlaneIt.Next())
792 {
793 const Handle(Graphic3d_ClipPlane)& aClipPlane = aPlaneIt.Value();
794 if (!aClipPlane->IsOn())
795 continue;
796
797 gp_Pln aGeomPlane = aClipPlane->ToPlane();
798
799 aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD);
800
801 const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ();
802
803 Standard_Real aDotProduct = DOTp (myViewRayDir, aPlaneDirXYZ);
804 Standard_Real aDistance = - (DOTp (myNearPickedPnt, aPlaneDirXYZ) + aPlaneD);
805
806 // check whether the pick line is parallel to clip plane
807 if (Abs (aDotProduct) < Precision::Angular())
808 {
809 // line lies below the plane and is not clipped, skip
810 continue;
811 }
812
813 // compute distance to point of pick line intersection with the plane
814 Standard_Real aParam = aDistance / aDotProduct;
815
816 // check if ray intersects the plane, in case aIntDist < 0
817 // the plane is "behind" the ray
818 if (aParam < 0.0)
819 {
820 continue;
821 }
822
823 const SelectMgr_Vec3 anIntersectionPt = myNearPickedPnt + myViewRayDir * aParam;
824 const Standard_Real aDistToPln = DISTANCE (anIntersectionPt, myNearPickedPnt);
825
826 // change depth limits for case of opposite and directed planes
827 if (aDotProduct < 0.0)
828 {
829 aMaxDepth = Min (aDistToPln, aMaxDepth);
830 }
831 else if (aDistToPln > aMinDepth)
832 {
833 aMinDepth = Max (aDistToPln, aMinDepth);
834 }
835 }
836
837 return (theDepth <= aMinDepth || theDepth >= aMaxDepth);
838}