Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ViewGeometry.cc
Go to the documentation of this file.
1#include <cmath>
2#include <iostream>
3
4#include <TGeoBBox.h>
5#include <TGeoCone.h>
6#include <TGeoArb8.h>
7#include <TGeoXtru.h>
8#include <TGeoBoolNode.h>
9#include <TGeoCompositeShape.h>
10#include <TPolyLine.h>
11
15#include "Garfield/Plotting.hh"
16#include "Garfield/Solid.hh"
18
19namespace Garfield {
20
21ViewGeometry::ViewGeometry() : ViewBase("ViewGeometry") {}
22
24 Reset();
25}
26
28 if (!geo) {
29 std::cerr << m_className << "::SetGeometry: Null pointer.\n";
30 return;
31 }
32
33 m_geometry = geo;
34}
35
36void ViewGeometry::Plot(const bool twod) {
37
38 if (twod) {
39 Plot2d();
40 } else {
41 Plot3d();
42 }
43}
44
46 if (!m_geometry) {
47 std::cerr << m_className << "::Plot3d: Geometry is not defined.\n";
48 return;
49 }
50
51 const unsigned int nSolids = m_geometry->GetNumberOfSolids();
52 if (nSolids == 0) {
53 std::cerr << m_className << "::Plot3d: Geometry is empty.\n";
54 return;
55 }
56
57 // Get the bounding box.
58 double xMin = 0., yMin = 0., zMin = 0.;
59 double xMax = 0., yMax = 0., zMax = 0.;
60 if (!m_geometry->GetBoundingBox(xMin, yMin, zMin, xMax, yMax, zMax)) {
61 std::cerr << m_className << "::Plot3d: Cannot retrieve bounding box.\n";
62 return;
63 }
64 auto canvas = GetCanvas();
65 canvas->cd();
66 gGeoManager = nullptr;
67 m_geoManager.reset(new TGeoManager("ViewGeometryGeoManager", ""));
68 TGeoMaterial* matVacuum = new TGeoMaterial("Vacuum", 0., 0., 0.);
69 TGeoMedium* medVacuum = new TGeoMedium("Vacuum", 1, matVacuum);
70 m_media.push_back(medVacuum);
71 // Use silicon as "default" material.
72 TGeoMaterial* matDefault = new TGeoMaterial("Default", 28.085, 14., 2.329);
73 TGeoMedium* medDefault = new TGeoMedium("Default", 1, matDefault);
74 TGeoVolume* world = m_geoManager->MakeBox(
75 "World", medVacuum, std::max(fabs(xMin), fabs(xMax)),
76 std::max(fabs(yMin), fabs(yMax)), std::max(fabs(zMin), fabs(zMax)));
77 m_geoManager->SetTopVolume(world);
78 m_volumes.push_back(world);
79
80 for (unsigned int i = 0; i < nSolids; ++i) {
81 Solid* solid = m_geometry->GetSolid(i);
82 if (!solid) {
83 std::cerr << m_className << "::Plot3d:\n"
84 << " Could not get solid " << i << " from geometry.\n";
85 continue;
86 }
87 // Get the center coordinates.
88 double x0 = 0., y0 = 0., z0 = 0.;
89 if (!solid->GetCentre(x0, y0, z0)) {
90 std::cerr << m_className << "::Plot3d: Could not determine solid centre.\n";
91 continue;
92 }
93 // Get the rotation.
94 double ctheta = 1., stheta = 0.;
95 double cphi = 1., sphi = 0.;
96 if (!solid->GetOrientation(ctheta, stheta, cphi, sphi)) {
97 std::cerr << m_className << "::Plot3d:\n"
98 << " Could not determine solid orientation.\n";
99 continue;
100 }
101 double matrix[9] = {cphi * ctheta, -sphi, cphi * stheta,
102 sphi * ctheta, cphi, sphi * stheta,
103 -stheta, 0, ctheta};
104 TGeoVolume* volume = nullptr;
105 if (solid->IsTube()) {
106 const double rt = solid->GetRadius();
107 const double lz = solid->GetHalfLengthZ();
108 volume = m_geoManager->MakeTube("Tube", medDefault, 0., rt, lz);
109 } else if (solid->IsWire()) {
110 const double rw = solid->GetRadius();
111 const double lz = solid->GetHalfLengthZ();
112 volume = m_geoManager->MakeTube("Wire", medDefault, 0., rw, lz);
113 } else if (solid->IsBox()) {
114 const double dx = solid->GetHalfLengthX();
115 const double dy = solid->GetHalfLengthY();
116 const double dz = solid->GetHalfLengthZ();
117 volume = m_geoManager->MakeBox("Box", medDefault, dx, dy, dz);
118 } else if (solid->IsSphere()) {
119 const double rmin = std::max(solid->GetInnerRadius(), 0.);
120 const double rmax = solid->GetOuterRadius();
121 volume = m_geoManager->MakeSphere("Sphere", medDefault, rmin, rmax);
122 } else if (solid->IsHole()) {
123 const double r1 = solid->GetLowerRadius();
124 const double r2 = solid->GetUpperRadius();
125 const double dx = solid->GetHalfLengthX();
126 const double dy = solid->GetHalfLengthY();
127 const double dz = solid->GetHalfLengthZ();
128 const double lz = 10 * std::max({dx, dy, dz});
129 const double rm = 0.5 * (r1 + r2);
130 const double dr = 0.5 * (r2 - r1) * lz / dz;
131 TGeoBBox* box = new TGeoBBox("HoleBox", dx, dy, dz);
132 TGeoCone* cone = new TGeoCone("HoleCone", lz, 0, rm - dr, 0, rm + dr);
133 TGeoCompositeShape* hole = new TGeoCompositeShape("Hole",
134 new TGeoSubtraction(box, cone));
135 hole->RegisterYourself();
136 volume = new TGeoVolume("Hole", hole, medDefault);
137 } else if (solid->IsRidge()) {
138 const double dx = solid->GetHalfLengthX();
139 const double dy = solid->GetHalfLengthY();
140 const double dz = 0.5 * solid->GetRidgeHeight();
141 const double xr = solid->GetRidgeOffset();
142 volume = m_geoManager->MakeArb8("Ridge", medDefault, dz);
143 auto arb = (TGeoArb8*)volume->GetShape();
144 arb->SetVertex(0, -dx, -dy);
145 arb->SetVertex(1, -dx, +dy);
146 arb->SetVertex(2, +dx, +dy);
147 arb->SetVertex(3, +dx, -dy);
148 arb->SetVertex(4, xr, -dy);
149 arb->SetVertex(5, xr, +dy);
150 arb->SetVertex(6, xr, +dy);
151 arb->SetVertex(7, xr, -dy);
152 z0 += dz;
153 } else if (solid->IsExtrusion()) {
154 const double dz = solid->GetHalfLengthZ();
155 std::vector<double> xp;
156 std::vector<double> yp;
157 if (!solid->GetProfile(xp, yp)) continue;
158 volume = m_geoManager->MakeXtru("Extrusion", medDefault, 2);
159 auto xtru = (TGeoXtru*)volume->GetShape();
160 xtru->DefinePolygon(xp.size(), xp.data(), yp.data());
161 xtru->DefineSection(0, -dz);
162 xtru->DefineSection(1, +dz);
163 } else {
164 std::cerr << m_className << "::Plot3d: Unknown type of solid.\n";
165 continue;
166 }
167 Medium* medium = m_geometry->GetMedium(x0, y0, z0);
168 if (solid->GetColour() >= 0) {
169 volume->SetLineColor(solid->GetColour());
170 } else if (!medium) {
171 volume->SetLineColor(kGreen + 2);
172 volume->SetTransparency(50);
173 } else if (medium->IsGas()) {
174 volume->SetLineColor(kBlue + medium->GetId());
175 volume->SetTransparency(50);
176 } else if (medium->IsSemiconductor()) {
177 volume->SetLineColor(kRed + medium->GetId());
178 volume->SetTransparency(50);
179 } else {
180 volume->SetLineColor(kViolet + medium->GetId());
181 volume->SetTransparency(0);
182 }
183 TGeoRotation r;
184 r.SetMatrix(matrix);
185 TGeoTranslation t(x0, y0, z0);
186 TGeoCombiTrans* transform = new TGeoCombiTrans(t, r);
187 m_volumes.push_back(volume);
188 m_geoManager->GetTopVolume()->AddNode(volume, 1, transform);
189 }
190 m_geoManager->CloseGeometry();
191 m_geoManager->GetTopNode()->Draw("ogl");
192}
193
195
196 if (!m_geometry) {
197 std::cerr << m_className << "::Plot2d: Geometry is not defined.\n";
198 return;
199 }
200
201 const unsigned int nSolids = m_geometry->GetNumberOfSolids();
202 if (nSolids == 0) {
203 std::cerr << m_className << "::Plot2d: Geometry is empty.\n";
204 return;
205 }
206
207 // Determine the plot limits.
208 double x0 = 0., y0 = 0.;
209 double x1 = 0., y1 = 0.;
210 if (m_userPlotLimits) {
211 x0 = m_xMinPlot;
212 y0 = m_yMinPlot;
213 x1 = m_xMaxPlot;
214 y1 = m_yMaxPlot;
215 } else if (m_userBox) {
216 PlotLimitsFromUserBox(x0, y0, x1, y1);
217 } else {
218 std::array<double, 3> bbmin;
219 std::array<double, 3> bbmax;
220 if (!m_geometry->GetBoundingBox(bbmin[0], bbmin[1], bbmin[2],
221 bbmax[0], bbmax[1], bbmax[2])) {
222 std::cerr << m_className << "::Plot2d: Cannot retrieve bounding box.\n";
223 return;
224 }
225 PlotLimits(bbmin, bbmax, x0, y0, x1, y1);
226 }
227
228 auto canvas = GetCanvas();
229 canvas->cd();
230 canvas->SetTitle("Geometry");
231
232 bool empty = false;
233 if (!gPad ||
234 (gPad->GetListOfPrimitives()->GetSize() == 0 && gPad->GetX1() == 0 &&
235 gPad->GetX2() == 1 && gPad->GetY1() == 0 && gPad->GetY2() == 1)) {
236 empty = true;
237 }
238 const double bm = canvas->GetBottomMargin();
239 const double lm = canvas->GetLeftMargin();
240 const double rm = canvas->GetRightMargin();
241 const double tm = canvas->GetTopMargin();
242 if (!empty) {
243 TPad* pad = new TPad("geo", "", 0, 0, 1, 1);
244 pad->SetFillStyle(0);
245 pad->SetFrameFillStyle(0);
246 pad->Draw();
247 pad->cd();
248 }
249 gPad->Range(x0 - (x1 - x0) * (lm / (1. - rm - lm)),
250 y0 - (y1 - y0) * (bm / (1. - tm - lm)),
251 x1 + (x1 - x0) * (rm / (1. - rm - lm)),
252 y1 + (y1 - y0) * (tm / (1. - tm - lm)));
253 TPolyLine pl;
254 pl.SetLineWidth(2);
255 for (unsigned int i = 0; i < nSolids; ++i) {
256 auto solid = m_geometry->GetSolid(i);
257 if (!solid) continue;
258 std::vector<Panel> panels;
259 solid->Cut(m_proj[2][0], m_proj[2][1], m_proj[2][2],
260 m_plane[0], m_plane[1], m_plane[2], panels);
261 for (const auto& panel : panels) {
262 const unsigned int nv = panel.xv.size();
263 if (nv < 3) continue;
264 std::vector<double> xpl;
265 std::vector<double> ypl;
266 for (unsigned int j = 0; j < nv; ++j) {
267 double u, v;
268 ToPlane(panel.xv[j], panel.yv[j], panel.zv[j], u, v);
269 xpl.push_back(u);
270 ypl.push_back(v);
271 }
272 xpl.push_back(xpl[0]);
273 ypl.push_back(ypl[0]);
274 if (panel.colour < 0) {
275 pl.SetLineColor(kBlack);
276 } else {
277 pl.SetLineColor(panel.colour);
278 }
279 pl.DrawPolyLine(nv + 1, xpl.data(), ypl.data(), "same");
280 }
281 }
282 gPad->Update();
283}
284
285void ViewGeometry::Reset() {
286 for (auto it = m_volumes.begin(), end = m_volumes.end(); it != end; ++it) {
287 if (*it) {
288 TGeoShape* shape = (*it)->GetShape();
289 if (shape) delete shape;
290 delete *it;
291 }
292 }
293 m_volumes.clear();
294 for (auto it = m_media.begin(), end = m_media.end(); it != end; ++it) {
295 if (*it) {
296 TGeoMaterial* material = (*it)->GetMaterial();
297 if (material) delete material;
298 delete *it;
299 }
300 }
301 m_media.clear();
302
303 m_geoManager.reset(nullptr);
304}
305
306}
"Native" geometry, using simple shapes.
size_t GetNumberOfSolids() const override
Return the number of solids in the geometry.
Medium * GetMedium(const double x, const double y, const double z, const bool tesselated=false) const override
Retrieve the medium at a given point.
Solid * GetSolid(const size_t i) const override
Get a solid from the list.
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box (envelope of the geometry).
Abstract base class for media.
Definition: Medium.hh:13
int GetId() const
Return the id number of the class instance.
Definition: Medium.hh:21
virtual bool IsSemiconductor() const
Is this medium a semiconductor?
Definition: Medium.hh:27
virtual bool IsGas() const
Is this medium a gas?
Definition: Medium.hh:25
Abstract base class for solids.
Definition: Solid.hh:28
virtual double GetUpperRadius() const
Return the upper radius (of a hole).
Definition: Solid.hh:121
virtual bool IsTube() const
Return true if the solid is a tube.
Definition: Solid.hh:53
virtual bool IsRidge() const
Return true if the solid is a ridge.
Definition: Solid.hh:59
virtual double GetHalfLengthX() const
Return the half-length along x.
Definition: Solid.hh:95
virtual bool IsHole() const
Return true if the solid is a hole.
Definition: Solid.hh:57
virtual double GetHalfLengthZ() const
Return the half-length along z.
Definition: Solid.hh:103
virtual bool IsBox() const
Return true if the solid is a box.
Definition: Solid.hh:51
virtual double GetHalfLengthY() const
Return the half-length along y.
Definition: Solid.hh:99
virtual bool IsExtrusion() const
Return true if the solid is an extrusion.
Definition: Solid.hh:61
bool GetCentre(double &x, double &y, double &z) const
Retrieve the centre point of the solid.
Definition: Solid.hh:71
virtual bool GetProfile(std::vector< double > &xv, std::vector< double > &yv) const
Get the vertices defining an extrusion.
Definition: Solid.cc:40
virtual double GetRidgeOffset() const
Return the x-offset of a ridge.
Definition: Solid.hh:125
virtual double GetLowerRadius() const
Return the lower radius (of a hole).
Definition: Solid.hh:117
virtual void Cut(const double x0, const double y0, const double z0, const double xn, const double yn, const double zn, std::vector< Panel > &panels)=0
virtual double GetOuterRadius() const
Return the outer radius.
Definition: Solid.hh:111
bool GetOrientation(double &ctheta, double &stheta, double &cphi, double &sphi) const
Retrieve the orientation (azimuthal and polar angles) of the solid.
Definition: Solid.hh:85
virtual bool IsWire() const
Return true if the solid is a wire.
Definition: Solid.hh:63
int GetColour() const
Get the colour of the solid.
Definition: Solid.hh:192
virtual double GetRadius() const
Return the radius.
Definition: Solid.hh:115
virtual bool IsSphere() const
Return true if the solid is a sphere.
Definition: Solid.hh:55
virtual double GetInnerRadius() const
Return the inner radius.
Definition: Solid.hh:107
virtual double GetRidgeHeight() const
Return the height of a ridge.
Definition: Solid.hh:129
Base class for visualization classes.
Definition: ViewBase.hh:18
std::array< double, 4 > m_plane
Definition: ViewBase.hh:99
std::string m_className
Definition: ViewBase.hh:78
std::array< std::array< double, 3 >, 3 > m_proj
Definition: ViewBase.hh:96
TPad * GetCanvas()
Retrieve the canvas.
Definition: ViewBase.cc:74
bool PlotLimits(Sensor *sensor, double &xmin, double &ymin, double &xmax, double &ymax) const
Definition: ViewBase.cc:608
void ToPlane(const T x, const T y, const T z, T &xp, T &yp) const
Definition: ViewBase.hh:109
bool PlotLimitsFromUserBox(double &xmin, double &ymin, double &xmax, double &ymax) const
Definition: ViewBase.cc:663
void Plot3d()
Draw a three-dimensional view of the geometry.
Definition: ViewGeometry.cc:45
void SetGeometry(GeometrySimple *geo)
Set the geometry to be drawn.
Definition: ViewGeometry.cc:27
~ViewGeometry()
Destructor.
Definition: ViewGeometry.cc:23
void Plot(const bool twod=false)
Draw the geometry.
Definition: ViewGeometry.cc:36
void Plot2d()
Draw a cut through the geometry at the current viewing plane.
ViewGeometry()
Constructor.
Definition: ViewGeometry.cc:21