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; aVolDir < aDirectionsNb; ++aVolDir)
0186     {
0187       gp_XYZ aDirection (DBL_MAX, DBL_MAX, DBL_MAX);
0188       aDirection.ChangeData()[aDim]      = 0;
0189       aDirection.ChangeData()[aNext]     = -myEdgeDirs[aVolDir].XYZ().GetData()[aNextNext];
0190       aDirection.ChangeData()[aNextNext] = myEdgeDirs[aVolDir].XYZ().GetData()[aNext];
0191 
0192       if (isSeparated (theMinPnt, theMaxPnt, aDirection, theInside))
0193       {
0194         return Standard_False;
0195       }
0196     }
0197   }
0198 
0199   return Standard_True;
0200 }
0201 
0202 // =======================================================================
0203 // function : hasPointOverlap
0204 // purpose  : SAT intersection test between defined volume and given point
0205 // =======================================================================
0206 template <int N>
0207 Standard_Boolean SelectMgr_Frustum<N>::hasPointOverlap (const gp_Pnt& thePnt) const
0208 {
0209   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0210   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0211   {
0212     const Standard_Real aPointProj = myPlanes[aPlaneIdx].XYZ().Dot (thePnt.XYZ());
0213 
0214     if (aPointProj > myMaxVertsProjections[aPlaneIdx]
0215      || aPointProj < myMinVertsProjections[aPlaneIdx])
0216     {
0217       return Standard_False;
0218     }
0219   }
0220 
0221   return Standard_True;
0222 }
0223 
0224 // =======================================================================
0225 // function : hasSegmentOverlap
0226 // purpose  : SAT intersection test between defined volume and given segment
0227 // =======================================================================
0228 template <int N>
0229 Standard_Boolean SelectMgr_Frustum<N>::hasSegmentOverlap (const gp_Pnt& theStartPnt,
0230                                                           const gp_Pnt& theEndPnt) const
0231 {
0232   const gp_XYZ& aDir = theEndPnt.XYZ() - theStartPnt.XYZ();
0233   if (aDir.Modulus() < Precision::Confusion())
0234     return Standard_True;
0235 
0236   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0237   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0238   {
0239     Standard_Real aMinSegm = RealLast(), aMaxSegm = RealFirst();
0240     Standard_Real aMinF    = RealLast(), aMaxF    = RealFirst();
0241 
0242     Standard_Real aProj1 = myPlanes[aPlaneIdx].XYZ().Dot (theStartPnt.XYZ());
0243     Standard_Real aProj2 = myPlanes[aPlaneIdx].XYZ().Dot (theEndPnt.XYZ());
0244     aMinSegm = Min (aProj1, aProj2);
0245     aMaxSegm = Max (aProj1, aProj2);
0246 
0247     aMaxF = myMaxVertsProjections[aPlaneIdx];
0248     aMinF = myMinVertsProjections[aPlaneIdx];
0249 
0250     if (aMinSegm > aMaxF
0251       || aMaxSegm < aMinF)
0252     {
0253       return Standard_False;
0254     }
0255   }
0256 
0257   Standard_Real aMin1 = DBL_MAX, aMax1 = -DBL_MAX;
0258   Standard_Real aMin2 = DBL_MAX, aMax2 = -DBL_MAX;
0259   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0260   {
0261     Standard_Real aProjection = aDir.Dot (myVertices[aVertIdx].XYZ());
0262     aMax2 = Max (aMax2, aProjection);
0263     aMin2 = Min (aMin2, aProjection);
0264   }
0265   Standard_Real aProj1 = aDir.Dot (theStartPnt.XYZ());
0266   Standard_Real aProj2 = aDir.Dot (theEndPnt.XYZ());
0267   aMin1 = Min (aProj1, aProj2);
0268   aMax1 = Max (aProj1, aProj2);
0269   if (aMin1 > aMax2
0270     || 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
0296       || aMaxSegm < aMinF)
0297     {
0298       return Standard_False;
0299     }
0300   }
0301 
0302   return Standard_True;
0303 }
0304 
0305 // =======================================================================
0306 // function : hasPolygonOverlap
0307 // purpose  : SAT intersection test between frustum given and planar convex
0308 //            polygon represented as ordered point set
0309 // =======================================================================
0310 template <int N>
0311 Standard_Boolean SelectMgr_Frustum<N>::hasPolygonOverlap (const TColgp_Array1OfPnt& theArrayOfPnts,
0312                                                           gp_Vec& theNormal) const
0313 {
0314   Standard_Integer aStartIdx = theArrayOfPnts.Lower();
0315   Standard_Integer anEndIdx = theArrayOfPnts.Upper();
0316 
0317   const gp_XYZ& aPnt1 = theArrayOfPnts.Value (aStartIdx).XYZ();
0318   const gp_XYZ& aPnt2 = theArrayOfPnts.Value (aStartIdx + 1).XYZ();
0319   const gp_XYZ& aPnt3 = theArrayOfPnts.Value (aStartIdx + 2).XYZ();
0320   const gp_XYZ aVec1 = aPnt1 - aPnt2;
0321   const gp_XYZ aVec2 = aPnt3 - aPnt2;
0322   theNormal = aVec2.Crossed (aVec1);
0323   const gp_XYZ& aNormal = theNormal.XYZ();
0324   Standard_Real aPolygProjection = aNormal.Dot (aPnt1);
0325 
0326   Standard_Real aMax = RealFirst();
0327   Standard_Real aMin = RealLast();
0328   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0329   {
0330     Standard_Real aProjection = aNormal.Dot (myVertices[aVertIdx].XYZ());
0331     aMax = Max (aMax, aProjection);
0332     aMin = Min (aMin, aProjection);
0333   }
0334   if (aPolygProjection > aMax
0335     || aPolygProjection < aMin)
0336   {
0337     return Standard_False;
0338   }
0339 
0340   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0341   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx <  N + 1; aPlaneIdx += anIncFactor)
0342   {
0343     Standard_Real aMaxF = RealFirst();
0344     Standard_Real aMinF = RealLast();
0345     Standard_Real aMaxPolyg = RealFirst();
0346     Standard_Real aMinPolyg = RealLast();
0347     const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
0348     for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
0349     {
0350       Standard_Real aProjection = aPlane.Dot (theArrayOfPnts.Value (aPntIter).XYZ());
0351       aMaxPolyg = Max (aMaxPolyg, aProjection);
0352       aMinPolyg = Min (aMinPolyg, aProjection);
0353     }
0354     aMaxF = myMaxVertsProjections[aPlaneIdx];
0355     aMinF = myMinVertsProjections[aPlaneIdx];
0356     if (aMinPolyg > aMaxF
0357       || aMaxPolyg < aMinF)
0358     {
0359       return Standard_False;
0360     }
0361   }
0362 
0363   Standard_Integer aDirectionsNb = Camera()->IsOrthographic() ? 4 : 6;
0364   for (Standard_Integer aPntsIter = 0, aLastIdx = anEndIdx - aStartIdx, aLen = theArrayOfPnts.Length(); aPntsIter <= aLastIdx; ++aPntsIter)
0365   {
0366     const gp_XYZ aSegmDir = theArrayOfPnts.Value ((aPntsIter + 1) % aLen + aStartIdx).XYZ()
0367       - theArrayOfPnts.Value (aPntsIter + aStartIdx).XYZ();
0368     for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
0369     {
0370       Standard_Real aMaxPolyg = RealFirst();
0371       Standard_Real aMinPolyg = RealLast();
0372       Standard_Real aMaxF = RealFirst();
0373       Standard_Real aMinF = RealLast();
0374       const gp_XYZ aTestDir = aSegmDir.Crossed (myEdgeDirs[aVolDir].XYZ());
0375 
0376       for (Standard_Integer aPntIter = aStartIdx; aPntIter <= anEndIdx; ++aPntIter)
0377       {
0378         Standard_Real aProjection = aTestDir.Dot (theArrayOfPnts.Value (aPntIter).XYZ());
0379         aMaxPolyg = Max (aMaxPolyg, aProjection);
0380         aMinPolyg = Min (aMinPolyg, aProjection);
0381       }
0382 
0383       for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0384       {
0385         Standard_Real aProjection = aTestDir.Dot (myVertices[aVertIdx].XYZ());
0386         aMaxF = Max (aMaxF, aProjection);
0387         aMinF = Min (aMinF, aProjection);
0388       }
0389 
0390       if (aMinPolyg > aMaxF
0391         || 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
0436       || aTriangleProjMax < aFrustumProjMin)
0437     {
0438       return Standard_False;
0439     }
0440   }
0441 
0442   theNormal = aTrEdges[2].Crossed (aTrEdges[0]);
0443   if (isSeparated (thePnt1, thePnt2, thePnt3, theNormal.XYZ()))
0444   {
0445     return Standard_False;
0446   }
0447 
0448   Standard_Integer aDirectionsNb = myCamera->IsOrthographic() ? 4 : 6;
0449   for (Standard_Integer aTriangleEdgeIdx = 0; aTriangleEdgeIdx < 3; ++aTriangleEdgeIdx)
0450   {
0451     for (Standard_Integer aVolDir = 0; aVolDir < aDirectionsNb; ++aVolDir)
0452     {
0453       const gp_XYZ& aTestDirection =  myEdgeDirs[aVolDir].XYZ().Crossed (aTrEdges[aTriangleEdgeIdx]);
0454 
0455       if (isSeparated (thePnt1, thePnt2, thePnt3, aTestDirection))
0456       {
0457         return Standard_False;
0458       }
0459     }
0460   }
0461   return Standard_True;
0462 }
0463 
0464 // =======================================================================
0465 // function : hasSphereOverlap
0466 // purpose  :
0467 // =======================================================================
0468 template <int N>
0469 Standard_Boolean SelectMgr_Frustum<N>::hasSphereOverlap (const gp_Pnt& thePnt,
0470                                                          const Standard_Real theRadius,
0471                                                          Standard_Boolean* theInside) const
0472 {
0473   Standard_Boolean isOverlapFull = Standard_True;
0474   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0475   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N; aPlaneIdx += anIncFactor)
0476   {
0477     const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
0478     const Standard_Real aNormVecLen = Sqrt (aPlane.Dot (aPlane));
0479     const Standard_Real aCenterProj = aPlane.Dot (thePnt.XYZ()) / aNormVecLen;
0480     const Standard_Real aMaxDist = myMaxVertsProjections[aPlaneIdx] / aNormVecLen;
0481     const Standard_Real aMinDist = myMinVertsProjections[aPlaneIdx] / aNormVecLen;
0482     if (aCenterProj > (aMaxDist + theRadius)
0483      || aCenterProj < (aMinDist - theRadius))
0484     {
0485       return Standard_False; // fully separated
0486     }
0487     else if (theInside)
0488     {
0489       *theInside &= aCenterProj >= (aMinDist + theRadius)
0490                  && aCenterProj <= (aMaxDist - theRadius);
0491     }
0492     isOverlapFull &= aCenterProj >= (aMinDist + theRadius)
0493                   && aCenterProj <= (aMaxDist - theRadius);
0494   }
0495   if (theInside || isOverlapFull)
0496   {
0497     return Standard_True;
0498   }
0499   const gp_Vec aVecPlane1 (myVertices[0], myVertices[2]);
0500   const gp_Vec aVecPlane2 (myVertices[0], myVertices[2 * N - 2]);
0501   if (aVecPlane1.IsParallel (aVecPlane2, Precision::Angular()))
0502   {
0503     return Standard_False;
0504   }
0505   const gp_Dir aNorm (aVecPlane1.Crossed (aVecPlane2));
0506   gp_Pnt aBoundariesCArr[5];
0507   NCollection_Array1<gp_Pnt> aBoundaries (aBoundariesCArr[0], 0, N);
0508   for (Standard_Integer anIdx = 0; anIdx < N * 2; anIdx += 2)
0509   {
0510     aBoundaries.SetValue (anIdx / 2, myVertices[anIdx]);
0511   }
0512   // 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
0513   const gp_Pnt aCenterProj = thePnt.XYZ() - aNorm.XYZ() * thePnt.XYZ().Dot (aNorm.XYZ());
0514   Standard_Boolean isBoundaryInside = Standard_False;
0515   return IsBoundaryIntersectSphere (aCenterProj, theRadius, aNorm, aBoundaries, isBoundaryInside);
0516 }
0517 
0518 // =======================================================================
0519 // function : IsDotInside
0520 // purpose  :
0521 // =======================================================================
0522 template<int N>
0523 Standard_Boolean SelectMgr_Frustum<N>::isDotInside (const gp_Pnt& thePnt,
0524                                                     const TColgp_Array1OfPnt& theVertices) const
0525 {
0526   Standard_Real anAngle = 0.0;
0527   for (Standard_Integer aVertIdx = 0; aVertIdx < theVertices.Size(); aVertIdx++)
0528   {
0529     const gp_Pnt aVert1 = theVertices[aVertIdx];
0530     const gp_Pnt aVert2 = (aVertIdx == (theVertices.Size() - 1) ? theVertices[0] : theVertices[aVertIdx + 1]);
0531     const gp_Vec aVec1 (thePnt, aVert1);
0532     const gp_Vec aVec2 (thePnt, aVert2);
0533     anAngle += aVec1.Angle (aVec2);
0534   }
0535   if (Abs (anAngle - 2.0 * M_PI) < Precision::Angular())
0536   {
0537     return true;
0538   }
0539   return false;
0540 }
0541 
0542 // =======================================================================
0543 // function : isSegmentsIntersect
0544 // purpose  :
0545 // =======================================================================
0546 template<int N>
0547 Standard_Boolean SelectMgr_Frustum<N>::isSegmentsIntersect (const gp_Pnt& thePnt1Seg1,
0548                                                             const gp_Pnt& thePnt2Seg1,
0549                                                             const gp_Pnt& thePnt1Seg2,
0550                                                             const gp_Pnt& thePnt2Seg2) const
0551 {
0552   const gp_Mat aMatPln (thePnt2Seg1.X() - thePnt1Seg1.X(), thePnt2Seg1.Y() - thePnt1Seg1.Y(), thePnt2Seg1.Z() - thePnt1Seg1.Z(),
0553                         thePnt1Seg2.X() - thePnt1Seg1.X(), thePnt1Seg2.Y() - thePnt1Seg1.Y(), thePnt1Seg2.Z() - thePnt1Seg1.Z(),
0554                         thePnt2Seg2.X() - thePnt1Seg1.X(), thePnt2Seg2.Y() - thePnt1Seg1.Y(), thePnt2Seg2.Z() - thePnt1Seg1.Z());
0555   if (Abs (aMatPln.Determinant()) > Precision::Confusion())
0556   {
0557     return false;
0558   }
0559 
0560   Standard_Real aFst[4] = {thePnt1Seg1.X(), thePnt2Seg1.X(), thePnt1Seg2.X(), thePnt2Seg2.X()};
0561   Standard_Real aSnd[4] = {thePnt1Seg1.Y(), thePnt2Seg1.Y(), thePnt1Seg2.Y(), thePnt2Seg2.Y()};
0562   if (aFst[0] == aFst[2] && aFst[1] == aFst[3])
0563   {
0564     aFst[0] = thePnt1Seg1.Z();
0565     aFst[1] = thePnt2Seg1.Z();
0566     aFst[2] = thePnt1Seg2.Z();
0567     aFst[3] = thePnt2Seg2.Z();
0568   }
0569   if (aSnd[0] == aSnd[2]
0570    && aSnd[1] == aSnd[3])
0571   {
0572     aSnd[0] = thePnt1Seg1.Z();
0573     aSnd[1] = thePnt2Seg1.Z();
0574     aSnd[2] = thePnt1Seg2.Z();
0575     aSnd[3] = thePnt2Seg2.Z();
0576   }
0577   const gp_Mat2d aMat (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
0578                        gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
0579 
0580   const gp_Mat2d aMatU (gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]),
0581                         gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
0582 
0583   const gp_Mat2d aMatV (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
0584                         gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]));
0585   if (aMat.Determinant() == 0.0)
0586   {
0587     return false;
0588   }
0589 
0590   const Standard_Real anU = aMatU.Determinant() / aMat.Determinant();
0591   const Standard_Real aV  = aMatV.Determinant() / aMat.Determinant();
0592   if (anU >= 0.0 && anU <= 1.0
0593    && aV  >= 0.0 && aV  <= 1.0)
0594   {
0595     return true;
0596   }
0597   return false;
0598 }
0599 
0600 // =======================================================================
0601 // function : isIntersectCircle
0602 // purpose  :
0603 // =======================================================================
0604 template<int N>
0605 Standard_Boolean SelectMgr_Frustum<N>::isIntersectCircle (const Standard_Real theRadius,
0606                                                           const gp_Pnt& theCenter,
0607                                                           const gp_Trsf& theTrsf,
0608                                                           const TColgp_Array1OfPnt& theVertices) const
0609 {
0610   const gp_Trsf aTrsfInv = theTrsf.Inverted();
0611   const gp_Dir aRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]).Transformed (aTrsfInv);
0612   if (aRayDir.Z() == 0.0)
0613   {
0614     return false;
0615   }
0616 
0617   for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
0618   {
0619     const gp_Pnt aPntStart = theVertices.Value (anIdx).Transformed (aTrsfInv);
0620     const gp_Pnt aPntFinish = anIdx == theVertices.Upper()
0621                             ? theVertices.Value (theVertices.Lower()).Transformed (aTrsfInv)
0622                             : theVertices.Value (anIdx + 1).Transformed (aTrsfInv);
0623 
0624     // Project points on the end face plane
0625     const Standard_Real aParam1 = (theCenter.Z() - aPntStart.Z()) / aRayDir.Z();
0626     const Standard_Real aX1 = aPntStart.X() + aRayDir.X() * aParam1;
0627     const Standard_Real anY1 = aPntStart.Y() + aRayDir.Y() * aParam1;
0628 
0629     const Standard_Real aParam2 = (theCenter.Z() - aPntFinish.Z()) / aRayDir.Z();
0630     const Standard_Real aX2 = aPntFinish.X() + aRayDir.X() * aParam2;
0631     const Standard_Real anY2 = aPntFinish.Y() + aRayDir.Y() * aParam2;
0632 
0633     // Solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
0634     const Standard_Real anA = (aX1 - aX2) * (aX1 - aX2) + (anY1 - anY2) * (anY1 - anY2);
0635     const Standard_Real aK = aX1 * (aX2 - aX1) + anY1 * (anY2 - anY1);
0636     const Standard_Real aC = aX1 * aX1 + anY1 * anY1 - theRadius * theRadius;
0637 
0638     const Standard_Real aDiscr = aK * aK - anA * aC;
0639     if (aDiscr >= 0.0)
0640     {
0641       const Standard_Real aT1 = (-aK + Sqrt (aDiscr)) / anA;
0642       const Standard_Real aT2 = (-aK - Sqrt (aDiscr)) / anA;
0643       if ((aT1 >= 0 && aT1 <= 1) || (aT2 >= 0 && aT2 <= 1))
0644       {
0645         return true;
0646       }
0647     }
0648   }
0649   return false;
0650 }
0651 
0652 // =======================================================================
0653 // function : isInsideCylinderEndFace
0654 // purpose  :
0655 // =======================================================================
0656 template<int N>
0657 Standard_Boolean SelectMgr_Frustum<N>::isInsideCylinderEndFace (const Standard_Real theBottomRad,
0658                                                                 const Standard_Real theTopRad,
0659                                                                 const Standard_Real theHeight,
0660                                                                 const gp_Trsf& theTrsf,
0661                                                                 const TColgp_Array1OfPnt& theVertices) const
0662 {
0663   const gp_Trsf aTrsfInv = theTrsf.Inverted();
0664   const gp_Dir aRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]).Transformed (aTrsfInv);
0665   if (aRayDir.Z() == 0.0)
0666   {
0667     return false;
0668   }
0669 
0670   for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
0671   {
0672     const gp_Pnt aLoc = theVertices.Value (anIdx).Transformed (aTrsfInv);
0673 
0674     const Standard_Real aTime1 = (0 - aLoc.Z()) / aRayDir.Z();
0675     const Standard_Real aX1 = aLoc.X() + aRayDir.X() * aTime1;
0676     const Standard_Real anY1 = aLoc.Y() + aRayDir.Y() * aTime1;
0677 
0678     const Standard_Real aTime2 = (theHeight - aLoc.Z()) / aRayDir.Z();
0679     const Standard_Real aX2 = aLoc.X() + aRayDir.X() * aTime2;
0680     const Standard_Real anY2 = aLoc.Y() + aRayDir.Y() * aTime2;
0681 
0682     if (aX1 * aX1 + anY1 * anY1 <= theBottomRad * theBottomRad
0683      && aX2 * aX2 + anY2 * anY2 <= theTopRad * theTopRad)
0684     {
0685       continue;
0686     }
0687 
0688     return false;
0689   }
0690   return true;
0691 }
0692 
0693 // =======================================================================
0694 // function : hasCylinderOverlap
0695 // purpose  :
0696 // =======================================================================
0697 template<int N>
0698 Standard_Boolean SelectMgr_Frustum<N>::hasCylinderOverlap (const Standard_Real theBottomRad,
0699                                                            const Standard_Real theTopRad,
0700                                                            const Standard_Real theHeight,
0701                                                            const gp_Trsf& theTrsf,
0702                                                            const Standard_Boolean theIsHollow,
0703                                                            Standard_Boolean* theInside) const
0704 {
0705   gp_Pnt aVerticesBuf[N];
0706   TColgp_Array1OfPnt aVertices (aVerticesBuf[0], 0, N - 1);
0707   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0708   if (anIncFactor == 2)
0709   {
0710     const Standard_Integer anIndices[] = { 0, 2, 6, 4 };
0711     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0712     {
0713       aVertices.SetValue (anIdx, myVertices[anIndices[anIdx]]);
0714     }
0715   }
0716   else
0717   {
0718     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0719     {
0720       aVertices.SetValue (anIdx, myVertices[anIdx]);
0721     }
0722   }
0723 
0724   if (theIsHollow && isInsideCylinderEndFace (theBottomRad, theTopRad, theHeight, theTrsf, aVertices))
0725   {
0726     if (theInside != NULL)
0727     {
0728       *theInside = false;
0729     }
0730     return false;
0731   }
0732 
0733   const gp_Dir aCylNorm (gp::DZ().Transformed (theTrsf));
0734   const gp_Pnt aBottomCenter (gp::Origin().Transformed (theTrsf));
0735   const gp_Pnt aTopCenter = aBottomCenter.XYZ() + aCylNorm.XYZ() * theHeight;
0736 
0737   const gp_Dir aViewRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]);
0738   const gp_Pln aPln (myVertices[0], aViewRayDir);
0739   Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
0740   aPln.Coefficients (aCoefA, aCoefB, aCoefC, aCoefD);
0741 
0742   const Standard_Real aTBottom = -(aBottomCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
0743   const gp_Pnt aBottomCenterProject (aCoefA * aTBottom + aBottomCenter.X(),
0744                                      aCoefB * aTBottom + aBottomCenter.Y(),
0745                                      aCoefC * aTBottom + aBottomCenter.Z());
0746   const Standard_Real aTTop = -(aTopCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
0747   const gp_Pnt aTopCenterProject (aCoefA * aTTop + aTopCenter.X(),
0748                                   aCoefB * aTTop + aTopCenter.Y(),
0749                                   aCoefC * aTTop + aTopCenter.Z());
0750   gp_Vec aCylNormProject (0, 0, 0);
0751   if (aTopCenterProject.Distance (aBottomCenterProject)  > 0.0)
0752   {
0753     aCylNormProject = gp_Vec ((aTopCenterProject.XYZ() - aBottomCenterProject.XYZ())
0754                              / aTopCenterProject.Distance (aBottomCenterProject));
0755   }
0756 
0757   gp_Pnt aPoints[6];
0758   const gp_Dir aDirEndFaces = (aCylNorm.IsParallel (aViewRayDir, Precision::Angular()))
0759                              ? gp::DY().Transformed (theTrsf)
0760                              : aCylNorm.Crossed (aViewRayDir);
0761 
0762   const Standard_Real anAngle = aCylNorm.Angle (aViewRayDir);
0763   aPoints[0] = aBottomCenterProject.XYZ() - aCylNormProject.XYZ() * theBottomRad * Abs (Cos (anAngle));
0764   aPoints[1] = aBottomCenterProject.XYZ() + aDirEndFaces.XYZ() * theBottomRad;
0765   aPoints[2] = aTopCenterProject.XYZ() + aDirEndFaces.XYZ() * theTopRad;
0766   aPoints[3] = aTopCenterProject.XYZ() + aCylNormProject.XYZ() * theTopRad * Abs (Cos (anAngle));
0767   aPoints[4] = aTopCenterProject.XYZ() - aDirEndFaces.XYZ() * theTopRad;
0768   aPoints[5] = aBottomCenterProject.XYZ() - aDirEndFaces.XYZ() * theBottomRad;
0769   const TColgp_Array1OfPnt aPointsArr (aPoints[0], 0, 5);
0770 
0771   for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0772   {
0773     if ((aCylNormProject.Dot (aCylNormProject) == 0.0
0774      && aVertices.Value (anIdx).Distance (aPoints[0]) <= Max (theTopRad, theBottomRad))
0775      || isDotInside (aVertices.Value (anIdx), aPointsArr))
0776     {
0777       if (theInside != NULL)
0778       {
0779         *theInside = false;
0780       }
0781       return true;
0782     }
0783   }
0784 
0785   for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
0786   {
0787     const gp_Pnt aPnt1Seg = aVertices[anIdx];
0788     const gp_Pnt aPnt2Seg = (anIdx == aVertices.Upper()) ? aVertices[aVertices.Lower()] : aVertices[anIdx + 1];
0789     if (isSegmentsIntersect (aPoints[1], aPoints[2], aPnt1Seg, aPnt2Seg)
0790      || isSegmentsIntersect (aPoints[4], aPoints[5], aPnt1Seg, aPnt2Seg)
0791      || isSegmentsIntersect (aPoints[4], aPoints[2], aPnt1Seg, aPnt2Seg)
0792      || isSegmentsIntersect (aPoints[1], aPoints[5], aPnt1Seg, aPnt2Seg))
0793     {
0794       if (theInside != NULL)
0795       {
0796         *theInside = false;
0797       }
0798       return true;
0799     }
0800   }
0801 
0802   if (!theIsHollow
0803    && (isIntersectCircle (theBottomRad, gp_Pnt (0, 0, 0), theTrsf, aVertices)
0804     || isIntersectCircle (theTopRad, gp_Pnt (0, 0, theHeight), theTrsf, aVertices)))
0805   {
0806     if (theInside != NULL)
0807     {
0808       *theInside = false;
0809     }
0810     return true;
0811   }
0812   bool isCylInsideRec = true;
0813   for (int i = 0; i < 6; ++i)
0814   {
0815     isCylInsideRec &= isDotInside (aPoints[i], aVertices);
0816   }
0817   if (theInside != NULL)
0818   {
0819     *theInside &= isCylInsideRec;
0820   }
0821   return isCylInsideRec;
0822 }
0823 
0824 // =======================================================================
0825 // function : hasCircleOverlap
0826 // purpose  :
0827 // =======================================================================
0828 template<int N>
0829 Standard_Boolean SelectMgr_Frustum<N>::hasCircleOverlap (const Standard_Real theRadius,
0830                                                          const gp_Trsf& theTrsf,
0831                                                          const Standard_Boolean theIsFilled,
0832                                                          Standard_Boolean* theInside) const
0833 {
0834   gp_Pnt aVerticesBuf[N];
0835   TColgp_Array1OfPnt aVertices (aVerticesBuf[0], 0, N - 1);
0836   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0837   if (anIncFactor == 2)
0838   {
0839     const Standard_Integer anIndices[] = { 0, 2, 6, 4 };
0840     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0841     {
0842       aVertices.SetValue (anIdx, myVertices[anIndices[anIdx]]);
0843     }
0844   }
0845   else
0846   {
0847     for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
0848     {
0849       aVertices.SetValue (anIdx, myVertices[anIdx]);
0850     }
0851   }
0852 
0853   if (isIntersectCircle (theRadius, gp_Pnt (0, 0, 0), theTrsf, aVertices))
0854   {
0855     if (theInside != NULL)
0856     {
0857       *theInside = false;
0858     }
0859     return true;
0860   }
0861 
0862   gp_Pnt aCircCenter = gp::Origin();//.Transformed (theTrsf);
0863   const gp_Dir aViewRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]);
0864   const gp_Pln aPln (myVertices[0], aViewRayDir);
0865   Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
0866   aPln.Coefficients (aCoefA, aCoefB, aCoefC, aCoefD);
0867 
0868   const Standard_Real aTCenter = -(aCircCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
0869   const gp_Pnt aCenterProject (aCoefA * aTCenter,
0870                                aCoefB * aTCenter,
0871                                aCoefC * aTCenter);
0872 
0873   const Standard_Boolean isCenterInside = isDotInside (aCenterProject, aVertices);
0874 
0875   Standard_Boolean isInside = false;
0876   for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
0877   {
0878     if (aVertices.Value (anIdx).Distance (aCenterProject) > theRadius)
0879     {
0880       isInside = true;
0881       break;
0882     }
0883   }
0884 
0885   if (theInside != NULL)
0886   {
0887     *theInside = isInside && isCenterInside;
0888   }
0889 
0890   return theIsFilled
0891        ? !isInside || (isCenterInside && isInside)
0892        : isInside && isCenterInside;
0893 }
0894 
0895 //=======================================================================
0896 //function : DumpJson
0897 //purpose  : 
0898 //=======================================================================
0899 template <int N>
0900 void SelectMgr_Frustum<N>::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
0901 {
0902   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
0903 
0904   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
0905   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
0906   {
0907     const gp_Vec& aPlane = myPlanes[aPlaneIdx];
0908     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &aPlane)
0909 
0910     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxVertsProjections[aPlaneIdx])
0911     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinVertsProjections[aPlaneIdx])
0912   }
0913 
0914   for (Standard_Integer aVertIdx = 0; aVertIdx < N * 2; ++aVertIdx)
0915   {
0916     const gp_Pnt& aVertex = myVertices[aVertIdx];
0917     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &aVertex)
0918   }
0919 
0920   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPixelTolerance)
0921   OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myBuilder)
0922   OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myCamera)
0923 
0924   for (Standard_Integer anIndex = 0; anIndex < 3; anIndex++)
0925   {
0926     Standard_Real aMaxOrthoVertsProjections = myMaxOrthoVertsProjections[anIndex];
0927     Standard_Real aMinOrthoVertsProjections = myMinOrthoVertsProjections[anIndex];
0928 
0929     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aMaxOrthoVertsProjections)
0930     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aMinOrthoVertsProjections)
0931   }
0932 
0933   for (Standard_Integer anIndex = 0; anIndex < 6; anIndex++)
0934   {
0935     const gp_Vec& anEdgeDir = myEdgeDirs[anIndex];
0936     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &anEdgeDir)
0937   }
0938 }