1 // Created on: 2014-05-22
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <NCollection_Vector.hxx>
17 #include <Poly_Array1OfTriangle.hxx>
19 #include <SelectMgr_RectangularFrustum.hxx>
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())))
26 // =======================================================================
27 // function : segmentSegmentDistance
29 // =======================================================================
30 void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1,
31 const gp_Pnt& theSegPnt2,
32 Standard_Real& theDepth)
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;
50 if (aCoef < Precision::Confusion())
59 aSn = (aB * anE - aC * aD);
60 aTn = (anA * anE - aB * aD);
92 else if ((-aD + aB) > anA)
99 aSc = (Abs (aSn) < Precision::Confusion() ? 0.0 : aSn / aSd);
100 aTc = (Abs (aTn) < Precision::Confusion() ? 0.0 : aTn / aTd);
102 SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + myViewRayDir * aTc;
103 theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
106 // =======================================================================
107 // function : segmentPlaneIntersection
109 // =======================================================================
110 void SelectMgr_RectangularFrustum::segmentPlaneIntersection (const SelectMgr_Vec3& thePlane,
111 const gp_Pnt& thePntOnPlane,
112 Standard_Real& theDepth)
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);
121 if (Abs (aD) < Precision::Confusion())
123 if (Abs (aN) < Precision::Angular())
135 Standard_Real aParam = aN / aD;
136 if (aParam < 0.0 || aParam > 1.0)
142 SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + anU * aParam;
143 theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
148 // =======================================================================
149 // function : computeNormals
150 // purpose : Computes normals to frustum faces
151 // =======================================================================
152 void computeNormals (const SelectMgr_Vec3* theVertices, SelectMgr_Vec3* theNormals)
155 theNormals[0] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0],
156 theVertices[4] - theVertices[0]);
158 theNormals[1] = SelectMgr_Vec3::Cross (theVertices[3] - theVertices[2],
159 theVertices[6] - theVertices[2]);
161 theNormals[2] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0],
162 theVertices[2] - theVertices[0]);
164 theNormals[3] = SelectMgr_Vec3::Cross (theVertices[5] - theVertices[4],
165 theVertices[6] - theVertices[4]);
167 theNormals[4] = SelectMgr_Vec3::Cross (theVertices[6] - theVertices[4],
168 theVertices[0] - theVertices[4]);
170 theNormals[5] = SelectMgr_Vec3::Cross (theVertices[7] - theVertices[5],
171 theVertices[1] - theVertices[5]);
175 // =======================================================================
177 // purpose : Build volume according to the point and given pixel
179 // =======================================================================
180 void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint)
182 myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 0.0);
183 myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 1.0);
184 myViewRayDir = myFarPickedPnt - myNearPickedPnt;
185 myMousePos = thePoint;
188 myVertices[0] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
189 thePoint.Y() + myPixelTolerance / 2.0,
192 myVertices[1] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
193 thePoint.Y() + myPixelTolerance / 2.0,
196 myVertices[2] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
197 thePoint.Y() - myPixelTolerance / 2.0,
200 myVertices[3] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
201 thePoint.Y() - myPixelTolerance / 2.0,
204 myVertices[4] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
205 thePoint.Y() + myPixelTolerance / 2.0,
208 myVertices[5] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
209 thePoint.Y() + myPixelTolerance / 2.0,
212 myVertices[6] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
213 thePoint.Y() - myPixelTolerance / 2.0,
216 myVertices[7] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
217 thePoint.Y() - myPixelTolerance / 2.0,
220 // compute frustum normals
221 computeNormals (myVertices, myPlanes);
223 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
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)
230 Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
231 aMax = Max (aMax, aProjection);
232 aMin = Min (aMin, aProjection);
234 myMaxVertsProjections[aPlaneIdx] = aMax;
235 myMinVertsProjections[aPlaneIdx] = aMin;
238 SelectMgr_Vec3 aDimensions[3] =
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)
245 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
247 Standard_Real aMax = -DBL_MAX;
248 Standard_Real aMin = DBL_MAX;
249 for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
251 Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
252 aMax = Max (aProjection, aMax);
253 aMin = Min (aProjection, aMin);
255 myMaxOrthoVertsProjections[aDim] = aMax;
256 myMinOrthoVertsProjections[aDim] = aMin;
260 myEdgeDirs[0] = myVertices[4] - myVertices[0];
262 myEdgeDirs[1] = myVertices[2] - myVertices[0];
264 myEdgeDirs[2] = myVertices[2] - myVertices[3];
266 myEdgeDirs[3] = myVertices[6] - myVertices[7];
268 myEdgeDirs[4] = myVertices[0] - myVertices[1];
270 myEdgeDirs[5] = myVertices[4] - myVertices[5];
273 // =======================================================================
275 // purpose : Build volume according to the selected rectangle
276 // =======================================================================
277 void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d& theMinPnt,
278 const gp_Pnt2d& theMaxPnt)
280 myNearPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5,
281 (theMinPnt.Y() + theMaxPnt.Y()) * 0.5,
283 myFarPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5,
284 (theMinPnt.Y() + theMaxPnt.Y()) * 0.5,
286 myViewRayDir = myFarPickedPnt - myNearPickedPnt;
289 myVertices[0] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
293 myVertices[1] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
297 myVertices[2] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
301 myVertices[3] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
305 myVertices[4] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
309 myVertices[5] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
313 myVertices[6] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
317 myVertices[7] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
321 // compute frustum normals
322 computeNormals (myVertices, myPlanes);
324 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
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)
331 Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
332 aMax = Max (aMax, aProjection);
333 aMin = Min (aMin, aProjection);
335 myMaxVertsProjections[aPlaneIdx] = aMax;
336 myMinVertsProjections[aPlaneIdx] = aMin;
339 SelectMgr_Vec3 aDimensions[3] =
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)
346 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
348 Standard_Real aMax = -DBL_MAX;
349 Standard_Real aMin = DBL_MAX;
350 for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
352 Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
353 aMax = Max (aMax, aProjection);
354 aMin = Min (aMin, aProjection);
356 myMaxOrthoVertsProjections[aDim] = aMax;
357 myMinOrthoVertsProjections[aDim] = aMin;
361 myEdgeDirs[0] = myVertices[4] - myVertices[0];
363 myEdgeDirs[1] = myVertices[2] - myVertices[0];
365 myEdgeDirs[2] = myVertices[2] - myVertices[3];
367 myEdgeDirs[3] = myVertices[6] - myVertices[7];
369 myEdgeDirs[4] = myVertices[0] - myVertices[1];
371 myEdgeDirs[5] = myVertices[4] - myVertices[5];
374 // =======================================================================
375 // function : Transform
376 // purpose : Returns a copy of the frustum transformed according to the matrix given
377 // =======================================================================
378 NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Transform (const gp_Trsf& theTrsf)
380 SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum();
382 aRes->myNearPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myNearPickedPnt);
383 aRes->myFarPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myFarPickedPnt);
384 aRes->myViewRayDir = aRes->myFarPickedPnt - aRes->myNearPickedPnt;
386 aRes->myIsOrthographic = myIsOrthographic;
389 aRes->myVertices[0] = SelectMgr_MatOp::Transform (theTrsf, myVertices[0]);
391 aRes->myVertices[1] = SelectMgr_MatOp::Transform (theTrsf, myVertices[1]);
393 aRes->myVertices[2] = SelectMgr_MatOp::Transform (theTrsf, myVertices[2]);
395 aRes->myVertices[3] = SelectMgr_MatOp::Transform (theTrsf, myVertices[3]);
397 aRes->myVertices[4] = SelectMgr_MatOp::Transform (theTrsf, myVertices[4]);
399 aRes->myVertices[5] = SelectMgr_MatOp::Transform (theTrsf, myVertices[5]);
401 aRes->myVertices[6] = SelectMgr_MatOp::Transform (theTrsf, myVertices[6]);
403 aRes->myVertices[7] = SelectMgr_MatOp::Transform (theTrsf, myVertices[7]);
405 // compute frustum normals
406 computeNormals (aRes->myVertices, aRes->myPlanes);
408 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
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)
415 Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]);
416 aMax = Max (aMax, aProjection);
417 aMin = Min (aMin, aProjection);
419 aRes->myMaxVertsProjections[aPlaneIdx] = aMax;
420 aRes->myMinVertsProjections[aPlaneIdx] = aMin;
423 SelectMgr_Vec3 aDimensions[3] =
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)
430 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
432 Standard_Real aMax = -DBL_MAX;
433 Standard_Real aMin = DBL_MAX;
434 for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
436 Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]);
437 aMax = Max (aMax, aProjection);
438 aMin = Min (aMin, aProjection);
440 aRes->myMaxOrthoVertsProjections[aDim] = aMax;
441 aRes->myMinOrthoVertsProjections[aDim] = aMin;
445 aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0];
447 aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0];
449 aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3];
451 aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7];
453 aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1];
455 aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5];
457 return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
460 // =======================================================================
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 // =======================================================================
465 NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Scale (const Standard_Real theScaleFactor)
467 SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum();
469 aRes->myNearPickedPnt = myNearPickedPnt;
470 aRes->myFarPickedPnt = myFarPickedPnt;
471 aRes->myViewRayDir = myViewRayDir;
473 aRes->myIsOrthographic = myIsOrthographic;
476 aRes->myVertices[0] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
477 myMousePos.Y() + theScaleFactor / 2.0,
480 aRes->myVertices[1] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
481 myMousePos.Y() + theScaleFactor / 2.0,
484 aRes->myVertices[2] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
485 myMousePos.Y() - theScaleFactor / 2.0,
488 aRes->myVertices[3] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0,
489 myMousePos.Y() - theScaleFactor / 2.0,
492 aRes->myVertices[4] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
493 myMousePos.Y() + theScaleFactor / 2.0,
496 aRes->myVertices[5] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
497 myMousePos.Y() + theScaleFactor / 2.0,
500 aRes->myVertices[6] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
501 myMousePos.Y() - theScaleFactor / 2.0,
504 aRes->myVertices[7] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0,
505 myMousePos.Y() - theScaleFactor / 2.0,
507 // compute frustum normals
508 computeNormals (aRes->myVertices, aRes->myPlanes);
510 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
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)
517 Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]);
518 aMax = Max (aMax, aProjection);
519 aMin = Min (aMin, aProjection);
521 aRes->myMaxVertsProjections[aPlaneIdx] = aMax;
522 aRes->myMinVertsProjections[aPlaneIdx] = aMin;
525 SelectMgr_Vec3 aDimensions[3] =
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)
532 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
534 Standard_Real aMax = -DBL_MAX;
535 Standard_Real aMin = DBL_MAX;
536 for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
538 Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]);
539 aMax = Max (aMax, aProjection);
540 aMin = Min (aMin, aProjection);
542 aRes->myMaxOrthoVertsProjections[aDim] = aMax;
543 aRes->myMinOrthoVertsProjections[aDim] = aMin;
547 aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0];
549 aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0];
551 aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3];
553 aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7];
555 aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1];
557 aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5];
559 return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
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 // =======================================================================
568 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin,
569 const SelectMgr_Vec3& theBoxMax,
570 Standard_Boolean* theInside)
572 return hasOverlap (theBoxMin, theBoxMax, theInside);
575 // =======================================================================
576 // function : Overlaps
577 // purpose : SAT intersection test between defined volume and
578 // given axis-aligned box
579 // =======================================================================
580 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const BVH_Box<Standard_Real, 3>& theBox,
581 Standard_Real& theDepth)
583 const SelectMgr_Vec3& aMinPnt = theBox.CornerMin();
584 const SelectMgr_Vec3& aMaxPnt = theBox.CornerMax();
585 if (!hasOverlap (aMinPnt, aMaxPnt))
586 return Standard_False;
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());
593 theDepth = DISTANCE (aNearestPnt, myNearPickedPnt);
595 return Standard_True;
598 // =======================================================================
599 // function : Overlaps
600 // purpose : Intersection test between defined volume and given point
601 // =======================================================================
602 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
603 Standard_Real& theDepth)
605 if (!hasOverlap (thePnt))
606 return Standard_False;
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));
612 theDepth = DISTANCE (aDetectedPnt, myNearPickedPnt);
614 return Standard_True;
617 // =======================================================================
618 // function : Overlaps
619 // purpose : Checks if line segment overlaps selecting frustum
620 // =======================================================================
621 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
622 const gp_Pnt& thePnt2,
623 Standard_Real& theDepth)
626 if (!hasOverlap (thePnt1, thePnt2))
627 return Standard_False;
629 segmentSegmentDistance (thePnt1, thePnt2, theDepth);
630 return Standard_True;
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 // =======================================================================
640 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
641 Select3D_TypeOfSensitivity theSensType,
642 Standard_Real& theDepth)
644 if (theSensType == Select3D_TOS_BOUNDARY)
646 Standard_Integer aMatchingSegmentsNb = -1;
648 Standard_Integer aLower = theArrayOfPnts->Lower();
649 Standard_Integer anUpper = theArrayOfPnts->Upper();
651 for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter)
653 const gp_Pnt& aStartPnt = theArrayOfPnts->Value (aPntIter);
654 const gp_Pnt& aEndPnt = aPntIter == anUpper ? theArrayOfPnts->Value (aLower)
655 : theArrayOfPnts->Value (aPntIter + 1);
657 if (hasOverlap (aStartPnt, aEndPnt))
659 aMatchingSegmentsNb++;
660 Standard_Real aSegmentDepth = RealLast();
661 segmentSegmentDistance (aStartPnt, aEndPnt, aSegmentDepth);
662 theDepth = Min (theDepth, aSegmentDepth);
666 if (aMatchingSegmentsNb == -1)
667 return Standard_False;
669 else if (theSensType == Select3D_TOS_INTERIOR)
671 SelectMgr_Vec3 aPolyNorm (RealLast());
672 if (!hasOverlap (theArrayOfPnts, aPolyNorm))
673 return Standard_False;
675 segmentPlaneIntersection (aPolyNorm,
676 theArrayOfPnts->Value (theArrayOfPnts->Lower()),
680 return Standard_True;
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 // =======================================================================
690 Standard_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)
696 if (theSensType == Select3D_TOS_BOUNDARY)
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);
705 else if (theSensType == Select3D_TOS_INTERIOR)
707 SelectMgr_Vec3 aTriangleNormal (RealLast());
708 if (!hasOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal))
709 return Standard_False;
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));
718 Standard_Real aTime = DOT (aTriangleNormal, anEdge);
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());
724 Standard_Real anU = DOT (aVec, aTrEdges[2]);
725 Standard_Real aV = DOT (aVec, aTrEdges[0]);
727 Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
731 SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * aTime;
732 theDepth = DISTANCE (myNearPickedPnt, aDetectedPnt);
733 return Standard_True;
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)
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)
752 aNearestEdgeIdx = anEdgeIdx;
755 segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], theDepth);
758 return Standard_True;
761 // =======================================================================
762 // function : DistToGeometryCenter
763 // purpose : Measures distance between 3d projection of user-picked
764 // screen point and given point theCOG
765 // =======================================================================
766 Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG)
768 const SelectMgr_Vec3& aCOG = SelectMgr_Vec3 (theCOG.X(), theCOG.Y(), theCOG.Z());
769 return DISTANCE (aCOG, myNearPickedPnt);
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 // =======================================================================
777 SelectMgr_Vec3 SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const
779 return myNearPickedPnt + myViewRayDir.Normalized() * theDepth;
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 // =======================================================================
787 Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes,
788 const Standard_Real theDepth)
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())
796 const Handle(Graphic3d_ClipPlane)& aClipPlane = aPlaneIt.Value();
797 if (!aClipPlane->IsOn())
800 gp_Pln aGeomPlane = aClipPlane->ToPlane();
802 aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD);
804 const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ();
806 Standard_Real aDotProduct = DOTp (myViewRayDir, aPlaneDirXYZ);
807 Standard_Real aDistance = - (DOTp (myNearPickedPnt, aPlaneDirXYZ) + aPlaneD);
809 // check whether the pick line is parallel to clip plane
810 if (Abs (aDotProduct) < Precision::Angular())
812 // line lies below the plane and is not clipped, skip
816 // compute distance to point of pick line intersection with the plane
817 Standard_Real aParam = aDistance / aDotProduct;
819 // check if ray intersects the plane, in case aIntDist < 0
820 // the plane is "behind" the ray
826 const SelectMgr_Vec3 anIntersectionPt = myNearPickedPnt + myViewRayDir * aParam;
827 const Standard_Real aDistToPln = DISTANCE (anIntersectionPt, myNearPickedPnt);
829 // change depth limits for case of opposite and directed planes
830 if (aDotProduct < 0.0)
832 aMaxDepth = Min (aDistToPln, aMaxDepth);
834 else if (aDistToPln > aMinDepth)
836 aMinDepth = Max (aDistToPln, aMinDepth);
840 return (theDepth <= aMinDepth || theDepth >= aMaxDepth);