Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/opencascade/SelectMgr_Frustum.lxx is written in an unsupported language. File is not indexed.

0001 // Created on: 2015-03-16
0002 // Created by: Varvara POSKONINA
0003 // Copyright (c) 2005-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #include <gp_Pln.hxx>
0017 #include <NCollection_Vector.hxx>
0018 #include <Poly_Array1OfTriangle.hxx>
0019 #include <Standard_Assert.hxx>
0020 #include <SelectMgr_FrustumBuilder.hxx>
0021 
0022 // =======================================================================
0023 // function : isSeparated
0024 // purpose  : Checks if AABB and frustum are separated along the given axis.
0025 // =======================================================================
0026 template <int N>
0027 Standard_Boolean SelectMgr_Frustum<N>::isSeparated(const SelectMgr_Vec3& theBoxMin,
0028                                                    const SelectMgr_Vec3& theBoxMax,
0029                                                    const gp_XYZ&         theDirect,
0030                                                    Standard_Boolean*     theInside) const
0031 {
0032   const Standard_Real aMinB =
0033     theDirect.X() * (theDirect.X() < 0.0 ? theBoxMax.x() : theBoxMin.x())
0034     + theDirect.Y() * (theDirect.Y() < 0.0 ? theBoxMax.y() : theBoxMin.y())
0035     + theDirect.Z() * (theDirect.Z() < 0.0 ? theBoxMax.z() : theBoxMin.z());
0036 
0037   const Standard_Real aMaxB =
0038     theDirect.X() * (theDirect.X() < 0.0 ? theBoxMin.x() : theBoxMax.x())
0039     + theDirect.Y() * (theDirect.Y() < 0.0 ? theBoxMin.y() : theBoxMax.y())
0040     + theDirect.Z() * (theDirect.Z() < 0.0 ? theBoxMin.z() : theBoxMax.z());
0041 
0042   Standard_ASSERT_RAISE(aMaxB >= aMinB, "Error! Failed to project box");
0043 
0044   // frustum projection
0045   Standard_Real aMinF = DBL_MAX;
0046   Standard_Real aMaxF = -DBL_MAX;
0047 
0048   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0049   {
0050     const Standard_Real aProj = myVertices[aVertIdx].XYZ().Dot(theDirect);
0051 
0052     aMinF = Min(aMinF, aProj);
0053     aMaxF = Max(aMaxF, aProj);
0054 
0055     if (aMinF <= aMaxB && aMaxF >= aMinB)
0056     {
0057       if (theInside == NULL || !(*theInside)) // only overlap test
0058       {
0059         return Standard_False;
0060       }
0061     }
0062   }
0063 
0064   if (aMinF > aMaxB || aMaxF < aMinB)
0065   {
0066     return Standard_True; // fully separated
0067   }
0068   else if (theInside != NULL) // to check for inclusion?
0069   {
0070     *theInside &= aMinB >= aMinF && aMaxB <= aMaxF;
0071   }
0072 
0073   return Standard_False;
0074 }
0075 
0076 // =======================================================================
0077 // function : isSeparated
0078 // purpose  : Checks if triangle and frustum are separated along the
0079 //            given axis
0080 // =======================================================================
0081 template <int N>
0082 Standard_Boolean SelectMgr_Frustum<N>::isSeparated(const gp_Pnt& thePnt1,
0083                                                    const gp_Pnt& thePnt2,
0084                                                    const gp_Pnt& thePnt3,
0085                                                    const gp_XYZ& theAxis) const
0086 {
0087   // frustum projection
0088   Standard_Real aMinF = RealLast();
0089   Standard_Real aMaxF = RealFirst();
0090 
0091   // triangle projection
0092   Standard_Real aMinTr = RealLast();
0093   Standard_Real aMaxTr = RealFirst();
0094 
0095   Standard_Real aTriangleProj;
0096 
0097   aTriangleProj = theAxis.Dot(thePnt1.XYZ());
0098   aMinTr        = Min(aMinTr, aTriangleProj);
0099   aMaxTr        = Max(aMaxTr, aTriangleProj);
0100 
0101   aTriangleProj = theAxis.Dot(thePnt2.XYZ());
0102   aMinTr        = Min(aMinTr, aTriangleProj);
0103   aMaxTr        = Max(aMaxTr, aTriangleProj);
0104 
0105   aTriangleProj = theAxis.Dot(thePnt3.XYZ());
0106   aMinTr        = Min(aMinTr, aTriangleProj);
0107   aMaxTr        = Max(aMaxTr, aTriangleProj);
0108 
0109   for (Standard_Integer aVertIter = 0; aVertIter < N * 2; ++aVertIter)
0110   {
0111     const Standard_Real aProj = myVertices[aVertIter].XYZ().Dot(theAxis);
0112 
0113     aMinF = Min(aMinF, aProj);
0114     aMaxF = Max(aMaxF, aProj);
0115 
0116     if (aMinF <= aMaxTr && aMaxF >= aMinTr)
0117     {
0118       return Standard_False;
0119     }
0120   }
0121 
0122   return aMinF > aMaxTr || aMaxF < aMinTr;
0123 }
0124 
0125 // =======================================================================
0126 // function : hasBoxOverlap
0127 // purpose  : Returns true if selecting volume is overlapped by
0128 //            axis-aligned bounding box with minimum corner at point
0129 //            theMinPnt and maximum at point theMaxPnt
0130 // =======================================================================
0131 template <int N>
0132 Standard_Boolean SelectMgr_Frustum<N>::hasBoxOverlap(const SelectMgr_Vec3& theMinPnt,
0133                                                      const SelectMgr_Vec3& theMaxPnt,
0134                                                      Standard_Boolean*     theInside) const
0135 {
0136   for (Standard_Integer anAxis = 0; anAxis < 3; ++anAxis)
0137   {
0138     if (theMinPnt[anAxis] > myMaxOrthoVertsProjections[anAxis]
0139         || theMaxPnt[anAxis] < myMinOrthoVertsProjections[anAxis])
0140     {
0141       return Standard_False; // fully separated
0142     }
0143     else if (theInside != NULL) // to check for inclusion?
0144     {
0145       *theInside &= theMinPnt[anAxis] >= myMinOrthoVertsProjections[anAxis]
0146                     && theMaxPnt[anAxis] <= myMaxOrthoVertsProjections[anAxis];
0147     }
0148   }
0149 
0150   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0151   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0152   {
0153     const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
0154 
0155     const Standard_Real aBoxProjMin =
0156       aPlane.X() * (aPlane.X() < 0.f ? theMaxPnt.x() : theMinPnt.x())
0157       + aPlane.Y() * (aPlane.Y() < 0.f ? theMaxPnt.y() : theMinPnt.y())
0158       + aPlane.Z() * (aPlane.Z() < 0.f ? theMaxPnt.z() : theMinPnt.z());
0159 
0160     const Standard_Real aBoxProjMax =
0161       aPlane.X() * (aPlane.X() < 0.f ? theMinPnt.x() : theMaxPnt.x())
0162       + aPlane.Y() * (aPlane.Y() < 0.f ? theMinPnt.y() : theMaxPnt.y())
0163       + aPlane.Z() * (aPlane.Z() < 0.f ? theMinPnt.z() : theMaxPnt.z());
0164 
0165     Standard_ASSERT_RAISE(aBoxProjMax >= aBoxProjMin, "Error! Failed to project box");
0166 
0167     if (aBoxProjMin > myMaxVertsProjections[aPlaneIdx]
0168         || aBoxProjMax < myMinVertsProjections[aPlaneIdx])
0169     {
0170       return Standard_False; // fully separated
0171     }
0172     else if (theInside != NULL) // to check for inclusion?
0173     {
0174       *theInside &= aBoxProjMin >= myMinVertsProjections[aPlaneIdx]
0175                     && aBoxProjMax <= myMaxVertsProjections[aPlaneIdx];
0176     }
0177   }
0178 
0179   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
0180   {
0181     // the following code performs a speedup of cross-product
0182     // of vector with 1.0 at the position aDim and myEdgeDirs[aVolDir]
0183     const Standard_Integer aNext     = (aDim + 1) % 3;
0184     const Standard_Integer aNextNext = (aDim + 2) % 3;
0185     for (Standard_Integer aVolDir = 0, aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
0186          aVolDir < aDirectionsNb;
0187          ++aVolDir)
0188     {
0189       gp_XYZ aDirection(DBL_MAX, DBL_MAX, DBL_MAX);
0190       aDirection.ChangeData()[aDim]      = 0;
0191       aDirection.ChangeData()[aNext]     = -myEdgeDirs[aVolDir].XYZ().GetData()[aNextNext];
0192       aDirection.ChangeData()[aNextNext] = myEdgeDirs[aVolDir].XYZ().GetData()[aNext];
0193 
0194       if (isSeparated(theMinPnt, theMaxPnt, aDirection, theInside))
0195       {
0196         return Standard_False;
0197       }
0198     }
0199   }
0200 
0201   return Standard_True;
0202 }
0203 
0204 // =======================================================================
0205 // function : hasPointOverlap
0206 // purpose  : SAT intersection test between defined volume and given point
0207 // =======================================================================
0208 template <int N>
0209 Standard_Boolean SelectMgr_Frustum<N>::hasPointOverlap(const gp_Pnt& thePnt) const
0210 {
0211   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0212   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0213   {
0214     const Standard_Real aPointProj = myPlanes[aPlaneIdx].XYZ().Dot(thePnt.XYZ());
0215 
0216     if (aPointProj > myMaxVertsProjections[aPlaneIdx]
0217         || aPointProj < myMinVertsProjections[aPlaneIdx])
0218     {
0219       return Standard_False;
0220     }
0221   }
0222 
0223   return Standard_True;
0224 }
0225 
0226 // =======================================================================
0227 // function : hasSegmentOverlap
0228 // purpose  : SAT intersection test between defined volume and given segment
0229 // =======================================================================
0230 template <int N>
0231 Standard_Boolean SelectMgr_Frustum<N>::hasSegmentOverlap(const gp_Pnt& theStartPnt,
0232                                                          const gp_Pnt& theEndPnt) const
0233 {
0234   const gp_XYZ& aDir = theEndPnt.XYZ() - theStartPnt.XYZ();
0235   if (aDir.Modulus() < Precision::Confusion())
0236     return Standard_True;
0237 
0238   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0239   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0240   {
0241     Standard_Real aMinSegm = RealLast(), aMaxSegm = RealFirst();
0242     Standard_Real aMinF = RealLast(), aMaxF = RealFirst();
0243 
0244     Standard_Real aProj1 = myPlanes[aPlaneIdx].XYZ().Dot(theStartPnt.XYZ());
0245     Standard_Real aProj2 = myPlanes[aPlaneIdx].XYZ().Dot(theEndPnt.XYZ());
0246     aMinSegm             = Min(aProj1, aProj2);
0247     aMaxSegm             = Max(aProj1, aProj2);
0248 
0249     aMaxF = myMaxVertsProjections[aPlaneIdx];
0250     aMinF = myMinVertsProjections[aPlaneIdx];
0251 
0252     if (aMinSegm > aMaxF || aMaxSegm < aMinF)
0253     {
0254       return Standard_False;
0255     }
0256   }
0257 
0258   Standard_Real aMin1 = DBL_MAX, aMax1 = -DBL_MAX;
0259   Standard_Real aMin2 = DBL_MAX, aMax2 = -DBL_MAX;
0260   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0261   {
0262     Standard_Real aProjection = aDir.Dot(myVertices[aVertIdx].XYZ());
0263     aMax2                     = Max(aMax2, aProjection);
0264     aMin2                     = Min(aMin2, aProjection);
0265   }
0266   Standard_Real aProj1 = aDir.Dot(theStartPnt.XYZ());
0267   Standard_Real aProj2 = aDir.Dot(theEndPnt.XYZ());
0268   aMin1                = Min(aProj1, aProj2);
0269   aMax1                = Max(aProj1, aProj2);
0270   if (aMin1 > aMax2 || aMax1 < aMin2)
0271   {
0272     return Standard_False;
0273   }
0274 
0275   Standard_Integer aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
0276   for (Standard_Integer aEdgeDirIdx = 0; aEdgeDirIdx < aDirectionsNb; ++aEdgeDirIdx)
0277   {
0278     Standard_Real aMinSegm = DBL_MAX, aMaxSegm = -DBL_MAX;
0279     Standard_Real aMinF = DBL_MAX, aMaxF = -DBL_MAX;
0280 
0281     const gp_XYZ aTestDir = aDir.Crossed(myEdgeDirs[aEdgeDirIdx].XYZ());
0282 
0283     Standard_Real Proj1 = aTestDir.Dot(theStartPnt.XYZ());
0284     Standard_Real Proj2 = aTestDir.Dot(theEndPnt.XYZ());
0285     aMinSegm            = Min(Proj1, Proj2);
0286     aMaxSegm            = Max(Proj1, Proj2);
0287 
0288     for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0289     {
0290       Standard_Real aProjection = aTestDir.Dot(myVertices[aVertIdx].XYZ());
0291       aMaxF                     = Max(aMaxF, aProjection);
0292       aMinF                     = Min(aMinF, aProjection);
0293     }
0294 
0295     if (aMinSegm > aMaxF || aMaxSegm < aMinF)
0296     {
0297       return Standard_False;
0298     }
0299   }
0300 
0301   return Standard_True;
0302 }
0303 
0304 // =======================================================================
0305 // function : hasPolygonOverlap
0306 // purpose  : SAT intersection test between frustum given and planar convex
0307 //            polygon represented as ordered point set
0308 // =======================================================================
0309 template <int N>
0310 Standard_Boolean SelectMgr_Frustum<N>::hasPolygonOverlap(const TColgp_Array1OfPnt& theArrayOfPnts,
0311                                                          gp_Vec&                   theNormal) const
0312 {
0313   Standard_Integer aStartIdx = theArrayOfPnts.Lower();
0314   Standard_Integer anEndIdx  = theArrayOfPnts.Upper();
0315 
0316   const gp_XYZ& aPnt1            = theArrayOfPnts.Value(aStartIdx).XYZ();
0317   const gp_XYZ& aPnt2            = theArrayOfPnts.Value(aStartIdx + 1).XYZ();
0318   const gp_XYZ& aPnt3            = theArrayOfPnts.Value(aStartIdx + 2).XYZ();
0319   const gp_XYZ  aVec1            = aPnt1 - aPnt2;
0320   const gp_XYZ  aVec2            = aPnt3 - aPnt2;
0321   theNormal                      = aVec2.Crossed(aVec1);
0322   const gp_XYZ& aNormal          = theNormal.XYZ();
0323   Standard_Real aPolygProjection = aNormal.Dot(aPnt1);
0324 
0325   Standard_Real aMax = RealFirst();
0326   Standard_Real aMin = RealLast();
0327   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0328   {
0329     Standard_Real aProjection = aNormal.Dot(myVertices[aVertIdx].XYZ());
0330     aMax                      = Max(aMax, aProjection);
0331     aMin                      = Min(aMin, aProjection);
0332   }
0333   if (aPolygProjection > aMax || aPolygProjection < aMin)
0334   {
0335     return Standard_False;
0336   }
0337 
0338   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0339   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0340   {
0341     Standard_Real aMaxF     = RealFirst();
0342     Standard_Real aMinF     = RealLast();
0343     Standard_Real aMaxPolyg = RealFirst();
0344     Standard_Real aMinPolyg = RealLast();
0345     const gp_XYZ& aPlane    = myPlanes[aPlaneIdx].XYZ();
0346     for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
0347     {
0348       Standard_Real aProjection = aPlane.Dot(theArrayOfPnts.Value(aPntIter).XYZ());
0349       aMaxPolyg                 = Max(aMaxPolyg, aProjection);
0350       aMinPolyg                 = Min(aMinPolyg, aProjection);
0351     }
0352     aMaxF = myMaxVertsProjections[aPlaneIdx];
0353     aMinF = myMinVertsProjections[aPlaneIdx];
0354     if (aMinPolyg > aMaxF || aMaxPolyg < aMinF)
0355     {
0356       return Standard_False;
0357     }
0358   }
0359 
0360   Standard_Integer aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
0361   for (Standard_Integer aPntsIter = 0,
0362                         aLastIdx  = anEndIdx - aStartIdx,
0363                         aLen      = theArrayOfPnts.Length();
0364        aPntsIter <= aLastIdx;
0365        ++aPntsIter)
0366   {
0367     const gp_XYZ aSegmDir = theArrayOfPnts.Value((aPntsIter + 1) % aLen + aStartIdx).XYZ()
0368                             - theArrayOfPnts.Value(aPntsIter + aStartIdx).XYZ();
0369     for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
0370     {
0371       Standard_Real aMaxPolyg = RealFirst();
0372       Standard_Real aMinPolyg = RealLast();
0373       Standard_Real aMaxF     = RealFirst();
0374       Standard_Real aMinF     = RealLast();
0375       const gp_XYZ  aTestDir  = aSegmDir.Crossed(myEdgeDirs[aVolDir].XYZ());
0376 
0377       for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
0378       {
0379         Standard_Real aProjection = aTestDir.Dot(theArrayOfPnts.Value(aPntIter).XYZ());
0380         aMaxPolyg                 = Max(aMaxPolyg, aProjection);
0381         aMinPolyg                 = Min(aMinPolyg, aProjection);
0382       }
0383 
0384       for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0385       {
0386         Standard_Real aProjection = aTestDir.Dot(myVertices[aVertIdx].XYZ());
0387         aMaxF                     = Max(aMaxF, aProjection);
0388         aMinF                     = Min(aMinF, aProjection);
0389       }
0390 
0391       if (aMinPolyg > aMaxF || aMaxPolyg < aMinF)
0392       {
0393         return Standard_False;
0394       }
0395     }
0396   }
0397 
0398   return Standard_True;
0399 }
0400 
0401 // =======================================================================
0402 // function : hasTriangleOverlap
0403 // purpose  : SAT intersection test between defined volume and given triangle
0404 // =======================================================================
0405 template <int N>
0406 Standard_Boolean SelectMgr_Frustum<N>::hasTriangleOverlap(const gp_Pnt& thePnt1,
0407                                                           const gp_Pnt& thePnt2,
0408                                                           const gp_Pnt& thePnt3,
0409                                                           gp_Vec&       theNormal) const
0410 {
0411   const gp_XYZ aTrEdges[3] = {thePnt2.XYZ() - thePnt1.XYZ(),
0412                               thePnt3.XYZ() - thePnt2.XYZ(),
0413                               thePnt1.XYZ() - thePnt3.XYZ()};
0414 
0415   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0416   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0417   {
0418     const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
0419     Standard_Real aTriangleProj;
0420 
0421     aTriangleProj                  = aPlane.Dot(thePnt1.XYZ());
0422     Standard_Real aTriangleProjMin = aTriangleProj;
0423     Standard_Real aTriangleProjMax = aTriangleProj;
0424 
0425     aTriangleProj    = aPlane.Dot(thePnt2.XYZ());
0426     aTriangleProjMin = Min(aTriangleProjMin, aTriangleProj);
0427     aTriangleProjMax = Max(aTriangleProjMax, aTriangleProj);
0428 
0429     aTriangleProj    = aPlane.Dot(thePnt3.XYZ());
0430     aTriangleProjMin = Min(aTriangleProjMin, aTriangleProj);
0431     aTriangleProjMax = Max(aTriangleProjMax, aTriangleProj);
0432 
0433     Standard_Real aFrustumProjMax = myMaxVertsProjections[aPlaneIdx];
0434     Standard_Real aFrustumProjMin = myMinVertsProjections[aPlaneIdx];
0435     if (aTriangleProjMin > aFrustumProjMax || aTriangleProjMax < aFrustumProjMin)
0436     {
0437       return Standard_False;
0438     }
0439   }
0440 
0441   theNormal = aTrEdges[2].Crossed(aTrEdges[0]);
0442   if (isSeparated(thePnt1, thePnt2, thePnt3, theNormal.XYZ()))
0443   {
0444     return Standard_False;
0445   }
0446 
0447   Standard_Integer aDirectionsNb = myCamera->IsOrthographic() ? 4 : 6;
0448   for (Standard_Integer aTriangleEdgeIdx = 0; aTriangleEdgeIdx < 3; ++aTriangleEdgeIdx)
0449   {
0450     for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
0451     {
0452       const gp_XYZ& aTestDirection = myEdgeDirs[aVolDir].XYZ().Crossed(aTrEdges[aTriangleEdgeIdx]);
0453 
0454       if (isSeparated(thePnt1, thePnt2, thePnt3, aTestDirection))
0455       {
0456         return Standard_False;
0457       }
0458     }
0459   }
0460   return Standard_True;
0461 }
0462 
0463 // =======================================================================
0464 // function : hasSphereOverlap
0465 // purpose  :
0466 // =======================================================================
0467 template <int N>
0468 Standard_Boolean SelectMgr_Frustum<N>::hasSphereOverlap(const gp_Pnt&       thePnt,
0469                                                         const Standard_Real theRadius,
0470                                                         Standard_Boolean*   theInside) const
0471 {
0472   Standard_Boolean       isOverlapFull = Standard_True;
0473   const Standard_Integer anIncFactor   = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0474   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N; aPlaneIdx += anIncFactor)
0475   {
0476     const gp_XYZ&       aPlane      = myPlanes[aPlaneIdx].XYZ();
0477     const Standard_Real aNormVecLen = Sqrt(aPlane.Dot(aPlane));
0478     const Standard_Real aCenterProj = aPlane.Dot(thePnt.XYZ()) / aNormVecLen;
0479     const Standard_Real aMaxDist    = myMaxVertsProjections[aPlaneIdx] / aNormVecLen;
0480     const Standard_Real aMinDist    = myMinVertsProjections[aPlaneIdx] / aNormVecLen;
0481     if (aCenterProj > (aMaxDist + theRadius) || aCenterProj < (aMinDist - theRadius))
0482     {
0483       return Standard_False; // fully separated
0484     }
0485     else if (theInside)
0486     {
0487       *theInside &= aCenterProj >= (aMinDist + theRadius) && aCenterProj <= (aMaxDist - theRadius);
0488     }
0489     isOverlapFull &= aCenterProj >= (aMinDist + theRadius) && aCenterProj <= (aMaxDist - theRadius);
0490   }
0491   if (theInside || isOverlapFull)
0492   {
0493     return Standard_True;
0494   }
0495   const gp_Vec aVecPlane1(myVertices[0], myVertices[2]);
0496   const gp_Vec aVecPlane2(myVertices[0], myVertices[2 * N - 2]);
0497   if (aVecPlane1.IsParallel(aVecPlane2, Precision::Angular()))
0498   {
0499     return Standard_False;
0500   }
0501   const gp_Dir               aNorm(aVecPlane1.Crossed(aVecPlane2));
0502   gp_Pnt                     aBoundariesCArr[5];
0503   NCollection_Array1<gp_Pnt> aBoundaries(aBoundariesCArr[0], 0, N);
0504   for (Standard_Integer anIdx = 0; anIdx < N * 2; anIdx += 2)
0505   {
0506     aBoundaries.SetValue(anIdx / 2, myVertices[anIdx]);
0507   }
0508   // distance from point(x,y,z) to plane(A,B,C,D) d = | Ax + By + Cz + D | / sqrt (A^2 + B^2 + C^2)
0509   // = aPnt.Dot (Norm) / 1
0510   const gp_Pnt     aCenterProj      = thePnt.XYZ() - aNorm.XYZ() * thePnt.XYZ().Dot(aNorm.XYZ());
0511   Standard_Boolean isBoundaryInside = Standard_False;
0512   return IsBoundaryIntersectSphere(aCenterProj, theRadius, aNorm, aBoundaries, isBoundaryInside);
0513 }
0514 
0515 // =======================================================================
0516 // function : IsDotInside
0517 // purpose  :
0518 // =======================================================================
0519 template <int N>
0520 Standard_Boolean SelectMgr_Frustum<N>::isDotInside(const gp_Pnt&             thePnt,
0521                                                    const TColgp_Array1OfPnt& theVertices) const
0522 {
0523   Standard_Real anAngle = 0.0;
0524   for (Standard_Integer aVertIdx = 0; aVertIdx < theVertices.Size(); aVertIdx++)
0525   {
0526     const gp_Pnt aVert1 = theVertices[aVertIdx];
0527     const gp_Pnt aVert2 =
0528       (aVertIdx == (theVertices.Size() - 1) ? theVertices[0] : theVertices[aVertIdx + 1]);
0529     const gp_Vec aVec1(thePnt, aVert1);
0530     const gp_Vec aVec2(thePnt, aVert2);
0531     anAngle += aVec1.Angle(aVec2);
0532   }
0533   if (Abs(anAngle - 2.0 * M_PI) < Precision::Angular())
0534   {
0535     return true;
0536   }
0537   return false;
0538 }
0539 
0540 // =======================================================================
0541 // function : isSegmentsIntersect
0542 // purpose  :
0543 // =======================================================================
0544 template <int N>
0545 Standard_Boolean SelectMgr_Frustum<N>::isSegmentsIntersect(const gp_Pnt& thePnt1Seg1,
0546                                                            const gp_Pnt& thePnt2Seg1,
0547                                                            const gp_Pnt& thePnt1Seg2,
0548                                                            const gp_Pnt& thePnt2Seg2) const
0549 {
0550   const gp_Mat aMatPln(thePnt2Seg1.X() - thePnt1Seg1.X(),
0551                        thePnt2Seg1.Y() - thePnt1Seg1.Y(),
0552                        thePnt2Seg1.Z() - thePnt1Seg1.Z(),
0553                        thePnt1Seg2.X() - thePnt1Seg1.X(),
0554                        thePnt1Seg2.Y() - thePnt1Seg1.Y(),
0555                        thePnt1Seg2.Z() - thePnt1Seg1.Z(),
0556                        thePnt2Seg2.X() - thePnt1Seg1.X(),
0557                        thePnt2Seg2.Y() - thePnt1Seg1.Y(),
0558                        thePnt2Seg2.Z() - thePnt1Seg1.Z());
0559   if (Abs(aMatPln.Determinant()) > Precision::Confusion())
0560   {
0561     return false;
0562   }
0563 
0564   Standard_Real aFst[4] = {thePnt1Seg1.X(), thePnt2Seg1.X(), thePnt1Seg2.X(), thePnt2Seg2.X()};
0565   Standard_Real aSnd[4] = {thePnt1Seg1.Y(), thePnt2Seg1.Y(), thePnt1Seg2.Y(), thePnt2Seg2.Y()};
0566   if (aFst[0] == aFst[2] && aFst[1] == aFst[3])
0567   {
0568     aFst[0] = thePnt1Seg1.Z();
0569     aFst[1] = thePnt2Seg1.Z();
0570     aFst[2] = thePnt1Seg2.Z();
0571     aFst[3] = thePnt2Seg2.Z();
0572   }
0573   if (aSnd[0] == aSnd[2] && aSnd[1] == aSnd[3])
0574   {
0575     aSnd[0] = thePnt1Seg1.Z();
0576     aSnd[1] = thePnt2Seg1.Z();
0577     aSnd[2] = thePnt1Seg2.Z();
0578     aSnd[3] = thePnt2Seg2.Z();
0579   }
0580   const gp_Mat2d aMat(gp_XY(aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
0581                       gp_XY(aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
0582 
0583   const gp_Mat2d aMatU(gp_XY(aFst[0] - aFst[2], aSnd[0] - aSnd[2]),
0584                        gp_XY(aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
0585 
0586   const gp_Mat2d aMatV(gp_XY(aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
0587                        gp_XY(aFst[0] - aFst[2], aSnd[0] - aSnd[2]));
0588   if (aMat.Determinant() == 0.0)
0589   {
0590     return false;
0591   }
0592 
0593   const Standard_Real anU = aMatU.Determinant() / aMat.Determinant();
0594   const Standard_Real aV  = aMatV.Determinant() / aMat.Determinant();
0595   if (anU >= 0.0 && anU <= 1.0 && aV >= 0.0 && aV <= 1.0)
0596   {
0597     return true;
0598   }
0599   return false;
0600 }
0601 
0602 // =======================================================================
0603 // function : isIntersectCircle
0604 // purpose  :
0605 // =======================================================================
0606 template <int N>
0607 Standard_Boolean SelectMgr_Frustum<N>::isIntersectCircle(
0608   const Standard_Real       theRadius,
0609   const gp_Pnt&             theCenter,
0610   const gp_Trsf&            theTrsf,
0611   const TColgp_Array1OfPnt& theVertices) const
0612 {
0613   const gp_Trsf aTrsfInv = theTrsf.Inverted();
0614   const gp_Dir  aRayDir  = gp_Dir(myEdgeDirs[N == 4 ? 4 : 0]).Transformed(aTrsfInv);
0615   if (aRayDir.Z() == 0.0)
0616   {
0617     return false;
0618   }
0619 
0620   for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
0621   {
0622     const gp_Pnt aPntStart  = theVertices.Value(anIdx).Transformed(aTrsfInv);
0623     const gp_Pnt aPntFinish = anIdx == theVertices.Upper()
0624                                 ? theVertices.Value(theVertices.Lower()).Transformed(aTrsfInv)
0625                                 : theVertices.Value(anIdx + 1).Transformed(aTrsfInv);
0626 
0627     // Project points on the end face plane
0628     const Standard_Real aParam1 = (theCenter.Z() - aPntStart.Z()) / aRayDir.Z();
0629     const Standard_Real aX1     = aPntStart.X() + aRayDir.X() * aParam1;
0630     const Standard_Real anY1    = aPntStart.Y() + aRayDir.Y() * aParam1;
0631 
0632     const Standard_Real aParam2 = (theCenter.Z() - aPntFinish.Z()) / aRayDir.Z();
0633     const Standard_Real aX2     = aPntFinish.X() + aRayDir.X() * aParam2;
0634     const Standard_Real anY2    = aPntFinish.Y() + aRayDir.Y() * aParam2;
0635 
0636     // Solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
0637     const Standard_Real anA = (aX1 - aX2) * (aX1 - aX2) + (anY1 - anY2) * (anY1 - anY2);
0638     const Standard_Real aK  = aX1 * (aX2 - aX1) + anY1 * (anY2 - anY1);
0639     const Standard_Real aC  = aX1 * aX1 + anY1 * anY1 - theRadius * theRadius;
0640 
0641     const Standard_Real aDiscr = aK * aK - anA * aC;
0642     if (aDiscr >= 0.0)
0643     {
0644       const Standard_Real aT1 = (-aK + Sqrt(aDiscr)) / anA;
0645       const Standard_Real aT2 = (-aK - Sqrt(aDiscr)) / anA;
0646       if ((aT1 >= 0 && aT1 <= 1) || (aT2 >= 0 && aT2 <= 1))
0647       {
0648         return true;
0649       }
0650     }
0651   }
0652   return false;
0653 }
0654 
0655 // =======================================================================
0656 // function : isInsideCylinderEndFace
0657 // purpose  :
0658 // =======================================================================
0659 template <int N>
0660 Standard_Boolean SelectMgr_Frustum<N>::isInsideCylinderEndFace(
0661   const Standard_Real       theBottomRad,
0662   const Standard_Real       theTopRad,
0663   const Standard_Real       theHeight,
0664   const gp_Trsf&            theTrsf,
0665   const TColgp_Array1OfPnt& theVertices) const
0666 {
0667   const gp_Trsf aTrsfInv = theTrsf.Inverted();
0668   const gp_Dir  aRayDir  = gp_Dir(myEdgeDirs[N == 4 ? 4 : 0]).Transformed(aTrsfInv);
0669   if (aRayDir.Z() == 0.0)
0670   {
0671     return false;
0672   }
0673 
0674   for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
0675   {
0676     const gp_Pnt aLoc = theVertices.Value(anIdx).Transformed(aTrsfInv);
0677 
0678     const Standard_Real aTime1 = (0 - aLoc.Z()) / aRayDir.Z();
0679     const Standard_Real aX1    = aLoc.X() + aRayDir.X() * aTime1;
0680     const Standard_Real anY1   = aLoc.Y() + aRayDir.Y() * aTime1;
0681 
0682     const Standard_Real aTime2 = (theHeight - aLoc.Z()) / aRayDir.Z();
0683     const Standard_Real aX2    = aLoc.X() + aRayDir.X() * aTime2;
0684     const Standard_Real anY2   = aLoc.Y() + aRayDir.Y() * aTime2;
0685 
0686     if (aX1 * aX1 + anY1 * anY1 <= theBottomRad * theBottomRad
0687         && aX2 * aX2 + anY2 * anY2 <= theTopRad * theTopRad)
0688     {
0689       continue;
0690     }
0691 
0692     return false;
0693   }
0694   return true;
0695 }
0696 
0697 // =======================================================================
0698 // function : hasCylinderOverlap
0699 // purpose  :
0700 // =======================================================================
0701 template <int N>
0702 Standard_Boolean SelectMgr_Frustum<N>::hasCylinderOverlap(const Standard_Real    theBottomRad,
0703                                                           const Standard_Real    theTopRad,
0704                                                           const Standard_Real    theHeight,
0705                                                           const gp_Trsf&         theTrsf,
0706                                                           const Standard_Boolean theIsHollow,
0707                                                           Standard_Boolean*      theInside) const
0708 {
0709   gp_Pnt                 aVerticesBuf[N];
0710   TColgp_Array1OfPnt     aVertices(aVerticesBuf[0], 0, N - 1);
0711   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0712   if (anIncFactor == 2)
0713   {
0714     const Standard_Integer anIndices[] = {0, 2, 6, 4};
0715     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0716     {
0717       aVertices.SetValue(anIdx, myVertices[anIndices[anIdx]]);
0718     }
0719   }
0720   else
0721   {
0722     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0723     {
0724       aVertices.SetValue(anIdx, myVertices[anIdx]);
0725     }
0726   }
0727 
0728   if (theIsHollow
0729       && isInsideCylinderEndFace(theBottomRad, theTopRad, theHeight, theTrsf, aVertices))
0730   {
0731     if (theInside != NULL)
0732     {
0733       *theInside = false;
0734     }
0735     return false;
0736   }
0737 
0738   const gp_Dir aCylNorm(gp::DZ().Transformed(theTrsf));
0739   const gp_Pnt aBottomCenter(gp::Origin().Transformed(theTrsf));
0740   const gp_Pnt aTopCenter = aBottomCenter.XYZ() + aCylNorm.XYZ() * theHeight;
0741 
0742   const gp_Dir  aViewRayDir = gp_Dir(myEdgeDirs[N == 4 ? 4 : 0]);
0743   const gp_Pln  aPln(myVertices[0], aViewRayDir);
0744   Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
0745   aPln.Coefficients(aCoefA, aCoefB, aCoefC, aCoefD);
0746 
0747   const Standard_Real aTBottom = -(aBottomCenter.XYZ().Dot(aViewRayDir.XYZ()) + aCoefD);
0748   const gp_Pnt        aBottomCenterProject(aCoefA * aTBottom + aBottomCenter.X(),
0749                                     aCoefB * aTBottom + aBottomCenter.Y(),
0750                                     aCoefC * aTBottom + aBottomCenter.Z());
0751   const Standard_Real aTTop = -(aTopCenter.XYZ().Dot(aViewRayDir.XYZ()) + aCoefD);
0752   const gp_Pnt        aTopCenterProject(aCoefA * aTTop + aTopCenter.X(),
0753                                  aCoefB * aTTop + aTopCenter.Y(),
0754                                  aCoefC * aTTop + aTopCenter.Z());
0755   gp_Vec              aCylNormProject(0, 0, 0);
0756   if (aTopCenterProject.Distance(aBottomCenterProject) > 0.0)
0757   {
0758     aCylNormProject = gp_Vec((aTopCenterProject.XYZ() - aBottomCenterProject.XYZ())
0759                              / aTopCenterProject.Distance(aBottomCenterProject));
0760   }
0761 
0762   gp_Pnt       aPoints[6];
0763   const gp_Dir aDirEndFaces = (aCylNorm.IsParallel(aViewRayDir, Precision::Angular()))
0764                                 ? gp::DY().Transformed(theTrsf)
0765                                 : aCylNorm.Crossed(aViewRayDir);
0766 
0767   const Standard_Real anAngle = aCylNorm.Angle(aViewRayDir);
0768   aPoints[0] =
0769     aBottomCenterProject.XYZ() - aCylNormProject.XYZ() * theBottomRad * Abs(Cos(anAngle));
0770   aPoints[1] = aBottomCenterProject.XYZ() + aDirEndFaces.XYZ() * theBottomRad;
0771   aPoints[2] = aTopCenterProject.XYZ() + aDirEndFaces.XYZ() * theTopRad;
0772   aPoints[3] = aTopCenterProject.XYZ() + aCylNormProject.XYZ() * theTopRad * Abs(Cos(anAngle));
0773   aPoints[4] = aTopCenterProject.XYZ() - aDirEndFaces.XYZ() * theTopRad;
0774   aPoints[5] = aBottomCenterProject.XYZ() - aDirEndFaces.XYZ() * theBottomRad;
0775   const TColgp_Array1OfPnt aPointsArr(aPoints[0], 0, 5);
0776 
0777   for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0778   {
0779     if ((aCylNormProject.Dot(aCylNormProject) == 0.0
0780          && aVertices.Value(anIdx).Distance(aPoints[0]) <= Max(theTopRad, theBottomRad))
0781         || isDotInside(aVertices.Value(anIdx), aPointsArr))
0782     {
0783       if (theInside != NULL)
0784       {
0785         *theInside = false;
0786       }
0787       return true;
0788     }
0789   }
0790 
0791   for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
0792   {
0793     const gp_Pnt aPnt1Seg = aVertices[anIdx];
0794     const gp_Pnt aPnt2Seg =
0795       (anIdx == aVertices.Upper()) ? aVertices[aVertices.Lower()] : aVertices[anIdx + 1];
0796     if (isSegmentsIntersect(aPoints[1], aPoints[2], aPnt1Seg, aPnt2Seg)
0797         || isSegmentsIntersect(aPoints[4], aPoints[5], aPnt1Seg, aPnt2Seg)
0798         || isSegmentsIntersect(aPoints[4], aPoints[2], aPnt1Seg, aPnt2Seg)
0799         || isSegmentsIntersect(aPoints[1], aPoints[5], aPnt1Seg, aPnt2Seg))
0800     {
0801       if (theInside != NULL)
0802       {
0803         *theInside = false;
0804       }
0805       return true;
0806     }
0807   }
0808 
0809   if (!theIsHollow
0810       && (isIntersectCircle(theBottomRad, gp_Pnt(0, 0, 0), theTrsf, aVertices)
0811           || isIntersectCircle(theTopRad, gp_Pnt(0, 0, theHeight), theTrsf, aVertices)))
0812   {
0813     if (theInside != NULL)
0814     {
0815       *theInside = false;
0816     }
0817     return true;
0818   }
0819   bool isCylInsideRec = true;
0820   for (int i = 0; i < 6; ++i)
0821   {
0822     isCylInsideRec &= isDotInside(aPoints[i], aVertices);
0823   }
0824   if (theInside != NULL)
0825   {
0826     *theInside &= isCylInsideRec;
0827   }
0828   return isCylInsideRec;
0829 }
0830 
0831 // =======================================================================
0832 // function : hasCircleOverlap
0833 // purpose  :
0834 // =======================================================================
0835 template <int N>
0836 Standard_Boolean SelectMgr_Frustum<N>::hasCircleOverlap(const Standard_Real    theRadius,
0837                                                         const gp_Trsf&         theTrsf,
0838                                                         const Standard_Boolean theIsFilled,
0839                                                         Standard_Boolean*      theInside) const
0840 {
0841   gp_Pnt                 aVerticesBuf[N];
0842   TColgp_Array1OfPnt     aVertices(aVerticesBuf[0], 0, N - 1);
0843   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0844   if (anIncFactor == 2)
0845   {
0846     const Standard_Integer anIndices[] = {0, 2, 6, 4};
0847     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0848     {
0849       aVertices.SetValue(anIdx, myVertices[anIndices[anIdx]]);
0850     }
0851   }
0852   else
0853   {
0854     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0855     {
0856       aVertices.SetValue(anIdx, myVertices[anIdx]);
0857     }
0858   }
0859 
0860   if (isIntersectCircle(theRadius, gp_Pnt(0, 0, 0), theTrsf, aVertices))
0861   {
0862     if (theInside != NULL)
0863     {
0864       *theInside = false;
0865     }
0866     return true;
0867   }
0868 
0869   gp_Pnt        aCircCenter = gp::Origin(); //.Transformed (theTrsf);
0870   const gp_Dir  aViewRayDir = gp_Dir(myEdgeDirs[N == 4 ? 4 : 0]);
0871   const gp_Pln  aPln(myVertices[0], aViewRayDir);
0872   Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
0873   aPln.Coefficients(aCoefA, aCoefB, aCoefC, aCoefD);
0874 
0875   const Standard_Real aTCenter = -(aCircCenter.XYZ().Dot(aViewRayDir.XYZ()) + aCoefD);
0876   const gp_Pnt        aCenterProject(aCoefA * aTCenter, aCoefB * aTCenter, aCoefC * aTCenter);
0877 
0878   const Standard_Boolean isCenterInside = isDotInside(aCenterProject, aVertices);
0879 
0880   Standard_Boolean isInside = false;
0881   for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
0882   {
0883     if (aVertices.Value(anIdx).Distance(aCenterProject) > theRadius)
0884     {
0885       isInside = true;
0886       break;
0887     }
0888   }
0889 
0890   if (theInside != NULL)
0891   {
0892     *theInside = isInside && isCenterInside;
0893   }
0894 
0895   return theIsFilled ? !isInside || (isCenterInside && isInside) : isInside && isCenterInside;
0896 }
0897 
0898 //=======================================================================
0899 // function : DumpJson
0900 // purpose  :
0901 //=======================================================================
0902 template <int N>
0903 void SelectMgr_Frustum<N>::DumpJson(Standard_OStream& theOStream, Standard_Integer theDepth) const
0904 {
0905   OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream)
0906 
0907   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0908   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0909   {
0910     const gp_Vec& aPlane = myPlanes[aPlaneIdx];
0911     OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &aPlane)
0912 
0913     OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myMaxVertsProjections[aPlaneIdx])
0914     OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myMinVertsProjections[aPlaneIdx])
0915   }
0916 
0917   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0918   {
0919     const gp_Pnt& aVertex = myVertices[aVertIdx];
0920     OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &aVertex)
0921   }
0922 
0923   OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myPixelTolerance)
0924   OCCT_DUMP_FIELD_VALUE_POINTER(theOStream, myBuilder)
0925   OCCT_DUMP_FIELD_VALUE_POINTER(theOStream, myCamera)
0926 
0927   for (Standard_Integer anIndex = 0; anIndex < 3; anIndex++)
0928   {
0929     Standard_Real aMaxOrthoVertsProjections = myMaxOrthoVertsProjections[anIndex];
0930     Standard_Real aMinOrthoVertsProjections = myMinOrthoVertsProjections[anIndex];
0931 
0932     OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, aMaxOrthoVertsProjections)
0933     OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, aMinOrthoVertsProjections)
0934   }
0935 
0936   for (Standard_Integer anIndex = 0; anIndex < 6; anIndex++)
0937   {
0938     const gp_Vec& anEdgeDir = myEdgeDirs[anIndex];
0939     OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, &anEdgeDir)
0940   }
0941 }