source: trunk/source/geometry/solids/CSG/src/G4Trd.cc@ 1349

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

tag geant4.9.4 beta 1 + modifs locales

File size: 37.5 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//
27// $Id: G4Trd.cc,v 1.34 2006/10/19 15:33:38 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-04-beta-01 $
29//
30//
31// Implementation for G4Trd class
32//
33// History:
34//
35// 28.04.05 V.Grichine: new SurfaceNormal according to J. Apostolakis proposal
36// 26.04.05, V.Grichine, new SurfaceNoramal is default
37// 07.12.04, V.Grichine, SurfaceNoramal with edges/vertices.
38// 07.05.00, V.Grichine, in d = DistanceToIn(p,v), if d<0.5*kCarTolerance, d=0
39// ~1996, V.Grichine, 1st implementation based on old code of P.Kent
40//
41//////////////////////////////////////////////////////////////////////////////
42
43#include "G4Trd.hh"
44
45#include "G4VPVParameterisation.hh"
46#include "G4VoxelLimits.hh"
47#include "G4AffineTransform.hh"
48#include "Randomize.hh"
49
50#include "G4VGraphicsScene.hh"
51#include "G4Polyhedron.hh"
52#include "G4NURBS.hh"
53#include "G4NURBSbox.hh"
54
55using namespace CLHEP;
56
57/////////////////////////////////////////////////////////////////////////
58//
59// Constructor - check & set half widths
60
61G4Trd::G4Trd( const G4String& pName,
62 G4double pdx1, G4double pdx2,
63 G4double pdy1, G4double pdy2,
64 G4double pdz )
65 : G4CSGSolid(pName)
66{
67 CheckAndSetAllParameters (pdx1, pdx2, pdy1, pdy2, pdz);
68}
69
70/////////////////////////////////////////////////////////////////////////
71//
72// Set and check (coplanarity) of trd parameters
73
74void G4Trd::CheckAndSetAllParameters ( G4double pdx1, G4double pdx2,
75 G4double pdy1, G4double pdy2,
76 G4double pdz )
77{
78 if ( pdx1>0&&pdx2>0&&pdy1>0&&pdy2>0&&pdz>0 )
79 {
80 fDx1=pdx1; fDx2=pdx2;
81 fDy1=pdy1; fDy2=pdy2;
82 fDz=pdz;
83 }
84 else
85 {
86 if ( pdx1>=0 && pdx2>=0 && pdy1>=0 && pdy2>=0 && pdz>=0 )
87 {
88 // G4double Minimum_length= (1+per_thousand) * kCarTolerance/2.;
89 // FIX-ME : temporary solution for ZERO or very-small parameters
90 //
91 G4double Minimum_length= kCarTolerance/2.;
92 fDx1=std::max(pdx1,Minimum_length);
93 fDx2=std::max(pdx2,Minimum_length);
94 fDy1=std::max(pdy1,Minimum_length);
95 fDy2=std::max(pdy2,Minimum_length);
96 fDz=std::max(pdz,Minimum_length);
97 }
98 else
99 {
100 G4cerr << "ERROR - G4Trd()::CheckAndSetAllParameters(): " << GetName()
101 << G4endl
102 << " Invalid dimensions, some are < 0 !" << G4endl
103 << " X - " << pdx1 << ", " << pdx2 << G4endl
104 << " Y - " << pdy1 << ", " << pdy2 << G4endl
105 << " Z - " << pdz << G4endl;
106 G4Exception("G4Trd::CheckAndSetAllParameters()",
107 "InvalidSetup", FatalException,
108 "Invalid parameters.");
109 }
110 }
111 fCubicVolume= 0.;
112 fSurfaceArea= 0.;
113 fpPolyhedron = 0;
114}
115
116///////////////////////////////////////////////////////////////////////
117//
118// Fake default constructor - sets only member data and allocates memory
119// for usage restricted to object persistency.
120//
121G4Trd::G4Trd( __void__& a )
122 : G4CSGSolid(a)
123{
124}
125
126//////////////////////////////////////////////////////////////////////////
127//
128// Destructor
129
130G4Trd::~G4Trd()
131{
132}
133
134////////////////////////////////////////////////////////////////////////////
135//
136//
137
138void G4Trd::SetAllParameters ( G4double pdx1, G4double pdx2, G4double pdy1,
139 G4double pdy2, G4double pdz )
140{
141 CheckAndSetAllParameters (pdx1, pdx2, pdy1, pdy2, pdz);
142}
143
144
145/////////////////////////////////////////////////////////////////////////
146//
147// Dispatch to parameterisation for replication mechanism dimension
148// computation & modification.
149
150void G4Trd::ComputeDimensions( G4VPVParameterisation* p,
151 const G4int n,
152 const G4VPhysicalVolume* pRep )
153{
154 p->ComputeDimensions(*this,n,pRep);
155}
156
157
158///////////////////////////////////////////////////////////////////////////
159//
160// Calculate extent under transform and specified limit
161
162G4bool G4Trd::CalculateExtent( const EAxis pAxis,
163 const G4VoxelLimits& pVoxelLimit,
164 const G4AffineTransform& pTransform,
165 G4double& pMin, G4double& pMax ) const
166{
167 if (!pTransform.IsRotated())
168 {
169 // Special case handling for unrotated solids
170 // Compute x/y/z mins and maxs respecting limits, with early returns
171 // if outside limits. Then switch() on pAxis
172
173 G4double xoffset,xMin,xMax;
174 G4double yoffset,yMin,yMax;
175 G4double zoffset,zMin,zMax;
176
177 zoffset=pTransform.NetTranslation().z();
178 zMin=zoffset-fDz;
179 zMax=zoffset+fDz;
180 if (pVoxelLimit.IsZLimited())
181 {
182 if ( (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance)
183 || (zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance) )
184 {
185 return false;
186 }
187 else
188 {
189 if (zMin<pVoxelLimit.GetMinZExtent())
190 {
191 zMin=pVoxelLimit.GetMinZExtent();
192 }
193 if (zMax>pVoxelLimit.GetMaxZExtent())
194 {
195 zMax=pVoxelLimit.GetMaxZExtent();
196 }
197 }
198 }
199 xoffset=pTransform.NetTranslation().x();
200 if (fDx2 >= fDx1)
201 {
202 xMax = xoffset+(fDx1+fDx2)/2+(zMax-zoffset)*(fDx2-fDx1)/(2*fDz) ;
203 xMin = 2*xoffset - xMax ;
204 }
205 else
206 {
207 xMax = xoffset+(fDx1+fDx2)/2+(zMin-zoffset)*(fDx2-fDx1)/(2*fDz) ;
208 xMin = 2*xoffset - xMax ;
209 }
210 if (pVoxelLimit.IsXLimited())
211 {
212 if ( (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance)
213 || (xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance) )
214 {
215 return false;
216 }
217 else
218 {
219 if (xMin<pVoxelLimit.GetMinXExtent())
220 {
221 xMin=pVoxelLimit.GetMinXExtent();
222 }
223 if (xMax>pVoxelLimit.GetMaxXExtent())
224 {
225 xMax=pVoxelLimit.GetMaxXExtent();
226 }
227 }
228 }
229 yoffset= pTransform.NetTranslation().y() ;
230 if(fDy2 >= fDy1)
231 {
232 yMax = yoffset+(fDy2+fDy1)/2+(zMax-zoffset)*(fDy2-fDy1)/(2*fDz) ;
233 yMin = 2*yoffset - yMax ;
234 }
235 else
236 {
237 yMax = yoffset+(fDy2+fDy1)/2+(zMin-zoffset)*(fDy2-fDy1)/(2*fDz) ;
238 yMin = 2*yoffset - yMax ;
239 }
240 if (pVoxelLimit.IsYLimited())
241 {
242 if ( (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance)
243 || (yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance) )
244 {
245 return false;
246 }
247 else
248 {
249 if (yMin<pVoxelLimit.GetMinYExtent())
250 {
251 yMin=pVoxelLimit.GetMinYExtent();
252 }
253 if (yMax>pVoxelLimit.GetMaxYExtent())
254 {
255 yMax=pVoxelLimit.GetMaxYExtent();
256 }
257 }
258 }
259
260 switch (pAxis)
261 {
262 case kXAxis:
263 pMin=xMin;
264 pMax=xMax;
265 break;
266 case kYAxis:
267 pMin=yMin;
268 pMax=yMax;
269 break;
270 case kZAxis:
271 pMin=zMin;
272 pMax=zMax;
273 break;
274 default:
275 break;
276 }
277
278 // Add 2*Tolerance to avoid precision troubles ?
279 //
280 pMin-=kCarTolerance;
281 pMax+=kCarTolerance;
282
283 return true;
284 }
285 else
286 {
287 // General rotated case - create and clip mesh to boundaries
288
289 G4bool existsAfterClip=false;
290 G4ThreeVectorList *vertices;
291
292 pMin=+kInfinity;
293 pMax=-kInfinity;
294
295 // Calculate rotated vertex coordinates
296 //
297 vertices=CreateRotatedVertices(pTransform);
298 ClipCrossSection(vertices,0,pVoxelLimit,pAxis,pMin,pMax);
299 ClipCrossSection(vertices,4,pVoxelLimit,pAxis,pMin,pMax);
300 ClipBetweenSections(vertices,0,pVoxelLimit,pAxis,pMin,pMax);
301
302 if (pMin!=kInfinity||pMax!=-kInfinity)
303 {
304 existsAfterClip=true;
305
306 // Add 2*tolerance to avoid precision troubles
307 //
308 pMin-=kCarTolerance;
309 pMax+=kCarTolerance;
310
311 }
312 else
313 {
314 // Check for case where completely enveloping clipping volume
315 // If point inside then we are confident that the solid completely
316 // envelopes the clipping volume. Hence set min/max extents according
317 // to clipping volume extents along the specified axis.
318
319 G4ThreeVector clipCentre(
320 (pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5,
321 (pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5,
322 (pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5);
323
324 if (Inside(pTransform.Inverse().TransformPoint(clipCentre))!=kOutside)
325 {
326 existsAfterClip=true;
327 pMin=pVoxelLimit.GetMinExtent(pAxis);
328 pMax=pVoxelLimit.GetMaxExtent(pAxis);
329 }
330 }
331 delete vertices;
332 return existsAfterClip;
333 }
334}
335
336///////////////////////////////////////////////////////////////////
337//
338// Return whether point inside/outside/on surface, using tolerance
339
340EInside G4Trd::Inside( const G4ThreeVector& p ) const
341{
342 EInside in=kOutside;
343 G4double x,y,zbase1,zbase2;
344
345 if (std::fabs(p.z())<=fDz-kCarTolerance/2)
346 {
347 zbase1=p.z()+fDz; // Dist from -ve z plane
348 zbase2=fDz-p.z(); // Dist from +ve z plane
349
350 // Check whether inside x tolerance
351 //
352 x=0.5*(fDx2*zbase1+fDx1*zbase2)/fDz - kCarTolerance/2;
353 if (std::fabs(p.x())<=x)
354 {
355 y=0.5*((fDy2*zbase1+fDy1*zbase2))/fDz - kCarTolerance/2;
356 if (std::fabs(p.y())<=y)
357 {
358 in=kInside;
359 }
360 else if (std::fabs(p.y())<=y+kCarTolerance)
361 {
362 in=kSurface;
363 }
364 }
365 else if (std::fabs(p.x())<=x+kCarTolerance)
366 {
367 // y = y half width of shape at z of point + tolerant boundary
368 //
369 y=0.5*((fDy2*zbase1+fDy1*zbase2))/fDz + kCarTolerance/2;
370 if (std::fabs(p.y())<=y)
371 {
372 in=kSurface;
373 }
374 }
375 }
376 else if (std::fabs(p.z())<=fDz+kCarTolerance/2)
377 {
378 // Only need to check outer tolerant boundaries
379 //
380 zbase1=p.z()+fDz; // Dist from -ve z plane
381 zbase2=fDz-p.z(); // Dist from +ve z plane
382
383 // x = x half width of shape at z of point plus tolerance
384 //
385 x=0.5*(fDx2*zbase1+fDx1*zbase2)/fDz + kCarTolerance/2;
386 if (std::fabs(p.x())<=x)
387 {
388 // y = y half width of shape at z of point
389 //
390 y=0.5*((fDy2*zbase1+fDy1*zbase2))/fDz + kCarTolerance/2;
391 if (std::fabs(p.y())<=y) in=kSurface;
392 }
393 }
394 return in;
395}
396
397//////////////////////////////////////////////////////////////////////////
398//
399// Calculate side nearest to p, and return normal
400// If two sides are equidistant, normal of first side (x/y/z)
401// encountered returned
402
403G4ThreeVector G4Trd::SurfaceNormal( const G4ThreeVector& p ) const
404{
405 G4ThreeVector norm, sumnorm(0.,0.,0.);
406 G4int noSurfaces = 0;
407 G4double z = 2.0*fDz, tanx, secx, newpx, widx;
408 G4double tany, secy, newpy, widy;
409 G4double distx, disty, distz, fcos;
410 G4double delta = 0.5*kCarTolerance;
411
412 tanx = (fDx2 - fDx1)/z;
413 secx = std::sqrt(1.0+tanx*tanx);
414 newpx = std::fabs(p.x())-p.z()*tanx;
415 widx = fDx2 - fDz*tanx;
416
417 tany = (fDy2 - fDy1)/z;
418 secy = std::sqrt(1.0+tany*tany);
419 newpy = std::fabs(p.y())-p.z()*tany;
420 widy = fDy2 - fDz*tany;
421
422 distx = std::fabs(newpx-widx)/secx; // perp. distance to x side
423 disty = std::fabs(newpy-widy)/secy; // to y side
424 distz = std::fabs(std::fabs(p.z())-fDz); // to z side
425
426 fcos = 1.0/secx;
427 G4ThreeVector nX = G4ThreeVector( fcos,0,-tanx*fcos);
428 G4ThreeVector nmX = G4ThreeVector(-fcos,0,-tanx*fcos);
429
430 fcos = 1.0/secy;
431 G4ThreeVector nY = G4ThreeVector(0, fcos,-tany*fcos);
432 G4ThreeVector nmY = G4ThreeVector(0,-fcos,-tany*fcos);
433 G4ThreeVector nZ = G4ThreeVector( 0, 0, 1.0);
434
435 if (distx <= delta)
436 {
437 noSurfaces ++;
438 if ( p.x() >= 0.) sumnorm += nX;
439 else sumnorm += nmX;
440 }
441 if (disty <= delta)
442 {
443 noSurfaces ++;
444 if ( p.y() >= 0.) sumnorm += nY;
445 else sumnorm += nmY;
446 }
447 if (distz <= delta)
448 {
449 noSurfaces ++;
450 if ( p.z() >= 0.) sumnorm += nZ;
451 else sumnorm -= nZ;
452 }
453 if ( noSurfaces == 0 )
454 {
455#ifdef G4CSGDEBUG
456 G4Exception("G4Trd::SurfaceNormal(p)", "Notification", JustWarning,
457 "Point p is not on surface !?" );
458#endif
459 norm = ApproxSurfaceNormal(p);
460 }
461 else if ( noSurfaces == 1 ) norm = sumnorm;
462 else norm = sumnorm.unit();
463 return norm;
464}
465
466
467/////////////////////////////////////////////////////////////////////////////
468//
469// Algorithm for SurfaceNormal() following the original specification
470// for points not on the surface
471
472G4ThreeVector G4Trd::ApproxSurfaceNormal( const G4ThreeVector& p ) const
473{
474 G4ThreeVector norm;
475 G4double z,tanx,secx,newpx,widx;
476 G4double tany,secy,newpy,widy;
477 G4double distx,disty,distz,fcos;
478
479 z=2.0*fDz;
480
481 tanx=(fDx2-fDx1)/z;
482 secx=std::sqrt(1.0+tanx*tanx);
483 newpx=std::fabs(p.x())-p.z()*tanx;
484 widx=fDx2-fDz*tanx;
485
486 tany=(fDy2-fDy1)/z;
487 secy=std::sqrt(1.0+tany*tany);
488 newpy=std::fabs(p.y())-p.z()*tany;
489 widy=fDy2-fDz*tany;
490
491 distx=std::fabs(newpx-widx)/secx; // perpendicular distance to x side
492 disty=std::fabs(newpy-widy)/secy; // to y side
493 distz=std::fabs(std::fabs(p.z())-fDz); // to z side
494
495 // find closest side
496 //
497 if (distx<=disty)
498 {
499 if (distx<=distz)
500 {
501 // Closest to X
502 //
503 fcos=1.0/secx;
504 // normal=(+/-std::cos(ang),0,-std::sin(ang))
505 if (p.x()>=0)
506 norm=G4ThreeVector(fcos,0,-tanx*fcos);
507 else
508 norm=G4ThreeVector(-fcos,0,-tanx*fcos);
509 }
510 else
511 {
512 // Closest to Z
513 //
514 if (p.z()>=0)
515 norm=G4ThreeVector(0,0,1);
516 else
517 norm=G4ThreeVector(0,0,-1);
518 }
519 }
520 else
521 {
522 if (disty<=distz)
523 {
524 // Closest to Y
525 //
526 fcos=1.0/secy;
527 if (p.y()>=0)
528 norm=G4ThreeVector(0,fcos,-tany*fcos);
529 else
530 norm=G4ThreeVector(0,-fcos,-tany*fcos);
531 }
532 else
533 {
534 // Closest to Z
535 //
536 if (p.z()>=0)
537 norm=G4ThreeVector(0,0,1);
538 else
539 norm=G4ThreeVector(0,0,-1);
540 }
541 }
542 return norm;
543}
544
545////////////////////////////////////////////////////////////////////////////
546//
547// Calculate distance to shape from outside
548// - return kInfinity if no intersection
549//
550// ALGORITHM:
551// For each component, calculate pair of minimum and maximum intersection
552// values for which the particle is in the extent of the shape
553// - The smallest (MAX minimum) allowed distance of the pairs is intersect
554// - Z plane intersectin uses tolerance
555// - XZ YZ planes use logic & *SLIGHTLY INCORRECT* tolerance
556// (this saves at least 1 sqrt, 1 multiply and 1 divide... in applicable
557// cases)
558// - Note: XZ and YZ planes each divide space into four regions,
559// characterised by ss1 ss2
560// NOTE:
561//
562// `Inside' safe - meaningful answers given if point is inside the exact
563// shape.
564
565G4double G4Trd::DistanceToIn( const G4ThreeVector& p,
566 const G4ThreeVector& v ) const
567{
568 G4double snxt = kInfinity ; // snxt = default return value
569 G4double smin,smax;
570 G4double s1,s2,tanxz,tanyz,ds1,ds2;
571 G4double ss1,ss2,sn1=0.,sn2=0.,Dist;
572
573 if ( v.z() ) // Calculate valid z intersect range
574 {
575 if ( v.z() > 0 ) // Calculate smax: must be +ve or no intersection.
576 {
577 Dist = fDz - p.z() ; // to plane at +dz
578
579 if (Dist >= 0.5*kCarTolerance)
580 {
581 smax = Dist/v.z() ;
582 smin = -(fDz + p.z())/v.z() ;
583 }
584 else return snxt ;
585 }
586 else // v.z <0
587 {
588 Dist=fDz+p.z(); // plane at -dz
589
590 if ( Dist >= 0.5*kCarTolerance )
591 {
592 smax = -Dist/v.z() ;
593 smin = (fDz - p.z())/v.z() ;
594 }
595 else return snxt ;
596 }
597 if (smin < 0 ) smin = 0 ;
598 }
599 else // v.z=0
600 {
601 if (std::fabs(p.z()) >= fDz ) return snxt ; // Outside & no intersect
602 else
603 {
604 smin = 0 ; // Always inside z range
605 smax = kInfinity;
606 }
607 }
608
609 // Calculate x intersection range
610 //
611 // Calc half width at p.z, and components towards planes
612
613 tanxz = (fDx2 - fDx1)*0.5/fDz ;
614 s1 = 0.5*(fDx1+fDx2) + tanxz*p.z() ; // x half width at p.z
615 ds1 = v.x() - tanxz*v.z() ; // Components of v towards faces at +-x
616 ds2 = v.x() + tanxz*v.z() ;
617 ss1 = s1 - p.x() ; // -delta x to +ve plane
618 // -ve when outside
619 ss2 = -s1 - p.x() ; // -delta x to -ve plane
620 // +ve when outside
621
622 if (ss1 < 0 && ss2 <= 0 )
623 {
624 if (ds1 < 0) // In +ve coord Area
625 {
626 sn1 = ss1/ds1 ;
627
628 if ( ds2 < 0 ) sn2 = ss2/ds2 ;
629 else sn2 = kInfinity ;
630 }
631 else return snxt ;
632 }
633 else if ( ss1 >= 0 && ss2 > 0 )
634 {
635 if ( ds2 > 0 ) // In -ve coord Area
636 {
637 sn1 = ss2/ds2 ;
638
639 if (ds1 > 0) sn2 = ss1/ds1 ;
640 else sn2 = kInfinity;
641
642 }
643 else return snxt ;
644 }
645 else if (ss1 >= 0 && ss2 <= 0 )
646 {
647 // Inside Area - calculate leaving distance
648 // *Don't* use exact distance to side for tolerance
649 // = ss1*std::cos(ang xz)
650 // = ss1/std::sqrt(1.0+tanxz*tanxz)
651 sn1 = 0 ;
652
653 if ( ds1 > 0 )
654 {
655 if (ss1 > 0.5*kCarTolerance) sn2 = ss1/ds1 ; // Leave +ve side extent
656 else return snxt ; // Leave immediately by +ve
657 }
658 else sn2 = kInfinity ;
659
660 if ( ds2 < 0 )
661 {
662 if ( ss2 < -0.5*kCarTolerance )
663 {
664 Dist = ss2/ds2 ; // Leave -ve side extent
665 if ( Dist < sn2 ) sn2 = Dist ;
666 }
667 else return snxt ;
668 }
669 }
670 else if (ss1 < 0 && ss2 > 0 )
671 {
672 // Within +/- plane cross-over areas (not on boundaries ss1||ss2==0)
673
674 if ( ds1 >= 0 || ds2 <= 0 )
675 {
676 return snxt ;
677 }
678 else // Will intersect & stay inside
679 {
680 sn1 = ss1/ds1 ;
681 Dist = ss2/ds2 ;
682 if (Dist > sn1 ) sn1 = Dist ;
683 sn2 = kInfinity ;
684 }
685 }
686
687 // Reduce allowed range of distances as appropriate
688
689 if ( sn1 > smin ) smin = sn1 ;
690 if ( sn2 < smax ) smax = sn2 ;
691
692 // Check for incompatible ranges (eg z intersects between 50 ->100 and x
693 // only 10-40 -> no intersection)
694
695 if ( smax < smin ) return snxt ;
696
697 // Calculate valid y intersection range
698 // (repeat of x intersection code)
699
700 tanyz = (fDy2-fDy1)*0.5/fDz ;
701 s2 = 0.5*(fDy1+fDy2) + tanyz*p.z() ; // y half width at p.z
702 ds1 = v.y() - tanyz*v.z() ; // Components of v towards faces at +-y
703 ds2 = v.y() + tanyz*v.z() ;
704 ss1 = s2 - p.y() ; // -delta y to +ve plane
705 ss2 = -s2 - p.y() ; // -delta y to -ve plane
706
707 if ( ss1 < 0 && ss2 <= 0 )
708 {
709 if (ds1 < 0 ) // In +ve coord Area
710 {
711 sn1 = ss1/ds1 ;
712 if ( ds2 < 0 ) sn2 = ss2/ds2 ;
713 else sn2 = kInfinity ;
714 }
715 else return snxt ;
716 }
717 else if ( ss1 >= 0 && ss2 > 0 )
718 {
719 if ( ds2 > 0 ) // In -ve coord Area
720 {
721 sn1 = ss2/ds2 ;
722 if ( ds1 > 0 ) sn2 = ss1/ds1 ;
723 else sn2 = kInfinity ;
724 }
725 else return snxt ;
726 }
727 else if (ss1 >= 0 && ss2 <= 0 )
728 {
729 // Inside Area - calculate leaving distance
730 // *Don't* use exact distance to side for tolerance
731 // = ss1*std::cos(ang yz)
732 // = ss1/std::sqrt(1.0+tanyz*tanyz)
733 sn1 = 0 ;
734
735 if ( ds1 > 0 )
736 {
737 if (ss1 > 0.5*kCarTolerance) sn2 = ss1/ds1 ; // Leave +ve side extent
738 else return snxt ; // Leave immediately by +ve
739 }
740 else sn2 = kInfinity ;
741
742 if ( ds2 < 0 )
743 {
744 if ( ss2 < -0.5*kCarTolerance )
745 {
746 Dist = ss2/ds2 ; // Leave -ve side extent
747 if (Dist < sn2) sn2=Dist;
748 }
749 else return snxt ;
750 }
751 }
752 else if (ss1 < 0 && ss2 > 0 )
753 {
754 // Within +/- plane cross-over areas (not on boundaries ss1||ss2==0)
755
756 if (ds1 >= 0 || ds2 <= 0 )
757 {
758 return snxt ;
759 }
760 else // Will intersect & stay inside
761 {
762 sn1 = ss1/ds1 ;
763 Dist = ss2/ds2 ;
764 if (Dist > sn1 ) sn1 = Dist ;
765 sn2 = kInfinity ;
766 }
767 }
768
769 // Reduce allowed range of distances as appropriate
770
771 if ( sn1 > smin) smin = sn1 ;
772 if ( sn2 < smax) smax = sn2 ;
773
774 // Check for incompatible ranges (eg x intersects between 50 ->100 and y
775 // only 10-40 -> no intersection). Set snxt if ok
776
777 if ( smax > smin ) snxt = smin ;
778 if (snxt < 0.5*kCarTolerance ) snxt = 0.0 ;
779
780 return snxt ;
781}
782
783/////////////////////////////////////////////////////////////////////////
784//
785// Approximate distance to shape
786// Calculate perpendicular distances to z/x/y surfaces, return largest
787// which is the most fast estimation of shortest distance to Trd
788// - Safe underestimate
789// - If point within exact shape, return 0
790
791G4double G4Trd::DistanceToIn( const G4ThreeVector& p ) const
792{
793 G4double safe=0.0;
794 G4double tanxz,distx,safx;
795 G4double tanyz,disty,safy;
796 G4double zbase;
797
798 safe=std::fabs(p.z())-fDz;
799 if (safe<0) safe=0; // Also used to ensure x/y distances
800 // POSITIVE
801
802 zbase=fDz+p.z();
803
804 // Find distance along x direction to closest x plane
805 //
806 tanxz=(fDx2-fDx1)*0.5/fDz;
807 // widx=fDx1+tanxz*(fDz+p.z()); // x width at p.z
808 // distx=std::fabs(p.x())-widx; // distance to plane
809 distx=std::fabs(p.x())-(fDx1+tanxz*zbase);
810 if (distx>safe)
811 {
812 safx=distx/std::sqrt(1.0+tanxz*tanxz); // vector Dist=Dist*std::cos(ang)
813 if (safx>safe) safe=safx;
814 }
815
816 // Find distance along y direction to slanted wall
817 tanyz=(fDy2-fDy1)*0.5/fDz;
818 // widy=fDy1+tanyz*(fDz+p.z()); // y width at p.z
819 // disty=std::fabs(p.y())-widy; // distance to plane
820 disty=std::fabs(p.y())-(fDy1+tanyz*zbase);
821 if (disty>safe)
822 {
823 safy=disty/std::sqrt(1.0+tanyz*tanyz); // distance along vector
824 if (safy>safe) safe=safy;
825 }
826 return safe;
827}
828
829////////////////////////////////////////////////////////////////////////
830//
831// Calcluate distance to surface of shape from inside
832// Calculate distance to x/y/z planes - smallest is exiting distance
833// - z planes have std. check for tolerance
834// - xz yz planes have check based on distance || to x or y axis
835// (not corrected for slope of planes)
836// ?BUG? If v.z==0 are there cases when snside not set????
837
838G4double G4Trd::DistanceToOut( const G4ThreeVector& p,
839 const G4ThreeVector& v,
840 const G4bool calcNorm,
841 G4bool *validNorm,
842 G4ThreeVector *n ) const
843{
844 ESide side = kUndefined, snside = kUndefined;
845 G4double snxt,pdist;
846 G4double central,ss1,ss2,ds1,ds2,sn=0.,sn2=0.;
847 G4double tanxz=0.,cosxz=0.,tanyz=0.,cosyz=0.;
848
849 if (calcNorm) *validNorm=true; // All normals are valid
850
851 // Calculate z plane intersection
852 if (v.z()>0)
853 {
854 pdist=fDz-p.z();
855 if (pdist>kCarTolerance/2)
856 {
857 snxt=pdist/v.z();
858 side=kPZ;
859 }
860 else
861 {
862 if (calcNorm)
863 {
864 *n=G4ThreeVector(0,0,1);
865 }
866 return snxt=0;
867 }
868 }
869 else if (v.z()<0)
870 {
871 pdist=fDz+p.z();
872 if (pdist>kCarTolerance/2)
873 {
874 snxt=-pdist/v.z();
875 side=kMZ;
876 }
877 else
878 {
879 if (calcNorm)
880 {
881 *n=G4ThreeVector(0,0,-1);
882 }
883 return snxt=0;
884 }
885 }
886 else
887 {
888 snxt=kInfinity;
889 }
890
891 //
892 // Calculate x intersection
893 //
894 tanxz=(fDx2-fDx1)*0.5/fDz;
895 central=0.5*(fDx1+fDx2);
896
897 // +ve plane (1)
898 //
899 ss1=central+tanxz*p.z()-p.x(); // distance || x axis to plane
900 // (+ve if point inside)
901 ds1=v.x()-tanxz*v.z(); // component towards plane at +x
902 // (-ve if +ve -> -ve direction)
903 // -ve plane (2)
904 //
905 ss2=-tanxz*p.z()-p.x()-central; //distance || x axis to plane
906 // (-ve if point inside)
907 ds2=tanxz*v.z()+v.x(); // component towards plane at -x
908
909 if (ss1>0&&ss2<0)
910 {
911 // Normal case - entirely inside region
912 if (ds1<=0&&ds2<0)
913 {
914 if (ss2<-kCarTolerance/2)
915 {
916 sn=ss2/ds2; // Leave by -ve side
917 snside=kMX;
918 }
919 else
920 {
921 sn=0; // Leave immediately by -ve side
922 snside=kMX;
923 }
924 }
925 else if (ds1>0&&ds2>=0)
926 {
927 if (ss1>kCarTolerance/2)
928 {
929 sn=ss1/ds1; // Leave by +ve side
930 snside=kPX;
931 }
932 else
933 {
934 sn=0; // Leave immediately by +ve side
935 snside=kPX;
936 }
937 }
938 else if (ds1>0&&ds2<0)
939 {
940 if (ss1>kCarTolerance/2)
941 {
942 // sn=ss1/ds1; // Leave by +ve side
943 if (ss2<-kCarTolerance/2)
944 {
945 sn=ss1/ds1; // Leave by +ve side
946 sn2=ss2/ds2;
947 if (sn2<sn)
948 {
949 sn=sn2;
950 snside=kMX;
951 }
952 else
953 {
954 snside=kPX;
955 }
956 }
957 else
958 {
959 sn=0; // Leave immediately by -ve
960 snside=kMX;
961 }
962 }
963 else
964 {
965 sn=0; // Leave immediately by +ve side
966 snside=kPX;
967 }
968 }
969 else
970 {
971 // Must be || to both
972 //
973 sn=kInfinity; // Don't leave by either side
974 }
975 }
976 else if (ss1<=0&&ss2<0)
977 {
978 // Outside, in +ve Area
979
980 if (ds1>0)
981 {
982 sn=0; // Away from shape
983 // Left by +ve side
984 snside=kPX;
985 }
986 else
987 {
988 if (ds2<0)
989 {
990 // Ignore +ve plane and use -ve plane intersect
991 //
992 sn=ss2/ds2; // Leave by -ve side
993 snside=kMX;
994 }
995 else
996 {
997 // Must be || to both -> exit determined by other axes
998 //
999 sn=kInfinity; // Don't leave by either side
1000 }
1001 }
1002 }
1003 else if (ss1>0&&ss2>=0)
1004 {
1005 // Outside, in -ve Area
1006
1007 if (ds2<0)
1008 {
1009 sn=0; // away from shape
1010 // Left by -ve side
1011 snside=kMX;
1012 }
1013 else
1014 {
1015 if (ds1>0)
1016 {
1017 // Ignore +ve plane and use -ve plane intersect
1018 //
1019 sn=ss1/ds1; // Leave by +ve side
1020 snside=kPX;
1021 }
1022 else
1023 {
1024 // Must be || to both -> exit determined by other axes
1025 //
1026 sn=kInfinity; // Don't leave by either side
1027 }
1028 }
1029 }
1030
1031 // Update minimum exit distance
1032
1033 if (sn<snxt)
1034 {
1035 snxt=sn;
1036 side=snside;
1037 }
1038 if (snxt>0)
1039 {
1040 // Calculate y intersection
1041
1042 tanyz=(fDy2-fDy1)*0.5/fDz;
1043 central=0.5*(fDy1+fDy2);
1044
1045 // +ve plane (1)
1046 //
1047 ss1=central+tanyz*p.z()-p.y(); // distance || y axis to plane
1048 // (+ve if point inside)
1049 ds1=v.y()-tanyz*v.z(); // component towards +ve plane
1050 // (-ve if +ve -> -ve direction)
1051 // -ve plane (2)
1052 //
1053 ss2=-tanyz*p.z()-p.y()-central; // distance || y axis to plane
1054 // (-ve if point inside)
1055 ds2=tanyz*v.z()+v.y(); // component towards -ve plane
1056
1057 if (ss1>0&&ss2<0)
1058 {
1059 // Normal case - entirely inside region
1060
1061 if (ds1<=0&&ds2<0)
1062 {
1063 if (ss2<-kCarTolerance/2)
1064 {
1065 sn=ss2/ds2; // Leave by -ve side
1066 snside=kMY;
1067 }
1068 else
1069 {
1070 sn=0; // Leave immediately by -ve side
1071 snside=kMY;
1072 }
1073 }
1074 else if (ds1>0&&ds2>=0)
1075 {
1076 if (ss1>kCarTolerance/2)
1077 {
1078 sn=ss1/ds1; // Leave by +ve side
1079 snside=kPY;
1080 }
1081 else
1082 {
1083 sn=0; // Leave immediately by +ve side
1084 snside=kPY;
1085 }
1086 }
1087 else if (ds1>0&&ds2<0)
1088 {
1089 if (ss1>kCarTolerance/2)
1090 {
1091 // sn=ss1/ds1; // Leave by +ve side
1092 if (ss2<-kCarTolerance/2)
1093 {
1094 sn=ss1/ds1; // Leave by +ve side
1095 sn2=ss2/ds2;
1096 if (sn2<sn)
1097 {
1098 sn=sn2;
1099 snside=kMY;
1100 }
1101 else
1102 {
1103 snside=kPY;
1104 }
1105 }
1106 else
1107 {
1108 sn=0; // Leave immediately by -ve
1109 snside=kMY;
1110 }
1111 }
1112 else
1113 {
1114 sn=0; // Leave immediately by +ve side
1115 snside=kPY;
1116 }
1117 }
1118 else
1119 {
1120 // Must be || to both
1121 //
1122 sn=kInfinity; // Don't leave by either side
1123 }
1124 }
1125 else if (ss1<=0&&ss2<0)
1126 {
1127 // Outside, in +ve Area
1128
1129 if (ds1>0)
1130 {
1131 sn=0; // Away from shape
1132 // Left by +ve side
1133 snside=kPY;
1134 }
1135 else
1136 {
1137 if (ds2<0)
1138 {
1139 // Ignore +ve plane and use -ve plane intersect
1140 //
1141 sn=ss2/ds2; // Leave by -ve side
1142 snside=kMY;
1143 }
1144 else
1145 {
1146 // Must be || to both -> exit determined by other axes
1147 //
1148 sn=kInfinity; // Don't leave by either side
1149 }
1150 }
1151 }
1152 else if (ss1>0&&ss2>=0)
1153 {
1154 // Outside, in -ve Area
1155 if (ds2<0)
1156 {
1157 sn=0; // away from shape
1158 // Left by -ve side
1159 snside=kMY;
1160 }
1161 else
1162 {
1163 if (ds1>0)
1164 {
1165 // Ignore +ve plane and use -ve plane intersect
1166 //
1167 sn=ss1/ds1; // Leave by +ve side
1168 snside=kPY;
1169 }
1170 else
1171 {
1172 // Must be || to both -> exit determined by other axes
1173 //
1174 sn=kInfinity; // Don't leave by either side
1175 }
1176 }
1177 }
1178
1179 // Update minimum exit distance
1180
1181 if (sn<snxt)
1182 {
1183 snxt=sn;
1184 side=snside;
1185 }
1186 }
1187
1188 if (calcNorm)
1189 {
1190 switch (side)
1191 {
1192 case kPX:
1193 cosxz=1.0/std::sqrt(1.0+tanxz*tanxz);
1194 *n=G4ThreeVector(cosxz,0,-tanxz*cosxz);
1195 break;
1196 case kMX:
1197 cosxz=-1.0/std::sqrt(1.0+tanxz*tanxz);
1198 *n=G4ThreeVector(cosxz,0,tanxz*cosxz);
1199 break;
1200 case kPY:
1201 cosyz=1.0/std::sqrt(1.0+tanyz*tanyz);
1202 *n=G4ThreeVector(0,cosyz,-tanyz*cosyz);
1203 break;
1204 case kMY:
1205 cosyz=-1.0/std::sqrt(1.0+tanyz*tanyz);
1206 *n=G4ThreeVector(0,cosyz,tanyz*cosyz);
1207 break;
1208 case kPZ:
1209 *n=G4ThreeVector(0,0,1);
1210 break;
1211 case kMZ:
1212 *n=G4ThreeVector(0,0,-1);
1213 break;
1214 default:
1215 DumpInfo();
1216 G4Exception("G4Trd::DistanceToOut(p,v,..)","Notification",JustWarning,
1217 "Undefined side for valid surface normal to solid.");
1218 break;
1219 }
1220 }
1221 return snxt;
1222}
1223
1224///////////////////////////////////////////////////////////////////////////
1225//
1226// Calculate exact shortest distance to any boundary from inside
1227// - Returns 0 is point outside
1228
1229G4double G4Trd::DistanceToOut( const G4ThreeVector& p ) const
1230{
1231 G4double safe=0.0;
1232 G4double tanxz,xdist,saf1;
1233 G4double tanyz,ydist,saf2;
1234 G4double zbase;
1235
1236#ifdef G4CSGDEBUG
1237 if( Inside(p) == kOutside )
1238 {
1239 G4cout.precision(16) ;
1240 G4cout << G4endl ;
1241 DumpInfo();
1242 G4cout << "Position:" << G4endl << G4endl ;
1243 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
1244 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
1245 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
1246 G4Exception("G4Trd::DistanceToOut(p)", "Notification", JustWarning,
1247 "Point p is outside !?" );
1248 }
1249#endif
1250
1251 safe=fDz-std::fabs(p.z()); // z perpendicular Dist
1252
1253 zbase=fDz+p.z();
1254
1255 // xdist = distance perpendicular to z axis to closest x plane from p
1256 // = (x half width of shape at p.z) - std::fabs(p.x)
1257 //
1258 tanxz=(fDx2-fDx1)*0.5/fDz;
1259 xdist=fDx1+tanxz*zbase-std::fabs(p.x());
1260 saf1=xdist/std::sqrt(1.0+tanxz*tanxz); // x*std::cos(ang_xz) =
1261 // shortest (perpendicular)
1262 // distance to plane
1263 tanyz=(fDy2-fDy1)*0.5/fDz;
1264 ydist=fDy1+tanyz*zbase-std::fabs(p.y());
1265 saf2=ydist/std::sqrt(1.0+tanyz*tanyz);
1266
1267 // Return minimum x/y/z distance
1268 //
1269 if (safe>saf1) safe=saf1;
1270 if (safe>saf2) safe=saf2;
1271
1272 if (safe<0) safe=0;
1273 return safe;
1274}
1275
1276////////////////////////////////////////////////////////////////////////////
1277//
1278// Create a List containing the transformed vertices
1279// Ordering [0-3] -fDz cross section
1280// [4-7] +fDz cross section such that [0] is below [4],
1281// [1] below [5] etc.
1282// Note:
1283// Caller has deletion resposibility
1284
1285G4ThreeVectorList*
1286G4Trd::CreateRotatedVertices( const G4AffineTransform& pTransform ) const
1287{
1288 G4ThreeVectorList *vertices;
1289 vertices=new G4ThreeVectorList();
1290 vertices->reserve(8);
1291 if (vertices)
1292 {
1293 G4ThreeVector vertex0(-fDx1,-fDy1,-fDz);
1294 G4ThreeVector vertex1(fDx1,-fDy1,-fDz);
1295 G4ThreeVector vertex2(fDx1,fDy1,-fDz);
1296 G4ThreeVector vertex3(-fDx1,fDy1,-fDz);
1297 G4ThreeVector vertex4(-fDx2,-fDy2,fDz);
1298 G4ThreeVector vertex5(fDx2,-fDy2,fDz);
1299 G4ThreeVector vertex6(fDx2,fDy2,fDz);
1300 G4ThreeVector vertex7(-fDx2,fDy2,fDz);
1301
1302 vertices->push_back(pTransform.TransformPoint(vertex0));
1303 vertices->push_back(pTransform.TransformPoint(vertex1));
1304 vertices->push_back(pTransform.TransformPoint(vertex2));
1305 vertices->push_back(pTransform.TransformPoint(vertex3));
1306 vertices->push_back(pTransform.TransformPoint(vertex4));
1307 vertices->push_back(pTransform.TransformPoint(vertex5));
1308 vertices->push_back(pTransform.TransformPoint(vertex6));
1309 vertices->push_back(pTransform.TransformPoint(vertex7));
1310 }
1311 else
1312 {
1313 DumpInfo();
1314 G4Exception("G4Trd::CreateRotatedVertices()",
1315 "FatalError", FatalException,
1316 "Error in allocation of vertices. Out of memory !");
1317 }
1318 return vertices;
1319}
1320
1321//////////////////////////////////////////////////////////////////////////
1322//
1323// GetEntityType
1324
1325G4GeometryType G4Trd::GetEntityType() const
1326{
1327 return G4String("G4Trd");
1328}
1329
1330//////////////////////////////////////////////////////////////////////////
1331//
1332// Stream object contents to an output stream
1333
1334std::ostream& G4Trd::StreamInfo( std::ostream& os ) const
1335{
1336 os << "-----------------------------------------------------------\n"
1337 << " *** Dump for solid - " << GetName() << " ***\n"
1338 << " ===================================================\n"
1339 << " Solid type: G4Trd\n"
1340 << " Parameters: \n"
1341 << " half length X, surface -dZ: " << fDx1/mm << " mm \n"
1342 << " half length X, surface +dZ: " << fDx2/mm << " mm \n"
1343 << " half length Y, surface -dZ: " << fDy1/mm << " mm \n"
1344 << " half length Y, surface +dZ: " << fDy2/mm << " mm \n"
1345 << " half length Z : " << fDz/mm << " mm \n"
1346 << "-----------------------------------------------------------\n";
1347
1348 return os;
1349}
1350
1351
1352////////////////////////////////////////////////////////////////////////
1353//
1354// GetPointOnSurface
1355//
1356// Return a point (G4ThreeVector) randomly and uniformly
1357// selected on the solid surface
1358
1359G4ThreeVector G4Trd::GetPointOnSurface() const
1360{
1361 G4double px, py, pz, tgX, tgY, secX, secY, select, sumS, tmp;
1362 G4double Sxy1, Sxy2, Sxy, Sxz, Syz;
1363
1364 tgX = 0.5*(fDx2-fDx1)/fDz;
1365 secX = std::sqrt(1+tgX*tgX);
1366 tgY = 0.5*(fDy2-fDy1)/fDz;
1367 secY = std::sqrt(1+tgY*tgY);
1368
1369 // calculate 0.25 of side surfaces, sumS is 0.25 of total surface
1370
1371 Sxy1 = fDx1*fDy1;
1372 Sxy2 = fDx2*fDy2;
1373 Sxy = Sxy1 + Sxy2;
1374 Sxz = (fDx1 + fDx2)*fDz*secY;
1375 Syz = (fDy1 + fDy2)*fDz*secX;
1376 sumS = Sxy + Sxz + Syz;
1377
1378 select = sumS*G4UniformRand();
1379
1380 if( select < Sxy ) // Sxy1 or Sxy2
1381 {
1382 if( select < Sxy1 )
1383 {
1384 pz = -fDz;
1385 px = -fDx1 + 2*fDx1*G4UniformRand();
1386 py = -fDy1 + 2*fDy1*G4UniformRand();
1387 }
1388 else
1389 {
1390 pz = fDz;
1391 px = -fDx2 + 2*fDx2*G4UniformRand();
1392 py = -fDy2 + 2*fDy2*G4UniformRand();
1393 }
1394 }
1395 else if ( ( select - Sxy ) < Sxz ) // Sxz
1396 {
1397 pz = -fDz + 2*fDz*G4UniformRand();
1398 tmp = fDx1 + (pz + fDz)*tgX;
1399 px = -tmp + 2*tmp*G4UniformRand();
1400 tmp = fDy1 + (pz + fDz)*tgY;
1401
1402 if(G4UniformRand() > 0.5) { py = tmp; }
1403 else { py = -tmp; }
1404 }
1405 else // Syz
1406 {
1407 pz = -fDz + 2*fDz*G4UniformRand();
1408 tmp = fDy1 + (pz + fDz)*tgY;
1409 py = -tmp + 2*tmp*G4UniformRand();
1410 tmp = fDx1 + (pz + fDz)*tgX;
1411
1412 if(G4UniformRand() > 0.5) { px = tmp; }
1413 else { px = -tmp; }
1414 }
1415 return G4ThreeVector(px,py,pz);
1416}
1417
1418///////////////////////////////////////////////////////////////////////
1419//
1420// Methods for visualisation
1421
1422void G4Trd::DescribeYourselfTo ( G4VGraphicsScene& scene ) const
1423{
1424 scene.AddSolid (*this);
1425}
1426
1427G4Polyhedron* G4Trd::CreatePolyhedron () const
1428{
1429 return new G4PolyhedronTrd2 (fDx1, fDx2, fDy1, fDy2, fDz);
1430}
1431
1432G4NURBS* G4Trd::CreateNURBS () const
1433{
1434 // return new G4NURBSbox (fDx, fDy, fDz);
1435 return 0;
1436}
Note: See TracBrowser for help on using the repository browser.