1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00
Files
occt/src/SelectMgr/SelectMgr_Frustum.lxx
dpasukhi a5a7b3185b Coding - Apply .clang-format formatting #286
Update empty method guards to new style with regex (see PR).
Used clang-format 18.1.8.
New actions to validate code formatting is added.
Update .clang-format with disabling of include sorting.
  It is temporary changes, then include will be sorted.
Apply formatting for /src and /tools folder.
The files with .hxx,.cxx,.lxx,.h,.pxx,.hpp,*.cpp extensions.
2025-01-26 00:43:57 +00:00

942 lines
36 KiB
Plaintext

// Created on: 2015-03-16
// Created by: Varvara POSKONINA
// Copyright (c) 2005-2014 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 <gp_Pln.hxx>
#include <NCollection_Vector.hxx>
#include <Poly_Array1OfTriangle.hxx>
#include <Standard_Assert.hxx>
#include <SelectMgr_FrustumBuilder.hxx>
// =======================================================================
// function : isSeparated
// purpose : Checks if AABB and frustum are separated along the given axis.
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::isSeparated(const SelectMgr_Vec3& theBoxMin,
const SelectMgr_Vec3& theBoxMax,
const gp_XYZ& theDirect,
Standard_Boolean* theInside) const
{
const Standard_Real aMinB =
theDirect.X() * (theDirect.X() < 0.0 ? theBoxMax.x() : theBoxMin.x())
+ theDirect.Y() * (theDirect.Y() < 0.0 ? theBoxMax.y() : theBoxMin.y())
+ theDirect.Z() * (theDirect.Z() < 0.0 ? theBoxMax.z() : theBoxMin.z());
const Standard_Real aMaxB =
theDirect.X() * (theDirect.X() < 0.0 ? theBoxMin.x() : theBoxMax.x())
+ theDirect.Y() * (theDirect.Y() < 0.0 ? theBoxMin.y() : theBoxMax.y())
+ theDirect.Z() * (theDirect.Z() < 0.0 ? theBoxMin.z() : theBoxMax.z());
Standard_ASSERT_RAISE(aMaxB >= aMinB, "Error! Failed to project box");
// frustum projection
Standard_Real aMinF = DBL_MAX;
Standard_Real aMaxF = -DBL_MAX;
for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
{
const Standard_Real aProj = myVertices[aVertIdx].XYZ().Dot(theDirect);
aMinF = Min(aMinF, aProj);
aMaxF = Max(aMaxF, aProj);
if (aMinF <= aMaxB && aMaxF >= aMinB)
{
if (theInside == NULL || !(*theInside)) // only overlap test
{
return Standard_False;
}
}
}
if (aMinF > aMaxB || aMaxF < aMinB)
{
return Standard_True; // fully separated
}
else if (theInside != NULL) // to check for inclusion?
{
*theInside &= aMinB >= aMinF && aMaxB <= aMaxF;
}
return Standard_False;
}
// =======================================================================
// function : isSeparated
// purpose : Checks if triangle and frustum are separated along the
// given axis
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::isSeparated(const gp_Pnt& thePnt1,
const gp_Pnt& thePnt2,
const gp_Pnt& thePnt3,
const gp_XYZ& theAxis) const
{
// frustum projection
Standard_Real aMinF = RealLast();
Standard_Real aMaxF = RealFirst();
// triangle projection
Standard_Real aMinTr = RealLast();
Standard_Real aMaxTr = RealFirst();
Standard_Real aTriangleProj;
aTriangleProj = theAxis.Dot(thePnt1.XYZ());
aMinTr = Min(aMinTr, aTriangleProj);
aMaxTr = Max(aMaxTr, aTriangleProj);
aTriangleProj = theAxis.Dot(thePnt2.XYZ());
aMinTr = Min(aMinTr, aTriangleProj);
aMaxTr = Max(aMaxTr, aTriangleProj);
aTriangleProj = theAxis.Dot(thePnt3.XYZ());
aMinTr = Min(aMinTr, aTriangleProj);
aMaxTr = Max(aMaxTr, aTriangleProj);
for (Standard_Integer aVertIter = 0; aVertIter < N * 2; ++aVertIter)
{
const Standard_Real aProj = myVertices[aVertIter].XYZ().Dot(theAxis);
aMinF = Min(aMinF, aProj);
aMaxF = Max(aMaxF, aProj);
if (aMinF <= aMaxTr && aMaxF >= aMinTr)
{
return Standard_False;
}
}
return aMinF > aMaxTr || aMaxF < aMinTr;
}
// =======================================================================
// function : hasBoxOverlap
// purpose : Returns true if selecting volume is overlapped by
// axis-aligned bounding box with minimum corner at point
// theMinPnt and maximum at point theMaxPnt
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::hasBoxOverlap(const SelectMgr_Vec3& theMinPnt,
const SelectMgr_Vec3& theMaxPnt,
Standard_Boolean* theInside) const
{
for (Standard_Integer anAxis = 0; anAxis < 3; ++anAxis)
{
if (theMinPnt[anAxis] > myMaxOrthoVertsProjections[anAxis]
|| theMaxPnt[anAxis] < myMinOrthoVertsProjections[anAxis])
{
return Standard_False; // fully separated
}
else if (theInside != NULL) // to check for inclusion?
{
*theInside &= theMinPnt[anAxis] >= myMinOrthoVertsProjections[anAxis]
&& theMaxPnt[anAxis] <= myMaxOrthoVertsProjections[anAxis];
}
}
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();
const Standard_Real aBoxProjMin =
aPlane.X() * (aPlane.X() < 0.f ? theMaxPnt.x() : theMinPnt.x())
+ aPlane.Y() * (aPlane.Y() < 0.f ? theMaxPnt.y() : theMinPnt.y())
+ aPlane.Z() * (aPlane.Z() < 0.f ? theMaxPnt.z() : theMinPnt.z());
const Standard_Real aBoxProjMax =
aPlane.X() * (aPlane.X() < 0.f ? theMinPnt.x() : theMaxPnt.x())
+ aPlane.Y() * (aPlane.Y() < 0.f ? theMinPnt.y() : theMaxPnt.y())
+ aPlane.Z() * (aPlane.Z() < 0.f ? theMinPnt.z() : theMaxPnt.z());
Standard_ASSERT_RAISE(aBoxProjMax >= aBoxProjMin, "Error! Failed to project box");
if (aBoxProjMin > myMaxVertsProjections[aPlaneIdx]
|| aBoxProjMax < myMinVertsProjections[aPlaneIdx])
{
return Standard_False; // fully separated
}
else if (theInside != NULL) // to check for inclusion?
{
*theInside &= aBoxProjMin >= myMinVertsProjections[aPlaneIdx]
&& aBoxProjMax <= myMaxVertsProjections[aPlaneIdx];
}
}
for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
{
// the following code performs a speedup of cross-product
// of vector with 1.0 at the position aDim and myEdgeDirs[aVolDir]
const Standard_Integer aNext = (aDim + 1) % 3;
const Standard_Integer aNextNext = (aDim + 2) % 3;
for (Standard_Integer aVolDir = 0, aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
aVolDir < aDirectionsNb;
++aVolDir)
{
gp_XYZ aDirection(DBL_MAX, DBL_MAX, DBL_MAX);
aDirection.ChangeData()[aDim] = 0;
aDirection.ChangeData()[aNext] = -myEdgeDirs[aVolDir].XYZ().GetData()[aNextNext];
aDirection.ChangeData()[aNextNext] = myEdgeDirs[aVolDir].XYZ().GetData()[aNext];
if (isSeparated(theMinPnt, theMaxPnt, aDirection, theInside))
{
return Standard_False;
}
}
}
return Standard_True;
}
// =======================================================================
// function : hasPointOverlap
// purpose : SAT intersection test between defined volume and given point
// =======================================================================
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());
if (aPointProj > myMaxVertsProjections[aPlaneIdx]
|| aPointProj < myMinVertsProjections[aPlaneIdx])
{
return Standard_False;
}
}
return Standard_True;
}
// =======================================================================
// function : hasSegmentOverlap
// purpose : SAT intersection test between defined volume and given segment
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::hasSegmentOverlap(const gp_Pnt& theStartPnt,
const gp_Pnt& theEndPnt) const
{
const gp_XYZ& aDir = theEndPnt.XYZ() - theStartPnt.XYZ();
if (aDir.Modulus() < Precision::Confusion())
return Standard_True;
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
{
Standard_Real aMinSegm = RealLast(), aMaxSegm = RealFirst();
Standard_Real aMinF = RealLast(), aMaxF = RealFirst();
Standard_Real aProj1 = myPlanes[aPlaneIdx].XYZ().Dot(theStartPnt.XYZ());
Standard_Real aProj2 = myPlanes[aPlaneIdx].XYZ().Dot(theEndPnt.XYZ());
aMinSegm = Min(aProj1, aProj2);
aMaxSegm = Max(aProj1, aProj2);
aMaxF = myMaxVertsProjections[aPlaneIdx];
aMinF = myMinVertsProjections[aPlaneIdx];
if (aMinSegm > aMaxF || aMaxSegm < aMinF)
{
return Standard_False;
}
}
Standard_Real aMin1 = DBL_MAX, aMax1 = -DBL_MAX;
Standard_Real aMin2 = DBL_MAX, aMax2 = -DBL_MAX;
for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
{
Standard_Real aProjection = aDir.Dot(myVertices[aVertIdx].XYZ());
aMax2 = Max(aMax2, aProjection);
aMin2 = Min(aMin2, aProjection);
}
Standard_Real aProj1 = aDir.Dot(theStartPnt.XYZ());
Standard_Real aProj2 = aDir.Dot(theEndPnt.XYZ());
aMin1 = Min(aProj1, aProj2);
aMax1 = Max(aProj1, aProj2);
if (aMin1 > aMax2 || aMax1 < aMin2)
{
return Standard_False;
}
Standard_Integer aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
for (Standard_Integer aEdgeDirIdx = 0; aEdgeDirIdx < aDirectionsNb; ++aEdgeDirIdx)
{
Standard_Real aMinSegm = DBL_MAX, aMaxSegm = -DBL_MAX;
Standard_Real aMinF = DBL_MAX, aMaxF = -DBL_MAX;
const gp_XYZ aTestDir = aDir.Crossed(myEdgeDirs[aEdgeDirIdx].XYZ());
Standard_Real Proj1 = aTestDir.Dot(theStartPnt.XYZ());
Standard_Real Proj2 = aTestDir.Dot(theEndPnt.XYZ());
aMinSegm = Min(Proj1, Proj2);
aMaxSegm = Max(Proj1, Proj2);
for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
{
Standard_Real aProjection = aTestDir.Dot(myVertices[aVertIdx].XYZ());
aMaxF = Max(aMaxF, aProjection);
aMinF = Min(aMinF, aProjection);
}
if (aMinSegm > aMaxF || aMaxSegm < aMinF)
{
return Standard_False;
}
}
return Standard_True;
}
// =======================================================================
// function : hasPolygonOverlap
// purpose : SAT intersection test between frustum given and planar convex
// polygon represented as ordered point set
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::hasPolygonOverlap(const TColgp_Array1OfPnt& theArrayOfPnts,
gp_Vec& theNormal) const
{
Standard_Integer aStartIdx = theArrayOfPnts.Lower();
Standard_Integer anEndIdx = theArrayOfPnts.Upper();
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;
theNormal = aVec2.Crossed(aVec1);
const gp_XYZ& aNormal = theNormal.XYZ();
Standard_Real aPolygProjection = aNormal.Dot(aPnt1);
Standard_Real aMax = RealFirst();
Standard_Real aMin = RealLast();
for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
{
Standard_Real aProjection = aNormal.Dot(myVertices[aVertIdx].XYZ());
aMax = Max(aMax, aProjection);
aMin = Min(aMin, aProjection);
}
if (aPolygProjection > aMax || aPolygProjection < aMin)
{
return Standard_False;
}
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
{
Standard_Real aMaxF = RealFirst();
Standard_Real aMinF = RealLast();
Standard_Real aMaxPolyg = RealFirst();
Standard_Real aMinPolyg = RealLast();
const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
{
Standard_Real aProjection = aPlane.Dot(theArrayOfPnts.Value(aPntIter).XYZ());
aMaxPolyg = Max(aMaxPolyg, aProjection);
aMinPolyg = Min(aMinPolyg, aProjection);
}
aMaxF = myMaxVertsProjections[aPlaneIdx];
aMinF = myMinVertsProjections[aPlaneIdx];
if (aMinPolyg > aMaxF || aMaxPolyg < aMinF)
{
return Standard_False;
}
}
Standard_Integer aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
for (Standard_Integer aPntsIter = 0,
aLastIdx = anEndIdx - aStartIdx,
aLen = theArrayOfPnts.Length();
aPntsIter <= aLastIdx;
++aPntsIter)
{
const gp_XYZ aSegmDir = theArrayOfPnts.Value((aPntsIter + 1) % aLen + aStartIdx).XYZ()
- theArrayOfPnts.Value(aPntsIter + aStartIdx).XYZ();
for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
{
Standard_Real aMaxPolyg = RealFirst();
Standard_Real aMinPolyg = RealLast();
Standard_Real aMaxF = RealFirst();
Standard_Real aMinF = RealLast();
const gp_XYZ aTestDir = aSegmDir.Crossed(myEdgeDirs[aVolDir].XYZ());
for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
{
Standard_Real aProjection = aTestDir.Dot(theArrayOfPnts.Value(aPntIter).XYZ());
aMaxPolyg = Max(aMaxPolyg, aProjection);
aMinPolyg = Min(aMinPolyg, aProjection);
}
for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
{
Standard_Real aProjection = aTestDir.Dot(myVertices[aVertIdx].XYZ());
aMaxF = Max(aMaxF, aProjection);
aMinF = Min(aMinF, aProjection);
}
if (aMinPolyg > aMaxF || aMaxPolyg < aMinF)
{
return Standard_False;
}
}
}
return Standard_True;
}
// =======================================================================
// function : hasTriangleOverlap
// purpose : SAT intersection test between defined volume and given triangle
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::hasTriangleOverlap(const gp_Pnt& thePnt1,
const gp_Pnt& thePnt2,
const gp_Pnt& thePnt3,
gp_Vec& theNormal) const
{
const gp_XYZ aTrEdges[3] = {thePnt2.XYZ() - thePnt1.XYZ(),
thePnt3.XYZ() - thePnt2.XYZ(),
thePnt1.XYZ() - thePnt3.XYZ()};
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();
Standard_Real aTriangleProj;
aTriangleProj = aPlane.Dot(thePnt1.XYZ());
Standard_Real aTriangleProjMin = aTriangleProj;
Standard_Real aTriangleProjMax = aTriangleProj;
aTriangleProj = aPlane.Dot(thePnt2.XYZ());
aTriangleProjMin = Min(aTriangleProjMin, aTriangleProj);
aTriangleProjMax = Max(aTriangleProjMax, aTriangleProj);
aTriangleProj = aPlane.Dot(thePnt3.XYZ());
aTriangleProjMin = Min(aTriangleProjMin, aTriangleProj);
aTriangleProjMax = Max(aTriangleProjMax, aTriangleProj);
Standard_Real aFrustumProjMax = myMaxVertsProjections[aPlaneIdx];
Standard_Real aFrustumProjMin = myMinVertsProjections[aPlaneIdx];
if (aTriangleProjMin > aFrustumProjMax || aTriangleProjMax < aFrustumProjMin)
{
return Standard_False;
}
}
theNormal = aTrEdges[2].Crossed(aTrEdges[0]);
if (isSeparated(thePnt1, thePnt2, thePnt3, theNormal.XYZ()))
{
return Standard_False;
}
Standard_Integer aDirectionsNb = myCamera->IsOrthographic() ? 4 : 6;
for (Standard_Integer aTriangleEdgeIdx = 0; aTriangleEdgeIdx < 3; ++aTriangleEdgeIdx)
{
for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
{
const gp_XYZ& aTestDirection = myEdgeDirs[aVolDir].XYZ().Crossed(aTrEdges[aTriangleEdgeIdx]);
if (isSeparated(thePnt1, thePnt2, thePnt3, aTestDirection))
{
return Standard_False;
}
}
}
return Standard_True;
}
// =======================================================================
// function : hasSphereOverlap
// purpose :
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::hasSphereOverlap(const gp_Pnt& thePnt,
const Standard_Real theRadius,
Standard_Boolean* theInside) const
{
Standard_Boolean isOverlapFull = Standard_True;
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N; aPlaneIdx += anIncFactor)
{
const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
const Standard_Real aNormVecLen = Sqrt(aPlane.Dot(aPlane));
const Standard_Real aCenterProj = aPlane.Dot(thePnt.XYZ()) / aNormVecLen;
const Standard_Real aMaxDist = myMaxVertsProjections[aPlaneIdx] / aNormVecLen;
const Standard_Real aMinDist = myMinVertsProjections[aPlaneIdx] / aNormVecLen;
if (aCenterProj > (aMaxDist + theRadius) || aCenterProj < (aMinDist - theRadius))
{
return Standard_False; // fully separated
}
else if (theInside)
{
*theInside &= aCenterProj >= (aMinDist + theRadius) && aCenterProj <= (aMaxDist - theRadius);
}
isOverlapFull &= aCenterProj >= (aMinDist + theRadius) && aCenterProj <= (aMaxDist - theRadius);
}
if (theInside || isOverlapFull)
{
return Standard_True;
}
const gp_Vec aVecPlane1(myVertices[0], myVertices[2]);
const gp_Vec aVecPlane2(myVertices[0], myVertices[2 * N - 2]);
if (aVecPlane1.IsParallel(aVecPlane2, Precision::Angular()))
{
return Standard_False;
}
const gp_Dir aNorm(aVecPlane1.Crossed(aVecPlane2));
gp_Pnt aBoundariesCArr[5];
NCollection_Array1<gp_Pnt> aBoundaries(aBoundariesCArr[0], 0, N);
for (Standard_Integer anIdx = 0; anIdx < N * 2; anIdx += 2)
{
aBoundaries.SetValue(anIdx / 2, myVertices[anIdx]);
}
// distance from point(x,y,z) to plane(A,B,C,D) d = | Ax + By + Cz + D | / sqrt (A^2 + B^2 + C^2)
// = aPnt.Dot (Norm) / 1
const gp_Pnt aCenterProj = thePnt.XYZ() - aNorm.XYZ() * thePnt.XYZ().Dot(aNorm.XYZ());
Standard_Boolean isBoundaryInside = Standard_False;
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 : isIntersectCircle
// purpose :
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::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[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 - 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 : isInsideCylinderEndFace
// purpose :
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::isInsideCylinderEndFace(
const Standard_Real theBottomRad,
const Standard_Real theTopRad,
const Standard_Real theHeight,
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 aLoc = theVertices.Value(anIdx).Transformed(aTrsfInv);
const Standard_Real aTime1 = (0 - aLoc.Z()) / aRayDir.Z();
const Standard_Real aX1 = aLoc.X() + aRayDir.X() * aTime1;
const Standard_Real anY1 = aLoc.Y() + aRayDir.Y() * aTime1;
const Standard_Real aTime2 = (theHeight - aLoc.Z()) / aRayDir.Z();
const Standard_Real aX2 = aLoc.X() + aRayDir.X() * aTime2;
const Standard_Real anY2 = aLoc.Y() + aRayDir.Y() * aTime2;
if (aX1 * aX1 + anY1 * anY1 <= theBottomRad * theBottomRad
&& aX2 * aX2 + anY2 * anY2 <= theTopRad * theTopRad)
{
continue;
}
return false;
}
return true;
}
// =======================================================================
// 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,
const Standard_Boolean theIsHollow,
Standard_Boolean* theInside) const
{
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]);
}
}
if (theIsHollow
&& isInsideCylinderEndFace(theBottomRad, theTopRad, theHeight, theTrsf, aVertices))
{
if (theInside != NULL)
{
*theInside = false;
}
return false;
}
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);
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 (!theIsHollow
&& (isIntersectCircle(theBottomRad, gp_Pnt(0, 0, 0), theTrsf, aVertices)
|| isIntersectCircle(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 : hasCircleOverlap
// purpose :
// =======================================================================
template <int N>
Standard_Boolean SelectMgr_Frustum<N>::hasCircleOverlap(const Standard_Real theRadius,
const gp_Trsf& theTrsf,
const Standard_Boolean theIsFilled,
Standard_Boolean* theInside) const
{
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]);
}
}
if (isIntersectCircle(theRadius, gp_Pnt(0, 0, 0), theTrsf, aVertices))
{
if (theInside != NULL)
{
*theInside = false;
}
return true;
}
gp_Pnt aCircCenter = gp::Origin(); //.Transformed (theTrsf);
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 aTCenter = -(aCircCenter.XYZ().Dot(aViewRayDir.XYZ()) + aCoefD);
const gp_Pnt aCenterProject(aCoefA * aTCenter, aCoefB * aTCenter, aCoefC * aTCenter);
const Standard_Boolean isCenterInside = isDotInside(aCenterProject, aVertices);
Standard_Boolean isInside = false;
for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
{
if (aVertices.Value(anIdx).Distance(aCenterProject) > theRadius)
{
isInside = true;
break;
}
}
if (theInside != NULL)
{
*theInside = isInside && isCenterInside;
}
return theIsFilled ? !isInside || (isCenterInside && isInside) : isInside && isCenterInside;
}
//=======================================================================
// function : DumpJson
// purpose :
//=======================================================================
template <int N>
void SelectMgr_Frustum<N>::DumpJson(Standard_OStream& theOStream, Standard_Integer theDepth) const
{
OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream)
const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
{
const gp_Vec& aPlane = myPlanes[aPlaneIdx];
OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &aPlane)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myMaxVertsProjections[aPlaneIdx])
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myMinVertsProjections[aPlaneIdx])
}
for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
{
const gp_Pnt& aVertex = myVertices[aVertIdx];
OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &aVertex)
}
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myPixelTolerance)
OCCT_DUMP_FIELD_VALUE_POINTER(theOStream, myBuilder)
OCCT_DUMP_FIELD_VALUE_POINTER(theOStream, myCamera)
for (Standard_Integer anIndex = 0; anIndex < 3; anIndex++)
{
Standard_Real aMaxOrthoVertsProjections = myMaxOrthoVertsProjections[anIndex];
Standard_Real aMinOrthoVertsProjections = myMinOrthoVertsProjections[anIndex];
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, aMaxOrthoVertsProjections)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, aMinOrthoVertsProjections)
}
for (Standard_Integer anIndex = 0; anIndex < 6; anIndex++)
{
const gp_Vec& anEdgeDir = myEdgeDirs[anIndex];
OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &anEdgeDir)
}
}