mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-03 17:56:21 +03:00
The new transform persistence mode, with flag `Graphic3d_TMF_OrthoPers`, can be combined (bitwise OR operation) with the other persistence modes (2D, Trihedron or Zoom/Rotate Persistence) to make objects be rendered with orthographic projection when it is on a view with perspective projection. If the view already uses orthographic projection, there will be no difference. This feature was implemented to fix ViewCube being distorted when view with perspective projection changes size.
790 lines
32 KiB
C++
790 lines
32 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 <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 : CopyWithBuilder
|
|
// purpose : Returns a copy of the frustum using the given frustum builder configuration.
|
|
// Returned frustum should be re-constructed before being used.
|
|
//=======================================================================
|
|
Handle(SelectMgr_BaseIntersector) SelectMgr_AxisIntersector::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
|
|
{
|
|
(void )theBuilder;
|
|
Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::CopyWithBuilder() should be called after selection axis initialization");
|
|
|
|
Handle(SelectMgr_AxisIntersector) aRes = new SelectMgr_AxisIntersector();
|
|
aRes->myAxis = myAxis;
|
|
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::OverlapsBox() 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::OverlapsBox() 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::OverlapsPoint() 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::OverlapsPoint() 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::OverlapsSegment() 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::OverlapsPolygon() 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::OverlapsTriangle() 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::OverlapsSphere() 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::OverlapsSphere() 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 Standard_Boolean theIsHollow,
|
|
const SelectMgr_ViewClipRange& theClipRange,
|
|
SelectBasics_PickResult& thePickResult) const
|
|
{
|
|
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::OverlapsCylinder() 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,
|
|
theIsHollow, aTimeEnter, aTimeLeave))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Standard_Real aDepth = 0.0;
|
|
Bnd_Range aRange (Max (aTimeEnter, 0.0), Max (aTimeEnter, 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,
|
|
const Standard_Boolean theIsHollow,
|
|
Standard_Boolean* theInside) const
|
|
{
|
|
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::OverlapsCylinder() 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,
|
|
theIsHollow, aTimeEnter, aTimeLeave))
|
|
{
|
|
return false;
|
|
}
|
|
if (theInside != NULL)
|
|
{
|
|
*theInside &= (aTimeEnter >= 0.0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : OverlapsCircle
|
|
// purpose :
|
|
//=======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::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,
|
|
"Error! SelectMgr_AxisIntersector::OverlapsCircle() should be called after selection axis initialization");
|
|
Standard_Real aTime = 0.0;
|
|
gp_Trsf aTrsfInv = theTrsf.Inverted();
|
|
gp_Pnt aLoc = myAxis.Location().Transformed (aTrsfInv);
|
|
gp_Dir aRayDir = myAxis.Direction().Transformed (aTrsfInv);
|
|
if (!RayCircleIntersection (theRadius, aLoc, aRayDir, theIsFilled, aTime))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Standard_Real aDepth = Max (aTime, 0.0);
|
|
if (theClipRange.IsClipped (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
|
|
{
|
|
thePickResult.SetSurfaceNormal (gp_Vec (aPntOnCylinder.X(), aPntOnCylinder.Y(), 0.0).Transformed (theTrsf));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : OverlapsCircle
|
|
// purpose :
|
|
//=======================================================================
|
|
Standard_Boolean SelectMgr_AxisIntersector::OverlapsCircle (const Standard_Real theRadius,
|
|
const gp_Trsf& theTrsf,
|
|
const Standard_Boolean theIsFilled,
|
|
Standard_Boolean* theInside) const
|
|
{
|
|
Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
|
|
"Error! SelectMgr_AxisIntersector::OverlapsCircle() should be called after selection axis initialization");
|
|
Standard_Real aTime = 0.0;
|
|
gp_Trsf aTrsfInv = theTrsf.Inverted();
|
|
gp_Pnt aLoc = myAxis.Location().Transformed (aTrsfInv);
|
|
gp_Dir aRayDir = myAxis.Direction().Transformed (aTrsfInv);
|
|
if (!RayCircleIntersection (theRadius, aLoc, aRayDir, theIsFilled, aTime))
|
|
{
|
|
return false;
|
|
}
|
|
if (theInside != NULL)
|
|
{
|
|
*theInside &= (aTime >= 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)
|
|
}
|