Geant4  10.00.p02
G4EllipticalCone.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 // $Id: G4EllipticalCone.cc 81641 2014-06-04 09:11:38Z gcosmo $
27 //
28 // Implementation of G4EllipticalCone class
29 //
30 // This code implements an Elliptical Cone given explicitly by the
31 // equation:
32 // x^2/a^2 + y^2/b^2 = (z-h)^2
33 // and specified by the parameters (a,b,h) and a cut parallel to the
34 // xy plane above z = 0.
35 //
36 // Author: Dionysios Anninos
37 //
38 // --------------------------------------------------------------------
39 
40 #include "globals.hh"
41 
42 #include "G4EllipticalCone.hh"
43 
44 #include "G4ClippablePolygon.hh"
45 #include "G4SolidExtentList.hh"
46 #include "G4VoxelLimits.hh"
47 #include "G4AffineTransform.hh"
48 #include "G4GeometryTolerance.hh"
49 
50 #include "meshdefs.hh"
51 
52 #include "Randomize.hh"
53 
54 #include "G4VGraphicsScene.hh"
55 #include "G4VisExtent.hh"
56 
57 //#define G4SPECSDEBUG 1
58 
59 using namespace CLHEP;
60 
62 //
63 // Constructor - check parameters
64 //
66  G4double pxSemiAxis,
67  G4double pySemiAxis,
68  G4double pzMax,
69  G4double pzTopCut)
70  : G4VSolid(pName), fpPolyhedron(0), fCubicVolume(0.), fSurfaceArea(0.),
71  zTopCut(0.)
72 {
73 
75 
78 
79  // Check Semi-Axis & Z-cut
80  //
81  if ( (pxSemiAxis <= 0.) || (pySemiAxis <= 0.) || (pzMax <= 0.) )
82  {
83  std::ostringstream message;
84  message << "Invalid semi-axis or height - " << GetName();
85  G4Exception("G4EllipticalCone::G4EllipticalCone()", "GeomSolids0002",
86  FatalErrorInArgument, message);
87  }
88  if ( pzTopCut <= 0 )
89  {
90  std::ostringstream message;
91  message << "Invalid z-coordinate for cutting plane - " << GetName();
92  G4Exception("G4EllipticalCone::G4EllipticalCone()", "InvalidSetup",
93  FatalErrorInArgument, message);
94  }
95 
96  SetSemiAxis( pxSemiAxis, pySemiAxis, pzMax );
97  SetZCut(pzTopCut);
98 }
99 
101 //
102 // Fake default constructor - sets only member data and allocates memory
103 // for usage restricted to object persistency.
104 //
106  : G4VSolid(a), fpPolyhedron(0), kRadTolerance(0.),
107  halfRadTol(0.), halfCarTol(0.), fCubicVolume(0.),
108  fSurfaceArea(0.), xSemiAxis(0.), ySemiAxis(0.), zheight(0.),
109  semiAxisMax(0.), zTopCut(0.)
110 {
111 }
112 
114 //
115 // Destructor
116 //
118 {
119 }
120 
122 //
123 // Copy constructor
124 //
126  : G4VSolid(rhs),
127  fpPolyhedron(0), kRadTolerance(rhs.kRadTolerance),
128  halfRadTol(rhs.halfRadTol), halfCarTol(rhs.halfCarTol),
129  fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
130  xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis), zheight(rhs.zheight),
131  semiAxisMax(rhs.semiAxisMax), zTopCut(rhs.zTopCut)
132 {
134 }
135 
137 //
138 // Assignment operator
139 //
141 {
142  // Check assignment to self
143  //
144  if (this == &rhs) { return *this; }
145 
146  // Copy base class data
147  //
148  G4VSolid::operator=(rhs);
149 
150  // Copy data
151  //
155  xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis;
158 
159  return *this;
160 }
161 
163 //
164 // Calculate extent under transform and specified limit
165 //
166 G4bool
168  const G4VoxelLimits &voxelLimit,
169  const G4AffineTransform &transform,
170  G4double &min, G4double &max ) const
171 {
172  G4SolidExtentList extentList( axis, voxelLimit );
173 
174  //
175  // We are going to divide up our elliptical face into small pieces
176  //
177 
178  //
179  // Choose phi size of our segment(s) based on constants as
180  // defined in meshdefs.hh
181  //
182  G4int numPhi = kMaxMeshSections;
183  G4double sigPhi = twopi/numPhi;
184 
185  //
186  // We have to be careful to keep our segments completely outside
187  // of the elliptical surface. To do so we imagine we have
188  // a simple (unit radius) circular cross section (as in G4Tubs)
189  // and then "stretch" the dimensions as necessary to fit the ellipse.
190  //
191  G4double rFudge = 1.0/std::cos(0.5*sigPhi);
192  G4double dxFudgeBot = xSemiAxis*2.*zheight*rFudge,
193  dyFudgeBot = ySemiAxis*2.*zheight*rFudge;
194  G4double dxFudgeTop = xSemiAxis*(zheight-zTopCut)*rFudge,
195  dyFudgeTop = ySemiAxis*(zheight-zTopCut)*rFudge;
196 
197  //
198  // As we work around the elliptical surface, we build
199  // a "phi" segment on the way, and keep track of two
200  // additional polygons for the two ends.
201  //
202  G4ClippablePolygon endPoly1, endPoly2, phiPoly;
203 
204  G4double phi = 0,
205  cosPhi = std::cos(phi),
206  sinPhi = std::sin(phi);
207  G4ThreeVector v0( dxFudgeTop*cosPhi, dyFudgeTop*sinPhi, +zTopCut ),
208  v1( dxFudgeBot*cosPhi, dyFudgeBot*sinPhi, -zTopCut ),
209  w0, w1;
210  transform.ApplyPointTransform( v0 );
211  transform.ApplyPointTransform( v1 );
212  do
213  {
214  phi += sigPhi;
215  if (numPhi == 1) phi = 0; // Try to avoid roundoff
216  cosPhi = std::cos(phi),
217  sinPhi = std::sin(phi);
218 
219  w0 = G4ThreeVector( dxFudgeTop*cosPhi, dyFudgeTop*sinPhi, +zTopCut );
220  w1 = G4ThreeVector( dxFudgeBot*cosPhi, dyFudgeBot*sinPhi, -zTopCut );
221  transform.ApplyPointTransform( w0 );
222  transform.ApplyPointTransform( w1 );
223 
224  //
225  // Add a point to our z ends
226  //
227  endPoly1.AddVertexInOrder( v0 );
228  endPoly2.AddVertexInOrder( v1 );
229 
230  //
231  // Build phi polygon
232  //
233  phiPoly.ClearAllVertices();
234 
235  phiPoly.AddVertexInOrder( v0 );
236  phiPoly.AddVertexInOrder( v1 );
237  phiPoly.AddVertexInOrder( w1 );
238  phiPoly.AddVertexInOrder( w0 );
239 
240  if (phiPoly.PartialClip( voxelLimit, axis ))
241  {
242  //
243  // Get unit normal
244  //
245  phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() );
246 
247  extentList.AddSurface( phiPoly );
248  }
249 
250  //
251  // Next vertex
252  //
253  v0 = w0;
254  v1 = w1;
255  } while( --numPhi > 0 );
256 
257  //
258  // Process the end pieces
259  //
260  if (endPoly1.PartialClip( voxelLimit, axis ))
261  {
262  static const G4ThreeVector normal(0,0,+1);
263  endPoly1.SetNormal( transform.TransformAxis(normal) );
264  extentList.AddSurface( endPoly1 );
265  }
266 
267  if (endPoly2.PartialClip( voxelLimit, axis ))
268  {
269  static const G4ThreeVector normal(0,0,-1);
270  endPoly2.SetNormal( transform.TransformAxis(normal) );
271  extentList.AddSurface( endPoly2 );
272  }
273 
274  //
275  // Return min/max value
276  //
277  return extentList.GetExtent( min, max );
278 }
279 
281 //
282 // Return whether point inside/outside/on surface
283 // Split into radius, phi, theta checks
284 // Each check modifies `in', or returns as approprate
285 //
287 {
288  G4double rad2oo, // outside surface outer tolerance
289  rad2oi; // outside surface inner tolerance
290 
291  EInside in;
292 
293  // check this side of z cut first, because that's fast
294  //
295 
296  if ( (p.z() < -zTopCut - halfCarTol)
297  || (p.z() > zTopCut + halfCarTol ) )
298  {
299  return in = kOutside;
300  }
301 
302  rad2oo= sqr(p.x()/( xSemiAxis + halfRadTol ))
303  + sqr(p.y()/( ySemiAxis + halfRadTol ));
304 
305  if ( rad2oo > sqr( zheight-p.z() ) )
306  {
307  return in = kOutside;
308  }
309 
310  // rad2oi= sqr( p.x()*(1.0 + 0.5*kRadTolerance/(xSemiAxis*xSemiAxis)) )
311  // + sqr( p.y()*(1.0 + 0.5*kRadTolerance/(ySemiAxis*ySemiAxis)) );
312  rad2oi = sqr(p.x()/( xSemiAxis - halfRadTol ))
313  + sqr(p.y()/( ySemiAxis - halfRadTol ));
314 
315  if (rad2oi < sqr( zheight-p.z() ) )
316  {
317  in = ( ( p.z() < -zTopCut + halfRadTol )
318  || ( p.z() > zTopCut - halfRadTol ) ) ? kSurface : kInside;
319  }
320  else
321  {
322  in = kSurface;
323  }
324 
325  return in;
326 }
327 
329 //
330 // Return unit normal of surface closest to p not protected against p=0
331 //
333 {
334 
335  G4double rx = sqr(p.x()/xSemiAxis),
336  ry = sqr(p.y()/ySemiAxis);
337 
338  G4double rds = std::sqrt(rx + ry);
339 
340  G4ThreeVector norm;
341 
342  if( (p.z() < -zTopCut) && ((rx+ry) < sqr(zTopCut + zheight)) )
343  {
344  return G4ThreeVector( 0., 0., -1. );
345  }
346 
347  if( (p.z() > (zheight > zTopCut ? zheight : zTopCut)) &&
348  ((rx+ry) < sqr(zheight-zTopCut)) )
349  {
350  return G4ThreeVector( 0., 0., 1. );
351  }
352 
353  if( p.z() > rds + 2.*zTopCut - zheight )
354  {
355  if ( p.z() > zTopCut )
356  {
357  if( p.x() == 0. )
358  {
359  norm = G4ThreeVector( 0., p.y() < 0. ? -1. : 1., 1. );
360  return norm /= norm.mag();
361  }
362  if( p.y() == 0. )
363  {
364  norm = G4ThreeVector( p.x() < 0. ? -1. : 1., 0., 1. );
365  return norm /= norm.mag();
366  }
367 
368  G4double k = std::fabs(p.x()/p.y());
370  G4double x = std::sqrt(c2);
371  G4double y = k*x;
372 
373  x /= sqr(xSemiAxis);
374  y /= sqr(ySemiAxis);
375 
376  norm = G4ThreeVector( p.x() < 0. ? -x : x,
377  p.y() < 0. ? -y : y,
378  - ( zheight - zTopCut ) );
379  norm /= norm.mag();
380  norm += G4ThreeVector( 0., 0., 1. );
381  return norm /= norm.mag();
382  }
383 
384  return G4ThreeVector( 0., 0., 1. );
385  }
386 
387  if( p.z() < rds - 2.*zTopCut - zheight )
388  {
389  if( p.x() == 0. )
390  {
391  norm = G4ThreeVector( 0., p.y() < 0. ? -1. : 1., -1. );
392  return norm /= norm.mag();
393  }
394  if( p.y() == 0. )
395  {
396  norm = G4ThreeVector( p.x() < 0. ? -1. : 1., 0., -1. );
397  return norm /= norm.mag();
398  }
399 
400  G4double k = std::fabs(p.x()/p.y());
402  G4double x = std::sqrt(c2);
403  G4double y = k*x;
404 
405  x /= sqr(xSemiAxis);
406  y /= sqr(ySemiAxis);
407 
408  norm = G4ThreeVector( p.x() < 0. ? -x : x,
409  p.y() < 0. ? -y : y,
410  - ( zheight - zTopCut ) );
411  norm /= norm.mag();
412  norm += G4ThreeVector( 0., 0., -1. );
413  return norm /= norm.mag();
414  }
415 
416  norm = G4ThreeVector(p.x()/sqr(xSemiAxis), p.y()/sqr(ySemiAxis), rds);
417 
418  G4double k = std::tan(pi/8.);
419  G4double c = -zTopCut - k*(zTopCut + zheight);
420 
421  if( p.z() < -k*rds + c )
422  return G4ThreeVector (0.,0.,-1.);
423 
424  return norm /= norm.mag();
425 }
426 
428 //
429 // Calculate distance to shape from outside, along normalised vector
430 // return kInfinity if no intersection, or intersection distance <= tolerance
431 //
433  const G4ThreeVector& v ) const
434 {
435  G4double distMin = kInfinity;
436 
437  // code from EllipticalTube
438 
439  G4double sigz = p.z()+zTopCut;
440 
441  //
442  // Check z = -dz planer surface
443  //
444 
445  if (sigz < halfCarTol)
446  {
447  //
448  // We are "behind" the shape in z, and so can
449  // potentially hit the rear face. Correct direction?
450  //
451  if (v.z() <= 0)
452  {
453  //
454  // As long as we are far enough away, we know we
455  // can't intersect
456  //
457  if (sigz < 0) return kInfinity;
458 
459  //
460  // Otherwise, we don't intersect unless we are
461  // on the surface of the ellipse
462  //
463 
464  if ( sqr(p.x()/( xSemiAxis - halfCarTol ))
465  + sqr(p.y()/( ySemiAxis - halfCarTol )) <= sqr( zheight+zTopCut ) )
466  return kInfinity;
467 
468  }
469  else
470  {
471  //
472  // How far?
473  //
474  G4double q = -sigz/v.z();
475 
476  //
477  // Where does that place us?
478  //
479  G4double xi = p.x() + q*v.x(),
480  yi = p.y() + q*v.y();
481 
482  //
483  // Is this on the surface (within ellipse)?
484  //
485  if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight + zTopCut ) )
486  {
487  //
488  // Yup. Return q, unless we are on the surface
489  //
490  return (sigz < -halfCarTol) ? q : 0;
491  }
492  else if (xi/(xSemiAxis*xSemiAxis)*v.x()
493  + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
494  {
495  //
496  // Else, if we are traveling outwards, we know
497  // we must miss
498  //
499  // return kInfinity;
500  }
501  }
502  }
503 
504  //
505  // Check z = +dz planer surface
506  //
507  sigz = p.z() - zTopCut;
508 
509  if (sigz > -halfCarTol)
510  {
511  if (v.z() >= 0)
512  {
513 
514  if (sigz > 0) return kInfinity;
515 
516  if ( sqr(p.x()/( xSemiAxis - halfCarTol ))
517  + sqr(p.y()/( ySemiAxis - halfCarTol )) <= sqr( zheight-zTopCut ) )
518  return kInfinity;
519 
520  }
521  else {
522  G4double q = -sigz/v.z();
523 
524  G4double xi = p.x() + q*v.x(),
525  yi = p.y() + q*v.y();
526 
527  if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight - zTopCut ) )
528  {
529  return (sigz > -halfCarTol) ? q : 0;
530  }
531  else if (xi/(xSemiAxis*xSemiAxis)*v.x()
532  + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
533  {
534  // return kInfinity;
535  }
536  }
537  }
538 
539 
540 #if 0
541 
542  // check to see if Z plane is relevant
543  //
544  if (p.z() < -zTopCut - 0.5*kCarTolerance)
545  {
546  if (v.z() <= 0.0)
547  return distMin;
548 
549  G4double lambda = (-zTopCut - p.z())/v.z();
550 
551  if ( sqr((lambda*v.x()+p.x())/xSemiAxis) +
552  sqr((lambda*v.y()+p.y())/ySemiAxis) <=
553  sqr(zTopCut + zheight + 0.5*kRadTolerance) )
554  {
555  return distMin = std::fabs(lambda);
556  }
557  }
558 
559  if (p.z() > zTopCut+0.5*kCarTolerance)
560  {
561  if (v.z() >= 0.0)
562  { return distMin; }
563 
564  G4double lambda = (zTopCut - p.z()) / v.z();
565 
566  if ( sqr((lambda*v.x() + p.x())/xSemiAxis) +
567  sqr((lambda*v.y() + p.y())/ySemiAxis) <=
568  sqr(zheight - zTopCut + 0.5*kRadTolerance) )
569  {
570  return distMin = std::fabs(lambda);
571  }
572  }
573 
574  if (p.z() > zTopCut - halfCarTol
575  && p.z() < zTopCut + halfCarTol )
576  {
577  if (v.z() > 0.)
578  { return kInfinity; }
579 
580  return distMin = 0.;
581  }
582 
583  if (p.z() < -zTopCut + halfCarTol
584  && p.z() > -zTopCut - halfCarTol)
585  {
586  if (v.z() < 0.)
587  { return distMin = kInfinity; }
588 
589  return distMin = 0.;
590  }
591 
592 #endif
593 
594  // if we are here then it either intersects or grazes the curved surface
595  // or it does not intersect at all
596  //
597  G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
598  G4double B = 2*(v.x()*p.x()/sqr(xSemiAxis) +
599  v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
600  G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis) -
601  sqr(zheight - p.z());
602 
603  G4double discr = B*B - 4.*A*C;
604 
605  // if the discriminant is negative it never hits the curved object
606  //
607  if ( discr < -halfCarTol )
608  { return distMin; }
609 
610  // case below is when it hits or grazes the surface
611  //
612  if ( (discr >= - halfCarTol ) && (discr < halfCarTol ) )
613  {
614  return distMin = std::fabs(-B/(2.*A));
615  }
616 
617  G4double plus = (-B+std::sqrt(discr))/(2.*A);
618  G4double minus = (-B-std::sqrt(discr))/(2.*A);
619 
620  // Special case::Point on Surface, Check norm.dot(v)
621 
622  if ( ( std::fabs(plus) < halfCarTol )||( std::fabs(minus) < halfCarTol ) )
623  {
624  G4ThreeVector truenorm(p.x()/(xSemiAxis*xSemiAxis),
625  p.y()/(ySemiAxis*ySemiAxis),
626  -( p.z() - zheight ));
627  if ( truenorm*v >= 0) // going outside the solid from surface
628  {
629  return kInfinity;
630  }
631  else
632  {
633  return 0;
634  }
635  }
636 
637  // G4double lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
638  G4double lambda = 0;
639 
640  if ( minus > halfCarTol && minus < distMin )
641  {
642  lambda = minus ;
643  // check normal vector n * v < 0
644  G4ThreeVector pin = p + lambda*v;
645  if(std::fabs(pin.z())<zTopCut+0.5*kCarTolerance)
646  {
647  G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
648  pin.y()/(ySemiAxis*ySemiAxis),
649  - ( pin.z() - zheight ));
650  if ( truenorm*v < 0)
651  { // yes, going inside the solid
652  distMin = lambda;
653  }
654  }
655  }
656  if ( plus > halfCarTol && plus < distMin )
657  {
658  lambda = plus ;
659  // check normal vector n * v < 0
660  G4ThreeVector pin = p + lambda*v;
661  if(std::fabs(pin.z())<zTopCut+0.5*kCarTolerance)
662  {
663  G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
664  pin.y()/(ySemiAxis*ySemiAxis),
665  - ( pin.z() - zheight ) );
666  if ( truenorm*v < 0)
667  { // yes, going inside the solid
668  distMin = lambda;
669  }
670  }
671  }
672  if (distMin < halfCarTol) distMin=0.;
673  return distMin ;
674 }
675 
677 //
678 // Calculate distance (<= actual) to closest surface of shape from outside
679 // Return 0 if point inside
680 //
682 {
683  G4double distR, distR2, distZ, maxDim;
684  G4double distRad;
685 
686  // check if the point lies either below z=-zTopCut in bottom elliptical
687  // region or on top within cut elliptical region
688  //
689  if( (p.z() <= -zTopCut) && (sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
690  <= sqr(zTopCut + zheight + 0.5*kCarTolerance )) )
691  {
692  //return distZ = std::fabs(zTopCut - p.z());
693  return distZ = std::fabs(zTopCut + p.z());
694  }
695 
696  if( (p.z() >= zTopCut) && (sqr(p.x()/xSemiAxis)+sqr(p.y()/ySemiAxis)
697  <= sqr(zheight - zTopCut + kCarTolerance/2.0 )) )
698  {
699  return distZ = std::fabs(p.z() - zTopCut);
700  }
701 
702  // below we use the following approximation: we take the largest of the
703  // axes and find the shortest distance to the circular (cut) cone of that
704  // radius.
705  //
706  maxDim = xSemiAxis >= ySemiAxis ? xSemiAxis:ySemiAxis;
707  distRad = std::sqrt(p.x()*p.x()+p.y()*p.y());
708 
709  if( p.z() > maxDim*distRad + zTopCut*(1.+maxDim)-sqr(maxDim)*zheight )
710  {
711  distR2 = sqr(p.z() - zTopCut) + sqr(distRad - maxDim*(zheight - zTopCut));
712  return std::sqrt( distR2 );
713  }
714 
715  if( distRad > maxDim*( zheight - p.z() ) )
716  {
717  if( p.z() > maxDim*distRad - (zTopCut*(1.+maxDim)+sqr(maxDim)*zheight) )
718  {
719  G4double zVal = (p.z()-maxDim*(distRad-maxDim*zheight))/(1.+sqr(maxDim));
720  G4double rVal = maxDim*(zheight - zVal);
721  return distR = std::sqrt(sqr(p.z() - zVal) + sqr(distRad - rVal));
722  }
723  }
724 
725  if( distRad <= maxDim*(zheight - p.z()) )
726  {
727  distR2 = sqr(distRad - maxDim*(zheight + zTopCut)) + sqr(p.z() + zTopCut);
728  return std::sqrt( distR2 );
729  }
730 
731  return distR = 0;
732 }
733 
735 //
736 // Calculate distance to surface of shape from `inside',
737 // allowing for tolerance
738 //
740  const G4ThreeVector& v,
741  const G4bool calcNorm,
742  G4bool *validNorm,
743  G4ThreeVector *n ) const
744 {
745  G4double distMin, lambda;
746  enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
747 
748  distMin = kInfinity;
749  surface = kNoSurf;
750 
751  if (v.z() < 0.0)
752  {
753  lambda = (-p.z() - zTopCut)/v.z();
754 
755  if ( (sqr((p.x() + lambda*v.x())/xSemiAxis) +
756  sqr((p.y() + lambda*v.y())/ySemiAxis)) <
757  sqr(zheight + zTopCut + 0.5*kCarTolerance) )
758  {
759  distMin = std::fabs(lambda);
760 
761  if (!calcNorm) { return distMin; }
762  }
763  distMin = std::fabs(lambda);
764  surface = kPlaneSurf;
765  }
766 
767  if (v.z() > 0.0)
768  {
769  lambda = (zTopCut - p.z()) / v.z();
770 
771  if ( (sqr((p.x() + lambda*v.x())/xSemiAxis)
772  + sqr((p.y() + lambda*v.y())/ySemiAxis) )
773  < (sqr(zheight - zTopCut + 0.5*kCarTolerance)) )
774  {
775  distMin = std::fabs(lambda);
776  if (!calcNorm) { return distMin; }
777  }
778  distMin = std::fabs(lambda);
779  surface = kPlaneSurf;
780  }
781 
782  // if we are here then it either intersects or grazes the
783  // curved surface...
784  //
785  G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
786  G4double B = 2.*(v.x()*p.x()/sqr(xSemiAxis) +
787  v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
788  G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
789  - sqr(zheight - p.z());
790 
791  G4double discr = B*B - 4.*A*C;
792 
793  if ( discr >= - 0.5*kCarTolerance && discr < 0.5*kCarTolerance )
794  {
795  if(!calcNorm) { return distMin = std::fabs(-B/(2.*A)); }
796  }
797 
798  else if ( discr > 0.5*kCarTolerance )
799  {
800  G4double plus = (-B+std::sqrt(discr))/(2.*A);
801  G4double minus = (-B-std::sqrt(discr))/(2.*A);
802 
803  if ( plus > 0.5*kCarTolerance && minus > 0.5*kCarTolerance )
804  {
805  // take the shorter distance
806  //
807  lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
808  }
809  else
810  {
811  // at least one solution is close to zero or negative
812  // so, take small positive solution or zero
813  //
814  lambda = plus > -0.5*kCarTolerance ? plus : 0;
815  }
816 
817  if ( std::fabs(lambda) < distMin )
818  {
819  if( std::fabs(lambda) > 0.5*kCarTolerance)
820  {
821  distMin = std::fabs(lambda);
822  surface = kCurvedSurf;
823  }
824  else // Point is On the Surface, Check Normal
825  {
826  G4ThreeVector truenorm(p.x()/(xSemiAxis*xSemiAxis),
827  p.y()/(ySemiAxis*ySemiAxis),
828  -( p.z() - zheight ));
829  if( truenorm.dot(v) > 0 )
830  {
831  distMin = 0.0;
832  surface = kCurvedSurf;
833  }
834  }
835  }
836  }
837 
838  // set normal if requested
839  //
840  if (calcNorm)
841  {
842  if (surface == kNoSurf)
843  {
844  *validNorm = false;
845  }
846  else
847  {
848  *validNorm = true;
849  switch (surface)
850  {
851  case kPlaneSurf:
852  {
853  *n = G4ThreeVector(0.,0.,(v.z() > 0.0 ? 1. : -1.));
854  }
855  break;
856 
857  case kCurvedSurf:
858  {
859  G4ThreeVector pexit = p + distMin*v;
860  G4ThreeVector truenorm( pexit.x()/(xSemiAxis*xSemiAxis),
861  pexit.y()/(ySemiAxis*ySemiAxis),
862  -( pexit.z() - zheight ) );
863  truenorm /= truenorm.mag();
864  *n= truenorm;
865  }
866  break;
867 
868  default: // Should never reach this case ...
869  DumpInfo();
870  std::ostringstream message;
871  G4int oldprc = message.precision(16);
872  message << "Undefined side for valid surface normal to solid."
873  << G4endl
874  << "Position:" << G4endl
875  << " p.x() = " << p.x()/mm << " mm" << G4endl
876  << " p.y() = " << p.y()/mm << " mm" << G4endl
877  << " p.z() = " << p.z()/mm << " mm" << G4endl
878  << "Direction:" << G4endl
879  << " v.x() = " << v.x() << G4endl
880  << " v.y() = " << v.y() << G4endl
881  << " v.z() = " << v.z() << G4endl
882  << "Proposed distance :" << G4endl
883  << " distMin = " << distMin/mm << " mm";
884  message.precision(oldprc);
885  G4Exception("G4EllipticalCone::DistanceToOut(p,v,..)",
886  "GeomSolids1002", JustWarning, message);
887  break;
888  }
889  }
890  }
891 
892  if (distMin<0.5*kCarTolerance) { distMin=0; }
893 
894  return distMin;
895 }
896 
898 //
899 // Calculate distance (<=actual) to closest surface of shape from inside
900 //
902 {
903  G4double rds,roo,roo1, distR, distZ, distMin=0.;
905 
906 #ifdef G4SPECSDEBUG
907  if( Inside(p) == kOutside )
908  {
909  DumpInfo();
910  std::ostringstream message;
911  G4int oldprc = message.precision(16);
912  message << "Point p is outside !?" << G4endl
913  << "Position:" << G4endl
914  << " p.x() = " << p.x()/mm << " mm" << G4endl
915  << " p.y() = " << p.y()/mm << " mm" << G4endl
916  << " p.z() = " << p.z()/mm << " mm";
917  message.precision(oldprc) ;
918  G4Exception("G4Ellipsoid::DistanceToOut(p)", "GeomSolids1002",
919  JustWarning, message);
920  }
921 #endif
922 
923  // since we have made the above warning, below we are working assuming p
924  // is inside check how close it is to the circular cone with radius equal
925  // to the smaller of the axes
926  //
927  if( sqr(p.x()/minAxis)+sqr(p.y()/minAxis) < sqr(zheight - p.z()) )
928  {
929  rds = std::sqrt(sqr(p.x()) + sqr(p.y()));
930  roo = minAxis*(zheight-p.z()); // radius of cone at z= p.z()
931  roo1 = minAxis*(zheight-zTopCut); // radius of cone at z=+zTopCut
932 
933  distZ=zTopCut - std::fabs(p.z()) ;
934  distR=(roo-rds)/(std::sqrt(1+sqr(minAxis)));
935 
936  if(rds>roo1)
937  {
938  distMin=(zTopCut-p.z())*(roo-rds)/(roo-roo1);
939  distMin=std::min(distMin,distR);
940  }
941  distMin=std::min(distR,distZ);
942  }
943 
944  return distMin;
945 }
946 
948 //
949 // GetEntityType
950 //
952 {
953  return G4String("G4EllipticalCone");
954 }
955 
957 //
958 // Make a clone of the object
959 //
961 {
962  return new G4EllipticalCone(*this);
963 }
964 
966 //
967 // Stream object contents to an output stream
968 //
969 std::ostream& G4EllipticalCone::StreamInfo( std::ostream& os ) const
970 {
971  G4int oldprc = os.precision(16);
972  os << "-----------------------------------------------------------\n"
973  << " *** Dump for solid - " << GetName() << " ***\n"
974  << " ===================================================\n"
975  << " Solid type: G4EllipticalCone\n"
976  << " Parameters: \n"
977 
978  << " semi-axis x: " << xSemiAxis/mm << " mm \n"
979  << " semi-axis y: " << ySemiAxis/mm << " mm \n"
980  << " height z: " << zheight/mm << " mm \n"
981  << " half length in z: " << zTopCut/mm << " mm \n"
982  << "-----------------------------------------------------------\n";
983  os.precision(oldprc);
984 
985  return os;
986 }
987 
989 //
990 // GetPointOnSurface
991 //
992 // returns quasi-uniformly distributed point on surface of elliptical cone
993 //
995 {
996 
997  G4double phi, sinphi, cosphi, aOne, aTwo, aThree,
998  chose, zRand, rRand1, rRand2;
999 
1000  G4double rOne = std::sqrt(sqr(xSemiAxis)
1001  + sqr(ySemiAxis))*(zheight - zTopCut);
1002  G4double rTwo = std::sqrt(sqr(xSemiAxis)
1003  + sqr(ySemiAxis))*(zheight + zTopCut);
1004 
1005  aOne = pi*(rOne + rTwo)*std::sqrt(sqr(rOne - rTwo)+sqr(2.*zTopCut));
1007  aThree = pi*xSemiAxis*ySemiAxis*sqr(zheight-zTopCut);
1008 
1009  phi = RandFlat::shoot(0.,twopi);
1010  cosphi = std::cos(phi);
1011  sinphi = std::sin(phi);
1012 
1013  if(zTopCut >= zheight) aThree = 0.;
1014 
1015  chose = RandFlat::shoot(0.,aOne+aTwo+aThree);
1016  if((chose>=0.) && (chose<aOne))
1017  {
1018  zRand = RandFlat::shoot(-zTopCut,zTopCut);
1019  return G4ThreeVector(xSemiAxis*(zheight-zRand)*cosphi,
1020  ySemiAxis*(zheight-zRand)*sinphi,zRand);
1021  }
1022  else if((chose>=aOne) && (chose<aOne+aTwo))
1023  {
1024  do
1025  {
1026  rRand1 = RandFlat::shoot(0.,1.) ;
1027  rRand2 = RandFlat::shoot(0.,1.) ;
1028  } while ( rRand2 >= rRand1 ) ;
1029 
1030  // rRand2 = RandFlat::shoot(0.,std::sqrt(1.-sqr(rRand1)));
1031  return G4ThreeVector(rRand1*xSemiAxis*(zheight+zTopCut)*cosphi,
1032  rRand1*ySemiAxis*(zheight+zTopCut)*sinphi, -zTopCut);
1033 
1034  }
1035  // else
1036  //
1037 
1038  do
1039  {
1040  rRand1 = RandFlat::shoot(0.,1.) ;
1041  rRand2 = RandFlat::shoot(0.,1.) ;
1042  } while ( rRand2 >= rRand1 ) ;
1043 
1044  return G4ThreeVector(rRand1*xSemiAxis*(zheight-zTopCut)*cosphi,
1045  rRand1*ySemiAxis*(zheight-zTopCut)*sinphi, zTopCut);
1046 }
1047 
1048 //
1049 // Methods for visualisation
1050 //
1051 
1053 {
1054  scene.AddSolid(*this);
1055 }
1056 
1058 {
1059  // Define the sides of the box into which the solid instance would fit.
1060  //
1061  G4double maxDim;
1062  maxDim = xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis;
1063  maxDim = maxDim > zTopCut ? maxDim : zTopCut;
1064 
1065  return G4VisExtent (-maxDim, maxDim,
1066  -maxDim, maxDim,
1067  -maxDim, maxDim);
1068 }
1069 
1071 {
1073 }
1074 
1076 {
1077  if ( (!fpPolyhedron)
1079  fpPolyhedron->GetNumberOfRotationSteps()) )
1080  {
1081  delete fpPolyhedron;
1083  }
1084  return fpPolyhedron;
1085 }
G4String GetName() const
G4VSolid * Clone() const
ThreeVector shoot(const G4int Ap, const G4int Af)
static c2_factory< G4double > c2
G4EllipticalCone & operator=(const G4EllipticalCone &rhs)
static const G4double kInfinity
Definition: geomdefs.hh:42
CLHEP::Hep3Vector G4ThreeVector
G4bool GetExtent(G4double &min, G4double &max) const
const G4double pi
EInside Inside(const G4ThreeVector &p) const
void SetNormal(const G4ThreeVector &newNormal)
virtual G4bool PartialClip(const G4VoxelLimits &voxelLimit, const EAxis IgnoreMe)
virtual void AddVertexInOrder(const G4ThreeVector vertex)
G4double a
Definition: TRTMaterials.hh:39
virtual void ClearAllVertices()
virtual void AddSolid(const G4Box &)=0
G4Polyhedron * CreatePolyhedron() const
int G4int
Definition: G4Types.hh:78
void DumpInfo() const
static double normal(HepRandomEngine *eptr)
Definition: RandPoisson.cc:77
std::ostream & StreamInfo(std::ostream &os) const
G4ThreeVector GetPointOnSurface() const
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
G4Polyhedron * fpPolyhedron
G4double GetRadialTolerance() const
bool G4bool
Definition: G4Types.hh:79
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4EllipticalCone(const G4String &pName, G4double pxSemiAxis, G4double pySemiAxis, G4double zMax, G4double pzTopCut)
void AddSurface(const G4ClippablePolygon &surface)
const G4int n
static const G4double A[nN]
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
void DescribeYourselfTo(G4VGraphicsScene &scene) const
void SetSemiAxis(G4double x, G4double y, G4double z)
T max(const T t1, const T t2)
brief Return the largest of the two arguments
EInside
Definition: geomdefs.hh:58
EAxis
Definition: geomdefs.hh:54
G4ThreeVector TransformAxis(const G4ThreeVector &axis) const
void SetZCut(G4double newzTopCut)
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
#define G4endl
Definition: G4ios.hh:61
G4VSolid & operator=(const G4VSolid &rhs)
Definition: G4VSolid.cc:110
G4double kCarTolerance
Definition: G4VSolid.hh:305
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
T sqr(const T &x)
Definition: templates.hh:145
double G4double
Definition: G4Types.hh:76
G4Polyhedron * GetPolyhedron() const
G4GeometryType GetEntityType() const
G4VisExtent GetExtent() const
virtual ~G4EllipticalCone()
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=G4bool(false), G4bool *validNorm=0, G4ThreeVector *n=0) const
static const double mm
Definition: G4SIunits.hh:102
static G4GeometryTolerance * GetInstance()
void ApplyPointTransform(G4ThreeVector &vec) const
const G4int kMaxMeshSections
Definition: meshdefs.hh:46