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