Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
SolidExtrusion.cc
Go to the documentation of this file.
1#include <cmath>
2#include <algorithm>
3#include <iostream>
4
5#include "Garfield/Polygon.hh"
7
8namespace Garfield {
9
11 const std::vector<double>& xp,
12 const std::vector<double>& yp)
13 : Solid(0, 0, 0, "SolidExtrusion"), m_lZ(lz) {
14 SetProfile(xp, yp);
15}
16
18 const std::vector<double>& xp,
19 const std::vector<double>& yp,
20 const double cx, const double cy,
21 const double cz,
22 const double dx, const double dy,
23 const double dz)
24 : SolidExtrusion(lz, xp, yp) {
25 m_cX = cx;
26 m_cY = cy;
27 m_cZ = cz;
28 SetDirection(dx, dy, dz);
29}
30
31bool SolidExtrusion::IsInside(const double x, const double y, const double z,
32 const bool /*tesselated*/) const {
33
34 if (m_xp.empty()) return false;
35 // Transform the point to local coordinates.
36 double u = x, v = y, w = z;
37 ToLocal(x, y, z, u, v, w);
38 if (fabs(w) > m_lZ) return false;
39 bool inside = false, edge = false;
40 Polygon::Inside(m_xp, m_yp, u, v, inside, edge);
41 return inside;
42}
43
44bool SolidExtrusion::GetBoundingBox(double& xmin, double& ymin, double& zmin,
45 double& xmax, double& ymax, double& zmax) const {
46
47 if (m_xp.empty()) return false;
48 const double x0 = *std::min_element(m_xp.begin(), m_xp.end());
49 const double x1 = *std::max_element(m_xp.begin(), m_xp.end());
50 const double y0 = *std::min_element(m_yp.begin(), m_yp.end());
51 const double y1 = *std::max_element(m_yp.begin(), m_yp.end());
52 // Take the margins wide.
53 const double r = std::max({fabs(x0), fabs(y0), fabs(x1), fabs(y1)});
54 const double d = sqrt(r * r + m_lZ * m_lZ);
55 xmin = m_cX - d;
56 xmax = m_cX + d;
57 ymin = m_cY - d;
58 ymax = m_cY + d;
59 zmin = m_cZ - d;
60 zmax = m_cZ + d;
61 return true;
62}
63
64void SolidExtrusion::SetHalfLengthZ(const double lz) {
65 if (lz > 0.) {
66 m_lZ = lz;
67 } else {
68 std::cerr << "SolidExtrusion::SetHalfLengthZ: Half-length must be > 0.\n";
69 }
70}
71
72void SolidExtrusion::SetProfile(const std::vector<double>& xp,
73 const std::vector<double>& yp) {
74
75 if (xp.size() != yp.size()) {
76 std::cerr << "SolidExtrusion::SetProfile:\n"
77 << " Mismatch between number of x and y coordinates.\n";
78 return;
79 }
80 const auto np = xp.size();
81 if (np < 3) {
82 std::cerr << "SolidExtrusion::SetProfile: Too few points; rejected.\n";
83 return;
84 }
85 if (!Polygon::NonTrivial(xp, yp)) {
86 std::cerr << "SolidExtrusion::SetProfile: Not a valid polygon.\n";
87 return;
88 }
89 const auto it = std::max_element(xp.begin(), xp.end());
90 const unsigned int i0 = std::distance(xp.begin(), it);
91 const unsigned int i1 = i0 < np - 1 ? i0 + 1 : 0;
92 const unsigned int i2 = i1 < np - 1 ? i1 + 1 : 0;
93 const double det = (xp[i1] - xp[i0]) * (yp[i2] - yp[i0]) -
94 (xp[i2] - xp[i0]) * (yp[i1] - yp[i0]);
95 if (det < 0.) {
96 m_clockwise = true;
97 } else if (det > 0.) {
98 m_clockwise = false;
99 } else {
100 std::cerr << "SolidExtrusion::SetProfile:\n"
101 << " Unable to determine profile orientation;"
102 << " assuming it is clockwise.\n";
103 m_clockwise = true;
104 }
105 m_xp = xp;
106 m_yp = yp;
107}
108
109bool SolidExtrusion::SolidPanels(std::vector<Panel>& panels) {
110 // -----------------------------------------------------------------------
111 // PLAEXP - Generates a table of polygons for an extrusion.
112 // -----------------------------------------------------------------------
113 const auto id = GetId();
114 const auto nPanels = panels.size();
115 if (m_xp.empty()) {
116 std::cerr << "SolidExtrusion::SolidPanels: Profile is not defined.\n";
117 return false;
118 }
119 // Direction vector.
120 const double fnorm = sqrt(m_dX * m_dX + m_dY * m_dY + m_dZ * m_dZ);
121 if (fnorm <= 0) {
122 std::cerr << "SolidExtrusion::SolidPanels:\n"
123 << " Zero norm direction vector; no panels generated.\n";
124 return false;
125 }
126 const double a = m_dX / fnorm;
127 const double b = m_dY / fnorm;
128 const double c = m_dZ / fnorm;
129 // Number of points
130 const unsigned int np = m_xp.size();
131 // Create the top lid.
132 if (m_toplid) {
133 Panel panel;
134 panel.a = a;
135 panel.b = b;
136 panel.c = c;
137 for (unsigned int i = 0; i < np; ++i) {
138 // Rotate into place.
139 double x, y, z;
140 ToGlobal(m_xp[i], m_yp[i], m_lZ, x, y, z);
141 panel.xv.push_back(x);
142 panel.yv.push_back(y);
143 panel.zv.push_back(z);
144 }
145 panel.colour = m_colour;
146 panel.volume = id;
147 panels.push_back(std::move(panel));
148 }
149 // Create the bottom lid.
150 if (m_botlid) {
151 Panel panel;
152 panel.a = -a;
153 panel.b = -b;
154 panel.c = -c;
155 for (unsigned int i = 0; i < np; ++i) {
156 // Rotate into place.
157 double x, y, z;
158 ToGlobal(m_xp[i], m_yp[i], -m_lZ, x, y, z);
159 panel.xv.push_back(x);
160 panel.yv.push_back(y);
161 panel.zv.push_back(z);
162 }
163 panel.colour = m_colour;
164 panel.volume = id;
165 panels.push_back(std::move(panel));
166 }
167 // Create the side panels.
168 if (m_lZ > 0) {
169 double x0, y0, z0;
170 ToGlobal(m_xp.back(), m_yp.back(), -m_lZ, x0, y0, z0);
171 double x1, y1, z1;
172 ToGlobal(m_xp.back(), m_yp.back(), +m_lZ, x1, y1, z1);
173 // Go around the extrusion.
174 for (unsigned int i = 0; i < np; ++i) {
175 // Bottom and top of the line along the axis of the extrusion.
176 double x2, y2, z2;
177 ToGlobal(m_xp[i], m_yp[i], +m_lZ, x2, y2, z2);
178 double x3, y3, z3;
179 ToGlobal(m_xp[i], m_yp[i], -m_lZ, x3, y3, z3);
180 // Compute the normal vector.
181 const unsigned int k = i == 0 ? np - 1 : i - 1;
182 double xn = m_yp[k] - m_yp[i];
183 double yn = m_xp[i] - m_xp[k];
184 const double fn = sqrt(xn * xn + yn * yn);
185 if (fn <= 0) {
186 std::cerr << "SolidExtrusion::SolidPanels: Zero norm edge (warning).\n";
187 continue;
188 }
189 if (m_clockwise) {
190 xn = xn / fn;
191 yn = yn / fn;
192 } else {
193 xn = -xn / fn;
194 yn = -yn / fn;
195 }
196 Panel panel;
197 panel.a = m_cPhi * m_cTheta * xn - m_sPhi * yn;
198 panel.b = m_sPhi * m_cTheta * xn + m_cPhi * yn;
199 panel.c = -m_sTheta * xn;
200 panel.xv = {x0, x1, x2, x3};
201 panel.yv = {y0, y1, y2, y3};
202 panel.zv = {z0, z1, z2, z3};
203 panel.colour = m_colour;
204 panel.volume = id;
205 panels.push_back(std::move(panel));
206 // Shift the points.
207 x0 = x3;
208 y0 = y3;
209 z0 = z3;
210 x1 = x2;
211 y1 = y2;
212 z1 = z2;
213 }
214 }
215 // Done, check panel count.
216 std::cout << "SolidExtrusion::SolidPanels: " << panels.size() - nPanels
217 << " panels.\n";
218 return true;
219}
220
222
223 // Transform the normal vector to local coordinates.
224 double u = 0., v = 0., w = 0.;
225 VectorToLocal(panel.a, panel.b, panel.c, u, v, w);
226 // Identify the vector.
227 if (w > std::max(fabs(u), fabs(v))) {
228 return m_dis[0];
229 } else if (w < -std::max(fabs(u), fabs(v))) {
230 return m_dis[1];
231 }
232 return m_dis[2];
233}
234
235void SolidExtrusion::Cut(const double x0, const double y0, const double z0,
236 const double xn, const double yn, const double zn,
237 std::vector<Panel>& panels) {
238
239 //-----------------------------------------------------------------------
240 // PLAEXC - Cuts extrusion with a plane.
241 //-----------------------------------------------------------------------
242
243 std::vector<double> xv;
244 std::vector<double> yv;
245 std::vector<double> zv;
246 const unsigned int np = m_xp.size();
247 // Go through the lines of the top lid, first point.
248 double x1, y1, z1;
249 ToGlobal(m_xp.back(), m_yp.back(), m_lZ, x1, y1, z1);
250 // Loop over the points.
251 for (unsigned int i = 0; i < np; ++i) {
252 double x2, y2, z2;
253 ToGlobal(m_xp[i], m_yp[i], m_lZ, x2, y2, z2);
254 // Cut with the plane.
255 double xc, yc, zc;
256 if (Intersect(x1, y1, z1, x2, y2, z2,
257 x0, y0, z0, xn, yn, zn, xc, yc, zc)) {
258 xv.push_back(xc);
259 yv.push_back(yc);
260 zv.push_back(zc);
261 }
262 // Shift the coordinates.
263 x1 = x2;
264 y1 = y2;
265 z1 = z2;
266 }
267
268 if (m_lZ > 0.) {
269 // Go through the lines of the bottom lid, first point.
270 ToGlobal(m_xp.back(), m_yp.back(), -m_lZ, x1, y1, z1);
271 // Loop over the points.
272 for (unsigned int i = 0; i < np; ++i) {
273 double x2, y2, z2;
274 ToGlobal(m_xp[i], m_yp[i], -m_lZ, x2, y2, z2);
275 double xc, yc, zc;
276 if (Intersect(x1, y1, z1, x2, y2, z2,
277 x0, y0, z0, xn, yn, zn, xc, yc, zc)) {
278 xv.push_back(xc);
279 yv.push_back(yc);
280 zv.push_back(zc);
281 }
282 // Shift the coordinates.
283 x1 = x2;
284 y1 = y2;
285 z1 = z2;
286 }
287 // Go through the ribs.
288 for (unsigned int i = 0; i < np; ++i) {
289 // Bottom and top of the line along the axis of the extrusion.
290 ToGlobal(m_xp[i], m_yp[i], +m_lZ, x1, y1, z1);
291 double x2, y2, z2;
292 ToGlobal(m_xp[i], m_yp[i], -m_lZ, x2, y2, z2);
293 double xc, yc, zc;
294 if (Intersect(x1, y1, z1, x2, y2, z2,
295 x0, y0, z0, xn, yn, zn, xc, yc, zc)) {
296 xv.push_back(xc);
297 yv.push_back(yc);
298 zv.push_back(zc);
299 }
300 }
301 }
302 // Get rid of butterflies.
304 if (xv.size() >= 3) {
305 Panel panel;
306 panel.a = xn;
307 panel.b = yn;
308 panel.c = zn;
309 panel.xv = xv;
310 panel.yv = yv;
311 panel.zv = zv;
312 panel.colour = m_colour;
313 panel.volume = GetId();
314 panels.push_back(std::move(panel));
315 }
316}
317
318}
bool IsInside(const double x, const double y, const double z, const bool tesselated) const override
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) const override
Return the bounding box of the solid.
double GetDiscretisationLevel(const Panel &panel) override
Retrieve the discretisation level of a panel.
bool SolidPanels(std::vector< Panel > &panels) override
Retrieve the surface panels of the solid.
void SetHalfLengthZ(const double lz)
Set the half-length of the extrusion.
void SetProfile(const std::vector< double > &xp, const std::vector< double > &yp)
Set the coordinates of the extrusion profile.
void Cut(const double x0, const double y0, const double z0, const double xn, const double yn, const double zn, std::vector< Panel > &panels) override
SolidExtrusion(const double lz, const std::vector< double > &xp, const std::vector< double > &yp)
Constructor from half-length and profile.
Abstract base class for solids.
Definition: Solid.hh:28
double m_dZ
Definition: Solid.hh:205
double m_cZ
Definition: Solid.hh:202
void VectorToLocal(const double x, const double y, const double z, double &u, double &v, double &w)
Transform a vector from global to local coordinates.
Definition: Solid.hh:253
double m_cTheta
Polar angle.
Definition: Solid.hh:209
static bool Intersect(const double x1, const double y1, const double z1, const double x2, const double y2, const double z2, const double x0, const double y0, const double z0, const double a, const double b, const double c, double &xc, double &yc, double &zc)
Definition: Solid.cc:52
double m_dX
Direction vector.
Definition: Solid.hh:205
unsigned int GetId() const
Get the ID of the solid.
Definition: Solid.hh:137
void ToLocal(const double x, const double y, const double z, double &u, double &v, double &w) const
Definition: Solid.hh:234
void SetDirection(const double dx, const double dy, const double dz)
Definition: Solid.cc:12
int m_colour
Colour.
Definition: Solid.hh:230
double m_sPhi
Definition: Solid.hh:207
void ToGlobal(const double u, const double v, const double w, double &x, double &y, double &z) const
Definition: Solid.hh:246
double m_sTheta
Definition: Solid.hh:209
double m_cY
Definition: Solid.hh:202
double m_dY
Definition: Solid.hh:205
double m_cX
Centre of the solid.
Definition: Solid.hh:202
double m_cPhi
Azimuthal angle.
Definition: Solid.hh:207
bool NonTrivial(const std::vector< double > &xp, const std::vector< double > &yp)
Check whether a set of points builds a non-trivial polygon.
Definition: Polygon.cc:285
void EliminateButterflies(std::vector< double > &xp, std::vector< double > &yp, std::vector< double > &zp)
Definition: Polygon.cc:355
void Inside(const std::vector< double > &xpl, const std::vector< double > &ypl, const double x, const double y, bool &inside, bool &edge)
Definition: Polygon.cc:187
Surface panel.
Definition: Solid.hh:11
std::vector< double > zv
Z-coordinates of vertices.
Definition: Solid.hh:19
int volume
Reference to solid to which the panel belongs.
Definition: Solid.hh:23
double a
Perpendicular vector.
Definition: Solid.hh:13
double c
Definition: Solid.hh:13
double b
Definition: Solid.hh:13
std::vector< double > xv
X-coordinates of vertices.
Definition: Solid.hh:15
std::vector< double > yv
Y-coordinates of vertices.
Definition: Solid.hh:17
int colour
Colour index.
Definition: Solid.hh:21