source: trunk/source/geometry/solids/specific/src/G4EllipticalCone.cc@ 1347

Last change on this file since 1347 was 1337, checked in by garnier, 15 years ago

tag geant4.9.4 beta 1 + modifs locales

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