Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 08:35:32

0001 #ifndef VECGEOM_SURFACE_CPUTYPES_H
0002 #define VECGEOM_SURFACE_CPUTYPES_H
0003 
0004 #include <VecGeom/surfaces/base/CommonTypes.h>
0005 #include <VecGeom/surfaces/Model.h>
0006 #include <set>
0007 
0008 namespace vgbrep {
0009 
0010 template <typename T>
0011 VECGEOM_FORCE_INLINE char const *to_cstring(T type)
0012 {
0013   return nullptr;
0014 }
0015 
0016 template <>
0017 VECGEOM_FORCE_INLINE char const *to_cstring<SurfaceType>(SurfaceType type)
0018 {
0019   static const char *const data[] = {"no_surf",   "planar", "cylindrical", "conical",
0020                                      "spherical", "torus",  "elliptical",  "arb4"};
0021   VECGEOM_ASSERT(size_t(type) * sizeof(const char *) < sizeof(data));
0022   return data[static_cast<int>(type)];
0023 }
0024 
0025 template <>
0026 VECGEOM_FORCE_INLINE char const *to_cstring<bool>(bool type)
0027 {
0028   if (type) return "true";
0029   return "false";
0030 }
0031 
0032 template <>
0033 VECGEOM_FORCE_INLINE char const *to_cstring<FrameType>(FrameType type)
0034 {
0035   static const char *const data[] = {"no_frame", "rangeZ", "ring", "z_phi", "rangeSph", "window", "triangle", "quad"};
0036   VECGEOM_ASSERT(size_t(type) * sizeof(const char *) < sizeof(data));
0037   return data[static_cast<int>(type)];
0038 }
0039 
0040 template <>
0041 VECGEOM_FORCE_INLINE char const *to_cstring<AxisType>(AxisType type)
0042 {
0043   static const char *const data[] = {"x-axis", "y-axis", "z-axis", "r-axis", "phi-axis", "xy-grid", "no-axis"};
0044   VECGEOM_ASSERT(size_t(type) * sizeof(const char *) < sizeof(data));
0045   return data[static_cast<int>(type)];
0046 }
0047 
0048 using LogicExpressionCPU = std::vector<logic_int>;
0049 
0050 // Placeholder (on host) for all surfaces belonging to a volume. An array of those will be indexed
0051 // by the logical volume id. Also an intermediate helper for building portals.
0052 // Note: the local surfaces defined by solids will have local references that will be changed by
0053 // the flattening process, depending on the scene on which the parent volume will be flattened
0054 struct VolumeShellCPU {
0055   std::vector<int> fSurfaces;             ///< Local surface id's for this volume
0056   std::vector<int> fExitingSurfaces;      ///< Local surface id's for this volume, excluding virtual ones
0057   std::vector<int> fEnteringSurfaces;     ///< Local surface id's for all surfaces of daughters, excluding virtual ones
0058   std::vector<int> fEnteringSurfacesPvol; ///< Global PVol ids for the daughter surfaces of this volume
0059   std::vector<int> fEnteringSurfacesPvolTrans; ///< Array of ids to daughter placed volume transformations
0060   std::vector<int> fEnteringSurfacesLvolIds;   ///< Array of ids to daughter logical volumes
0061   std::vector<int> fDaughterPvolIds;           ///< Global PV Ids of the daughter PVs of this Volume
0062   std::vector<int> fDaughterPvolTrans;         ///< Transformations of the daughter PVs of this Volume
0063 
0064   LogicExpressionCPU fLogic; ///< Logic expression for the solid
0065   bool fSimplified{false};   ///< The logic was simplified
0066   int fBVH{0};
0067 };
0068 
0069 /// @brief Helper for dividing a side in equal slices along one axis, keeping frame candidates in each slice
0070 /// @details The range given by the side extent is divided in equal slices along an axis. Each
0071 ///          slice intersects a number of frames. The slice is found besed on the crossing point, then the full
0072 ///          frame loops are reduced to the list of candidates in that slice.
0073 struct SideDivisionCPU {
0074   using VecInt_t = std::vector<int>;
0075   double fStartU{0.};                ///< Division start on primary division axis
0076   double fStepU{0.};                 ///< Division step on primary division axis
0077   double fStartV{0.};                ///< Division start on secondary axis (if any)
0078   double fStepV{0.};                 ///< Division step on secondary axis (if any)
0079   unsigned short fNslices{0};        ///< Total number of slices
0080   unsigned short fNslicesU{0};       ///< Number of slices on primary division axis
0081   unsigned short fNslicesV{1};       ///< Number of slices on secondary division axis (if no axis this must be 1)
0082   AxisType fAxis{AxisType::kNoAxis}; ///< Division axis
0083   std::vector<VecInt_t> fSlices;     ///< Array of slices
0084 
0085   // Methods
0086   SideDivisionCPU() = default;
0087   SideDivisionCPU(AxisType axis, double coord_min, double coord_max, int ncand)
0088       : fStartU(coord_min), fStepU((coord_max - coord_min) / ncand), fNslices(ncand), fAxis(axis)
0089   {
0090     fSlices.insert(fSlices.end(), ncand, {});
0091   }
0092 
0093   SideDivisionCPU(AxisType axis, double coord_minU, double coord_maxU, double coord_minV, double coord_maxV, int ncand)
0094       : fAxis(axis)
0095   {
0096     fNslicesU = 1 + std::sqrt(static_cast<double>(ncand)); // rounding happens
0097     fNslicesV = ncand / fNslicesU;                         // rounding happens
0098     fNslices  = fNslicesU * fNslicesV;
0099     fStartU   = coord_minU;
0100     fStepU    = (coord_maxU - coord_minU) / fNslicesU;
0101     fStartV   = coord_minV;
0102     fStepV    = (coord_maxV - coord_minV) / fNslicesV;
0103     fSlices.insert(fSlices.end(), fNslices, {});
0104   }
0105 
0106   void AddCandidate(int icand, double coord_min, double coord_max)
0107   {
0108     int istart = (coord_min - fStartU - vecgeom::kToleranceDist<double>) / fStepU;
0109     int iend   = (coord_max - fStartU + vecgeom::kToleranceDist<double>) / fStepU;
0110     for (int i = istart; i <= iend && i < fNslices; ++i) {
0111       if (i < 0) continue;
0112       fSlices[i].push_back(icand);
0113     }
0114   }
0115 
0116   /// @brief Get the indices of the slices intersected by a bounding box
0117   /// @param amin lower bbox corner
0118   /// @param amax upper bbox corner
0119   /// @param umin lower first index
0120   /// @param umax upper first index
0121   /// @param vmin lower second index
0122   /// @param vmax upper second index
0123   /// @return number of crossed slices
0124   int GetNslices(Vector3D<double> const &amin, Vector3D<double> const &amax, int &umin, int &umax, int &vmin,
0125                  int &vmax) const
0126   {
0127     umin = umax = vmin = vmax = 0;
0128     switch (fAxis) {
0129     case AxisType::kXY: {
0130       umin = std::max(0, int((amin[0] - fStartU) / fStepU));
0131       if (umin >= fNslicesU) return 0;
0132       umax = std::min(fNslicesU - 1, int((amax[0] - fStartU) / fStepU));
0133       if (umax < 0) return 0;
0134       vmin = std::max(0, int((amin[1] - fStartV) / fStepV));
0135       if (vmin >= fNslicesV) return 0;
0136       vmax = std::min(fNslicesV - 1, int((amax[1] - fStartV) / fStepV));
0137       if (vmax < 0) return 0;
0138       return (umax - umin + 1) * (vmax - vmin + 1);
0139     }
0140     case AxisType::kR: {
0141       auto rmin = amin[0];
0142       auto rmax = amax[0];
0143       umin      = std::max(0, int((rmin - fStartU) / fStepU));
0144       if (umin >= fNslices) return 0;
0145       umax = std::min(fNslices - 1, int((rmax - fStartU) / fStepU));
0146       if (umax < 0) return 0;
0147       return (umax - umin + 1);
0148     }
0149     case AxisType::kPhi: {
0150       VECGEOM_LOG(error) << "GetNdlices not supported for phi division";
0151       return 0;
0152     }
0153     default:
0154       umin = std::max(0, int((amin[fAxis] - fStartU) / fStepU));
0155       if (umin >= fNslices) return 0;
0156       umax = std::min(fNslices - 1, int((amax[fAxis] - fStartU) / fStepU));
0157       if (umax < 0) return 0;
0158       return (umax - umin + 1);
0159     }
0160   }
0161 
0162   void AddCandidate(int icand, double umin, double umax, double vmin, double vmax)
0163   {
0164     int istartU = (umin - fStartU - vecgeom::kToleranceDist<double>) / fStepU;
0165     int iendU   = (umax - fStartU + vecgeom::kToleranceDist<double>) / fStepU;
0166     int istartV = (vmin - fStartV - vecgeom::kToleranceDist<double>) / fStepV;
0167     int iendV   = (vmax - fStartV + vecgeom::kToleranceDist<double>) / fStepV;
0168     for (int i = istartU; i <= iendU && i < fNslicesU; ++i) {
0169       for (int j = istartV; j <= iendV && j < fNslicesV; ++j) {
0170         if (i < 0 || j < 0) continue;
0171         fSlices[i * fNslicesV + j].push_back(icand);
0172       }
0173     }
0174   }
0175 
0176   const VecInt_t *GetSlice(int u, int v) const { return &fSlices[u * fNslicesV + v]; }
0177 
0178   template <typename Real_t>
0179   void CopyTo(SideDivision<Real_t> &div, SliceCand *slices, int *candidates) const
0180   {
0181     div.fStartU   = fStartU;
0182     div.fStepU    = fStepU;
0183     div.fStartV   = fStartV;
0184     div.fStepV    = fStepV;
0185     div.fNslices  = fNslices;
0186     div.fNslicesU = fNslicesU;
0187     div.fNslicesV = fNslicesV;
0188     div.fAxis     = fAxis;
0189     div.fSlices   = slices;
0190     auto cand     = candidates;
0191     for (size_t i = 0; i < fSlices.size(); ++i) {
0192       slices[i].fNcand      = fSlices[i].size();
0193       slices[i].fCandidates = cand;
0194       for (int j = 0; j < slices[i].fNcand; ++j)
0195         cand[j] = fSlices[i][j];
0196       cand += slices[i].fNcand;
0197     }
0198   }
0199 
0200   template <typename Real_t>
0201   size_t GetSizeObject() const
0202   {
0203     return sizeof(SideDivision<Real_t>);
0204   }
0205 
0206   template <typename Real_t>
0207   size_t GetSizeSlices() const
0208   {
0209     return fNslices * sizeof(SliceCand);
0210   }
0211 
0212   size_t GetNcandidates() const
0213   {
0214     size_t size = 0;
0215     for (auto i = 0; i < fNslices; ++i)
0216       size += fSlices[i].size();
0217     return size;
0218   }
0219 
0220   size_t GetSizeCandidates() const { return GetNcandidates() * sizeof(int); }
0221 
0222   template <typename Real_t>
0223   size_t GetSize() const
0224   {
0225     size_t size = GetSizeObject<Real_t>() + GetSizeSlices<Real_t>() + GetSizeCandidates();
0226     return size;
0227   }
0228 
0229   void Print() const
0230   {
0231     if (fAxis == AxisType::kXY) {
0232       std::cout << to_cstring(fAxis) << " division: fNslices = " << fNslices << ", fNslicesU = " << fNslicesU
0233                 << ", fNslicesV = " << fNslicesV << ", fStartU = " << fStartU << ", fStepU = " << fStepU
0234                 << ", fStartV = " << fStartV << ", fStepV = " << fStepV << ", efficiency = " << 100 * Efficiency()
0235                 << " %\n";
0236     } else {
0237       std::cout << to_cstring(fAxis) << " division: fNslices = " << fNslices << ", fStart = " << fStartU
0238                 << ", fStep = " << fStepU << ", efficiency = " << 100 * Efficiency() << " %\n";
0239     }
0240     for (auto i = 0; i < fNslices; ++i)
0241       std::cout << fSlices[i].size() << " ";
0242     std::cout << "\n";
0243   }
0244 
0245   double Efficiency() const
0246   {
0247     // VECGEOM_ASSERT(fSlices[0].size() * fSlices[fNslices - 1].size() > 0); // except kXY
0248     double average = 0;
0249     for (auto i = 0; i < fNslices; ++i)
0250       average += fSlices[i].size();
0251     average /= fNslices;
0252     double eff = (fNslices - average) / (average * (fNslices - 1));
0253     return eff;
0254   }
0255 };
0256 
0257 // Surface data used only on CPU during the conversion process
0258 template <typename Real_t>
0259 struct CPUsurfData {
0260   using VecInt_t       = std::vector<int>;
0261   using VecChar_t      = std::vector<char>;
0262   using MultimapInt_t  = std::multimap<long, int>;
0263   using SurfData_t     = SurfData<Real_t>;
0264   using EllipData_t    = EllipData<Real_t>;
0265   using TorusData_t    = TorusData<Real_t>;
0266   using Arb4Data_t     = Arb4Data<Real_t>;
0267   using WindowMask_t   = WindowMask<Real_t>;
0268   using RingMask_t     = RingMask<Real_t>;
0269   using ZPhiMask_t     = ZPhiMask<Real_t>;
0270   using TriangleMask_t = TriangleMask<Real_t>;
0271   using QuadMask_t     = QuadrilateralMask<Real_t>;
0272 
0273   std::vector<WindowMask_t> fWindowMasks; ///< rectangular masks
0274   std::vector<RingMask_t> fRingMasks;     ///< ring masks
0275   std::vector<ZPhiMask_t> fZPhiMasks;     ///< cylindrical masks
0276   std::vector<TriangleMask_t> fTriangleMasks;
0277   std::vector<QuadMask_t> fQuadMasks; ///< quadrilateral masks
0278 
0279   std::vector<EllipData_t> fEllipData;                                         ///< data for elliptical surfaces
0280   std::vector<TorusData_t> fTorusData;                                         ///< data for torus surfaces
0281   std::vector<Arb4Data_t> fArb4Data;                                           ///< data for Arb4 surfaces
0282   std::vector<TransformationMP<Real_t>> fPVolTrans;                            ///< Transformations to placed volumes
0283   std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>> fLocalSurfaces; ///< local surfaces per logical volume
0284   std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>> fFramedSurf;    ///< global surfaces
0285   std::vector<CommonSurface<Real_t>> fCommonSurfaces;                          ///< common surfaces
0286   std::vector<VolumeShellCPU> fShells;                                         ///< vector of local volume surfaces
0287   std::vector<VolumeShellCPU> fSceneShells;                                    ///< vector of scene volume surfaces
0288 
0289   VecInt_t fSceneStartIndex;            ///< Start indices for data indexed by state id (per scene)
0290   VecInt_t fSceneTouchables;            ///< Number of touchables (per scene)
0291   std::vector<MultimapInt_t> fSurfHash; ///< maps rotation hash index to a list of common surface id's (per scene)
0292 
0293   std::vector<VecInt_t> fCandidatesEntering; ///< list of entering candidates: scene0...,scene1...
0294   std::vector<VecInt_t> fCandidatesExiting;  ///< list of exiting candidates: scene0...,scene1...
0295   std::vector<VecInt_t> fFrameIndEntering; ///< list of start frame indices for entering candidates: scene0...,scene1...
0296   std::vector<VecInt_t> fFrameIndExiting;  ///< list of start frame indices for exiting candidates: scene0...,scene1...
0297   std::vector<VecChar_t> fSidesEntering;   ///< list of relevant sides for entering candidates: scene0...,scene1...
0298   std::vector<VecChar_t> fSidesExiting;    ///< list of relevant sides for exiting candidates: scene0...,scene1...
0299 
0300   std::vector<SideDivisionCPU> fSideDivisions; ///< list of divisions for all sides
0301 
0302 private:
0303   CPUsurfData() = default;
0304 
0305 public:
0306   static VECGEOM_FORCE_INLINE CPUsurfData<Real_t> &Instance()
0307   {
0308     static CPUsurfData<Real_t> gCPUsurfdata;
0309     return gCPUsurfdata;
0310   }
0311 
0312   void Clear()
0313   {
0314     // Dispose of surface data and shrink the container
0315     std::vector<WindowMask_t>().swap(fWindowMasks);
0316     std::vector<RingMask_t>().swap(fRingMasks);
0317     std::vector<ZPhiMask_t>().swap(fZPhiMasks);
0318     std::vector<TriangleMask_t>().swap(fTriangleMasks);
0319     std::vector<QuadMask_t>().swap(fQuadMasks);
0320     std::vector<EllipData_t>().swap(fEllipData);
0321     std::vector<TorusData_t>().swap(fTorusData);
0322     std::vector<TransformationMP<Real_t>>().swap(fPVolTrans);
0323     std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>>().swap(fLocalSurfaces);
0324     std::vector<FramedSurface<Real_t, TransformationMP<Real_t>>>().swap(fFramedSurf);
0325     std::vector<CommonSurface<Real_t>>().swap(fCommonSurfaces);
0326     std::vector<VolumeShellCPU>().swap(fShells);
0327     std::vector<VolumeShellCPU>().swap(fSceneShells);
0328     VecInt_t().swap(fSceneStartIndex);
0329     VecInt_t().swap(fSceneTouchables);
0330     std::vector<MultimapInt_t>().swap(fSurfHash);
0331     std::vector<VecInt_t>().swap(fCandidatesEntering);
0332     std::vector<VecInt_t>().swap(fCandidatesExiting);
0333     std::vector<VecInt_t>().swap(fFrameIndEntering);
0334     std::vector<VecInt_t>().swap(fFrameIndExiting);
0335     std::vector<VecChar_t>().swap(fSidesEntering);
0336     std::vector<VecChar_t>().swap(fSidesExiting);
0337     std::vector<SideDivisionCPU>().swap(fSideDivisions);
0338   }
0339 
0340   VecInt_t &GetCandidatesEntering(int scene_id, int state_id)
0341   {
0342     return fCandidatesEntering[fSceneStartIndex[scene_id] + state_id];
0343   }
0344 
0345   VecInt_t &GetCandidatesExiting(int scene_id, int state_id)
0346   {
0347     return fCandidatesExiting[fSceneStartIndex[scene_id] + state_id];
0348   }
0349 
0350   VecInt_t &GetFrameIndEntering(int scene_id, int state_id)
0351   {
0352     return fFrameIndEntering[fSceneStartIndex[scene_id] + state_id];
0353   }
0354 
0355   VecInt_t &GetFrameIndExiting(int scene_id, int state_id)
0356   {
0357     return fFrameIndExiting[fSceneStartIndex[scene_id] + state_id];
0358   }
0359 
0360   VecChar_t &GetSidesEntering(int scene_id, int state_id)
0361   {
0362     return fSidesEntering[fSceneStartIndex[scene_id] + state_id];
0363   }
0364 
0365   VecChar_t &GetSidesExiting(int scene_id, int state_id)
0366   {
0367     return fSidesExiting[fSceneStartIndex[scene_id] + state_id];
0368   }
0369 
0370   WindowMask_t const &GetWindowMask(int id) const { return fWindowMasks[id]; }
0371   RingMask_t const &GetRingMask(int id) const { return fRingMasks[id]; }
0372   ZPhiMask_t const &GetZPhiMask(int id) const { return fZPhiMasks[id]; }
0373   TriangleMask_t const &GetTriangleMask(int id) const { return fTriangleMasks[id]; }
0374   QuadMask_t const &GetQuadMask(int id) const { return fQuadMasks[id]; }
0375 
0376   EllipData_t const &GetEllipData(int id) const { return fEllipData[id]; }
0377   TorusData_t const &GetTorusData(int id) const { return fTorusData[id]; }
0378   Arb4Data_t const &GetArb4Data(int id) const { return fArb4Data[id]; }
0379 
0380   /// @brief Trampoline function to to the frame checker
0381   /// @param f1 Parent framed surface
0382   /// @param f2 Child framed surface
0383   /// @return Parent frame classification with respect to child
0384   FrameIntersect CheckFrames(FramedSurface<Real_t, TransformationMP<Real_t>> const &f1,
0385                              FramedSurface<Real_t, TransformationMP<Real_t>> const &f2,
0386                              TransformationMP<Real_t> *tscene = nullptr)
0387   {
0388     auto log_not_supported = [&]() {
0389       VECGEOM_LOG(error) << "Embedding check " << to_cstring(f1.fFrame.type) << " - " << to_cstring(f2.fFrame.type)
0390                          << " not supported";
0391     };
0392     TransformationMP<Real_t> t1 = f1.fTrans;
0393     TransformationMP<Real_t> t2 = f2.fTrans;
0394     if (tscene) t2 *= (*tscene);
0395     TransformationMP<Real_t> trans = t2 * t1.Inverse();
0396     trans.SetProperties();
0397 
0398     switch (f1.fFrame.type) {
0399     case FrameType::kRing: {
0400       RingMask_t const mask1 = GetRingMask(f1.fFrame.id);
0401       switch (f2.fFrame.type) {
0402       case FrameType::kRing: {
0403         RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0404         return FrameChecker<Real_t, RingMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0405       }
0406       case FrameType::kWindow: {
0407         WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0408         return FrameChecker<Real_t, RingMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0409       }
0410       case FrameType::kTriangle: {
0411         TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0412         return FrameChecker<Real_t, RingMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0413       }
0414       case FrameType::kQuadrilateral: {
0415         QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0416         return FrameChecker<Real_t, RingMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0417       }
0418       default:
0419         log_not_supported();
0420       };
0421       break;
0422     }
0423     case FrameType::kZPhi: {
0424       ZPhiMask_t const mask1 = GetZPhiMask(f1.fFrame.id);
0425       switch (f2.fFrame.type) {
0426       case FrameType::kZPhi: {
0427         ZPhiMask_t const mask2 = GetZPhiMask(f2.fFrame.id);
0428         return FrameChecker<Real_t, ZPhiMask_t, ZPhiMask_t>::CheckFrames(mask1, mask2, trans);
0429       }
0430       default:
0431         log_not_supported();
0432       };
0433       break;
0434     }
0435     case FrameType::kWindow: {
0436       WindowMask_t const mask1 = GetWindowMask(f1.fFrame.id);
0437       switch (f2.fFrame.type) {
0438       case FrameType::kRing: {
0439         RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0440         return FrameChecker<Real_t, WindowMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0441       }
0442       case FrameType::kWindow: {
0443         WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0444         return FrameChecker<Real_t, WindowMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0445       }
0446       case FrameType::kTriangle: {
0447         TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0448         return FrameChecker<Real_t, WindowMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0449       }
0450       case FrameType::kQuadrilateral: {
0451         QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0452         return FrameChecker<Real_t, WindowMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0453       }
0454       default:
0455         log_not_supported();
0456       };
0457       break;
0458     }
0459     case FrameType::kTriangle: {
0460       TriangleMask_t const mask1 = GetTriangleMask(f1.fFrame.id);
0461       switch (f2.fFrame.type) {
0462       case FrameType::kRing: {
0463         RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0464         return FrameChecker<Real_t, TriangleMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0465       }
0466       case FrameType::kWindow: {
0467         WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0468         return FrameChecker<Real_t, TriangleMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0469       }
0470       case FrameType::kTriangle: {
0471         TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0472         return FrameChecker<Real_t, TriangleMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0473       }
0474       case FrameType::kQuadrilateral: {
0475         QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0476         return FrameChecker<Real_t, TriangleMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0477       }
0478       default:
0479         log_not_supported();
0480       };
0481       break;
0482     }
0483     case FrameType::kQuadrilateral: {
0484       QuadMask_t const mask1 = GetQuadMask(f1.fFrame.id);
0485       switch (f2.fFrame.type) {
0486       case FrameType::kRing: {
0487         RingMask_t const mask2 = GetRingMask(f2.fFrame.id);
0488         return FrameChecker<Real_t, QuadMask_t, RingMask_t>::CheckFrames(mask1, mask2, trans);
0489       }
0490       case FrameType::kWindow: {
0491         WindowMask_t const mask2 = GetWindowMask(f2.fFrame.id);
0492         return FrameChecker<Real_t, QuadMask_t, WindowMask_t>::CheckFrames(mask1, mask2, trans);
0493       }
0494       case FrameType::kTriangle: {
0495         TriangleMask_t const mask2 = GetTriangleMask(f2.fFrame.id);
0496         return FrameChecker<Real_t, QuadMask_t, TriangleMask_t>::CheckFrames(mask1, mask2, trans);
0497       }
0498       case FrameType::kQuadrilateral: {
0499         QuadMask_t const mask2 = GetQuadMask(f2.fFrame.id);
0500         return FrameChecker<Real_t, QuadMask_t, QuadMask_t>::CheckFrames(mask1, mask2, trans);
0501       }
0502       default:
0503         log_not_supported();
0504       };
0505       break;
0506     }
0507     default:
0508       log_not_supported();
0509     };
0510     return FrameIntersect::kNoIntersect;
0511   }
0512 };
0513 
0514 } // namespace vgbrep
0515 
0516 #endif