From 07e2f5c6307b8c2f379617a9767fa6f0d42cccd5 Mon Sep 17 00:00:00 2001 From: Andrei Gheata Date: Tue, 14 Feb 2023 17:34:57 +0100 Subject: [PATCH] [geom] Extended TGeoVGShape with extra solids Added support for tesselated, ellipsoid, hyperboloid and cut tube. Added the macro tutorials/geom/tessellatedNav.C importing and raytracing a tessellated solid. --- geom/geom/inc/TGeoTessellated.h | 4 +- geom/vecgeom/src/TGeoVGShape.cxx | 62 +++++++++++++++++++++--- tutorials/CMakeLists.txt | 5 ++ tutorials/geom/tessellatedNav.C | 81 ++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 tutorials/geom/tessellatedNav.C diff --git a/geom/geom/inc/TGeoTessellated.h b/geom/geom/inc/TGeoTessellated.h index 64deb80fdac07..3e382f21ef695 100644 --- a/geom/geom/inc/TGeoTessellated.h +++ b/geom/geom/inc/TGeoTessellated.h @@ -141,8 +141,8 @@ class TGeoTessellated : public TGeoBBox { bool IsClosedBody() const { return fClosedBody; } bool IsDefined() const { return fDefined; } - const TGeoFacet &GetFacet(int i) { return fFacets[i]; } - const Vertex_t &GetVertex(int i) { return fVertices[i]; } + const TGeoFacet &GetFacet(int i) const { return fFacets[i]; } + const Vertex_t &GetVertex(int i) const { return fVertices[i]; } virtual void AfterStreamer(); virtual int DistancetoPrimitive(int, int) { return 99999; } diff --git a/geom/vecgeom/src/TGeoVGShape.cxx b/geom/vecgeom/src/TGeoVGShape.cxx index 8b933fedf9285..c3a2188d82aa5 100644 --- a/geom/vecgeom/src/TGeoVGShape.cxx +++ b/geom/vecgeom/src/TGeoVGShape.cxx @@ -33,6 +33,11 @@ Bridge class for using a VecGeom solid as TGeoShape. #include "VecGeom/volumes/UnplacedScaledShape.h" #include "VecGeom/volumes/UnplacedGenTrap.h" #include "VecGeom/volumes/UnplacedSExtruVolume.h" +#include "VecGeom/volumes/UnplacedTessellated.h" +#include "VecGeom/volumes/UnplacedEllipticalTube.h" +#include "VecGeom/volumes/UnplacedHype.h" +#include "VecGeom/volumes/UnplacedCutTube.h" + #include "TError.h" #include "TGeoManager.h" #include "TGeoMaterial.h" @@ -54,6 +59,8 @@ Bridge class for using a VecGeom solid as TGeoShape. #include "TGeoTorus.h" #include "TGeoEltu.h" #include "TGeoXtru.h" +#include "TGeoTessellated.h" +#include "TGeoHype.h" //////////////////////////////////////////////////////////////////////////////// /// Default constructor @@ -122,6 +129,7 @@ vecgeom::cxx::Transformation3D *TGeoVGShape::Convert(TGeoMatrix const *const geo vecgeom::cxx::VUnplacedVolume *TGeoVGShape::Convert(TGeoShape const *const shape) { using namespace vecgeom; + using Vector3D = vecgeom::cxx::Vector3D; VUnplacedVolume *unplaced_volume = nullptr; // THE BOX @@ -287,20 +295,36 @@ vecgeom::cxx::VUnplacedVolume *TGeoVGShape::Convert(TGeoShape const *const shape GeoManager::MakeInstance(referenced_shape, scale_root[0], scale_root[1], scale_root[2]); } - // THE ELLIPTICAL TUBE AS SCALED TUBE + // THE CUT TUBE + if (shape->IsA() == TGeoCtub::Class()) { + TGeoCtub const *const p = static_cast(shape); + auto low = p->GetNlow(); + auto high = p->GetNhigh(); + auto const bottomNormal = Vector3D{low[0], low[1], low[2]}; + auto const topNormal = Vector3D{high[0], high[1], high[2]}; + + unplaced_volume = + GeoManager::MakeInstance(p->GetRmin(), p->GetRmax(), p->GetDz(), kDegToRad * p->GetPhi1(), + kDegToRad * (p->GetPhi2() - p->GetPhi1()), bottomNormal, topNormal); + } + + // THE ELLIPTICAL TUBE if (shape->IsA() == TGeoEltu::Class()) { TGeoEltu const *const p = static_cast(shape); - // Create the corresponding unplaced tube, with: - // rmin=0, rmax=A, dz=dz, which is scaled with (1., A/B, 1.) - GenericUnplacedTube *tubeUnplaced = new GenericUnplacedTube(0, p->GetA(), p->GetDZ(), 0, kTwoPi); - unplaced_volume = new UnplacedScaledShape(tubeUnplaced, 1., p->GetB() / p->GetA(), 1.); + unplaced_volume = GeoManager::MakeInstance(p->GetA(), p->GetB(), p->GetDz()); + } + + // THE HYPERBOLOID + if (shape->IsA() == TGeoHype::Class()) { + TGeoHype const *const p = static_cast(shape); + unplaced_volume = GeoManager::MakeInstance(p->GetRmin(), p->GetRmax(), kDegToRad * p->GetStIn(), + kDegToRad * p->GetStOut(), p->GetDz()); } // THE ARB8 if (shape->IsA() == TGeoArb8::Class() || shape->IsA() == TGeoGtra::Class()) { TGeoArb8 *p = (TGeoArb8 *)(shape); // Create the corresponding GenTrap - std::vector> vertexlist; const double *vertices = p->GetVertices(); Precision verticesx[8], verticesy[8]; for (auto ivert = 0; ivert < 8; ++ivert) { @@ -338,6 +362,32 @@ vecgeom::cxx::VUnplacedVolume *TGeoVGShape::Convert(TGeoShape const *const shape } } + // THE TESSELLATED + if (shape->IsA() == TGeoTessellated::Class()) { + TGeoTessellated const *const tsl = static_cast(shape); + unplaced_volume = GeoManager::MakeInstance(); + auto vtsl = static_cast(unplaced_volume); + + for (auto i = 0; i < tsl->GetNfacets(); ++i) { + auto const &facet = tsl->GetFacet(i); + int nvert = facet.GetNvert(); + auto const &v0 = facet.GetVertex(0); + auto const &v1 = facet.GetVertex(1); + auto const &v2 = facet.GetVertex(2); + if (nvert == 3) { + vtsl->AddTriangularFacet(Vector3D(v0[0], v0[1], v0[2]), Vector3D(v1[0], v1[1], v1[2]), + Vector3D(v2[0], v2[1], v2[2])); + } else if (nvert == 4) { + auto const &v3 = facet.GetVertex(3); + vtsl->AddQuadrilateralFacet(Vector3D(v0[0], v0[1], v0[2]), Vector3D(v1[0], v1[1], v1[2]), + Vector3D(v2[0], v2[1], v2[2]), Vector3D(v3[0], v3[1], v3[2])); + } else { + return nullptr; // should never happen + } + } + vtsl->Close(); + } + // New volumes should be implemented here... if (!unplaced_volume) { printf("Unsupported shape for ROOT shape \"%s\" of type %s. " diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index f662d6a44b770..5bd882cf4b0e9 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -330,6 +330,10 @@ else() endif() endif() +if (NOT ROOT_vecgeom_FOUND) + set(vecgeom_veto geom/tessellatedNav.C) +endif() + if(root7) set(root7_veto dataframe/df013_InspectAnalysis.C v7/browser.cxx @@ -446,6 +450,7 @@ set(all_veto hsimple.C ${imt_veto} ${classic_veto} ${pythia_veto} + ${vecgeom_veto} ${root7_veto} ${xrootd_veto} ${mlp_veto} diff --git a/tutorials/geom/tessellatedNav.C b/tutorials/geom/tessellatedNav.C new file mode 100644 index 0000000000000..86b1bd16f1860 --- /dev/null +++ b/tutorials/geom/tessellatedNav.C @@ -0,0 +1,81 @@ +/// \file +/// \ingroup tutorial_geom +/// Macro allowing to vizualize tessellations from Wavefront's .obj format. +/// +/// \image html geom_visualizeWavefrontObj.png width=500px +/// \macro_code +/// +/// \author Andrei Gheata + +#include +#include +#include +#include +#include +#include +#include +#include + +//______________________________________________________________________________ +int randomColor() +{ + gRandom = new TRandom3(); + TDatime dt; + gRandom->SetSeed(dt.GetTime()); + int ci = TColor::GetFreeColorIndex(); + TColor *color = new TColor(ci, gRandom->Rndm(), gRandom->Rndm(), gRandom->Rndm()); + return ci; +} + +//______________________________________________________________________________ +void tessellatedNav(const char *dot_obj_file = "", bool check = false) +{ + // Input a file in .obj format (https://en.wikipedia.org/wiki/Wavefront_.obj_file) + // The file should have a single object inside, only vertex and faces information is used + TString name = dot_obj_file; + TString sfile = dot_obj_file; + if (sfile.IsNull()) { + sfile = gROOT->GetTutorialsDir(); + sfile += "/geom/teddy.obj"; + } + name.ReplaceAll(".obj", ""); + gROOT->GetListOfCanvases()->Delete(); + if (gGeoManager) + delete gGeoManager; + auto geom = new TGeoManager(name, "Imported from .obj file"); + TGeoMaterial *mat = new TGeoMaterial("Al", 26.98, 13, 2.7); + TGeoMedium *med = new TGeoMedium("MED", 1, mat); + TGeoVolume *top = geom->MakeBox("TOP", med, 10, 10, 10); + geom->SetTopVolume(top); + + auto tsl = TGeoTessellated::ImportFromObjFormat(sfile.Data(), check); + if (!tsl) + return; + tsl->ResizeCenter(5.); + + TGeoVolume *vol = new TGeoVolume(name, tsl, med); + vol->SetLineColor(randomColor()); + vol->SetLineWidth(2); + top->AddNode(vol, 1); + geom->CloseGeometry(); + + // Convert to VecGeom tessellated solid + auto converter = TVirtualGeoConverter::Instance(geom); + if (!converter) { + printf("Raytracing a tessellated shape without VecGeom support will just draw a box\n"); + } else { + converter->ConvertGeometry(); + } + + if (gROOT->IsBatch()) + return; + // Set the view + top->Draw(); + TView *view = gPad->GetView(); + if (!view) + return; + view->Top(); + + // Raytracing will call VecGeom navigation + top->Raytrace(); +}