Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4GenericTrap.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4GenericTrap implementation
27//
28// Authors:
29// Tatiana Nikitina, CERN; Ivana Hrivnacova, IPN Orsay
30// Adapted from Root Arb8 implementation by Andrei Gheata, CERN
31//
32// 27.05.2024 - Evgueni Tcherniaev, complete revision, speed up
33// --------------------------------------------------------------------
34
35#include "G4GenericTrap.hh"
36
37#if !defined(G4GEOM_USE_UGENERICTRAP)
38
39#include <iomanip>
40
42#include "G4SystemOfUnits.hh"
43#include "G4VoxelLimits.hh"
44#include "G4AffineTransform.hh"
45#include "G4BoundingEnvelope.hh"
46#include "G4QuickRand.hh"
47
48#include "G4GeomTools.hh"
49
50#include "G4VGraphicsScene.hh"
51#include "G4Polyhedron.hh"
52#include "G4VisExtent.hh"
53
54#include "G4AutoLock.hh"
55
56namespace
57{
58 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
59 G4Mutex lateralareaMutex = G4MUTEX_INITIALIZER;
60 G4Mutex gentrapMutex = G4MUTEX_INITIALIZER;
61}
62
63////////////////////////////////////////////////////////////////////////
64//
65// Constructor
66//
68 const std::vector<G4TwoVector>& vertices)
69 : G4VSolid(name)
70{
71 halfTolerance = 0.5*kCarTolerance;
72 CheckParameters(halfZ, vertices);
73 ComputeLateralSurfaces();
74 ComputeBoundingBox();
75 ComputeScratchLength();
76}
77
78////////////////////////////////////////////////////////////////////////
79//
80// Fake default constructor - sets only member data and allocates memory
81// for usage restricted to object persistency.
83 : G4VSolid(a)
84{
85}
86
87////////////////////////////////////////////////////////////////////////
88//
89// Copy constructor
90//
92 : G4VSolid(rhs),
93 halfTolerance(rhs.halfTolerance), fScratch(rhs.fScratch),
94 fDz(rhs.fDz), fVertices(rhs.fVertices), fIsTwisted(rhs.fIsTwisted),
95 fMinBBox(rhs.fMinBBox), fMaxBBox(rhs.fMaxBBox),
96 fVisSubdivisions(rhs.fVisSubdivisions),
97 fSurfaceArea(rhs.fSurfaceArea), fCubicVolume(rhs.fCubicVolume)
98{
99 for (auto i = 0; i < 5; ++i) { fTwist[i] = rhs.fTwist[i]; }
100 for (auto i = 0; i < 4; ++i) { fDelta[i] = rhs.fDelta[i]; }
101 for (auto i = 0; i < 8; ++i) { fPlane[i] = rhs.fPlane[i]; }
102 for (auto i = 0; i < 4; ++i) { fSurf[i] = rhs.fSurf[i]; }
103 for (auto i = 0; i < 4; ++i) { f4k[i] = rhs.f4k[i]; }
104 for (auto i = 0; i < 4; ++i) { fArea[i] = rhs.fArea[i]; }
105}
106
107////////////////////////////////////////////////////////////////////////
108//
109// Assignment
110//
112{
113 // Check assignment to self
114 if (this == &rhs) { return *this; }
115
116 // Copy base class data
118
119 // Copy data
120 halfTolerance = rhs.halfTolerance; fScratch = rhs.fScratch;
121 fDz = rhs.fDz; fVertices = rhs.fVertices; fIsTwisted = rhs.fIsTwisted;
122 fMinBBox = rhs.fMinBBox; fMaxBBox = rhs.fMaxBBox;
123 fVisSubdivisions = rhs.fVisSubdivisions;
124 fSurfaceArea = rhs.fSurfaceArea; fCubicVolume = rhs.fCubicVolume;
125
126 for (auto i = 0; i < 8; ++i) { fVertices[i] = rhs.fVertices[i]; }
127 for (auto i = 0; i < 5; ++i) { fTwist[i] = rhs.fTwist[i]; }
128 for (auto i = 0; i < 4; ++i) { fDelta[i] = rhs.fDelta[i]; }
129 for (auto i = 0; i < 8; ++i) { fPlane[i] = rhs.fPlane[i]; }
130 for (auto i = 0; i < 4; ++i) { fSurf[i] = rhs.fSurf[i]; }
131 for (auto i = 0; i < 4; ++i) { f4k[i] = rhs.f4k[i]; }
132 for (auto i = 0; i < 4; ++i) { fArea[i] = rhs.fArea[i]; }
133
134 fRebuildPolyhedron = false;
135 delete fpPolyhedron; fpPolyhedron = nullptr;
136
137 return *this;
138}
139
140////////////////////////////////////////////////////////////////////////
141//
142// Returns position of the point (inside/outside/surface)
143//
145{
146 G4double px = p.x(), py = p.y(), pz = p.z();
147
148 // intersect edges by z = pz plane
149 G4TwoVector pp[4];
150 G4double z = (pz + fDz);
151 for (auto i = 0; i < 4; ++i)
152 {
153 pp[i] = fVertices[i] + fDelta[i]*z;
154 }
155
156 // estimate distance to the solid
157 G4double dist = std::abs(pz) - fDz;
158 for (auto i = 0; i < 4; ++i)
159 {
160 if (fTwist[i] == 0.)
161 {
162 G4double dd = fSurf[i].D*px + fSurf[i].E*py + fSurf[i].F*pz + fSurf[i].G;
163 dist = std::max(dd, dist);
164 }
165 else
166 {
167 auto j = (i + 1)%4;
168 G4TwoVector a = pp[i];
169 G4TwoVector b = pp[j];
170 G4double dx = b.x() - a.x();
171 G4double dy = b.y() - a.y();
172 G4double leng = std::sqrt(dx*dx + dy*dy);
173 G4double dd = (dx*(py - a.y()) - dy*(px - a.x()))/leng;
174 dist = std::max(dd, dist);
175 }
176 }
177 return (dist > halfTolerance) ? kOutside :
178 ((dist > -halfTolerance) ? kSurface : kInside);
179}
180
181////////////////////////////////////////////////////////////////////////
182//
183// Return unit normal to surface at p
184//
186{
187 G4double halfToleranceSquared = halfTolerance*halfTolerance;
188 G4double px = p.x(), py = p.y(), pz = p.z();
189 G4double nx = 0, ny = 0, nz = 0;
190
191 // intersect edges by z = pz plane
192 G4TwoVector pp[4];
193 G4double tz = (pz + fDz);
194 for (auto i = 0; i < 4; ++i)
195 {
196 pp[i] = fVertices[i] + fDelta[i]*tz;
197 }
198
199 // check bottom and top faces
200 G4double dz = std::abs(pz) - fDz;
201 nz = std::copysign(G4double(std::abs(dz) <= halfTolerance), pz);
202
203 // check lateral faces
204 for (auto i = 0; i < 4; ++i)
205 {
206 if (fTwist[i] == 0.)
207 {
208 G4double dd = fSurf[i].D*px + fSurf[i].E*py + fSurf[i].F*pz + fSurf[i].G;
209 if (std::abs(dd) <= halfTolerance)
210 {
211 nx += fSurf[i].D;
212 ny += fSurf[i].E;
213 nz += fSurf[i].F;
214 }
215 }
216 else
217 {
218 auto j = (i + 1)%4;
219 G4TwoVector a = pp[i];
220 G4TwoVector b = pp[j];
221 G4double dx = b.x() - a.x();
222 G4double dy = b.y() - a.y();
223 G4double ll = dx*dx + dy*dy;
224 G4double dd = dx*(py - a.y()) - dy*(px - a.x());
225 if (dd*dd <= halfToleranceSquared*ll)
226 {
227 G4double x = fSurf[i].A*pz + fSurf[i].D;
228 G4double y = fSurf[i].B*pz + fSurf[i].E;
229 G4double z = fSurf[i].A*px + fSurf[i].B*py + 2.*fSurf[i].C*pz + fSurf[i].F;
230 G4double inv = 1./std::sqrt(x*x + y*y + z*z);
231 nx += x*inv;
232 ny += y*inv;
233 nz += z*inv;
234 }
235 }
236 }
237
238 // return normal
239 G4double mag2 = nx*nx + ny*ny + nz*nz;
240 if (mag2 == 0.)
241 {
242 return ApproxSurfaceNormal(p); // point is not on the surface
243 }
244 G4double mag = std::sqrt(mag2);
245 G4double inv = (mag == 1.) ? 1. : 1./mag;
246 return { nx*inv, ny*inv, nz*inv };
247}
248
249////////////////////////////////////////////////////////////////////////
250//
251// Find surface nearest to the point and return corresponding normal
252// Normally this method should not be called
253//
254G4ThreeVector G4GenericTrap::ApproxSurfaceNormal( const G4ThreeVector& p ) const
255{
256#ifdef G4SPECSDEBUG
257 std::ostringstream message;
258 message.precision(16);
259 message << "Point p is not on surface of solid: " << GetName() << " !?\n"
260 << "Position: " << p << " is "
261 << ((Inside(p) == kInside) ? "inside" : "outside") << "\n";
262 StreamInfo(message);
263 G4Exception("G4GenericTrap::ApproxSurfaceNormal(p)", "GeomSolids1002",
264 JustWarning, message );
265#endif
266 G4double px = p.x(), py = p.y(), pz = p.z();
267 G4double dist = -DBL_MAX;
268 auto iside = 0;
269
270 // intersect edges by z = pz plane
271 G4TwoVector pp[4];
272 G4double tz = (pz + fDz);
273 for (auto i = 0; i < 4; ++i)
274 {
275 pp[i] = fVertices[i] + fDelta[i]*tz;
276 }
277
278 // check lateral faces
279 for (auto i = 0; i < 4; ++i)
280 {
281 if (fTwist[i] == 0.)
282 {
283 G4double d = fSurf[i].D*px + fSurf[i].E*py + fSurf[i].F*pz + fSurf[i].G;
284 if (d > dist) { dist = d; iside = i; }
285 }
286 else
287 {
288 auto j = (i + 1)%4;
289 G4TwoVector a = pp[i];
290 G4TwoVector b = pp[j];
291 G4double dx = b.x() - a.x();
292 G4double dy = b.y() - a.y();
293 G4double leng = std::sqrt(dx*dx + dy*dy);
294 G4double d = (dx*(py - a.y()) - dy*(px - a.x()))/leng;
295 if (d > dist) { dist = d; iside = i; }
296 }
297 }
298 // check bottom and top faces
299 G4double distz = std::abs(pz) - fDz;
300 if (distz >= dist) { return { 0., 0., std::copysign(1., pz) };
301}
302
303 G4double x = fSurf[iside].A*pz + fSurf[iside].D;
304 G4double y = fSurf[iside].B*pz + fSurf[iside].E;
305 G4double z = fSurf[iside].A*px + fSurf[iside].B*py + 2.*fSurf[iside].C*pz + fSurf[iside].F;
306 G4double inv = 1./std::sqrt(x*x + y*y + z*z);
307 return { x*inv, y*inv, z*inv };
308}
309
310////////////////////////////////////////////////////////////////////////
311//
312// Compute distance to the surface from outside,
313// return kInfinity if no intersection
314//
316 const G4ThreeVector& v) const
317{
318 G4double px = p.x(), py = p.y(), pz = p.z();
319 G4double vx = v.x(), vy = v.y(), vz = v.z();
320
321 // Find intersections with the bounding polyhedron
322 //
323 if (std::abs(pz) - fDz >= -halfTolerance && pz*vz >= 0) { return kInfinity; }
324 G4double invz = (vz == 0) ? kInfinity : -1./vz;
325 G4double dz = std::copysign(fDz,invz);
326 G4double xin = (pz - dz)*invz;
327 G4double xout = (pz + dz)*invz;
328
329 // Check plane faces
330 for (auto k = 0; k < 4; ++k)
331 {
332 if (fTwist[k] != 0) { continue; } // skip twisted faces
333 const G4GenericTrapPlane& surf = fPlane[2*k];
334 G4double cosa = surf.A*vx + surf.B*vy + surf.C*vz;
335 G4double dist = surf.A*px + surf.B*py + surf.C*pz + surf.D;
336 if (dist >= -halfTolerance)
337 {
338 if (cosa >= 0.) { return kInfinity; } // point flies away
339 G4double tmp = -dist/cosa;
340 xin = std::max(tmp, xin);
341 }
342 else
343 {
344 if (cosa > 0) { xout = std::min(-dist/cosa, xout); }
345 if (cosa < 0) { xin = std::max(-dist/cosa, xin); }
346 }
347 }
348
349 // Check planes around twisted faces, each twisted face is bounded by two planes
350 G4double tin = xin;
351 G4double tout = xout;
352 for (auto i = 0; i < 4; ++i)
353 {
354 if (fTwist[i] == 0) { continue; } // skip plane faces
355
356 // check intersection with 1st bounding plane
357 const G4GenericTrapPlane& surf1 = fPlane[2*i];
358 G4double cosa = surf1.A*vx + surf1.B*vy + surf1.C*vz;
359 G4double dist = surf1.A*px + surf1.B*py + surf1.C*pz + surf1.D;
360 if (dist >= -halfTolerance)
361 {
362 if (cosa >= 0.) { return kInfinity; } // point flies away
363 G4double tmp = -dist/cosa;
364 tin = std::max(tmp, tin);
365 }
366 else
367 {
368 if (cosa > 0) { tout = std::min(-dist/cosa, tout); }
369 if (cosa < 0) { tin = std::max(-dist/cosa, tin); }
370 }
371
372 // check intersection with 2nd bounding plane
373 const G4GenericTrapPlane& surf2 = fPlane[2*i + 1];
374 cosa = surf2.A*vx + surf2.B*vy + surf2.C*vz;
375 dist = surf2.A*px + surf2.B*py + surf2.C*pz + surf2.D;
376 if (dist >= -halfTolerance)
377 {
378 if (cosa >= 0.) { return kInfinity; } // point flies away
379 G4double tmp = -dist/cosa;
380 tin = std::max(tmp, tin);
381 }
382 else
383 {
384 if (cosa > 0) { tout = std::min(-dist/cosa, tout); }
385 if (cosa < 0) { tin = std::max(-dist/cosa, tin); }
386 }
387 }
388 if (tout - tin <= halfTolerance) { return kInfinity; } // touch or no hit
389
390 // if point is outside of the bounding box
391 // then move it to the surface of the bounding polyhedron
392 G4double t0 = 0., x0 = px, y0 = py, z0 = pz;
393 if (x0 < fMinBBox.x() - halfTolerance ||
394 y0 < fMinBBox.y() - halfTolerance ||
395 z0 < fMinBBox.z() - halfTolerance ||
396 x0 > fMaxBBox.x() + halfTolerance ||
397 y0 > fMaxBBox.y() + halfTolerance ||
398 z0 > fMaxBBox.z() + halfTolerance)
399 {
400 t0 = tin;
401 x0 += vx*t0;
402 y0 += vy*t0;
403 z0 += vz*t0;
404 }
405
406 // Check intersections with twisted faces
407 //
408 G4double ttin[2] = { DBL_MAX, DBL_MAX };
409 G4double ttout[2] = { tout, tout };
410
411 if (tin - xin < halfTolerance) { ttin[0] = xin; }
412 if (xout - tout < halfTolerance) { ttout[0] = xout; }
413 G4double tminimal = tin - halfTolerance;
414 G4double tmaximal = tout + halfTolerance;
415
416 constexpr G4double EPSILON = 1000.*DBL_EPSILON;
417 for (auto i = 0; i < 4; ++i)
418 {
419 if (fTwist[i] == 0) { continue; } // skip plane faces
420
421 // twisted face, solve quadratic equation
422 G4double ABC = fSurf[i].A*vx + fSurf[i].B*vy + fSurf[i].C*vz;
423 G4double ABCF = fSurf[i].A*x0 + fSurf[i].B*y0 + fSurf[i].C*z0 + fSurf[i].F;
424 G4double A = ABC*vz;
425 G4double B = 0.5*(fSurf[i].D*vx + fSurf[i].E*vy + ABCF*vz + ABC*z0);
426 G4double C = fSurf[i].D*x0 + fSurf[i].E*y0 + ABCF*z0 + fSurf[i].G;
427 if (std::abs(A) <= EPSILON)
428 {
429 // case 1: track is parallel to the surface
430 if (std::abs(B) <= EPSILON)
431 {
432 // check position of the track relative to the surface,
433 // for the reason of precision it's better to use (x0,y0,z0) instead of (px,py,pz)
434 auto j = (i + 1)%4;
435 G4double z = (z0 + fDz);
436 G4TwoVector a = fVertices[i] + fDelta[i]*z;
437 G4TwoVector b = fVertices[j] + fDelta[j]*z;
438 G4double dx = b.x() - a.x();
439 G4double dy = b.y() - a.y();
440 G4double leng = std::sqrt(dx*dx + dy*dy);
441 G4double dist = dx*(y0 - a.y()) - dy*(x0 - a.x());
442 if (dist >= -halfTolerance*leng) { return kInfinity; }
443 continue;
444 }
445
446 // case 2: single root
447 G4double tmp = t0 - 0.5*C/B;
448 // compute normal at the intersection point and check direction
449 G4double x = px + vx*tmp;
450 G4double y = py + vy*tmp;
451 G4double z = pz + vz*tmp;
452 const G4GenericTrapSurface& surf = fSurf[i];
453 G4double nx = surf.A*z + surf.D;
454 G4double ny = surf.B*z + surf.E;
455 G4double nz = surf.A*x + surf.B*y + 2.*surf.C*z + surf.F;
456
457 if (nx*vx + ny*vy + nz*vz >= 0.) // point is flying to outside
458 {
459 auto k = (i == 3) ? 0 : i + 1;
460 G4double tz = (pz + fDz);
461 G4TwoVector a = fVertices[i] + fDelta[i]*tz;
462 G4TwoVector b = fVertices[k] + fDelta[k]*tz;
463 G4double dx = b.x() - a.x();
464 G4double dy = b.y() - a.y();
465 G4double leng = std::sqrt(dx*dx + dy*dy);
466 G4double dist = dx*(py - a.y()) - dy*(px - a.x());
467 if (dist >= -halfTolerance*leng) { return kInfinity; } // point is flies away
468
469 if (tmp < tminimal || tmp > tmaximal) { continue; }
470 if (std::abs(tmp - ttout[0]) < halfTolerance) { continue; }
471 if (tmp < ttout[0])
472 {
473 ttout[1] = ttout[0];
474 ttout[0] = tmp;
475 }
476 else { ttout[1] = std::min(tmp, ttout[1]); }
477 }
478 else // point is flying to inside
479 {
480 if (tmp < tminimal || tmp > tmaximal) { continue; }
481 if (std::abs(tmp - ttin[0]) < halfTolerance) { continue; }
482 if (tmp < ttin[0])
483 {
484 ttin[1] = ttin[0];
485 ttin[0] = tmp;
486 }
487 else { ttin[1] = std::min(tmp, ttin[1]); }
488 }
489 continue;
490 }
491
492 // case 3: scratch or no intersection
493 G4double D = B*B - A*C;
494 if (D < 0.25*fScratch*fScratch*A*A)
495 {
496 if (A > 0) { return kInfinity; }
497 continue;
498 }
499
500 // case 4: two intersection points
501 G4double tmp = -B - std::copysign(std::sqrt(D), B);
502 G4double t1 = tmp/A + t0;
503 G4double t2 = C/tmp + t0;
504 G4double tsurfin = std::min(t1, t2);
505 G4double tsurfout = std::max(t1, t2);
506 if (A < 0) { std::swap(tsurfin, tsurfout); }
507
508 if (tsurfin >= tminimal && tsurfin <= tmaximal)
509 {
510 if (std::abs(tsurfin - ttin[0]) >= halfTolerance)
511 {
512 if (tsurfin < ttin[0])
513 {
514 ttin[1] = ttin[0];
515 ttin[0] = tsurfin;
516 }
517 else { ttin[1] = std::min(tsurfin, ttin[1]); }
518 }
519 }
520 if (tsurfout >= tminimal && tsurfout <= tmaximal)
521 {
522 if (std::abs(tsurfout - ttout[0]) >= halfTolerance)
523 {
524 if (tsurfout < ttout[0])
525 {
526 ttout[1] = ttout[0];
527 ttout[0] = tsurfout;
528 }
529 else { ttout[1] = std::min(tsurfout, ttout[1]); }
530 }
531 }
532 }
533
534 // Compute distance to In
535 //
536 if (ttin[0] == DBL_MAX) { return kInfinity; } // no entry point
537
538 // single entry point
539 if (ttin[1] == DBL_MAX)
540 {
541 G4double distin = ttin[0];
542 G4double distout = (distin >= ttout[0] - halfTolerance) ? ttout[1] : ttout[0];
543 G4double dist = (distout <= halfTolerance || distout - distin <= halfTolerance) ? kInfinity : distin;
544 return (dist < halfTolerance) ? 0. : dist;
545 }
546
547 // two entry points
548 if (ttin[1] < ttout[0])
549 {
550 G4double distin = ttin[1], distout = ttout[0];
551 G4double dist = (distout <= halfTolerance || distout - distin <= halfTolerance) ? kInfinity : distin;
552 return (dist < halfTolerance) ? 0. : dist;
553 }
554
555 // check 1st pair of in-out points
556 G4double distin1 = ttin[0], distout1 = ttout[0];
557 G4double dist1 = (distout1 <= halfTolerance || distout1 - distin1 <= halfTolerance) ? kInfinity : distin1;
558 if (dist1 != kInfinity) { return (dist1 < halfTolerance) ? 0. : dist1; }
559
560 // check 2nd pair of in-out points
561 G4double distin2 = ttin[1], distout2 = ttout[1];
562 G4double dist2 = (distout2 <= halfTolerance || distout2 - distin2 <= halfTolerance) ? kInfinity : distin2;
563 return (dist2 < halfTolerance) ? 0. : dist2;
564}
565
566////////////////////////////////////////////////////////////////////////
567//
568// Estimate safety distance to the surface from outside
569//
571{
572 G4double x = p.x(), y = p.y(), z = p.z();
573 G4double dist = std::abs(z) - fDz;
574 for (auto i = 0; i < 4; ++i)
575 {
576 if (fTwist[i] == 0.)
577 {
578 G4double distPlane = fSurf[i].D*x + fSurf[i].E*y + fSurf[i].F*z + fSurf[i].G;
579 dist = std::max(distPlane, dist);
580 }
581 else
582 {
583 G4double A = fSurf[i].A;
584 G4double B = fSurf[i].B;
585 G4double C = fSurf[i].C;
586 G4double Cz = C*z;
587 G4double CzF = Cz + fSurf[i].F;
588 G4double gradx = A*z + fSurf[i].D;
589 G4double grady = B*z + fSurf[i].E;
590 G4double gradz = A*x + B*y + Cz + CzF;
591 G4double fun = gradx*x + grady*y + CzF*z + fSurf[i].G;
592 G4double grad2 = gradx*gradx + grady*grady + gradz*gradz;
593 G4double divisor = std::sqrt(grad2) + std::sqrt(grad2 + f4k[i]*std::abs(fun));
594 G4double distSurf = 2.*fun/divisor;
595 dist = std::max(distSurf, dist);
596 }
597 }
598 return (dist > 0.) ? dist : 0.; // return safety distance
599}
600
601////////////////////////////////////////////////////////////////////////
602//
603// Calculate distance to surface from inside
604//
606 const G4ThreeVector& v,
607 const G4bool calcNorm,
608 G4bool* validNorm,
609 G4ThreeVector* n) const
610{
611 G4double px = p.x(), py = p.y(), pz = p.z();
612 G4double vx = v.x(), vy = v.y(), vz = v.z();
613
614 // Check intersections with plane faces
615 //
616 if ((std::abs(pz) - fDz) >= -halfTolerance && pz*vz > 0.)
617 {
618 if (calcNorm)
619 {
620 *validNorm = true;
621 n->set(0., 0., std::copysign(1., pz));
622 }
623 return 0.;
624 }
625 G4double tout = (vz == 0) ? DBL_MAX : (std::copysign(fDz, vz) - pz)/vz;
626 G4int iface = (vz < 0) ? -4 : -2; // little trick for z-normal: (-4+3)=-1, (-2+3)=+1
627
628 for (auto i = 0; i < 4; ++i)
629 {
630 if (fTwist[i] != 0) { continue; } // skip twisted faces
631 const G4GenericTrapPlane& surf = fPlane[2*i];
632 G4double cosa = surf.A*vx + surf.B*vy + surf.C*vz;
633 if (cosa > 0)
634 {
635 G4double dist = surf.A*px + surf.B*py + surf.C*pz + surf.D;
636 if (dist >= -halfTolerance)
637 {
638 if (calcNorm)
639 {
640 *validNorm = true;
641 n->set(surf.A, surf.B, surf.C);
642 }
643 return 0.;
644 }
645 G4double tmp = -dist/cosa;
646 if (tout > tmp) { tout = tmp; iface = i; }
647 }
648 }
649
650 // Check intersections with twisted faces
651 //
652 constexpr G4double EPSILON = 1000.*DBL_EPSILON;
653 for (auto i = 0; i < 4; ++i)
654 {
655 if (fTwist[i] == 0) { continue; } // skip plane faces
656
657 // twisted face, solve quadratic equation
658 const G4GenericTrapSurface& surf = fSurf[i];
659 G4double ABC = surf.A*vx + surf.B*vy + surf.C*vz;
660 G4double ABCF = surf.A*px + surf.B*py + surf.C*pz + surf.F;
661 G4double A = ABC*vz;
662 G4double B = 0.5*(surf.D*vx + surf.E*vy + ABCF*vz + ABC*pz);
663 G4double C = surf.D*px + surf.E*py + ABCF*pz + surf.G;
664
665 if (std::abs(A) <= EPSILON)
666 {
667 // case 1: track is parallel to the surface
668 if (std::abs(B) <= EPSILON) { continue; }
669
670 // case 2: single root
671 G4double tmp = -0.5*C/B;
672 // compute normal at intersection point and check direction
673 G4double x = px + vx*tmp;
674 G4double y = py + vy*tmp;
675 G4double z = pz + vz*tmp;
676 G4double nx = surf.A*z + surf.D;
677 G4double ny = surf.B*z + surf.E;
678 G4double nz = surf.A*x + surf.B*y + 2.*surf.C*z + surf.F;
679
680 if (nx*vx + ny*vy + nz*vz > 0.) // point is flying to outside
681 {
682 auto k = (i + 1)%4;
683 G4double tz = (pz + fDz);
684 G4TwoVector a = fVertices[i] + fDelta[i]*tz;
685 G4TwoVector b = fVertices[k] + fDelta[k]*tz;
686 G4double dx = b.x() - a.x();
687 G4double dy = b.y() - a.y();
688 G4double leng = std::sqrt(dx*dx + dy*dy);
689 G4double dist = dx*(py - a.y()) - dy*(px - a.x());
690 if (dist >= -halfTolerance*leng) // point is on the surface
691 {
692 if (calcNorm)
693 {
694 *validNorm = false;
695 G4double normx = surf.A*pz + surf.D;
696 G4double normy = surf.B*pz + surf.E;
697 G4double normz = surf.A*px + surf.B*py + 2.*surf.C*pz + surf.F;
698 G4double inv = 1./std::sqrt(normx*normx + normy*normy + normz*normz);
699 n->set(normx*inv, normy*inv, normz*inv);
700 }
701 return 0.;
702 }
703 if (tout > tmp) { tout = tmp; iface = i; }
704 }
705 continue;
706 }
707
708 // case 3: scratch or no intersection
709 G4double D = B*B - A*C;
710 if (D < 0.25*fScratch*fScratch*A*A)
711 {
712 // check position of the point
713 auto j = (i + 1)%4;
714 G4double tz = pz + fDz;
715 G4TwoVector a = fVertices[i] + fDelta[i]*tz;
716 G4TwoVector b = fVertices[j] + fDelta[j]*tz;
717 G4double dx = b.x() - a.x();
718 G4double dy = b.y() - a.y();
719 G4double leng = std::sqrt(dx*dx + dy*dy);
720 G4double dist = dx*(py - a.y()) - dy*(px - a.x());
721 if (dist <= -halfTolerance*leng) { continue; } // point is inside
722 if (A > 0 || dist > halfTolerance*leng) // convex surface (or point is outside)
723 {
724 if (calcNorm)
725 {
726 *validNorm = false;
727 G4double nx = surf.A*pz + surf.D;
728 G4double ny = surf.B*pz + surf.E;
729 G4double nz = surf.A*px + surf.B*py + 2.*surf.C*pz + surf.F;
730 G4double inv = 1./std::sqrt(nx*nx + ny*ny + nz*nz);
731 n->set(nx*inv, ny*inv, nz*inv);
732 }
733 return 0.;
734 }
735 continue;
736 }
737
738 // case 4: two intersection points
739 G4double tmp = -B - std::copysign(std::sqrt(D), B);
740 G4double t1 = tmp / A;
741 G4double t2 = C / tmp;
742 G4double tmin = std::min(t1, t2);
743 G4double tmax = std::max(t1, t2);
744
745 if (A < 0) // concave profile: tmin(out) -> tmax(in)
746 {
747 if (std::abs(tmax) < std::abs(tmin)) { continue; } // point flies inside
748 if (tmin <= halfTolerance) // point is on external side of the surface
749 {
750 G4double t = 0.5*(tmin + tmax);
751 G4double x = px + vx*t;
752 G4double y = py + vy*t;
753 G4double z = pz + vz*t;
754
755 auto j = (i + 1)%4;
756 G4double tz = z + fDz;
757 G4TwoVector a = fVertices[i] + fDelta[i]*tz;
758 G4TwoVector b = fVertices[j] + fDelta[j]*tz;
759 G4double dx = b.x() - a.x();
760 G4double dy = b.y() - a.y();
761 G4double leng = std::sqrt(dx*dx + dy*dy);
762 G4double dist = dx*(y - a.y()) - dy*(x - a.x());
763 if (dist <= -halfTolerance*leng) { continue; } // scratch
764 if (calcNorm)
765 {
766 *validNorm = false;
767 G4double nx = surf.A*pz + surf.D;
768 G4double ny = surf.B*pz + surf.E;
769 G4double nz = surf.A*px + surf.B*py + 2.*surf.C*pz + surf.F;
770 G4double inv = 1./std::sqrt(nx*nx + ny*ny + nz*nz);
771 n->set(nx*inv, ny*inv, nz*inv);
772 }
773 return 0.;
774 }
775 if (tout > tmin) { tout = tmin; iface = i; }
776 }
777 else // convex profile: tmin(in) -> tmax(out)
778 {
779 if (tmax < halfTolerance) // point is on the surface
780 {
781 if (calcNorm)
782 {
783 *validNorm = false;
784 G4double nx = surf.A*pz + surf.D;
785 G4double ny = surf.B*pz + surf.E;
786 G4double nz = surf.A*px + surf.B*py + 2.*surf.C*pz + surf.F;
787 G4double inv = 1./std::sqrt(nx*nx + ny*ny + nz*nz);
788 n->set(nx*inv, ny*inv, nz*inv);
789 }
790 return 0.;
791 }
792 if (tout > tmax) { tout = tmax; iface = i; }
793 }
794 }
795
796 // Compute normal, if required, and return distance to out
797 //
798 if (tout < halfTolerance) { tout = 0.; }
799 if (calcNorm)
800 {
801 if (iface < 0)
802 {
803 *validNorm = true;
804 n->set(0, 0, iface + 3); // little trick: (-4+3)=-1, (-2+3)=+1
805 }
806 else
807 {
808 const G4GenericTrapSurface& surf = fSurf[iface];
809 if (fTwist[iface] == 0)
810 {
811 *validNorm = true;
812 n->set(surf.D, surf.E, surf.F);
813 }
814 else
815 {
816 *validNorm = false;
817 G4double x = px + vx*tout;
818 G4double y = py + vy*tout;
819 G4double z = pz + vz*tout;
820 G4double nx = surf.A*z + surf.D;
821 G4double ny = surf.B*z + surf.E;
822 G4double nz = surf.A*x + surf.B*y + 2.*surf.C*z + surf.F;
823 G4double inv = 1./std::sqrt(nx*nx + ny*ny + nz*nz);
824 n->set(nx*inv, ny*inv, nz*inv);
825 }
826 }
827 }
828 return tout;
829}
830
831////////////////////////////////////////////////////////////////////////
832//
833// Estimate safety distance to the surface from inside
834//
836{
837 G4double x = p.x(), y = p.y(), z = p.z();
838 G4double dist = std::abs(z) - fDz;
839 for (auto i = 0; i < 4; ++i)
840 {
841 if (fTwist[i] == 0.)
842 {
843 G4double distPlane = fSurf[i].D*x + fSurf[i].E*y + fSurf[i].F*z + fSurf[i].G;
844 dist = std::max(distPlane, dist);
845 }
846 else
847 {
848 G4double A = fSurf[i].A;
849 G4double B = fSurf[i].B;
850 G4double C = fSurf[i].C;
851 G4double Cz = C*z;
852 G4double CzF = Cz + fSurf[i].F;
853 G4double gradx = A*z + fSurf[i].D;
854 G4double grady = B*z + fSurf[i].E;
855 G4double gradz = A*x + B*y + Cz + CzF;
856 G4double fun = gradx*x + grady*y + CzF*z + fSurf[i].G;
857 G4double grad2 = gradx*gradx + grady*grady + gradz*gradz;
858 G4double divisor = std::sqrt(grad2) + std::sqrt(grad2 + f4k[i]*std::abs(fun));
859 G4double distSurf = 2.*fun/divisor;
860 dist = std::max(distSurf, dist);
861 }
862 }
863 return (dist < 0.) ? -dist : 0.; // return safety distance
864}
865
866////////////////////////////////////////////////////////////////////////
867//
868// Return bounding box
869//
871 G4ThreeVector& pMax) const
872{
873 pMin = fMinBBox;
874 pMax = fMaxBBox;
875}
876
877////////////////////////////////////////////////////////////////////////
878//
879// Calculate extent under transform and specified limits
880//
881G4bool
883 const G4VoxelLimits& pVoxelLimit,
884 const G4AffineTransform& pTransform,
885 G4double& pMin, G4double& pMax) const
886{
887 G4ThreeVector bmin, bmax;
888 G4bool exist;
889
890 // Check bounding box (bbox)
891 //
892 BoundingLimits(bmin,bmax);
893 G4BoundingEnvelope bbox(bmin,bmax);
894#ifdef G4BBOX_EXTENT
895 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
896#endif
897 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
898 {
899 return exist = pMin < pMax;
900 }
901
902 // Set bounding envelope (benv) and calculate extent
903 //
904 // To build the bounding envelope with plane faces, each lateral face of
905 // the trapezoid is subdivided in two triangles. Subdivision is done by
906 // duplication of vertices in the bases in a way that the envelope be
907 // a convex polyhedron (some faces of the envelope can be degenerated)
908 //
910 G4ThreeVectorList baseA(8), baseB(8);
911 for (G4int i = 0; i < 4; ++i)
912 {
913 G4TwoVector va = GetVertex(i);
914 G4TwoVector vb = GetVertex(i+4);
915 baseA[2*i].set(va.x(), va.y(),-dz);
916 baseB[2*i].set(vb.x(), vb.y(), dz);
917 }
918 for (G4int i = 0; i < 4; ++i)
919 {
920 G4int k1 = 2*i, k2 = (2*i + 2)%8;
921 G4double ax = (baseA[k2].x() - baseA[k1].x());
922 G4double ay = (baseA[k2].y() - baseA[k1].y());
923 G4double bx = (baseB[k2].x() - baseB[k1].x());
924 G4double by = (baseB[k2].y() - baseB[k1].y());
925 G4double znorm = ax*by - ay*bx;
926 baseA[k1+1] = (znorm < 0.0) ? baseA[k2] : baseA[k1];
927 baseB[k1+1] = (znorm < 0.0) ? baseB[k1] : baseB[k2];
928 }
929
930 std::vector<const G4ThreeVectorList *> polygons(2);
931 polygons[0] = &baseA;
932 polygons[1] = &baseB;
933
934 G4BoundingEnvelope benv(bmin, bmax, polygons);
935 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
936 return exist;
937}
938
939////////////////////////////////////////////////////////////////////////
940//
941// Return type of the solid
942//
944{
945 return { "G4GenericTrap" };
946}
947
948////////////////////////////////////////////////////////////////////////
949//
950// Return true if not twisted, false otherwise
951//
953{
954 return (!fIsTwisted);
955}
956
957////////////////////////////////////////////////////////////////////////
958//
959// Make a clone of the solid
960//
962{
963 return new G4GenericTrap(*this);
964}
965
966////////////////////////////////////////////////////////////////////////
967//
968// Write parameters of the solid to the specified output stream
969//
970std::ostream& G4GenericTrap::StreamInfo(std::ostream& os) const
971{
972 G4long oldprc = os.precision(16);
973 os << "-----------------------------------------------------------\n"
974 << " *** Dump for solid - " << GetName() << " ***\n"
975 << " ===================================================\n"
976 << "Solid geometry type: " << GetEntityType() << "\n"
977 << " half length Z: " << fDz/mm << "\n"
978 << " list of vertices:\n";
979 for (G4int i = 0; i < 8; ++i)
980 {
981 os << " #" << i << " " << fVertices[i] << "\n";
982 }
983 os << "-----------------------------------------------------------\n";
984 os.precision(oldprc);
985 return os;
986}
987
988////////////////////////////////////////////////////////////////////////
989//
990// Pick up a random point on the surface
991//
993{
994 if (fArea[0] + fArea[1] + fArea[2] + fArea[3] == 0.)
995 {
996 G4AutoLock l(&lateralareaMutex);
997 fArea[0] = GetLateralFaceArea(0);
998 fArea[1] = GetLateralFaceArea(1);
999 fArea[2] = GetLateralFaceArea(2);
1000 fArea[3] = GetLateralFaceArea(3);
1001 l.unlock();
1002 }
1003
1004 constexpr G4int iface[6][4] =
1005 { {0,1,2,3}, {0,4,5,1}, {1,5,6,2}, {2,6,7,3}, {3,7,4,0}, {4,5,6,7} };
1006
1007 G4bool isTwisted[6] = {false};
1008 for (auto i = 0; i < 4; ++i)
1009 {
1010 isTwisted[i + 1] = (fTwist[i] != 0.0);
1011 }
1012
1013 G4double ssurf[6];
1014 G4TwoVector A = fVertices[3] - fVertices[1];
1015 G4TwoVector B = fVertices[2] - fVertices[0];
1016 G4TwoVector C = fVertices[7] - fVertices[5];
1017 G4TwoVector D = fVertices[6] - fVertices[4];
1018 ssurf[0] = (A.x()*B.y() - A.y()*B.x())*0.5; // -fDz face
1019 ssurf[1] = ssurf[0] + fArea[0];
1020 ssurf[2] = ssurf[1] + fArea[1];
1021 ssurf[3] = ssurf[2] + fArea[2];
1022 ssurf[4] = ssurf[3] + fArea[3];
1023 ssurf[5] = ssurf[4] + (C.x()*D.y() - C.y()*D.x())*.5; // +fDz face
1024
1025 G4double select = ssurf[5]*G4QuickRand();
1026 G4int k;
1027 for (k = 0; k < 5; ++k)
1028 {
1029 if (select <= ssurf[k]) { break; }
1030 }
1031
1032 G4int i0 = iface[k][0];
1033 G4int i1 = iface[k][1];
1034 G4int i2 = iface[k][2];
1035 G4int i3 = iface[k][3];
1036 G4ThreeVector pp[4];
1037 pp[0].set(fVertices[i0].x(), fVertices[i0].y(), ((k == 5) ? fDz : -fDz));
1038 pp[1].set(fVertices[i1].x(), fVertices[i1].y(), ((k == 0) ? -fDz : fDz));
1039 pp[2].set(fVertices[i2].x(), fVertices[i2].y(), ((k == 0) ? -fDz : fDz));
1040 pp[3].set(fVertices[i3].x(), fVertices[i3].y(), ((k == 5) ? fDz : -fDz));
1041
1042 G4ThreeVector point;
1043 if (isTwisted[k])
1044 { // twisted face, rejection sampling
1045 G4double maxlength = std::max((pp[2] - pp[1]).mag(), (pp[3] - pp[0]).mag());
1046 point = (pp[0] + pp[1] + pp[2] + pp[3])*0.25;
1047 for (auto i = 0; i < 10000; ++i)
1048 {
1049 G4double u = G4QuickRand();
1050 G4ThreeVector p0 = pp[0] + (pp[1] - pp[0])*u;
1051 G4ThreeVector p1 = pp[3] + (pp[2] - pp[3])*u;
1052 G4double v = G4QuickRand()*(maxlength/(p1 - p0).mag());
1053 if (v >= 1.) { continue; }
1054 point = p0 + (p1 - p0)*v;
1055 break;
1056 }
1057 }
1058 else
1059 { // plane face
1060 G4double u = G4QuickRand();
1061 G4double v = G4QuickRand();
1062 if (u + v > 1.) { u = 1. - u; v = 1. - v; }
1063 G4double ss = (((pp[2] - pp[0]).cross(pp[3] - pp[0])).mag())*0.5;
1064 G4int j = (select > ssurf[k] - ss) ? 3 : 1;
1065 point = pp[0] + (pp[2] - pp[0])*u + (pp[j] - pp[0])*v;
1066 }
1067 return point;
1068}
1069
1070////////////////////////////////////////////////////////////////////////
1071//
1072// Compute lateral face area
1073//
1074G4double G4GenericTrap::GetLateralFaceArea(G4int iface) const
1075{
1076 G4int i1 = iface, i2 = (i1 + 1)%4, i3 = i1 + 4, i4 = i2 + 4;
1077
1078 // plane face
1079 if (fTwist[iface] == 0.0)
1080 {
1081 G4ThreeVector p1(fVertices[i1].x(), fVertices[i1].y(),-fDz);
1082 G4ThreeVector p2(fVertices[i2].x(), fVertices[i2].y(),-fDz);
1083 G4ThreeVector p3(fVertices[i3].x(), fVertices[i3].y(), fDz);
1084 G4ThreeVector p4(fVertices[i4].x(), fVertices[i4].y(), fDz);
1085 return ((p4 - p1).cross(p3 - p2)).mag()*0.5;
1086 }
1087
1088 // twisted face
1089 constexpr G4int NSTEP = 250;
1090 constexpr G4double dt = 1./NSTEP;
1091
1092 G4double x21 = fVertices[i2].x() - fVertices[i1].x();
1093 G4double y21 = fVertices[i2].y() - fVertices[i1].y();
1094 G4double x31 = fVertices[i3].x() - fVertices[i1].x();
1095 G4double y31 = fVertices[i3].y() - fVertices[i1].y();
1096 G4double x42 = fVertices[i4].x() - fVertices[i2].x();
1097 G4double y42 = fVertices[i4].y() - fVertices[i2].y();
1098 G4double x43 = fVertices[i4].x() - fVertices[i3].x();
1099 G4double y43 = fVertices[i4].y() - fVertices[i3].y();
1100
1101 G4double A = x21*y43 - y21*x43;
1102 G4double B0 = x21*y31 - y21*x31;
1103 G4double B1 = x42*y31 - y42*x31;
1104 G4double HH = 4*fDz*fDz;
1105 G4double invAA = 1./(A*A);
1106 G4double sqrtAA = 2.*std::abs(A);
1107 G4double invSqrtAA = 1./sqrtAA;
1108
1109 G4double area = 0.;
1110 for (G4int i = 0; i < NSTEP; ++i)
1111 {
1112 G4double t = (i + 0.5)*dt;
1113 G4double I = y21 + (y43 - y21)*t;
1114 G4double J = x21 + (x43 - x21)*t;
1115 G4double IIJJ = HH*(I*I + J*J);
1116 G4double B = B1*t + B0;
1117
1118 G4double aa = A*A;
1119 G4double bb = 2.*A*B;
1120 G4double cc = IIJJ + B*B;
1121
1122 G4double R1 = std::sqrt(aa + bb + cc);
1123 G4double R0 = std::sqrt(cc);
1124 G4double log1 = std::log(std::abs(sqrtAA*R1 + 2.*aa + bb));
1125 G4double log0 = std::log(std::abs(sqrtAA*R0 + bb));
1126
1127 area += 0.5*R1 + 0.25*bb*invAA*(R1 - R0) + IIJJ*invSqrtAA*(log1 - log0);
1128 }
1129 return area*dt;
1130}
1131
1132////////////////////////////////////////////////////////////////////////
1133//
1134// Return volume of the solid
1135//
1137{
1138 if (fCubicVolume == 0)
1139 {
1140 G4AutoLock l(&gentrapMutex);
1141 // diagonals
1142 G4TwoVector A = fVertices[3] - fVertices[1];
1143 G4TwoVector B = fVertices[2] - fVertices[0];
1144 G4TwoVector C = fVertices[7] - fVertices[5];
1145 G4TwoVector D = fVertices[6] - fVertices[4];
1146
1147 // kross products
1148 G4double AB = A.x()*B.y() - A.y()*B.x();
1149 G4double CD = C.x()*D.y() - C.y()*D.x();
1150 G4double AD = A.x()*D.y() - A.y()*D.x();
1151 G4double CB = C.x()*B.y() - C.y()*B.x();
1152
1153 fCubicVolume = ((AB + CD)/3. + (AD + CB)/6.)*fDz;
1154 l.unlock();
1155 }
1156 return fCubicVolume;
1157}
1158
1159////////////////////////////////////////////////////////////////////////
1160//
1161// Return surface area of the solid
1162//
1164{
1165 if (fSurfaceArea == 0)
1166 {
1167 G4AutoLock l(&gentrapMutex);
1168 G4TwoVector A = fVertices[3] - fVertices[1];
1169 G4TwoVector B = fVertices[2] - fVertices[0];
1170 G4TwoVector C = fVertices[7] - fVertices[5];
1171 G4TwoVector D = fVertices[6] - fVertices[4];
1172 G4double S_bot = (A.x()*B.y() - A.y()*B.x())*0.5;
1173 G4double S_top = (C.x()*D.y() - C.y()*D.x())*0.5;
1174 fArea[0] = GetLateralFaceArea(0);
1175 fArea[1] = GetLateralFaceArea(1);
1176 fArea[2] = GetLateralFaceArea(2);
1177 fArea[3] = GetLateralFaceArea(3);
1178 fSurfaceArea = S_bot + S_top + fArea[0] + fArea[1] + fArea[2] + fArea[3];
1179 l.unlock();
1180 }
1181 return fSurfaceArea;
1182}
1183
1184////////////////////////////////////////////////////////////////////////
1185//
1186// Check parameters of the solid
1187//
1188void
1189G4GenericTrap::CheckParameters(G4double halfZ,
1190 const std::vector<G4TwoVector>& vertices)
1191{
1192 // Check number of vertices
1193 //
1194 if (vertices.size() != 8)
1195 {
1196 std::ostringstream message;
1197 message << "Number of vertices is " << vertices.size()
1198 << " instead of 8 for Solid: " << GetName() << " !";
1199 G4Exception("G4GenericTrap::CheckParameters()", "GeomSolids0002",
1200 FatalException, message);
1201 }
1202
1203 // Check dZ
1204 //
1205 if ((fDz = halfZ) < 2.*kCarTolerance)
1206 {
1207 std::ostringstream message;
1208 message << "Z-dimension is too small or negative (dZ = " << fDz << " mm)"
1209 << " for Solid: " << GetName() << " !";
1210 G4Exception("G4GenericTrap::CheckParameters()", "GeomSolids0002",
1211 FatalException, message);
1212 }
1213
1214 // Check order of vertices
1215 //
1216 for (auto i = 0; i < 8; ++i) { fVertices.at(i) = vertices[i]; }
1217
1218 // Bottom polygon area
1219 G4TwoVector diag1 = fVertices[2] - fVertices[0];
1220 G4TwoVector diag2 = fVertices[3] - fVertices[1];
1221 G4double ldiagbot = std::max(diag1.mag(), diag2.mag());
1222 G4double zbot = diag1.x()*diag2.y() - diag1.y()*diag2.x();
1223 if (std::abs(zbot) < ldiagbot*kCarTolerance) { zbot = 0.; }
1224
1225 // Top polygon area
1226 G4TwoVector diag3 = fVertices[6] - fVertices[4];
1227 G4TwoVector diag4 = fVertices[7] - fVertices[5];
1228 G4double ldiagtop = std::max(diag3.mag(), diag4.mag());
1229 G4double ztop = diag3.x()*diag4.y() - diag3.y()*diag4.x();
1230 if (std::abs(ztop) < ldiagtop*kCarTolerance) { ztop = 0.; }
1231
1232 if (zbot*ztop < 0.)
1233 {
1234 std::ostringstream message;
1235 message << "Vertices of the bottom and top polygons are defined in opposite directions !\n";
1236 StreamInfo(message);
1237 G4Exception("G4GenericTrap::CheckParameters()", "GeomSolids0002",
1238 FatalException, message);
1239 }
1240 if ((zbot > 0.) || (ztop > 0.))
1241 {
1242 std::swap(fVertices[1], fVertices[3]);
1243 std::swap(fVertices[5], fVertices[7]);
1244 std::ostringstream message;
1245 message << "Vertices re-ordered in Solid: " << GetName() << " !\n"
1246 << "Vertices of the bottom and top polygons must be defined in a clockwise direction.";
1247 G4Exception("G4GenericTrap::CheckParameters()", "GeomSolids1001",
1248 JustWarning, message);
1249 }
1250
1251 // Check for degeneracy
1252 //
1253 G4int ndegenerated = 0;
1254 for (auto i = 0; i < 4; ++i)
1255 {
1256 auto j = (i + 1)%4;
1257 G4double lbot = (fVertices[j] - fVertices[i]).mag();
1258 G4double ltop = (fVertices[j + 4] - fVertices[i + 4]).mag();
1259 ndegenerated += static_cast<int>(std::max(lbot, ltop) < kCarTolerance);
1260 }
1261 if (ndegenerated > 1 ||
1262 GetCubicVolume() < fDz*std::max(ldiagbot, ldiagtop)*kCarTolerance)
1263 {
1264 std::ostringstream message;
1265 message << "Degenerated solid !\n";
1266 StreamInfo(message);
1267 G4Exception("G4GenericTrap::CheckParameters()", "GeomSolids0002",
1268 FatalException, message);
1269 }
1270
1271 // Check that the polygons are convex
1272 //
1273 G4bool isConvex = true;
1274 for (auto i = 0; i < 4; ++i)
1275 {
1276 auto j = (i + 1)%4;
1277 auto k = (j + 1)%4;
1278 G4TwoVector edge1 = fVertices[j] - fVertices[i];
1279 G4TwoVector edge2 = fVertices[k] - fVertices[j];
1280 isConvex = ((edge1.x()*edge2.y() - edge1.y()*edge2.x()) < kCarTolerance);
1281 if (!isConvex) { break; }
1282 G4TwoVector edge3 = fVertices[j + 4] - fVertices[i + 4];
1283 G4TwoVector edge4 = fVertices[k + 4] - fVertices[j + 4];
1284 isConvex = ((edge3.x()*edge4.y() - edge3.y()*edge4.x()) < kCarTolerance);
1285 if (!isConvex) { break; }
1286 }
1287 if (!isConvex)
1288 {
1289 std::ostringstream message;
1290 message << "The bottom and top faces must be convex polygons !\n";
1291 StreamInfo(message);
1292 G4Exception("G4GenericTrap::CheckParameters()", "GeomSolids0002",
1293 FatalException, message);
1294 }
1295}
1296
1297////////////////////////////////////////////////////////////////////////
1298//
1299// Compute surface equations and twist angles of lateral faces
1300//
1301void G4GenericTrap::ComputeLateralSurfaces()
1302{
1303 for (auto i = 0; i < 4; ++i)
1304 {
1305 auto j = (i + 1)%4;
1306 G4ThreeVector p1(fVertices[j].x(), fVertices[j].y(), -fDz);
1307 G4ThreeVector p2(fVertices[i].x(), fVertices[i].y(), -fDz);
1308 G4ThreeVector p3(fVertices[j + 4].x(), fVertices[j + 4].y(), fDz);
1309 G4ThreeVector p4(fVertices[i + 4].x(), fVertices[i + 4].y(), fDz);
1310 G4ThreeVector ebot = p2 - p1;
1311 G4ThreeVector etop = p4 - p3;
1312 G4double lbot = ebot.mag();
1313 G4double ltop = etop.mag();
1314 G4double zcross = ebot.x()*etop.y() - ebot.y()*etop.x();
1315 G4double eps = kCarTolerance*std::max(lbot,ltop);
1316 if (std::min(lbot, ltop) < kCarTolerance || std::abs(zcross) < eps)
1317 { // plane surface: Dx + Ey + Fz + G = 0
1318 G4ThreeVector normal;
1319 if (std::max(lbot, ltop) < kCarTolerance) // degenerated face
1320 {
1321 auto k = (j + 1)%4; // N
1322 auto l = (k + 1)%4; // i | j
1323 G4TwoVector vl = fVertices[l] + fVertices[l + 4]; // +---+
1324 G4TwoVector vi = fVertices[i] + fVertices[i + 4]; // l / \ k
1325 G4TwoVector vj = fVertices[j] + fVertices[j + 4]; // +-------+
1326 G4TwoVector vk = fVertices[k] + fVertices[k + 4]; //
1327 G4TwoVector vij = (vi - vl).unit() + (vj - vk).unit();
1328 G4ThreeVector epar = (p4 + p3 - p2 - p1);
1329 G4ThreeVector eort = epar.cross(G4ThreeVector(vij.x(), vij.y(), 0.0));
1330 normal = (eort.cross(epar)).unit();
1331 }
1332 else
1333 {
1334 normal = ((p4 - p1).cross(p3 - p2)).unit();
1335 }
1336 fSurf[i].D = fPlane[2*i].A = fPlane[2*i + 1].A = normal.x();
1337 fSurf[i].E = fPlane[2*i].B = fPlane[2*i + 1].B = normal.y();
1338 fSurf[i].F = fPlane[2*i].C = fPlane[2*i + 1].C = normal.z();
1339 fSurf[i].G = fPlane[2*i].D = fPlane[2*i + 1].D = -normal.dot((p1 + p2 + p3 + p4)/4.);
1340 }
1341 else
1342 { // hyperbolic paraboloid: Axz + Byz + Czz + Dx + Ey + Fz + G = 0
1343 fIsTwisted = true;
1344 G4double angle = std::acos(ebot.dot(etop)/(lbot*ltop));
1345 if (angle > CLHEP::halfpi)
1346 {
1347 std::ostringstream message;
1348 message << "Twist on " << angle/CLHEP::deg
1349 << " degrees, should not be more than 90 degrees !";
1350 StreamInfo(message);
1351 G4Exception("G4GenericTrap::ComputeLateralSurfaces()", "GeomSolids0002",
1352 FatalException, message);
1353 }
1354 fTwist[i] = std::copysign(angle, zcross);
1355 // set equation of twisted surface (hyperbolic paraboloid)
1356 fSurf[i].A = 2.*fDz*(p4.y() - p3.y() - p2.y() + p1.y());
1357 fSurf[i].B =-2.*fDz*(p4.x() - p3.x() - p2.x() + p1.x());
1358 fSurf[i].C = ((p4.x() - p2.x())*(p3.y() - p1.y()) - (p4.y() - p2.y())*(p3.x() - p1.x()));
1359 fSurf[i].D = 2.*fDz*fDz*(p4.y() - p3.y() + p2.y() - p1.y());
1360 fSurf[i].E =-2.*fDz*fDz*(p4.x() - p3.x() + p2.x() - p1.x());
1361 fSurf[i].F = 2.*fDz*(p4.x()*p3.y() - p3.x()*p4.y() - p2.x()*p1.y() + p1.x()*p2.y());
1362 fSurf[i].G = fDz*fDz*((p4.x() + p2.x())*(p3.y() + p1.y()) - (p3.x() + p1.x())*(p4.y() + p2.y()));
1363 G4double magnitude = G4ThreeVector(fSurf[i].D, fSurf[i].E, fSurf[i].F).mag();
1364 if (magnitude < kCarTolerance) { continue; }
1365 fSurf[i].A /= magnitude;
1366 fSurf[i].B /= magnitude;
1367 fSurf[i].C /= magnitude;
1368 fSurf[i].D /= magnitude;
1369 fSurf[i].E /= magnitude;
1370 fSurf[i].F /= magnitude;
1371 fSurf[i].G /= magnitude;
1372 // set Lipschitz constants
1373 G4double k = std::abs(fSurf[i].C) + std::sqrt(sqr(fSurf[i].A) + sqr(fSurf[i].B) + sqr(fSurf[i].C));
1374 f4k[i] = 4.*k;
1375 // set planes of bounding polyhedron
1376 G4ThreeVector normal1, normal2;
1377 G4ThreeVector c1, c2;
1378 if (fTwist[i] < 0.)
1379 {
1380 normal1 = ((p2 - p1).cross(p4 - p1)).unit();
1381 normal2 = ((p3 - p4).cross(p1 - p4)).unit();
1382 c1 = p1;
1383 c2 = p4;
1384 }
1385 else
1386 {
1387 normal1 = ((p3 - p2).cross(p1 - p2)).unit();
1388 normal2 = ((p2 - p3).cross(p4 - p3)).unit();
1389 c1 = p2;
1390 c2 = p3;
1391 }
1392 fPlane[2*i].A = normal1.x();
1393 fPlane[2*i].B = normal1.y();
1394 fPlane[2*i].C = normal1.z();
1395 fPlane[2*i].D = -normal1.dot(c1);
1396 fPlane[2*i + 1].A = normal2.x();
1397 fPlane[2*i + 1].B = normal2.y();
1398 fPlane[2*i + 1].C = normal2.z();
1399 fPlane[2*i + 1].D = -normal2.dot(c2);
1400 }
1401 fDelta[i] = (fVertices[i + 4] - fVertices[i])/(2*fDz);
1402 }
1403}
1404
1405////////////////////////////////////////////////////////////////////////
1406//
1407// Set bounding box
1408//
1409void G4GenericTrap::ComputeBoundingBox()
1410{
1411 G4double minX, maxX, minY, maxY;
1412 minX = maxX = fVertices[0].x();
1413 minY = maxY = fVertices[0].y();
1414 for (auto i = 1; i < 8; ++i)
1415 {
1416 minX = std::min(minX, fVertices[i].x());
1417 maxX = std::max(maxX, fVertices[i].x());
1418 minY = std::min(minY, fVertices[i].y());
1419 maxY = std::max(maxY, fVertices[i].y());
1420 }
1421 fMinBBox = G4ThreeVector(minX, minY,-fDz);
1422 fMaxBBox = G4ThreeVector(maxX, maxY, fDz);
1423
1424 // Check correctness of the bounding box
1425 //
1426 if (minX >= maxX || minY >= maxY || -fDz >= fDz)
1427 {
1428 std::ostringstream message;
1429 message << "Bad bounding box (min >= max) for solid: "
1430 << GetName() << " !"
1431 << "\npMin = " << fMinBBox
1432 << "\npMax = " << fMaxBBox;
1433 G4Exception("G4GenericTrap::ComputeBoundingBox()", "GeomSolids1001",
1434 JustWarning, message);
1435 DumpInfo();
1436 }
1437}
1438
1439////////////////////////////////////////////////////////////////////////
1440//
1441// Set max length of a scratch
1442//
1443void G4GenericTrap::ComputeScratchLength()
1444{
1445 G4double scratch = kInfinity;
1446 for (auto i = 0; i < 4; ++i)
1447 {
1448 if (fTwist[i] == 0.) { continue; } // skip plane face
1449 auto k = (i + 1)%4;
1450 G4ThreeVector p1(fVertices[i].x(), fVertices[i].y(), -fDz);
1451 G4ThreeVector p2(fVertices[k].x(), fVertices[k].y(), -fDz);
1452 G4ThreeVector p3(fVertices[i + 4].x(), fVertices[i + 4].y(), fDz);
1453 G4ThreeVector p4(fVertices[k + 4].x(), fVertices[k + 4].y(), fDz);
1454 G4ThreeVector p0 = (p1 + p2 + p3 + p4)*0.25; // center of the face
1455 G4ThreeVector norm = SurfaceNormal(p0);
1456 G4ThreeVector pp[2]; // points inside and outside the surface
1457 pp[0] = p0 - norm * halfTolerance;
1458 pp[1] = p0 + norm * halfTolerance;
1459 G4ThreeVector vv[2]; // unit vectors along the diagonals
1460 vv[0] = (p4 - p1).unit();
1461 vv[1] = (p3 - p2).unit();
1462 // find intersection points and compute the scratch
1463 for (const auto & ip : pp)
1464 {
1465 G4double px = ip.x();
1466 G4double py = ip.y();
1467 G4double pz = ip.z();
1468 for (const auto & iv : vv)
1469 {
1470 G4double vx = iv.x();
1471 G4double vy = iv.y();
1472 G4double vz = iv.z();
1473 // solve quadratic equation
1474 G4double ABC = fSurf[i].A*vx + fSurf[i].B*vy + fSurf[i].C*vz;
1475 G4double ABCF = fSurf[i].A*px + fSurf[i].B*py + fSurf[i].C*pz + fSurf[i].F;
1476 G4double A = ABC*vz;
1477 G4double B = 0.5*(fSurf[i].D*vx + fSurf[i].E*vy + ABCF*vz + ABC*pz);
1478 G4double C = fSurf[i].D*px + fSurf[i].E*py + ABCF*pz + fSurf[i].G;
1479 G4double D = B*B - A*C;
1480 if (D < 0) { continue; }
1481 G4double leng = 2.*std::sqrt(D)/std::abs(A);
1482 scratch = std::min(leng, scratch);
1483 }
1484 }
1485 }
1486 fScratch = std::max(kCarTolerance, scratch);
1487}
1488
1489////////////////////////////////////////////////////////////////////////
1490//
1491// GetPolyhedron
1492//
1494{
1495 if ( (fpPolyhedron == nullptr)
1496 || fRebuildPolyhedron
1497 || (fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
1498 fpPolyhedron->GetNumberOfRotationSteps()) )
1499 {
1500 G4AutoLock l(&polyhedronMutex);
1501 delete fpPolyhedron;
1502 fpPolyhedron = CreatePolyhedron();
1503 fRebuildPolyhedron = false;
1504 l.unlock();
1505 }
1506 return fpPolyhedron;
1507}
1508
1509////////////////////////////////////////////////////////////////////////
1510//
1511// Method for visualisation
1512//
1514{
1515 scene.AddSolid(*this);
1516}
1517
1518////////////////////////////////////////////////////////////////////////
1519//
1520// Return VisExtent
1521//
1523{
1524 return { fMinBBox.x(), fMaxBBox.x(),
1525 fMinBBox.y(), fMaxBBox.y(),
1526 fMinBBox.z(), fMaxBBox.z() };
1527}
1528
1529// --------------------------------------------------------------------
1530
1532{
1533 // Approximation of Twisted Side
1534 // Construct extra Points, if Twisted Side
1535 //
1536 G4Polyhedron* polyhedron;
1537 G4int nVertices, nFacets;
1538
1539 G4int subdivisions = 0;
1540 if (fIsTwisted)
1541 {
1542 if (GetVisSubdivisions() != 0)
1543 {
1544 subdivisions = GetVisSubdivisions();
1545 }
1546 else
1547 {
1548 // Estimation of Number of Subdivisions for smooth visualisation
1549 //
1550 G4double maxTwist = 0.;
1551 for(G4int i = 0; i < 4; ++i)
1552 {
1553 if (GetTwistAngle(i) > maxTwist) { maxTwist = GetTwistAngle(i); }
1554 }
1555
1556 // Computes bounding vectors for the shape
1557 //
1558 G4double Dx, Dy;
1559 Dx = 0.5*(fMaxBBox.x() - fMinBBox.y());
1560 Dy = 0.5*(fMaxBBox.y() - fMinBBox.y());
1561 if (Dy > Dx) { Dx = Dy; }
1562
1563 subdivisions = 8*G4int(maxTwist/(Dx*Dx*Dx)*fDz);
1564 if (subdivisions < 4) { subdivisions = 4; }
1565 if (subdivisions > 30) { subdivisions = 30; }
1566 }
1567 }
1568 G4int sub4 = 4*subdivisions;
1569 nVertices = 8 + subdivisions*4;
1570 nFacets = 6 + subdivisions*4;
1571 G4double cf = 1./(subdivisions + 1);
1572 polyhedron = new G4Polyhedron(nVertices, nFacets);
1573
1574 // Set vertices
1575 //
1576 G4int icur = 0;
1577 for (G4int i = 0; i < 4; ++i)
1578 {
1579 G4ThreeVector v(fVertices[i].x(),fVertices[i].y(),-fDz);
1580 polyhedron->SetVertex(++icur, v);
1581 }
1582 for (G4int i = 0; i < subdivisions; ++i)
1583 {
1584 for (G4int j = 0; j < 4; ++j)
1585 {
1586 G4TwoVector u = fVertices[j]+cf*(i+1)*(fVertices[j+4]-fVertices[j]);
1587 G4ThreeVector v(u.x(),u.y(),-fDz+cf*2*fDz*(i+1));
1588 polyhedron->SetVertex(++icur, v);
1589 }
1590 }
1591 for (G4int i = 4; i < 8; ++i)
1592 {
1593 G4ThreeVector v(fVertices[i].x(),fVertices[i].y(),fDz);
1594 polyhedron->SetVertex(++icur, v);
1595 }
1596
1597 // Set facets
1598 //
1599 icur = 0;
1600 polyhedron->SetFacet(++icur, 1, 4, 3, 2); // Z-plane
1601 for (G4int i = 0; i < subdivisions + 1; ++i)
1602 {
1603 G4int is = i*4;
1604 polyhedron->SetFacet(++icur, 5+is, 8+is, 4+is, 1+is);
1605 polyhedron->SetFacet(++icur, 8+is, 7+is, 3+is, 4+is);
1606 polyhedron->SetFacet(++icur, 7+is, 6+is, 2+is, 3+is);
1607 polyhedron->SetFacet(++icur, 6+is, 5+is, 1+is, 2+is);
1608 }
1609 polyhedron->SetFacet(++icur, 5+sub4, 6+sub4, 7+sub4, 8+sub4); // Z-plane
1610
1611 polyhedron->SetReferences();
1612 polyhedron->InvertFacets();
1613
1614 return polyhedron;
1615}
1616
1617////////////////////////////////////////////////////////////////////////
1618//
1619// Print out a warning if A has an unexpected sign
1620//
1621void G4GenericTrap::WarningSignA(const G4String& method, const G4String& icase, G4double A,
1622 const G4ThreeVector& p, const G4ThreeVector& v) const
1623{
1624 std::ostringstream message;
1625 message.precision(16);
1626 message << icase << " in " << GetName() << "\n"
1627 << " p" << p << "\n"
1628 << " v" << v << "\n"
1629 << " A = " << A << " (is "
1630 << ((A < 0) ? "negative, instead of positive)" : "positive, instead of negative)") << " !?\n";
1631 StreamInfo(message);
1632 const G4String function = "G4GenericTrap::DistanceTo" + method + "(p,v)";
1633 G4Exception(function, "GeomSolids1002", JustWarning, message );
1634}
1635
1636////////////////////////////////////////////////////////////////////////
1637//
1638// Print out a warning if B has an unexpected sign
1639//
1640void G4GenericTrap::WarningSignB(const G4String& method, const G4String& icase,
1641 G4double f, G4double B,
1642 const G4ThreeVector& p, const G4ThreeVector& v) const
1643{
1644 std::ostringstream message;
1645 message.precision(16);
1646 message << icase << " in " << GetName() << "\n"
1647 << " p" << p << "\n"
1648 << " v" << v << "\n"
1649 << " f = " << f << " B = " << B << " (is "
1650 << ((B < 0) ? "negative, instead of positive)" : "positive, instead of negative)") << " !?\n";
1651 StreamInfo(message);
1652 const G4String function = "G4GenericTrap::DistanceTo" + method + "(p,v)";
1653 G4Exception(function, "GeomSolids1002", JustWarning, message );
1654}
1655
1656////////////////////////////////////////////////////////////////////////
1657//
1658// Print out a warning in DistanceToIn(p,v)
1659//
1660void G4GenericTrap::WarningDistanceToIn(G4int k, const G4ThreeVector& p, const G4ThreeVector& v,
1661 G4double tmin, G4double tmax,
1662 const G4double ttin[2], const G4double ttout[2]) const
1663{
1664 G4String check = "";
1665 if (ttin[1] != DBL_MAX)
1666 {
1667 G4double tcheck = 0.5*(ttout[0] + ttin[1]);
1668 if (Inside(p + v*tcheck) != kOutside)
1669 {
1670 check = "\n !!! check point 0.5*(ttout[0] + ttin[1]) is NOT outside !!!";
1671 }
1672 }
1673
1674 auto position = Inside(p);
1675 std::ostringstream message;
1676 message.precision(16);
1677 message << k << "_Unexpected sequence of intersections in solid: " << GetName() << " !?\n"
1678 << " position = " << ((position == kInside) ? "kInside" : ((position == kOutside) ? "kOutside" : "kSurface")) << "\n"
1679 << " p" << p << "\n"
1680 << " v" << v << "\n"
1681 << " range : [" << tmin << ", " << tmax << "]\n"
1682 << " ttin[2] : "
1683 << ((ttin[0] == DBL_MAX) ? kInfinity : ttin[0]) << ", "
1684 << ((ttin[1] == DBL_MAX) ? kInfinity : ttin[1]) << "\n"
1685 << " ttout[2] : "
1686 << ((ttout[0] == DBL_MAX) ? kInfinity : ttout[0]) << ", "
1687 << ((ttout[1] == DBL_MAX) ? kInfinity : ttout[1]) << check << "\n";
1688 StreamInfo(message);
1689 G4Exception("G4GenericTrap::DistanceToIn(p,v)", "GeomSolids1002",
1690 JustWarning, message );
1691}
1692
1693////////////////////////////////////////////////////////////////////////
1694//
1695// Print out a warning in DistanceToOut(p,v)
1696//
1697void G4GenericTrap::WarningDistanceToOut(const G4ThreeVector& p,
1698 const G4ThreeVector& v,
1699 G4double tout) const
1700{
1701 auto position = Inside(p);
1702 std::ostringstream message;
1703 message.precision(16);
1704 message << "Unexpected final tout = " << tout << " in solid: " << GetName() << " !?\n"
1705 << " position = " << ((position == kInside) ? "kInside" : ((position == kOutside) ? "kOutside" : "kSurface")) << "\n"
1706 << " p" << p << "\n"
1707 << " v" << v << "\n";
1708 StreamInfo(message);
1709 G4Exception("G4GenericTrap::DistanceToOut(p,v)", "GeomSolids1002",
1710 JustWarning, message );
1711}
1712
1713#endif
G4TemplateAutoLock< G4Mutex > G4AutoLock
std::vector< G4ThreeVector > G4ThreeVectorList
G4double(*)(G4double) function
G4double C(G4double temp)
G4double B(G4double temperature)
G4double D(G4double temp)
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4double G4QuickRand(uint32_t seed=0)
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
CLHEP::Hep3Vector G4ThreeVector
CLHEP::Hep2Vector G4TwoVector
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4String G4GeometryType
Definition G4VSolid.hh:70
const G4double A[17]
double x() const
double mag() const
double y() const
double z() const
Hep3Vector unit() const
double x() const
double y() const
Hep3Vector cross(const Hep3Vector &) const
double dot(const Hep3Vector &) const
double mag() const
G4AffineTransform is a class for geometric affine transformations. It supports efficient arbitrary ro...
G4BoundingEnvelope is a helper class to facilitate calculation of the extent of a solid within the li...
G4bool BoundingBoxVsVoxelLimits(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
G4GenericTrap & operator=(const G4GenericTrap &rhs)
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
G4double GetZHalfLength() const
std::ostream & StreamInfo(std::ostream &os) const override
G4TwoVector GetVertex(G4int index) const
G4GeometryType GetEntityType() const override
G4Polyhedron * GetPolyhedron() const override
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
G4double GetTwistAngle(G4int index) const
G4double GetCubicVolume() override
G4VisExtent GetExtent() const override
G4VSolid * Clone() const override
G4int GetVisSubdivisions() const
EInside Inside(const G4ThreeVector &p) const override
G4Polyhedron * CreatePolyhedron() const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const override
G4bool IsFaceted() const override
G4GenericTrap(const G4String &name, G4double halfZ, const std::vector< G4TwoVector > &vertices)
G4double GetSurfaceArea() override
G4ThreeVector GetPointOnSurface() const override
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
virtual void AddSolid(const G4Box &)=0
G4String GetName() const
G4VSolid(const G4String &name)
Definition G4VSolid.cc:59
void DumpInfo() const
G4double kCarTolerance
Definition G4VSolid.hh:418
G4VSolid & operator=(const G4VSolid &rhs)
Definition G4VSolid.cc:108
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...
void SetVertex(G4int index, const G4Point3D &v)
void SetFacet(G4int index, G4int iv1, G4int iv2, G4int iv3, G4int iv4=0)
EAxis
Definition geomdefs.hh:54
EInside
Definition geomdefs.hh:67
@ kInside
Definition geomdefs.hh:70
@ kOutside
Definition geomdefs.hh:68
@ kSurface
Definition geomdefs.hh:69
T sqr(const T &x)
Definition templates.hh:128
#define DBL_EPSILON
Definition templates.hh:66
#define DBL_MAX
Definition templates.hh:62