Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-27 08:39:15

0001 // Created by: Eugeny MALTCHIKOV
0002 // Created on: 2019-04-17
0003 // Copyright (c) 2019 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 #ifndef _BVH_Tools_Header
0017 #define _BVH_Tools_Header
0018 
0019 #include <BVH_Box.hxx>
0020 #include <BVH_Ray.hxx>
0021 #include <BVH_Types.hxx>
0022 
0023 //! Defines a set of static methods operating with points and bounding boxes.
0024 //! \tparam T Numeric data type
0025 //! \tparam N Vector dimension
0026 template <class T, int N>
0027 class BVH_Tools
0028 {
0029 public: //! @name public types
0030   typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
0031 
0032 public:
0033   enum BVH_PrjStateInTriangle
0034   {
0035     BVH_PrjStateInTriangle_VERTEX,
0036     BVH_PrjStateInTriangle_EDGE,
0037     BVH_PrjStateInTriangle_INNER
0038   };
0039 
0040 public: //! @name Box-Box Square distance
0041   //! Computes Square distance between Axis aligned bounding boxes
0042   static T BoxBoxSquareDistance(const BVH_Box<T, N>& theBox1, const BVH_Box<T, N>& theBox2)
0043   {
0044     if (!theBox1.IsValid() || !theBox2.IsValid())
0045     {
0046       return static_cast<T>(0);
0047     }
0048     return BoxBoxSquareDistance(theBox1.CornerMin(),
0049                                 theBox1.CornerMax(),
0050                                 theBox2.CornerMin(),
0051                                 theBox2.CornerMax());
0052   }
0053 
0054   //! Computes Square distance between Axis aligned bounding boxes
0055   static T BoxBoxSquareDistance(const BVH_VecNt& theCMin1,
0056                                 const BVH_VecNt& theCMax1,
0057                                 const BVH_VecNt& theCMin2,
0058                                 const BVH_VecNt& theCMax2)
0059   {
0060     T aDist = 0;
0061     for (int i = 0; i < N; ++i)
0062     {
0063       if (theCMin1[i] > theCMax2[i])
0064       {
0065         T d = theCMin1[i] - theCMax2[i];
0066         d *= d;
0067         aDist += d;
0068       }
0069       else if (theCMax1[i] < theCMin2[i])
0070       {
0071         T d = theCMin2[i] - theCMax1[i];
0072         d *= d;
0073         aDist += d;
0074       }
0075     }
0076     return aDist;
0077   }
0078 
0079 public: //! @name Point-Box Square distance
0080   //! Computes square distance between point and bounding box
0081   static T PointBoxSquareDistance(const BVH_VecNt& thePoint, const BVH_Box<T, N>& theBox)
0082   {
0083     if (!theBox.IsValid())
0084     {
0085       return static_cast<T>(0);
0086     }
0087     return PointBoxSquareDistance(thePoint, theBox.CornerMin(), theBox.CornerMax());
0088   }
0089 
0090   //! Computes square distance between point and bounding box
0091   static T PointBoxSquareDistance(const BVH_VecNt& thePoint,
0092                                   const BVH_VecNt& theCMin,
0093                                   const BVH_VecNt& theCMax)
0094   {
0095     T aDist = 0;
0096     for (int i = 0; i < N; ++i)
0097     {
0098       if (thePoint[i] < theCMin[i])
0099       {
0100         T d = theCMin[i] - thePoint[i];
0101         d *= d;
0102         aDist += d;
0103       }
0104       else if (thePoint[i] > theCMax[i])
0105       {
0106         T d = thePoint[i] - theCMax[i];
0107         d *= d;
0108         aDist += d;
0109       }
0110     }
0111     return aDist;
0112   }
0113 
0114 public: //! @name Point-Box projection
0115   //! Computes projection of point on bounding box
0116   static BVH_VecNt PointBoxProjection(const BVH_VecNt& thePoint, const BVH_Box<T, N>& theBox)
0117   {
0118     if (!theBox.IsValid())
0119     {
0120       return thePoint;
0121     }
0122     return PointBoxProjection(thePoint, theBox.CornerMin(), theBox.CornerMax());
0123   }
0124 
0125   //! Computes projection of point on bounding box
0126   static BVH_VecNt PointBoxProjection(const BVH_VecNt& thePoint,
0127                                       const BVH_VecNt& theCMin,
0128                                       const BVH_VecNt& theCMax)
0129   {
0130     return thePoint.cwiseMax(theCMin).cwiseMin(theCMax);
0131   }
0132 
0133 public: //! @name Point-Triangle Square distance
0134   //! Find nearest point on a triangle for the given point
0135   static BVH_VecNt PointTriangleProjection(const BVH_VecNt&        thePoint,
0136                                            const BVH_VecNt&        theNode0,
0137                                            const BVH_VecNt&        theNode1,
0138                                            const BVH_VecNt&        theNode2,
0139                                            BVH_PrjStateInTriangle* thePrjState          = nullptr,
0140                                            Standard_Integer*       theNumberOfFirstNode = nullptr,
0141                                            Standard_Integer*       theNumberOfLastNode  = nullptr)
0142   {
0143     const BVH_VecNt aAB = theNode1 - theNode0;
0144     const BVH_VecNt aAC = theNode2 - theNode0;
0145     const BVH_VecNt aAP = thePoint - theNode0;
0146 
0147     T aABdotAP = aAB.Dot(aAP);
0148     T aACdotAP = aAC.Dot(aAP);
0149 
0150     if (aABdotAP <= 0. && aACdotAP <= 0.)
0151     {
0152       if (thePrjState != nullptr)
0153       {
0154         *thePrjState          = BVH_PrjStateInTriangle_VERTEX;
0155         *theNumberOfFirstNode = 0;
0156         *theNumberOfLastNode  = 0;
0157       }
0158       return theNode0;
0159     }
0160 
0161     const BVH_VecNt aBC = theNode2 - theNode1;
0162     const BVH_VecNt aBP = thePoint - theNode1;
0163 
0164     T aBAdotBP = -(aAB.Dot(aBP));
0165     T aBCdotBP = (aBC.Dot(aBP));
0166 
0167     if (aBAdotBP <= 0. && aBCdotBP <= 0.)
0168     {
0169       if (thePrjState != nullptr)
0170       {
0171         *thePrjState          = BVH_PrjStateInTriangle_VERTEX;
0172         *theNumberOfFirstNode = 1;
0173         *theNumberOfLastNode  = 1;
0174       }
0175       return theNode1;
0176     }
0177 
0178     const BVH_VecNt aCP = thePoint - theNode2;
0179 
0180     T aCBdotCP = -(aBC.Dot(aCP));
0181     T aCAdotCP = -(aAC.Dot(aCP));
0182 
0183     if (aCAdotCP <= 0. && aCBdotCP <= 0.)
0184     {
0185       if (thePrjState != nullptr)
0186       {
0187         *thePrjState          = BVH_PrjStateInTriangle_VERTEX;
0188         *theNumberOfFirstNode = 2;
0189         *theNumberOfLastNode  = 2;
0190       }
0191       return theNode2;
0192     }
0193 
0194     T aACdotBP = (aAC.Dot(aBP));
0195 
0196     T aVC = aABdotAP * aACdotBP + aBAdotBP * aACdotAP;
0197 
0198     if (aVC <= 0. && aABdotAP > 0. && aBAdotBP > 0.)
0199     {
0200       if (thePrjState != nullptr)
0201       {
0202         *thePrjState          = BVH_PrjStateInTriangle_EDGE;
0203         *theNumberOfFirstNode = 0;
0204         *theNumberOfLastNode  = 1;
0205       }
0206       return theNode0 + aAB * (aABdotAP / (aABdotAP + aBAdotBP));
0207     }
0208 
0209     T aABdotCP = (aAB.Dot(aCP));
0210 
0211     T aVA = aBAdotBP * aCAdotCP - aABdotCP * aACdotBP;
0212 
0213     if (aVA <= 0. && aBCdotBP > 0. && aCBdotCP > 0.)
0214     {
0215       if (thePrjState != nullptr)
0216       {
0217         *thePrjState          = BVH_PrjStateInTriangle_EDGE;
0218         *theNumberOfFirstNode = 1;
0219         *theNumberOfLastNode  = 2;
0220       }
0221       return theNode1 + aBC * (aBCdotBP / (aBCdotBP + aCBdotCP));
0222     }
0223 
0224     T aVB = aABdotCP * aACdotAP + aABdotAP * aCAdotCP;
0225 
0226     if (aVB <= 0. && aACdotAP > 0. && aCAdotCP > 0.)
0227     {
0228       if (thePrjState != nullptr)
0229       {
0230         *thePrjState          = BVH_PrjStateInTriangle_EDGE;
0231         *theNumberOfFirstNode = 2;
0232         *theNumberOfLastNode  = 0;
0233       }
0234       return theNode0 + aAC * (aACdotAP / (aACdotAP + aCAdotCP));
0235     }
0236 
0237     T aNorm = aVA + aVB + aVC;
0238 
0239     if (thePrjState != nullptr)
0240     {
0241       *thePrjState = BVH_PrjStateInTriangle_INNER;
0242     }
0243 
0244     return (theNode0 * aVA + theNode1 * aVB + theNode2 * aVC) / aNorm;
0245   }
0246 
0247   //! Computes square distance between point and triangle
0248   static T PointTriangleSquareDistance(const BVH_VecNt& thePoint,
0249                                        const BVH_VecNt& theNode0,
0250                                        const BVH_VecNt& theNode1,
0251                                        const BVH_VecNt& theNode2)
0252   {
0253     const BVH_VecNt aProj = PointTriangleProjection(thePoint, theNode0, theNode1, theNode2);
0254     const BVH_VecNt aPP   = aProj - thePoint;
0255     return aPP.Dot(aPP);
0256   }
0257 
0258 public: //! @name Ray-Box Intersection
0259   //! Computes hit time of ray-box intersection
0260   static Standard_Boolean RayBoxIntersection(const BVH_Ray<T, N>& theRay,
0261                                              const BVH_Box<T, N>& theBox,
0262                                              T&                   theTimeEnter,
0263                                              T&                   theTimeLeave)
0264   {
0265     if (!theBox.IsValid())
0266     {
0267       return Standard_False;
0268     }
0269     return RayBoxIntersection(theRay,
0270                               theBox.CornerMin(),
0271                               theBox.CornerMax(),
0272                               theTimeEnter,
0273                               theTimeLeave);
0274   }
0275 
0276   //! Computes hit time of ray-box intersection
0277   static Standard_Boolean RayBoxIntersection(const BVH_Ray<T, N>& theRay,
0278                                              const BVH_VecNt&     theBoxCMin,
0279                                              const BVH_VecNt&     theBoxCMax,
0280                                              T&                   theTimeEnter,
0281                                              T&                   theTimeLeave)
0282   {
0283     return RayBoxIntersection(theRay.Origin,
0284                               theRay.Direct,
0285                               theBoxCMin,
0286                               theBoxCMax,
0287                               theTimeEnter,
0288                               theTimeLeave);
0289   }
0290 
0291   //! Computes hit time of ray-box intersection
0292   static Standard_Boolean RayBoxIntersection(const BVH_VecNt&     theRayOrigin,
0293                                              const BVH_VecNt&     theRayDirection,
0294                                              const BVH_Box<T, N>& theBox,
0295                                              T&                   theTimeEnter,
0296                                              T&                   theTimeLeave)
0297   {
0298     if (!theBox.IsValid())
0299     {
0300       return Standard_False;
0301     }
0302     return RayBoxIntersection(theRayOrigin,
0303                               theRayDirection,
0304                               theBox.CornerMin(),
0305                               theBox.CornerMax(),
0306                               theTimeEnter,
0307                               theTimeLeave);
0308   }
0309 
0310   //! Computes hit time of ray-box intersection
0311   static Standard_Boolean RayBoxIntersection(const BVH_VecNt& theRayOrigin,
0312                                              const BVH_VecNt& theRayDirection,
0313                                              const BVH_VecNt& theBoxCMin,
0314                                              const BVH_VecNt& theBoxCMax,
0315                                              T&               theTimeEnter,
0316                                              T&               theTimeLeave)
0317   {
0318     BVH_VecNt aNodeMin, aNodeMax;
0319     for (int i = 0; i < N; ++i)
0320     {
0321       if (theRayDirection[i] == 0)
0322       {
0323         aNodeMin[i] = (theBoxCMin[i] - theRayOrigin[i]) <= 0 ? (std::numeric_limits<T>::min)()
0324                                                              : (std::numeric_limits<T>::max)();
0325         aNodeMax[i] = (theBoxCMax[i] - theRayOrigin[i]) < 0 ? (std::numeric_limits<T>::min)()
0326                                                             : (std::numeric_limits<T>::max)();
0327       }
0328       else
0329       {
0330         aNodeMin[i] = (theBoxCMin[i] - theRayOrigin[i]) / theRayDirection[i];
0331         aNodeMax[i] = (theBoxCMax[i] - theRayOrigin[i]) / theRayDirection[i];
0332       }
0333     }
0334 
0335     BVH_VecNt aTimeMin, aTimeMax;
0336     for (int i = 0; i < N; ++i)
0337     {
0338       aTimeMin[i] = Min(aNodeMin[i], aNodeMax[i]);
0339       aTimeMax[i] = Max(aNodeMin[i], aNodeMax[i]);
0340     }
0341 
0342     T aTimeEnter = Max(aTimeMin[0], Max(aTimeMin[1], aTimeMin[2]));
0343     T aTimeLeave = Min(aTimeMax[0], Min(aTimeMax[1], aTimeMax[2]));
0344 
0345     Standard_Boolean hasIntersection = aTimeEnter <= aTimeLeave && aTimeLeave >= 0;
0346     if (hasIntersection)
0347     {
0348       theTimeEnter = aTimeEnter;
0349       theTimeLeave = aTimeLeave;
0350     }
0351 
0352     return hasIntersection;
0353   }
0354 };
0355 
0356 #endif