Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/solids/specific/src/G4GenericTrap.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

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