From: age Date: Mon, 16 Nov 2020 11:53:07 +0000 (+0300) Subject: 0031798: Visualization, SelectMgr_ViewerSelector - fix comparing depth of direct... X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=20d15a152091f857bbbf826364b5a946957fcb70;p=occt-copy.git 0031798: Visualization, SelectMgr_ViewerSelector - fix comparing depth of direct and indirect triangle hits --- diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx index 547b204f21..51fbe50582 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx @@ -130,6 +130,59 @@ bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePl namespace { + // ======================================================================= + // function : intersectSegmentPlane + // purpose : + // ======================================================================= + Standard_Boolean intersectSegmentPlane (const gp_Pnt& theSegPnt1, const gp_Pnt& theSegPnt2, const gp_Vec& thePlane, const gp_Pnt& thePntOnPlane, gp_Pnt& theResPnt) + { + gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ(); + gp_XYZ aW = theSegPnt1.XYZ() - thePntOnPlane.XYZ(); + Standard_Real aD = thePlane.Dot(anU); + Standard_Real aN = -thePlane.Dot(aW); + + if (Abs(aD) < Precision::Confusion()) + { + return Standard_False; + } + + Standard_Real aParam = aN / aD; + if (aParam < 0.0 || aParam > 1.0) + { + return Standard_False; + } + + theResPnt = theSegPnt1.XYZ() + anU * aParam; + + return Standard_True; + } + + // ======================================================================= + // function : projectPointOnPlane + // purpose : + // ======================================================================= + gp_Pnt projectPointOnPlane (const gp_Pnt& thePnt, const gp_Vec& thePlane, const gp_Pnt& thePntOnPlane) + { + return thePnt.XYZ() - thePlane.XYZ() * (thePnt.XYZ() - thePntOnPlane.XYZ()).Dot(thePlane.XYZ()); + } + + // ======================================================================= + // function : pointLineDistanceField + // purpose : + // ======================================================================= + Standard_Real pointLineDistanceField (const gp_Pnt& thePnt, const gp_Pnt& theLinePnt1, const gp_Pnt& theLinePnt2, const gp_Pnt& thePntOnNeg, gp_Pnt& theResPntOnLine) + { + gp_XYZ aLine = theLinePnt2.XYZ() - theLinePnt1.XYZ(); + gp_XYZ aW = thePnt.XYZ() - theLinePnt1.XYZ(); + gp_XYZ anU = thePntOnNeg.XYZ() - theLinePnt1.XYZ(); + + Standard_Real aCoeff = aW.Dot (aLine) / aLine.Dot (aLine); + aCoeff = aCoeff < 0 ? 0 : aCoeff > 1 ? 1 : aCoeff; + + theResPntOnLine = theLinePnt1.XYZ() + aLine * aCoeff; + return Sign (thePnt.Distance (theResPntOnLine), aW.Crossed (aLine).DotCross (aLine, anU)); + } + // ======================================================================= // function : computeFrustum // purpose : Computes base frustum data: its vertices and edge directions @@ -691,35 +744,83 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1, const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0); const gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime; + if (isInterior) { - thePickResult.SetDepth (myNearPickedPnt.Distance (aPtOnPlane) * myScale); - thePickResult.SetPickedPoint (aPtOnPlane); - thePickResult.SetSurfaceNormal (aTriangleNormal); - return !theClipRange.IsClipped (thePickResult.Depth()); + thePickResult.SetSurfaceNormal(aTriangleNormal); } - - Standard_Real aMinDist = RealLast(); - Standard_Integer aNearestEdgeIdx1 = -1; - for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx) + + gp_Pnt aPnts[3] = { thePnt1, thePnt2, thePnt3 }; + + gp_Vec aTrgNorm = aTriangleNormal.Normalized(); + + gp_Pnt aProjNearPnt = projectPointOnPlane (myNearPickedPnt, aTrgNorm, thePnt1); + + gp_Pnt aProjFrustumPnt[4]; + Standard_Integer aLastIdx = 0; + gp_Pnt aResProjPnt; + if (intersectSegmentPlane (myVertices[0], myVertices[1], aTrgNorm, thePnt1, aResProjPnt)) + { + aProjFrustumPnt[aLastIdx++] = aResProjPnt; + } + if (intersectSegmentPlane (myVertices[2], myVertices[3], aTrgNorm, thePnt1, aResProjPnt)) + { + aProjFrustumPnt[aLastIdx++] = aResProjPnt; + } + if (intersectSegmentPlane (myVertices[6], myVertices[7], aTrgNorm, thePnt1, aResProjPnt)) + { + aProjFrustumPnt[aLastIdx++] = aResProjPnt; + } + if (intersectSegmentPlane (myVertices[4], myVertices[5], aTrgNorm, thePnt1, aResProjPnt)) + { + aProjFrustumPnt[aLastIdx++] = aResProjPnt; + } + + // Distance from projected myNearPickedPnt to projected fructum rectangle, + // inside distance is 0, outside distance is positive + gp_Pnt aNearPntOnFrustumRect; + Standard_Real aDistToFrustumRect = -RealLast(); + for (Standard_Integer aVertIdx = 0; aVertIdx < aLastIdx && aLastIdx > 1; ++aVertIdx) + { + gp_Pnt aTmpPnt; + Standard_Real aDist = pointLineDistanceField (aProjNearPnt, aProjFrustumPnt[aVertIdx], aProjFrustumPnt[(aVertIdx + 1) % aLastIdx], aPtOnPlane, aTmpPnt); + if (aDist > aDistToFrustumRect) + { + aDistToFrustumRect = aDist; + aNearPntOnFrustumRect = aTmpPnt; + } + } + if (aDistToFrustumRect < 0) + { + aNearPntOnFrustumRect = aProjNearPnt; + aDistToFrustumRect = 0; + } + + // Distance from projected myNearPickedPnt to triangle, + // inside distance is 0, outside distance is positive + gp_Pnt aNearPntOnTriangle; + Standard_Real aDistToTriangle = -RealLast(); + for (Standard_Integer aVertIdx = 0; aVertIdx < 3; ++aVertIdx) { - 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) + gp_Pnt aTmpPnt; + Standard_Real aDist = pointLineDistanceField (aProjNearPnt, aPnts[aVertIdx], aPnts[(aVertIdx + 1) % 3], aPnts[(aVertIdx + 2) % 3], aTmpPnt); + if (aDist > aDistToTriangle) { - aMinDist = aDist; - aNearestEdgeIdx1 = anEdgeIdx; + aDistToTriangle = aDist; + aNearPntOnTriangle = aTmpPnt; } } - Standard_Integer aNearestEdgeIdx2 = (aNearestEdgeIdx1 + 1) % 3; - const gp_Vec aVec12 (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2]); - if (aVec12.SquareMagnitude() > gp::Resolution() - && myViewRayDir.IsParallel (aVec12, Precision::Angular())) + if (aDistToTriangle < 0) { - aNearestEdgeIdx2 = aNearestEdgeIdx1 == 0 ? 2 : aNearestEdgeIdx1 - 1; + aNearPntOnTriangle = aProjNearPnt; + aDistToTriangle = 0; } - segmentSegmentDistance (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2], thePickResult); + + // Combining distances + gp_Pnt aResPnt = aDistToFrustumRect > aDistToTriangle ? aNearPntOnFrustumRect : aNearPntOnTriangle; + + thePickResult.SetDepth (myNearPickedPnt.Distance(aResPnt) * myScale); + thePickResult.SetPickedPoint (aResPnt); } return !theClipRange.IsClipped (thePickResult.Depth());