source: trunk/source/geometry/solids/CSG/src/G4Tubs.cc@ 833

Last change on this file since 833 was 831, checked in by garnier, 17 years ago

import all except CVS

File size: 55.1 KB
RevLine 
[831]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: G4Tubs.cc,v 1.66 2007/11/23 09:07:43 tnikitin Exp $
28// GEANT4 tag $Name: $
29//
30//
31// class G4Tubs
32//
33// History:
34//
35// 02.08.07 T.Nikitina: bug fixed in DistanceToOut(p,v,..) for negative value under sqrt
36// for the case: p on the surface and v is tangent to the surface
37// 11.05.07 T.Nikitina: bug fixed in DistanceToOut(p,v,..) for phi < 2pi
38// 03.05.05 V.Grichine: SurfaceNormal(p) according to J. Apostolakis proposal
39// 16.03.05 V.Grichine: SurfaceNormal(p) with edges/corners for boolean
40// 20.07.01 V.Grichine: bug fixed in Inside(p)
41// 20.02.01 V.Grichine: bug fixed in Inside(p) and CalculateExtent was
42// simplified base on G4Box::CalculateExtent
43// 07.12.00 V.Grichine: phi-section algorithm was changed in Inside(p)
44// 28.11.00 V.Grichine: bug fixed in Inside(p)
45// 31.10.00 V.Grichine: assign sr, sphi in Distance ToOut(p,v,...)
46// 08.08.00 V.Grichine: more stable roots of 2-equation in DistanceToOut(p,v,..)
47// 02.08.00 V.Grichine: point is outside check in Distance ToOut(p)
48// 17.05.00 V.Grichine: bugs (#76,#91) fixed in Distance ToOut(p,v,...)
49// 31.03.00 V.Grichine: bug fixed in Inside(p)
50// 19.11.99 V.Grichine: side = kNull in DistanceToOut(p,v,...)
51// 13.10.99 V.Grichine: bugs fixed in DistanceToIn(p,v)
52// 28.05.99 V.Grichine: bugs fixed in DistanceToOut(p,v,...)
53// 25.05.99 V.Grichine: bugs fixed in DistanceToIn(p,v)
54// 23.03.99 V.Grichine: bug fixed in DistanceToIn(p,v)
55// 09.10.98 V.Grichine: modifications in DistanceToOut(p,v,...)
56// 18.06.98 V.Grichine: n-normalisation in DistanceToOut(p,v)
57//
58// 1994-95 P.Kent: implementation
59//
60/////////////////////////////////////////////////////////////////////////
61
62#include "G4Tubs.hh"
63
64#include "G4VoxelLimits.hh"
65#include "G4AffineTransform.hh"
66#include "G4GeometryTolerance.hh"
67
68#include "G4VPVParameterisation.hh"
69
70#include "Randomize.hh"
71
72#include "meshdefs.hh"
73
74#include "G4VGraphicsScene.hh"
75#include "G4Polyhedron.hh"
76#include "G4NURBS.hh"
77#include "G4NURBStube.hh"
78#include "G4NURBScylinder.hh"
79#include "G4NURBStubesector.hh"
80
81using namespace CLHEP;
82
83/////////////////////////////////////////////////////////////////////////
84//
85// Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI
86// - note if pdphi>2PI then reset to 2PI
87
88G4Tubs::G4Tubs( const G4String &pName,
89 G4double pRMin, G4double pRMax,
90 G4double pDz,
91 G4double pSPhi, G4double pDPhi )
92 : G4CSGSolid(pName)
93{
94
95 kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance();
96 kAngTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance();
97
98 if (pDz>0) // Check z-len
99 {
100 fDz = pDz ;
101 }
102 else
103 {
104 G4cerr << "ERROR - G4Tubs()::G4Tubs(): " << GetName() << G4endl
105 << " Negative Z half-length ! - "
106 << pDz << G4endl;
107 G4Exception("G4Tubs::G4Tubs()", "InvalidSetup", FatalException,
108 "Invalid Z half-length");
109 }
110 if ( pRMin < pRMax && pRMin >= 0 ) // Check radii
111 {
112 fRMin = pRMin ;
113 fRMax = pRMax ;
114 }
115 else
116 {
117 G4cerr << "ERROR - G4Tubs()::G4Tubs(): " << GetName() << G4endl
118 << " Invalid values for radii !" << G4endl
119 << " pRMin = " << pRMin << ", pRMax = " << pRMax << G4endl;
120 G4Exception("G4Tubs::G4Tubs()", "InvalidSetup", FatalException,
121 "Invalid radii.");
122 }
123 if ( pDPhi >= twopi ) // Check angles
124 {
125 fDPhi=twopi;
126 }
127 else
128 {
129 if ( pDPhi > 0 )
130 {
131 fDPhi = pDPhi;
132 }
133 else
134 {
135 G4cerr << "ERROR - G4Tubs()::G4Tubs(): " << GetName() << G4endl
136 << " Negative delta-Phi ! - "
137 << pDPhi << G4endl;
138 G4Exception("G4Tubs::G4Tubs()", "InvalidSetup", FatalException,
139 "Invalid dphi.");
140 }
141 }
142
143 // Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0
144
145 fSPhi = pSPhi;
146
147 if ( fSPhi < 0 )
148 {
149 fSPhi = twopi - std::fmod(std::fabs(fSPhi),twopi) ;
150 }
151 else
152 {
153 fSPhi = std::fmod(fSPhi,twopi) ;
154 }
155 if (fSPhi + fDPhi > twopi )
156 {
157 fSPhi -= twopi ;
158 }
159}
160
161///////////////////////////////////////////////////////////////////////
162//
163// Fake default constructor - sets only member data and allocates memory
164// for usage restricted to object persistency.
165//
166G4Tubs::G4Tubs( __void__& a )
167 : G4CSGSolid(a)
168{
169}
170
171//////////////////////////////////////////////////////////////////////////
172//
173// Destructor
174
175G4Tubs::~G4Tubs()
176{
177}
178
179/////////////////////////////////////////////////////////////////////////
180//
181// Dispatch to parameterisation for replication mechanism dimension
182// computation & modification.
183
184void G4Tubs::ComputeDimensions( G4VPVParameterisation* p,
185 const G4int n,
186 const G4VPhysicalVolume* pRep )
187{
188 p->ComputeDimensions(*this,n,pRep) ;
189}
190
191////////////////////////////////////////////////////////////////////////
192//
193// Calculate extent under transform and specified limit
194
195G4bool G4Tubs::CalculateExtent( const EAxis pAxis,
196 const G4VoxelLimits& pVoxelLimit,
197 const G4AffineTransform& pTransform,
198 G4double& pMin,
199 G4double& pMax ) const
200{
201
202 if ( !pTransform.IsRotated() && fDPhi == twopi && fRMin == 0 )
203 {
204 // Special case handling for unrotated solid tubes
205 // Compute x/y/z mins and maxs fro bounding box respecting limits,
206 // with early returns if outside limits. Then switch() on pAxis,
207 // and compute exact x and y limit for x/y case
208
209 G4double xoffset, xMin, xMax ;
210 G4double yoffset, yMin, yMax ;
211 G4double zoffset, zMin, zMax ;
212
213 G4double diff1, diff2, maxDiff, newMin, newMax ;
214 G4double xoff1, xoff2, yoff1, yoff2, delta ;
215
216 xoffset = pTransform.NetTranslation().x() ;
217 xMin = xoffset - fRMax ;
218 xMax = xoffset + fRMax ;
219
220 if (pVoxelLimit.IsXLimited())
221 {
222 if ( (xMin > pVoxelLimit.GetMaxXExtent())
223 || (xMax < pVoxelLimit.GetMinXExtent()) )
224 {
225 return false;
226 }
227 else
228 {
229 if ( xMin < pVoxelLimit.GetMinXExtent() )
230 {
231 xMin = pVoxelLimit.GetMinXExtent() ;
232 }
233 if (xMax > pVoxelLimit.GetMaxXExtent() )
234 {
235 xMax = pVoxelLimit.GetMaxXExtent() ;
236 }
237 }
238 }
239 yoffset = pTransform.NetTranslation().y() ;
240 yMin = yoffset - fRMax ;
241 yMax = yoffset + fRMax ;
242
243 if ( pVoxelLimit.IsYLimited() )
244 {
245 if ( (yMin > pVoxelLimit.GetMaxYExtent())
246 || (yMax < pVoxelLimit.GetMinYExtent()) )
247 {
248 return false ;
249 }
250 else
251 {
252 if ( yMin < pVoxelLimit.GetMinYExtent() )
253 {
254 yMin = pVoxelLimit.GetMinYExtent() ;
255 }
256 if ( yMax > pVoxelLimit.GetMaxYExtent() )
257 {
258 yMax=pVoxelLimit.GetMaxYExtent();
259 }
260 }
261 }
262 zoffset = pTransform.NetTranslation().z() ;
263 zMin = zoffset - fDz ;
264 zMax = zoffset + fDz ;
265
266 if ( pVoxelLimit.IsZLimited() )
267 {
268 if ( (zMin > pVoxelLimit.GetMaxZExtent())
269 || (zMax < pVoxelLimit.GetMinZExtent()) )
270 {
271 return false ;
272 }
273 else
274 {
275 if ( zMin < pVoxelLimit.GetMinZExtent() )
276 {
277 zMin = pVoxelLimit.GetMinZExtent() ;
278 }
279 if ( zMax > pVoxelLimit.GetMaxZExtent() )
280 {
281 zMax = pVoxelLimit.GetMaxZExtent();
282 }
283 }
284 }
285 switch ( pAxis ) // Known to cut cylinder
286 {
287 case kXAxis :
288 {
289 yoff1 = yoffset - yMin ;
290 yoff2 = yMax - yoffset ;
291
292 if ( yoff1 >= 0 && yoff2 >= 0 ) // Y limits cross max/min x => no change
293 {
294 pMin = xMin ;
295 pMax = xMax ;
296 }
297 else
298 {
299 // Y limits don't cross max/min x => compute max delta x,
300 // hence new mins/maxs
301
302 delta = fRMax*fRMax - yoff1*yoff1;
303 diff1 = (delta>0.) ? std::sqrt(delta) : 0.;
304 delta = fRMax*fRMax - yoff2*yoff2;
305 diff2 = (delta>0.) ? std::sqrt(delta) : 0.;
306 maxDiff = (diff1 > diff2) ? diff1:diff2;
307 newMin = xoffset - maxDiff;
308 newMax = xoffset + maxDiff;
309 pMin = (newMin < xMin) ? xMin : newMin;
310 pMax = (newMax > xMax) ? xMax : newMax;
311 }
312 break;
313 }
314 case kYAxis :
315 {
316 xoff1 = xoffset - xMin ;
317 xoff2 = xMax - xoffset ;
318
319 if ( xoff1 >= 0 && xoff2 >= 0 ) // X limits cross max/min y => no change
320 {
321 pMin = yMin ;
322 pMax = yMax ;
323 }
324 else
325 {
326 // X limits don't cross max/min y => compute max delta y,
327 // hence new mins/maxs
328
329 delta = fRMax*fRMax - xoff1*xoff1;
330 diff1 = (delta>0.) ? std::sqrt(delta) : 0.;
331 delta = fRMax*fRMax - xoff2*xoff2;
332 diff2 = (delta>0.) ? std::sqrt(delta) : 0.;
333 maxDiff = (diff1 > diff2) ? diff1 : diff2 ;
334 newMin = yoffset - maxDiff ;
335 newMax = yoffset + maxDiff ;
336 pMin = (newMin < yMin) ? yMin : newMin ;
337 pMax =(newMax > yMax) ? yMax : newMax ;
338 }
339 break ;
340 }
341 case kZAxis:
342 {
343 pMin = zMin ;
344 pMax = zMax ;
345 break ;
346 }
347 default:
348 break;
349 }
350 pMin -= kCarTolerance ;
351 pMax += kCarTolerance ;
352 return true;
353 }
354 else // Calculate rotated vertex coordinates
355 {
356 G4int i, noEntries, noBetweenSections4 ;
357 G4bool existsAfterClip = false ;
358 G4ThreeVectorList* vertices = CreateRotatedVertices(pTransform) ;
359
360 pMin = +kInfinity ;
361 pMax = -kInfinity ;
362
363 noEntries = vertices->size() ;
364 noBetweenSections4 = noEntries - 4 ;
365 /*
366 G4cout << "vertices = " << noEntries << "\t"
367 << "v-4 = " << noBetweenSections4 << G4endl;
368 G4cout << G4endl;
369 for(i = 0 ; i < noEntries ; i++ )
370 {
371 G4cout << i << "\t" << "v.x = " << ((*vertices)[i]).x() << "\t"
372 << "v.y = " << ((*vertices)[i]).y() << "\t"
373 << "v.z = " << ((*vertices)[i]).z() << "\t" << G4endl;
374 }
375 G4cout << G4endl;
376 G4cout << "ClipCrossSection" << G4endl;
377 */
378 for (i = 0 ; i < noEntries ; i += 4 )
379 {
380 // G4cout << "section = " << i << G4endl;
381 ClipCrossSection(vertices,i,pVoxelLimit,pAxis,pMin,pMax) ;
382 }
383 // G4cout << "ClipBetweenSections" << G4endl;
384 for (i = 0 ; i < noBetweenSections4 ; i += 4 )
385 {
386 // G4cout << "between sections = " << i << G4endl;
387 ClipBetweenSections(vertices,i,pVoxelLimit,pAxis,pMin,pMax) ;
388 }
389 if (pMin != kInfinity || pMax != -kInfinity )
390 {
391 existsAfterClip = true ;
392 pMin -= kCarTolerance ; // Add 2*tolerance to avoid precision troubles
393 pMax += kCarTolerance ;
394 }
395 else
396 {
397 // Check for case where completely enveloping clipping volume
398 // If point inside then we are confident that the solid completely
399 // envelopes the clipping volume. Hence set min/max extents according
400 // to clipping volume extents along the specified axis.
401
402 G4ThreeVector clipCentre(
403 (pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5,
404 (pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5,
405 (pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5 ) ;
406
407 if ( Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside )
408 {
409 existsAfterClip = true ;
410 pMin = pVoxelLimit.GetMinExtent(pAxis) ;
411 pMax = pVoxelLimit.GetMaxExtent(pAxis) ;
412 }
413 }
414 delete vertices;
415 return existsAfterClip;
416 }
417}
418
419
420///////////////////////////////////////////////////////////////////////////
421//
422// Return whether point inside/outside/on surface
423
424EInside G4Tubs::Inside( const G4ThreeVector& p ) const
425{
426 G4double r2,pPhi,tolRMin,tolRMax;
427 EInside in = kOutside ;
428
429 if (std::fabs(p.z()) <= fDz - kCarTolerance*0.5)
430 {
431 r2 = p.x()*p.x() + p.y()*p.y() ;
432
433 if (fRMin) { tolRMin = fRMin + kRadTolerance*0.5 ; }
434 else { tolRMin = 0 ; }
435
436 tolRMax = fRMax - kRadTolerance*0.5 ;
437
438 if (r2 >= tolRMin*tolRMin && r2 <= tolRMax*tolRMax)
439 {
440 if ( fDPhi == twopi )
441 {
442 in = kInside ;
443 }
444 else
445 {
446 // Try inner tolerant phi boundaries (=>inside)
447 // if not inside, try outer tolerant phi boundaries
448
449 pPhi = std::atan2(p.y(),p.x()) ;
450 if ((tolRMin==0)&&(p.x()==0)&&(p.y()==0))
451 {
452 in=kSurface;
453 }
454 else
455 {
456 if ( pPhi < -kAngTolerance*0.5 ) { pPhi += twopi; } // 0<=pPhi<2pi
457
458 if ( fSPhi >= 0 )
459 {
460 if ( (std::abs(pPhi) < kAngTolerance*0.5)
461 && (std::abs(fSPhi + fDPhi - twopi) < kAngTolerance*0.5) )
462 {
463 pPhi += twopi ; // 0 <= pPhi < 2pi
464 }
465 if ( (pPhi >= fSPhi + kAngTolerance*0.5)
466 && (pPhi <= fSPhi + fDPhi - kAngTolerance*0.5) )
467 {
468 in = kInside ;
469 }
470 else if ( (pPhi >= fSPhi - kAngTolerance*0.5)
471 && (pPhi <= fSPhi + fDPhi + kAngTolerance*0.5) )
472 {
473 in = kSurface ;
474 }
475 }
476 else // fSPhi < 0
477 {
478 if ( (pPhi <= fSPhi + twopi - kAngTolerance*0.5)
479 && (pPhi >= fSPhi + fDPhi + kAngTolerance*0.5) ) {;}
480 else if ( (pPhi <= fSPhi + twopi + kAngTolerance*0.5)
481 && (pPhi >= fSPhi + fDPhi - kAngTolerance*0.5) )
482 {
483 in = kSurface ;
484 }
485 else
486 {
487 in = kInside ;
488 }
489 }
490 }
491 }
492 }
493 else // Try generous boundaries
494 {
495 tolRMin = fRMin - kRadTolerance*0.5 ;
496 tolRMax = fRMax + kRadTolerance*0.5 ;
497
498 if ( tolRMin < 0 ) { tolRMin = 0; }
499
500 if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) )
501 {
502 if ( fDPhi == twopi || r2 == 0 ) // Continuous in phi or on z-axis
503 {
504 in = kSurface ;
505 }
506 else // Try outer tolerant phi boundaries only
507 {
508 pPhi = std::atan2(p.y(),p.x()) ;
509
510 if ( pPhi < -kAngTolerance*0.5 ) { pPhi += twopi; } // 0<=pPhi<2pi
511 if ( fSPhi >= 0 )
512 {
513 if ( (std::abs(pPhi) < kAngTolerance*0.5)
514 && (std::abs(fSPhi + fDPhi - twopi) < kAngTolerance*0.5) )
515 {
516 pPhi += twopi ; // 0 <= pPhi < 2pi
517 }
518 if ( (pPhi >= fSPhi - kAngTolerance*0.5)
519 && (pPhi <= fSPhi + fDPhi + kAngTolerance*0.5) )
520 {
521 in = kSurface ;
522 }
523 }
524 else // fSPhi < 0
525 {
526 if ( (pPhi <= fSPhi + twopi - kAngTolerance*0.5)
527 && (pPhi >= fSPhi + fDPhi + kAngTolerance*0.5) ) {;}
528 else
529 {
530 in = kSurface ;
531 }
532 }
533 }
534 }
535 }
536 }
537 else if (std::fabs(p.z()) <= fDz + kCarTolerance*0.5)
538 { // Check within tolerant r limits
539 r2 = p.x()*p.x() + p.y()*p.y() ;
540 tolRMin = fRMin - kRadTolerance*0.5 ;
541 tolRMax = fRMax + kRadTolerance*0.5 ;
542
543 if ( tolRMin < 0 ) { tolRMin = 0; }
544
545 if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) )
546 {
547 if (fDPhi == twopi || r2 == 0 ) // Continuous in phi or on z-axis
548 {
549 in = kSurface ;
550 }
551 else // Try outer tolerant phi boundaries
552 {
553 pPhi = std::atan2(p.y(),p.x()) ;
554
555 if ( pPhi < -kAngTolerance*0.5 ) { pPhi += twopi; } // 0<=pPhi<2pi
556 if ( fSPhi >= 0 )
557 {
558 if ( (std::abs(pPhi) < kAngTolerance*0.5)
559 && (std::abs(fSPhi + fDPhi - twopi) < kAngTolerance*0.5) )
560 {
561 pPhi += twopi ; // 0 <= pPhi < 2pi
562 }
563 if ( (pPhi >= fSPhi - kAngTolerance*0.5)
564 && (pPhi <= fSPhi + fDPhi + kAngTolerance*0.5) )
565 {
566 in = kSurface;
567 }
568 }
569 else // fSPhi < 0
570 {
571 if ( (pPhi <= fSPhi + twopi - kAngTolerance*0.5)
572 && (pPhi >= fSPhi + fDPhi + kAngTolerance*0.5) ) {;}
573 else
574 {
575 in = kSurface ;
576 }
577 }
578 }
579 }
580 }
581 return in;
582}
583
584///////////////////////////////////////////////////////////////////////////
585//
586// Return unit normal of surface closest to p
587// - note if point on z axis, ignore phi divided sides
588// - unsafe if point close to z axis a rmin=0 - no explicit checks
589
590G4ThreeVector G4Tubs::SurfaceNormal( const G4ThreeVector& p ) const
591{ G4int noSurfaces = 0;
592 G4double rho, pPhi;
593 G4double delta = 0.5*kCarTolerance, dAngle = 0.5*kAngTolerance;
594 G4double distZ, distRMin, distRMax;
595 G4double distSPhi = kInfinity, distEPhi = kInfinity;
596 G4ThreeVector norm, sumnorm(0.,0.,0.);
597 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0);
598 G4ThreeVector nR, nPs, nPe;
599
600 rho = std::sqrt(p.x()*p.x() + p.y()*p.y());
601
602 distRMin = std::fabs(rho - fRMin);
603 distRMax = std::fabs(rho - fRMax);
604 distZ = std::fabs(std::fabs(p.z()) - fDz);
605
606 if (fDPhi < twopi) // && rho ) // Protected against (0,0,z)
607 {
608 if ( rho )
609 {
610 pPhi = std::atan2(p.y(),p.x());
611
612 if(pPhi < fSPhi-delta) { pPhi += twopi; }
613 else if(pPhi > fSPhi+fDPhi+delta) { pPhi -= twopi; }
614
615 distSPhi = std::fabs( pPhi - fSPhi );
616 distEPhi = std::fabs(pPhi - fSPhi - fDPhi);
617 }
618 else if( !fRMin )
619 {
620 distSPhi = 0.;
621 distEPhi = 0.;
622 }
623 nPs = G4ThreeVector(std::sin(fSPhi),-std::cos(fSPhi),0);
624 nPe = G4ThreeVector(-std::sin(fSPhi+fDPhi),std::cos(fSPhi+fDPhi),0);
625 }
626 if ( rho > delta ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); }
627
628 if( distRMax <= delta )
629 {
630 noSurfaces ++;
631 sumnorm += nR;
632 }
633 if( fRMin && distRMin <= delta )
634 {
635 noSurfaces ++;
636 sumnorm -= nR;
637 }
638 if( fDPhi < twopi )
639 {
640 if (distSPhi <= dAngle) // delta)
641 {
642 noSurfaces ++;
643 sumnorm += nPs;
644 }
645 if (distEPhi <= dAngle) // delta)
646 {
647 noSurfaces ++;
648 sumnorm += nPe;
649 }
650 }
651 if (distZ <= delta)
652 {
653 noSurfaces ++;
654 if ( p.z() >= 0.) { sumnorm += nZ; }
655 else { sumnorm -= nZ; }
656 }
657 if ( noSurfaces == 0 )
658 {
659#ifdef G4CSGDEBUG
660 G4Exception("G4Tube::SurfaceNormal(p)", "Notification",
661 JustWarning, "Point p is not on surface !?" );
662 G4cout.precision(20);
663 G4cout<< "G4Tubs::SN ( "<<p.x()<<", "<<p.y()<<", "<<p.z()<<" ); "
664 << G4endl << G4endl;
665#endif
666 norm = ApproxSurfaceNormal(p);
667 }
668 else if ( noSurfaces == 1 ) { norm = sumnorm; }
669 else { norm = sumnorm.unit(); }
670 return norm;
671}
672
673/////////////////////////////////////////////////////////////////////////////
674//
675// Algorithm for SurfaceNormal() following the original specification
676// for points not on the surface
677
678G4ThreeVector G4Tubs::ApproxSurfaceNormal( const G4ThreeVector& p ) const
679{ ENorm side ;
680 G4ThreeVector norm ;
681 G4double rho, phi ;
682 G4double distZ, distRMin, distRMax, distSPhi, distEPhi, distMin ;
683
684 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
685
686 distRMin = std::fabs(rho - fRMin) ;
687 distRMax = std::fabs(rho - fRMax) ;
688 distZ = std::fabs(std::fabs(p.z()) - fDz) ;
689
690 if (distRMin < distRMax) // First minimum
691 {
692 if ( distZ < distRMin )
693 {
694 distMin = distZ ;
695 side = kNZ ;
696 }
697 else
698 {
699 distMin = distRMin ;
700 side = kNRMin ;
701 }
702 }
703 else
704 {
705 if ( distZ < distRMax )
706 {
707 distMin = distZ ;
708 side = kNZ ;
709 }
710 else
711 {
712 distMin = distRMax ;
713 side = kNRMax ;
714 }
715 }
716 if (fDPhi < twopi && rho ) // Protected against (0,0,z)
717 {
718 phi = std::atan2(p.y(),p.x()) ;
719
720 if ( phi < 0 ) { phi += twopi; }
721
722 if ( fSPhi < 0 )
723 {
724 distSPhi = std::fabs(phi - (fSPhi + twopi))*rho ;
725 }
726 else
727 {
728 distSPhi = std::fabs(phi - fSPhi)*rho ;
729 }
730 distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ;
731
732 if (distSPhi < distEPhi) // Find new minimum
733 {
734 if ( distSPhi < distMin )
735 {
736 side = kNSPhi ;
737 }
738 }
739 else
740 {
741 if ( distEPhi < distMin )
742 {
743 side = kNEPhi ;
744 }
745 }
746 }
747 switch ( side )
748 {
749 case kNRMin : // Inner radius
750 {
751 norm = G4ThreeVector(-p.x()/rho,-p.y()/rho,0) ;
752 break ;
753 }
754 case kNRMax : // Outer radius
755 {
756 norm = G4ThreeVector(p.x()/rho,p.y()/rho,0) ;
757 break ;
758 }
759 case kNZ : // + or - dz
760 {
761 if ( p.z() > 0 ) norm = G4ThreeVector(0,0,1) ;
762 else norm = G4ThreeVector(0,0,-1) ;
763 break ;
764 }
765 case kNSPhi:
766 {
767 norm = G4ThreeVector(std::sin(fSPhi),-std::cos(fSPhi),0) ;
768 break ;
769 }
770 case kNEPhi:
771 {
772 norm = G4ThreeVector(-std::sin(fSPhi+fDPhi),std::cos(fSPhi+fDPhi),0) ;
773 break;
774 }
775 default:
776 {
777 DumpInfo();
778 G4Exception("G4Tubs::ApproxSurfaceNormal()", "Notification", JustWarning,
779 "Undefined side for valid surface normal to solid.");
780 break ;
781 }
782 }
783 return norm;
784}
785
786////////////////////////////////////////////////////////////////////
787//
788//
789// Calculate distance to shape from outside, along normalised vector
790// - return kInfinity if no intersection, or intersection distance <= tolerance
791//
792// - Compute the intersection with the z planes
793// - if at valid r, phi, return
794//
795// -> If point is outer outer radius, compute intersection with rmax
796// - if at valid phi,z return
797//
798// -> Compute intersection with inner radius, taking largest +ve root
799// - if valid (in z,phi), save intersction
800//
801// -> If phi segmented, compute intersections with phi half planes
802// - return smallest of valid phi intersections and
803// inner radius intersection
804//
805// NOTE:
806// - Precalculations for phi trigonometry are Done `just in time'
807// - `if valid' implies tolerant checking of intersection points
808
809G4double G4Tubs::DistanceToIn( const G4ThreeVector& p,
810 const G4ThreeVector& v ) const
811{
812 G4double snxt = kInfinity ; // snxt = default return value
813
814 // Precalculated trig for phi intersections - used by r,z intersections to
815 // check validity
816
817 G4bool seg ; // true if segmented
818
819 G4double hDPhi, hDPhiOT, hDPhiIT, cosHDPhiOT=0., cosHDPhiIT=0. ;
820 // half dphi + outer tolerance
821
822 G4double cPhi, sinCPhi=0., cosCPhi=0. ; // central phi
823
824 G4double tolORMin2, tolIRMax2 ; // `generous' radii squared
825
826 G4double tolORMax2, tolIRMin2, tolODz, tolIDz ;
827
828 // Intersection point variables
829 //
830 G4double Dist, s, xi, yi, zi, rho2, inum, iden, cosPsi ;
831
832 G4double t1, t2, t3, b, c, d ; // Quadratic solver variables
833
834 G4double Comp ;
835 G4double cosSPhi, sinSPhi ; // Trig for phi start intersect
836
837 G4double ePhi, cosEPhi, sinEPhi ; // for phi end intersect
838
839 // Set phi divided flag and precalcs
840
841 if ( fDPhi < twopi )
842 {
843 seg = true ;
844 hDPhi = 0.5*fDPhi ; // half delta phi
845 cPhi = fSPhi + hDPhi ;
846 hDPhiOT = hDPhi + 0.5*kAngTolerance ; // outers tol' half delta phi
847 hDPhiIT = hDPhi - 0.5*kAngTolerance ;
848 sinCPhi = std::sin(cPhi) ;
849 cosCPhi = std::cos(cPhi) ;
850 cosHDPhiOT = std::cos(hDPhiOT) ;
851 cosHDPhiIT = std::cos(hDPhiIT) ;
852 }
853 else
854 {
855 seg = false ;
856 }
857
858 // Calculate tolerant rmin and rmax
859
860 if (fRMin > kRadTolerance)
861 {
862 tolORMin2 = (fRMin - 0.5*kRadTolerance)*(fRMin - 0.5*kRadTolerance) ;
863 tolIRMin2 = (fRMin + 0.5*kRadTolerance)*(fRMin + 0.5*kRadTolerance) ;
864 }
865 else
866 {
867 tolORMin2 = 0.0 ;
868 tolIRMin2 = 0.0 ;
869 }
870 tolORMax2 = (fRMax + 0.5*kRadTolerance)*(fRMax + 0.5*kRadTolerance) ;
871 tolIRMax2 = (fRMax - 0.5*kRadTolerance)*(fRMax - 0.5*kRadTolerance) ;
872
873 // Intersection with Z surfaces
874
875 tolIDz = fDz - kCarTolerance*0.5 ;
876 tolODz = fDz + kCarTolerance*0.5 ;
877
878 if (std::fabs(p.z()) >= tolIDz)
879 {
880 if ( p.z()*v.z() < 0 ) // at +Z going in -Z or visa versa
881 {
882 s = (std::fabs(p.z()) - fDz)/std::fabs(v.z()) ; // Z intersect distance
883
884 if(s < 0.0) { s = 0.0; }
885
886 xi = p.x() + s*v.x() ; // Intersection coords
887 yi = p.y() + s*v.y() ;
888 rho2 = xi*xi + yi*yi ;
889
890 // Check validity of intersection
891
892 if (tolIRMin2 <= rho2 && rho2 <= tolIRMax2)
893 {
894 if (seg && rho2)
895 {
896 // Psi = angle made with central (average) phi of shape
897 //
898 inum = xi*cosCPhi + yi*sinCPhi ;
899 iden = std::sqrt(rho2) ;
900 cosPsi = inum/iden ;
901 if (cosPsi >= cosHDPhiIT) return s ;
902 }
903 else
904 {
905 return s ;
906 }
907 }
908 }
909 else
910 {
911 if ( snxt<kCarTolerance*0.5 ) { snxt=0; }
912 return snxt ; // On/outside extent, and heading away
913 // -> cannot intersect
914 }
915 }
916
917 // -> Can not intersect z surfaces
918 //
919 // Intersection with rmax (possible return) and rmin (must also check phi)
920 //
921 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
922 //
923 // Intersects with x^2+y^2=R^2
924 //
925 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
926 // t1 t2 t3
927
928 t1 = 1.0 - v.z()*v.z() ;
929 t2 = p.x()*v.x() + p.y()*v.y() ;
930 t3 = p.x()*p.x() + p.y()*p.y() ;
931
932 if ( t1 > 0 ) // Check not || to z axis
933 {
934 b = t2/t1 ;
935 c = t3 - fRMax*fRMax ;
936 if (t3 >= tolORMax2 && t2<0) // This also handles the tangent case
937 {
938 // Try outer cylinder intersection
939 // c=(t3-fRMax*fRMax)/t1;
940
941 c /= t1 ;
942 d = b*b - c ;
943
944 if (d >= 0) // If real root
945 {
946 s = -b - std::sqrt(d) ;
947 if (s >= 0) // If 'forwards'
948 {
949 // Check z intersection
950 //
951 zi = p.z() + s*v.z() ;
952 if (std::fabs(zi)<=tolODz)
953 {
954 // Z ok. Check phi intersection if reqd
955 //
956 if (!seg)
957 {
958 return s ;
959 }
960 else
961 {
962 xi = p.x() + s*v.x() ;
963 yi = p.y() + s*v.y() ;
964 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ;
965 if (cosPsi >= cosHDPhiIT) return s ;
966 }
967 } // end if std::fabs(zi)
968 } // end if (s>=0)
969 } // end if (d>=0)
970 } // end if (r>=fRMax)
971 else
972 {
973 // Inside outer radius :
974 // check not inside, and heading through tubs (-> 0 to in)
975
976 if (t3 > tolIRMin2 && t2 < 0 && std::fabs(p.z()) <= tolIDz)
977 {
978 // Inside both radii, delta r -ve, inside z extent
979
980 if (seg)
981 {
982 inum = p.x()*cosCPhi + p.y()*sinCPhi ;
983 iden = std::sqrt(t3) ;
984 cosPsi = inum/iden ;
985 if (cosPsi >= cosHDPhiIT) { return 0.0; }
986 }
987 else
988 {
989 return 0.0 ;
990 }
991 }
992 }
993 if ( fRMin ) // Try inner cylinder intersection
994 {
995 c = (t3 - fRMin*fRMin)/t1 ;
996 d = b*b - c ;
997 if ( d >= 0.0 ) // If real root
998 {
999 // Always want 2nd root - we are outside and know rmax Hit was bad
1000 // - If on surface of rmin also need farthest root
1001
1002 s = -b + std::sqrt(d) ;
1003 if (s >= -0.5*kCarTolerance) // check forwards
1004 {
1005 // Check z intersection
1006 //
1007 if(s < 0.0) { s = 0.0; }
1008 zi = p.z() + s*v.z() ;
1009 if (std::fabs(zi) <= tolODz)
1010 {
1011 // Z ok. Check phi
1012 //
1013 if ( !seg )
1014 {
1015 return s ;
1016 }
1017 else
1018 {
1019 xi = p.x() + s*v.x() ;
1020 yi = p.y() + s*v.y() ;
1021 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMin ;
1022 if (cosPsi >= cosHDPhiIT)
1023 {
1024 // Good inner radius isect
1025 // - but earlier phi isect still possible
1026
1027 snxt = s ;
1028 }
1029 }
1030 } // end if std::fabs(zi)
1031 } // end if (s>=0)
1032 } // end if (d>=0)
1033 } // end if (fRMin)
1034 }
1035
1036 // Phi segment intersection
1037 //
1038 // o Tolerant of points inside phi planes by up to kCarTolerance*0.5
1039 //
1040 // o NOTE: Large duplication of code between sphi & ephi checks
1041 // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane
1042 // intersection check <=0 -> >=0
1043 // -> use some form of loop Construct ?
1044 //
1045 if ( seg )
1046 {
1047 // First phi surface (Starting phi)
1048
1049 sinSPhi = std::sin(fSPhi) ;
1050 cosSPhi = std::cos(fSPhi) ;
1051 Comp = v.x()*sinSPhi - v.y()*cosSPhi ;
1052
1053 if ( Comp < 0 ) // Component in outwards normal dirn
1054 {
1055 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ;
1056
1057 if ( Dist < kCarTolerance*0.5 )
1058 {
1059 s = Dist/Comp ;
1060
1061 if (s < snxt)
1062 {
1063 if ( s < 0 ) { s = 0.0; }
1064 zi = p.z() + s*v.z() ;
1065 if ( std::fabs(zi) <= tolODz )
1066 {
1067 xi = p.x() + s*v.x() ;
1068 yi = p.y() + s*v.y() ;
1069 rho2 = xi*xi + yi*yi ;
1070
1071 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1072 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2)
1073 && ( v.y()*cosSPhi - v.x()*sinSPhi > 0 )
1074 && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 ) )
1075 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1076 && (v.y()*cosSPhi - v.x()*sinSPhi > 0)
1077 && (v.x()*cosSPhi + v.y()*sinSPhi < 0) ) )
1078 {
1079 // z and r intersections good
1080 // - check intersecting with correct half-plane
1081 //
1082 if ((yi*cosCPhi-xi*sinCPhi) <= 0) snxt = s ;
1083 }
1084 }
1085 }
1086 }
1087 }
1088
1089 // Second phi surface (`E'nding phi)
1090
1091 ePhi = fSPhi + fDPhi ;
1092 sinEPhi = std::sin(ePhi) ;
1093 cosEPhi = std::cos(ePhi) ;
1094 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ;
1095
1096 if (Comp < 0 ) // Component in outwards normal dirn
1097 {
1098 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ;
1099
1100 if ( Dist < kCarTolerance*0.5 )
1101 {
1102 s = Dist/Comp ;
1103
1104 if (s < snxt)
1105 {
1106 if ( s < 0 ) { s = 0; }
1107 zi = p.z() + s*v.z() ;
1108 if ( std::fabs(zi) <= tolODz )
1109 {
1110 xi = p.x() + s*v.x() ;
1111 yi = p.y() + s*v.y() ;
1112 rho2 = xi*xi + yi*yi ;
1113 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1114 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2)
1115 && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1116 && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) )
1117 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1118 && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1119 && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) )
1120 {
1121 // z and r intersections good
1122 // - check intersecting with correct half-plane
1123 //
1124 if ( (yi*cosCPhi-xi*sinCPhi) >= 0 ) { snxt = s; }
1125 }
1126 }
1127 }
1128 }
1129 } // Comp < 0
1130 } // seg != 0
1131 if ( snxt<kCarTolerance*0.5 ) { snxt=0; }
1132 return snxt ;
1133}
1134
1135//////////////////////////////////////////////////////////////////
1136//
1137// Calculate distance to shape from outside, along normalised vector
1138// - return kInfinity if no intersection, or intersection distance <= tolerance
1139//
1140// - Compute the intersection with the z planes
1141// - if at valid r, phi, return
1142//
1143// -> If point is outer outer radius, compute intersection with rmax
1144// - if at valid phi,z return
1145//
1146// -> Compute intersection with inner radius, taking largest +ve root
1147// - if valid (in z,phi), save intersction
1148//
1149// -> If phi segmented, compute intersections with phi half planes
1150// - return smallest of valid phi intersections and
1151// inner radius intersection
1152//
1153// NOTE:
1154// - Precalculations for phi trigonometry are Done `just in time'
1155// - `if valid' implies tolerant checking of intersection points
1156// Calculate distance (<= actual) to closest surface of shape from outside
1157// - Calculate distance to z, radial planes
1158// - Only to phi planes if outside phi extent
1159// - Return 0 if point inside
1160
1161G4double G4Tubs::DistanceToIn( const G4ThreeVector& p ) const
1162{
1163 G4double safe=0.0, rho, safe1, safe2, safe3 ;
1164 G4double phiC, cosPhiC, sinPhiC, safePhi, ePhi, cosPsi ;
1165
1166 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1167 safe1 = fRMin - rho ;
1168 safe2 = rho - fRMax ;
1169 safe3 = std::fabs(p.z()) - fDz ;
1170
1171 if ( safe1 > safe2 ) { safe = safe1; }
1172 else { safe = safe2; }
1173 if ( safe3 > safe ) { safe = safe3; }
1174
1175 if (fDPhi < twopi && rho)
1176 {
1177 phiC = fSPhi + fDPhi*0.5 ;
1178 cosPhiC = std::cos(phiC) ;
1179 sinPhiC = std::sin(phiC) ;
1180
1181 // Psi=angle from central phi to point
1182 //
1183 cosPsi = (p.x()*cosPhiC + p.y()*sinPhiC)/rho ;
1184
1185 if ( cosPsi < std::cos(fDPhi*0.5) )
1186 {
1187 // Point lies outside phi range
1188
1189 if ( (p.y()*cosPhiC - p.x()*sinPhiC) <= 0 )
1190 {
1191 safePhi = std::fabs(p.x()*std::sin(fSPhi) - p.y()*std::cos(fSPhi)) ;
1192 }
1193 else
1194 {
1195 ePhi = fSPhi + fDPhi ;
1196 safePhi = std::fabs(p.x()*std::sin(ePhi) - p.y()*std::cos(ePhi)) ;
1197 }
1198 if ( safePhi > safe ) { safe = safePhi; }
1199 }
1200 }
1201 if ( safe < 0 ) { safe = 0; }
1202 return safe ;
1203}
1204
1205//////////////////////////////////////////////////////////////////////////////
1206//
1207// Calculate distance to surface of shape from `inside', allowing for tolerance
1208// - Only Calc rmax intersection if no valid rmin intersection
1209
1210G4double G4Tubs::DistanceToOut( const G4ThreeVector& p,
1211 const G4ThreeVector& v,
1212 const G4bool calcNorm,
1213 G4bool *validNorm,
1214 G4ThreeVector *n ) const
1215{
1216 ESide side = kNull , sider = kNull, sidephi = kNull ;
1217 G4double snxt, sr = kInfinity, sphi = kInfinity, pdist ;
1218 G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ;
1219
1220 // Vars for phi intersection:
1221
1222 G4double sinSPhi, cosSPhi, ePhi, sinEPhi, cosEPhi ;
1223 G4double cPhi, sinCPhi, cosCPhi ;
1224 G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ;
1225
1226 // Z plane intersection
1227
1228 if (v.z() > 0 )
1229 {
1230 pdist = fDz - p.z() ;
1231 if ( pdist > kCarTolerance*0.5 )
1232 {
1233 snxt = pdist/v.z() ;
1234 side = kPZ ;
1235 }
1236 else
1237 {
1238 if (calcNorm)
1239 {
1240 *n = G4ThreeVector(0,0,1) ;
1241 *validNorm = true ;
1242 }
1243 return snxt = 0 ;
1244 }
1245 }
1246 else if ( v.z() < 0 )
1247 {
1248 pdist = fDz + p.z() ;
1249
1250 if ( pdist > kCarTolerance*0.5 )
1251 {
1252 snxt = -pdist/v.z() ;
1253 side = kMZ ;
1254 }
1255 else
1256 {
1257 if (calcNorm)
1258 {
1259 *n = G4ThreeVector(0,0,-1) ;
1260 *validNorm = true ;
1261 }
1262 return snxt = 0.0 ;
1263 }
1264 }
1265 else
1266 {
1267 snxt = kInfinity ; // Travel perpendicular to z axis
1268 side = kNull;
1269 }
1270
1271 // Radial Intersections
1272 //
1273 // Find intersction with cylinders at rmax/rmin
1274 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1275 //
1276 // Intersects with x^2+y^2=R^2
1277 //
1278 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
1279 //
1280 // t1 t2 t3
1281
1282 t1 = 1.0 - v.z()*v.z() ; // since v normalised
1283 t2 = p.x()*v.x() + p.y()*v.y() ;
1284 t3 = p.x()*p.x() + p.y()*p.y() ;
1285
1286 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fRMax*fRMax; }
1287 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; } // radius^2 on +-fDz
1288
1289 if ( t1 > 0 ) // Check not parallel
1290 {
1291 // Calculate sr, r exit distance
1292
1293 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) )
1294 {
1295 // Delta r not negative => leaving via rmax
1296
1297 deltaR = t3 - fRMax*fRMax ;
1298
1299 // NOTE: Should use rho-fRMax<-kRadTolerance*0.5
1300 // - avoid sqrt for efficiency
1301
1302 if ( deltaR < -kRadTolerance*fRMax )
1303 {
1304 b = t2/t1 ;
1305 c = deltaR/t1 ;
1306 d2= b*b-c;
1307 if(d2>=0.){sr = -b + std::sqrt(d2);}
1308 else{sr=0.;};
1309 sider = kRMax ;
1310 }
1311 else
1312 {
1313 // On tolerant boundary & heading outwards (or perpendicular to)
1314 // outer radial surface -> leaving immediately
1315
1316 if ( calcNorm )
1317 {
1318 // if ( p.x() || p.y() )
1319 // {
1320 // *n=G4ThreeVector(p.x(),p.y(),0);
1321 // }
1322 // else
1323 // {
1324 // *n=v;
1325 // }
1326 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1327 *validNorm = true ;
1328 }
1329 return snxt = 0 ; // Leaving by rmax immediately
1330 }
1331 }
1332 else if ( t2 < 0. ) // i.e. t2 < 0; Possible rmin intersection
1333 {
1334 roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement
1335
1336 if ( fRMin && (roMin2 < fRMin*(fRMin - kRadTolerance)) )
1337 {
1338 deltaR = t3 - fRMin*fRMin ;
1339 b = t2/t1 ;
1340 c = deltaR/t1 ;
1341 d2 = b*b - c ;
1342
1343 if ( d2 >= 0 ) // Leaving via rmin
1344 {
1345 // NOTE: SHould use rho-rmin>kRadTolerance*0.5
1346 // - avoid sqrt for efficiency
1347
1348 if (deltaR > kRadTolerance*fRMin)
1349 {
1350 sr = -b-std::sqrt(d2) ;
1351 sider = kRMin ;
1352 }
1353 else
1354 {
1355 if ( calcNorm ) { *validNorm = false; } // Concave side
1356 return snxt = 0.0;
1357 }
1358 }
1359 else // No rmin intersect -> must be rmax intersect
1360 {
1361 deltaR = t3 - fRMax*fRMax ;
1362 c = deltaR/t1 ;
1363 d2 = b*b-c;
1364 if(d2>=0.)
1365 {
1366 sr = -b + std::sqrt(d2) ;
1367 sider = kRMax ;
1368 }
1369 else // Case: On the border+t2<kRadTolerance
1370 // (v is perpendiculair to the surface)
1371 {
1372 if (calcNorm)
1373 {
1374 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1375 *validNorm = true ;
1376 }
1377 return snxt = 0.0;
1378 }
1379 }
1380 }
1381 else if ( roi2 > fRMax*(fRMax + kRadTolerance) )
1382 // No rmin intersect -> must be rmax intersect
1383 {
1384 deltaR = t3 - fRMax*fRMax ;
1385 b = t2/t1 ;
1386 c = deltaR/t1;
1387 d2 = b*b-c;
1388 if(d2>=0.)
1389 {
1390 sr = -b + std::sqrt(d2) ;
1391 sider = kRMax ;
1392 }
1393 else // Case: On the border+t2<kRadTolerance
1394 // (v is perpendiculair to the surface)
1395 {
1396 if (calcNorm)
1397 {
1398 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1399 *validNorm = true ;
1400 }
1401 return snxt = 0.0;
1402 }
1403 }
1404 }
1405
1406 // Phi Intersection
1407
1408 if ( fDPhi < twopi )
1409 {
1410 sinSPhi = std::sin(fSPhi) ;
1411 cosSPhi = std::cos(fSPhi) ;
1412 ePhi = fSPhi + fDPhi ;
1413 sinEPhi = std::sin(ePhi) ;
1414 cosEPhi = std::cos(ePhi) ;
1415 cPhi = fSPhi + fDPhi*0.5 ;
1416 sinCPhi = std::sin(cPhi) ;
1417 cosCPhi = std::cos(cPhi) ;
1418
1419 // add angle calculation with correction
1420 // of the difference in domain of atan2 and Sphi
1421 //
1422 vphi = std::atan2(v.y(),v.x()) ;
1423
1424 if ( vphi < fSPhi - kAngTolerance*0.5 ) { vphi += twopi; }
1425 else if ( vphi > fSPhi + fDPhi + kAngTolerance*0.5 ) { vphi -= twopi; }
1426
1427
1428 if ( p.x() || p.y() ) // Check if on z axis (rho not needed later)
1429 {
1430 // pDist -ve when inside
1431
1432 pDistS = p.x()*sinSPhi - p.y()*cosSPhi ;
1433 pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ;
1434
1435 // Comp -ve when in direction of outwards normal
1436
1437 compS = -sinSPhi*v.x() + cosSPhi*v.y() ;
1438 compE = sinEPhi*v.x() - cosEPhi*v.y() ;
1439 sidephi = kNull;
1440
1441 if( ( (fDPhi <= pi) && ( (pDistS <= 0.5*kCarTolerance)
1442 && (pDistE <= 0.5*kCarTolerance) ) )
1443 || ( (fDPhi > pi) && !((pDistS > 0.5*kCarTolerance)
1444 && (pDistE > 0.5*kCarTolerance) ) ) )
1445 {
1446 // Inside both phi *full* planes
1447
1448 if ( compS < 0 )
1449 {
1450 sphi = pDistS/compS ;
1451
1452 if (sphi >= -0.5*kCarTolerance)
1453 {
1454 xi = p.x() + sphi*v.x() ;
1455 yi = p.y() + sphi*v.y() ;
1456
1457 // Check intersecting with correct half-plane
1458 // (if not -> no intersect)
1459 //
1460 if((std::abs(xi)<=kCarTolerance)&&(std::abs(yi)<=kCarTolerance))
1461 { sidephi = kSPhi;
1462 if (((fSPhi-0.5*kAngTolerance)<=vphi)
1463 &&((ePhi+0.5*kAngTolerance)>=vphi))
1464 {
1465 sphi = kInfinity;
1466 }
1467 }
1468 else if ((yi*cosCPhi-xi*sinCPhi)>=0)
1469 {
1470 sphi = kInfinity ;
1471 }
1472 else
1473 {
1474 sidephi = kSPhi ;
1475 if ( pDistS > -kCarTolerance*0.5 )
1476 {
1477 sphi = 0.0 ; // Leave by sphi immediately
1478 }
1479 }
1480 }
1481 else
1482 {
1483 sphi = kInfinity ;
1484 }
1485 }
1486 else
1487 {
1488 sphi = kInfinity ;
1489 }
1490
1491 if ( compE < 0 )
1492 {
1493 sphi2 = pDistE/compE ;
1494
1495 // Only check further if < starting phi intersection
1496 //
1497 if ( (sphi2 > -0.5*kCarTolerance) && (sphi2 < sphi) )
1498 {
1499 xi = p.x() + sphi2*v.x() ;
1500 yi = p.y() + sphi2*v.y() ;
1501
1502 if ((std::abs(xi)<=kCarTolerance)&&(std::abs(yi)<=kCarTolerance))
1503 {
1504 // Leaving via ending phi
1505 //
1506 if(!(((fSPhi-0.5*kAngTolerance)<=vphi)
1507 &&((ePhi+0.5*kAngTolerance)>=vphi)))
1508 {
1509 sidephi = kEPhi ;
1510 if ( pDistE <= -kCarTolerance*0.5 ) { sphi = sphi2 ; }
1511 else { sphi = 0.0 ; }
1512 }
1513 }
1514 else // Check intersecting with correct half-plane
1515
1516 if ( (yi*cosCPhi-xi*sinCPhi) >= 0)
1517 {
1518 // Leaving via ending phi
1519 //
1520 sidephi = kEPhi ;
1521 if ( pDistE <= -kCarTolerance*0.5 ) { sphi = sphi2 ; }
1522 else { sphi = 0.0 ; }
1523 }
1524 }
1525 }
1526 }
1527 else
1528 {
1529 sphi = kInfinity ;
1530 }
1531 }
1532 else
1533 {
1534 // On z axis + travel not || to z axis -> if phi of vector direction
1535 // within phi of shape, Step limited by rmax, else Step =0
1536
1537 // vphi = std::atan2(v.y(),v.x()) ;//defined previosly
1538 // G4cout<<"In axis vphi="<<vphi
1539 // <<" Sphi="<<fSPhi<<" Ephi="<<ePhi<<G4endl;
1540 // old if ( (fSPhi < vphi) && (vphi < fSPhi + fDPhi) )
1541 // new : correction for if statement, must be '<='
1542
1543 if ( ((fSPhi-0.5*kAngTolerance) <= vphi)
1544 && (vphi <=( ePhi+0.5*kAngTolerance) ))
1545 {
1546 sphi = kInfinity ;
1547 }
1548 else
1549 {
1550 sidephi = kSPhi ; // arbitrary
1551 sphi = 0.0 ;
1552 }
1553 }
1554 if (sphi < snxt) // Order intersecttions
1555 {
1556 snxt = sphi ;
1557 side = sidephi ;
1558 }
1559 }
1560 if (sr < snxt) // Order intersections
1561 {
1562 snxt = sr ;
1563 side = sider ;
1564 }
1565 }
1566 if (calcNorm)
1567 {
1568 switch(side)
1569 {
1570 case kRMax:
1571 // Note: returned vector not normalised
1572 // (divide by fRMax for unit vector)
1573 //
1574 xi = p.x() + snxt*v.x() ;
1575 yi = p.y() + snxt*v.y() ;
1576 *n = G4ThreeVector(xi/fRMax,yi/fRMax,0) ;
1577 *validNorm = true ;
1578 break ;
1579
1580 case kRMin:
1581 *validNorm = false ; // Rmin is inconvex
1582 break ;
1583
1584 case kSPhi:
1585 if ( fDPhi <= pi )
1586 {
1587 *n = G4ThreeVector(std::sin(fSPhi),-std::cos(fSPhi),0) ;
1588 *validNorm = true ;
1589 }
1590 else
1591 {
1592 *validNorm = false ;
1593 }
1594 break ;
1595
1596 case kEPhi:
1597 if (fDPhi <= pi)
1598 {
1599 *n = G4ThreeVector(-std::sin(fSPhi+fDPhi),std::cos(fSPhi+fDPhi),0) ;
1600 *validNorm = true ;
1601 }
1602 else
1603 {
1604 *validNorm = false ;
1605 }
1606 break ;
1607
1608 case kPZ:
1609 *n=G4ThreeVector(0,0,1) ;
1610 *validNorm=true ;
1611 break ;
1612
1613 case kMZ:
1614 *n = G4ThreeVector(0,0,-1) ;
1615 *validNorm = true ;
1616 break ;
1617
1618 default:
1619 G4cout.precision(16) ;
1620 G4cout << G4endl ;
1621 DumpInfo();
1622 G4cout << "Position:" << G4endl << G4endl ;
1623 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
1624 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
1625 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
1626 G4cout << "Direction:" << G4endl << G4endl ;
1627 G4cout << "v.x() = " << v.x() << G4endl ;
1628 G4cout << "v.y() = " << v.y() << G4endl ;
1629 G4cout << "v.z() = " << v.z() << G4endl << G4endl ;
1630 G4cout << "Proposed distance :" << G4endl << G4endl ;
1631 G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl ;
1632 G4Exception("G4Tubs::DistanceToOut(p,v,..)","Notification",JustWarning,
1633 "Undefined side for valid surface normal to solid.");
1634 break ;
1635 }
1636 }
1637 if ( snxt<kCarTolerance*0.5 ) { snxt=0 ; }
1638
1639 return snxt ;
1640}
1641
1642//////////////////////////////////////////////////////////////////////////
1643//
1644// Calculate distance (<=actual) to closest surface of shape from inside
1645
1646G4double G4Tubs::DistanceToOut( const G4ThreeVector& p ) const
1647{
1648 G4double safe=0.0, rho, safeR1, safeR2, safeZ ;
1649 G4double safePhi, phiC, cosPhiC, sinPhiC, ePhi ;
1650 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1651
1652#ifdef G4CSGDEBUG
1653 if( Inside(p) == kOutside )
1654 {
1655 G4cout.precision(16) ;
1656 G4cout << G4endl ;
1657 DumpInfo();
1658 G4cout << "Position:" << G4endl << G4endl ;
1659 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
1660 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
1661 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
1662 G4Exception("G4Tubs::DistanceToOut(p)", "Notification", JustWarning,
1663 "Point p is outside !?");
1664 }
1665#endif
1666
1667 if ( fRMin )
1668 {
1669 safeR1 = rho - fRMin ;
1670 safeR2 = fRMax - rho ;
1671
1672 if ( safeR1 < safeR2 ) { safe = safeR1 ; }
1673 else { safe = safeR2 ; }
1674 }
1675 else
1676 {
1677 safe = fRMax - rho ;
1678 }
1679 safeZ = fDz - std::fabs(p.z()) ;
1680
1681 if ( safeZ < safe ) { safe = safeZ ; }
1682
1683 // Check if phi divided, Calc distances closest phi plane
1684 //
1685 if ( fDPhi < twopi )
1686 {
1687 // Above/below central phi of Tubs?
1688
1689 phiC = fSPhi + fDPhi*0.5 ;
1690 cosPhiC = std::cos(phiC) ;
1691 sinPhiC = std::sin(phiC) ;
1692
1693 if ( (p.y()*cosPhiC - p.x()*sinPhiC) <= 0 )
1694 {
1695 safePhi = -(p.x()*std::sin(fSPhi) - p.y()*std::cos(fSPhi)) ;
1696 }
1697 else
1698 {
1699 ePhi = fSPhi + fDPhi ;
1700 safePhi = (p.x()*std::sin(ePhi) - p.y()*std::cos(ePhi)) ;
1701 }
1702 if (safePhi < safe) { safe = safePhi ; }
1703 }
1704 if ( safe < 0 ) { safe = 0 ; }
1705
1706 return safe ;
1707}
1708
1709/////////////////////////////////////////////////////////////////////////
1710//
1711// Create a List containing the transformed vertices
1712// Ordering [0-3] -fDz cross section
1713// [4-7] +fDz cross section such that [0] is below [4],
1714// [1] below [5] etc.
1715// Note:
1716// Caller has deletion resposibility
1717// Potential improvement: For last slice, use actual ending angle
1718// to avoid rounding error problems.
1719
1720G4ThreeVectorList*
1721G4Tubs::CreateRotatedVertices( const G4AffineTransform& pTransform ) const
1722{
1723 G4ThreeVectorList* vertices ;
1724 G4ThreeVector vertex0, vertex1, vertex2, vertex3 ;
1725 G4double meshAngle, meshRMax, crossAngle,
1726 cosCrossAngle, sinCrossAngle, sAngle;
1727 G4double rMaxX, rMaxY, rMinX, rMinY, meshRMin ;
1728 G4int crossSection, noCrossSections;
1729
1730 // Compute no of cross-sections necessary to mesh tube
1731 //
1732 noCrossSections = G4int(fDPhi/kMeshAngleDefault) + 1 ;
1733
1734 if ( noCrossSections < kMinMeshSections )
1735 {
1736 noCrossSections = kMinMeshSections ;
1737 }
1738 else if (noCrossSections>kMaxMeshSections)
1739 {
1740 noCrossSections = kMaxMeshSections ;
1741 }
1742 // noCrossSections = 4 ;
1743
1744 meshAngle = fDPhi/(noCrossSections - 1) ;
1745 // meshAngle = fDPhi/(noCrossSections) ;
1746
1747 meshRMax = (fRMax+100*kCarTolerance)/std::cos(meshAngle*0.5) ;
1748 meshRMin = fRMin - 100*kCarTolerance ;
1749
1750 // If complete in phi, set start angle such that mesh will be at fRMax
1751 // on the x axis. Will give better extent calculations when not rotated.
1752
1753 if (fDPhi == pi*2.0 && fSPhi == 0 ) { sAngle = -meshAngle*0.5 ; }
1754 else { sAngle = fSPhi ; }
1755
1756 vertices = new G4ThreeVectorList();
1757 vertices->reserve(noCrossSections*4);
1758
1759 if ( vertices )
1760 {
1761 for (crossSection = 0 ; crossSection < noCrossSections ; crossSection++ )
1762 {
1763 // Compute coordinates of cross section at section crossSection
1764
1765 crossAngle = sAngle + crossSection*meshAngle ;
1766 cosCrossAngle = std::cos(crossAngle) ;
1767 sinCrossAngle = std::sin(crossAngle) ;
1768
1769 rMaxX = meshRMax*cosCrossAngle ;
1770 rMaxY = meshRMax*sinCrossAngle ;
1771
1772 if(meshRMin <= 0.0)
1773 {
1774 rMinX = 0.0 ;
1775 rMinY = 0.0 ;
1776 }
1777 else
1778 {
1779 rMinX = meshRMin*cosCrossAngle ;
1780 rMinY = meshRMin*sinCrossAngle ;
1781 }
1782 vertex0 = G4ThreeVector(rMinX,rMinY,-fDz) ;
1783 vertex1 = G4ThreeVector(rMaxX,rMaxY,-fDz) ;
1784 vertex2 = G4ThreeVector(rMaxX,rMaxY,+fDz) ;
1785 vertex3 = G4ThreeVector(rMinX,rMinY,+fDz) ;
1786
1787 vertices->push_back(pTransform.TransformPoint(vertex0)) ;
1788 vertices->push_back(pTransform.TransformPoint(vertex1)) ;
1789 vertices->push_back(pTransform.TransformPoint(vertex2)) ;
1790 vertices->push_back(pTransform.TransformPoint(vertex3)) ;
1791 }
1792 }
1793 else
1794 {
1795 DumpInfo();
1796 G4Exception("G4Tubs::CreateRotatedVertices()",
1797 "FatalError", FatalException,
1798 "Error in allocation of vertices. Out of memory !");
1799 }
1800 return vertices ;
1801}
1802
1803//////////////////////////////////////////////////////////////////////////
1804//
1805// Stream object contents to an output stream
1806
1807G4GeometryType G4Tubs::GetEntityType() const
1808{
1809 return G4String("G4Tubs");
1810}
1811
1812//////////////////////////////////////////////////////////////////////////
1813//
1814// Stream object contents to an output stream
1815
1816std::ostream& G4Tubs::StreamInfo( std::ostream& os ) const
1817{
1818 os << "-----------------------------------------------------------\n"
1819 << " *** Dump for solid - " << GetName() << " ***\n"
1820 << " ===================================================\n"
1821 << " Solid type: G4Tubs\n"
1822 << " Parameters: \n"
1823 << " inner radius : " << fRMin/mm << " mm \n"
1824 << " outer radius : " << fRMax/mm << " mm \n"
1825 << " half length Z: " << fDz/mm << " mm \n"
1826 << " starting phi : " << fSPhi/degree << " degrees \n"
1827 << " delta phi : " << fDPhi/degree << " degrees \n"
1828 << "-----------------------------------------------------------\n";
1829
1830 return os;
1831}
1832
1833/////////////////////////////////////////////////////////////////////////
1834//
1835// GetPointOnSurface
1836
1837G4ThreeVector G4Tubs::GetPointOnSurface() const
1838{
1839 G4double xRand, yRand, zRand, phi, cosphi, sinphi, chose,
1840 aOne, aTwo, aThr, aFou;
1841 G4double rRand;
1842
1843 aOne = 2.*fDz*fDPhi*fRMax;
1844 aTwo = 2.*fDz*fDPhi*fRMin;
1845 aThr = 0.5*fDPhi*(fRMax*fRMax-fRMin*fRMin);
1846 aFou = 2.*fDz*(fRMax-fRMin);
1847
1848 phi = RandFlat::shoot(fSPhi, fSPhi+fDPhi);
1849 cosphi = std::cos(phi);
1850 sinphi = std::sin(phi);
1851
1852 rRand = RandFlat::shoot(fRMin,fRMax);
1853
1854 if( (fSPhi == 0) && (fDPhi == twopi) ) { aFou = 0; }
1855
1856 chose = RandFlat::shoot(0.,aOne+aTwo+2.*aThr+2.*aFou);
1857
1858 if( (chose >=0) && (chose < aOne) )
1859 {
1860 xRand = fRMax*cosphi;
1861 yRand = fRMax*sinphi;
1862 zRand = RandFlat::shoot(-1.*fDz,fDz);
1863 return G4ThreeVector (xRand, yRand, zRand);
1864 }
1865 else if( (chose >= aOne) && (chose < aOne + aTwo) )
1866 {
1867 xRand = fRMin*cosphi;
1868 yRand = fRMin*sinphi;
1869 zRand = RandFlat::shoot(-1.*fDz,fDz);
1870 return G4ThreeVector (xRand, yRand, zRand);
1871 }
1872 else if( (chose >= aOne + aTwo) && (chose < aOne + aTwo + aThr) )
1873 {
1874 xRand = rRand*cosphi;
1875 yRand = rRand*sinphi;
1876 zRand = fDz;
1877 return G4ThreeVector (xRand, yRand, zRand);
1878 }
1879 else if( (chose >= aOne + aTwo + aThr) && (chose < aOne + aTwo + 2.*aThr) )
1880 {
1881 xRand = rRand*cosphi;
1882 yRand = rRand*sinphi;
1883 zRand = -1.*fDz;
1884 return G4ThreeVector (xRand, yRand, zRand);
1885 }
1886 else if( (chose >= aOne + aTwo + 2.*aThr)
1887 && (chose < aOne + aTwo + 2.*aThr + aFou) )
1888 {
1889 xRand = rRand*std::cos(fSPhi);
1890 yRand = rRand*std::sin(fSPhi);
1891 zRand = RandFlat::shoot(-1.*fDz,fDz);
1892 return G4ThreeVector (xRand, yRand, zRand);
1893 }
1894 else
1895 {
1896 xRand = rRand*std::cos(fSPhi+fDPhi);
1897 yRand = rRand*std::sin(fSPhi+fDPhi);
1898 zRand = RandFlat::shoot(-1.*fDz,fDz);
1899 return G4ThreeVector (xRand, yRand, zRand);
1900 }
1901}
1902
1903///////////////////////////////////////////////////////////////////////////
1904//
1905// Methods for visualisation
1906
1907void G4Tubs::DescribeYourselfTo ( G4VGraphicsScene& scene ) const
1908{
1909 scene.AddSolid (*this) ;
1910}
1911
1912G4Polyhedron* G4Tubs::CreatePolyhedron () const
1913{
1914 return new G4PolyhedronTubs (fRMin, fRMax, fDz, fSPhi, fDPhi) ;
1915}
1916
1917G4NURBS* G4Tubs::CreateNURBS () const
1918{
1919 G4NURBS* pNURBS ;
1920 if (fRMin != 0)
1921 {
1922 if (fDPhi >= twopi)
1923 {
1924 pNURBS = new G4NURBStube (fRMin,fRMax,fDz) ;
1925 }
1926 else
1927 {
1928 pNURBS = new G4NURBStubesector (fRMin,fRMax,fDz,fSPhi,fSPhi+fDPhi) ;
1929 }
1930 }
1931 else
1932 {
1933 if (fDPhi >= twopi)
1934 {
1935 pNURBS = new G4NURBScylinder (fRMax,fDz) ;
1936 }
1937 else
1938 {
1939 const G4double epsilon = 1.e-4 ; // Cylinder sector not yet available!
1940 pNURBS = new G4NURBStubesector (epsilon,fRMax,fDz,fSPhi,fSPhi+fDPhi) ;
1941 }
1942 }
1943 return pNURBS ;
1944}
Note: See TracBrowser for help on using the repository browser.