#include <SelectMgr_RectangularFrustum.hxx>
-#define DOT(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z())
-#define DOTp(A, B) (A.x() * B.X() + A.y() * B.Y() + A.z() * B.Z())
-#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())))
-#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())))
-
// =======================================================================
// function : segmentSegmentDistance
// purpose :
// =======================================================================
void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1,
const gp_Pnt& theSegPnt2,
- Standard_Real& theDepth)
+ SelectBasics_PickResult& thePickResult) const
{
- SelectMgr_Vec3 anU = SelectMgr_Vec3 (theSegPnt2.X() - theSegPnt1.X(),
- theSegPnt2.Y() - theSegPnt1.Y(),
- theSegPnt2.Z() - theSegPnt1.Z());
- SelectMgr_Vec3 aV = myViewRayDir;
- SelectMgr_Vec3 aW = SelectMgr_Vec3 (theSegPnt1.X() - myNearPickedPnt.x(),
- theSegPnt1.Y() - myNearPickedPnt.y(),
- theSegPnt1.Z() - myNearPickedPnt.z());
- Standard_Real anA = DOT (anU, anU);
- Standard_Real aB = DOT (anU, aV);
- Standard_Real aC = DOT (aV, aV);
- Standard_Real aD = DOT (anU, aW);
- Standard_Real anE = DOT (aV, aW);
+ gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ();
+ gp_XYZ aV = myViewRayDir.XYZ();
+ gp_XYZ aW = theSegPnt1.XYZ() - myNearPickedPnt.XYZ();
+
+ Standard_Real anA = anU.Dot (anU);
+ Standard_Real aB = anU.Dot (aV);
+ Standard_Real aC = aV.Dot (aV);
+ Standard_Real aD = anU.Dot (aW);
+ Standard_Real anE = aV.Dot (aW);
Standard_Real aCoef = anA * aC - aB * aB;
- Standard_Real aSc, aSn, aSd = aCoef;
+ Standard_Real aSn = aCoef;
Standard_Real aTc, aTn, aTd = aCoef;
- if (aCoef < Precision::Confusion())
+ if (aCoef < gp::Resolution())
{
- aSn = 0.0;
- aSd = 1.0;
aTn = anE;
aTd = aC;
}
aTn = (anA * anE - aB * aD);
if (aSn < 0.0)
{
- aSn = 0.0;
aTn = anE;
aTd = aC;
}
- else if (aSn > aSd)
+ else if (aSn > aCoef)
{
- aSn = aSd;
aTn = anE + aB;
aTd = aC;
}
if (aTn < 0.0)
{
aTn = 0.0;
- if (-aD < 0.0)
- aSn = 0.0;
- else if (-aD > anA)
- aSn = aSd;
- else {
- aSn = -aD;
- aSd = anA;
- }
}
else if (aTn > aTd)
{
aTn = aTd;
- if ((-aD + aB) < 0.0)
- aSn = 0;
- else if ((-aD + aB) > anA)
- aSn = aSd;
- else {
- aSn = (-aD + aB);
- aSd = anA;
- }
}
- aSc = (Abs (aSn) < Precision::Confusion() ? 0.0 : aSn / aSd);
- aTc = (Abs (aTn) < Precision::Confusion() ? 0.0 : aTn / aTd);
+ aTc = (Abs (aTd) < gp::Resolution() ? 0.0 : aTn / aTd);
+
+ const gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTc;
+ thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale);
+
+ const gp_Vec aPickedVec = aClosestPnt.XYZ() - theSegPnt1.XYZ();
+ const gp_Vec aFigureVec = theSegPnt2.XYZ() - theSegPnt1.XYZ();
+ const Standard_Real aPickedVecMod = aPickedVec.Magnitude();
+ const Standard_Real aFigureVecMod = aFigureVec.Magnitude();
+ if (aPickedVecMod <= gp::Resolution()
+ || aFigureVecMod <= gp::Resolution())
+ {
+ thePickResult.SetPickedPoint (aClosestPnt);
+ return;
+ }
- SelectMgr_Vec3 aDiff = aW + (anU * aSc) - (aV * aTc);
- SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + myViewRayDir * aTc;
- theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
+ const Standard_Real aCosOfAngle = aFigureVec.Dot (aPickedVec) / (aPickedVecMod * aFigureVecMod);
+ const Standard_Real aSegPntShift = Min(aFigureVecMod, Max(0.0, aCosOfAngle * aPickedVecMod));
+ thePickResult.SetPickedPoint (theSegPnt1.XYZ() + aFigureVec.XYZ() * (aSegPntShift / aFigureVecMod));
}
// =======================================================================
// function : segmentPlaneIntersection
// purpose :
// =======================================================================
-void SelectMgr_RectangularFrustum::segmentPlaneIntersection (const SelectMgr_Vec3& thePlane,
+bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePlane,
const gp_Pnt& thePntOnPlane,
- Standard_Real& theDepth)
+ SelectBasics_PickResult& thePickResult) const
{
- SelectMgr_Vec3 anU = myViewRayDir;
- SelectMgr_Vec3 aW = SelectMgr_Vec3 (myNearPickedPnt.x() - thePntOnPlane.X(),
- myNearPickedPnt.y() - thePntOnPlane.Y(),
- myNearPickedPnt.z() - thePntOnPlane.Z());
- Standard_Real aD = DOT (thePlane, anU);
- Standard_Real aN = -DOT (thePlane, aW);
+ gp_XYZ anU = myViewRayDir.XYZ();
+ gp_XYZ aW = myNearPickedPnt.XYZ() - thePntOnPlane.XYZ();
+ Standard_Real aD = thePlane.Dot (anU);
+ Standard_Real aN = -thePlane.Dot (aW);
if (Abs (aD) < Precision::Confusion())
{
if (Abs (aN) < Precision::Angular())
{
- theDepth = DBL_MAX;
- return;
+ thePickResult.Invalidate();
+ return false;
}
else
{
- theDepth = DBL_MAX;
- return;
+ thePickResult.Invalidate();
+ return false;
}
}
Standard_Real aParam = aN / aD;
if (aParam < 0.0 || aParam > 1.0)
{
- theDepth = DBL_MAX;
- return;
+ thePickResult.Invalidate();
+ return false;
+ }
+
+ gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + anU * aParam;
+ thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale);
+ return true;
+}
+
+namespace
+{
+ // =======================================================================
+ // function : computeFrustum
+ // purpose : Computes base frustum data: its vertices and edge directions
+ // =======================================================================
+ void computeFrustum (const gp_Pnt2d theMinPnt, const gp_Pnt2d& theMaxPnt,
+ const Handle(SelectMgr_FrustumBuilder)& theBuilder,
+ gp_Pnt* theVertices, gp_Vec* theEdges)
+ {
+ // LeftTopNear
+ theVertices[0] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
+ theMaxPnt.Y(),
+ 0.0);
+ // LeftTopFar
+ theVertices[1] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
+ theMaxPnt.Y(),
+ 1.0);
+ // LeftBottomNear
+ theVertices[2] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
+ theMinPnt.Y(),
+ 0.0);
+ // LeftBottomFar
+ theVertices[3] = theBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
+ theMinPnt.Y(),
+ 1.0);
+ // RightTopNear
+ theVertices[4] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
+ theMaxPnt.Y(),
+ 0.0);
+ // RightTopFar
+ theVertices[5] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
+ theMaxPnt.Y(),
+ 1.0);
+ // RightBottomNear
+ theVertices[6] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
+ theMinPnt.Y(),
+ 0.0);
+ // RightBottomFar
+ theVertices[7] = theBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
+ theMinPnt.Y(),
+ 1.0);
+
+ // Horizontal
+ theEdges[0] = theVertices[4].XYZ() - theVertices[0].XYZ();
+ // Vertical
+ theEdges[1] = theVertices[2].XYZ() - theVertices[0].XYZ();
+ // LeftLower
+ theEdges[2] = theVertices[2].XYZ() - theVertices[3].XYZ();
+ // RightLower
+ theEdges[3] = theVertices[6].XYZ() - theVertices[7].XYZ();
+ // LeftUpper
+ theEdges[4] = theVertices[0].XYZ() - theVertices[1].XYZ();
+ // RightUpper
+ theEdges[5] = theVertices[4].XYZ() - theVertices[5].XYZ();
}
- SelectMgr_Vec3 aClosestPnt = myNearPickedPnt + anU * aParam;
- theDepth = DISTANCE (myNearPickedPnt, aClosestPnt);
+ // =======================================================================
+ // function : computeNormals
+ // purpose : Computes normals to frustum faces
+ // =======================================================================
+ void computeNormals (const gp_Vec* theEdges, gp_Vec* theNormals)
+ {
+ // Top
+ theNormals[0] = theEdges[0].Crossed (theEdges[4]);
+ // Bottom
+ theNormals[1] = theEdges[2].Crossed (theEdges[0]);
+ // Left
+ theNormals[2] = theEdges[4].Crossed (theEdges[1]);
+ // Right
+ theNormals[3] = theEdges[1].Crossed (theEdges[5]);
+ // Near
+ theNormals[4] = theEdges[0].Crossed (theEdges[1]);
+ // Far
+ theNormals[5] = -theNormals[4];
+ }
}
// =======================================================================
-// function : Build
-// purpose : Build volume according to the point and given pixel
-// tolerance
+// function : cacheVertexProjections
+// purpose : Caches projection of frustum's vertices onto its plane directions
+// and {i, j, k}
// =======================================================================
-void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint)
+void SelectMgr_RectangularFrustum::cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum) const
{
- myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 0.0);
- myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 1.0);
- myViewRayDir = myFarPickedPnt - myNearPickedPnt;
-
- // LeftTopNear
- myVertices[0] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
- thePoint.Y() + myPixelTolerance / 2.0,
- 0.0);
- // LeftTopFar
- myVertices[1] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
- thePoint.Y() + myPixelTolerance / 2.0,
- 1.0);
- // LeftBottomNear
- myVertices[2] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
- thePoint.Y() - myPixelTolerance / 2.0,
- 0.0);
- // LeftBottomFar
- myVertices[3] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0,
- thePoint.Y() - myPixelTolerance / 2.0,
- 1.0);
- // RightTopNear
- myVertices[4] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
- thePoint.Y() + myPixelTolerance / 2.0,
- 0.0);
- // RightTopFar
- myVertices[5] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
- thePoint.Y() + myPixelTolerance / 2.0,
- 1.0);
- // RightBottomNear
- myVertices[6] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
- thePoint.Y() - myPixelTolerance / 2.0,
- 0.0);
- // RightBottomFar
- myVertices[7] = myBuilder->ProjectPntOnViewPlane (thePoint.X() + myPixelTolerance / 2.0,
- thePoint.Y() - myPixelTolerance / 2.0,
- 1.0);
- // Top
- myPlanes[0] = myBuilder->PlaneEquation (myVertices[1],
- myVertices[0],
- myVertices[5],
- myVertices[6]);
- // Bottom
- myPlanes[1] = myBuilder->PlaneEquation (myVertices[3],
- myVertices[2],
- myVertices[7],
- myVertices[4]);
- // Left
- myPlanes[2] = myBuilder->PlaneEquation (myVertices[1],
- myVertices[0],
- myVertices[2],
- myVertices[6]);
- // Right
- myPlanes[3] = myBuilder->PlaneEquation (myVertices[5],
- myVertices[4],
- myVertices[6],
- myVertices[2]);
- // Near
- myPlanes[4] = myBuilder->PlaneEquation (myVertices[4],
- myVertices[6],
- myVertices[2],
- myVertices[3]);
- // Far
- myPlanes[5] = myBuilder->PlaneEquation (myVertices[5],
- myVertices[7],
- myVertices[3],
- myVertices[2]);
-
- for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
+ if (theFrustum->myIsOrthographic)
{
- Standard_Real aMax = -DBL_MAX;
- Standard_Real aMin = DBL_MAX;
- const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
- for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
+ // project vertices onto frustum normals
+ // Since orthographic view volume's faces are always a pairwise translation of
+ // one another, only 2 vertices that belong to opposite faces can be projected
+ // to simplify calculations.
+ Standard_Integer aVertIdxs[6] = { LeftTopNear, LeftBottomNear, // opposite planes in height direction
+ LeftBottomNear, RightBottomNear, // opposite planes in width direcion
+ LeftBottomFar, RightBottomNear }; // opposite planes in depth direction
+ for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; aPlaneIdx += 2)
{
- Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
- aMax = Max (aMax, aProjection);
- aMin = Min (aMin, aProjection);
+ Standard_Real aProj1 = theFrustum->myPlanes[aPlaneIdx].XYZ().Dot (theFrustum->myVertices[aVertIdxs[aPlaneIdx]].XYZ());
+ Standard_Real aProj2 = theFrustum->myPlanes[aPlaneIdx].XYZ().Dot (theFrustum->myVertices[aVertIdxs[aPlaneIdx + 1]].XYZ());
+ theFrustum->myMinVertsProjections[aPlaneIdx] = Min (aProj1, aProj2);
+ theFrustum->myMaxVertsProjections[aPlaneIdx] = Max (aProj1, aProj2);
}
- myMaxVertsProjections[aPlaneIdx] = aMax;
- myMinVertsProjections[aPlaneIdx] = aMin;
}
-
- SelectMgr_Vec3 aDimensions[3] =
+ else
{
- SelectMgr_Vec3 (1.0, 0.0, 0.0),
- SelectMgr_Vec3 (0.0, 1.0, 0.0),
- SelectMgr_Vec3 (0.0, 0.0, 1.0)
- };
+ // project all vertices onto frustum normals
+ for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
+ {
+ Standard_Real aMax = -DBL_MAX;
+ Standard_Real aMin = DBL_MAX;
+ const gp_XYZ& aPlane = theFrustum->myPlanes[aPlaneIdx].XYZ();
+ for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
+ {
+ Standard_Real aProjection = aPlane.Dot (theFrustum->myVertices[aVertIdx].XYZ());
+ aMin = Min (aMin, aProjection);
+ aMax = Max (aMax, aProjection);
+ }
+ theFrustum->myMinVertsProjections[aPlaneIdx] = aMin;
+ theFrustum->myMaxVertsProjections[aPlaneIdx] = aMax;
+ }
+ }
+ // project vertices onto {i, j, k}
for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
{
Standard_Real aMax = -DBL_MAX;
- Standard_Real aMin = DBL_MAX;
+ Standard_Real aMin = DBL_MAX;
for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
{
- Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
- aMax = Max (aProjection, aMax);
- aMin = Min (aProjection, aMin);
+ const gp_XYZ& aVert = theFrustum->myVertices[aVertIdx].XYZ();
+ aMax = Max (aVert.GetData()[aDim], aMax);
+ aMin = Min (aVert.GetData()[aDim], aMin);
}
- myMaxOrthoVertsProjections[aDim] = aMax;
- myMinOrthoVertsProjections[aDim] = aMin;
+ theFrustum->myMaxOrthoVertsProjections[aDim] = aMax;
+ theFrustum->myMinOrthoVertsProjections[aDim] = aMin;
}
+}
+
+// =======================================================================
+// function : Build
+// purpose : Build volume according to the point and given pixel
+// tolerance
+// =======================================================================
+void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint)
+{
+ myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 0.0);
+ myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 1.0);
+ myViewRayDir = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ();
+ myMousePos = thePoint;
+
+ gp_Pnt2d aMinPnt (thePoint.X() - myPixelTolerance * 0.5,
+ thePoint.Y() - myPixelTolerance * 0.5);
+ gp_Pnt2d aMaxPnt (thePoint.X() + myPixelTolerance * 0.5,
+ thePoint.Y() + myPixelTolerance * 0.5);
+
+ // calculate base frustum characteristics: vertices and edge directions
+ computeFrustum (aMinPnt, aMaxPnt, myBuilder, myVertices, myEdgeDirs);
- // Horizontal
- myEdgeDirs[0] = myVertices[4] - myVertices[0];
- // Vertical
- myEdgeDirs[1] = myVertices[2] - myVertices[0];
- // LeftLower
- myEdgeDirs[2] = myVertices[2] - myVertices[3];
- // RightLower
- myEdgeDirs[3] = myVertices[6] - myVertices[7];
- // LeftUpper
- myEdgeDirs[4] = myVertices[0] - myVertices[1];
- // RightUpper
- myEdgeDirs[5] = myVertices[4] - myVertices[5];
+ // compute frustum normals
+ computeNormals (myEdgeDirs, myPlanes);
+
+ // compute vertices projections onto frustum normals and
+ // {i, j, k} vectors and store them to corresponding class fields
+ cacheVertexProjections (this);
+
+ myViewClipRange.SetVoid();
+
+ myScale = 1.0;
}
// =======================================================================
myFarPickedPnt = myBuilder->ProjectPntOnViewPlane ((theMinPnt.X() + theMaxPnt.X()) * 0.5,
(theMinPnt.Y() + theMaxPnt.Y()) * 0.5,
1.0);
- myViewRayDir = myFarPickedPnt - myNearPickedPnt;
-
- // LeftTopNear
- myVertices[0] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
- theMaxPnt.Y(),
- 0.0);
- // LeftTopFar
- myVertices[1] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
- theMaxPnt.Y(),
- 1.0);
- // LeftBottomNear
- myVertices[2] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
- theMinPnt.Y(),
- 0.0);
- // LeftBottomFar
- myVertices[3] = myBuilder->ProjectPntOnViewPlane (theMinPnt.X(),
- theMinPnt.Y(),
- 1.0);
- // RightTopNear
- myVertices[4] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
- theMaxPnt.Y(),
- 0.0);
- // RightTopFar
- myVertices[5] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
- theMaxPnt.Y(),
- 1.0);
- // RightBottomNear
- myVertices[6] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X(),
- theMinPnt.Y(),
- 0.0);
- // RightBottomFar
- myVertices[7] = myBuilder->ProjectPntOnViewPlane (theMaxPnt.X() ,
- theMinPnt.Y(),
- 1.0);
-
- // Top
- myPlanes[0] = myBuilder->PlaneEquation (myVertices[1],
- myVertices[0],
- myVertices[5],
- myVertices[6]);
- // Bottom
- myPlanes[1] = myBuilder->PlaneEquation (myVertices[3],
- myVertices[2],
- myVertices[7],
- myVertices[4]);
- // Left
- myPlanes[2] = myBuilder->PlaneEquation (myVertices[1],
- myVertices[0],
- myVertices[2],
- myVertices[6]);
- // Right
- myPlanes[3] = myBuilder->PlaneEquation (myVertices[5],
- myVertices[4],
- myVertices[6],
- myVertices[2]);
- // Near
- myPlanes[4] = myBuilder->PlaneEquation (myVertices[4],
- myVertices[6],
- myVertices[2],
- myVertices[3]);
- // Far
- myPlanes[5] = myBuilder->PlaneEquation (myVertices[5],
- myVertices[7],
- myVertices[3],
- myVertices[2]);
+ myViewRayDir = myFarPickedPnt.XYZ() - myNearPickedPnt.XYZ();
- for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
- {
- Standard_Real aMax = -DBL_MAX;
- Standard_Real aMin = DBL_MAX;
- const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
- for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
- {
- Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
- aMax = Max (aMax, aProjection);
- aMin = Min (aMin, aProjection);
- }
- myMaxVertsProjections[aPlaneIdx] = aMax;
- myMinVertsProjections[aPlaneIdx] = aMin;
- }
+ // calculate base frustum characteristics: vertices and edge directions
+ computeFrustum (theMinPnt, theMaxPnt, myBuilder, myVertices, myEdgeDirs);
- SelectMgr_Vec3 aDimensions[3] =
- {
- SelectMgr_Vec3 (1.0, 0.0, 0.0),
- SelectMgr_Vec3 (0.0, 1.0, 0.0),
- SelectMgr_Vec3 (0.0, 0.0, 1.0)
- };
+ // compute frustum normals
+ computeNormals (myEdgeDirs, myPlanes);
- for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
- {
- Standard_Real aMax = -DBL_MAX;
- Standard_Real aMin = DBL_MAX;
- for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
- {
- Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
- aMax = Max (aMax, aProjection);
- aMin = Min (aMin, aProjection);
- }
- myMaxOrthoVertsProjections[aDim] = aMax;
- myMinOrthoVertsProjections[aDim] = aMin;
- }
+ // compute vertices projections onto frustum normals and
+ // {i, j, k} vectors and store them to corresponding class fields
+ cacheVertexProjections (this);
- // Horizontal
- myEdgeDirs[0] = myVertices[4] - myVertices[0];
- // Vertical
- myEdgeDirs[1] = myVertices[2] - myVertices[0];
- // LeftLower
- myEdgeDirs[2] = myVertices[2] - myVertices[3];
- // RightLower
- myEdgeDirs[3] = myVertices[6] - myVertices[7];
- // LeftUpper
- myEdgeDirs[4] = myVertices[0] - myVertices[1];
- // RightUpper
- myEdgeDirs[5] = myVertices[4] - myVertices[5];
+ myViewClipRange.SetVoid();
+
+ myScale = 1.0;
}
// =======================================================================
-// function : Transform
-// purpose : Returns a copy of the frustum transformed according to the matrix given
+// function : ScaleAndTransform
+// purpose : IMPORTANT: Scaling makes sense only for frustum built on a single point!
+// Note that this method does not perform any checks on type of the frustum.
+// Returns a copy of the frustum resized according to the scale factor given
+// and transforms it using the matrix given.
+// There are no default parameters, but in case if:
+// - transformation only is needed: @theScaleFactor must be initialized
+// as any negative value;
+// - scale only is needed: @theTrsf must be set to gp_Identity.
// =======================================================================
-NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Transform (const gp_Trsf& theTrsf)
+Handle(SelectMgr_BaseFrustum) SelectMgr_RectangularFrustum::ScaleAndTransform (const Standard_Integer theScaleFactor,
+ const gp_GTrsf& theTrsf) const
{
- SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum();
+ Standard_ASSERT_RAISE (theScaleFactor > 0,
+ "Error! Pixel tolerance for selection should be greater than zero");
- aRes->myNearPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myNearPickedPnt);
- aRes->myFarPickedPnt = SelectMgr_MatOp::Transform (theTrsf, myFarPickedPnt);
- aRes->myViewRayDir = aRes->myFarPickedPnt - aRes->myNearPickedPnt;
+ Handle(SelectMgr_RectangularFrustum) aRes = new SelectMgr_RectangularFrustum();
+ const Standard_Boolean isToScale = theScaleFactor != 1;
+ const Standard_Boolean isToTrsf = theTrsf.Form() != gp_Identity;
- aRes->myIsOrthographic = myIsOrthographic;
+ if (!isToScale && !isToTrsf)
+ return aRes;
- // LeftTopNear
- aRes->myVertices[0] = SelectMgr_MatOp::Transform (theTrsf, myVertices[0]);
- // LeftTopFar
- aRes->myVertices[1] = SelectMgr_MatOp::Transform (theTrsf, myVertices[1]);
- // LeftBottomNear
- aRes->myVertices[2] = SelectMgr_MatOp::Transform (theTrsf, myVertices[2]);
- // LeftBottomFar
- aRes->myVertices[3] = SelectMgr_MatOp::Transform (theTrsf, myVertices[3]);
- // RightTopNear
- aRes->myVertices[4] = SelectMgr_MatOp::Transform (theTrsf, myVertices[4]);
- // RightTopFar
- aRes->myVertices[5] = SelectMgr_MatOp::Transform (theTrsf, myVertices[5]);
- // RightBottomNear
- aRes->myVertices[6] = SelectMgr_MatOp::Transform (theTrsf, myVertices[6]);
- // RightBottomFar
- aRes->myVertices[7] = SelectMgr_MatOp::Transform (theTrsf, myVertices[7]);
-
- // Top
- aRes->myPlanes[0] = myBuilder->PlaneEquation (aRes->myVertices[1],
- aRes->myVertices[0],
- aRes->myVertices[5],
- aRes->myVertices[6]);
- // Bottom
- aRes->myPlanes[1] = myBuilder->PlaneEquation (aRes->myVertices[3],
- aRes->myVertices[2],
- aRes->myVertices[7],
- aRes->myVertices[4]);
- // Left
- aRes->myPlanes[2] = myBuilder->PlaneEquation (aRes->myVertices[1],
- aRes->myVertices[0],
- aRes->myVertices[2],
- aRes->myVertices[6]);
- // Right
- aRes->myPlanes[3] = myBuilder->PlaneEquation (aRes->myVertices[5],
- aRes->myVertices[4],
- aRes->myVertices[6],
- aRes->myVertices[2]);
- // Near
- aRes->myPlanes[4] = myBuilder->PlaneEquation (aRes->myVertices[4],
- aRes->myVertices[6],
- aRes->myVertices[2],
- aRes->myVertices[3]);
- // Far
- aRes->myPlanes[5] = myBuilder->PlaneEquation (aRes->myVertices[5],
- aRes->myVertices[7],
- aRes->myVertices[3],
- aRes->myVertices[2]);
+ aRes->myIsOrthographic = myIsOrthographic;
+ const SelectMgr_RectangularFrustum* aRef = this;
- for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
+ if (isToScale)
{
- Standard_Real aMax = -DBL_MAX;
- Standard_Real aMin = DBL_MAX;
- const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx];
- for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
- {
- Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]);
- aMax = Max (aMax, aProjection);
- aMin = Min (aMin, aProjection);
- }
- aRes->myMaxVertsProjections[aPlaneIdx] = aMax;
- aRes->myMinVertsProjections[aPlaneIdx] = aMin;
+ aRes->myNearPickedPnt = myNearPickedPnt;
+ aRes->myFarPickedPnt = myFarPickedPnt;
+ aRes->myViewRayDir = myViewRayDir;
+
+ const gp_Pnt2d aMinPnt (myMousePos.X() - theScaleFactor * 0.5,
+ myMousePos.Y() - theScaleFactor * 0.5);
+ const gp_Pnt2d aMaxPnt (myMousePos.X() + theScaleFactor * 0.5,
+ myMousePos.Y() + theScaleFactor * 0.5);
+
+ // recompute base frustum characteristics from scratch
+ computeFrustum (aMinPnt, aMaxPnt, myBuilder, aRes->myVertices, aRes->myEdgeDirs);
+
+ aRef = aRes.get();
}
- SelectMgr_Vec3 aDimensions[3] =
+ if (isToTrsf)
{
- SelectMgr_Vec3 (1.0, 0.0, 0.0),
- SelectMgr_Vec3 (0.0, 1.0, 0.0),
- SelectMgr_Vec3 (0.0, 0.0, 1.0)
- };
+ const Standard_Real aRefScale = aRef->myFarPickedPnt.SquareDistance (aRef->myNearPickedPnt);
- for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
- {
- Standard_Real aMax = -DBL_MAX;
- Standard_Real aMin = DBL_MAX;
- for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx)
+ gp_Pnt aPoint = aRef->myNearPickedPnt;
+ theTrsf.Transforms (aPoint.ChangeCoord());
+ aRes->myNearPickedPnt = aPoint;
+
+ aPoint.SetXYZ (aRef->myFarPickedPnt.XYZ());
+ theTrsf.Transforms (aPoint.ChangeCoord());
+ aRes->myFarPickedPnt = aPoint;
+
+ aRes->myViewRayDir = aRes->myFarPickedPnt.XYZ() - aRes->myNearPickedPnt.XYZ();
+
+ for (Standard_Integer anIt = 0; anIt < 8; anIt++)
{
- Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]);
- aMax = Max (aMax, aProjection);
- aMin = Min (aMin, aProjection);
+ aPoint = aRef->myVertices[anIt];
+ theTrsf.Transforms (aPoint.ChangeCoord());
+ aRes->myVertices[anIt] = aPoint;
}
- aRes->myMaxOrthoVertsProjections[aDim] = aMax;
- aRes->myMinOrthoVertsProjections[aDim] = aMin;
+
+ // Horizontal
+ aRes->myEdgeDirs[0] = aRes->myVertices[4].XYZ() - aRes->myVertices[0].XYZ();
+ // Vertical
+ aRes->myEdgeDirs[1] = aRes->myVertices[2].XYZ() - aRes->myVertices[0].XYZ();
+ // LeftLower
+ aRes->myEdgeDirs[2] = aRes->myVertices[2].XYZ() - aRes->myVertices[3].XYZ();
+ // RightLower
+ aRes->myEdgeDirs[3] = aRes->myVertices[6].XYZ() - aRes->myVertices[7].XYZ();
+ // LeftUpper
+ aRes->myEdgeDirs[4] = aRes->myVertices[0].XYZ() - aRes->myVertices[1].XYZ();
+ // RightUpper
+ aRes->myEdgeDirs[5] = aRes->myVertices[4].XYZ() - aRes->myVertices[5].XYZ();
+
+ // Compute scale to transform depth from local coordinate system to world coordinate system
+ aRes->myScale = Sqrt (aRefScale / aRes->myFarPickedPnt.SquareDistance (aRes->myNearPickedPnt));
}
- // Horizontal
- aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0];
- // Vertical
- aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0];
- // LeftLower
- aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3];
- // RightLower
- aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7];
- // LeftUpper
- aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1];
- // RightUpper
- aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5];
-
- return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
+ // compute frustum normals
+ computeNormals (aRes->myEdgeDirs, aRes->myPlanes);
+
+ cacheVertexProjections (aRes.get());
+
+ aRes->myViewClipRange = myViewClipRange;
+ aRes->myIsViewClipEnabled = myIsViewClipEnabled;
+ aRes->myMousePos = myMousePos;
+
+ return aRes;
}
// =======================================================================
// axis-aligned bounding box with minimum corner at point
// theMinPnt and maximum at point theMaxPnt
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theMinPnt,
- const SelectMgr_Vec3& theMaxPnt)
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin,
+ const SelectMgr_Vec3& theBoxMax,
+ Standard_Boolean* theInside) const
{
- return hasOverlap (theMinPnt, theMaxPnt);
+ return hasOverlap (theBoxMin, theBoxMax, theInside);
}
// =======================================================================
// purpose : SAT intersection test between defined volume and
// given axis-aligned box
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const BVH_Box<Standard_Real, 3>& theBox,
- Standard_Real& theDepth)
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin,
+ const SelectMgr_Vec3& theBoxMax,
+ SelectBasics_PickResult& thePickResult) const
{
- const SelectMgr_Vec3& aMinPnt = theBox.CornerMin();
- const SelectMgr_Vec3& aMaxPnt = theBox.CornerMax();
- if (!hasOverlap (aMinPnt, aMaxPnt))
+ if (!hasOverlap (theBoxMin, theBoxMax))
return Standard_False;
- SelectMgr_Vec3 aNearestPnt = SelectMgr_Vec3 (RealLast(), RealLast(), RealLast());
- aNearestPnt.x() = Max (Min (myNearPickedPnt.x(), aMaxPnt.x()), aMinPnt.x());
- aNearestPnt.y() = Max (Min (myNearPickedPnt.y(), aMaxPnt.y()), aMinPnt.y());
- aNearestPnt.z() = Max (Min (myNearPickedPnt.z(), aMaxPnt.z()), aMinPnt.z());
+ gp_Pnt aNearestPnt (RealLast(), RealLast(), RealLast());
+ aNearestPnt.SetX (Max (Min (myNearPickedPnt.X(), theBoxMax.x()), theBoxMin.x()));
+ aNearestPnt.SetY (Max (Min (myNearPickedPnt.Y(), theBoxMax.y()), theBoxMin.y()));
+ aNearestPnt.SetZ (Max (Min (myNearPickedPnt.Z(), theBoxMax.z()), theBoxMin.z()));
- theDepth = DISTANCE (aNearestPnt, myNearPickedPnt);
+ thePickResult.SetDepth (aNearestPnt.Distance (myNearPickedPnt));
- return Standard_True;
+ return isViewClippingOk (thePickResult);
}
// =======================================================================
// function : Overlaps
// purpose : Intersection test between defined volume and given point
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
- Standard_Real& theDepth)
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
+ SelectBasics_PickResult& thePickResult) const
{
if (!hasOverlap (thePnt))
return Standard_False;
- SelectMgr_Vec3 aPnt (thePnt.X(), thePnt.Y(), thePnt.Z());
- SelectMgr_Vec3 aV = aPnt - myNearPickedPnt;
- SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * (DOT (aV, myViewRayDir) / DOT (myViewRayDir, myViewRayDir));
+ gp_XYZ aV = thePnt.XYZ() - myNearPickedPnt.XYZ();
+ gp_Pnt aDetectedPnt =
+ myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * (aV.Dot (myViewRayDir.XYZ()) / myViewRayDir.Dot (myViewRayDir));
- theDepth = DISTANCE (aDetectedPnt, myNearPickedPnt);
+ thePickResult.SetDepth (aDetectedPnt.Distance (myNearPickedPnt) * myScale);
+ thePickResult.SetPickedPoint (thePnt);
- return Standard_True;
+ return isViewClippingOk (thePickResult);
+}
+
+// =======================================================================
+// function : Overlaps
+// purpose : Intersection test between defined volume and given point
+// =======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt) const
+{
+ return hasOverlap (thePnt);
}
// =======================================================================
// function : Overlaps
// purpose : Checks if line segment overlaps selecting frustum
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
- const gp_Pnt& thePnt2,
- Standard_Real& theDepth)
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
+ const gp_Pnt& thePnt2,
+ SelectBasics_PickResult& thePickResult) const
{
- theDepth = -DBL_MAX;
if (!hasOverlap (thePnt1, thePnt2))
return Standard_False;
- segmentSegmentDistance (thePnt1, thePnt2, theDepth);
- return Standard_True;
+ segmentSegmentDistance (thePnt1, thePnt2, thePickResult);
+
+ return isViewClippingOk (thePickResult);
}
// =======================================================================
// may be considered of interior part or boundary line defined
// by segments depending on given sensitivity type
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
- Select3D_TypeOfSensitivity theSensType,
- Standard_Real& theDepth)
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const TColgp_Array1OfPnt& theArrayOfPnts,
+ Select3D_TypeOfSensitivity theSensType,
+ SelectBasics_PickResult& thePickResult) const
{
if (theSensType == Select3D_TOS_BOUNDARY)
{
Standard_Integer aMatchingSegmentsNb = -1;
- theDepth = DBL_MAX;
- Standard_Integer aLower = theArrayOfPnts->Lower();
- Standard_Integer anUpper = theArrayOfPnts->Upper();
-
+ SelectBasics_PickResult aPickResult;
+ thePickResult.Invalidate();
+ const Standard_Integer aLower = theArrayOfPnts.Lower();
+ const Standard_Integer anUpper = theArrayOfPnts.Upper();
for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter)
{
- const gp_Pnt& aStartPnt = theArrayOfPnts->Value (aPntIter);
- const gp_Pnt& aEndPnt = aPntIter == anUpper ? theArrayOfPnts->Value (aLower)
- : theArrayOfPnts->Value (aPntIter + 1);
-
+ const gp_Pnt& aStartPnt = theArrayOfPnts.Value (aPntIter);
+ const gp_Pnt& aEndPnt = theArrayOfPnts.Value (aPntIter == anUpper ? aLower : (aPntIter + 1));
if (hasOverlap (aStartPnt, aEndPnt))
{
aMatchingSegmentsNb++;
- Standard_Real aSegmentDepth = RealLast();
- segmentSegmentDistance (aStartPnt, aEndPnt, aSegmentDepth);
- theDepth = Min (theDepth, aSegmentDepth);
+ segmentSegmentDistance (aStartPnt, aEndPnt, aPickResult);
+ thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
}
}
}
else if (theSensType == Select3D_TOS_INTERIOR)
{
- SelectMgr_Vec3 aPolyNorm (RealLast());
- if (!hasOverlap (theArrayOfPnts, aPolyNorm))
+ gp_Vec aPolyNorm (gp_XYZ (RealLast(), RealLast(), RealLast()));
+ if (!hasOverlap (theArrayOfPnts, aPolyNorm)
+ || !segmentPlaneIntersection (aPolyNorm,
+ theArrayOfPnts.First(),
+ thePickResult))
+ {
return Standard_False;
-
- segmentPlaneIntersection (aPolyNorm,
- theArrayOfPnts->Value (theArrayOfPnts->Lower()),
- theDepth);
+ }
}
- return Standard_True;
+ return isViewClippingOk (thePickResult);
}
// =======================================================================
// boundary line defined by triangle vertices depending on
// given sensitivity type
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
- const gp_Pnt& thePnt2,
- const gp_Pnt& thePnt3,
- Select3D_TypeOfSensitivity theSensType,
- Standard_Real& theDepth)
+Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
+ const gp_Pnt& thePnt2,
+ const gp_Pnt& thePnt3,
+ Select3D_TypeOfSensitivity theSensType,
+ SelectBasics_PickResult& thePickResult) const
{
if (theSensType == Select3D_TOS_BOUNDARY)
{
- Handle(TColgp_HArray1OfPnt) aPntsArray = new TColgp_HArray1OfPnt(1, 4);
- aPntsArray->SetValue (1, thePnt1);
- aPntsArray->SetValue (2, thePnt2);
- aPntsArray->SetValue (3, thePnt3);
- aPntsArray->SetValue (4, thePnt1);
- return Overlaps (aPntsArray, Select3D_TOS_BOUNDARY, theDepth);
+ const gp_Pnt aPntsArrayBuf[4] = { thePnt1, thePnt2, thePnt3, thePnt1 };
+ const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 4);
+ return Overlaps (aPntsArray, Select3D_TOS_BOUNDARY, thePickResult);
}
else if (theSensType == Select3D_TOS_INTERIOR)
{
- SelectMgr_Vec3 aTriangleNormal (RealLast());
+ gp_Vec aTriangleNormal (gp_XYZ (RealLast(), RealLast(), RealLast()));
if (!hasOverlap (thePnt1, thePnt2, thePnt3, aTriangleNormal))
return Standard_False;
// check if intersection point belongs to triangle's interior part
- SelectMgr_Vec3 aPnt1 (thePnt1.X(), thePnt1.Y(), thePnt1.Z());
- SelectMgr_Vec3 aTrEdges[3] = { SelectMgr_Vec3 (thePnt2.X() - thePnt1.X(), thePnt2.Y() - thePnt1.Y(), thePnt2.Z() - thePnt1.Z()),
- SelectMgr_Vec3 (thePnt3.X() - thePnt2.X(), thePnt3.Y() - thePnt2.Y(), thePnt3.Z() - thePnt2.Z()),
- SelectMgr_Vec3 (thePnt1.X() - thePnt3.X(), thePnt1.Y() - thePnt3.Y(), thePnt1.Z() - thePnt3.Z()) };
- SelectMgr_Vec3 anEdge = (aPnt1 - myNearPickedPnt) * (1.0 / DOT (aTriangleNormal, myViewRayDir));
+ gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(),
+ thePnt3.XYZ() - thePnt2.XYZ(),
+ thePnt1.XYZ() - thePnt3.XYZ() };
+
+ Standard_Real anAlpha = aTriangleNormal.Dot (myViewRayDir);
+ if (Abs (anAlpha) < gp::Resolution())
+ {
+ // handle degenerated triangles: in this case, there is no possible way to detect overlap correctly.
+ if (aTriangleNormal.SquareMagnitude() < gp::Resolution())
+ {
+ return Standard_False;
+ }
- Standard_Real aTime = DOT (aTriangleNormal, anEdge);
+ // handle the case when triangle normal and selecting frustum direction are orthogonal: for this case, overlap
+ // is detected correctly, and distance to triangle's plane can be measured as distance to its arbitrary vertex.
+ const gp_XYZ aDiff = myNearPickedPnt.XYZ() - thePnt1.XYZ();
+ thePickResult.SetDepth (aTriangleNormal.Dot (aDiff) * myScale);
+ thePickResult.SetPickedPoint (thePnt1);
+ return isViewClippingOk (thePickResult);
+ }
- SelectMgr_Vec3 aVec = SelectMgr_Vec3 (myViewRayDir.y() * anEdge.z() - myViewRayDir.z() * anEdge.y(),
- myViewRayDir.z() * anEdge.x() - myViewRayDir.x() * anEdge.z(),
- myViewRayDir.x() * anEdge.y() - myViewRayDir.y() * anEdge.x());
+ gp_XYZ anEdge = (thePnt1.XYZ() - myNearPickedPnt.XYZ()) * (1.0 / anAlpha);
- Standard_Real anU = DOT (aVec, aTrEdges[2]);
- Standard_Real aV = DOT (aVec, aTrEdges[0]);
+ Standard_Real aTime = aTriangleNormal.Dot (anEdge);
- Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
+ gp_XYZ aVec = myViewRayDir.XYZ().Crossed (anEdge);
+ Standard_Real anU = aVec.Dot (aTrEdges[2]);
+ Standard_Real aV = aVec.Dot (aTrEdges[0]);
+
+ const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
+ const gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime;
if (isInterior)
{
- SelectMgr_Vec3 aDetectedPnt = myNearPickedPnt + myViewRayDir * aTime;
- theDepth = DISTANCE (myNearPickedPnt, aDetectedPnt);
- return Standard_True;
+ thePickResult.SetDepth (myNearPickedPnt.Distance (aPtOnPlane) * myScale);
+ thePickResult.SetPickedPoint (aPtOnPlane);
+ return isViewClippingOk (thePickResult);
}
gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
Standard_Real aMinDist = RealLast();
Standard_Integer aNearestEdgeIdx = -1;
- SelectMgr_Vec3 aPtOnPlane = myNearPickedPnt + myViewRayDir * aTime;
for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
{
- SelectMgr_Vec3 aW = SelectMgr_Vec3 (aPtOnPlane.x() - aPnts[anEdgeIdx].X(),
- aPtOnPlane.y() - aPnts[anEdgeIdx].Y(),
- aPtOnPlane.z() - aPnts[anEdgeIdx].Z());
- Standard_Real aCoef = DOT (aTrEdges[anEdgeIdx], aW) / DOT (aTrEdges[anEdgeIdx], aTrEdges[anEdgeIdx]);
- Standard_Real aDist = DISTANCE (aPtOnPlane, SelectMgr_Vec3 (aPnts[anEdgeIdx].X() + aCoef * aTrEdges[anEdgeIdx].x(),
- aPnts[anEdgeIdx].Y() + aCoef * aTrEdges[anEdgeIdx].y(),
- aPnts[anEdgeIdx].Z() + aCoef * aTrEdges[anEdgeIdx].z()));
+ gp_XYZ aW = aPtOnPlane.XYZ() - aPnts[anEdgeIdx].XYZ();
+ Standard_Real aCoef = aTrEdges[anEdgeIdx].Dot (aW) / aTrEdges[anEdgeIdx].Dot (aTrEdges[anEdgeIdx]);
+ Standard_Real aDist = aPtOnPlane.Distance (aPnts[anEdgeIdx].XYZ() + aCoef * aTrEdges[anEdgeIdx]);
if (aMinDist > aDist)
{
aMinDist = aDist;
aNearestEdgeIdx = anEdgeIdx;
}
}
- segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], theDepth);
+ segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], thePickResult);
}
- return Standard_True;
+ return isViewClippingOk (thePickResult);
}
// =======================================================================
// purpose : Measures distance between 3d projection of user-picked
// screen point and given point theCOG
// =======================================================================
-const Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG)
+Standard_Real SelectMgr_RectangularFrustum::DistToGeometryCenter (const gp_Pnt& theCOG) const
{
- const SelectMgr_Vec3& aCOG = SelectMgr_Vec3 (theCOG.X(), theCOG.Y(), theCOG.Z());
- return DISTANCE (aCOG, myNearPickedPnt);
+ return theCOG.Distance (myNearPickedPnt) * myScale;
}
// =======================================================================
// purpose : Calculates the point on a view ray that was detected during
// the run of selection algo by given depth
// =======================================================================
-SelectMgr_Vec3 SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const
+gp_Pnt SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth) const
{
- return myNearPickedPnt + myViewRayDir * theDepth;
+ return myNearPickedPnt.XYZ() + myViewRayDir.Normalized().XYZ() * theDepth / myScale;
}
// =======================================================================
-// function : IsClipped
-// purpose : Checks if the point of sensitive in which selection was
-// detected belongs to the region defined by clipping planes
+// function : computeClippingRange
+// purpose :
// =======================================================================
-const Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes,
- const Standard_Real theDepth)
+void SelectMgr_RectangularFrustum::computeClippingRange (const Graphic3d_SequenceOfHClipPlane& thePlanes,
+ SelectMgr_ViewClipRange& theRange) const
{
- Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes);
- Standard_Real aMaxDepth = DBL_MAX;
- Standard_Real aMinDepth = -DBL_MAX;
Standard_Real aPlaneA, aPlaneB, aPlaneC, aPlaneD;
- for ( ; aPlaneIt.More(); aPlaneIt.Next())
+ for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes); aPlaneIt.More(); aPlaneIt.Next())
{
const Handle(Graphic3d_ClipPlane)& aClipPlane = aPlaneIt.Value();
if (!aClipPlane->IsOn())
+ {
continue;
+ }
- gp_Pln aGeomPlane = aClipPlane->ToPlane();
-
- aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD);
+ Bnd_Range aSubRange (RealFirst(), RealLast());
+ for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get())
+ {
+ const gp_Pln aGeomPlane = aSubPlaneIter->ToPlane();
+ aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD);
- const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ();
+ const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ();
+ Standard_Real aDotProduct = myViewRayDir.XYZ().Dot (aPlaneDirXYZ);
+ Standard_Real aDistance = -myNearPickedPnt.XYZ().Dot (aPlaneDirXYZ) - aPlaneD;
+ Standard_Real aDistToPln = 0.0;
- Standard_Real aDotProduct = DOTp (myViewRayDir, aPlaneDirXYZ);
- Standard_Real aDistance = - (DOTp (myNearPickedPnt, aPlaneDirXYZ) + aPlaneD);
+ // check whether the pick line is parallel to clip plane
+ if (Abs (aDotProduct) < Precision::Angular())
+ {
+ if (aDistance < 0.0)
+ {
+ continue;
+ }
+ aDistToPln = RealLast();
+ aDotProduct = 1.0;
+ }
+ else
+ {
+ // compute distance to point of pick line intersection with the plane
+ const Standard_Real aParam = aDistance / aDotProduct;
+
+ const gp_Pnt anIntersectionPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aParam;
+ aDistToPln = anIntersectionPnt.Distance (myNearPickedPnt);
+ if (aParam < 0.0)
+ {
+ // the plane is "behind" the ray
+ aDistToPln = -aDistToPln;
+ }
+ }
- // check whether the pick line is parallel to clip plane
- if (Abs (aDotProduct) < Precision::Angular())
- {
- // line lies below the plane and is not clipped, skip
- continue;
+ // change depth limits for case of opposite and directed planes
+ if (!aClipPlane->IsChain())
+ {
+ if (aDotProduct < 0.0)
+ {
+ theRange.ChangeUnclipRange().TrimTo (aDistToPln);
+ }
+ else
+ {
+ theRange.ChangeUnclipRange().TrimFrom (aDistToPln);
+ }
+ }
+ else
+ {
+ if (aDotProduct < 0.0)
+ {
+ aSubRange.TrimFrom (aDistToPln);
+ }
+ else
+ {
+ aSubRange.TrimTo (aDistToPln);
+ }
+ }
}
- // compute distance to point of pick line intersection with the plane
- Standard_Real aParam = aDistance / aDotProduct;
-
- // check if ray intersects the plane, in case aIntDist < 0
- // the plane is "behind" the ray
- if (aParam < 0.0)
+ if (!aSubRange.IsVoid()
+ && aClipPlane->IsChain())
{
- continue;
+ theRange.AddClipSubRange (aSubRange);
}
+ }
+}
- const SelectMgr_Vec3 anIntersectionPt = myNearPickedPnt + myViewRayDir * aParam;
- const Standard_Real aDistToPln = DISTANCE (anIntersectionPt, myNearPickedPnt);
+// =======================================================================
+// function : IsClipped
+// purpose : Checks if the point of sensitive in which selection was
+// detected belongs to the region defined by clipping planes
+// =======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes,
+ const Standard_Real theDepth) const
+{
+ SelectMgr_ViewClipRange aRange;
+ computeClippingRange (thePlanes, aRange);
+ return aRange.IsClipped (theDepth);
+}
- // change depth limits for case of opposite and directed planes
- if (aDotProduct < 0.0)
- {
- aMaxDepth = Min (aDistToPln, aMaxDepth);
- }
- else if (aDistToPln > aMinDepth)
- {
- aMinDepth = Max (aDistToPln, aMinDepth);
- }
+// =======================================================================
+// function : SetViewClipping
+// purpose :
+// =======================================================================
+void SelectMgr_RectangularFrustum::SetViewClipping (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes)
+{
+ if (thePlanes.IsNull()
+ || thePlanes->IsEmpty())
+ {
+ myViewClipRange.SetVoid();
+ return;
}
- return (theDepth <= aMinDepth || theDepth >= aMaxDepth);
+ computeClippingRange (*thePlanes, myViewClipRange);
+}
+
+// =======================================================================
+// function : isViewClippingOk
+// purpose :
+// =======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::isViewClippingOk (const SelectBasics_PickResult& thePickResult) const
+{
+ return !myIsViewClipEnabled
+ || !myViewClipRange.IsClipped (thePickResult.Depth());
+}
+
+// =======================================================================
+// function : GetPlanes
+// purpose :
+// =======================================================================
+void SelectMgr_RectangularFrustum::GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const
+{
+ thePlaneEquations.Clear();
+
+ SelectMgr_Vec4 anEquation;
+ for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx)
+ {
+ const gp_Vec& aPlaneNorm = myIsOrthographic && aPlaneIdx % 2 == 1 ?
+ myPlanes[aPlaneIdx - 1].Reversed() : myPlanes[aPlaneIdx];
+ anEquation.x() = aPlaneNorm.X();
+ anEquation.y() = aPlaneNorm.Y();
+ anEquation.z() = aPlaneNorm.Z();
+ anEquation.w() = - (aPlaneNorm.XYZ().Dot (myVertices[aPlaneIdx % 2 == 0 ? aPlaneIdx : aPlaneIdx + 2].XYZ()));
+ thePlaneEquations.Append (anEquation);
+ }
}