mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-14 13:30:48 +03:00
0032281: Visualization - add Select3D_SensitiveCylinder
- implemented Select3D_SensitiveCylinder class performing an analytical intersection with an untriangulated cone/cylinder - added tests
This commit is contained in:
@@ -547,6 +547,66 @@ Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCen
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_AxisIntersector::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const
|
||||
{
|
||||
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
|
||||
"Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
|
||||
Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
|
||||
gp_Trsf aTrsfInv = theTrsf.Inverted();
|
||||
gp_Pnt aLoc = myAxis.Location() .Transformed (aTrsfInv);
|
||||
gp_Dir aRayDir = myAxis.Direction().Transformed (aTrsfInv);
|
||||
if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Standard_Real aDepth = 0.0;
|
||||
Bnd_Range aRange (Max (aTimeEnter, 0.0), aTimeLeave);
|
||||
aRange.GetMin (aDepth);
|
||||
if (!theClipRange.GetNearestDepth (aRange, aDepth))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
thePickResult.SetDepth (aDepth);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_AxisIntersector::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
|
||||
"Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
|
||||
Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
|
||||
gp_Trsf aTrsfInv = theTrsf.Inverted();
|
||||
gp_Pnt aLoc = myAxis.Location() .Transformed (aTrsfInv);
|
||||
gp_Dir aRayDir = myAxis.Direction().Transformed (aTrsfInv);
|
||||
if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (theInside != NULL)
|
||||
{
|
||||
*theInside &= (aTimeEnter >= 0.0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : GetNearPnt
|
||||
// purpose :
|
||||
|
@@ -111,6 +111,23 @@ public:
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
|
||||
|
||||
public:
|
||||
|
||||
//! Measures distance between start axis point and given point theCOG.
|
||||
|
@@ -14,6 +14,9 @@
|
||||
#include <SelectMgr_BaseIntersector.hxx>
|
||||
|
||||
#include <Graphic3d_Camera.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_BaseIntersector, Standard_Transient)
|
||||
|
||||
@@ -164,6 +167,132 @@ Standard_Boolean SelectMgr_BaseIntersector::RaySphereIntersection (const gp_Pnt&
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : RayCylinderIntersection
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_BaseIntersector::RayCylinderIntersection (const Standard_Real theBottomRadius,
|
||||
const Standard_Real theTopRadius,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Pnt& theLoc,
|
||||
const gp_Dir& theRayDir,
|
||||
Standard_Real& theTimeEnter,
|
||||
Standard_Real& theTimeLeave) const
|
||||
{
|
||||
Standard_Integer aNbIntersections = 0;
|
||||
Standard_Real anIntersections[4] = { RealLast(), RealLast(), RealLast(), RealLast() };
|
||||
//NCollection_Vector<Standard_Real> anIntersections; // vector for all intersections
|
||||
// Check intersections with end faces
|
||||
// point of intersection theRayDir and z = 0
|
||||
if (theRayDir.Z() != 0)
|
||||
{
|
||||
const Standard_Real aTime1 = (0 - theLoc.Z()) / theRayDir.Z();
|
||||
const Standard_Real aX1 = theLoc.X() + theRayDir.X() * aTime1;
|
||||
const Standard_Real anY1 = theLoc.Y() + theRayDir.Y() * aTime1;
|
||||
if (aX1 * aX1 + anY1 * anY1 <= theBottomRadius * theBottomRadius)
|
||||
{
|
||||
anIntersections[aNbIntersections++] = aTime1;
|
||||
}
|
||||
// point of intersection theRayDir and z = theHeight
|
||||
const Standard_Real aTime2 = (theHeight - theLoc.Z()) / theRayDir.Z();
|
||||
const Standard_Real aX2 = theLoc.X() + theRayDir.X() * aTime2;
|
||||
const Standard_Real anY2 = theLoc.Y() + theRayDir.Y() * aTime2;
|
||||
if (aX2 * aX2 + anY2 * anY2 <= theTopRadius * theTopRadius)
|
||||
{
|
||||
anIntersections[aNbIntersections++] = aTime2;
|
||||
}
|
||||
}
|
||||
// ray intersection with cone / truncated cone
|
||||
if (theTopRadius != theBottomRadius)
|
||||
{
|
||||
const Standard_Real aTriangleHeight = Min (theBottomRadius, theTopRadius) * theHeight /
|
||||
(Abs (theBottomRadius - theTopRadius));
|
||||
gp_Ax3 aSystem;
|
||||
if (theBottomRadius > theTopRadius)
|
||||
{
|
||||
aSystem.SetLocation (gp_Pnt (0, 0, theHeight + aTriangleHeight));
|
||||
aSystem.SetDirection (-gp::DZ());
|
||||
}
|
||||
else
|
||||
{
|
||||
aSystem.SetLocation (gp_Pnt (0, 0, -aTriangleHeight));
|
||||
aSystem.SetDirection (gp::DZ());
|
||||
}
|
||||
gp_Trsf aTrsfCone;
|
||||
aTrsfCone.SetTransformation (gp_Ax3(), aSystem);
|
||||
const gp_Pnt aPnt (theLoc.Transformed (aTrsfCone));
|
||||
const gp_Dir aDir (theRayDir.Transformed (aTrsfCone));
|
||||
const Standard_Real aMaxRad = Max (theBottomRadius, theTopRadius);
|
||||
const Standard_Real aConeHeight = theHeight + aTriangleHeight;
|
||||
|
||||
// solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
|
||||
const Standard_Real anA = aDir.X() * aDir.X() / (aMaxRad * aMaxRad)
|
||||
+ aDir.Y() * aDir.Y() / (aMaxRad * aMaxRad)
|
||||
- aDir.Z() * aDir.Z() / (aConeHeight * aConeHeight);
|
||||
const Standard_Real aK = aDir.X() * aPnt.X() / (aMaxRad * aMaxRad)
|
||||
+ aDir.Y() * aPnt.Y() / (aMaxRad * aMaxRad)
|
||||
- aDir.Z() * aPnt.Z() / (aConeHeight * aConeHeight);
|
||||
const Standard_Real aC = aPnt.X() * aPnt.X() / (aMaxRad * aMaxRad)
|
||||
+ aPnt.Y() * aPnt.Y() / (aMaxRad * aMaxRad)
|
||||
- aPnt.Z() * aPnt.Z() / (aConeHeight * aConeHeight);
|
||||
Standard_Real aDiscr = aK * aK - anA * aC;
|
||||
if (aDiscr > 0)
|
||||
{
|
||||
const Standard_Real aTimeEnterCone = (-aK - Sqrt (aDiscr)) / anA;
|
||||
const Standard_Real aTimeLeaveCone = (-aK + Sqrt (aDiscr)) / anA;
|
||||
const Standard_Real aZFromRoot1 = aPnt.Z() + aTimeEnterCone * aDir.Z();
|
||||
const Standard_Real aZFromRoot2 = aPnt.Z() + aTimeLeaveCone * aDir.Z();
|
||||
|
||||
if (aZFromRoot1 > aTriangleHeight && aZFromRoot1 < aConeHeight)
|
||||
{
|
||||
anIntersections[aNbIntersections++] = aTimeEnterCone;
|
||||
}
|
||||
if (aZFromRoot2 > aTriangleHeight && aZFromRoot2 < aConeHeight)
|
||||
{
|
||||
anIntersections[aNbIntersections++] = aTimeLeaveCone;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // ray intersection with cylinder
|
||||
{
|
||||
const gp_Pnt2d aLoc2d (theLoc.X(), theLoc.Y());
|
||||
const gp_Vec2d aRayDir2d (theRayDir.X(), theRayDir.Y());
|
||||
|
||||
// solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
|
||||
const Standard_Real anA = aRayDir2d.Dot (aRayDir2d);
|
||||
const Standard_Real aK = aLoc2d.XY().Dot (aRayDir2d.XY());
|
||||
const Standard_Real aC = aLoc2d.XY().Dot (aLoc2d.XY()) - theTopRadius * theTopRadius;
|
||||
const Standard_Real aDiscr = aK * aK - anA * aC;
|
||||
if (aDiscr > 0)
|
||||
{
|
||||
const Standard_Real aRoot1 = (-aK + Sqrt (aDiscr)) / anA;
|
||||
const Standard_Real aRoot2 = (-aK - Sqrt (aDiscr)) / anA;
|
||||
const Standard_Real aZFromRoot1 = theLoc.Z() + aRoot1 * theRayDir.Z();
|
||||
const Standard_Real aZFromRoot2 = theLoc.Z() + aRoot2 * theRayDir.Z();
|
||||
if (aZFromRoot1 > 0 && aZFromRoot1 < theHeight)
|
||||
{
|
||||
anIntersections[aNbIntersections++] = aRoot1;
|
||||
}
|
||||
if (aZFromRoot2 > 0 && aZFromRoot2 < theHeight)
|
||||
{
|
||||
anIntersections[aNbIntersections++] = aRoot2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aNbIntersections == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::sort (anIntersections, anIntersections + aNbIntersections);
|
||||
theTimeEnter = anIntersections[0];
|
||||
if (aNbIntersections > 1)
|
||||
{
|
||||
theTimeLeave = anIntersections[1];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : DistToGeometryCenter
|
||||
// purpose :
|
||||
|
@@ -181,6 +181,23 @@ public:
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const = 0;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const = 0;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const = 0;
|
||||
|
||||
public:
|
||||
|
||||
//! Measures distance between 3d projection of user-picked
|
||||
@@ -206,6 +223,16 @@ public:
|
||||
Standard_Real& theTimeEnter,
|
||||
Standard_Real& theTimeLeave) const;
|
||||
|
||||
//! Checks whether the ray that starts at the point theLoc and directs with the direction theRayDir intersects
|
||||
//! with the cylinder (or cone) with radiuses theBottomRad and theTopRad and height theHeights
|
||||
Standard_EXPORT virtual Standard_Boolean RayCylinderIntersection (const Standard_Real theBottomRadius,
|
||||
const Standard_Real theTopRadius,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Pnt& theLoc,
|
||||
const gp_Dir& theRayDir,
|
||||
Standard_Real& theTimeEnter,
|
||||
Standard_Real& theTimeLeave) const;
|
||||
|
||||
DEFINE_STANDARD_RTTIEXT(SelectMgr_BaseIntersector,Standard_Transient)
|
||||
|
||||
protected:
|
||||
|
@@ -93,8 +93,34 @@ protected:
|
||||
const Standard_Real theRadius,
|
||||
Standard_Boolean* theInside = NULL) const;
|
||||
|
||||
//! Intersection test between defined volume and given cylinder (or cone).
|
||||
Standard_Boolean hasCylinderOverlap (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const;
|
||||
|
||||
//! Checking whether the point thePnt is inside the shape with borders theVertices.
|
||||
//! thePnt and theVertices lie in the same plane.
|
||||
Standard_Boolean IsDotInside (const gp_Pnt& thePnt,
|
||||
const TColgp_Array1OfPnt& theVertices) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Return true if one segment enclosed between the points thePnt1Seg1 and thePnt2Seg1
|
||||
//! intersects another segment that enclosed between thePnt1Seg2 and thePnt2Seg2.
|
||||
Standard_Boolean isSegmentsIntersect (const gp_Pnt& thePnt1Seg1,
|
||||
const gp_Pnt& thePnt2Seg1,
|
||||
const gp_Pnt& thePnt1Seg2,
|
||||
const gp_Pnt& thePnt2Seg2) const;
|
||||
|
||||
//! Checking whether the borders theVertices of the shape intersect
|
||||
//! the cylinder (or cone) end face with the center theCenter and radius theRadius
|
||||
Standard_Boolean isIntersectCylinderEndFace (const Standard_Real theRad,
|
||||
const gp_Pnt& theCenter,
|
||||
const gp_Trsf& theTrsf,
|
||||
const TColgp_Array1OfPnt& theVertices) const;
|
||||
|
||||
//! Checks if AABB and frustum are separated along the given axis
|
||||
Standard_Boolean isSeparated (const SelectMgr_Vec3& theBoxMin,
|
||||
const SelectMgr_Vec3& theBoxMax,
|
||||
|
@@ -13,6 +13,7 @@
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <gp_Pln.hxx>
|
||||
#include <NCollection_Vector.hxx>
|
||||
#include <Poly_Array1OfTriangle.hxx>
|
||||
#include <Standard_Assert.hxx>
|
||||
@@ -147,7 +148,6 @@ Standard_Boolean SelectMgr_Frustum<N>::hasBoxOverlap (const SelectMgr_Vec3& theM
|
||||
}
|
||||
|
||||
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
|
||||
|
||||
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
|
||||
{
|
||||
const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
|
||||
@@ -207,7 +207,6 @@ template <int N>
|
||||
Standard_Boolean SelectMgr_Frustum<N>::hasPointOverlap (const gp_Pnt& thePnt) const
|
||||
{
|
||||
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
|
||||
|
||||
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
|
||||
{
|
||||
const Standard_Real aPointProj = myPlanes[aPlaneIdx].XYZ().Dot (thePnt.XYZ());
|
||||
@@ -516,6 +515,259 @@ Standard_Boolean SelectMgr_Frustum<N>::hasSphereOverlap (const gp_Pnt& thePnt,
|
||||
return IsBoundaryIntersectSphere (aCenterProj, theRadius, aNorm, aBoundaries, isBoundaryInside);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : IsDotInside
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
template<int N>
|
||||
Standard_Boolean SelectMgr_Frustum<N>::IsDotInside (const gp_Pnt& thePnt,
|
||||
const TColgp_Array1OfPnt& theVertices) const
|
||||
{
|
||||
Standard_Real anAngle = 0.0;
|
||||
for (Standard_Integer aVertIdx = 0; aVertIdx < theVertices.Size(); aVertIdx++)
|
||||
{
|
||||
const gp_Pnt aVert1 = theVertices[aVertIdx];
|
||||
const gp_Pnt aVert2 = (aVertIdx == (theVertices.Size() - 1) ? theVertices[0] : theVertices[aVertIdx + 1]);
|
||||
const gp_Vec aVec1 (thePnt, aVert1);
|
||||
const gp_Vec aVec2 (thePnt, aVert2);
|
||||
anAngle += aVec1.Angle (aVec2);
|
||||
}
|
||||
if (Abs (anAngle - 2.0 * M_PI) < Precision::Angular())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : isSegmentsIntersect
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
template<int N>
|
||||
Standard_Boolean SelectMgr_Frustum<N>::isSegmentsIntersect (const gp_Pnt& thePnt1Seg1,
|
||||
const gp_Pnt& thePnt2Seg1,
|
||||
const gp_Pnt& thePnt1Seg2,
|
||||
const gp_Pnt& thePnt2Seg2) const
|
||||
{
|
||||
const gp_Mat aMatPln (thePnt2Seg1.X() - thePnt1Seg1.X(), thePnt2Seg1.Y() - thePnt1Seg1.Y(), thePnt2Seg1.Z() - thePnt1Seg1.Z(),
|
||||
thePnt1Seg2.X() - thePnt1Seg1.X(), thePnt1Seg2.Y() - thePnt1Seg1.Y(), thePnt1Seg2.Z() - thePnt1Seg1.Z(),
|
||||
thePnt2Seg2.X() - thePnt1Seg1.X(), thePnt2Seg2.Y() - thePnt1Seg1.Y(), thePnt2Seg2.Z() - thePnt1Seg1.Z());
|
||||
if (Abs (aMatPln.Determinant()) > Precision::Confusion())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Standard_Real aFst[4] = {thePnt1Seg1.X(), thePnt2Seg1.X(), thePnt1Seg2.X(), thePnt2Seg2.X()};
|
||||
Standard_Real aSnd[4] = {thePnt1Seg1.Y(), thePnt2Seg1.Y(), thePnt1Seg2.Y(), thePnt2Seg2.Y()};
|
||||
if (aFst[0] == aFst[2] && aFst[1] == aFst[3])
|
||||
{
|
||||
aFst[0] = thePnt1Seg1.Z();
|
||||
aFst[1] = thePnt2Seg1.Z();
|
||||
aFst[2] = thePnt1Seg2.Z();
|
||||
aFst[3] = thePnt2Seg2.Z();
|
||||
}
|
||||
if (aSnd[0] == aSnd[2]
|
||||
&& aSnd[1] == aSnd[3])
|
||||
{
|
||||
aSnd[0] = thePnt1Seg1.Z();
|
||||
aSnd[1] = thePnt2Seg1.Z();
|
||||
aSnd[2] = thePnt1Seg2.Z();
|
||||
aSnd[3] = thePnt2Seg2.Z();
|
||||
}
|
||||
const gp_Mat2d aMat (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
|
||||
gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
|
||||
|
||||
const gp_Mat2d aMatU (gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]),
|
||||
gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
|
||||
|
||||
const gp_Mat2d aMatV (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
|
||||
gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]));
|
||||
if (aMat.Determinant() == 0.0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const Standard_Real anU = aMatU.Determinant() / aMat.Determinant();
|
||||
const Standard_Real aV = aMatV.Determinant() / aMat.Determinant();
|
||||
if (anU >= 0.0 && anU <= 1.0
|
||||
&& aV >= 0.0 && aV <= 1.0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : isIntersectCylinderEndFace
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
template<int N>
|
||||
Standard_Boolean SelectMgr_Frustum<N>::isIntersectCylinderEndFace (const Standard_Real theRad,
|
||||
const gp_Pnt& theCenter,
|
||||
const gp_Trsf& theTrsf,
|
||||
const TColgp_Array1OfPnt& theVertices) const
|
||||
{
|
||||
const gp_Trsf aTrsfInv = theTrsf.Inverted();
|
||||
const gp_Dir aRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]).Transformed (aTrsfInv);
|
||||
if (aRayDir.Z() == 0.0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
|
||||
{
|
||||
const gp_Pnt aPntStart = theVertices.Value (anIdx).Transformed (aTrsfInv);
|
||||
const gp_Pnt aPntFinish = anIdx == theVertices.Upper()
|
||||
? theVertices.Value (theVertices.Lower()).Transformed (aTrsfInv)
|
||||
: theVertices.Value (anIdx + 1).Transformed (aTrsfInv);
|
||||
|
||||
// Project points on the end face plane
|
||||
const Standard_Real aParam1 = (theCenter.Z() - aPntStart.Z()) / aRayDir.Z();
|
||||
const Standard_Real aX1 = aPntStart.X() + aRayDir.X() * aParam1;
|
||||
const Standard_Real anY1 = aPntStart.Y() + aRayDir.Y() * aParam1;
|
||||
|
||||
const Standard_Real aParam2 = (theCenter.Z() - aPntFinish.Z()) / aRayDir.Z();
|
||||
const Standard_Real aX2 = aPntFinish.X() + aRayDir.X() * aParam2;
|
||||
const Standard_Real anY2 = aPntFinish.Y() + aRayDir.Y() * aParam2;
|
||||
|
||||
// Solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
|
||||
const Standard_Real anA = (aX1 - aX2) * (aX1 - aX2) + (anY1 - anY2) * (anY1 - anY2);
|
||||
const Standard_Real aK = aX1 * (aX2 - aX1) + anY1 * (anY2 - anY1);
|
||||
const Standard_Real aC = aX1 * aX1 + anY1 * anY1 - theRad * theRad;
|
||||
|
||||
const Standard_Real aDiscr = aK * aK - anA * aC;
|
||||
if (aDiscr >= 0.0)
|
||||
{
|
||||
const Standard_Real aT1 = (-aK + Sqrt (aDiscr)) / anA;
|
||||
const Standard_Real aT2 = (-aK - Sqrt (aDiscr)) / anA;
|
||||
if ((aT1 >= 0 && aT1 <= 1) || (aT2 >= 0 && aT2 <= 1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : hasCylinderOverlap
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
template<int N>
|
||||
Standard_Boolean SelectMgr_Frustum<N>::hasCylinderOverlap (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
const gp_Dir aCylNorm (gp::DZ().Transformed (theTrsf));
|
||||
const gp_Pnt aBottomCenter (gp::Origin().Transformed (theTrsf));
|
||||
const gp_Pnt aTopCenter = aBottomCenter.XYZ() + aCylNorm.XYZ() * theHeight;
|
||||
|
||||
const gp_Dir aViewRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]);
|
||||
const gp_Pln aPln (myVertices[0], aViewRayDir);
|
||||
Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
|
||||
aPln.Coefficients (aCoefA, aCoefB, aCoefC, aCoefD);
|
||||
|
||||
const Standard_Real aTBottom = -(aBottomCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
|
||||
const gp_Pnt aBottomCenterProject (aCoefA * aTBottom + aBottomCenter.X(),
|
||||
aCoefB * aTBottom + aBottomCenter.Y(),
|
||||
aCoefC * aTBottom + aBottomCenter.Z());
|
||||
const Standard_Real aTTop = -(aTopCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
|
||||
const gp_Pnt aTopCenterProject (aCoefA * aTTop + aTopCenter.X(),
|
||||
aCoefB * aTTop + aTopCenter.Y(),
|
||||
aCoefC * aTTop + aTopCenter.Z());
|
||||
gp_Vec aCylNormProject (0, 0, 0);
|
||||
if (aTopCenterProject.Distance (aBottomCenterProject) > 0.0)
|
||||
{
|
||||
aCylNormProject = gp_Vec ((aTopCenterProject.XYZ() - aBottomCenterProject.XYZ())
|
||||
/ aTopCenterProject.Distance (aBottomCenterProject));
|
||||
}
|
||||
|
||||
gp_Pnt aPoints[6];
|
||||
const gp_Dir aDirEndFaces = (aCylNorm.IsParallel (aViewRayDir, Precision::Angular()))
|
||||
? gp::DY().Transformed (theTrsf)
|
||||
: aCylNorm.Crossed (aViewRayDir);
|
||||
|
||||
const Standard_Real anAngle = aCylNorm.Angle (aViewRayDir);
|
||||
aPoints[0] = aBottomCenterProject.XYZ() - aCylNormProject.XYZ() * theBottomRad * Abs (Cos (anAngle));
|
||||
aPoints[1] = aBottomCenterProject.XYZ() + aDirEndFaces.XYZ() * theBottomRad;
|
||||
aPoints[2] = aTopCenterProject.XYZ() + aDirEndFaces.XYZ() * theTopRad;
|
||||
aPoints[3] = aTopCenterProject.XYZ() + aCylNormProject.XYZ() * theTopRad * Abs (Cos (anAngle));
|
||||
aPoints[4] = aTopCenterProject.XYZ() - aDirEndFaces.XYZ() * theTopRad;
|
||||
aPoints[5] = aBottomCenterProject.XYZ() - aDirEndFaces.XYZ() * theBottomRad;
|
||||
const TColgp_Array1OfPnt aPointsArr (aPoints[0], 0, 5);
|
||||
|
||||
gp_Pnt aVerticesBuf[N];
|
||||
TColgp_Array1OfPnt aVertices (aVerticesBuf[0], 0, N - 1);
|
||||
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
|
||||
if (anIncFactor == 2)
|
||||
{
|
||||
const Standard_Integer anIndices[] = { 0, 2, 6, 4 };
|
||||
for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
|
||||
{
|
||||
aVertices.SetValue (anIdx, myVertices[anIndices[anIdx]]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
|
||||
{
|
||||
aVertices.SetValue (anIdx, myVertices[anIdx]);
|
||||
}
|
||||
}
|
||||
for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
|
||||
{
|
||||
if ((aCylNormProject.Dot (aCylNormProject) == 0.0
|
||||
&& aVertices.Value (anIdx).Distance (aPoints[0]) <= Max (theTopRad, theBottomRad))
|
||||
|| IsDotInside (aVertices.Value (anIdx), aPointsArr))
|
||||
{
|
||||
if (theInside != NULL)
|
||||
{
|
||||
*theInside = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
|
||||
{
|
||||
const gp_Pnt aPnt1Seg = aVertices[anIdx];
|
||||
const gp_Pnt aPnt2Seg = (anIdx == aVertices.Upper()) ? aVertices[aVertices.Lower()] : aVertices[anIdx + 1];
|
||||
if (isSegmentsIntersect (aPoints[1], aPoints[2], aPnt1Seg, aPnt2Seg)
|
||||
|| isSegmentsIntersect (aPoints[4], aPoints[5], aPnt1Seg, aPnt2Seg)
|
||||
|| isSegmentsIntersect (aPoints[4], aPoints[2], aPnt1Seg, aPnt2Seg)
|
||||
|| isSegmentsIntersect (aPoints[1], aPoints[5], aPnt1Seg, aPnt2Seg))
|
||||
{
|
||||
if (theInside != NULL)
|
||||
{
|
||||
*theInside = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isIntersectCylinderEndFace (theBottomRad, gp_Pnt (0, 0, 0), theTrsf, aVertices)
|
||||
|| isIntersectCylinderEndFace (theTopRad, gp_Pnt (0, 0, theHeight), theTrsf, aVertices))
|
||||
{
|
||||
if (theInside != NULL)
|
||||
{
|
||||
*theInside = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool isCylInsideRec = true;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
isCylInsideRec &= IsDotInside (aPoints[i], aVertices);
|
||||
}
|
||||
if (theInside != NULL)
|
||||
{
|
||||
*theInside &= isCylInsideRec;
|
||||
}
|
||||
return isCylInsideRec;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : DumpJson
|
||||
//purpose :
|
||||
|
@@ -740,6 +740,65 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsTriangle (const gp_Pnt& t
|
||||
return !theClipRange.IsClipped (thePickResult.Depth());
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const
|
||||
{
|
||||
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
|
||||
"Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
|
||||
Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
|
||||
const gp_Trsf aTrsfInv = theTrsf.Inverted();
|
||||
const gp_Pnt aLoc = myNearPickedPnt.Transformed (aTrsfInv);
|
||||
const gp_Dir aRayDir = myViewRayDir .Transformed (aTrsfInv);
|
||||
if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
thePickResult.SetDepth (aTimeEnter * myScale);
|
||||
if (theClipRange.IsClipped (thePickResult.Depth()))
|
||||
{
|
||||
thePickResult.SetDepth (aTimeLeave * myScale);
|
||||
}
|
||||
const gp_Pnt aPntOnCylinder (aLoc.XYZ() + aRayDir.XYZ() * thePickResult.Depth());
|
||||
if (Abs (aPntOnCylinder.Z()) < Precision::Confusion())
|
||||
{
|
||||
thePickResult.SetSurfaceNormal (-gp::DZ().Transformed (theTrsf));
|
||||
}
|
||||
else if (Abs (aPntOnCylinder.Z() - theHeight) < Precision::Confusion())
|
||||
{
|
||||
thePickResult.SetSurfaceNormal (gp::DZ().Transformed (theTrsf));
|
||||
}
|
||||
else
|
||||
{
|
||||
thePickResult.SetSurfaceNormal (gp_Vec (aPntOnCylinder.X(), aPntOnCylinder.Y(), 0.0).Transformed (theTrsf));
|
||||
}
|
||||
thePickResult.SetPickedPoint (aPntOnCylinder);
|
||||
return !theClipRange.IsClipped (thePickResult.Depth());
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
|
||||
"Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
|
||||
|
||||
return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf, theInside);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : GetMousePosition
|
||||
// purpose :
|
||||
|
@@ -144,6 +144,23 @@ public:
|
||||
const Standard_Real theRadius,
|
||||
Standard_Boolean* theInside) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
|
||||
|
||||
//! Measures distance between 3d projection of user-picked
|
||||
//! screen point and given point theCOG.
|
||||
//! It makes sense only for frustums built on a single point.
|
||||
|
@@ -418,6 +418,40 @@ Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsSphere (const gp_Pnt&
|
||||
return myActiveSelectingVolume->OverlapsSphere (theCenter, theRadius, theInside);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
SelectBasics_PickResult& thePickResult) const
|
||||
{
|
||||
if (myActiveSelectingVolume.IsNull())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return myActiveSelectingVolume->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, myViewClipRange, thePickResult);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
if (myActiveSelectingVolume.IsNull())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return myActiveSelectingVolume->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, theInside);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : DistToGeometryCenter
|
||||
// purpose : Measures distance between 3d projection of user-picked
|
||||
|
@@ -162,6 +162,22 @@ public:
|
||||
const Standard_Real theRadius,
|
||||
Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
|
||||
|
||||
//! Measures distance between 3d projection of user-picked
|
||||
//! screen point and given point theCOG
|
||||
Standard_EXPORT virtual Standard_Real DistToGeometryCenter (const gp_Pnt& theCOG) const Standard_OVERRIDE;
|
||||
|
@@ -67,6 +67,56 @@ namespace
|
||||
NCollection_DataMap<Handle(Select3D_SensitiveEntity), Quantity_Color> myMapEntityColors;
|
||||
};
|
||||
|
||||
//! Help class for filling pixel with random color.
|
||||
class GeneratedEntityTypeColorFiller : public SelectMgr_SelectionImageFiller
|
||||
{
|
||||
public:
|
||||
GeneratedEntityTypeColorFiller (Image_PixMap& thePixMap,
|
||||
SelectMgr_ViewerSelector* theSelector)
|
||||
: SelectMgr_SelectionImageFiller (thePixMap, theSelector)
|
||||
{
|
||||
// generate per-entity colors in the order as they have been activated
|
||||
for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelector->SelectableObjects()); anObjIter.More(); anObjIter.Next())
|
||||
{
|
||||
const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
|
||||
for (SelectMgr_SequenceOfSelection::Iterator aSelIter (anObj->Selections()); aSelIter.More(); aSelIter.Next())
|
||||
{
|
||||
const Handle(SelectMgr_Selection)& aSel = aSelIter.Value();
|
||||
for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
|
||||
{
|
||||
const Handle(SelectMgr_SensitiveEntity)& aSens = aSelEntIter.Value();
|
||||
if (!myMapEntityColors.IsBound (aSens->BaseSensitive()->DynamicType()))
|
||||
{
|
||||
Quantity_Color aColor;
|
||||
randomPastelColor (aColor);
|
||||
myMapEntityColors.Bind (aSens->BaseSensitive()->DynamicType(), aColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Fill (const Standard_Integer theCol,
|
||||
const Standard_Integer theRow,
|
||||
const Standard_Integer thePicked) Standard_OVERRIDE
|
||||
{
|
||||
if (thePicked < 1
|
||||
|| thePicked > myMainSel->NbPicked())
|
||||
{
|
||||
myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
|
||||
return;
|
||||
}
|
||||
|
||||
const Handle(Select3D_SensitiveEntity)& aPickedEntity = myMainSel->PickedEntity (thePicked);
|
||||
Quantity_Color aColor (Quantity_NOC_BLACK);
|
||||
myMapEntityColors.Find (aPickedEntity->DynamicType(), aColor);
|
||||
myImage->SetPixelColor (theCol, theRow, aColor);
|
||||
}
|
||||
|
||||
protected:
|
||||
NCollection_DataMap<Handle(Standard_Type), Quantity_Color> myMapEntityColors;
|
||||
};
|
||||
|
||||
//! Help class for filling pixel with normalized depth of ray.
|
||||
class NormalizedDepthFiller : public SelectMgr_SelectionImageFiller
|
||||
{
|
||||
@@ -384,6 +434,10 @@ Handle(SelectMgr_SelectionImageFiller) SelectMgr_SelectionImageFiller::CreateFil
|
||||
{
|
||||
return new GeneratedEntityColorFiller (thePixMap, theSelector);
|
||||
}
|
||||
case StdSelect_TypeOfSelectionImage_ColoredEntityType:
|
||||
{
|
||||
return new GeneratedEntityTypeColorFiller (thePixMap, theSelector);
|
||||
}
|
||||
case StdSelect_TypeOfSelectionImage_ColoredOwner:
|
||||
{
|
||||
return new GeneratedOwnerColorFiller (thePixMap, theSelector);
|
||||
|
@@ -329,6 +329,36 @@ Standard_Boolean SelectMgr_TriangularFrustum::OverlapsSphere (const gp_Pnt& theC
|
||||
return hasSphereOverlap (theCenter, theRadius);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const
|
||||
{
|
||||
(void)theClipRange;
|
||||
(void)thePickResult;
|
||||
return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
(void) theInside;
|
||||
return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Clear
|
||||
// purpose : Nullifies the handle for corresponding builder instance to prevent
|
||||
|
@@ -117,6 +117,23 @@ public: //! @name SAT Tests for different objects
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
|
||||
|
||||
public:
|
||||
|
||||
//! Nullifies the handle to corresponding builder instance to prevent memory leaks
|
||||
|
@@ -498,6 +498,123 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsSphere (const gp_Pnt& t
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const
|
||||
{
|
||||
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Polyline,
|
||||
"Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
|
||||
for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
if (anIter.Value()->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, theClipRange, thePickResult))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : OverlapsCylinder
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
const gp_Dir aCylNorm (gp::DZ().Transformed (theTrsf));
|
||||
const gp_Pnt aBottomCenter (gp::Origin().Transformed (theTrsf));
|
||||
const gp_Pnt aTopCenter = aBottomCenter.XYZ() + aCylNorm.XYZ() * theHeight;
|
||||
|
||||
const gp_Vec aVecPlane1 (myFrustums.First()->myVertices[0], myFrustums.First()->myVertices[1]);
|
||||
const gp_Vec aVecPlane2 (myFrustums.First()->myVertices[0], myFrustums.First()->myVertices[2]);
|
||||
|
||||
const gp_Dir aDirNorm (aVecPlane1.Crossed (aVecPlane2));
|
||||
const Standard_Real anAngle = aCylNorm.Angle (aDirNorm);
|
||||
const Standard_Real aCosAngle = Cos (anAngle);
|
||||
const gp_Pln aPln (myFrustums.First()->myVertices[0], aDirNorm);
|
||||
Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
|
||||
aPln.Coefficients (aCoefA, aCoefB, aCoefC, aCoefD);
|
||||
|
||||
const Standard_Real aTBottom = -(aBottomCenter.XYZ().Dot (aDirNorm.XYZ()) + aCoefD) / aDirNorm.Dot (aDirNorm);
|
||||
const gp_Pnt aBottomCenterProject (aCoefA * aTBottom + aBottomCenter.X(),
|
||||
aCoefB * aTBottom + aBottomCenter.Y(),
|
||||
aCoefC * aTBottom + aBottomCenter.Z());
|
||||
|
||||
const Standard_Real aTTop = -(aTopCenter.XYZ().Dot (aDirNorm.XYZ()) + aCoefD) / aDirNorm.Dot (aDirNorm);
|
||||
const gp_Pnt aTopCenterProject (aCoefA * aTTop + aTopCenter.X(),
|
||||
aCoefB * aTTop + aTopCenter.Y(),
|
||||
aCoefC * aTTop + aTopCenter.Z());
|
||||
|
||||
gp_XYZ aCylNormProject;
|
||||
const gp_XYZ aTopBottomVec = aTopCenterProject.XYZ() - aBottomCenterProject.XYZ();
|
||||
const Standard_Real aTopBottomDist = aTopBottomVec.Modulus();
|
||||
if (aTopBottomDist > 0.0)
|
||||
{
|
||||
aCylNormProject = aTopBottomVec / aTopBottomDist;
|
||||
}
|
||||
|
||||
gp_Pnt aPoints[6];
|
||||
aPoints[0] = aBottomCenterProject.XYZ() - aCylNormProject * theBottomRad * Abs (aCosAngle);
|
||||
aPoints[1] = aTopCenterProject.XYZ() + aCylNormProject * theTopRad * Abs (aCosAngle);
|
||||
const gp_Dir aDirEndFaces = (aCylNorm.IsParallel (aDirNorm, Precision::Angular()))
|
||||
? gp::DY().Transformed (theTrsf)
|
||||
: aCylNorm.Crossed (aDirNorm);
|
||||
|
||||
aPoints[2] = aTopCenterProject.XYZ() + aDirEndFaces.XYZ() * theTopRad;
|
||||
aPoints[3] = aTopCenterProject.XYZ() - aDirEndFaces.XYZ() * theTopRad;
|
||||
aPoints[4] = aBottomCenterProject.XYZ() + aDirEndFaces.XYZ() * theBottomRad;
|
||||
aPoints[5] = aBottomCenterProject.XYZ() - aDirEndFaces.XYZ() * theBottomRad;
|
||||
|
||||
gp_Pnt aVerticesBuf[3];
|
||||
TColgp_Array1OfPnt aVertices (aVerticesBuf[0], 0, 2);
|
||||
|
||||
bool isCylInsideTriangSet = true;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
bool isInside = false;
|
||||
for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
|
||||
for (int anIdx = 0; anIdx < 3; anIdx++)
|
||||
{
|
||||
aVertices[anIdx] = anIter.Value()->myVertices[anIdx];
|
||||
}
|
||||
if (anIter.Value()->IsDotInside (aPoints[i], aVertices))
|
||||
{
|
||||
isInside = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
isCylInsideTriangSet &= isInside;
|
||||
}
|
||||
if (theInside != NULL)
|
||||
{
|
||||
*theInside &= isCylInsideTriangSet;
|
||||
}
|
||||
if (isCylInsideTriangSet)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
if (anIter.Value()->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, theInside))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : GetPlanes
|
||||
// purpose :
|
||||
|
@@ -118,6 +118,23 @@ public:
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
const SelectMgr_ViewClipRange& theClipRange,
|
||||
SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
|
||||
|
||||
//! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
|
||||
//! and theTopRad, height theHeight and transformation to apply theTrsf.
|
||||
Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
|
||||
const Standard_Real theTopRad,
|
||||
const Standard_Real theHeight,
|
||||
const gp_Trsf& theTrsf,
|
||||
Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
|
||||
|
||||
//! Stores plane equation coefficients (in the following form:
|
||||
//! Ax + By + Cz + D = 0) to the given vector
|
||||
Standard_EXPORT virtual void GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const Standard_OVERRIDE;
|
||||
|
Reference in New Issue
Block a user