ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4GenericTrap.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4GenericTrap.cc
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 
33 #include "G4GenericTrap.hh"
34 
35 #if !defined(G4GEOM_USE_UGENERICTRAP)
36 
37 #include <iomanip>
38 
39 #include "G4PhysicalConstants.hh"
40 #include "G4SystemOfUnits.hh"
41 #include "G4TriangularFacet.hh"
42 #include "G4QuadrangularFacet.hh"
43 #include "G4VoxelLimits.hh"
44 #include "G4AffineTransform.hh"
45 #include "G4BoundingEnvelope.hh"
46 #include "Randomize.hh"
47 
48 #include "G4VGraphicsScene.hh"
49 #include "G4Polyhedron.hh"
50 #include "G4PolyhedronArbitrary.hh"
51 #include "G4VisExtent.hh"
52 
53 #include "G4AutoLock.hh"
54 
55 namespace
56 {
57  G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
58 }
59 
62 
63 // --------------------------------------------------------------------
64 
66  const std::vector<G4TwoVector>& vertices )
67  : G4VSolid(name), fDz(halfZ), fVertices(),
68  fMinBBoxVector(G4ThreeVector(0,0,0)), fMaxBBoxVector(G4ThreeVector(0,0,0))
69 {
70  // General constructor
71  const G4double min_length=5*1.e-6;
72  G4double length = 0.;
73  G4int k=0;
74  G4String errorDescription = "InvalidSetup in \" ";
75  errorDescription += name;
76  errorDescription += "\"";
77 
79 
80  // Check vertices size
81 
82  if ( G4int(vertices.size()) != fgkNofVertices )
83  {
84  G4Exception("G4GenericTrap::G4GenericTrap()", "GeomSolids0002",
85  FatalErrorInArgument, "Number of vertices != 8");
86  }
87 
88  // Check dZ
89  //
90  if (halfZ < kCarTolerance)
91  {
92  G4Exception("G4GenericTrap::G4GenericTrap()", "GeomSolids0002",
93  FatalErrorInArgument, "dZ is too small or negative");
94  }
95 
96  // Check Ordering and Copy vertices
97  //
98  if(CheckOrder(vertices))
99  {
100  for (G4int i=0; i<fgkNofVertices; ++i) {fVertices.push_back(vertices[i]);}
101  }
102  else
103  {
104  for (auto i=0; i <4; ++i) {fVertices.push_back(vertices[3-i]);}
105  for (auto i=0; i <4; ++i) {fVertices.push_back(vertices[7-i]);}
106  }
107 
108  // Check length of segments and Adjust
109  //
110  for (auto j=0; j<2; ++j)
111  {
112  for (auto i=1; i<4; ++i)
113  {
114  k = j*4+i;
115  length = (fVertices[k]-fVertices[k-1]).mag();
116  if ( ( length < min_length) && ( length > kCarTolerance ) )
117  {
118  std::ostringstream message;
119  message << "Length segment is too small." << G4endl
120  << "Distance between " << fVertices[k-1] << " and "
121  << fVertices[k] << " is only " << length << " mm !";
122  G4Exception("G4GenericTrap::G4GenericTrap()", "GeomSolids1001",
123  JustWarning, message, "Vertices will be collapsed.");
124  fVertices[k]=fVertices[k-1];
125  }
126  }
127  }
128 
129  // Compute Twist
130  //
131  for( auto i=0; i<4; ++i) { fTwist[i]=0.; }
133 
134  // Compute Bounding Box
135  //
136  ComputeBBox();
137 
138  // If not twisted - create tessellated solid
139  // (an alternative implementation for testing)
140  //
141 #ifdef G4TESS_TEST
143 #endif
144 }
145 
146 // --------------------------------------------------------------------
147 
149  : G4VSolid(a), halfCarTolerance(0.), fDz(0.), fVertices(),
150  fMinBBoxVector(G4ThreeVector(0,0,0)), fMaxBBoxVector(G4ThreeVector(0,0,0))
151 {
152  // Fake default constructor - sets only member data and allocates memory
153  // for usage restricted to object persistency.
154 }
155 
156 // --------------------------------------------------------------------
157 
159 {
160  delete fTessellatedSolid;
161 }
162 
163 // --------------------------------------------------------------------
164 
166  : G4VSolid(rhs),
167  halfCarTolerance(rhs.halfCarTolerance),
168  fDz(rhs.fDz), fVertices(rhs.fVertices),
169  fIsTwisted(rhs.fIsTwisted),
170  fMinBBoxVector(rhs.fMinBBoxVector), fMaxBBoxVector(rhs.fMaxBBoxVector),
171  fVisSubdivisions(rhs.fVisSubdivisions),
172  fSurfaceArea(rhs.fSurfaceArea), fCubicVolume(rhs.fCubicVolume)
173 {
174  for (auto i=0; i<4; ++i) { fTwist[i] = rhs.fTwist[i]; }
175 #ifdef G4TESS_TEST
176  if (rhs.fTessellatedSolid && !fIsTwisted )
178 #endif
179 }
180 
181 // --------------------------------------------------------------------
182 
184 {
185  // Check assignment to self
186  //
187  if (this == &rhs) { return *this; }
188 
189  // Copy base class data
190  //
191  G4VSolid::operator=(rhs);
192 
193  // Copy data
194  //
196  fDz = rhs.fDz; fVertices = rhs.fVertices;
197  fIsTwisted = rhs.fIsTwisted; fTessellatedSolid = nullptr;
201 
202  for (auto i=0; i<4; ++i) { fTwist[i] = rhs.fTwist[i]; }
203 #ifdef G4TESS_TEST
204  if (rhs.fTessellatedSolid && !fIsTwisted )
206 #endif
207  fRebuildPolyhedron = false;
208  delete fpPolyhedron; fpPolyhedron = nullptr;
209 
210  return *this;
211 }
212 
213 // --------------------------------------------------------------------
214 
215 EInside
217  const std::vector<G4TwoVector>& poly) const
218 {
219  EInside in = kInside;
220  G4double cross, len2;
221  G4int count=0;
222 
223  for (G4int i=0; i<4; ++i)
224  {
225  G4int j = (i+1) % 4;
226 
227  cross = (p.x()-poly[i].x())*(poly[j].y()-poly[i].y())-
228  (p.y()-poly[i].y())*(poly[j].x()-poly[i].x());
229 
230  len2=(poly[i]-poly[j]).mag2();
231  if (len2 > kCarTolerance)
232  {
233  if(cross*cross<=len2*halfCarTolerance*halfCarTolerance) // Surface check
234  {
235  G4double test;
236 
237  // Check if p lies between the two extremes of the segment
238  //
239  G4int iMax;
240  G4int iMin;
241 
242  if (poly[j].x() > poly[i].x())
243  {
244  iMax = j;
245  iMin = i;
246  }
247  else {
248  iMax = i;
249  iMin = j;
250  }
251  if ( p.x() > poly[iMax].x()+halfCarTolerance
252  || p.x() < poly[iMin].x()-halfCarTolerance )
253  {
254  return kOutside;
255  }
256 
257  if (poly[j].y() > poly[i].y())
258  {
259  iMax = j;
260  iMin = i;
261  }
262  else
263  {
264  iMax = i;
265  iMin = j;
266  }
267  if ( p.y() > poly[iMax].y()+halfCarTolerance
268  || p.y() < poly[iMin].y()-halfCarTolerance )
269  {
270  return kOutside;
271  }
272 
273  if ( poly[iMax].x() != poly[iMin].x() )
274  {
275  test = (p.x()-poly[iMin].x())/(poly[iMax].x()-poly[iMin].x())
276  * (poly[iMax].y()-poly[iMin].y())+poly[iMin].y();
277  }
278  else
279  {
280  test = p.y();
281  }
282 
283  // Check if point is Inside Segment
284  //
285  if( (test>=(poly[iMin].y()-halfCarTolerance))
286  && (test<=(poly[iMax].y()+halfCarTolerance)) )
287  {
288  return kSurface;
289  }
290  else
291  {
292  return kOutside;
293  }
294  }
295  else if (cross<0.) { return kOutside; }
296  }
297  else
298  {
299  ++count;
300  }
301  }
302 
303  // All collapsed vertices, Tet like
304  //
305  if(count==4)
306  {
307  if ( (std::fabs(p.x()-poly[0].x())
308  +std::fabs(p.y()-poly[0].y())) > halfCarTolerance )
309  {
310  in = kOutside;
311  }
312  }
313  return in;
314 }
315 
316 // --------------------------------------------------------------------
317 
319 {
320  // Test if point is inside this shape
321 
322 #ifdef G4TESS_TEST
323  if ( fTessellatedSolid )
324  {
325  return fTessellatedSolid->Inside(p);
326  }
327 #endif
328 
329  EInside innew=kOutside;
330  std::vector<G4TwoVector> xy;
331 
332  if (std::fabs(p.z()) <= fDz+halfCarTolerance) // First check Z range
333  {
334  // Compute intersection between Z plane containing point and the shape
335  //
336  G4double cf = 0.5*(fDz-p.z())/fDz;
337  for (auto i=0; i<4; ++i)
338  {
339  xy.push_back(fVertices[i+4]+cf*( fVertices[i]-fVertices[i+4]));
340  }
341 
342  innew=InsidePolygone(p,xy);
343 
344  if( (innew==kInside) || (innew==kSurface) )
345  {
346  if(std::fabs(p.z()) > fDz-halfCarTolerance) { innew=kSurface; }
347  }
348  }
349  return innew;
350 }
351 
352 // --------------------------------------------------------------------
353 
355 {
356  // Calculate side nearest to p, and return normal
357  // If two sides are equidistant, sum of the Normal is returned
358 
359 #ifdef G4TESS_TEST
360  if ( fTessellatedSolid )
361  {
362  return fTessellatedSolid->SurfaceNormal(p);
363  }
364 #endif
365 
366  G4ThreeVector lnorm, sumnorm(0.,0.,0.), apprnorm(0.,0.,1.),
367  p0, p1, p2, r1, r2, r3, r4;
368  G4int noSurfaces = 0;
369  G4double distxy,distz;
370  G4bool zPlusSide=false;
371 
372  distz = fDz-std::fabs(p.z());
373  if (distz < halfCarTolerance)
374  {
375  if(p.z()>0)
376  {
377  zPlusSide=true;
378  sumnorm=G4ThreeVector(0,0,1);
379  }
380  else
381  {
382  sumnorm=G4ThreeVector(0,0,-1);
383  }
384  ++noSurfaces;
385  }
386 
387  // Check lateral planes
388  //
389  std:: vector<G4TwoVector> vertices;
390  G4double cf = 0.5*(fDz-p.z())/fDz;
391  for (auto i=0; i<4; ++i)
392  {
393  vertices.push_back(fVertices[i+4]+cf*(fVertices[i]-fVertices[i+4]));
394  }
395 
396  // Compute distance for lateral planes
397  //
398  for (G4int q=0; q<4; ++q)
399  {
400  p0=G4ThreeVector(vertices[q].x(),vertices[q].y(),p.z());
401  if(zPlusSide)
402  {
403  p1=G4ThreeVector(fVertices[q].x(),fVertices[q].y(),-fDz);
404  }
405  else
406  {
407  p1=G4ThreeVector(fVertices[q+4].x(),fVertices[q+4].y(),fDz);
408  }
409  p2=G4ThreeVector(vertices[(q+1)%4].x(),vertices[(q+1)%4].y(),p.z());
410 
411  // Collapsed vertices
412  //
413  if ( (p2-p0).mag2() < kCarTolerance )
414  {
415  if ( std::fabs(p.z()+fDz) > kCarTolerance )
416  {
417  p2=G4ThreeVector(fVertices[(q+1)%4].x(),fVertices[(q+1)%4].y(),-fDz);
418  }
419  else
420  {
421  p2=G4ThreeVector(fVertices[(q+1)%4+4].x(),fVertices[(q+1)%4+4].y(),fDz);
422  }
423  }
424  lnorm = (p1-p0).cross(p2-p0);
425  lnorm = lnorm.unit();
426  if(zPlusSide) { lnorm=-lnorm; }
427 
428  // Adjust Normal for Twisted Surface
429  //
430  if ( (fIsTwisted) && (GetTwistAngle(q)!=0) )
431  {
432  G4double normP=(p2-p0).mag();
433  if(normP)
434  {
435  G4double proj=(p-p0).dot(p2-p0)/normP;
436  if(proj<0) { proj=0; }
437  if(proj>normP) { proj=normP; }
438  G4int j=(q+1)%4;
439  r1=G4ThreeVector(fVertices[q+4].x(),fVertices[q+4].y(),fDz);
440  r2=G4ThreeVector(fVertices[j+4].x(),fVertices[j+4].y(),fDz);
441  r3=G4ThreeVector(fVertices[q].x(),fVertices[q].y(),-fDz);
442  r4=G4ThreeVector(fVertices[j].x(),fVertices[j].y(),-fDz);
443  r1=r1+proj*(r2-r1)/normP;
444  r3=r3+proj*(r4-r3)/normP;
445  r2=r1-r3;
446  r4=r2.cross(p2-p0); r4=r4.unit();
447  lnorm=r4;
448  }
449  } // End if fIsTwisted
450 
451  distxy=std::fabs((p0-p).dot(lnorm));
452  if ( distxy<halfCarTolerance )
453  {
454  ++noSurfaces;
455 
456  // Negative sign for Normal is taken for Outside Normal
457  //
458  sumnorm=sumnorm+lnorm;
459  }
460 
461  // For ApproxSurfaceNormal
462  //
463  if (distxy<distz)
464  {
465  distz=distxy;
466  apprnorm=lnorm;
467  }
468  } // End for loop
469 
470  // Calculate final Normal, add Normal in the Corners and Touching Sides
471  //
472  if ( noSurfaces == 0 )
473  {
474 #ifdef G4SPECSDEBUG
475  G4Exception("G4GenericTrap::SurfaceNormal(p)", "GeomSolids1002",
476  JustWarning, "Point p is not on surface !?" );
477 #endif
478  sumnorm=apprnorm;
479  // Add Approximative Surface Normal Calculation?
480  }
481  else if ( noSurfaces == 1 ) { ; }
482  else { sumnorm = sumnorm.unit(); }
483 
484  return sumnorm ;
485 }
486 
487 // --------------------------------------------------------------------
488 
490  const G4int ipl ) const
491 {
492  // Return normal to given lateral plane ipl
493 
494 #ifdef G4TESS_TEST
495  if ( fTessellatedSolid )
496  {
497  return fTessellatedSolid->SurfaceNormal(p);
498  }
499 #endif
500 
501  G4ThreeVector lnorm, norm(0.,0.,0.), p0,p1,p2;
502 
503  G4double distz = fDz-p.z();
504  G4int i=ipl; // current plane index
505 
506  G4TwoVector u,v;
507  G4ThreeVector r1,r2,r3,r4;
508  G4double cf = 0.5*(fDz-p.z())/fDz;
509  G4int j=(i+1)%4;
510 
511  u=fVertices[i+4]+cf*(fVertices[i]-fVertices[i+4]);
512  v=fVertices[j+4]+cf*(fVertices[j]-fVertices[j+4]);
513 
514  // Compute cross product
515  //
516  p0=G4ThreeVector(u.x(),u.y(),p.z());
517 
518  if (std::fabs(distz)<halfCarTolerance)
519  {
520  p1=G4ThreeVector(fVertices[i].x(),fVertices[i].y(),-fDz);
521  distz=-1;
522  }
523  else
524  {
525  p1=G4ThreeVector(fVertices[i+4].x(),fVertices[i+4].y(),fDz);
526  }
527  p2=G4ThreeVector(v.x(),v.y(),p.z());
528 
529  // Collapsed vertices
530  //
531  if ( (p2-p0).mag2() < kCarTolerance )
532  {
533  if ( std::fabs(p.z()+fDz) > halfCarTolerance )
534  {
535  p2=G4ThreeVector(fVertices[j].x(),fVertices[j].y(),-fDz);
536  }
537  else
538  {
539  p2=G4ThreeVector(fVertices[j+4].x(),fVertices[j+4].y(),fDz);
540  }
541  }
542  lnorm=-(p1-p0).cross(p2-p0);
543  if (distz>-halfCarTolerance) { lnorm=-lnorm.unit(); }
544  else { lnorm=lnorm.unit(); }
545 
546  // Adjust Normal for Twisted Surface
547  //
548  if( (fIsTwisted) && (GetTwistAngle(ipl)!=0) )
549  {
550  G4double normP=(p2-p0).mag();
551  if(normP)
552  {
553  G4double proj=(p-p0).dot(p2-p0)/normP;
554  if (proj<0) { proj=0; }
555  if (proj>normP) { proj=normP; }
556 
557  r1=G4ThreeVector(fVertices[i+4].x(),fVertices[i+4].y(),fDz);
558  r2=G4ThreeVector(fVertices[j+4].x(),fVertices[j+4].y(),fDz);
559  r3=G4ThreeVector(fVertices[i].x(),fVertices[i].y(),-fDz);
560  r4=G4ThreeVector(fVertices[j].x(),fVertices[j].y(),-fDz);
561  r1=r1+proj*(r2-r1)/normP;
562  r3=r3+proj*(r4-r3)/normP;
563  r2=r1-r3;
564  r4=r2.cross(p2-p0);r4=r4.unit();
565  lnorm=r4;
566  }
567  } // End if fIsTwisted
568 
569  return lnorm;
570 }
571 
572 // --------------------------------------------------------------------
573 
575  const G4ThreeVector& v,
576  const G4int ipl) const
577 {
578  // Computes distance to plane ipl :
579  // ipl=0 : points 0,4,1,5
580  // ipl=1 : points 1,5,2,6
581  // ipl=2 : points 2,6,3,7
582  // ipl=3 : points 3,7,0,4
583 
584  G4double xa,xb,xc,xd,ya,yb,yc,yd;
585 
586  G4int j = (ipl+1)%4;
587 
588  xa=fVertices[ipl].x();
589  ya=fVertices[ipl].y();
590  xb=fVertices[ipl+4].x();
591  yb=fVertices[ipl+4].y();
592  xc=fVertices[j].x();
593  yc=fVertices[j].y();
594  xd=fVertices[4+j].x();
595  yd=fVertices[4+j].y();
596 
597  G4double dz2 =0.5/fDz;
598  G4double tx1 =dz2*(xb-xa);
599  G4double ty1 =dz2*(yb-ya);
600  G4double tx2 =dz2*(xd-xc);
601  G4double ty2 =dz2*(yd-yc);
602  G4double dzp =fDz+p.z();
603  G4double xs1 =xa+tx1*dzp;
604  G4double ys1 =ya+ty1*dzp;
605  G4double xs2 =xc+tx2*dzp;
606  G4double ys2 =yc+ty2*dzp;
607  G4double dxs =xs2-xs1;
608  G4double dys =ys2-ys1;
609  G4double dtx =tx2-tx1;
610  G4double dty =ty2-ty1;
611 
612  G4double a = (dtx*v.y()-dty*v.x()+(tx1*ty2-tx2*ty1)*v.z())*v.z();
613  G4double b = dxs*v.y()-dys*v.x()+(dtx*p.y()-dty*p.x()+ty2*xs1-ty1*xs2
614  + tx1*ys2-tx2*ys1)*v.z();
615  G4double c=dxs*p.y()-dys*p.x()+xs1*ys2-xs2*ys1;
617  G4double x1,x2,y1,y2,xp,yp,zi;
618 
619  if (std::fabs(a)<kCarTolerance)
620  {
621  if (std::fabs(b)<kCarTolerance) { return kInfinity; }
622  q=-c/b;
623 
624  // Check if Point is on the Surface
625 
626  if (q>-halfCarTolerance)
627  {
628  if (q<halfCarTolerance)
629  {
630  if (NormalToPlane(p,ipl).dot(v)<=0)
631  { if(Inside(p) != kOutside) { return 0.; } }
632  else
633  { return kInfinity; }
634  }
635 
636  // Check the Intersection
637  //
638  zi=p.z()+q*v.z();
639  if (std::fabs(zi)<fDz)
640  {
641  x1=xs1+tx1*v.z()*q;
642  x2=xs2+tx2*v.z()*q;
643  xp=p.x()+q*v.x();
644  y1=ys1+ty1*v.z()*q;
645  y2=ys2+ty2*v.z()*q;
646  yp=p.y()+q*v.y();
647  zi = (xp-x1)*(xp-x2)+(yp-y1)*(yp-y2);
648  if (zi<=halfCarTolerance) { return q; }
649  }
650  }
651  return kInfinity;
652  }
653  G4double d=b*b-4*a*c;
654  if (d>=0)
655  {
656  if (a>0) { q=0.5*(-b-std::sqrt(d))/a; }
657  else { q=0.5*(-b+std::sqrt(d))/a; }
658 
659  // Check if Point is on the Surface
660  //
661  if (q>-halfCarTolerance)
662  {
663  if(q<halfCarTolerance)
664  {
665  if (NormalToPlane(p,ipl).dot(v)<=0)
666  {
667  if(Inside(p)!= kOutside) { return 0.; }
668  }
669  else // Check second root; return kInfinity
670  {
671  if (a>0) { q=0.5*(-b+std::sqrt(d))/a; }
672  else { q=0.5*(-b-std::sqrt(d))/a; }
673  if (q<=halfCarTolerance) { return kInfinity; }
674  }
675  }
676  // Check the Intersection
677  //
678  zi=p.z()+q*v.z();
679  if (std::fabs(zi)<fDz)
680  {
681  x1=xs1+tx1*v.z()*q;
682  x2=xs2+tx2*v.z()*q;
683  xp=p.x()+q*v.x();
684  y1=ys1+ty1*v.z()*q;
685  y2=ys2+ty2*v.z()*q;
686  yp=p.y()+q*v.y();
687  zi = (xp-x1)*(xp-x2)+(yp-y1)*(yp-y2);
688  if (zi<=halfCarTolerance) { return q; }
689  }
690  }
691  if (a>0) { q=0.5*(-b+std::sqrt(d))/a; }
692  else { q=0.5*(-b-std::sqrt(d))/a; }
693 
694  // Check if Point is on the Surface
695  //
696  if (q>-halfCarTolerance)
697  {
698  if(q<halfCarTolerance)
699  {
700  if (NormalToPlane(p,ipl).dot(v)<=0)
701  {
702  if(Inside(p) != kOutside) { return 0.; }
703  }
704  else // Check second root; return kInfinity.
705  {
706  if (a>0) { q=0.5*(-b-std::sqrt(d))/a; }
707  else { q=0.5*(-b+std::sqrt(d))/a; }
708  if (q<=halfCarTolerance) { return kInfinity; }
709  }
710  }
711  // Check the Intersection
712  //
713  zi=p.z()+q*v.z();
714  if (std::fabs(zi)<fDz)
715  {
716  x1=xs1+tx1*v.z()*q;
717  x2=xs2+tx2*v.z()*q;
718  xp=p.x()+q*v.x();
719  y1=ys1+ty1*v.z()*q;
720  y2=ys2+ty2*v.z()*q;
721  yp=p.y()+q*v.y();
722  zi = (xp-x1)*(xp-x2)+(yp-y1)*(yp-y2);
723  if (zi<=halfCarTolerance) { return q; }
724  }
725  }
726  }
727  return kInfinity;
728 }
729 
730 // --------------------------------------------------------------------
731 
733  const G4ThreeVector& v) const
734 {
735 #ifdef G4TESS_TEST
736  if ( fTessellatedSolid )
737  {
738  return fTessellatedSolid->DistanceToIn(p, v);
739  }
740 #endif
741 
742  G4double dist[5];
744 
745  // Check lateral faces
746  //
747  G4int i;
748  for (i=0; i<4; ++i)
749  {
750  dist[i]=DistToPlane(p, v, i);
751  }
752 
753  // Check Z planes
754  //
755  dist[4]=kInfinity;
756  if (std::fabs(p.z())>fDz-halfCarTolerance)
757  {
758  if (v.z())
759  {
761  if (p.z()>0)
762  {
763  dist[4] = (fDz-p.z())/v.z();
764  }
765  else
766  {
767  dist[4] = (-fDz-p.z())/v.z();
768  }
769  if (dist[4]<-halfCarTolerance)
770  {
771  dist[4]=kInfinity;
772  }
773  else
774  {
775  if(dist[4]<halfCarTolerance)
776  {
777  if(p.z()>0) { n=G4ThreeVector(0,0,1); }
778  else { n=G4ThreeVector(0,0,-1); }
779  if (n.dot(v)<0) { dist[4]=0.; }
780  else { dist[4]=kInfinity; }
781  }
782  pt=p+dist[4]*v;
783  if (Inside(pt)==kOutside) { dist[4]=kInfinity; }
784  }
785  }
786  }
787  G4double distmin = dist[0];
788  for (i=1; i<5 ; ++i)
789  {
790  if (dist[i] < distmin) { distmin = dist[i]; }
791  }
792 
793  if (distmin<halfCarTolerance) { distmin=0.; }
794 
795  return distmin;
796 }
797 
798 // --------------------------------------------------------------------
799 
801 {
802  // Computes the closest distance from given point to this shape
803 
804 #ifdef G4TESS_TEST
805  if ( fTessellatedSolid )
806  {
807  return fTessellatedSolid->DistanceToIn(p);
808  }
809 #endif
810 
811  G4double safz = std::fabs(p.z())-fDz;
812  if(safz<0) { safz=0; }
813 
814  G4int iseg;
815  G4double safe = safz;
816  G4double safxy = safz;
817 
818  for (iseg=0; iseg<4; ++iseg)
819  {
820  safxy = SafetyToFace(p,iseg);
821  if (safxy>safe) { safe=safxy; }
822  }
823 
824  return safe;
825 }
826 
827 // --------------------------------------------------------------------
828 
829 G4double
831 {
832  // Estimate distance to lateral plane defined by segment iseg in range [0,3]
833  // Might be negative: plane seen only from inside
834 
835  G4ThreeVector p1,norm;
836  G4double safe;
837 
838  p1=G4ThreeVector(fVertices[iseg].x(),fVertices[iseg].y(),-fDz);
839 
840  norm=NormalToPlane(p,iseg);
841  safe = (p-p1).dot(norm); // Can be negative
842 
843  return safe;
844 }
845 
846 // --------------------------------------------------------------------
847 
848 G4double
850  const G4ThreeVector& v, const G4int ipl) const
851 {
852  G4double xa=fVertices[ipl].x();
853  G4double ya=fVertices[ipl].y();
854  G4double xb=fVertices[ipl+4].x();
855  G4double yb=fVertices[ipl+4].y();
856  G4int j=(ipl+1)%4;
857  G4double xc=fVertices[j].x();
858  G4double yc=fVertices[j].y();
859  G4double zab=2*fDz;
860  G4double zac=0;
861 
862  if ( (std::fabs(xa-xc)+std::fabs(ya-yc)) < halfCarTolerance )
863  {
864  xc=fVertices[j+4].x();
865  yc=fVertices[j+4].y();
866  zac=2*fDz;
867  zab=2*fDz;
868 
869  //Line case
870  //
871  if ( (std::fabs(xb-xc)+std::fabs(yb-yc)) < halfCarTolerance )
872  {
873  return kInfinity;
874  }
875  }
876  G4double a=(yb-ya)*zac-(yc-ya)*zab;
877  G4double b=(xc-xa)*zab-(xb-xa)*zac;
878  G4double c=(xb-xa)*(yc-ya)-(xc-xa)*(yb-ya);
879  G4double d=-xa*a-ya*b+fDz*c;
880  G4double t=a*v.x()+b*v.y()+c*v.z();
881 
882  if (t!=0)
883  {
884  t=-(a*p.x()+b*p.y()+c*p.z()+d)/t;
885  }
886  if ( (t<halfCarTolerance) && (t>-halfCarTolerance) )
887  {
888  if (NormalToPlane(p,ipl).dot(v)<kCarTolerance)
889  {
890  t=kInfinity;
891  }
892  else
893  {
894  t=0;
895  }
896  }
897  if (Inside(p+v*t) != kSurface) { t=kInfinity; }
898 
899  return t;
900 }
901 
902 // --------------------------------------------------------------------
903 
905  const G4ThreeVector& v,
906  const G4bool calcNorm,
907  G4bool* validNorm,
908  G4ThreeVector* n) const
909 {
910 #ifdef G4TESS_TEST
911  if ( fTessellatedSolid )
912  {
913  return fTessellatedSolid->DistanceToOut(p, v, calcNorm, validNorm, n);
914  }
915 #endif
916 
917  G4double distmin;
918  G4bool lateral_cross = false;
919  ESide side = kUndef;
920 
921  if (calcNorm) { *validNorm = true; } // All normals are valid
922 
923  if (v.z() < 0)
924  {
925  distmin=(-fDz-p.z())/v.z();
926  if (calcNorm) { side=kMZ; *n=G4ThreeVector(0,0,-1); }
927  }
928  else
929  {
930  if (v.z() > 0)
931  {
932  distmin = (fDz-p.z())/v.z();
933  if (calcNorm) { side=kPZ; *n=G4ThreeVector(0,0,1); }
934  }
935  else { distmin = kInfinity; }
936  }
937 
938  G4double dz2 =0.5/fDz;
939  G4double xa,xb,xc,xd;
940  G4double ya,yb,yc,yd;
941 
942  for (G4int ipl=0; ipl<4; ++ipl)
943  {
944  G4int j = (ipl+1)%4;
945  xa=fVertices[ipl].x();
946  ya=fVertices[ipl].y();
947  xb=fVertices[ipl+4].x();
948  yb=fVertices[ipl+4].y();
949  xc=fVertices[j].x();
950  yc=fVertices[j].y();
951  xd=fVertices[4+j].x();
952  yd=fVertices[4+j].y();
953 
954  if ( ((std::fabs(xb-xd)+std::fabs(yb-yd))<halfCarTolerance)
955  || ((std::fabs(xa-xc)+std::fabs(ya-yc))<halfCarTolerance) )
956  {
957  G4double q=DistToTriangle(p,v,ipl) ;
958  if ( (q>=0) && (q<distmin) )
959  {
960  distmin=q;
961  lateral_cross=true;
962  side=ESide(ipl+1);
963  }
964  continue;
965  }
966  G4double tx1 =dz2*(xb-xa);
967  G4double ty1 =dz2*(yb-ya);
968  G4double tx2 =dz2*(xd-xc);
969  G4double ty2 =dz2*(yd-yc);
970  G4double dzp =fDz+p.z();
971  G4double xs1 =xa+tx1*dzp;
972  G4double ys1 =ya+ty1*dzp;
973  G4double xs2 =xc+tx2*dzp;
974  G4double ys2 =yc+ty2*dzp;
975  G4double dxs =xs2-xs1;
976  G4double dys =ys2-ys1;
977  G4double dtx =tx2-tx1;
978  G4double dty =ty2-ty1;
979  G4double a = (dtx*v.y()-dty*v.x()+(tx1*ty2-tx2*ty1)*v.z())*v.z();
980  G4double b = dxs*v.y()-dys*v.x()+(dtx*p.y()-dty*p.x()+ty2*xs1-ty1*xs2
981  + tx1*ys2-tx2*ys1)*v.z();
982  G4double c=dxs*p.y()-dys*p.x()+xs1*ys2-xs2*ys1;
984 
985  if (std::fabs(a) < kCarTolerance)
986  {
987  if (std::fabs(b) < kCarTolerance) { continue; }
988  q=-c/b;
989 
990  // Check for Point on the Surface
991  //
992  if ((q > -halfCarTolerance) && (q < distmin))
993  {
994  if (q < halfCarTolerance)
995  {
996  if (NormalToPlane(p,ipl).dot(v)<0.) { continue; }
997  }
998  distmin =q;
999  lateral_cross=true;
1000  side=ESide(ipl+1);
1001  }
1002  continue;
1003  }
1004  G4double d=b*b-4*a*c;
1005  if (d >= 0.)
1006  {
1007  if (a > 0) { q=0.5*(-b-std::sqrt(d))/a; }
1008  else { q=0.5*(-b+std::sqrt(d))/a; }
1009 
1010  // Check for Point on the Surface
1011  //
1012  if (q > -halfCarTolerance )
1013  {
1014  if (q < distmin)
1015  {
1016  if(q < halfCarTolerance)
1017  {
1018  if (NormalToPlane(p,ipl).dot(v)<0.) // Check second root
1019  {
1020  if (a > 0) { q=0.5*(-b+std::sqrt(d))/a; }
1021  else { q=0.5*(-b-std::sqrt(d))/a; }
1022  if (( q > halfCarTolerance) && (q < distmin))
1023  {
1024  distmin=q;
1025  lateral_cross = true;
1026  side=ESide(ipl+1);
1027  }
1028  continue;
1029  }
1030  }
1031  distmin = q;
1032  lateral_cross = true;
1033  side=ESide(ipl+1);
1034  }
1035  }
1036  else
1037  {
1038  if (a > 0) { q=0.5*(-b+std::sqrt(d))/a; }
1039  else { q=0.5*(-b-std::sqrt(d))/a; }
1040 
1041  // Check for Point on the Surface
1042  //
1043  if ((q > -halfCarTolerance) && (q < distmin))
1044  {
1045  if (q < halfCarTolerance)
1046  {
1047  if (NormalToPlane(p,ipl).dot(v)<0.) // Check second root
1048  {
1049  if (a > 0) { q=0.5*(-b-std::sqrt(d))/a; }
1050  else { q=0.5*(-b+std::sqrt(d))/a; }
1051  if ( ( q > halfCarTolerance) && (q < distmin) )
1052  {
1053  distmin=q;
1054  lateral_cross = true;
1055  side=ESide(ipl+1);
1056  }
1057  continue;
1058  }
1059  }
1060  distmin =q;
1061  lateral_cross = true;
1062  side=ESide(ipl+1);
1063  }
1064  }
1065  }
1066  }
1067  if (!lateral_cross) // Make sure that track crosses the top or bottom
1068  {
1069  if (distmin >= kInfinity) { distmin=kCarTolerance; }
1070  G4ThreeVector pt=p+distmin*v;
1071 
1072  // Check if propagated point is in the polygon
1073  //
1074  G4int i=0;
1075  if (v.z()>0.) { i=4; }
1076  std::vector<G4TwoVector> xy;
1077  for ( G4int j=0; j<4; j++) { xy.push_back(fVertices[i+j]); }
1078 
1079  // Check Inside
1080  //
1081  if (InsidePolygone(pt,xy)==kOutside)
1082  {
1083  if(calcNorm)
1084  {
1085  if (v.z()>0) {side= kPZ; *n = G4ThreeVector(0,0,1);}
1086  else { side=kMZ; *n = G4ThreeVector(0,0,-1);}
1087  }
1088  return 0.;
1089  }
1090  else
1091  {
1092  if(v.z()>0) {side=kPZ;}
1093  else {side=kMZ;}
1094  }
1095  }
1096 
1097  if (calcNorm)
1098  {
1099  G4ThreeVector pt=p+v*distmin;
1100  switch (side)
1101  {
1102  case kXY0:
1103  *n=NormalToPlane(pt,0);
1104  break;
1105  case kXY1:
1106  *n=NormalToPlane(pt,1);
1107  break;
1108  case kXY2:
1109  *n=NormalToPlane(pt,2);
1110  break;
1111  case kXY3:
1112  *n=NormalToPlane(pt,3);
1113  break;
1114  case kPZ:
1115  *n=G4ThreeVector(0,0,1);
1116  break;
1117  case kMZ:
1118  *n=G4ThreeVector(0,0,-1);
1119  break;
1120  default:
1121  DumpInfo();
1122  std::ostringstream message;
1123  G4int oldprc = message.precision(16);
1124  message << "Undefined side for valid surface normal to solid." << G4endl
1125  << "Position:" << G4endl
1126  << " p.x() = " << p.x()/mm << " mm" << G4endl
1127  << " p.y() = " << p.y()/mm << " mm" << G4endl
1128  << " p.z() = " << p.z()/mm << " mm" << G4endl
1129  << "Direction:" << G4endl
1130  << " v.x() = " << v.x() << G4endl
1131  << " v.y() = " << v.y() << G4endl
1132  << " v.z() = " << v.z() << G4endl
1133  << "Proposed distance :" << G4endl
1134  << " distmin = " << distmin/mm << " mm";
1135  message.precision(oldprc);
1136  G4Exception("G4GenericTrap::DistanceToOut(p,v,..)",
1137  "GeomSolids1002", JustWarning, message);
1138  break;
1139  }
1140  }
1141 
1142  if (distmin<halfCarTolerance) { distmin=0.; }
1143 
1144  return distmin;
1145 }
1146 
1147 // --------------------------------------------------------------------
1148 
1150 {
1151 
1152 #ifdef G4TESS_TEST
1153  if ( fTessellatedSolid )
1154  {
1155  return fTessellatedSolid->DistanceToOut(p);
1156  }
1157 #endif
1158 
1159  G4double safz = fDz-std::fabs(p.z());
1160  if (safz<0) { safz = 0; }
1161 
1162  G4double safe = safz;
1163  G4double safxy = safz;
1164 
1165  for (G4int iseg=0; iseg<4; ++iseg)
1166  {
1167  safxy = std::fabs(SafetyToFace(p,iseg));
1168  if (safxy < safe) { safe = safxy; }
1169  }
1170 
1171  return safe;
1172 }
1173 
1174 // --------------------------------------------------------------------
1175 
1177  G4ThreeVector& pMax) const
1178 {
1179  pMin = GetMinimumBBox();
1180  pMax = GetMaximumBBox();
1181 
1182  // Check correctness of the bounding box
1183  //
1184  if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
1185  {
1186  std::ostringstream message;
1187  message << "Bad bounding box (min >= max) for solid: "
1188  << GetName() << " !"
1189  << "\npMin = " << pMin
1190  << "\npMax = " << pMax;
1191  G4Exception("G4GenericTrap::BoundingLimits()", "GeomMgt0001",
1192  JustWarning, message);
1193  DumpInfo();
1194  }
1195 }
1196 
1197 // --------------------------------------------------------------------
1198 
1199 G4bool
1201  const G4VoxelLimits& pVoxelLimit,
1202  const G4AffineTransform& pTransform,
1203  G4double& pMin, G4double& pMax) const
1204 {
1205  G4ThreeVector bmin, bmax;
1206  G4bool exist;
1207 
1208  // Check bounding box (bbox)
1209  //
1210  BoundingLimits(bmin,bmax);
1211  G4BoundingEnvelope bbox(bmin,bmax);
1212 #ifdef G4BBOX_EXTENT
1213  return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
1214 #endif
1215  if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
1216  {
1217  return exist = (pMin < pMax) ? true : false;
1218  }
1219 
1220  // Set bounding envelope (benv) and calculate extent
1221  //
1222  // To build the bounding envelope with plane faces each side face of
1223  // the trapezoid is subdivided in triangles. Subdivision is done by
1224  // duplication of vertices in the bases in a way that the envelope be
1225  // a convex polyhedron (some faces of the envelope can be degenerate)
1226  //
1228  G4ThreeVectorList baseA(8), baseB(8);
1229  for (G4int i=0; i<4; ++i)
1230  {
1231  G4TwoVector va = GetVertex(i);
1232  G4TwoVector vb = GetVertex(i+4);
1233  baseA[2*i].set(va.x(),va.y(),-dz);
1234  baseB[2*i].set(vb.x(),vb.y(), dz);
1235  }
1236  for (G4int i=0; i<4; ++i)
1237  {
1238  G4int k1=2*i, k2=(2*i+2)%8;
1239  G4double ax = (baseA[k2].x()-baseA[k1].x());
1240  G4double ay = (baseA[k2].y()-baseA[k1].y());
1241  G4double bx = (baseB[k2].x()-baseB[k1].x());
1242  G4double by = (baseB[k2].y()-baseB[k1].y());
1243  G4double znorm = ax*by - ay*bx;
1244  baseA[k1+1] = (znorm < 0.0) ? baseA[k2] : baseA[k1];
1245  baseB[k1+1] = (znorm < 0.0) ? baseB[k1] : baseB[k2];
1246  }
1247 
1248  std::vector<const G4ThreeVectorList *> polygons(2);
1249  polygons[0] = &baseA;
1250  polygons[1] = &baseB;
1251 
1252  G4BoundingEnvelope benv(bmin,bmax,polygons);
1253  exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
1254  return exist;
1255 }
1256 
1257 // --------------------------------------------------------------------
1258 
1260 {
1261  return G4String("G4GenericTrap");
1262 }
1263 
1264 // --------------------------------------------------------------------
1265 
1267 {
1268  return new G4GenericTrap(*this);
1269 }
1270 
1271 // --------------------------------------------------------------------
1272 
1273 std::ostream& G4GenericTrap::StreamInfo(std::ostream& os) const
1274 {
1275  G4int oldprc = os.precision(16);
1276  os << "-----------------------------------------------------------\n"
1277  << " *** Dump for solid - " << GetName() << " *** \n"
1278  << " =================================================== \n"
1279  << " Solid geometry type: " << GetEntityType() << G4endl
1280  << " half length Z: " << fDz/mm << " mm \n"
1281  << " list of vertices:\n";
1282 
1283  for ( G4int i=0; i<fgkNofVertices; ++i )
1284  {
1285  os << std::setw(5) << "#" << i
1286  << " vx = " << fVertices[i].x()/mm << " mm"
1287  << " vy = " << fVertices[i].y()/mm << " mm" << G4endl;
1288  }
1289  os.precision(oldprc);
1290 
1291  return os;
1292 }
1293 
1294 // --------------------------------------------------------------------
1295 
1297 {
1298 
1299 #ifdef G4TESS_TEST
1300  if ( fTessellatedSolid )
1301  {
1303  }
1304 #endif
1305 
1307  G4TwoVector u,v,w;
1308  G4double rand,area,chose,cf,lambda0,lambda1,alfa,beta,zp;
1309  G4int ipl,j;
1310 
1311  std::vector<G4ThreeVector> vertices;
1312  for (auto i=0; i<4; ++i)
1313  {
1314  vertices.push_back(G4ThreeVector(fVertices[i].x(),fVertices[i].y(),-fDz));
1315  }
1316  for (auto i=4; i<8; ++i)
1317  {
1318  vertices.push_back(G4ThreeVector(fVertices[i].x(),fVertices[i].y(),fDz));
1319  }
1320 
1321  // Surface Area of Planes(only estimation for twisted)
1322  //
1323  G4double Surface0=GetFaceSurfaceArea(vertices[0],vertices[1],
1324  vertices[2],vertices[3]);//-fDz plane
1325  G4double Surface1=GetFaceSurfaceArea(vertices[0],vertices[1],
1326  vertices[5],vertices[4]);// Lat plane
1327  G4double Surface2=GetFaceSurfaceArea(vertices[3],vertices[0],
1328  vertices[4],vertices[7]);// Lat plane
1329  G4double Surface3=GetFaceSurfaceArea(vertices[2],vertices[3],
1330  vertices[7],vertices[6]);// Lat plane
1331  G4double Surface4=GetFaceSurfaceArea(vertices[2],vertices[1],
1332  vertices[5],vertices[6]);// Lat plane
1333  G4double Surface5=GetFaceSurfaceArea(vertices[4],vertices[5],
1334  vertices[6],vertices[7]);// fDz plane
1335  rand = G4UniformRand();
1336  area = Surface0+Surface1+Surface2+Surface3+Surface4+Surface5;
1337  chose = rand*area;
1338 
1339  if ( ( chose < Surface0)
1340  || ( chose > (Surface0+Surface1+Surface2+Surface3+Surface4)) )
1341  { // fDz or -fDz Plane
1342  ipl = G4int(G4UniformRand()*4);
1343  j = (ipl+1)%4;
1344  if(chose < Surface0)
1345  {
1346  zp = -fDz;
1347  u = fVertices[ipl]; v = fVertices[j];
1348  w = fVertices[(ipl+3)%4];
1349  }
1350  else
1351  {
1352  zp = fDz;
1353  u = fVertices[ipl+4]; v = fVertices[j+4];
1354  w = fVertices[(ipl+3)%4+4];
1355  }
1356  alfa = G4UniformRand();
1357  beta = G4UniformRand();
1358  lambda1=alfa*beta;
1359  lambda0=alfa-lambda1;
1360  v = v-u;
1361  w = w-u;
1362  v = u+lambda0*v+lambda1*w;
1363  }
1364  else // Lateral Plane Twisted or Not
1365  {
1366  if (chose < Surface0+Surface1) { ipl=0; }
1367  else if (chose < Surface0+Surface1+Surface2) { ipl=1; }
1368  else if (chose < Surface0+Surface1+Surface2+Surface3) { ipl=2; }
1369  else { ipl=3; }
1370  j = (ipl+1)%4;
1371  zp = -fDz+G4UniformRand()*2*fDz;
1372  cf = 0.5*(fDz-zp)/fDz;
1373  u = fVertices[ipl+4]+cf*( fVertices[ipl]-fVertices[ipl+4]);
1374  v = fVertices[j+4]+cf*(fVertices[j]-fVertices[j+4]);
1375  v = u+(v-u)*G4UniformRand();
1376  }
1377  point=G4ThreeVector(v.x(),v.y(),zp);
1378 
1379  return point;
1380 }
1381 
1382 // --------------------------------------------------------------------
1383 
1385 {
1386  if (fSurfaceArea == 0.0)
1387  {
1388  if(fIsTwisted)
1389  {
1391  }
1392  else
1393  {
1394  // Set vertices
1395  G4ThreeVector vertix0(fVertices[0].x(),fVertices[0].y(),-fDz);
1396  G4ThreeVector vertix1(fVertices[1].x(),fVertices[1].y(),-fDz);
1397  G4ThreeVector vertix2(fVertices[2].x(),fVertices[2].y(),-fDz);
1398  G4ThreeVector vertix3(fVertices[3].x(),fVertices[3].y(),-fDz);
1399  G4ThreeVector vertix4(fVertices[4].x(),fVertices[4].y(), fDz);
1400  G4ThreeVector vertix5(fVertices[5].x(),fVertices[5].y(), fDz);
1401  G4ThreeVector vertix6(fVertices[6].x(),fVertices[6].y(), fDz);
1402  G4ThreeVector vertix7(fVertices[7].x(),fVertices[7].y(), fDz);
1403 
1404  // Find Surface Area
1405  fSurfaceArea = GetFaceSurfaceArea(vertix0,vertix1,vertix2,vertix3) // -fDz plane
1406  + GetFaceSurfaceArea(vertix1,vertix0,vertix4,vertix5) // Lat plane
1407  + GetFaceSurfaceArea(vertix2,vertix1,vertix5,vertix6) // Lat plane
1408  + GetFaceSurfaceArea(vertix3,vertix2,vertix6,vertix7) // Lat plane
1409  + GetFaceSurfaceArea(vertix0,vertix3,vertix7,vertix4) // Lat plane
1410  + GetFaceSurfaceArea(vertix7,vertix6,vertix5,vertix4); // +fDz plane
1411  }
1412  }
1413  return fSurfaceArea;
1414 }
1415 
1416 // --------------------------------------------------------------------
1417 
1419 {
1420  if (fCubicVolume == 0.0)
1421  {
1422  if(fIsTwisted)
1423  {
1425  }
1426  else
1427  {
1428  // Set vertices
1429  G4ThreeVector vertix0(fVertices[0].x(),fVertices[0].y(),-fDz);
1430  G4ThreeVector vertix1(fVertices[1].x(),fVertices[1].y(),-fDz);
1431  G4ThreeVector vertix2(fVertices[2].x(),fVertices[2].y(),-fDz);
1432  G4ThreeVector vertix3(fVertices[3].x(),fVertices[3].y(),-fDz);
1433  G4ThreeVector vertix4(fVertices[4].x(),fVertices[4].y(), fDz);
1434  G4ThreeVector vertix5(fVertices[5].x(),fVertices[5].y(), fDz);
1435  G4ThreeVector vertix6(fVertices[6].x(),fVertices[6].y(), fDz);
1436  G4ThreeVector vertix7(fVertices[7].x(),fVertices[7].y(), fDz);
1437 
1438  // Find Cubic Volume
1439  fCubicVolume = GetFaceCubicVolume(vertix0,vertix1,vertix2,vertix3) // -fDz plane
1440  + GetFaceCubicVolume(vertix1,vertix0,vertix4,vertix5) // Lat plane
1441  + GetFaceCubicVolume(vertix2,vertix1,vertix5,vertix6) // Lat plane
1442  + GetFaceCubicVolume(vertix3,vertix2,vertix6,vertix7) // Lat plane
1443  + GetFaceCubicVolume(vertix0,vertix3,vertix7,vertix4) // Lat plane
1444  + GetFaceCubicVolume(vertix7,vertix6,vertix5,vertix4); // +fDz plane
1445  }
1446  }
1447  return fCubicVolume;
1448 }
1449 
1450 // --------------------------------------------------------------------
1451 
1453  const G4ThreeVector& p1,
1454  const G4ThreeVector& p2,
1455  const G4ThreeVector& p3) const
1456 {
1457  // Returns area of the facet
1458  return (((p2-p0).cross(p3-p1)).mag()) / 2.;
1459 }
1460 
1461 // --------------------------------------------------------------------
1462 
1464  const G4ThreeVector& p1,
1465  const G4ThreeVector& p2,
1466  const G4ThreeVector& p3) const
1467 {
1468  // Returns contribution of the facet to the volume of the solid.
1469  // Orientation of the facet is important, normal should point to outside.
1470  return (((p2-p0).cross(p3-p1)).dot(p0)) / 6.;
1471 }
1472 
1473 // --------------------------------------------------------------------
1474 
1476 {
1477  // Computes tangents of twist angles (angles between projections on XY plane
1478  // of corresponding -dz +dz edges).
1479 
1480  G4bool twisted = false;
1481  G4double dx1, dy1, dx2, dy2;
1482  G4int nv = fgkNofVertices/2;
1483 
1484  for ( G4int i=0; i<4; ++i )
1485  {
1486  dx1 = fVertices[(i+1)%nv].x()-fVertices[i].x();
1487  dy1 = fVertices[(i+1)%nv].y()-fVertices[i].y();
1488  if ( (dx1 == 0) && (dy1 == 0) ) { continue; }
1489 
1490  dx2 = fVertices[nv+(i+1)%nv].x()-fVertices[nv+i].x();
1491  dy2 = fVertices[nv+(i+1)%nv].y()-fVertices[nv+i].y();
1492 
1493  if ( dx2 == 0 && dy2 == 0 ) { continue; }
1494  G4double twist_angle = std::fabs(dy1*dx2 - dx1*dy2);
1495  if ( twist_angle < fgkTolerance ) { continue; }
1496  twisted = true;
1497  SetTwistAngle(i,twist_angle);
1498 
1499  // Check on big angles, potentially navigation problem
1500 
1501  twist_angle = std::acos( (dx1*dx2 + dy1*dy2)
1502  / (std::sqrt(dx1*dx1+dy1*dy1)
1503  * std::sqrt(dx2*dx2+dy2*dy2)) );
1504 
1505  if ( std::fabs(twist_angle) > 0.5*pi+kCarTolerance )
1506  {
1507  std::ostringstream message;
1508  message << "Twisted Angle is bigger than 90 degrees - " << GetName()
1509  << G4endl
1510  << " Potential problem of malformed Solid !" << G4endl
1511  << " TwistANGLE = " << twist_angle
1512  << "*rad for lateral plane N= " << i;
1513  G4Exception("G4GenericTrap::ComputeIsTwisted()", "GeomSolids1002",
1514  JustWarning, message);
1515  }
1516  }
1517 
1518  return twisted;
1519 }
1520 
1521 // --------------------------------------------------------------------
1522 
1523 G4bool G4GenericTrap::CheckOrder(const std::vector<G4TwoVector>& vertices) const
1524 {
1525  // Test if the vertices are in a clockwise order, if not reorder them.
1526  // Also test if they're well defined without crossing opposite segments
1527 
1528  G4bool clockwise_order=true;
1529  G4double sum1 = 0.;
1530  G4double sum2 = 0.;
1531  G4int j;
1532 
1533  for (G4int i=0; i<4; ++i)
1534  {
1535  j = (i+1)%4;
1536  sum1 += vertices[i].x()*vertices[j].y() - vertices[j].x()*vertices[i].y();
1537  sum2 += vertices[i+4].x()*vertices[j+4].y()
1538  - vertices[j+4].x()*vertices[i+4].y();
1539  }
1540  if (sum1*sum2 < -fgkTolerance)
1541  {
1542  std::ostringstream message;
1543  message << "Lower/upper faces defined with opposite clockwise - "
1544  << GetName();
1545  G4Exception("G4GenericTrap::CheckOrder()", "GeomSolids0002",
1546  FatalException, message);
1547  }
1548 
1549  if ((sum1 > 0.)||(sum2 > 0.))
1550  {
1551  std::ostringstream message;
1552  message << "Vertices must be defined in clockwise XY planes - "
1553  << GetName();
1554  G4Exception("G4GenericTrap::CheckOrder()", "GeomSolids1001",
1555  JustWarning,message, "Re-ordering...");
1556  clockwise_order = false;
1557  }
1558 
1559  // Check for illegal crossings
1560  //
1561  G4bool illegal_cross = false;
1562  illegal_cross = IsSegCrossingZ(vertices[0],vertices[4],
1563  vertices[1],vertices[5]);
1564 
1565  if (!illegal_cross)
1566  {
1567  illegal_cross = IsSegCrossingZ(vertices[2],vertices[6],
1568  vertices[3],vertices[7]);
1569  }
1570  // +/- dZ planes
1571  if (!illegal_cross)
1572  {
1573  illegal_cross = IsSegCrossing(vertices[0],vertices[1],
1574  vertices[2],vertices[3]);
1575  }
1576  if (!illegal_cross)
1577  {
1578  illegal_cross = IsSegCrossing(vertices[0],vertices[3],
1579  vertices[1],vertices[2]);
1580  }
1581  if (!illegal_cross)
1582  {
1583  illegal_cross = IsSegCrossing(vertices[4],vertices[5],
1584  vertices[6],vertices[7]);
1585  }
1586  if (!illegal_cross)
1587  {
1588  illegal_cross = IsSegCrossing(vertices[4],vertices[7],
1589  vertices[5],vertices[6]);
1590  }
1591 
1592  if (illegal_cross)
1593  {
1594  std::ostringstream message;
1595  message << "Malformed polygone with opposite sides - " << GetName();
1596  G4Exception("G4GenericTrap::CheckOrderAndSetup()",
1597  "GeomSolids0002", FatalException, message);
1598  }
1599  return clockwise_order;
1600 }
1601 
1602 // --------------------------------------------------------------------
1603 
1604 void G4GenericTrap::ReorderVertices(std::vector<G4ThreeVector>& vertices) const
1605 {
1606  // Reorder the vector of vertices
1607 
1608  std::vector<G4ThreeVector> oldVertices(vertices);
1609 
1610  for ( size_t i=0; i<oldVertices.size(); ++i )
1611  {
1612  vertices[i] = oldVertices[oldVertices.size()-1-i];
1613  }
1614 }
1615 
1616 // --------------------------------------------------------------------
1617 
1618 G4bool
1620  const G4TwoVector& c, const G4TwoVector& d) const
1621 {
1622  // Check if segments [A,B] and [C,D] are crossing
1623 
1624  G4bool stand1 = false;
1625  G4bool stand2 = false;
1626  G4double dx1,dx2,xm=0.,ym=0.,a1=0.,a2=0.,b1=0.,b2=0.;
1627  dx1=(b-a).x();
1628  dx2=(d-c).x();
1629 
1630  if( std::fabs(dx1) < fgkTolerance ) { stand1 = true; }
1631  if( std::fabs(dx2) < fgkTolerance ) { stand2 = true; }
1632  if (!stand1)
1633  {
1634  a1 = (b.x()*a.y()-a.x()*b.y())/dx1;
1635  b1 = (b-a).y()/dx1;
1636  }
1637  if (!stand2)
1638  {
1639  a2 = (d.x()*c.y()-c.x()*d.y())/dx2;
1640  b2 = (d-c).y()/dx2;
1641  }
1642  if (stand1 && stand2)
1643  {
1644  // Segments parallel and vertical
1645  //
1646  if (std::fabs(a.x()-c.x())<fgkTolerance)
1647  {
1648  // Check if segments are overlapping
1649  //
1650  if ( ((c.y()-a.y())*(c.y()-b.y())<-fgkTolerance)
1651  || ((d.y()-a.y())*(d.y()-b.y())<-fgkTolerance)
1652  || ((a.y()-c.y())*(a.y()-d.y())<-fgkTolerance)
1653  || ((b.y()-c.y())*(b.y()-d.y())<-fgkTolerance) ) { return true; }
1654 
1655  return false;
1656  }
1657  // Different x values
1658  //
1659  return false;
1660  }
1661 
1662  if (stand1) // First segment vertical
1663  {
1664  xm = a.x();
1665  ym = a2+b2*xm;
1666  }
1667  else
1668  {
1669  if (stand2) // Second segment vertical
1670  {
1671  xm = c.x();
1672  ym = a1+b1*xm;
1673  }
1674  else // Normal crossing
1675  {
1676  if (std::fabs(b1-b2) < fgkTolerance)
1677  {
1678  // Parallel segments, are they aligned
1679  //
1680  if (std::fabs(c.y()-(a1+b1*c.x())) > fgkTolerance) { return false; }
1681 
1682  // Aligned segments, are they overlapping
1683  //
1684  if ( ((c.x()-a.x())*(c.x()-b.x())<-fgkTolerance)
1685  || ((d.x()-a.x())*(d.x()-b.x())<-fgkTolerance)
1686  || ((a.x()-c.x())*(a.x()-d.x())<-fgkTolerance)
1687  || ((b.x()-c.x())*(b.x()-d.x())<-fgkTolerance) ) { return true; }
1688 
1689  return false;
1690  }
1691  xm = (a1-a2)/(b2-b1);
1692  ym = (a1*b2-a2*b1)/(b2-b1);
1693  }
1694  }
1695 
1696  // Check if crossing point is both between A,B and C,D
1697  //
1698  G4double check = (xm-a.x())*(xm-b.x())+(ym-a.y())*(ym-b.y());
1699  if (check > -fgkTolerance) { return false; }
1700  check = (xm-c.x())*(xm-d.x())+(ym-c.y())*(ym-d.y());
1701  if (check > -fgkTolerance) { return false; }
1702 
1703  return true;
1704 }
1705 
1706 // --------------------------------------------------------------------
1707 
1708 G4bool
1710  const G4TwoVector& c, const G4TwoVector& d) const
1711 {
1712  // Check if segments [A,B] and [C,D] are crossing when
1713  // A and C are on -dZ and B and D are on +dZ
1714 
1715  // Calculate the Intersection point between two lines in 3D
1716  //
1718  G4ThreeVector v1,v2,p1,p2,p3,p4,dv;
1719  G4double q,det;
1720  p1=G4ThreeVector(a.x(),a.y(),-fDz);
1721  p2=G4ThreeVector(c.x(),c.y(),-fDz);
1722  p3=G4ThreeVector(b.x(),b.y(),fDz);
1723  p4=G4ThreeVector(d.x(),d.y(),fDz);
1724  v1=p3-p1;
1725  v2=p4-p2;
1726  dv=p2-p1;
1727 
1728  // In case of Collapsed Vertices No crossing
1729  //
1730  if( (std::fabs(dv.x()) < kCarTolerance )&&
1731  (std::fabs(dv.y()) < kCarTolerance ) ) { return false; }
1732 
1733  if( (std::fabs((p4-p3).x()) < kCarTolerance )&&
1734  (std::fabs((p4-p3).y()) < kCarTolerance ) ) { return false; }
1735 
1736  // First estimate if Intersection is possible( if det is 0)
1737  //
1738  det = dv.x()*v1.y()*v2.z()+dv.y()*v1.z()*v2.x()
1739  - dv.x()*v1.z()*v2.y()-dv.y()*v1.x()*v2.z();
1740 
1741  if (std::fabs(det)<kCarTolerance) //Intersection
1742  {
1743  temp1 = v1.cross(v2);
1744  temp2 = (p2-p1).cross(v2);
1745  if (temp1.dot(temp2) < 0) { return false; } // intersection negative
1746  q = temp1.mag();
1747 
1748  if ( q < kCarTolerance ) { return false; } // parallel lines
1749  q = ((dv).cross(v2)).mag()/q;
1750 
1751  if(q < 1.-kCarTolerance) { return true; }
1752  }
1753  return false;
1754 }
1755 
1756 // --------------------------------------------------------------------
1757 
1758 G4VFacet*
1759 G4GenericTrap::MakeDownFacet(const std::vector<G4ThreeVector>& fromVertices,
1760  G4int ind1, G4int ind2, G4int ind3) const
1761 {
1762  // Create a triangular facet from the polygon points given by indices
1763  // forming the down side ( the normal goes in -z)
1764  // Do not create facet if 2 vertices are the same
1765 
1766  if ( (fromVertices[ind1] == fromVertices[ind2]) ||
1767  (fromVertices[ind2] == fromVertices[ind3]) ||
1768  (fromVertices[ind1] == fromVertices[ind3]) ) { return 0; }
1769 
1770  std::vector<G4ThreeVector> vertices;
1771  vertices.push_back(fromVertices[ind1]);
1772  vertices.push_back(fromVertices[ind2]);
1773  vertices.push_back(fromVertices[ind3]);
1774 
1775  // first vertex most left
1776  //
1777  G4ThreeVector cross=(vertices[1]-vertices[0]).cross(vertices[2]-vertices[1]);
1778 
1779  if ( cross.z() > 0.0 )
1780  {
1781  // Should not happen, as vertices should have been reordered at this stage
1782 
1783  std::ostringstream message;
1784  message << "Vertices in wrong order - " << GetName();
1785  G4Exception("G4GenericTrap::MakeDownFacet", "GeomSolids0002",
1786  FatalException, message);
1787  }
1788 
1789  return new G4TriangularFacet(vertices[0], vertices[1], vertices[2], ABSOLUTE);
1790 }
1791 
1792 // --------------------------------------------------------------------
1793 
1794 G4VFacet*
1795 G4GenericTrap::MakeUpFacet(const std::vector<G4ThreeVector>& fromVertices,
1796  G4int ind1, G4int ind2, G4int ind3) const
1797 {
1798  // Create a triangular facet from the polygon points given by indices
1799  // forming the upper side ( z>0 )
1800 
1801  // Do not create facet if 2 vertices are the same
1802  //
1803  if ( (fromVertices[ind1] == fromVertices[ind2]) ||
1804  (fromVertices[ind2] == fromVertices[ind3]) ||
1805  (fromVertices[ind1] == fromVertices[ind3]) ) { return nullptr; }
1806 
1807  std::vector<G4ThreeVector> vertices;
1808  vertices.push_back(fromVertices[ind1]);
1809  vertices.push_back(fromVertices[ind2]);
1810  vertices.push_back(fromVertices[ind3]);
1811 
1812  // First vertex most left
1813  //
1814  G4ThreeVector cross=(vertices[1]-vertices[0]).cross(vertices[2]-vertices[1]);
1815 
1816  if ( cross.z() < 0.0 )
1817  {
1818  // Should not happen, as vertices should have been reordered at this stage
1819 
1820  std::ostringstream message;
1821  message << "Vertices in wrong order - " << GetName();
1822  G4Exception("G4GenericTrap::MakeUpFacet", "GeomSolids0002",
1823  FatalException, message);
1824  }
1825 
1826  return new G4TriangularFacet(vertices[0], vertices[1], vertices[2], ABSOLUTE);
1827 }
1828 
1829 // --------------------------------------------------------------------
1830 
1831 G4VFacet*
1833  const G4ThreeVector& downVertex1,
1834  const G4ThreeVector& upVertex1,
1835  const G4ThreeVector& upVertex0) const
1836 {
1837  // Creates a triangular facet from the polygon points given by indices
1838  // forming the upper side ( z>0 )
1839 
1840  if ( (downVertex0 == downVertex1) && (upVertex0 == upVertex1) )
1841  {
1842  return nullptr;
1843  }
1844 
1845  if ( downVertex0 == downVertex1 )
1846  {
1847  return new G4TriangularFacet(downVertex0, upVertex1, upVertex0, ABSOLUTE);
1848  }
1849 
1850  if ( upVertex0 == upVertex1 )
1851  {
1852  return new G4TriangularFacet(downVertex0, downVertex1, upVertex0, ABSOLUTE);
1853  }
1854 
1855  return new G4QuadrangularFacet(downVertex0, downVertex1,
1856  upVertex1, upVertex0, ABSOLUTE);
1857 }
1858 
1859 // --------------------------------------------------------------------
1860 
1862 {
1863  // 3D vertices
1864  //
1865  G4int nv = fgkNofVertices/2;
1866  std::vector<G4ThreeVector> downVertices;
1867  for ( G4int i=0; i<nv; ++i )
1868  {
1869  downVertices.push_back(G4ThreeVector(fVertices[i].x(),
1870  fVertices[i].y(), -fDz));
1871  }
1872 
1873  std::vector<G4ThreeVector> upVertices;
1874  for ( G4int i=nv; i<2*nv; ++i )
1875  {
1876  upVertices.push_back(G4ThreeVector(fVertices[i].x(),
1877  fVertices[i].y(), fDz));
1878  }
1879 
1880  // Reorder vertices if they are not ordered anti-clock wise
1881  //
1883  = (downVertices[1]-downVertices[0]).cross(downVertices[2]-downVertices[1]);
1884  G4ThreeVector cross1
1885  = (upVertices[1]-upVertices[0]).cross(upVertices[2]-upVertices[1]);
1886  if ( (cross.z() > 0.0) || (cross1.z() > 0.0) )
1887  {
1888  ReorderVertices(downVertices);
1889  ReorderVertices(upVertices);
1890  }
1891 
1892  G4TessellatedSolid* tessellatedSolid = new G4TessellatedSolid(GetName());
1893 
1894  G4VFacet* facet = 0;
1895  facet = MakeDownFacet(downVertices, 0, 1, 2);
1896  if (facet) { tessellatedSolid->AddFacet( facet ); }
1897  facet = MakeDownFacet(downVertices, 0, 2, 3);
1898  if (facet) { tessellatedSolid->AddFacet( facet ); }
1899  facet = MakeUpFacet(upVertices, 0, 2, 1);
1900  if (facet) { tessellatedSolid->AddFacet( facet ); }
1901  facet = MakeUpFacet(upVertices, 0, 3, 2);
1902  if (facet) { tessellatedSolid->AddFacet( facet ); }
1903 
1904  // The quadrangular sides
1905  //
1906  for ( G4int i = 0; i < nv; ++i )
1907  {
1908  G4int j = (i+1) % nv;
1909  facet = MakeSideFacet(downVertices[j], downVertices[i],
1910  upVertices[i], upVertices[j]);
1911 
1912  if ( facet ) { tessellatedSolid->AddFacet( facet ); }
1913  }
1914 
1915  tessellatedSolid->SetSolidClosed(true);
1916 
1917  return tessellatedSolid;
1918 }
1919 
1920 // --------------------------------------------------------------------
1921 
1923 {
1924  // Computes bounding box for a shape.
1925 
1926  G4double minX, maxX, minY, maxY;
1927  minX = maxX = fVertices[0].x();
1928  minY = maxY = fVertices[0].y();
1929 
1930  for (G4int i=1; i< fgkNofVertices; i++)
1931  {
1932  if (minX>fVertices[i].x()) { minX=fVertices[i].x(); }
1933  if (maxX<fVertices[i].x()) { maxX=fVertices[i].x(); }
1934  if (minY>fVertices[i].y()) { minY=fVertices[i].y(); }
1935  if (maxY<fVertices[i].y()) { maxY=fVertices[i].y(); }
1936  }
1937  fMinBBoxVector = G4ThreeVector(minX,minY,-fDz);
1938  fMaxBBoxVector = G4ThreeVector(maxX,maxY, fDz);
1939 }
1940 
1941 // --------------------------------------------------------------------
1942 
1944 {
1945 
1946 #ifdef G4TESS_TEST
1947  if ( fTessellatedSolid )
1948  {
1949  return fTessellatedSolid->GetPolyhedron();
1950  }
1951 #endif
1952 
1953  if ( (fpPolyhedron == nullptr)
1957  {
1958  G4AutoLock l(&polyhedronMutex);
1959  delete fpPolyhedron;
1961  fRebuildPolyhedron = false;
1962  l.unlock();
1963  }
1964  return fpPolyhedron;
1965 }
1966 
1967 // --------------------------------------------------------------------
1968 
1970 {
1971 
1972 #ifdef G4TESS_TEST
1973  if ( fTessellatedSolid )
1974  {
1975  return fTessellatedSolid->DescribeYourselfTo(scene);
1976  }
1977 #endif
1978 
1979  scene.AddSolid(*this);
1980 }
1981 
1982 // --------------------------------------------------------------------
1983 
1985 {
1986  // Computes bounding vectors for the shape
1987 
1988 #ifdef G4TESS_TEST
1989  if ( fTessellatedSolid != nullptr )
1990  {
1991  return fTessellatedSolid->GetExtent();
1992  }
1993 #endif
1994 
1995  G4ThreeVector minVec = GetMinimumBBox();
1996  G4ThreeVector maxVec = GetMaximumBBox();
1997  return G4VisExtent (minVec.x(), maxVec.x(),
1998  minVec.y(), maxVec.y(),
1999  minVec.z(), maxVec.z());
2000 }
2001 
2002 // --------------------------------------------------------------------
2003 
2005 {
2006 
2007 #ifdef G4TESS_TEST
2008  if ( fTessellatedSolid != nullptr )
2009  {
2011  }
2012 #endif
2013 
2014  // Approximation of Twisted Side
2015  // Construct extra Points, if Twisted Side
2016  //
2017  G4PolyhedronArbitrary* polyhedron;
2018  size_t nVertices, nFacets;
2019 
2020  G4int subdivisions=0;
2021  G4int i;
2022  if(fIsTwisted)
2023  {
2024  if ( GetVisSubdivisions()!= 0 )
2025  {
2026  subdivisions=GetVisSubdivisions();
2027  }
2028  else
2029  {
2030  // Estimation of Number of Subdivisions for smooth visualisation
2031  //
2032  G4double maxTwist=0.;
2033  for(i=0; i<4; ++i)
2034  {
2035  if(GetTwistAngle(i)>maxTwist) { maxTwist=GetTwistAngle(i); }
2036  }
2037 
2038  // Computes bounding vectors for the shape
2039  //
2040  G4double Dx,Dy;
2041  G4ThreeVector minVec = GetMinimumBBox();
2042  G4ThreeVector maxVec = GetMaximumBBox();
2043  Dx = 0.5*(maxVec.x()- minVec.y());
2044  Dy = 0.5*(maxVec.y()- minVec.y());
2045  if (Dy > Dx) { Dx=Dy; }
2046 
2047  subdivisions=8*G4int(maxTwist/(Dx*Dx*Dx)*fDz);
2048  if (subdivisions<4) { subdivisions=4; }
2049  if (subdivisions>30) { subdivisions=30; }
2050  }
2051  }
2052  G4int sub4=4*subdivisions;
2053  nVertices = 8+subdivisions*4;
2054  nFacets = 6+subdivisions*4;
2055  G4double cf=1./(subdivisions+1);
2056  polyhedron = new G4PolyhedronArbitrary (nVertices, nFacets);
2057 
2058  // Add Vertex
2059  //
2060  for (i=0; i<4; ++i)
2061  {
2062  polyhedron->AddVertex(G4ThreeVector(fVertices[i].x(),
2063  fVertices[i].y(),-fDz));
2064  }
2065  for( i=0; i<subdivisions; ++i)
2066  {
2067  for(G4int j=0;j<4;j++)
2068  {
2069  G4TwoVector u=fVertices[j]+cf*(i+1)*( fVertices[j+4]-fVertices[j]);
2070  polyhedron->AddVertex(G4ThreeVector(u.x(),u.y(),-fDz+cf*2*fDz*(i+1)));
2071  }
2072  }
2073  for (i=4; i<8; ++i)
2074  {
2075  polyhedron->AddVertex(G4ThreeVector(fVertices[i].x(),
2076  fVertices[i].y(),fDz));
2077  }
2078 
2079  // Add Facets
2080  //
2081  polyhedron->AddFacet(1,4,3,2); //Z-plane
2082  for (i=0; i<subdivisions+1; ++i)
2083  {
2084  G4int is=i*4;
2085  polyhedron->AddFacet(5+is,8+is,4+is,1+is);
2086  polyhedron->AddFacet(8+is,7+is,3+is,4+is);
2087  polyhedron->AddFacet(7+is,6+is,2+is,3+is);
2088  polyhedron->AddFacet(6+is,5+is,1+is,2+is);
2089  }
2090  polyhedron->AddFacet(5+sub4,6+sub4,7+sub4,8+sub4); //Z-plane
2091 
2092  polyhedron->SetReferences();
2093  polyhedron->InvertFacets();
2094 
2095  return (G4Polyhedron*) polyhedron;
2096 }
2097 
2098 // --------------------------------------------------------------------
2099 
2100 #endif