mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-06-17 05:37:45 +08:00
SelectMgr_RectangularFrustum::OverlapsCylinder() - added missing 3D point transformation. StdSelect_BRepSelectionTool::ComputeSensitive() - fixed cylinder height computation on TopoDS_Shape with scale transformation. SelectMgr_AxisIntersector::OverlapsCylinder(),::OverlapsSphere() - added missing computations of surface normal.
701 lines
28 KiB
C++
701 lines
28 KiB
C++
// Copyright (c) 2021 OPEN CASCADE SAS
|
|
//
|
|
// This file is part of Open CASCADE Technology software library.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License version 2.1 as published
|
|
// by the Free Software Foundation, with special exception defined in the file
|
|
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
|
// distribution for complete text of the license and disclaimer of any warranty.
|
|
//
|
|
// Alternatively, this file may be used under the terms of Open CASCADE
|
|
// commercial license or contractual agreement.
|
|
|
|
#include <SelectMgr_AxisIntersector.hxx>
|
|
|
|
#include <Bnd_Range.hxx>
|
|
#include <BVH_Tools.hxx>
|
|
#include <Precision.hxx>
|
|
#include <SelectBasics_PickResult.hxx>
|
|
#include <SelectMgr_ViewClipRange.hxx>
|
|
|
|
// =======================================================================
|
|
// function : Constructor
|
|
// purpose :
|
|
// =======================================================================
|
|
SelectMgr_AxisIntersector::SelectMgr_AxisIntersector()
|
|
{
|
|
//
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : ~SelectMgr_AxisIntersector
|
|
// purpose :
|
|
// =======================================================================
|
|
SelectMgr_AxisIntersector::~SelectMgr_AxisIntersector()
|
|
{
|
|
//
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : Init
|
|
// purpose :
|
|
// =======================================================================
|
|
void SelectMgr_AxisIntersector::Init (const gp_Ax1& theAxis)
|
|
{
|
|
mySelectionType = SelectMgr_SelectionType_Point;
|
|
myAxis = theAxis;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : Build
|
|
// purpose :
|
|
// =======================================================================
|
|
void SelectMgr_AxisIntersector::Build()
|
|
{
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : SetCamera
|
|
// purpose :
|
|
//=======================================================================
|
|
void SelectMgr_AxisIntersector::SetCamera (const Handle(Graphic3d_Camera)&)
|
|
{
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : ScaleAndTransform
|
|
// purpose :
|
|
// =======================================================================
|
|
Handle(SelectMgr_BaseIntersector) SelectMgr_AxisIntersector::ScaleAndTransform (const Standard_Integer theScaleFactor,
|
|
const gp_GTrsf& theTrsf,
|
|
const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::ScaleAndTransform() should be called after selection axis initialization");
|
|
|
|
(void )theScaleFactor;
|
|
(void )theBuilder;
|
|
if (theTrsf.Form() == gp_Identity)
|
|
{
|
|
return new SelectMgr_AxisIntersector();
|
|
}
|
|
|
|
gp_Pnt aTransformedLoc = myAxis.Location();
|
|
theTrsf.Transforms (aTransformedLoc.ChangeCoord());
|
|
gp_XYZ aTransformedDir = myAxis.Direction().XYZ();
|
|
gp_GTrsf aTrsf = theTrsf;
|
|
aTrsf.SetTranslationPart (gp_XYZ(0., 0., 0.));
|
|
aTrsf.Transforms (aTransformedDir);
|
|
|
|
Handle(SelectMgr_AxisIntersector) aRes = new SelectMgr_AxisIntersector();
|
|
aRes->myAxis = gp_Ax1(aTransformedLoc, gp_Dir(aTransformedDir));
|
|
aRes->mySelectionType = mySelectionType;
|
|
return aRes;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : hasIntersection
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::hasIntersection (const SelectMgr_Vec3& theBoxMin,
|
|
const SelectMgr_Vec3& theBoxMax,
|
|
Standard_Real& theTimeEnter,
|
|
Standard_Real& theTimeLeave) const
|
|
{
|
|
const gp_Pnt& anAxisLoc = myAxis.Location();
|
|
const gp_Dir& anAxisDir = myAxis.Direction();
|
|
BVH_Ray<Standard_Real, 3> aRay(SelectMgr_Vec3(anAxisLoc.X(), anAxisLoc.Y(), anAxisLoc.Z()),
|
|
SelectMgr_Vec3(anAxisDir.X(), anAxisDir.Y(), anAxisDir.Z()));
|
|
if (!BVH_Tools<Standard_Real, 3>::RayBoxIntersection (aRay, theBoxMin, theBoxMax, theTimeEnter, theTimeLeave))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : hasIntersection
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::hasIntersection (const gp_Pnt& thePnt,
|
|
Standard_Real& theDepth) const
|
|
{
|
|
const gp_Pnt& anAxisLoc = myAxis.Location();
|
|
const gp_Dir& anAxisDir = myAxis.Direction();
|
|
|
|
// Check that vectors are co-directed (thePnt lies on this axis)
|
|
gp_Dir aDirToPnt(thePnt.XYZ() - anAxisLoc.XYZ());
|
|
if (!anAxisDir.IsEqual (aDirToPnt, Precision::Angular()))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
theDepth = anAxisLoc.Distance (thePnt);
|
|
return Standard_True;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : raySegmentDistance
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::raySegmentDistance (const gp_Pnt& theSegPnt1,
|
|
const gp_Pnt& theSegPnt2,
|
|
SelectBasics_PickResult& thePickResult) const
|
|
{
|
|
const gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ();
|
|
const gp_XYZ aV = myAxis.Direction().XYZ();
|
|
const gp_XYZ aW = theSegPnt1.XYZ() - myAxis.Location().XYZ();
|
|
|
|
const gp_XYZ anUVNormVec = aV.Crossed (anU);
|
|
const Standard_Real anUVNormVecMod = anUVNormVec.Modulus();
|
|
if (anUVNormVecMod <= Precision::Confusion())
|
|
{
|
|
// Lines have no intersection
|
|
thePickResult.Invalidate();
|
|
return false;
|
|
}
|
|
|
|
const gp_XYZ anUWNormVec = aW.Crossed (anU);
|
|
const Standard_Real anUWNormVecMod = anUWNormVec.Modulus();
|
|
if (anUWNormVecMod <= Precision::Confusion())
|
|
{
|
|
// Lines have no intersection
|
|
thePickResult.Invalidate();
|
|
return false;
|
|
}
|
|
|
|
const Standard_Real aParam = anUWNormVec.Dot (anUVNormVec) / anUVNormVec.SquareModulus();
|
|
if (aParam < 0.0)
|
|
{
|
|
// Intersection is out of axis start point
|
|
thePickResult.Invalidate();
|
|
return false;
|
|
}
|
|
|
|
const gp_XYZ anIntersectPnt = myAxis.Location().XYZ() + aV * aParam;
|
|
if ((anIntersectPnt - theSegPnt1.XYZ()).Modulus() +
|
|
(anIntersectPnt - theSegPnt2.XYZ()).Modulus() >
|
|
anU.Modulus() + Precision::Confusion())
|
|
{
|
|
// Intersection point doesn't lie on the segment
|
|
thePickResult.Invalidate();
|
|
return false;
|
|
}
|
|
|
|
thePickResult.SetDepth (myAxis.Location().Distance (anIntersectPnt));
|
|
thePickResult.SetPickedPoint (anIntersectPnt);
|
|
return true;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : rayPlaneIntersection
|
|
// purpose :
|
|
// =======================================================================
|
|
bool SelectMgr_AxisIntersector::rayPlaneIntersection (const gp_Vec& thePlane,
|
|
const gp_Pnt& thePntOnPlane,
|
|
SelectBasics_PickResult& thePickResult) const
|
|
{
|
|
gp_XYZ anU = myAxis.Direction().XYZ();
|
|
gp_XYZ aW = myAxis.Location().XYZ() - thePntOnPlane.XYZ();
|
|
Standard_Real aD = thePlane.Dot (anU);
|
|
Standard_Real aN = -thePlane.Dot (aW);
|
|
|
|
if (Abs (aD) < Precision::Confusion())
|
|
{
|
|
thePickResult.Invalidate();
|
|
return false;
|
|
}
|
|
|
|
Standard_Real aParam = aN / aD;
|
|
if (aParam < 0.0)
|
|
{
|
|
thePickResult.Invalidate();
|
|
return false;
|
|
}
|
|
|
|
gp_Pnt aClosestPnt = myAxis.Location().XYZ() + anU * aParam;
|
|
thePickResult.SetDepth (myAxis.Location().Distance (aClosestPnt));
|
|
thePickResult.SetPickedPoint (aClosestPnt);
|
|
return true;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsBox
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsBox (const SelectMgr_Vec3& theBoxMin,
|
|
const SelectMgr_Vec3& theBoxMax,
|
|
Standard_Boolean* theInside) const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
|
|
|
|
(void )theInside;
|
|
Standard_Real aTimeEnter, aTimeLeave;
|
|
if (!hasIntersection (theBoxMin, theBoxMax, aTimeEnter, aTimeLeave))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
if (theInside != NULL)
|
|
{
|
|
*theInside &= (aTimeEnter >= 0.0);
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsBox
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsBox (const SelectMgr_Vec3& theBoxMin,
|
|
const SelectMgr_Vec3& theBoxMax,
|
|
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, aTimeLeave;
|
|
if (!hasIntersection (theBoxMin, theBoxMax, aTimeEnter, aTimeLeave))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
Standard_Real aDepth = 0.0;
|
|
Bnd_Range aRange(Max (aTimeEnter, 0.0), aTimeLeave);
|
|
aRange.GetMin (aDepth);
|
|
|
|
if (!theClipRange.GetNearestDepth (aRange, aDepth))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
thePickResult.SetDepth (aDepth);
|
|
|
|
return Standard_True;
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsPoint
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsPoint (const gp_Pnt& thePnt,
|
|
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 aDepth = 0.0;
|
|
if (!hasIntersection (thePnt, aDepth))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
thePickResult.SetDepth (aDepth);
|
|
thePickResult.SetPickedPoint (thePnt);
|
|
|
|
return !theClipRange.IsClipped (thePickResult.Depth());
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsPoint
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsPoint (const gp_Pnt& thePnt) const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
|
|
|
|
Standard_Real aDepth = 0.0;
|
|
return hasIntersection (thePnt, aDepth);
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsSegment
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsSegment (const gp_Pnt& thePnt1,
|
|
const gp_Pnt& thePnt2,
|
|
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");
|
|
|
|
if (!raySegmentDistance (thePnt1, thePnt2, thePickResult))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
return !theClipRange.IsClipped (thePickResult.Depth());
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsPolygon
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPnts,
|
|
Select3D_TypeOfSensitivity theSensType,
|
|
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");
|
|
|
|
if (theSensType == Select3D_TOS_BOUNDARY)
|
|
{
|
|
Standard_Integer aMatchingSegmentsNb = -1;
|
|
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 = theArrayOfPnts.Value (aPntIter == anUpper ? aLower : (aPntIter + 1));
|
|
if (raySegmentDistance (aStartPnt, aEndPnt, aPickResult))
|
|
{
|
|
aMatchingSegmentsNb++;
|
|
thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
|
|
}
|
|
}
|
|
|
|
if (aMatchingSegmentsNb == -1)
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
else if (theSensType == Select3D_TOS_INTERIOR)
|
|
{
|
|
Standard_Integer aStartIdx = theArrayOfPnts.Lower();
|
|
const gp_XYZ& aPnt1 = theArrayOfPnts.Value (aStartIdx).XYZ();
|
|
const gp_XYZ& aPnt2 = theArrayOfPnts.Value (aStartIdx + 1).XYZ();
|
|
const gp_XYZ& aPnt3 = theArrayOfPnts.Value (aStartIdx + 2).XYZ();
|
|
const gp_XYZ aVec1 = aPnt1 - aPnt2;
|
|
const gp_XYZ aVec2 = aPnt3 - aPnt2;
|
|
gp_Vec aPolyNorm = aVec2.Crossed (aVec1);
|
|
if (aPolyNorm.Magnitude() <= Precision::Confusion())
|
|
{
|
|
// treat degenerated polygon as point
|
|
return OverlapsPoint (theArrayOfPnts.First(), theClipRange, thePickResult);
|
|
}
|
|
else if (!rayPlaneIntersection (aPolyNorm, theArrayOfPnts.First(), thePickResult))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
}
|
|
|
|
return !theClipRange.IsClipped (thePickResult.Depth());
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : OverlapsTriangle
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsTriangle (const gp_Pnt& thePnt1,
|
|
const gp_Pnt& thePnt2,
|
|
const gp_Pnt& thePnt3,
|
|
Select3D_TypeOfSensitivity theSensType,
|
|
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");
|
|
|
|
if (theSensType == Select3D_TOS_BOUNDARY)
|
|
{
|
|
const gp_Pnt aPntsArrayBuf[4] = { thePnt1, thePnt2, thePnt3, thePnt1 };
|
|
const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 4);
|
|
return OverlapsPolygon (aPntsArray, Select3D_TOS_BOUNDARY, theClipRange, thePickResult);
|
|
}
|
|
else if (theSensType == Select3D_TOS_INTERIOR)
|
|
{
|
|
gp_Vec aTriangleNormal (gp_XYZ (RealLast(), RealLast(), RealLast()));
|
|
const gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(),
|
|
thePnt3.XYZ() - thePnt2.XYZ(),
|
|
thePnt1.XYZ() - thePnt3.XYZ() };
|
|
aTriangleNormal = aTrEdges[2].Crossed (aTrEdges[0]);
|
|
if (aTriangleNormal.SquareMagnitude() < gp::Resolution())
|
|
{
|
|
// consider degenerated triangle as point or segment
|
|
return aTrEdges[0].SquareModulus() > gp::Resolution()
|
|
? OverlapsSegment (thePnt1, thePnt2, theClipRange, thePickResult)
|
|
: (aTrEdges[1].SquareModulus() > gp::Resolution()
|
|
? OverlapsSegment (thePnt2, thePnt3, theClipRange, thePickResult)
|
|
: OverlapsPoint (thePnt1, theClipRange, thePickResult));
|
|
}
|
|
|
|
const gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
|
|
const Standard_Real anAlpha = aTriangleNormal.XYZ().Dot (myAxis.Direction().XYZ());
|
|
if (Abs (anAlpha) < gp::Resolution())
|
|
{
|
|
// handle the case when triangle normal and selecting frustum direction are orthogonal
|
|
SelectBasics_PickResult aPickResult;
|
|
thePickResult.Invalidate();
|
|
for (Standard_Integer anEdgeIter = 0; anEdgeIter < 3; ++anEdgeIter)
|
|
{
|
|
const gp_Pnt& aStartPnt = aPnts[anEdgeIter];
|
|
const gp_Pnt& anEndPnt = aPnts[anEdgeIter < 2 ? anEdgeIter + 1 : 0];
|
|
if (raySegmentDistance (aStartPnt, anEndPnt, aPickResult))
|
|
{
|
|
thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
|
|
}
|
|
}
|
|
thePickResult.SetSurfaceNormal (aTriangleNormal);
|
|
return thePickResult.IsValid()
|
|
&& !theClipRange.IsClipped (thePickResult.Depth());
|
|
}
|
|
|
|
// check if intersection point belongs to triangle's interior part
|
|
const gp_XYZ anEdge = (thePnt1.XYZ() - myAxis.Location().XYZ()) * (1.0 / anAlpha);
|
|
|
|
const Standard_Real aTime = aTriangleNormal.Dot (anEdge);
|
|
const gp_XYZ aVec = myAxis.Direction().XYZ().Crossed (anEdge);
|
|
const Standard_Real anU = aVec.Dot (aTrEdges[2]);
|
|
const 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 = myAxis.Location().XYZ() + myAxis.Direction().XYZ() * aTime;
|
|
if (isInterior)
|
|
{
|
|
thePickResult.SetDepth (myAxis.Location().Distance (aPtOnPlane));
|
|
thePickResult.SetPickedPoint (aPtOnPlane);
|
|
thePickResult.SetSurfaceNormal (aTriangleNormal);
|
|
return !theClipRange.IsClipped (thePickResult.Depth());
|
|
}
|
|
|
|
Standard_Real aMinDist = RealLast();
|
|
Standard_Integer aNearestEdgeIdx1 = -1;
|
|
for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
|
|
{
|
|
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 (aDist < aMinDist)
|
|
{
|
|
aMinDist = aDist;
|
|
aNearestEdgeIdx1 = anEdgeIdx;
|
|
}
|
|
}
|
|
Standard_Integer aNearestEdgeIdx2 = (aNearestEdgeIdx1 + 1) % 3;
|
|
const gp_Vec aVec12 (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2]);
|
|
if (aVec12.SquareMagnitude() > gp::Resolution()
|
|
&& myAxis.Direction().IsParallel (aVec12, Precision::Angular()))
|
|
{
|
|
aNearestEdgeIdx2 = aNearestEdgeIdx1 == 0 ? 2 : aNearestEdgeIdx1 - 1;
|
|
}
|
|
if (raySegmentDistance (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2], thePickResult))
|
|
{
|
|
thePickResult.SetSurfaceNormal (aTriangleNormal);
|
|
}
|
|
}
|
|
|
|
return thePickResult.IsValid()
|
|
&& !theClipRange.IsClipped (thePickResult.Depth());
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : OverlapsSphere
|
|
// purpose :
|
|
//=======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCenter,
|
|
const Standard_Real theRadius,
|
|
Standard_Boolean* theInside) const
|
|
{
|
|
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
|
|
(void )theInside;
|
|
Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
|
|
if (!RaySphereIntersection (theCenter, theRadius, myAxis.Location(), myAxis.Direction(), aTimeEnter, aTimeLeave))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
if (theInside != NULL)
|
|
{
|
|
*theInside &= (aTimeEnter >= 0.0);
|
|
}
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : OverlapsSphere
|
|
// purpose :
|
|
//=======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCenter,
|
|
const Standard_Real theRadius,
|
|
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;
|
|
if (!RaySphereIntersection (theCenter, theRadius, myAxis.Location(), myAxis.Direction(), aTimeEnter, aTimeLeave))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
Standard_Real aDepth = 0.0;
|
|
Bnd_Range aRange (Max (aTimeEnter, 0.0), aTimeLeave);
|
|
aRange.GetMin (aDepth);
|
|
if (!theClipRange.GetNearestDepth (aRange, aDepth))
|
|
{
|
|
return Standard_False;
|
|
}
|
|
|
|
const gp_Pnt aPntOnSphere (myAxis.Location().XYZ() + myAxis.Direction().XYZ() * aDepth);
|
|
const gp_Vec aNormal (aPntOnSphere.XYZ() - theCenter.XYZ());
|
|
thePickResult.SetDepth (aDepth);
|
|
thePickResult.SetPickedPoint (aPntOnSphere);
|
|
thePickResult.SetSurfaceNormal (aNormal);
|
|
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;
|
|
}
|
|
|
|
const gp_Pnt aPntOnCylinder = aLoc.XYZ() + aRayDir.XYZ() * aDepth;
|
|
thePickResult.SetDepth (aDepth);
|
|
thePickResult.SetPickedPoint (aPntOnCylinder.Transformed (theTrsf));
|
|
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));
|
|
}
|
|
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 :
|
|
//=======================================================================
|
|
const gp_Pnt& SelectMgr_AxisIntersector::GetNearPnt() const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::GetNearPnt() should be called after selection axis initialization");
|
|
|
|
return myAxis.Location();
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : GetFarPnt
|
|
// purpose :
|
|
//=======================================================================
|
|
const gp_Pnt& SelectMgr_AxisIntersector::GetFarPnt() const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::GetFarPnt() should be called after selection axis initialization");
|
|
|
|
static gp_Pnt anInfPnt(RealLast(), RealLast(), RealLast());
|
|
return anInfPnt;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : GetViewRayDirection
|
|
// purpose :
|
|
//=======================================================================
|
|
const gp_Dir& SelectMgr_AxisIntersector::GetViewRayDirection() const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::GetViewRayDirection() should be called after selection axis initialization");
|
|
|
|
return myAxis.Direction();
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : DistToGeometryCenter
|
|
// purpose :
|
|
// =======================================================================
|
|
Standard_Real SelectMgr_AxisIntersector::DistToGeometryCenter (const gp_Pnt& theCOG) const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::DistToGeometryCenter() should be called after selection axis initialization");
|
|
|
|
return theCOG.Distance (myAxis.Location());
|
|
}
|
|
|
|
// =======================================================================
|
|
// function : DetectedPoint
|
|
// purpose :
|
|
// =======================================================================
|
|
gp_Pnt SelectMgr_AxisIntersector::DetectedPoint (const Standard_Real theDepth) const
|
|
{
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::DetectedPoint() should be called after selection axis initialization");
|
|
|
|
return myAxis.Location().XYZ() + myAxis.Direction().XYZ() * theDepth;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : DumpJson
|
|
//purpose :
|
|
//=======================================================================
|
|
void SelectMgr_AxisIntersector::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
|
|
{
|
|
OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_AxisIntersector)
|
|
OCCT_DUMP_BASE_CLASS (theOStream, theDepth, SelectMgr_BaseIntersector)
|
|
|
|
OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myAxis)
|
|
}
|