Geant4  10.02.p03
G4TwistedTubs.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 //
27 // $Id: G4TwistedTubs.cc 83572 2014-09-01 15:23:27Z gcosmo $
28 //
29 //
30 // --------------------------------------------------------------------
31 // GEANT 4 class source file
32 //
33 //
34 // G4TwistTubsSide.cc
35 //
36 // Author:
37 // 01-Aug-2002 - Kotoyo Hoshina (hoshina@hepburn.s.chiba-u.ac.jp)
38 //
39 // History:
40 // 13-Nov-2003 - O.Link (Oliver.Link@cern.ch), Integration in Geant4
41 // from original version in Jupiter-2.5.02 application.
42 // --------------------------------------------------------------------
43 
44 #include "G4TwistedTubs.hh"
45 
46 #include "G4PhysicalConstants.hh"
47 #include "G4SystemOfUnits.hh"
48 #include "G4GeometryTolerance.hh"
49 #include "G4VoxelLimits.hh"
50 #include "G4AffineTransform.hh"
51 #include "G4SolidExtentList.hh"
52 #include "G4ClippablePolygon.hh"
53 #include "G4VPVParameterisation.hh"
54 #include "meshdefs.hh"
55 
56 #include "G4VGraphicsScene.hh"
57 #include "G4Polyhedron.hh"
58 #include "G4VisExtent.hh"
59 
60 #include "Randomize.hh"
61 
62 #include "G4AutoLock.hh"
63 
64 namespace
65 {
66  G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
67 }
68 
69 //=====================================================================
70 //* constructors ------------------------------------------------------
71 
73  G4double twistedangle,
74  G4double endinnerrad,
75  G4double endouterrad,
76  G4double halfzlen,
77  G4double dphi)
78  : G4VSolid(pname), fDPhi(dphi),
79  fLowerEndcap(0), fUpperEndcap(0), fLatterTwisted(0),
80  fFormerTwisted(0), fInnerHype(0), fOuterHype(0),
81  fCubicVolume(0.), fSurfaceArea(0.),
82  fRebuildPolyhedron(false), fpPolyhedron(0)
83 {
84  if (endinnerrad < DBL_MIN)
85  {
86  G4Exception("G4TwistedTubs::G4TwistedTubs()", "GeomSolids0002",
87  FatalErrorInArgument, "Invalid end-inner-radius!");
88  }
89 
90  G4double sinhalftwist = std::sin(0.5 * twistedangle);
91 
92  G4double endinnerradX = endinnerrad * sinhalftwist;
93  G4double innerrad = std::sqrt( endinnerrad * endinnerrad
94  - endinnerradX * endinnerradX );
95 
96  G4double endouterradX = endouterrad * sinhalftwist;
97  G4double outerrad = std::sqrt( endouterrad * endouterrad
98  - endouterradX * endouterradX );
99 
100  // temporary treatment!!
101  SetFields(twistedangle, innerrad, outerrad, -halfzlen, halfzlen);
102  CreateSurfaces();
103 }
104 
106  G4double twistedangle,
107  G4double endinnerrad,
108  G4double endouterrad,
109  G4double halfzlen,
110  G4int nseg,
111  G4double totphi)
112  : G4VSolid(pname),
115  fCubicVolume(0.), fSurfaceArea(0.),
117 {
118 
119  if (!nseg)
120  {
121  std::ostringstream message;
122  message << "Invalid number of segments." << G4endl
123  << " nseg = " << nseg;
124  G4Exception("G4TwistedTubs::G4TwistedTubs()", "GeomSolids0002",
125  FatalErrorInArgument, message);
126  }
127  if (totphi == DBL_MIN || endinnerrad < DBL_MIN)
128  {
129  G4Exception("G4TwistedTubs::G4TwistedTubs()", "GeomSolids0002",
130  FatalErrorInArgument, "Invalid total-phi or end-inner-radius!");
131  }
132 
133  G4double sinhalftwist = std::sin(0.5 * twistedangle);
134 
135  G4double endinnerradX = endinnerrad * sinhalftwist;
136  G4double innerrad = std::sqrt( endinnerrad * endinnerrad
137  - endinnerradX * endinnerradX );
138 
139  G4double endouterradX = endouterrad * sinhalftwist;
140  G4double outerrad = std::sqrt( endouterrad * endouterrad
141  - endouterradX * endouterradX );
142 
143  // temporary treatment!!
144  fDPhi = totphi / nseg;
145  SetFields(twistedangle, innerrad, outerrad, -halfzlen, halfzlen);
146  CreateSurfaces();
147 }
148 
150  G4double twistedangle,
151  G4double innerrad,
152  G4double outerrad,
153  G4double negativeEndz,
154  G4double positiveEndz,
155  G4double dphi)
156  : G4VSolid(pname), fDPhi(dphi),
159  fCubicVolume(0.), fSurfaceArea(0.),
161 {
162  if (innerrad < DBL_MIN)
163  {
164  G4Exception("G4TwistedTubs::G4TwistedTubs()", "GeomSolids0002",
165  FatalErrorInArgument, "Invalid end-inner-radius!");
166  }
167 
168  SetFields(twistedangle, innerrad, outerrad, negativeEndz, positiveEndz);
169  CreateSurfaces();
170 }
171 
173  G4double twistedangle,
174  G4double innerrad,
175  G4double outerrad,
176  G4double negativeEndz,
177  G4double positiveEndz,
178  G4int nseg,
179  G4double totphi)
180  : G4VSolid(pname),
183  fCubicVolume(0.), fSurfaceArea(0.),
185 {
186  if (!nseg)
187  {
188  std::ostringstream message;
189  message << "Invalid number of segments." << G4endl
190  << " nseg = " << nseg;
191  G4Exception("G4TwistedTubs::G4TwistedTubs()", "GeomSolids0002",
192  FatalErrorInArgument, message);
193  }
194  if (totphi == DBL_MIN || innerrad < DBL_MIN)
195  {
196  G4Exception("G4TwistedTubs::G4TwistedTubs()", "GeomSolids0002",
197  FatalErrorInArgument, "Invalid total-phi or end-inner-radius!");
198  }
199 
200  fDPhi = totphi / nseg;
201  SetFields(twistedangle, innerrad, outerrad, negativeEndz, positiveEndz);
202  CreateSurfaces();
203 }
204 
205 //=====================================================================
206 //* Fake default constructor ------------------------------------------
207 
209  : G4VSolid(a), fPhiTwist(0.), fInnerRadius(0.), fOuterRadius(0.), fDPhi(0.),
214  fCubicVolume(0.), fSurfaceArea(0.),
216 {
217 }
218 
219 //=====================================================================
220 //* destructor --------------------------------------------------------
221 
223 {
224  if (fLowerEndcap) { delete fLowerEndcap; }
225  if (fUpperEndcap) { delete fUpperEndcap; }
226  if (fLatterTwisted) { delete fLatterTwisted; }
227  if (fFormerTwisted) { delete fFormerTwisted; }
228  if (fInnerHype) { delete fInnerHype; }
229  if (fOuterHype) { delete fOuterHype; }
230  if (fpPolyhedron) { delete fpPolyhedron; fpPolyhedron = 0; }
231 }
232 
233 //=====================================================================
234 //* Copy constructor --------------------------------------------------
235 
237  : G4VSolid(rhs), fPhiTwist(rhs.fPhiTwist),
246  fInnerHype(0), fOuterHype(0),
248  fRebuildPolyhedron(false), fpPolyhedron(0),
254 {
255  for (size_t i=0; i<2; ++i)
256  {
257  fEndZ[i] = rhs.fEndZ[i];
258  fEndInnerRadius[i] = rhs.fEndInnerRadius[i];
259  fEndOuterRadius[i] = rhs.fEndOuterRadius[i];
260  fEndPhi[i] = rhs.fEndPhi[i];
261  fEndZ2[i] = rhs.fEndZ2[i];
262  }
263  CreateSurfaces();
264 }
265 
266 
267 //=====================================================================
268 //* Assignment operator -----------------------------------------------
269 
271 {
272  // Check assignment to self
273  //
274  if (this == &rhs) { return *this; }
275 
276  // Copy base class data
277  //
278  G4VSolid::operator=(rhs);
279 
280  // Copy data
281  //
282  fPhiTwist= rhs.fPhiTwist;
298 
299  for (size_t i=0; i<2; ++i)
300  {
301  fEndZ[i] = rhs.fEndZ[i];
302  fEndInnerRadius[i] = rhs.fEndInnerRadius[i];
303  fEndOuterRadius[i] = rhs.fEndOuterRadius[i];
304  fEndPhi[i] = rhs.fEndPhi[i];
305  fEndZ2[i] = rhs.fEndZ2[i];
306  }
307 
308  CreateSurfaces();
309  fRebuildPolyhedron = false;
310  delete fpPolyhedron; fpPolyhedron = 0;
311 
312  return *this;
313 }
314 
315 //=====================================================================
316 //* ComputeDimensions -------------------------------------------------
317 
319  const G4int /* n */ ,
320  const G4VPhysicalVolume* /* pRep */ )
321 {
322  G4Exception("G4TwistedTubs::ComputeDimensions()",
323  "GeomSolids0001", FatalException,
324  "G4TwistedTubs does not support Parameterisation.");
325 }
326 
327 
328 //=====================================================================
329 //* CalculateExtent ---------------------------------------------------
330 
332  const G4VoxelLimits &voxelLimit,
333  const G4AffineTransform &transform,
334  G4double &min,
335  G4double &max ) const
336 {
337 
338  G4SolidExtentList extentList( axis, voxelLimit );
339  G4double maxEndOuterRad = (fEndOuterRadius[0] > fEndOuterRadius[1] ?
341  G4double maxEndInnerRad = (fEndInnerRadius[0] > fEndInnerRadius[1] ?
343  G4double maxphi = (std::fabs(fEndPhi[0]) > std::fabs(fEndPhi[1]) ?
344  std::fabs(fEndPhi[0]) : std::fabs(fEndPhi[1]));
345 
346  //
347  // Choose phi size of our segment(s) based on constants as
348  // defined in meshdefs.hh
349  //
350  // G4int numPhi = kMaxMeshSections;
351  G4double sigPhi = 2*maxphi + fDPhi;
352  G4double rFudge = 1.0/std::cos(0.5*sigPhi);
353  G4double fudgeEndOuterRad = rFudge * maxEndOuterRad;
354 
355  //
356  // We work around in phi building polygons along the way.
357  // As a reasonable compromise between accuracy and
358  // complexity (=cpu time), the following facets are chosen:
359  //
360  // 1. If fOuterRadius/maxEndOuterRad > 0.95, approximate
361  // the outer surface as a cylinder, and use one
362  // rectangular polygon (0-1) to build its mesh.
363  //
364  // Otherwise, use two trapazoidal polygons that
365  // meet at z = 0 (0-4-1)
366  //
367  // 2. If there is no inner surface, then use one
368  // polygon for each entire endcap. (0) and (1)
369  //
370  // Otherwise, use a trapazoidal polygon for each
371  // phi segment of each endcap. (0-2) and (1-3)
372  //
373  // 3. For the inner surface, if fInnerRadius/maxEndInnerRad > 0.95,
374  // approximate the inner surface as a cylinder of
375  // radius fInnerRadius and use one rectangular polygon
376  // to build each phi segment of its mesh. (2-3)
377  //
378  // Otherwise, use one rectangular polygon centered
379  // at z = 0 (5-6) and two connecting trapazoidal polygons
380  // for each phi segment (2-5) and (3-6).
381  //
382 
383  G4bool splitOuter = (fOuterRadius/maxEndOuterRad < 0.95);
384  G4bool splitInner = (fInnerRadius/maxEndInnerRad < 0.95);
385 
386  //
387  // Vertex assignments (v and w arrays)
388  // [0] and [1] are mandatory
389  // the rest are optional
390  //
391  // + -
392  // [0]------[4]------[1] <--- outer radius
393  // | |
394  // | |
395  // [2]---[5]---[6]---[3] <--- inner radius
396  //
397 
398  G4ClippablePolygon endPoly1, endPoly2;
399 
400  G4double phimax = maxphi + 0.5*fDPhi;
401  if ( phimax > pi/2) { phimax = pi-phimax; }
402  G4double phimin = - phimax;
403 
404  G4ThreeVector v0, v1, v2, v3, v4, v5, v6; // -ve phi verticies for polygon
405  G4ThreeVector w0, w1, w2, w3, w4, w5, w6; // +ve phi verticies for polygon
406 
407  //
408  // decide verticies of -ve phi boundary
409  //
410 
411  G4double cosPhi = std::cos(phimin);
412  G4double sinPhi = std::sin(phimin);
413 
414  // Outer hyperbolic surface
415 
416  v0 = transform.TransformPoint(
417  G4ThreeVector(fudgeEndOuterRad*cosPhi, fudgeEndOuterRad*sinPhi,
418  + fZHalfLength));
419  v1 = transform.TransformPoint(
420  G4ThreeVector(fudgeEndOuterRad*cosPhi, fudgeEndOuterRad*sinPhi,
421  - fZHalfLength));
422  if (splitOuter)
423  {
424  v4 = transform.TransformPoint(
425  G4ThreeVector(fudgeEndOuterRad*cosPhi, fudgeEndOuterRad*sinPhi, 0));
426  }
427 
428  // Inner hyperbolic surface
429 
430  G4double zInnerSplit = 0.;
431  if (splitInner)
432  {
433  v2 = transform.TransformPoint(
434  G4ThreeVector(maxEndInnerRad*cosPhi, maxEndInnerRad*sinPhi,
435  + fZHalfLength));
436  v3 = transform.TransformPoint(
437  G4ThreeVector(maxEndInnerRad*cosPhi, maxEndInnerRad*sinPhi,
438  - fZHalfLength));
439 
440  // Find intersection of tangential line of inner
441  // surface at z = fZHalfLength and line r=fInnerRadius.
443  G4double dz = maxEndInnerRad;
444  zInnerSplit = fZHalfLength + (fInnerRadius - maxEndInnerRad) * dz / dr;
445 
446  // Build associated vertices
447  v5 = transform.TransformPoint(
448  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
449  + zInnerSplit));
450  v6 = transform.TransformPoint(
451  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
452  - zInnerSplit));
453  }
454  else
455  {
456  v2 = transform.TransformPoint(
457  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
458  + fZHalfLength));
459  v3 = transform.TransformPoint(
460  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
461  - fZHalfLength));
462  }
463 
464  //
465  // decide vertices of +ve phi boundary
466  //
467 
468  cosPhi = std::cos(phimax);
469  sinPhi = std::sin(phimax);
470 
471  // Outer hyperbolic surface
472 
473  w0 = transform.TransformPoint(
474  G4ThreeVector(fudgeEndOuterRad*cosPhi, fudgeEndOuterRad*sinPhi,
475  + fZHalfLength));
476  w1 = transform.TransformPoint(
477  G4ThreeVector(fudgeEndOuterRad*cosPhi, fudgeEndOuterRad*sinPhi,
478  - fZHalfLength));
479  if (splitOuter)
480  {
481  G4double r = rFudge*fOuterRadius;
482 
483  w4 = transform.TransformPoint(G4ThreeVector( r*cosPhi, r*sinPhi, 0 ));
484 
485  AddPolyToExtent( v0, v4, w4, w0, voxelLimit, axis, extentList );
486  AddPolyToExtent( v4, v1, w1, w4, voxelLimit, axis, extentList );
487  }
488  else
489  {
490  AddPolyToExtent( v0, v1, w1, w0, voxelLimit, axis, extentList );
491  }
492 
493  // Inner hyperbolic surface
494 
495  if (splitInner)
496  {
497  w2 = transform.TransformPoint(
498  G4ThreeVector(maxEndInnerRad*cosPhi, maxEndInnerRad*sinPhi,
499  + fZHalfLength));
500  w3 = transform.TransformPoint(
501  G4ThreeVector(maxEndInnerRad*cosPhi, maxEndInnerRad*sinPhi,
502  - fZHalfLength));
503 
504  w5 = transform.TransformPoint(
505  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
506  + zInnerSplit));
507  w6 = transform.TransformPoint(
508  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
509  - zInnerSplit));
510 
511  AddPolyToExtent( v3, v6, w6, w3, voxelLimit, axis, extentList );
512  AddPolyToExtent( v6, v5, w5, w6, voxelLimit, axis, extentList );
513  AddPolyToExtent( v5, v2, w2, w5, voxelLimit, axis, extentList );
514 
515  }
516  else
517  {
518  w2 = transform.TransformPoint(
519  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
520  + fZHalfLength));
521  w3 = transform.TransformPoint(
522  G4ThreeVector(fInnerRadius*cosPhi, fInnerRadius*sinPhi,
523  - fZHalfLength));
524 
525  AddPolyToExtent( v3, v2, w2, w3, voxelLimit, axis, extentList );
526  }
527 
528  //
529  // Endplate segments
530  //
531  AddPolyToExtent( v1, v3, w3, w1, voxelLimit, axis, extentList );
532  AddPolyToExtent( v2, v0, w0, w2, voxelLimit, axis, extentList );
533 
534  //
535  // Return min/max value
536  //
537  return extentList.GetExtent( min, max );
538 }
539 
540 
541 //=====================================================================
542 //* AddPolyToExtent ---------------------------------------------------
543 
545  const G4ThreeVector &v1,
546  const G4ThreeVector &w1,
547  const G4ThreeVector &w0,
548  const G4VoxelLimits &voxelLimit,
549  const EAxis axis,
550  G4SolidExtentList &extentList )
551 {
552  // Utility function for CalculateExtent
553  //
554  G4ClippablePolygon phiPoly;
555 
556  phiPoly.AddVertexInOrder( v0 );
557  phiPoly.AddVertexInOrder( v1 );
558  phiPoly.AddVertexInOrder( w1 );
559  phiPoly.AddVertexInOrder( w0 );
560 
561  if (phiPoly.PartialClip( voxelLimit, axis ))
562  {
563  phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() );
564  extentList.AddSurface( phiPoly );
565  }
566 }
567 
568 
569 //=====================================================================
570 //* Inside ------------------------------------------------------------
571 
573 {
574 
575  const G4double halftol
577  // static G4int timerid = -1;
578  // G4Timer timer(timerid, "G4TwistedTubs", "Inside");
579  // timer.Start();
580 
581  G4ThreeVector *tmpp;
582  EInside *tmpinside;
583  if (fLastInside.p == p)
584  {
585  return fLastInside.inside;
586  }
587  else
588  {
589  tmpp = const_cast<G4ThreeVector*>(&(fLastInside.p));
590  tmpinside = const_cast<EInside*>(&(fLastInside.inside));
591  tmpp->set(p.x(), p.y(), p.z());
592  }
593 
594  EInside outerhypearea = ((G4TwistTubsHypeSide *)fOuterHype)->Inside(p);
595  G4double innerhyperho = ((G4TwistTubsHypeSide *)fInnerHype)->GetRhoAtPZ(p);
596  G4double distanceToOut = p.getRho() - innerhyperho; // +ve: inside
597 
598  if ((outerhypearea == kOutside) || (distanceToOut < -halftol))
599  {
600  *tmpinside = kOutside;
601  }
602  else if (outerhypearea == kSurface)
603  {
604  *tmpinside = kSurface;
605  }
606  else
607  {
608  if (distanceToOut <= halftol)
609  {
610  *tmpinside = kSurface;
611  }
612  else
613  {
614  *tmpinside = kInside;
615  }
616  }
617 
618  return fLastInside.inside;
619 }
620 
621 //=====================================================================
622 //* SurfaceNormal -----------------------------------------------------
623 
625 {
626  //
627  // return the normal unit vector to the Hyperbolical Surface at a point
628  // p on (or nearly on) the surface
629  //
630  // Which of the three or four surfaces are we closest to?
631  //
632 
633  if (fLastNormal.p == p)
634  {
635  return fLastNormal.vec;
636  }
637  G4ThreeVector *tmpp =
638  const_cast<G4ThreeVector*>(&(fLastNormal.p));
639  G4ThreeVector *tmpnormal =
640  const_cast<G4ThreeVector*>(&(fLastNormal.vec));
641  G4VTwistSurface **tmpsurface =
642  const_cast<G4VTwistSurface**>(fLastNormal.surface);
643  tmpp->set(p.x(), p.y(), p.z());
644 
645  G4double distance = kInfinity;
646 
647  G4VTwistSurface *surfaces[6];
648  surfaces[0] = fLatterTwisted;
649  surfaces[1] = fFormerTwisted;
650  surfaces[2] = fInnerHype;
651  surfaces[3] = fOuterHype;
652  surfaces[4] = fLowerEndcap;
653  surfaces[5] = fUpperEndcap;
654 
656  G4ThreeVector bestxx;
657  G4int i;
658  G4int besti = -1;
659  for (i=0; i< 6; i++)
660  {
661  G4double tmpdistance = surfaces[i]->DistanceTo(p, xx);
662  if (tmpdistance < distance)
663  {
664  distance = tmpdistance;
665  bestxx = xx;
666  besti = i;
667  }
668  }
669 
670  tmpsurface[0] = surfaces[besti];
671  *tmpnormal = tmpsurface[0]->GetNormal(bestxx, true);
672 
673  return fLastNormal.vec;
674 }
675 
676 //=====================================================================
677 //* DistanceToIn (p, v) -----------------------------------------------
678 
680  const G4ThreeVector& v ) const
681 {
682 
683  // DistanceToIn (p, v):
684  // Calculate distance to surface of shape from `outside'
685  // along with the v, allowing for tolerance.
686  // The function returns kInfinity if no intersection or
687  // just grazing within tolerance.
688 
689  //
690  // checking last value
691  //
692 
693  G4ThreeVector *tmpp;
694  G4ThreeVector *tmpv;
695  G4double *tmpdist;
696  if ((fLastDistanceToInWithV.p == p) && (fLastDistanceToInWithV.vec == v))
697  {
698  return fLastDistanceToIn.value;
699  }
700  else
701  {
702  tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToInWithV.p));
703  tmpv = const_cast<G4ThreeVector*>(&(fLastDistanceToInWithV.vec));
704  tmpdist = const_cast<G4double*>(&(fLastDistanceToInWithV.value));
705  tmpp->set(p.x(), p.y(), p.z());
706  tmpv->set(v.x(), v.y(), v.z());
707  }
708 
709  //
710  // Calculate DistanceToIn(p,v)
711  //
712 
713  EInside currentside = Inside(p);
714 
715  if (currentside == kInside)
716  {
717  }
718  else
719  {
720  if (currentside == kSurface)
721  {
722  // particle is just on a boundary.
723  // If the particle is entering to the volume, return 0.
724  //
726  if (normal*v < 0)
727  {
728  *tmpdist = 0;
730  }
731  }
732  }
733 
734  // now, we can take smallest positive distance.
735 
736  // Initialize
737  //
738  G4double distance = kInfinity;
739 
740  // find intersections and choose nearest one.
741  //
742  G4VTwistSurface *surfaces[6];
743  surfaces[0] = fLowerEndcap;
744  surfaces[1] = fUpperEndcap;
745  surfaces[2] = fLatterTwisted;
746  surfaces[3] = fFormerTwisted;
747  surfaces[4] = fInnerHype;
748  surfaces[5] = fOuterHype;
749 
751  G4ThreeVector bestxx;
752  G4int i;
753  for (i=0; i< 6; i++)
754  {
755  G4double tmpdistance = surfaces[i]->DistanceToIn(p, v, xx);
756  if (tmpdistance < distance)
757  {
758  distance = tmpdistance;
759  bestxx = xx;
760  }
761  }
762  *tmpdist = distance;
763 
765 }
766 
767 //=====================================================================
768 //* DistanceToIn (p) --------------------------------------------------
769 
771 {
772  // DistanceToIn(p):
773  // Calculate distance to surface of shape from `outside',
774  // allowing for tolerance
775 
776  //
777  // checking last value
778  //
779 
780  G4ThreeVector *tmpp;
781  G4double *tmpdist;
782  if (fLastDistanceToIn.p == p)
783  {
784  return fLastDistanceToIn.value;
785  }
786  else
787  {
788  tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToIn.p));
789  tmpdist = const_cast<G4double*>(&(fLastDistanceToIn.value));
790  tmpp->set(p.x(), p.y(), p.z());
791  }
792 
793  //
794  // Calculate DistanceToIn(p)
795  //
796 
797  EInside currentside = Inside(p);
798 
799  switch (currentside)
800  {
801  case (kInside) :
802  {}
803  case (kSurface) :
804  {
805  *tmpdist = 0.;
806  return fLastDistanceToIn.value;
807  }
808  case (kOutside) :
809  {
810  // Initialize
811  G4double distance = kInfinity;
812 
813  // find intersections and choose nearest one.
814  G4VTwistSurface *surfaces[6];
815  surfaces[0] = fLowerEndcap;
816  surfaces[1] = fUpperEndcap;
817  surfaces[2] = fLatterTwisted;
818  surfaces[3] = fFormerTwisted;
819  surfaces[4] = fInnerHype;
820  surfaces[5] = fOuterHype;
821 
822  G4int i;
824  G4ThreeVector bestxx;
825  for (i=0; i< 6; i++)
826  {
827  G4double tmpdistance = surfaces[i]->DistanceTo(p, xx);
828  if (tmpdistance < distance)
829  {
830  distance = tmpdistance;
831  bestxx = xx;
832  }
833  }
834  *tmpdist = distance;
835  return fLastDistanceToIn.value;
836  }
837  default :
838  {
839  G4Exception("G4TwistedTubs::DistanceToIn(p)", "GeomSolids0003",
840  FatalException, "Unknown point location!");
841  }
842  } // switch end
843 
844  return kInfinity;
845 }
846 
847 //=====================================================================
848 //* DistanceToOut (p, v) ----------------------------------------------
849 
851  const G4ThreeVector& v,
852  const G4bool calcNorm,
853  G4bool *validNorm,
854  G4ThreeVector *norm ) const
855 {
856  // DistanceToOut (p, v):
857  // Calculate distance to surface of shape from `inside'
858  // along with the v, allowing for tolerance.
859  // The function returns kInfinity if no intersection or
860  // just grazing within tolerance.
861 
862  //
863  // checking last value
864  //
865 
866  G4ThreeVector *tmpp;
867  G4ThreeVector *tmpv;
868  G4double *tmpdist;
870  {
872  }
873  else
874  {
875  tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToOutWithV.p));
876  tmpv = const_cast<G4ThreeVector*>(&(fLastDistanceToOutWithV.vec));
877  tmpdist = const_cast<G4double*>(&(fLastDistanceToOutWithV.value));
878  tmpp->set(p.x(), p.y(), p.z());
879  tmpv->set(v.x(), v.y(), v.z());
880  }
881 
882  //
883  // Calculate DistanceToOut(p,v)
884  //
885 
886  EInside currentside = Inside(p);
887 
888  if (currentside == kOutside)
889  {
890  }
891  else
892  {
893  if (currentside == kSurface)
894  {
895  // particle is just on a boundary.
896  // If the particle is exiting from the volume, return 0.
897  //
899  G4VTwistSurface *blockedsurface = fLastNormal.surface[0];
900  if (normal*v > 0)
901  {
902  if (calcNorm)
903  {
904  *norm = (blockedsurface->GetNormal(p, true));
905  *validNorm = blockedsurface->IsValidNorm();
906  }
907  *tmpdist = 0.;
909  }
910  }
911  }
912 
913  // now, we can take smallest positive distance.
914 
915  // Initialize
916  //
917  G4double distance = kInfinity;
918 
919  // find intersections and choose nearest one.
920  //
921  G4VTwistSurface *surfaces[6];
922  surfaces[0] = fLatterTwisted;
923  surfaces[1] = fFormerTwisted;
924  surfaces[2] = fInnerHype;
925  surfaces[3] = fOuterHype;
926  surfaces[4] = fLowerEndcap;
927  surfaces[5] = fUpperEndcap;
928 
929  G4int i;
930  G4int besti = -1;
932  G4ThreeVector bestxx;
933  for (i=0; i< 6; i++)
934  {
935  G4double tmpdistance = surfaces[i]->DistanceToOut(p, v, xx);
936  if (tmpdistance < distance)
937  {
938  distance = tmpdistance;
939  bestxx = xx;
940  besti = i;
941  }
942  }
943 
944  if (calcNorm)
945  {
946  if (besti != -1)
947  {
948  *norm = (surfaces[besti]->GetNormal(p, true));
949  *validNorm = surfaces[besti]->IsValidNorm();
950  }
951  }
952 
953  *tmpdist = distance;
954 
956 }
957 
958 
959 //=====================================================================
960 //* DistanceToOut (p) ----------------------------------------------
961 
963 {
964  // DistanceToOut(p):
965  // Calculate distance to surface of shape from `inside',
966  // allowing for tolerance
967 
968  //
969  // checking last value
970  //
971 
972  G4ThreeVector *tmpp;
973  G4double *tmpdist;
974  if (fLastDistanceToOut.p == p)
975  {
976  return fLastDistanceToOut.value;
977  }
978  else
979  {
980  tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToOut.p));
981  tmpdist = const_cast<G4double*>(&(fLastDistanceToOut.value));
982  tmpp->set(p.x(), p.y(), p.z());
983  }
984 
985  //
986  // Calculate DistanceToOut(p)
987  //
988 
989  EInside currentside = Inside(p);
990 
991  switch (currentside)
992  {
993  case (kOutside) :
994  {
995  }
996  case (kSurface) :
997  {
998  *tmpdist = 0.;
999  return fLastDistanceToOut.value;
1000  }
1001  case (kInside) :
1002  {
1003  // Initialize
1004  G4double distance = kInfinity;
1005 
1006  // find intersections and choose nearest one.
1007  G4VTwistSurface *surfaces[6];
1008  surfaces[0] = fLatterTwisted;
1009  surfaces[1] = fFormerTwisted;
1010  surfaces[2] = fInnerHype;
1011  surfaces[3] = fOuterHype;
1012  surfaces[4] = fLowerEndcap;
1013  surfaces[5] = fUpperEndcap;
1014 
1015  G4int i;
1016  G4ThreeVector xx;
1017  G4ThreeVector bestxx;
1018  for (i=0; i< 6; i++)
1019  {
1020  G4double tmpdistance = surfaces[i]->DistanceTo(p, xx);
1021  if (tmpdistance < distance)
1022  {
1023  distance = tmpdistance;
1024  bestxx = xx;
1025  }
1026  }
1027  *tmpdist = distance;
1028 
1029  return fLastDistanceToOut.value;
1030  }
1031  default :
1032  {
1033  G4Exception("G4TwistedTubs::DistanceToOut(p)", "GeomSolids0003",
1034  FatalException, "Unknown point location!");
1035  }
1036  } // switch end
1037 
1038  return 0;
1039 }
1040 
1041 //=====================================================================
1042 //* StreamInfo --------------------------------------------------------
1043 
1044 std::ostream& G4TwistedTubs::StreamInfo(std::ostream& os) const
1045 {
1046  //
1047  // Stream object contents to an output stream
1048  //
1049  G4int oldprc = os.precision(16);
1050  os << "-----------------------------------------------------------\n"
1051  << " *** Dump for solid - " << GetName() << " ***\n"
1052  << " ===================================================\n"
1053  << " Solid type: G4TwistedTubs\n"
1054  << " Parameters: \n"
1055  << " -ve end Z : " << fEndZ[0]/mm << " mm \n"
1056  << " +ve end Z : " << fEndZ[1]/mm << " mm \n"
1057  << " inner end radius(-ve z): " << fEndInnerRadius[0]/mm << " mm \n"
1058  << " inner end radius(+ve z): " << fEndInnerRadius[1]/mm << " mm \n"
1059  << " outer end radius(-ve z): " << fEndOuterRadius[0]/mm << " mm \n"
1060  << " outer end radius(+ve z): " << fEndOuterRadius[1]/mm << " mm \n"
1061  << " inner radius (z=0) : " << fInnerRadius/mm << " mm \n"
1062  << " outer radius (z=0) : " << fOuterRadius/mm << " mm \n"
1063  << " twisted angle : " << fPhiTwist/degree << " degrees \n"
1064  << " inner stereo angle : " << fInnerStereo/degree << " degrees \n"
1065  << " outer stereo angle : " << fOuterStereo/degree << " degrees \n"
1066  << " phi-width of a piece : " << fDPhi/degree << " degrees \n"
1067  << "-----------------------------------------------------------\n";
1068  os.precision(oldprc);
1069 
1070  return os;
1071 }
1072 
1073 
1074 //=====================================================================
1075 //* DiscribeYourselfTo ------------------------------------------------
1076 
1078 {
1079  scene.AddSolid (*this);
1080 }
1081 
1082 //=====================================================================
1083 //* GetExtent ---------------------------------------------------------
1084 
1086 {
1087  // Define the sides of the box into which the G4Tubs instance would fit.
1088 
1089  G4double maxEndOuterRad = (fEndOuterRadius[0] > fEndOuterRadius[1] ? 0 : 1);
1090  return G4VisExtent( -maxEndOuterRad, maxEndOuterRad,
1091  -maxEndOuterRad, maxEndOuterRad,
1093 }
1094 
1095 //=====================================================================
1096 //* CreatePolyhedron --------------------------------------------------
1097 
1099 {
1100  // number of meshes
1101  //
1103  const G4int k =
1105  const G4int n =
1107 
1108  const G4int nnodes = 4*(k-1)*(n-2) + 2*k*k ;
1109  const G4int nfaces = 4*(k-1)*(n-1) + 2*(k-1)*(k-1) ;
1110 
1111  G4Polyhedron *ph=new G4Polyhedron;
1112  typedef G4double G4double3[3];
1113  typedef G4int G4int4[4];
1114  G4double3* xyz = new G4double3[nnodes]; // number of nodes
1115  G4int4* faces = new G4int4[nfaces] ; // number of faces
1116  fLowerEndcap->GetFacets(k,k,xyz,faces,0) ;
1117  fUpperEndcap->GetFacets(k,k,xyz,faces,1) ;
1118  fInnerHype->GetFacets(k,n,xyz,faces,2) ;
1119  fFormerTwisted->GetFacets(k,n,xyz,faces,3) ;
1120  fOuterHype->GetFacets(k,n,xyz,faces,4) ;
1121  fLatterTwisted->GetFacets(k,n,xyz,faces,5) ;
1122 
1123  ph->createPolyhedron(nnodes,nfaces,xyz,faces);
1124 
1125  delete[] xyz;
1126  delete[] faces;
1127 
1128  return ph;
1129 }
1130 
1131 //=====================================================================
1132 //* GetPolyhedron -----------------------------------------------------
1133 
1135 {
1136  if (!fpPolyhedron ||
1140  {
1141  G4AutoLock l(&polyhedronMutex);
1142  delete fpPolyhedron;
1144  fRebuildPolyhedron = false;
1145  l.unlock();
1146  }
1147  return fpPolyhedron;
1148 }
1149 
1150 //=====================================================================
1151 //* CreateSurfaces ----------------------------------------------------
1152 
1154 {
1155  // create 6 surfaces of TwistedTub
1156 
1157  G4ThreeVector x0(0, 0, fEndZ[0]);
1158  G4ThreeVector n (0, 0, -1);
1159 
1160  fLowerEndcap = new G4TwistTubsFlatSide("LowerEndcap",
1162  fDPhi, fEndPhi, fEndZ, -1) ;
1163 
1164  fUpperEndcap = new G4TwistTubsFlatSide("UpperEndcap",
1166  fDPhi, fEndPhi, fEndZ, 1) ;
1167 
1168  G4RotationMatrix rotHalfDPhi;
1169  rotHalfDPhi.rotateZ(0.5*fDPhi);
1170 
1171  fLatterTwisted = new G4TwistTubsSide("LatterTwisted",
1173  fDPhi, fEndPhi, fEndZ,
1175  1 ) ;
1176  fFormerTwisted = new G4TwistTubsSide("FormerTwisted",
1178  fDPhi, fEndPhi, fEndZ,
1180  -1 ) ;
1181 
1182  fInnerHype = new G4TwistTubsHypeSide("InnerHype",
1184  fDPhi, fEndPhi, fEndZ,
1187  fOuterHype = new G4TwistTubsHypeSide("OuterHype",
1189  fDPhi, fEndPhi, fEndZ,
1192 
1193 
1194  // set neighbour surfaces
1195  //
1208 }
1209 
1210 
1211 //=====================================================================
1212 //* GetEntityType -----------------------------------------------------
1213 
1215 {
1216  return G4String("G4TwistedTubs");
1217 }
1218 
1219 //=====================================================================
1220 //* Clone -------------------------------------------------------------
1221 
1223 {
1224  return new G4TwistedTubs(*this);
1225 }
1226 
1227 //=====================================================================
1228 //* GetCubicVolume ----------------------------------------------------
1229 
1231 {
1232  if(fCubicVolume != 0.) {;}
1235  return fCubicVolume;
1236 }
1237 
1238 //=====================================================================
1239 //* GetSurfaceArea ----------------------------------------------------
1240 
1242 {
1243  if(fSurfaceArea != 0.) {;}
1245  return fSurfaceArea;
1246 }
1247 
1248 //=====================================================================
1249 //* GetPointOnSurface -------------------------------------------------
1250 
1252 {
1253 
1255  G4double phi , phimin, phimax ;
1256  G4double x , xmin, xmax ;
1257  G4double r , rmin, rmax ;
1258 
1265 
1266  G4double chose = G4RandFlat::shoot(0.,a1 + a2 + a3 + a4 + a5 + a6) ;
1267 
1268  if(chose < a1)
1269  {
1270 
1271  phimin = fOuterHype->GetBoundaryMin(z) ;
1272  phimax = fOuterHype->GetBoundaryMax(z) ;
1273  phi = G4RandFlat::shoot(phimin,phimax) ;
1274 
1275  return fOuterHype->SurfacePoint(phi,z,true) ;
1276 
1277  }
1278  else if ( (chose >= a1) && (chose < a1 + a2 ) )
1279  {
1280 
1281  phimin = fInnerHype->GetBoundaryMin(z) ;
1282  phimax = fInnerHype->GetBoundaryMax(z) ;
1283  phi = G4RandFlat::shoot(phimin,phimax) ;
1284 
1285  return fInnerHype->SurfacePoint(phi,z,true) ;
1286 
1287  }
1288  else if ( (chose >= a1 + a2 ) && (chose < a1 + a2 + a3 ) )
1289  {
1290 
1291  xmin = fLatterTwisted->GetBoundaryMin(z) ;
1292  xmax = fLatterTwisted->GetBoundaryMax(z) ;
1293  x = G4RandFlat::shoot(xmin,xmax) ;
1294 
1295  return fLatterTwisted->SurfacePoint(x,z,true) ;
1296 
1297  }
1298  else if ( (chose >= a1 + a2 + a3 ) && (chose < a1 + a2 + a3 + a4 ) )
1299  {
1300 
1301  xmin = fFormerTwisted->GetBoundaryMin(z) ;
1302  xmax = fFormerTwisted->GetBoundaryMax(z) ;
1303  x = G4RandFlat::shoot(xmin,xmax) ;
1304 
1305  return fFormerTwisted->SurfacePoint(x,z,true) ;
1306  }
1307  else if( (chose >= a1 + a2 + a3 + a4 )&&(chose < a1 + a2 + a3 + a4 + a5 ) )
1308  {
1309  rmin = GetEndInnerRadius(0) ;
1310  rmax = GetEndOuterRadius(0) ;
1311  r = std::sqrt(G4RandFlat::shoot()*(sqr(rmax)-sqr(rmin))+sqr(rmin));
1312 
1313  phimin = fLowerEndcap->GetBoundaryMin(r) ;
1314  phimax = fLowerEndcap->GetBoundaryMax(r) ;
1315  phi = G4RandFlat::shoot(phimin,phimax) ;
1316 
1317  return fLowerEndcap->SurfacePoint(phi,r,true) ;
1318  }
1319  else
1320  {
1321  rmin = GetEndInnerRadius(1) ;
1322  rmax = GetEndOuterRadius(1) ;
1323  r = rmin + (rmax-rmin)*std::sqrt(G4RandFlat::shoot());
1324 
1325  phimin = fUpperEndcap->GetBoundaryMin(r) ;
1326  phimax = fUpperEndcap->GetBoundaryMax(r) ;
1327  phi = G4RandFlat::shoot(phimin,phimax) ;
1328 
1329  return fUpperEndcap->SurfacePoint(phi,r,true) ;
1330  }
1331 }
G4double fZHalfLength
void set(double x, double y, double z)
ThreeVector shoot(const G4int Ap, const G4int Af)
std::ostream & StreamInfo(std::ostream &os) const
static const G4double kInfinity
Definition: geomdefs.hh:42
G4double fPhiTwist
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
CLHEP::Hep3Vector G4ThreeVector
virtual G4ThreeVector GetNormal(const G4ThreeVector &xx, G4bool isGlobal)=0
G4ThreeVector GetPointOnSurface() const
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcnorm=G4bool(false), G4bool *validnorm=0, G4ThreeVector *n=0) const
G4VisExtent GetExtent() const
G4int createPolyhedron(G4int Nnodes, G4int Nfaces, const G4double xyz[][3], const G4int faces[][4])
static void AddPolyToExtent(const G4ThreeVector &v0, const G4ThreeVector &v1, const G4ThreeVector &w1, const G4ThreeVector &w0, const G4VoxelLimits &voxellimit, const EAxis axis, G4SolidExtentList &extentlist)
static const G4double a1
G4ThreeVector TransformPoint(const G4ThreeVector &vec) const
Float_t norm
G4VTwistSurface * fFormerTwisted
Double_t xx
void SetNormal(const G4ThreeVector &newNormal)
G4double fEndOuterRadius[2]
LastValueWithDoubleVector fLastDistanceToInWithV
static const G4double a4
virtual G4bool PartialClip(const G4VoxelLimits &voxelLimit, const EAxis IgnoreMe)
virtual void AddVertexInOrder(const G4ThreeVector vertex)
LastValue fLastDistanceToIn
virtual void AddSolid(const G4Box &)=0
int G4int
Definition: G4Types.hh:78
void ComputeDimensions(G4VPVParameterisation *, const G4int, const G4VPhysicalVolume *)
G4double fEndInnerRadius[2]
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:175
G4String GetName() const
G4VTwistSurface * fUpperEndcap
G4bool GetExtent(G4double &min, G4double &max) const
EInside Inside(const G4ThreeVector &p) const
G4double fEndPhi[2]
virtual G4double DistanceToIn(const G4ThreeVector &gp, const G4ThreeVector &gv, G4ThreeVector &gxxbest)
G4bool CalculateExtent(const EAxis paxis, const G4VoxelLimits &pvoxellimit, const G4AffineTransform &ptransform, G4double &pmin, G4double &pmax) const
G4double fInnerRadius
G4double fEndZ[2]
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
G4VTwistSurface * fOuterHype
G4Polyhedron * GetPolyhedron() const
G4double fSurfaceArea
virtual G4double GetSurfaceArea()=0
Char_t n[5]
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4bool IsValidNorm() const
G4double fInnerRadius2
G4double GetRadialTolerance() const
G4double fOuterRadius2
void SetNeighbours(G4VTwistSurface *axis0min, G4VTwistSurface *axis1min, G4VTwistSurface *axis0max, G4VTwistSurface *axis1max)
virtual G4double DistanceTo(const G4ThreeVector &gp, G4ThreeVector &gxx)
virtual G4double DistanceToOut(const G4ThreeVector &gp, const G4ThreeVector &gv, G4ThreeVector &gxxbest)
virtual G4ThreeVector SurfacePoint(G4double, G4double, G4bool isGlobal=false)=0
bool G4bool
Definition: G4Types.hh:79
G4VTwistSurface ** surface
static const double twopi
Definition: G4SIunits.hh:75
void SetFields(G4double phitwist, G4double innerrad, G4double outerrad, G4double negativeEndz, G4double positiveEndz)
G4double GetEndInnerRadius() const
G4bool fRebuildPolyhedron
void AddSurface(const G4ClippablePolygon &surface)
G4VSolid * Clone() const
LastValueWithDoubleVector fLastDistanceToOutWithV
G4double fEndZ2[2]
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
virtual G4double GetBoundaryMax(G4double)=0
string pname
Definition: eplot.py:33
static const G4double a3
G4double GetSurfaceArea()
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
double x() const
LastValue fLastDistanceToOut
virtual void GetFacets(G4int m, G4int n, G4double xyz[][3], G4int faces[][4], G4int iside)=0
virtual G4double GetBoundaryMin(G4double)=0
LastState fLastInside
G4int G4Mutex
Definition: G4Threading.hh:173
G4VTwistSurface * fLatterTwisted
G4double fOuterRadius
static const double pi
Definition: G4SIunits.hh:74
virtual ~G4TwistedTubs()
double y() const
static G4int GetNumberOfRotationSteps()
G4Polyhedron * CreatePolyhedron() const
EInside
Definition: geomdefs.hh:58
G4GeometryType GetEntityType() const
G4VTwistSurface * fInnerHype
EAxis
Definition: geomdefs.hh:54
double z() const
#define DBL_MIN
Definition: templates.hh:75
void DescribeYourselfTo(G4VGraphicsScene &scene) const
G4double fTanOuterStereo
static const double degree
Definition: G4SIunits.hh:143
HepRotation & rotateZ(double delta)
Definition: Rotation.cc:92
G4double fTanInnerStereo2
G4Polyhedron * fpPolyhedron
G4TwistedTubs(const G4String &pname, G4double twistedangle, G4double endinnerrad, G4double endouterrad, G4double halfzlen, G4double dphi)
#define G4endl
Definition: G4ios.hh:61
G4VSolid & operator=(const G4VSolid &rhs)
Definition: G4VSolid.cc:110
LastVector fLastNormal
G4double fTanOuterStereo2
G4double fTanInnerStereo
T sqr(const T &x)
Definition: templates.hh:145
double getRho() const
static const G4double a5
double G4double
Definition: G4Types.hh:76
G4double fInnerStereo
G4double GetCubicVolume()
G4double fCubicVolume
G4double GetEndOuterRadius() const
G4VTwistSurface * fLowerEndcap
static const double mm
Definition: G4SIunits.hh:114
virtual G4double GetSurfaceArea()
Definition: G4VSolid.cc:250
G4double fOuterStereo
static const G4double a2
static G4GeometryTolerance * GetInstance()
G4TwistedTubs & operator=(const G4TwistedTubs &rhs)