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 <SelectMgr_RectangularFrustum.hxx>
18 #include <BVH_Tools.hxx>
20 #include <NCollection_Vector.hxx>
21 #include <Poly_Array1OfTriangle.hxx>
22 #include <SelectMgr_FrustumBuilder.hxx>
23 #include <SelectMgr_ViewClipRange.hxx>
25 // =======================================================================
26 // function : Constructor
28 // =======================================================================
29 SelectMgr_RectangularFrustum::SelectMgr_RectangularFrustum()
34 // =======================================================================
35 // function : segmentSegmentDistance
37 // =======================================================================
38 void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1,
39 const gp_Pnt& theSegPnt2,
40 SelectBasics_PickResult& thePickResult) const
42 gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ();
43 gp_XYZ aV = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); // use unnormalized vector instead of myViewRayDir to clip solutions behind Far plane
44 gp_XYZ aW = theSegPnt1.XYZ() - myNearPickedPnt.XYZ();
46 Standard_Real anA = anU.Dot (anU);
47 Standard_Real aB = anU.Dot (aV);
48 Standard_Real aC = aV.Dot (aV);
49 Standard_Real aD = anU.Dot (aW);
50 Standard_Real anE = aV.Dot (aW);
51 Standard_Real aCoef = anA * aC - aB * aB;
52 Standard_Real aSn = aCoef;
53 Standard_Real aTc, aTn, aTd = aCoef;
55 if (aCoef < gp::Resolution())
62 aSn = (aB * anE - aC * aD);
63 aTn = (anA * anE - aB * aD);
84 aTc = (Abs (aTd) < gp::Resolution() ? 0.0 : aTn / aTd);
86 const gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + aV * aTc;
87 thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale);
89 const gp_Vec aPickedVec = aClosestPnt.XYZ() - theSegPnt1.XYZ();
90 const gp_Vec aFigureVec = theSegPnt2.XYZ() - theSegPnt1.XYZ();
91 const Standard_Real aPickedVecMod = aPickedVec.Magnitude();
92 const Standard_Real aFigureVecMod = aFigureVec.Magnitude();
93 if (aPickedVecMod <= gp::Resolution()
94 || aFigureVecMod <= gp::Resolution())
96 thePickResult.SetPickedPoint (aClosestPnt);
100 const Standard_Real aCosOfAngle = aFigureVec.Dot (aPickedVec) / (aPickedVecMod * aFigureVecMod);
101 const Standard_Real aSegPntShift = Min(aFigureVecMod, Max(0.0, aCosOfAngle * aPickedVecMod));
102 thePickResult.SetPickedPoint (theSegPnt1.XYZ() + aFigureVec.XYZ() * (aSegPntShift / aFigureVecMod));
105 // =======================================================================
106 // function : segmentPlaneIntersection
108 // =======================================================================
109 bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePlane,
110 const gp_Pnt& thePntOnPlane,
111 SelectBasics_PickResult& thePickResult) const
113 gp_XYZ anU = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ(); // use unnormalized vector instead of myViewRayDir to clip solutions behind Far plane by > 1.0 check
114 gp_XYZ aW = myNearPickedPnt.XYZ() - thePntOnPlane.XYZ();
115 Standard_Real aD = thePlane.Dot (anU);
116 Standard_Real aN = -thePlane.Dot (aW);
118 if (Abs (aD) < Precision::Confusion())
120 if (Abs (aN) < Precision::Angular())
122 thePickResult.Invalidate();
127 thePickResult.Invalidate();
132 Standard_Real aParam = aN / aD;
133 if (aParam < 0.0 || aParam > 1.0) // > 1.0 check could be removed for an infinite ray and anU=myViewRayDir
135 thePickResult.Invalidate();
139 gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + anU * aParam;
140 thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale);
146 // =======================================================================
147 // function : computeFrustum
148 // purpose : Computes base frustum data: its vertices and edge directions
149 // =======================================================================
150 void computeFrustum (const gp_Pnt2d theMinPnt, const gp_Pnt2d& theMaxPnt,
151 const Handle(SelectMgr_FrustumBuilder)& theBuilder,
152 gp_Pnt* theVertices, gp_Vec* theEdges)
155 theVertices[0] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
159 theVertices[1] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
163 theVertices[2] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
167 theVertices[3] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
171 theVertices[4] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
175 theVertices[5] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
179 theVertices[6] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
183 theVertices[7] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
188 theEdges[0] = theVertices[4].XYZ() - theVertices[0].XYZ();
190 theEdges[1] = theVertices[2].XYZ() - theVertices[0].XYZ();
192 theEdges[2] = theVertices[2].XYZ() - theVertices[3].XYZ();
194 theEdges[3] = theVertices[6].XYZ() - theVertices[7].XYZ();
196 theEdges[4] = theVertices[0].XYZ() - theVertices[1].XYZ();
198 theEdges[5] = theVertices[4].XYZ() - theVertices[5].XYZ();
201 // =======================================================================
202 // function : computeNormals
203 // purpose : Computes normals to frustum faces
204 // =======================================================================
205 void computeNormals (const gp_Vec* theEdges, gp_Vec* theNormals)
208 theNormals[0] = theEdges[0].Crossed (theEdges[4]);
210 theNormals[1] = theEdges[2].Crossed (theEdges[0]);
212 theNormals[2] = theEdges[4].Crossed (theEdges[1]);
214 theNormals[3] = theEdges[1].Crossed (theEdges[5]);
216 theNormals[4] = theEdges[0].Crossed (theEdges[1]);
218 theNormals[5] = -theNormals[4];
222 // =======================================================================
223 // function : cacheVertexProjections
224 // purpose : Caches projection of frustum's vertices onto its plane directions
226 // =======================================================================
227 void SelectMgr_RectangularFrustum::cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum) const
229 if (theFrustum->Camera()->IsOrthographic())
231 // project vertices onto frustum normals
232 // Since orthographic view volume's faces are always a pairwise translation of
233 // one another, only 2 vertices that belong to opposite faces can be projected
234 // to simplify calculations.
235 Standard_Integer aVertIdxs[6] = { LeftTopNear, LeftBottomNear, // opposite planes in height direction
236 LeftBottomNear, RightBottomNear, // opposite planes in width direcion
237 LeftBottomFar, RightBottomNear }; // opposite planes in depth direction
238 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; aPlaneIdx += 2)
240 Standard_Real aProj1 = theFrustum->myPlanes[aPlaneIdx].XYZ().Dot (theFrustum->myVertices[aVertIdxs[aPlaneIdx]].XYZ());
241 Standard_Real aProj2 = theFrustum->myPlanes[aPlaneIdx].XYZ().Dot (theFrustum->myVertices[aVertIdxs[aPlaneIdx + 1]].XYZ());
242 theFrustum->myMinVertsProjections[aPlaneIdx] = Min (aProj1, aProj2);
243 theFrustum->myMaxVertsProjections[aPlaneIdx] = Max (aProj1, aProj2);
248 // project all vertices onto frustum normals
249 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
251 Standard_Real aMax = -DBL_MAX;
252 Standard_Real aMin = DBL_MAX;
253 const gp_XYZ& aPlane = theFrustum->myPlanes[aPlaneIdx].XYZ();
254 for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
256 Standard_Real aProjection = aPlane.Dot (theFrustum->myVertices[aVertIdx].XYZ());
257 aMin = Min (aMin, aProjection);
258 aMax = Max (aMax, aProjection);
260 theFrustum->myMinVertsProjections[aPlaneIdx] = aMin;
261 theFrustum->myMaxVertsProjections[aPlaneIdx] = aMax;
265 // project vertices onto {i, j, k}
266 for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
268 Standard_Real aMax = -DBL_MAX;
269 Standard_Real aMin = DBL_MAX;
270 for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
272 const gp_XYZ& aVert = theFrustum->myVertices[aVertIdx].XYZ();
273 aMax = Max (aVert.GetData()[aDim], aMax);
274 aMin = Min (aVert.GetData()[aDim], aMin);
276 theFrustum->myMaxOrthoVertsProjections[aDim] = aMax;
277 theFrustum->myMinOrthoVertsProjections[aDim] = aMin;
281 // =======================================================================
284 // =======================================================================
285 void SelectMgr_RectangularFrustum::Init (const gp_Pnt2d &thePoint)
287 mySelectionType = SelectMgr_SelectionType_Point;
288 mySelRectangle.SetMousePos (thePoint);
291 // =======================================================================
294 // =======================================================================
295 void SelectMgr_RectangularFrustum::Init (const gp_Pnt2d& theMinPnt,
296 const gp_Pnt2d& theMaxPnt)
298 mySelectionType = SelectMgr_SelectionType_Box;
299 mySelRectangle.SetMinPnt (theMinPnt);
300 mySelRectangle.SetMaxPnt (theMaxPnt);
303 // =======================================================================
306 // =======================================================================
307 void SelectMgr_RectangularFrustum::Build()
309 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
310 "Error! SelectMgr_RectangularFrustum::Build() should be called after selection frustum initialization");
311 gp_Pnt2d aMinPnt, aMaxPnt;
312 if (mySelectionType == SelectMgr_SelectionType_Point)
314 const gp_Pnt2d& aMousePos = mySelRectangle.MousePos();
315 myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (aMousePos.X(), aMousePos.Y(), 0.0);
316 myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (aMousePos.X(), aMousePos.Y(), 1.0);
318 aMinPnt.SetCoord (aMousePos.X() - myPixelTolerance * 0.5,
319 aMousePos.Y() - myPixelTolerance * 0.5);
320 aMaxPnt.SetCoord (aMousePos.X() + myPixelTolerance * 0.5,
321 aMousePos.Y() + myPixelTolerance * 0.5);
325 aMinPnt = mySelRectangle.MinPnt();
326 aMaxPnt = mySelRectangle.MaxPnt();
327 myNearPickedPnt = myBuilder->ProjectPntOnViewPlane ((aMinPnt.X() + aMaxPnt.X()) * 0.5,
328 (aMinPnt.Y() + aMaxPnt.Y()) * 0.5,
330 myFarPickedPnt = myBuilder->ProjectPntOnViewPlane ((aMinPnt.X() + aMaxPnt.X()) * 0.5,
331 (aMinPnt.Y() + aMaxPnt.Y()) * 0.5,
335 myViewRayDir = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ();
337 // calculate base frustum characteristics: vertices and edge directions
338 computeFrustum (aMinPnt, aMaxPnt, myBuilder, myVertices, myEdgeDirs);
340 // compute frustum normals
341 computeNormals (myEdgeDirs, myPlanes);
343 // compute vertices projections onto frustum normals and
344 // {i, j, k} vectors and store them to corresponding class fields
345 cacheVertexProjections (this);
350 // =======================================================================
351 // function : ScaleAndTransform
352 // purpose : IMPORTANT: Scaling makes sense only for frustum built on a single point!
353 // Note that this method does not perform any checks on type of the frustum.
354 // Returns a copy of the frustum resized according to the scale factor given
355 // and transforms it using the matrix given.
356 // There are no default parameters, but in case if:
357 // - transformation only is needed: @theScaleFactor must be initialized
358 // as any negative value;
359 // - scale only is needed: @theTrsf must be set to gp_Identity.
360 // =======================================================================
361 Handle(SelectMgr_BaseIntersector) SelectMgr_RectangularFrustum::ScaleAndTransform (const Standard_Integer theScaleFactor,
362 const gp_GTrsf& theTrsf,
363 const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
365 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
366 "Error! SelectMgr_RectangularFrustum::ScaleAndTransform() should be called after selection frustum initialization");
368 Standard_ASSERT_RAISE (theScaleFactor >= 0,
369 "Error! Pixel tolerance for selection should not be negative");
371 Handle(SelectMgr_RectangularFrustum) aRes = new SelectMgr_RectangularFrustum();
372 const Standard_Boolean isToScale = theScaleFactor != 1;
373 const Standard_Boolean isToTrsf = theTrsf.Form() != gp_Identity;
375 if (!isToScale && !isToTrsf)
377 aRes->SetBuilder (theBuilder);
381 aRes->SetCamera (myCamera);
382 const SelectMgr_RectangularFrustum* aRef = this;
386 aRes->myNearPickedPnt = myNearPickedPnt;
387 aRes->myFarPickedPnt = myFarPickedPnt;
388 aRes->myViewRayDir = myViewRayDir;
390 const gp_Pnt2d& aMousePos = mySelRectangle.MousePos();
391 const gp_Pnt2d aMinPnt (aMousePos.X() - theScaleFactor * 0.5,
392 aMousePos.Y() - theScaleFactor * 0.5);
393 const gp_Pnt2d aMaxPnt (aMousePos.X() + theScaleFactor * 0.5,
394 aMousePos.Y() + theScaleFactor * 0.5);
396 // recompute base frustum characteristics from scratch
397 computeFrustum (aMinPnt, aMaxPnt, myBuilder, aRes->myVertices, aRes->myEdgeDirs);
404 const Standard_Real aRefScale = aRef->myFarPickedPnt.SquareDistance (aRef->myNearPickedPnt);
406 gp_Pnt aPoint = aRef->myNearPickedPnt;
407 theTrsf.Transforms (aPoint.ChangeCoord());
408 aRes->myNearPickedPnt = aPoint;
410 aPoint.SetXYZ (aRef->myFarPickedPnt.XYZ());
411 theTrsf.Transforms (aPoint.ChangeCoord());
412 aRes->myFarPickedPnt = aPoint;
414 aRes->myViewRayDir = aRes->myFarPickedPnt.XYZ() - aRes->myNearPickedPnt.XYZ();
416 for (Standard_Integer anIt = 0; anIt < 8; anIt++)
418 aPoint = aRef->myVertices[anIt];
419 theTrsf.Transforms (aPoint.ChangeCoord());
420 aRes->myVertices[anIt] = aPoint;
424 aRes->myEdgeDirs[0] = aRes->myVertices[4].XYZ() - aRes->myVertices[0].XYZ();
426 aRes->myEdgeDirs[1] = aRes->myVertices[2].XYZ() - aRes->myVertices[0].XYZ();
428 aRes->myEdgeDirs[2] = aRes->myVertices[2].XYZ() - aRes->myVertices[3].XYZ();
430 aRes->myEdgeDirs[3] = aRes->myVertices[6].XYZ() - aRes->myVertices[7].XYZ();
432 aRes->myEdgeDirs[4] = aRes->myVertices[0].XYZ() - aRes->myVertices[1].XYZ();
434 aRes->myEdgeDirs[5] = aRes->myVertices[4].XYZ() - aRes->myVertices[5].XYZ();
436 // Compute scale to transform depth from local coordinate system to world coordinate system
437 aRes->myScale = Sqrt (aRefScale / aRes->myFarPickedPnt.SquareDistance (aRes->myNearPickedPnt));
440 aRes->SetBuilder (theBuilder);
442 // compute frustum normals
443 computeNormals (aRes->myEdgeDirs, aRes->myPlanes);
445 cacheVertexProjections (aRes.get());
447 aRes->mySelectionType = mySelectionType;
448 aRes->mySelRectangle = mySelRectangle;
452 // =======================================================================
453 // function : CopyWithBuilder
454 // purpose : Returns a copy of the frustum using the given frustum builder configuration.
455 // Returned frustum should be re-constructed before being used.
456 // =======================================================================
457 Handle(SelectMgr_BaseIntersector) SelectMgr_RectangularFrustum::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
459 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
460 "Error! SelectMgr_RectangularFrustum::CopyWithBuilder() should be called after selection frustum initialization");
462 Standard_ASSERT_RAISE (!theBuilder.IsNull(),
463 "Error! SelectMgr_RectangularFrustum::CopyWithBuilder() should be called with valid builder");
465 Handle(SelectMgr_RectangularFrustum) aRes = new SelectMgr_RectangularFrustum();
466 aRes->mySelectionType = mySelectionType;
467 aRes->mySelRectangle = mySelRectangle;
468 aRes->myPixelTolerance = myPixelTolerance;
469 aRes->SetBuilder (theBuilder);
474 // =======================================================================
475 // function : IsScalable
477 // =======================================================================
478 Standard_Boolean SelectMgr_RectangularFrustum::IsScalable() const
480 return mySelectionType == SelectMgr_SelectionType_Point;
483 // =======================================================================
484 // function : OverlapsBox
485 // purpose : Returns true if selecting volume is overlapped by
486 // axis-aligned bounding box with minimum corner at point
487 // theMinPnt and maximum at point theMaxPnt
488 // =======================================================================
489 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsBox (const SelectMgr_Vec3& theBoxMin,
490 const SelectMgr_Vec3& theBoxMax,
491 Standard_Boolean* theInside) const
493 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
494 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
496 return hasBoxOverlap (theBoxMin, theBoxMax, theInside);
499 // =======================================================================
500 // function : OverlapsBox
501 // purpose : SAT intersection test between defined volume and
502 // given axis-aligned box
503 // =======================================================================
504 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsBox (const SelectMgr_Vec3& theBoxMin,
505 const SelectMgr_Vec3& theBoxMax,
506 const SelectMgr_ViewClipRange& theClipRange,
507 SelectBasics_PickResult& thePickResult) const
509 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
510 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
512 if (!hasBoxOverlap (theBoxMin, theBoxMax))
513 return Standard_False;
515 Standard_Real aDepth = 0.0;
516 BVH_Ray<Standard_Real, 3> aRay(SelectMgr_Vec3(myNearPickedPnt.X(), myNearPickedPnt.Y(), myNearPickedPnt.Z()),
517 SelectMgr_Vec3(myViewRayDir.X(), myViewRayDir.Y(), myViewRayDir.Z()));
518 Standard_Real aTimeEnter, aTimeLeave;
519 if (!BVH_Tools<Standard_Real, 3>::RayBoxIntersection (aRay, theBoxMin, theBoxMax, aTimeEnter, aTimeLeave))
521 gp_Pnt aNearestPnt (RealLast(), RealLast(), RealLast());
522 aNearestPnt.SetX (Max (Min (myNearPickedPnt.X(), theBoxMax.x()), theBoxMin.x()));
523 aNearestPnt.SetY (Max (Min (myNearPickedPnt.Y(), theBoxMax.y()), theBoxMin.y()));
524 aNearestPnt.SetZ (Max (Min (myNearPickedPnt.Z(), theBoxMax.z()), theBoxMin.z()));
526 aDepth = aNearestPnt.Distance (myNearPickedPnt);
527 thePickResult.SetDepth (aDepth);
528 return !theClipRange.IsClipped (thePickResult.Depth());
531 Bnd_Range aRange(Max (aTimeEnter, 0.0), aTimeLeave);
532 aRange.GetMin (aDepth);
534 if (!theClipRange.GetNearestDepth (aRange, aDepth))
536 return Standard_False;
539 thePickResult.SetDepth (aDepth);
541 return Standard_True;
544 // =======================================================================
545 // function : OverlapsPoint
546 // purpose : Intersection test between defined volume and given point
547 // =======================================================================
548 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsPoint (const gp_Pnt& thePnt,
549 const SelectMgr_ViewClipRange& theClipRange,
550 SelectBasics_PickResult& thePickResult) const
552 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
553 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
555 if (!hasPointOverlap (thePnt))
556 return Standard_False;
558 gp_XYZ aV = thePnt.XYZ() - myNearPickedPnt.XYZ();
559 const Standard_Real aDepth = aV.Dot (myViewRayDir.XYZ());
561 thePickResult.SetDepth (Abs (aDepth) * myScale);
562 thePickResult.SetPickedPoint (thePnt);
564 return !theClipRange.IsClipped (thePickResult.Depth());
567 // =======================================================================
568 // function : OverlapsPoint
569 // purpose : Intersection test between defined volume and given point
570 // =======================================================================
571 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsPoint (const gp_Pnt& thePnt) const
573 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
574 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
576 return hasPointOverlap (thePnt);
579 // =======================================================================
580 // function : OverlapsSegment
581 // purpose : Checks if line segment overlaps selecting frustum
582 // =======================================================================
583 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSegment (const gp_Pnt& thePnt1,
584 const gp_Pnt& thePnt2,
585 const SelectMgr_ViewClipRange& theClipRange,
586 SelectBasics_PickResult& thePickResult) const
588 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
589 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
591 if (!hasSegmentOverlap (thePnt1, thePnt2))
592 return Standard_False;
594 segmentSegmentDistance (thePnt1, thePnt2, thePickResult);
596 return !theClipRange.IsClipped (thePickResult.Depth());
599 // =======================================================================
600 // function : OverlapsPolygon
601 // purpose : SAT intersection test between defined volume and given
602 // ordered set of points, representing line segments. The test
603 // may be considered of interior part or boundary line defined
604 // by segments depending on given sensitivity type
605 // =======================================================================
606 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPnts,
607 Select3D_TypeOfSensitivity theSensType,
608 const SelectMgr_ViewClipRange& theClipRange,
609 SelectBasics_PickResult& thePickResult) const
611 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
612 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
614 if (theSensType == Select3D_TOS_BOUNDARY)
616 Standard_Integer aMatchingSegmentsNb = -1;
617 SelectBasics_PickResult aPickResult;
618 thePickResult.Invalidate();
619 const Standard_Integer aLower = theArrayOfPnts.Lower();
620 const Standard_Integer anUpper = theArrayOfPnts.Upper();
621 for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter)
623 const gp_Pnt& aStartPnt = theArrayOfPnts.Value (aPntIter);
624 const gp_Pnt& aEndPnt = theArrayOfPnts.Value (aPntIter == anUpper ? aLower : (aPntIter + 1));
625 if (hasSegmentOverlap (aStartPnt, aEndPnt))
627 aMatchingSegmentsNb++;
628 segmentSegmentDistance (aStartPnt, aEndPnt, aPickResult);
629 thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
633 if (aMatchingSegmentsNb == -1)
634 return Standard_False;
636 else if (theSensType == Select3D_TOS_INTERIOR)
638 gp_Vec aPolyNorm (gp_XYZ (RealLast(), RealLast(), RealLast()));
639 if (!hasPolygonOverlap (theArrayOfPnts, aPolyNorm))
641 return Standard_False;
644 if (aPolyNorm.Magnitude() <= Precision::Confusion())
646 // treat degenerated polygon as point
647 return OverlapsPoint (theArrayOfPnts.First(), theClipRange, thePickResult);
649 else if (!segmentPlaneIntersection (aPolyNorm, theArrayOfPnts.First(), thePickResult))
651 return Standard_False;
655 return !theClipRange.IsClipped (thePickResult.Depth());
658 // =======================================================================
659 // function : OverlapsTriangle
660 // purpose : SAT intersection test between defined volume and given
661 // triangle. The test may be considered of interior part or
662 // boundary line defined by triangle vertices depending on
663 // given sensitivity type
664 // =======================================================================
665 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsTriangle (const gp_Pnt& thePnt1,
666 const gp_Pnt& thePnt2,
667 const gp_Pnt& thePnt3,
668 Select3D_TypeOfSensitivity theSensType,
669 const SelectMgr_ViewClipRange& theClipRange,
670 SelectBasics_PickResult& thePickResult) const
672 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
673 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
675 if (theSensType == Select3D_TOS_BOUNDARY)
677 const gp_Pnt aPntsArrayBuf[4] = { thePnt1, thePnt2, thePnt3, thePnt1 };
678 const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 4);
679 return OverlapsPolygon (aPntsArray, Select3D_TOS_BOUNDARY, theClipRange, thePickResult);
681 else if (theSensType == Select3D_TOS_INTERIOR)
683 gp_Vec aTriangleNormal (gp_XYZ (RealLast(), RealLast(), RealLast()));
684 if (!hasTriangleOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal))
686 return Standard_False;
689 const gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(),
690 thePnt3.XYZ() - thePnt2.XYZ(),
691 thePnt1.XYZ() - thePnt3.XYZ() };
692 if (aTriangleNormal.SquareMagnitude() < gp::Resolution())
694 // consider degenerated triangle as point or segment
695 return aTrEdges[0].SquareModulus() > gp::Resolution()
696 ? OverlapsSegment (thePnt1, thePnt2, theClipRange, thePickResult)
697 : (aTrEdges[1].SquareModulus() > gp::Resolution()
698 ? OverlapsSegment (thePnt2, thePnt3, theClipRange, thePickResult)
699 : OverlapsPoint (thePnt1, theClipRange, thePickResult));
702 const gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
703 const Standard_Real anAlpha = aTriangleNormal.XYZ().Dot (myViewRayDir.XYZ());
704 if (Abs (anAlpha) < gp::Resolution())
706 // handle the case when triangle normal and selecting frustum direction are orthogonal
707 SelectBasics_PickResult aPickResult;
708 thePickResult.Invalidate();
709 for (Standard_Integer anEdgeIter = 0; anEdgeIter < 3; ++anEdgeIter)
711 const gp_Pnt& aStartPnt = aPnts[anEdgeIter];
712 const gp_Pnt& anEndPnt = aPnts[anEdgeIter < 2 ? anEdgeIter + 1 : 0];
713 segmentSegmentDistance (aStartPnt, anEndPnt, aPickResult);
714 thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
716 thePickResult.SetSurfaceNormal (aTriangleNormal);
717 return !theClipRange.IsClipped (thePickResult.Depth());
720 // check if intersection point belongs to triangle's interior part
721 const gp_XYZ anEdge = (thePnt1.XYZ() - myNearPickedPnt.XYZ()) * (1.0 / anAlpha);
723 const Standard_Real aTime = aTriangleNormal.Dot (anEdge);
724 const gp_XYZ aVec = myViewRayDir.XYZ().Crossed (anEdge);
725 const Standard_Real anU = aVec.Dot (aTrEdges[2]);
726 const Standard_Real aV = aVec.Dot (aTrEdges[0]);
728 const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
729 const gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime;
732 thePickResult.SetDepth (myNearPickedPnt.Distance (aPtOnPlane) * myScale);
733 thePickResult.SetPickedPoint (aPtOnPlane);
734 thePickResult.SetSurfaceNormal (aTriangleNormal);
735 return !theClipRange.IsClipped (thePickResult.Depth());
738 Standard_Real aMinDist = RealLast();
739 Standard_Integer aNearestEdgeIdx1 = -1;
740 for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
742 gp_XYZ aW = aPtOnPlane.XYZ() - aPnts[anEdgeIdx].XYZ();
743 Standard_Real aCoef = aTrEdges[anEdgeIdx].Dot (aW) / aTrEdges[anEdgeIdx].Dot (aTrEdges[anEdgeIdx]);
744 Standard_Real aDist = aPtOnPlane.Distance (aPnts[anEdgeIdx].XYZ() + aCoef * aTrEdges[anEdgeIdx]);
745 if (aDist < aMinDist)
748 aNearestEdgeIdx1 = anEdgeIdx;
751 Standard_Integer aNearestEdgeIdx2 = (aNearestEdgeIdx1 + 1) % 3;
752 const gp_Vec aVec12 (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2]);
753 if (aVec12.SquareMagnitude() > gp::Resolution()
754 && myViewRayDir.IsParallel (aVec12, Precision::Angular()))
756 aNearestEdgeIdx2 = aNearestEdgeIdx1 == 0 ? 2 : aNearestEdgeIdx1 - 1;
758 segmentSegmentDistance (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2], thePickResult);
759 thePickResult.SetSurfaceNormal (aTriangleNormal);
762 return !theClipRange.IsClipped (thePickResult.Depth());
765 //=======================================================================
766 // function : OverlapsCylinder
768 //=======================================================================
769 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
770 const Standard_Real theTopRad,
771 const Standard_Real theHeight,
772 const gp_Trsf& theTrsf,
773 const Standard_Boolean theIsHollow,
774 const SelectMgr_ViewClipRange& theClipRange,
775 SelectBasics_PickResult& thePickResult) const
777 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
778 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
779 Standard_Real aTimes[2] = { 0.0, 0.0 };
780 const gp_Trsf aTrsfInv = theTrsf.Inverted();
781 const gp_Pnt aLoc = myNearPickedPnt.Transformed (aTrsfInv);
782 const gp_Dir aRayDir = myViewRayDir .Transformed (aTrsfInv);
783 if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, theIsHollow, aTimes[0], aTimes[1]))
785 return Standard_False;
788 Standard_Integer aResTime = 0;
789 thePickResult.SetDepth (aTimes[aResTime] * myScale);
790 if (theClipRange.IsClipped (thePickResult.Depth()))
793 thePickResult.SetDepth (aTimes[aResTime] * myScale);
796 const gp_Pnt aPntOnCylinder = aLoc.XYZ() + aRayDir.XYZ() * aTimes[aResTime];
797 if (Abs (aPntOnCylinder.Z()) < Precision::Confusion())
799 thePickResult.SetSurfaceNormal (-gp::DZ().Transformed (theTrsf));
801 else if (Abs (aPntOnCylinder.Z() - theHeight) < Precision::Confusion())
803 thePickResult.SetSurfaceNormal (gp::DZ().Transformed (theTrsf));
807 thePickResult.SetSurfaceNormal (gp_Vec (aPntOnCylinder.X(), aPntOnCylinder.Y(), 0.0).Transformed (theTrsf));
809 thePickResult.SetPickedPoint (aPntOnCylinder.Transformed (theTrsf));
810 return !theClipRange.IsClipped (thePickResult.Depth());
813 //=======================================================================
814 // function : OverlapsCircle
816 //=======================================================================
817 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCircle (const Standard_Real theRadius,
818 const gp_Trsf& theTrsf,
819 const Standard_Boolean theIsFilled,
820 const SelectMgr_ViewClipRange& theClipRange,
821 SelectBasics_PickResult& thePickResult) const
823 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
824 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
825 Standard_Real aTime = 0.0;
826 const gp_Trsf aTrsfInv = theTrsf.Inverted();
827 const gp_Pnt aLoc = myNearPickedPnt.Transformed (aTrsfInv);
828 const gp_Dir aRayDir = myViewRayDir.Transformed (aTrsfInv);
831 if (!hasCircleOverlap (theRadius, theTrsf, theIsFilled, NULL))
833 return Standard_False;
835 if (aRayDir.Z() != 0)
837 aTime = (0 - aLoc.Z()) / aRayDir.Z();
840 else if (!RayCircleIntersection (theRadius, aLoc, aRayDir, theIsFilled, aTime))
842 return Standard_False;
845 thePickResult.SetDepth (aTime * myScale);
846 if (theClipRange.IsClipped (thePickResult.Depth()))
848 thePickResult.SetDepth (aTime * myScale);
851 const gp_Pnt aPntOnCircle = aLoc.XYZ() + aRayDir.XYZ() * aTime;
852 if (Abs (aPntOnCircle.Z()) < Precision::Confusion())
854 thePickResult.SetSurfaceNormal (-gp::DZ().Transformed (theTrsf));
858 thePickResult.SetSurfaceNormal (gp_Vec (aPntOnCircle.X(), aPntOnCircle.Y(), 0.0).Transformed (theTrsf));
860 thePickResult.SetPickedPoint (aPntOnCircle.Transformed (theTrsf));
861 return !theClipRange.IsClipped (thePickResult.Depth());
864 //=======================================================================
865 // function : isIntersectCircle
867 //=======================================================================
868 Standard_Boolean SelectMgr_RectangularFrustum::isIntersectCircle (const Standard_Real theRadius,
869 const gp_Pnt& theCenter,
870 const gp_Trsf& theTrsf,
871 const TColgp_Array1OfPnt& theVertices) const
873 const gp_Trsf aTrsfInv = theTrsf.Inverted();
874 const gp_Dir aRayDir = gp_Dir (myEdgeDirs[4 == 4 ? 4 : 0]).Transformed (aTrsfInv);
875 if (aRayDir.Z() == 0.0)
880 for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
882 const gp_Pnt aPntStart = theVertices.Value (anIdx).Transformed (aTrsfInv);
883 const gp_Pnt aPntFinish = anIdx == theVertices.Upper()
884 ? theVertices.Value (theVertices.Lower()).Transformed (aTrsfInv)
885 : theVertices.Value (anIdx + 1).Transformed (aTrsfInv);
887 // Project points on the end face plane
888 const Standard_Real aParam1 = (theCenter.Z() - aPntStart.Z()) / aRayDir.Z();
889 const Standard_Real aX1 = aPntStart.X() + aRayDir.X() * aParam1;
890 const Standard_Real anY1 = aPntStart.Y() + aRayDir.Y() * aParam1;
892 const Standard_Real aParam2 = (theCenter.Z() - aPntFinish.Z()) / aRayDir.Z();
893 const Standard_Real aX2 = aPntFinish.X() + aRayDir.X() * aParam2;
894 const Standard_Real anY2 = aPntFinish.Y() + aRayDir.Y() * aParam2;
896 // Solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
897 const Standard_Real anA = (aX1 - aX2) * (aX1 - aX2) + (anY1 - anY2) * (anY1 - anY2);
898 const Standard_Real aK = aX1 * (aX2 - aX1) + anY1 * (anY2 - anY1);
899 const Standard_Real aC = aX1 * aX1 + anY1 * anY1 - theRadius * theRadius;
901 const Standard_Real aDiscr = aK * aK - anA * aC;
904 const Standard_Real aT1 = (-aK + Sqrt (aDiscr)) / anA;
905 const Standard_Real aT2 = (-aK - Sqrt (aDiscr)) / anA;
906 if ((aT1 >= 0 && aT1 <= 1) || (aT2 >= 0 && aT2 <= 1))
915 //=======================================================================
916 // function : isSegmentsIntersect
918 //=======================================================================
919 Standard_Boolean SelectMgr_RectangularFrustum::isSegmentsIntersect (const gp_Pnt& thePnt1Seg1,
920 const gp_Pnt& thePnt2Seg1,
921 const gp_Pnt& thePnt1Seg2,
922 const gp_Pnt& thePnt2Seg2) const
924 const gp_Mat aMatPln (thePnt2Seg1.X() - thePnt1Seg1.X(), thePnt2Seg1.Y() - thePnt1Seg1.Y(), thePnt2Seg1.Z() - thePnt1Seg1.Z(),
925 thePnt1Seg2.X() - thePnt1Seg1.X(), thePnt1Seg2.Y() - thePnt1Seg1.Y(), thePnt1Seg2.Z() - thePnt1Seg1.Z(),
926 thePnt2Seg2.X() - thePnt1Seg1.X(), thePnt2Seg2.Y() - thePnt1Seg1.Y(), thePnt2Seg2.Z() - thePnt1Seg1.Z());
927 if (Abs (aMatPln.Determinant()) > Precision::Confusion())
932 Standard_Real aFst[4] = { thePnt1Seg1.X(), thePnt2Seg1.X(), thePnt1Seg2.X(), thePnt2Seg2.X() };
933 Standard_Real aSnd[4] = { thePnt1Seg1.Y(), thePnt2Seg1.Y(), thePnt1Seg2.Y(), thePnt2Seg2.Y() };
934 if (aFst[0] == aFst[2] && aFst[1] == aFst[3])
936 aFst[0] = thePnt1Seg1.Z();
937 aFst[1] = thePnt2Seg1.Z();
938 aFst[2] = thePnt1Seg2.Z();
939 aFst[3] = thePnt2Seg2.Z();
941 if (aSnd[0] == aSnd[2]
942 && aSnd[1] == aSnd[3])
944 aSnd[0] = thePnt1Seg1.Z();
945 aSnd[1] = thePnt2Seg1.Z();
946 aSnd[2] = thePnt1Seg2.Z();
947 aSnd[3] = thePnt2Seg2.Z();
949 const gp_Mat2d aMat (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
950 gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
952 const gp_Mat2d aMatU (gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]),
953 gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
955 const gp_Mat2d aMatV (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
956 gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]));
957 if (aMat.Determinant() == 0.0)
962 const Standard_Real anU = aMatU.Determinant() / aMat.Determinant();
963 const Standard_Real aV = aMatV.Determinant() / aMat.Determinant();
964 if (anU >= 0.0 && anU <= 1.0
965 && aV >= 0.0 && aV <= 1.0)
972 //=======================================================================
973 // function : OverlapsCylinder
975 //=======================================================================
976 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
977 const Standard_Real theTopRad,
978 const Standard_Real theHeight,
979 const gp_Trsf& theTrsf,
980 const Standard_Boolean theIsHollow,
981 Standard_Boolean* theInside) const
983 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
984 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
986 return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf, theIsHollow, theInside);
989 //=======================================================================
990 // function : OverlapsCircle
992 //=======================================================================
993 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCircle (const Standard_Real theRadius,
994 const gp_Trsf& theTrsf,
995 const Standard_Boolean theIsFilled,
996 Standard_Boolean* theInside) const
998 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
999 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
1001 return hasCircleOverlap (theRadius, theTrsf, theIsFilled, theInside);
1004 // =======================================================================
1005 // function : GetMousePosition
1007 // =======================================================================
1008 const gp_Pnt2d& SelectMgr_RectangularFrustum::GetMousePosition() const
1010 if (mySelectionType == SelectMgr_SelectionType_Point)
1012 return mySelRectangle.MousePos();
1014 return base_type::GetMousePosition();
1017 // =======================================================================
1018 // function : OverlapsSphere
1020 // =======================================================================
1021 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& theCenter,
1022 const Standard_Real theRadius,
1023 const SelectMgr_ViewClipRange& theClipRange,
1024 SelectBasics_PickResult& thePickResult) const
1026 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
1027 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
1028 Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
1029 if (!RaySphereIntersection (theCenter, theRadius, myNearPickedPnt, myViewRayDir, aTimeEnter, aTimeLeave))
1031 return Standard_False;
1034 thePickResult.SetDepth (aTimeEnter * myScale);
1035 if (theClipRange.IsClipped (thePickResult.Depth()))
1037 thePickResult.SetDepth (aTimeLeave * myScale);
1039 gp_Pnt aPntOnSphere (myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * thePickResult.Depth() / myScale);
1040 gp_Vec aNormal (aPntOnSphere.XYZ() - theCenter.XYZ());
1041 thePickResult.SetPickedPoint (aPntOnSphere);
1042 thePickResult.SetSurfaceNormal (aNormal);
1043 return !theClipRange.IsClipped (thePickResult.Depth());
1046 // =======================================================================
1047 // function : OverlapsSphere
1049 // =======================================================================
1050 Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& theCenter,
1051 const Standard_Real theRadius,
1052 Standard_Boolean* theInside) const
1054 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
1055 "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
1056 return hasSphereOverlap (theCenter, theRadius, theInside);
1059 // =======================================================================
1060 // function : DistToGeometryCenter
1061 // purpose : Measures distance between 3d projection of user-picked
1062 // screen point and given point theCOG
1063 // =======================================================================
1064 Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG) const
1066 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
1067 "Error! SelectMgr_RectangularFrustum::DistToGeometryCenter() should be called after selection frustum initialization");
1069 return theCOG.Distance (myNearPickedPnt) * myScale;
1072 // =======================================================================
1073 // function : DetectedPoint
1074 // purpose : Calculates the point on a view ray that was detected during
1075 // the run of selection algo by given depth
1076 // =======================================================================
1077 gp_Pnt SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const
1079 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
1080 "SelectMgr_RectangularFrustum::DetectedPoint() should be called only for Point selection type");
1081 return myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * theDepth / myScale;
1084 // =======================================================================
1085 // function : GetPlanes
1087 // =======================================================================
1088 void SelectMgr_RectangularFrustum::GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const
1090 thePlaneEquations.Clear();
1092 SelectMgr_Vec4 anEquation;
1093 for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
1095 const gp_Vec& aPlaneNorm = Camera()->IsOrthographic() && aPlaneIdx % 2 == 1 ?
1096 myPlanes[aPlaneIdx - 1].Reversed() : myPlanes[aPlaneIdx];
1097 anEquation.x() = aPlaneNorm.X();
1098 anEquation.y() = aPlaneNorm.Y();
1099 anEquation.z() = aPlaneNorm.Z();
1100 anEquation.w() = - (aPlaneNorm.XYZ().Dot (myVertices[aPlaneIdx % 2 == 0 ? aPlaneIdx : aPlaneIdx + 2].XYZ()));
1101 thePlaneEquations.Append (anEquation);
1105 //=======================================================================
1106 //function : DumpJson
1108 //=======================================================================
1109 void SelectMgr_RectangularFrustum::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1111 OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_RectangularFrustum)
1112 OCCT_DUMP_BASE_CLASS (theOStream, theDepth, SelectMgr_Frustum)
1114 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myNearPickedPnt)
1115 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myFarPickedPnt)
1116 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myViewRayDir)
1117 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &mySelRectangle.MinPnt())
1118 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &mySelRectangle.MaxPnt())
1120 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myScale)