1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-24 13:50:49 +03:00

0032547: Visualization, Select3D_SensitiveCylinder - implement picking of a hollow cylinder

Select3D_SensitiveCircle now inherits directly from Select3D_SensitiveEntity.
The sensitive circle sector is created using the Select3D_SensitivePoly class directly.

Added appropriate methods for selecting sensitive circles.
Added parameter myIsHollow to Select3D_SensitiveCylinder class.
It allows you to search for intersections with cylinders without covers.

The Draw vcircle command has been extended with UStart and UEnd parameters
to create a sector of a circle.

Added tests: vselect/cone_cylinder/circle_sector
             vselect/cone_cylinder/circle_wire
             vselect/cone_cylinder/filled_circle
             vselect/cone_cylinder/transformed
             vselect/cone_cylinder/hollow_cone_cyl
This commit is contained in:
mzernova
2022-08-18 17:12:03 +03:00
committed by smoskvin
parent da76ea432b
commit 7aaed2ce3b
38 changed files with 2117 additions and 784 deletions

View File

@@ -748,6 +748,7 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_
const Standard_Real theTopRad,
const Standard_Real theHeight,
const gp_Trsf& theTrsf,
const Standard_Boolean theIsHollow,
const SelectMgr_ViewClipRange& theClipRange,
SelectBasics_PickResult& thePickResult) const
{
@@ -757,7 +758,7 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_
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, aTimes[0], aTimes[1]))
if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, theIsHollow, aTimes[0], aTimes[1]))
{
return Standard_False;
}
@@ -787,6 +788,165 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_
return !theClipRange.IsClipped (thePickResult.Depth());
}
//=======================================================================
// function : OverlapsCircle
// purpose :
//=======================================================================
Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCircle (const Standard_Real theRadius,
const gp_Trsf& theTrsf,
const Standard_Boolean theIsFilled,
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 aTime = 0.0;
const gp_Trsf aTrsfInv = theTrsf.Inverted();
const gp_Pnt aLoc = myNearPickedPnt.Transformed (aTrsfInv);
const gp_Dir aRayDir = myViewRayDir.Transformed (aTrsfInv);
if (!theIsFilled)
{
if (!hasCircleOverlap (theRadius, theTrsf, theIsFilled, NULL))
{
return Standard_False;
}
if (aRayDir.Z() != 0)
{
aTime = (0 - aLoc.Z()) / aRayDir.Z();
}
}
else if (!RayCircleIntersection (theRadius, aLoc, aRayDir, theIsFilled, aTime))
{
return Standard_False;
}
thePickResult.SetDepth (aTime * myScale);
if (theClipRange.IsClipped (thePickResult.Depth()))
{
thePickResult.SetDepth (aTime * myScale);
}
const gp_Pnt aPntOnCircle = aLoc.XYZ() + aRayDir.XYZ() * aTime;
if (Abs (aPntOnCircle.Z()) < Precision::Confusion())
{
thePickResult.SetSurfaceNormal (-gp::DZ().Transformed (theTrsf));
}
else
{
thePickResult.SetSurfaceNormal (gp_Vec (aPntOnCircle.X(), aPntOnCircle.Y(), 0.0).Transformed (theTrsf));
}
thePickResult.SetPickedPoint (aPntOnCircle.Transformed (theTrsf));
return !theClipRange.IsClipped (thePickResult.Depth());
}
//=======================================================================
// function : isIntersectCircle
// purpose :
//=======================================================================
Standard_Boolean SelectMgr_RectangularFrustum::isIntersectCircle (const Standard_Real theRadius,
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[4 == 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 - theRadius * theRadius;
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 : isSegmentsIntersect
// purpose :
//=======================================================================
Standard_Boolean SelectMgr_RectangularFrustum::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 : OverlapsCylinder
// purpose :
@@ -795,12 +955,28 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_
const Standard_Real theTopRad,
const Standard_Real theHeight,
const gp_Trsf& theTrsf,
const Standard_Boolean theIsHollow,
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);
return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf, theIsHollow, theInside);
}
//=======================================================================
// function : OverlapsCircle
// purpose :
//=======================================================================
Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCircle (const Standard_Real theRadius,
const gp_Trsf& theTrsf,
const Standard_Boolean theIsFilled,
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 hasCircleOverlap (theRadius, theTrsf, theIsFilled, theInside);
}
// =======================================================================