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