File indexing completed on 2025-10-31 09:19:06
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 #ifndef VECGEOM_NAVIGATION_EMBREENAVIGATOR_H_
0009 #define VECGEOM_NAVIGATION_EMBREENAVIGATOR_H_
0010 
0011 #include "VecGeom/base/Global.h"
0012 
0013 #include "VecGeom/volumes/PlacedVolume.h"
0014 #include "VecGeom/base/Vector3D.h"
0015 #include "VecGeom/management/GeoManager.h"
0016 #include "VecGeom/navigation/NavigationState.h"
0017 #include "VecGeom/base/Transformation3D.h"
0018 #include "VecGeom/management/EmbreeManager.h"
0019 #include "VecGeom/navigation/VNavigator.h"
0020 #include "VecGeom/navigation/HybridSafetyEstimator.h"
0021 #include "VecGeom/navigation/SimpleABBoxNavigator.h"
0022 
0023 #include <vector>
0024 #include <stack>
0025 
0026 namespace vecgeom {
0027 inline namespace VECGEOM_IMPL_NAMESPACE {
0028 
0029 extern double g_step;
0030 extern LogicalVolume const *g_lvol;
0031 extern VPlacedVolume const *g_pvol;
0032 extern VPlacedVolume const *g_lastexited;
0033 extern Vector3D<double> const *g_pos;
0034 extern Vector3D<double> const *g_dir;
0035 extern Vector3D<float> const *g_normals;
0036 extern int g_count;
0037 extern std::vector<int> *g_geomIDs;
0038 extern EmbreeManager::BoxIdDistancePair_t *g_hitlist;
0039 
0040 
0041 
0042 template <bool MotherIsConvex = false>
0043 class EmbreeNavigator : public VNavigatorHelper<EmbreeNavigator<MotherIsConvex>, MotherIsConvex> {
0044 
0045 private:
0046   EmbreeManager &fAccelerationManager;
0047   EmbreeNavigator()
0048       : VNavigatorHelper<EmbreeNavigator<MotherIsConvex>, MotherIsConvex>(SimpleABBoxSafetyEstimator::Instance()),
0049         fAccelerationManager(EmbreeManager::Instance())
0050   {
0051   }
0052 
0053   static VPlacedVolume const *LookupDaughter(LogicalVolume const *lvol, int const daughterIndex)
0054   {
0055     return lvol->GetDaughters()[daughterIndex];
0056   }
0057 
0058   
0059   template <typename T> 
0060   static void insertionsort(T *arr, unsigned int N)
0061   {
0062     for (unsigned short i = 1; i < N; ++i) {
0063       T value    = arr[i];
0064       short hole = i;
0065 
0066       for (; hole > 0 && value.second < arr[hole - 1].second; --hole)
0067         arr[hole] = arr[hole - 1];
0068 
0069       arr[hole] = value;
0070     }
0071   }
0072 
0073   
0074 
0075 
0076   size_t GetHitCandidates_v(EmbreeManager::EmbreeAccelerationStructure const &accstructure,
0077                             Vector3D<Precision> const &point, Vector3D<Precision> const &dir,
0078                             EmbreeManager::BoxIdDistancePair_t *hitlist, float step) const
0079   {
0080     if (accstructure.fNumberObjects == 0) return false;
0081     
0082     RTCRayHit ray;
0083     ray.ray.flags = 0;
0084     ray.ray.org_x = point.x();
0085     ray.ray.org_y = point.y();
0086     ray.ray.org_z = point.z();
0087     ray.ray.dir_x = dir.x();
0088     ray.ray.dir_y = dir.y();
0089     ray.ray.dir_z = dir.z();
0090     ray.ray.tnear = 0.f;
0091     ray.ray.tfar  = 1E20f; 
0092 
0093     g_normals = accstructure.fNormals;
0094     g_hitlist = hitlist;
0095     g_count   = 0;
0096     g_geomIDs->clear(); 
0097 
0098     RTCIntersectContext context;
0099     
0100     auto hitFilter = [](const RTCFilterFunctionNArguments *args) {
0101       
0102       
0103       const auto hit = (RTCHit *)args->hit;
0104       int *hitvalid  = args->valid;
0105       const auto id  = hit->geomID;
0106       
0107       
0108       
0109       
0110       
0111       if (std::find(g_geomIDs->begin(), g_geomIDs->end(), id) != g_geomIDs->end()) {
0112         hitvalid[0] = 0;
0113         return;
0114       }
0115       g_geomIDs->push_back(id);
0116 
0117       const auto ray      = (RTCRay *)args->ray;
0118       const auto normalID = id * 6 + hit->primID;
0119       const auto normal   = g_normals[normalID];
0120       const bool backface = ray->dir_x * normal.x() + ray->dir_y * normal.y() + ray->dir_z * normal.z() > 0;
0121       float dist          = backface ? -1.f : ray->tfar;
0122 
0123       
0124 
0125       
0126       g_hitlist[g_count++] = HybridManager2::BoxIdDistancePair_t(id, dist);
0127       
0128       hitvalid[0] = 0;
0129     };
0130 
0131     rtcInitIntersectContext(&context);
0132     context.filter = hitFilter;
0133     rtcIntersect1(accstructure.fScene, &context, &ray);
0134 
0135     
0136     return g_count;
0137   }
0138 
0139 public:
0140   
0141   
0142   
0143   
0144   
0145   
0146 
0147   
0148   
0149   template <typename AccStructure, typename Func>
0150   VECGEOM_FORCE_INLINE
0151   void BVHSortedIntersectionsLooper(AccStructure const &accstructure, Vector3D<Precision> const &localpoint,
0152                                     Vector3D<Precision> const &localdir, float stepmax, Func &&userhook) const
0153   {
0154     
0155     
0156     using IdDistPair_t = HybridManager2::BoxIdDistancePair_t;
0157     char stackspace[VECGEOM_MAXFACETS * sizeof(IdDistPair_t)];
0158     IdDistPair_t *hitlist = reinterpret_cast<IdDistPair_t *>(&stackspace);
0159 
0160     auto ncandidates = GetHitCandidates_v(accstructure, localpoint, localdir, hitlist, stepmax);
0161     
0162     insertionsort(hitlist, ncandidates);
0163 
0164     
0165     
0166     
0167 
0168     for (size_t index = 0; index < ncandidates; ++index) {
0169       auto hitbox = hitlist[index];
0170       
0171       
0172       auto done = userhook(hitbox);
0173       if (done) break;
0174     }
0175   }
0176 
0177   VECGEOM_FORCE_INLINE
0178   virtual bool CheckDaughterIntersections(LogicalVolume const *lvol, Vector3D<Precision> const &localpoint,
0179                                           Vector3D<Precision> const &localdir, NavigationState const *in_state,
0180                                           NavigationState * , Precision &step,
0181                                           VPlacedVolume const *&hitcandidate) const override
0182   {
0183     if (lvol->GetDaughtersp()->size() == 0) return false;
0184     auto &accstructure = *fAccelerationManager.GetAccStructure(lvol);
0185 
0186     BVHSortedIntersectionsLooper(
0187         accstructure, localpoint, localdir, step, [&](HybridManager2::BoxIdDistancePair_t hitbox) {
0188           
0189           if (!(step < hitbox.second)) {
0190             VPlacedVolume const *candidate = LookupDaughter(lvol, hitbox.first);
0191             Precision ddistance            = candidate->DistanceToIn(localpoint, localdir, step);
0192             const auto valid               = !IsInf(ddistance) && ddistance < step &&
0193                                !((ddistance <= 0.) && in_state && in_state->GetLastExited() == candidate);
0194             hitcandidate = valid ? candidate : hitcandidate;
0195             step         = valid ? ddistance : step;
0196             return false; 
0197           }
0198           return true; 
0199         });
0200     return false;
0201   }
0202 
0203   
0204   
0205   
0206   
0207   
0208   
0209   
0210   
0211   
0212   
0213   
0214   
0215   
0216   
0217   
0218   
0219   
0220   
0221   
0222   
0223   
0224   
0225   
0226   
0227   
0228   
0229   
0230   
0231   
0232   
0233   
0234   
0235   
0236   
0237   
0238   
0239   
0240   
0241   
0242   
0243   
0244   
0245   
0246   
0247   
0248   
0249   
0250   
0251   
0252   
0253   
0254   
0255   
0256   
0257   
0258   
0259   
0260   
0261   
0262   
0263   
0264   
0265   
0266   
0267   
0268   
0269   
0270   
0271   
0272   
0273   
0274   
0275   
0276   
0277   
0278   
0279   
0280   
0281   
0282   
0283   
0284   
0285   
0286   
0287   
0288   
0289   
0290   
0291   
0292   
0293   
0294   
0295   
0296   
0297   
0298 
0299   static VNavigator *Instance()
0300   {
0301     static EmbreeNavigator instance;
0302     return &instance;
0303   }
0304 
0305   static constexpr const char *gClassNameString = "EmbreeNavigator";
0306   typedef SimpleABBoxSafetyEstimator SafetyEstimator_t;
0307 };
0308 } 
0309 } 
0310 
0311 #endif