source: trunk/source/geometry/solids/specific/src/G4Polyhedra.cc@ 1358

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

tag geant4.9.4 beta 1 + modifs locales

File size: 34.8 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: G4Polyhedra.cc,v 1.43 2010/06/16 08:24:14 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-04-beta-01 $
29//
30//
31// --------------------------------------------------------------------
32// GEANT 4 class source file
33//
34//
35// G4Polyhedra.cc
36//
37// Implementation of a CSG polyhedra, as an inherited class of G4VCSGfaceted.
38//
39// To be done:
40// * Cracks: there are probably small cracks in the seams between the
41// phi face (G4PolyPhiFace) and sides (G4PolyhedraSide) that are not
42// entirely leakproof. Also, I am not sure all vertices are leak proof.
43// * Many optimizations are possible, but not implemented.
44// * Visualization needs to be updated outside of this routine.
45//
46// Utility classes:
47// * G4EnclosingCylinder: I decided a quick check of geometry would be a
48// good idea (for CPU speed). If the quick check fails, the regular
49// full-blown G4VCSGfaceted version is invoked.
50// * G4ReduciblePolygon: Really meant as a check of input parameters,
51// this utility class also "converts" the GEANT3-like PGON/PCON
52// arguments into the newer ones.
53// Both these classes are implemented outside this file because they are
54// shared with G4Polycone.
55//
56// --------------------------------------------------------------------
57
58#include "G4Polyhedra.hh"
59
60#include "G4PolyhedraSide.hh"
61#include "G4PolyPhiFace.hh"
62
63#include "Randomize.hh"
64
65#include "G4Polyhedron.hh"
66#include "G4EnclosingCylinder.hh"
67#include "G4ReduciblePolygon.hh"
68#include "G4VPVParameterisation.hh"
69
70#include <sstream>
71
72using namespace CLHEP;
73
74//
75// Constructor (GEANT3 style parameters)
76//
77// GEANT3 PGON radii are specified in the distance to the norm of each face.
78//
79G4Polyhedra::G4Polyhedra( const G4String& name,
80 G4double phiStart,
81 G4double thePhiTotal,
82 G4int theNumSide,
83 G4int numZPlanes,
84 const G4double zPlane[],
85 const G4double rInner[],
86 const G4double rOuter[] )
87 : G4VCSGfaceted( name ), genericPgon(false)
88{
89 if (theNumSide <= 0)
90 {
91 G4cerr << "ERROR - G4Polyhedra::G4Polyhedra(): " << GetName() << G4endl
92 << " No sides specified !"
93 << G4endl;
94 G4Exception("G4Polyhedra::G4Polyhedra()", "InvalidSetup",
95 FatalException, "Solid must have at least one side.");
96 }
97
98 //
99 // Calculate conversion factor from G3 radius to G4 radius
100 //
101 G4double phiTotal = thePhiTotal;
102 if ( (phiTotal <=0) || (phiTotal >= twopi*(1-DBL_EPSILON)) )
103 { phiTotal = twopi; }
104 G4double convertRad = std::cos(0.5*phiTotal/theNumSide);
105
106 //
107 // Some historical stuff
108 //
109 original_parameters = new G4PolyhedraHistorical;
110
111 original_parameters->numSide = theNumSide;
112 original_parameters->Start_angle = phiStart;
113 original_parameters->Opening_angle = phiTotal;
114 original_parameters->Num_z_planes = numZPlanes;
115 original_parameters->Z_values = new G4double[numZPlanes];
116 original_parameters->Rmin = new G4double[numZPlanes];
117 original_parameters->Rmax = new G4double[numZPlanes];
118
119 G4int i;
120 for (i=0; i<numZPlanes; i++)
121 {
122 if (( i < numZPlanes-1) && ( zPlane[i] == zPlane[i+1] ))
123 {
124 if( (rInner[i] > rOuter[i+1])
125 ||(rInner[i+1] > rOuter[i]) )
126 {
127 DumpInfo();
128 G4cerr << "ERROR - G4Polyhedra::G4Polyhedra()"
129 << G4endl
130 << " Segments are not contiguous !" << G4endl
131 << " rMin[" << i << "] = " << rInner[i]
132 << " -- rMax[" << i+1 << "] = " << rOuter[i+1] << G4endl
133 << " rMin[" << i+1 << "] = " << rInner[i+1]
134 << " -- rMax[" << i << "] = " << rOuter[i] << G4endl;
135 G4Exception("G4Polyhedra::G4Polyhedra()","InvalidSetup",FatalException,
136 "Cannot create a Polyhedra with no contiguous segments.");
137 }
138 }
139 original_parameters->Z_values[i] = zPlane[i];
140 original_parameters->Rmin[i] = rInner[i]/convertRad;
141 original_parameters->Rmax[i] = rOuter[i]/convertRad;
142 }
143
144
145 //
146 // Build RZ polygon using special PCON/PGON GEANT3 constructor
147 //
148 G4ReduciblePolygon *rz =
149 new G4ReduciblePolygon( rInner, rOuter, zPlane, numZPlanes );
150 rz->ScaleA( 1/convertRad );
151
152 //
153 // Do the real work
154 //
155 Create( phiStart, phiTotal, theNumSide, rz );
156
157 delete rz;
158}
159
160
161//
162// Constructor (generic parameters)
163//
164G4Polyhedra::G4Polyhedra( const G4String& name,
165 G4double phiStart,
166 G4double phiTotal,
167 G4int theNumSide,
168 G4int numRZ,
169 const G4double r[],
170 const G4double z[] )
171 : G4VCSGfaceted( name ), genericPgon(true)
172{
173 G4ReduciblePolygon *rz = new G4ReduciblePolygon( r, z, numRZ );
174
175 Create( phiStart, phiTotal, theNumSide, rz );
176
177 // Set original_parameters struct for consistency
178 //
179 SetOriginalParameters();
180
181 delete rz;
182}
183
184
185//
186// Create
187//
188// Generic create routine, called by each constructor
189// after conversion of arguments
190//
191void G4Polyhedra::Create( G4double phiStart,
192 G4double phiTotal,
193 G4int theNumSide,
194 G4ReduciblePolygon *rz )
195{
196 //
197 // Perform checks of rz values
198 //
199 if (rz->Amin() < 0.0)
200 {
201 G4cerr << "ERROR - G4Polyhedra::Create() " << GetName() << G4endl
202 << " All R values must be >= 0 !"
203 << G4endl;
204 G4Exception("G4Polyhedra::Create()", "InvalidSetup",
205 FatalException, "Illegal input parameters.");
206 }
207
208 G4double rzArea = rz->Area();
209 if (rzArea < -kCarTolerance)
210 rz->ReverseOrder();
211
212 else if (rzArea < -kCarTolerance)
213 {
214 G4cerr << "ERROR - G4Polyhedra::Create() " << GetName() << G4endl
215 << " R/Z cross section is zero or near zero: "
216 << rzArea << G4endl;
217 G4Exception("G4Polyhedra::Create()", "InvalidSetup",
218 FatalException, "Illegal input parameters.");
219 }
220
221 if ( (!rz->RemoveDuplicateVertices( kCarTolerance ))
222 || (!rz->RemoveRedundantVertices( kCarTolerance )) )
223 {
224 G4cerr << "ERROR - G4Polyhedra::Create() " << GetName() << G4endl
225 << " Too few unique R/Z values !"
226 << G4endl;
227 G4Exception("G4Polyhedra::Create()", "InvalidSetup",
228 FatalException, "Illegal input parameters.");
229 }
230
231 if (rz->CrossesItself( 1/kInfinity ))
232 {
233 G4cerr << "ERROR - G4Polyhedra::Create() " << GetName() << G4endl
234 << " R/Z segments cross !"
235 << G4endl;
236 G4Exception("G4Polyhedra::Create()", "InvalidSetup",
237 FatalException, "Illegal input parameters.");
238 }
239
240 numCorner = rz->NumVertices();
241
242
243 startPhi = phiStart;
244 while( startPhi < 0 ) startPhi += twopi;
245 //
246 // Phi opening? Account for some possible roundoff, and interpret
247 // nonsense value as representing no phi opening
248 //
249 if ( (phiTotal <= 0) || (phiTotal > twopi*(1-DBL_EPSILON)) )
250 {
251 phiIsOpen = false;
252 endPhi = phiStart+twopi;
253 }
254 else
255 {
256 phiIsOpen = true;
257
258 //
259 // Convert phi into our convention
260 //
261 endPhi = phiStart+phiTotal;
262 while( endPhi < startPhi ) endPhi += twopi;
263 }
264
265 //
266 // Save number sides
267 //
268 numSide = theNumSide;
269
270 //
271 // Allocate corner array.
272 //
273 corners = new G4PolyhedraSideRZ[numCorner];
274
275 //
276 // Copy corners
277 //
278 G4ReduciblePolygonIterator iterRZ(rz);
279
280 G4PolyhedraSideRZ *next = corners;
281 iterRZ.Begin();
282 do
283 {
284 next->r = iterRZ.GetA();
285 next->z = iterRZ.GetB();
286 } while( ++next, iterRZ.Next() );
287
288 //
289 // Allocate face pointer array
290 //
291 numFace = phiIsOpen ? numCorner+2 : numCorner;
292 faces = new G4VCSGface*[numFace];
293
294 //
295 // Construct side faces
296 //
297 // To do so properly, we need to keep track of four successive RZ
298 // corners.
299 //
300 // But! Don't construct a face if both points are at zero radius!
301 //
302 G4PolyhedraSideRZ *corner = corners,
303 *prev = corners + numCorner-1,
304 *nextNext;
305 G4VCSGface **face = faces;
306 do
307 {
308 next = corner+1;
309 if (next >= corners+numCorner) next = corners;
310 nextNext = next+1;
311 if (nextNext >= corners+numCorner) nextNext = corners;
312
313 if (corner->r < 1/kInfinity && next->r < 1/kInfinity) continue;
314
315 //
316 // We must decide here if we can dare declare one of our faces
317 // as having a "valid" normal (i.e. allBehind = true). This
318 // is never possible if the face faces "inward" in r *unless*
319 // we have only one side
320 //
321 G4bool allBehind;
322 if ((corner->z > next->z) && (numSide > 1))
323 {
324 allBehind = false;
325 }
326 else
327 {
328 //
329 // Otherwise, it is only true if the line passing
330 // through the two points of the segment do not
331 // split the r/z cross section
332 //
333 allBehind = !rz->BisectedBy( corner->r, corner->z,
334 next->r, next->z, kCarTolerance );
335 }
336
337 *face++ = new G4PolyhedraSide( prev, corner, next, nextNext,
338 numSide, startPhi, endPhi-startPhi, phiIsOpen );
339 } while( prev=corner, corner=next, corner > corners );
340
341 if (phiIsOpen)
342 {
343 //
344 // Construct phi open edges
345 //
346 *face++ = new G4PolyPhiFace( rz, startPhi, phiTotal/numSide, endPhi );
347 *face++ = new G4PolyPhiFace( rz, endPhi, phiTotal/numSide, startPhi );
348 }
349
350 //
351 // We might have dropped a face or two: recalculate numFace
352 //
353 numFace = face-faces;
354
355 //
356 // Make enclosingCylinder
357 //
358 enclosingCylinder =
359 new G4EnclosingCylinder( rz, phiIsOpen, phiStart, phiTotal );
360}
361
362
363//
364// Fake default constructor - sets only member data and allocates memory
365// for usage restricted to object persistency.
366//
367G4Polyhedra::G4Polyhedra( __void__& a )
368 : G4VCSGfaceted(a), genericPgon(false), corners(0),
369 original_parameters(0), enclosingCylinder(0)
370{
371}
372
373
374//
375// Destructor
376//
377G4Polyhedra::~G4Polyhedra()
378{
379 delete [] corners;
380 if (original_parameters) delete original_parameters;
381
382 delete enclosingCylinder;
383}
384
385
386//
387// Copy constructor
388//
389G4Polyhedra::G4Polyhedra( const G4Polyhedra &source )
390 : G4VCSGfaceted( source )
391{
392 CopyStuff( source );
393}
394
395
396//
397// Assignment operator
398//
399const G4Polyhedra &G4Polyhedra::operator=( const G4Polyhedra &source )
400{
401 if (this == &source) return *this;
402
403 G4VCSGfaceted::operator=( source );
404
405 delete [] corners;
406 if (original_parameters) delete original_parameters;
407
408 delete enclosingCylinder;
409
410 CopyStuff( source );
411
412 return *this;
413}
414
415
416//
417// CopyStuff
418//
419void G4Polyhedra::CopyStuff( const G4Polyhedra &source )
420{
421 //
422 // Simple stuff
423 //
424 numSide = source.numSide;
425 startPhi = source.startPhi;
426 endPhi = source.endPhi;
427 phiIsOpen = source.phiIsOpen;
428 numCorner = source.numCorner;
429 genericPgon= source.genericPgon;
430
431 //
432 // The corner array
433 //
434 corners = new G4PolyhedraSideRZ[numCorner];
435
436 G4PolyhedraSideRZ *corn = corners,
437 *sourceCorn = source.corners;
438 do
439 {
440 *corn = *sourceCorn;
441 } while( ++sourceCorn, ++corn < corners+numCorner );
442
443 //
444 // Original parameters
445 //
446 if (source.original_parameters)
447 {
448 original_parameters =
449 new G4PolyhedraHistorical( *source.original_parameters );
450 }
451
452 //
453 // Enclosing cylinder
454 //
455 enclosingCylinder = new G4EnclosingCylinder( *source.enclosingCylinder );
456}
457
458
459//
460// Reset
461//
462// Recalculates and reshapes the solid, given pre-assigned scaled
463// original_parameters.
464//
465G4bool G4Polyhedra::Reset()
466{
467 if (genericPgon)
468 {
469 G4cerr << "Solid " << GetName() << " built using generic construct."
470 << G4endl << "Not applicable to the generic construct !" << G4endl;
471 G4Exception("G4Polyhedra::Reset()", "NotApplicableConstruct",
472 JustWarning, "Parameters NOT resetted.");
473 return 1;
474 }
475
476 //
477 // Clear old setup
478 //
479 G4VCSGfaceted::DeleteStuff();
480 delete [] corners;
481 delete enclosingCylinder;
482
483 //
484 // Rebuild polyhedra
485 //
486 G4ReduciblePolygon *rz =
487 new G4ReduciblePolygon( original_parameters->Rmin,
488 original_parameters->Rmax,
489 original_parameters->Z_values,
490 original_parameters->Num_z_planes );
491 Create( original_parameters->Start_angle,
492 original_parameters->Opening_angle,
493 original_parameters->numSide, rz );
494 delete rz;
495
496 return 0;
497}
498
499
500//
501// Inside
502//
503// This is an override of G4VCSGfaceted::Inside, created in order
504// to speed things up by first checking with G4EnclosingCylinder.
505//
506EInside G4Polyhedra::Inside( const G4ThreeVector &p ) const
507{
508 //
509 // Quick test
510 //
511 if (enclosingCylinder->MustBeOutside(p)) return kOutside;
512
513 //
514 // Long answer
515 //
516 return G4VCSGfaceted::Inside(p);
517}
518
519
520//
521// DistanceToIn
522//
523// This is an override of G4VCSGfaceted::Inside, created in order
524// to speed things up by first checking with G4EnclosingCylinder.
525//
526G4double G4Polyhedra::DistanceToIn( const G4ThreeVector &p,
527 const G4ThreeVector &v ) const
528{
529 //
530 // Quick test
531 //
532 if (enclosingCylinder->ShouldMiss(p,v))
533 return kInfinity;
534
535 //
536 // Long answer
537 //
538 return G4VCSGfaceted::DistanceToIn( p, v );
539}
540
541
542//
543// DistanceToIn
544//
545G4double G4Polyhedra::DistanceToIn( const G4ThreeVector &p ) const
546{
547 return G4VCSGfaceted::DistanceToIn(p);
548}
549
550
551//
552// ComputeDimensions
553//
554void G4Polyhedra::ComputeDimensions( G4VPVParameterisation* p,
555 const G4int n,
556 const G4VPhysicalVolume* pRep )
557{
558 p->ComputeDimensions(*this,n,pRep);
559}
560
561
562//
563// GetEntityType
564//
565G4GeometryType G4Polyhedra::GetEntityType() const
566{
567 return G4String("G4Polyhedra");
568}
569
570
571//
572// Stream object contents to an output stream
573//
574std::ostream& G4Polyhedra::StreamInfo( std::ostream& os ) const
575{
576 os << "-----------------------------------------------------------\n"
577 << " *** Dump for solid - " << GetName() << " ***\n"
578 << " ===================================================\n"
579 << " Solid type: G4Polyhedra\n"
580 << " Parameters: \n"
581 << " starting phi angle : " << startPhi/degree << " degrees \n"
582 << " ending phi angle : " << endPhi/degree << " degrees \n";
583 G4int i=0;
584 if (!genericPgon)
585 {
586 G4int numPlanes = original_parameters->Num_z_planes;
587 os << " number of Z planes: " << numPlanes << "\n"
588 << " Z values: \n";
589 for (i=0; i<numPlanes; i++)
590 {
591 os << " Z plane " << i << ": "
592 << original_parameters->Z_values[i] << "\n";
593 }
594 os << " Tangent distances to inner surface (Rmin): \n";
595 for (i=0; i<numPlanes; i++)
596 {
597 os << " Z plane " << i << ": "
598 << original_parameters->Rmin[i] << "\n";
599 }
600 os << " Tangent distances to outer surface (Rmax): \n";
601 for (i=0; i<numPlanes; i++)
602 {
603 os << " Z plane " << i << ": "
604 << original_parameters->Rmax[i] << "\n";
605 }
606 }
607 os << " number of RZ points: " << numCorner << "\n"
608 << " RZ values (corners): \n";
609 for (i=0; i<numCorner; i++)
610 {
611 os << " "
612 << corners[i].r << ", " << corners[i].z << "\n";
613 }
614 os << "-----------------------------------------------------------\n";
615
616 return os;
617}
618
619
620//
621// GetPointOnPlane
622//
623// Auxiliary method for get point on surface
624//
625G4ThreeVector G4Polyhedra::GetPointOnPlane(G4ThreeVector p0, G4ThreeVector p1,
626 G4ThreeVector p2, G4ThreeVector p3) const
627{
628 G4double lambda1, lambda2, chose,aOne,aTwo;
629 G4ThreeVector t, u, v, w, Area, normal;
630 aOne = 1.;
631 aTwo = 1.;
632
633 t = p1 - p0;
634 u = p2 - p1;
635 v = p3 - p2;
636 w = p0 - p3;
637
638 chose = RandFlat::shoot(0.,aOne+aTwo);
639 if( (chose>=0.) && (chose < aOne) )
640 {
641 lambda1 = RandFlat::shoot(0.,1.);
642 lambda2 = RandFlat::shoot(0.,lambda1);
643 return (p2+lambda1*v+lambda2*w);
644 }
645
646 lambda1 = RandFlat::shoot(0.,1.);
647 lambda2 = RandFlat::shoot(0.,lambda1);
648 return (p0+lambda1*t+lambda2*u);
649}
650
651
652//
653// GetPointOnTriangle
654//
655// Auxiliary method for get point on surface
656//
657G4ThreeVector G4Polyhedra::GetPointOnTriangle(G4ThreeVector p1,
658 G4ThreeVector p2,
659 G4ThreeVector p3) const
660{
661 G4double lambda1,lambda2;
662 G4ThreeVector v=p3-p1, w=p1-p2;
663
664 lambda1 = RandFlat::shoot(0.,1.);
665 lambda2 = RandFlat::shoot(0.,lambda1);
666
667 return (p2 + lambda1*w + lambda2*v);
668}
669
670
671//
672// GetPointOnSurface
673//
674G4ThreeVector G4Polyhedra::GetPointOnSurface() const
675{
676 if( !genericPgon ) // Polyhedra by faces
677 {
678 G4int j, numPlanes = original_parameters->Num_z_planes, Flag=0;
679 G4double chose, totArea=0., Achose1, Achose2,
680 rad1, rad2, sinphi1, sinphi2, cosphi1, cosphi2;
681 G4double a, b, l2, rang, totalPhi, ksi,
682 area, aTop=0., aBottom=0., zVal=0.;
683
684 G4ThreeVector p0, p1, p2, p3;
685 std::vector<G4double> aVector1;
686 std::vector<G4double> aVector2;
687 std::vector<G4double> aVector3;
688
689 totalPhi= (phiIsOpen) ? (endPhi-startPhi) : twopi;
690 ksi = totalPhi/numSide;
691 G4double cosksi = std::cos(ksi/2.);
692
693 // Below we generate the areas relevant to our solid
694 //
695 for(j=0; j<numPlanes-1; j++)
696 {
697 a = original_parameters->Rmax[j+1];
698 b = original_parameters->Rmax[j];
699 l2 = sqr(original_parameters->Z_values[j]
700 -original_parameters->Z_values[j+1]) + sqr(b-a);
701 area = std::sqrt(l2-sqr((a-b)*cosksi))*(a+b)*cosksi;
702 aVector1.push_back(area);
703 }
704
705 for(j=0; j<numPlanes-1; j++)
706 {
707 a = original_parameters->Rmin[j+1];//*cosksi;
708 b = original_parameters->Rmin[j];//*cosksi;
709 l2 = sqr(original_parameters->Z_values[j]
710 -original_parameters->Z_values[j+1]) + sqr(b-a);
711 area = std::sqrt(l2-sqr((a-b)*cosksi))*(a+b)*cosksi;
712 aVector2.push_back(area);
713 }
714
715 for(j=0; j<numPlanes-1; j++)
716 {
717 if(phiIsOpen == true)
718 {
719 aVector3.push_back(0.5*(original_parameters->Rmax[j]
720 -original_parameters->Rmin[j]
721 +original_parameters->Rmax[j+1]
722 -original_parameters->Rmin[j+1])
723 *std::fabs(original_parameters->Z_values[j+1]
724 -original_parameters->Z_values[j]));
725 }
726 else { aVector3.push_back(0.); }
727 }
728
729 for(j=0; j<numPlanes-1; j++)
730 {
731 totArea += numSide*(aVector1[j]+aVector2[j])+2.*aVector3[j];
732 }
733
734 // Must include top and bottom areas
735 //
736 if(original_parameters->Rmax[numPlanes-1] != 0.)
737 {
738 a = original_parameters->Rmax[numPlanes-1];
739 b = original_parameters->Rmin[numPlanes-1];
740 l2 = sqr(a-b);
741 aTop = std::sqrt(l2-sqr((a-b)*cosksi))*(a+b)*cosksi;
742 }
743
744 if(original_parameters->Rmax[0] != 0.)
745 {
746 a = original_parameters->Rmax[0];
747 b = original_parameters->Rmin[0];
748 l2 = sqr(a-b);
749 aBottom = std::sqrt(l2-sqr((a-b)*cosksi))*(a+b)*cosksi;
750 }
751
752 Achose1 = 0.;
753 Achose2 = numSide*(aVector1[0]+aVector2[0])+2.*aVector3[0];
754
755 chose = RandFlat::shoot(0.,totArea+aTop+aBottom);
756 if( (chose >= 0.) && (chose < aTop + aBottom) )
757 {
758 chose = RandFlat::shoot(startPhi,startPhi+totalPhi);
759 rang = std::floor((chose-startPhi)/ksi-0.01);
760 if(rang<0) { rang=0; }
761 rang = std::fabs(rang);
762 sinphi1 = std::sin(startPhi+rang*ksi);
763 sinphi2 = std::sin(startPhi+(rang+1)*ksi);
764 cosphi1 = std::cos(startPhi+rang*ksi);
765 cosphi2 = std::cos(startPhi+(rang+1)*ksi);
766 chose = RandFlat::shoot(0., aTop + aBottom);
767 if(chose>=0. && chose<aTop)
768 {
769 rad1 = original_parameters->Rmin[numPlanes-1];
770 rad2 = original_parameters->Rmax[numPlanes-1];
771 zVal = original_parameters->Z_values[numPlanes-1];
772 }
773 else
774 {
775 rad1 = original_parameters->Rmin[0];
776 rad2 = original_parameters->Rmax[0];
777 zVal = original_parameters->Z_values[0];
778 }
779 p0 = G4ThreeVector(rad1*cosphi1,rad1*sinphi1,zVal);
780 p1 = G4ThreeVector(rad2*cosphi1,rad2*sinphi1,zVal);
781 p2 = G4ThreeVector(rad2*cosphi2,rad2*sinphi2,zVal);
782 p3 = G4ThreeVector(rad1*cosphi2,rad1*sinphi2,zVal);
783 return GetPointOnPlane(p0,p1,p2,p3);
784 }
785 else
786 {
787 for (j=0; j<numPlanes-1; j++)
788 {
789 if( ((chose >= Achose1) && (chose < Achose2)) || (j == numPlanes-2) )
790 {
791 Flag = j; break;
792 }
793 Achose1 += numSide*(aVector1[j]+aVector2[j])+2.*aVector3[j];
794 Achose2 = Achose1 + numSide*(aVector1[j+1]+aVector2[j+1])
795 + 2.*aVector3[j+1];
796 }
797 }
798
799 // At this point we have chosen a subsection
800 // between to adjacent plane cuts...
801
802 j = Flag;
803
804 totArea = numSide*(aVector1[j]+aVector2[j])+2.*aVector3[j];
805 chose = RandFlat::shoot(0.,totArea);
806
807 if( (chose>=0.) && (chose<numSide*aVector1[j]) )
808 {
809 chose = RandFlat::shoot(startPhi,startPhi+totalPhi);
810 rang = std::floor((chose-startPhi)/ksi-0.01);
811 if(rang<0) { rang=0; }
812 rang = std::fabs(rang);
813 rad1 = original_parameters->Rmax[j];
814 rad2 = original_parameters->Rmax[j+1];
815 sinphi1 = std::sin(startPhi+rang*ksi);
816 sinphi2 = std::sin(startPhi+(rang+1)*ksi);
817 cosphi1 = std::cos(startPhi+rang*ksi);
818 cosphi2 = std::cos(startPhi+(rang+1)*ksi);
819 zVal = original_parameters->Z_values[j];
820
821 p0 = G4ThreeVector(rad1*cosphi1,rad1*sinphi1,zVal);
822 p1 = G4ThreeVector(rad1*cosphi2,rad1*sinphi2,zVal);
823
824 zVal = original_parameters->Z_values[j+1];
825
826 p2 = G4ThreeVector(rad2*cosphi2,rad2*sinphi2,zVal);
827 p3 = G4ThreeVector(rad2*cosphi1,rad2*sinphi1,zVal);
828 return GetPointOnPlane(p0,p1,p2,p3);
829 }
830 else if ( (chose >= numSide*aVector1[j])
831 && (chose <= numSide*(aVector1[j]+aVector2[j])) )
832 {
833 chose = RandFlat::shoot(startPhi,startPhi+totalPhi);
834 rang = std::floor((chose-startPhi)/ksi-0.01);
835 if(rang<0) { rang=0; }
836 rang = std::fabs(rang);
837 rad1 = original_parameters->Rmin[j];
838 rad2 = original_parameters->Rmin[j+1];
839 sinphi1 = std::sin(startPhi+rang*ksi);
840 sinphi2 = std::sin(startPhi+(rang+1)*ksi);
841 cosphi1 = std::cos(startPhi+rang*ksi);
842 cosphi2 = std::cos(startPhi+(rang+1)*ksi);
843 zVal = original_parameters->Z_values[j];
844
845 p0 = G4ThreeVector(rad1*cosphi1,rad1*sinphi1,zVal);
846 p1 = G4ThreeVector(rad1*cosphi2,rad1*sinphi2,zVal);
847
848 zVal = original_parameters->Z_values[j+1];
849
850 p2 = G4ThreeVector(rad2*cosphi2,rad2*sinphi2,zVal);
851 p3 = G4ThreeVector(rad2*cosphi1,rad2*sinphi1,zVal);
852 return GetPointOnPlane(p0,p1,p2,p3);
853 }
854
855 chose = RandFlat::shoot(0.,2.2);
856 if( (chose>=0.) && (chose < 1.) )
857 {
858 rang = startPhi;
859 }
860 else
861 {
862 rang = endPhi;
863 }
864
865 cosphi1 = std::cos(rang); rad1 = original_parameters->Rmin[j];
866 sinphi1 = std::sin(rang); rad2 = original_parameters->Rmax[j];
867
868 p0 = G4ThreeVector(rad1*cosphi1,rad1*sinphi1,
869 original_parameters->Z_values[j]);
870 p1 = G4ThreeVector(rad2*cosphi1,rad2*sinphi1,
871 original_parameters->Z_values[j]);
872
873 rad1 = original_parameters->Rmax[j+1];
874 rad2 = original_parameters->Rmin[j+1];
875
876 p2 = G4ThreeVector(rad1*cosphi1,rad1*sinphi1,
877 original_parameters->Z_values[j+1]);
878 p3 = G4ThreeVector(rad2*cosphi1,rad2*sinphi1,
879 original_parameters->Z_values[j+1]);
880 return GetPointOnPlane(p0,p1,p2,p3);
881 }
882 else // Generic polyhedra
883 {
884 return GetPointOnSurfaceGeneric();
885 }
886}
887
888//
889// CreatePolyhedron
890//
891G4Polyhedron* G4Polyhedra::CreatePolyhedron() const
892{
893 if (!genericPgon)
894 {
895 return new G4PolyhedronPgon( original_parameters->Start_angle,
896 original_parameters->Opening_angle,
897 original_parameters->numSide,
898 original_parameters->Num_z_planes,
899 original_parameters->Z_values,
900 original_parameters->Rmin,
901 original_parameters->Rmax);
902 }
903 else
904 {
905 // The following code prepares for:
906 // HepPolyhedron::createPolyhedron(int Nnodes, int Nfaces,
907 // const double xyz[][3],
908 // const int faces_vec[][4])
909 // Here is an extract from the header file HepPolyhedron.h:
910 /**
911 * Creates user defined polyhedron.
912 * This function allows to the user to define arbitrary polyhedron.
913 * The faces of the polyhedron should be either triangles or planar
914 * quadrilateral. Nodes of a face are defined by indexes pointing to
915 * the elements in the xyz array. Numeration of the elements in the
916 * array starts from 1 (like in fortran). The indexes can be positive
917 * or negative. Negative sign means that the corresponding edge is
918 * invisible. The normal of the face should be directed to exterior
919 * of the polyhedron.
920 *
921 * @param Nnodes number of nodes
922 * @param Nfaces number of faces
923 * @param xyz nodes
924 * @param faces_vec faces (quadrilaterals or triangles)
925 * @return status of the operation - is non-zero in case of problem
926 */
927 G4int nNodes;
928 G4int nFaces;
929 typedef G4double double3[3];
930 double3* xyz;
931 typedef G4int int4[4];
932 int4* faces_vec;
933 if (phiIsOpen)
934 {
935 // Triangulate open ends. Simple ear-chopping algorithm...
936 // I'm not sure how robust this algorithm is (J.Allison).
937 //
938 std::vector<G4bool> chopped(numCorner, false);
939 std::vector<G4int*> triQuads;
940 G4int remaining = numCorner;
941 G4int iStarter = 0;
942 while (remaining >= 3)
943 {
944 // Find unchopped corners...
945 //
946 G4int A = -1, B = -1, C = -1;
947 G4int iStepper = iStarter;
948 do
949 {
950 if (A < 0) { A = iStepper; }
951 else if (B < 0) { B = iStepper; }
952 else if (C < 0) { C = iStepper; }
953 do
954 {
955 if (++iStepper >= numCorner) iStepper = 0;
956 }
957 while (chopped[iStepper]);
958 }
959 while (C < 0 && iStepper != iStarter);
960
961 // Check triangle at B is pointing outward (an "ear").
962 // Sign of z cross product determines...
963
964 G4double BAr = corners[A].r - corners[B].r;
965 G4double BAz = corners[A].z - corners[B].z;
966 G4double BCr = corners[C].r - corners[B].r;
967 G4double BCz = corners[C].z - corners[B].z;
968 if (BAr * BCz - BAz * BCr < kCarTolerance)
969 {
970 G4int* tq = new G4int[3];
971 tq[0] = A + 1;
972 tq[1] = B + 1;
973 tq[2] = C + 1;
974 triQuads.push_back(tq);
975 chopped[B] = true;
976 --remaining;
977 }
978 else
979 {
980 do
981 {
982 if (++iStarter >= numCorner) { iStarter = 0; }
983 }
984 while (chopped[iStarter]);
985 }
986 }
987
988 // Transfer to faces...
989
990 nNodes = (numSide + 1) * numCorner;
991 nFaces = numSide * numCorner + 2 * triQuads.size();
992 faces_vec = new int4[nFaces];
993 G4int iface = 0;
994 G4int addition = numCorner * numSide;
995 G4int d = numCorner - 1;
996 for (G4int iEnd = 0; iEnd < 2; ++iEnd)
997 {
998 for (size_t i = 0; i < triQuads.size(); ++i)
999 {
1000 // Negative for soft/auxiliary/normally invisible edges...
1001 //
1002 G4int a, b, c;
1003 if (iEnd == 0)
1004 {
1005 a = triQuads[i][0];
1006 b = triQuads[i][1];
1007 c = triQuads[i][2];
1008 }
1009 else
1010 {
1011 a = triQuads[i][0] + addition;
1012 b = triQuads[i][2] + addition;
1013 c = triQuads[i][1] + addition;
1014 }
1015 G4int ab = std::abs(b - a);
1016 G4int bc = std::abs(c - b);
1017 G4int ca = std::abs(a - c);
1018 faces_vec[iface][0] = (ab == 1 || ab == d)? a: -a;
1019 faces_vec[iface][1] = (bc == 1 || bc == d)? b: -b;
1020 faces_vec[iface][2] = (ca == 1 || ca == d)? c: -c;
1021 faces_vec[iface][3] = 0;
1022 ++iface;
1023 }
1024 }
1025
1026 // Continue with sides...
1027
1028 xyz = new double3[nNodes];
1029 const G4double dPhi = (endPhi - startPhi) / numSide;
1030 G4double phi = startPhi;
1031 G4int ixyz = 0;
1032 for (G4int iSide = 0; iSide < numSide; ++iSide)
1033 {
1034 for (G4int iCorner = 0; iCorner < numCorner; ++iCorner)
1035 {
1036 xyz[ixyz][0] = corners[iCorner].r * std::cos(phi);
1037 xyz[ixyz][1] = corners[iCorner].r * std::sin(phi);
1038 xyz[ixyz][2] = corners[iCorner].z;
1039 if (iCorner < numCorner - 1)
1040 {
1041 faces_vec[iface][0] = ixyz + 1;
1042 faces_vec[iface][1] = ixyz + numCorner + 1;
1043 faces_vec[iface][2] = ixyz + numCorner + 2;
1044 faces_vec[iface][3] = ixyz + 2;
1045 }
1046 else
1047 {
1048 faces_vec[iface][0] = ixyz + 1;
1049 faces_vec[iface][1] = ixyz + numCorner + 1;
1050 faces_vec[iface][2] = ixyz + 2;
1051 faces_vec[iface][3] = ixyz - numCorner + 2;
1052 }
1053 ++iface;
1054 ++ixyz;
1055 }
1056 phi += dPhi;
1057 }
1058
1059 // Last corners...
1060
1061 for (G4int iCorner = 0; iCorner < numCorner; ++iCorner)
1062 {
1063 xyz[ixyz][0] = corners[iCorner].r * std::cos(phi);
1064 xyz[ixyz][1] = corners[iCorner].r * std::sin(phi);
1065 xyz[ixyz][2] = corners[iCorner].z;
1066 ++ixyz;
1067 }
1068 }
1069 else // !phiIsOpen - i.e., a complete 360 degrees.
1070 {
1071 nNodes = numSide * numCorner;
1072 nFaces = numSide * numCorner;;
1073 xyz = new double3[nNodes];
1074 faces_vec = new int4[nFaces];
1075 // const G4double dPhi = (endPhi - startPhi) / numSide;
1076 const G4double dPhi = twopi / numSide; // !phiIsOpen endPhi-startPhi = 360 degrees.
1077 G4double phi = startPhi;
1078 G4int ixyz = 0, iface = 0;
1079 for (G4int iSide = 0; iSide < numSide; ++iSide)
1080 {
1081 for (G4int iCorner = 0; iCorner < numCorner; ++iCorner)
1082 {
1083 xyz[ixyz][0] = corners[iCorner].r * std::cos(phi);
1084 xyz[ixyz][1] = corners[iCorner].r * std::sin(phi);
1085 xyz[ixyz][2] = corners[iCorner].z;
1086 if (iSide < numSide - 1)
1087 {
1088 if (iCorner < numCorner - 1)
1089 {
1090 faces_vec[iface][0] = ixyz + 1;
1091 faces_vec[iface][1] = ixyz + numCorner + 1;
1092 faces_vec[iface][2] = ixyz + numCorner + 2;
1093 faces_vec[iface][3] = ixyz + 2;
1094 }
1095 else
1096 {
1097 faces_vec[iface][0] = ixyz + 1;
1098 faces_vec[iface][1] = ixyz + numCorner + 1;
1099 faces_vec[iface][2] = ixyz + 2;
1100 faces_vec[iface][3] = ixyz - numCorner + 2;
1101 }
1102 }
1103 else // Last side joins ends...
1104 {
1105 if (iCorner < numCorner - 1)
1106 {
1107 faces_vec[iface][0] = ixyz + 1;
1108 faces_vec[iface][1] = ixyz + numCorner - nFaces + 1;
1109 faces_vec[iface][2] = ixyz + numCorner - nFaces + 2;
1110 faces_vec[iface][3] = ixyz + 2;
1111 }
1112 else
1113 {
1114 faces_vec[iface][0] = ixyz + 1;
1115 faces_vec[iface][1] = ixyz - nFaces + numCorner + 1;
1116 faces_vec[iface][2] = ixyz - nFaces + 2;
1117 faces_vec[iface][3] = ixyz - numCorner + 2;
1118 }
1119 }
1120 ++ixyz;
1121 ++iface;
1122 }
1123 phi += dPhi;
1124 }
1125 }
1126 G4Polyhedron* polyhedron = new G4Polyhedron;
1127 G4int problem = polyhedron->createPolyhedron(nNodes, nFaces, xyz, faces_vec);
1128 delete [] faces_vec;
1129 delete [] xyz;
1130 if (problem)
1131 {
1132 std::ostringstream oss;
1133 oss << "Problem creating G4Polyhedron for: " << GetName();
1134 G4Exception("G4Polyhedra::CreatePolyhedron()", "BadPolyhedron",
1135 JustWarning, oss.str().c_str());
1136 delete polyhedron;
1137 return 0;
1138 }
1139 else
1140 {
1141 return polyhedron;
1142 }
1143 }
1144}
1145
1146//
1147// CreateNURBS
1148//
1149G4NURBS *G4Polyhedra::CreateNURBS() const
1150{
1151 return 0;
1152}
1153
1154
1155//
1156// G4PolyhedraHistorical stuff
1157//
1158G4PolyhedraHistorical::G4PolyhedraHistorical()
1159 : Z_values(0), Rmin(0), Rmax(0)
1160{
1161}
1162
1163G4PolyhedraHistorical::~G4PolyhedraHistorical()
1164{
1165 delete [] Z_values;
1166 delete [] Rmin;
1167 delete [] Rmax;
1168}
1169
1170G4PolyhedraHistorical::
1171G4PolyhedraHistorical( const G4PolyhedraHistorical& source )
1172{
1173 Start_angle = source.Start_angle;
1174 Opening_angle = source.Opening_angle;
1175 numSide = source.numSide;
1176 Num_z_planes = source.Num_z_planes;
1177
1178 Z_values = new G4double[Num_z_planes];
1179 Rmin = new G4double[Num_z_planes];
1180 Rmax = new G4double[Num_z_planes];
1181
1182 for( G4int i = 0; i < Num_z_planes; i++)
1183 {
1184 Z_values[i] = source.Z_values[i];
1185 Rmin[i] = source.Rmin[i];
1186 Rmax[i] = source.Rmax[i];
1187 }
1188}
1189
1190G4PolyhedraHistorical&
1191G4PolyhedraHistorical::operator=( const G4PolyhedraHistorical& right )
1192{
1193 if ( &right == this ) return *this;
1194
1195 if (&right)
1196 {
1197 Start_angle = right.Start_angle;
1198 Opening_angle = right.Opening_angle;
1199 numSide = right.numSide;
1200 Num_z_planes = right.Num_z_planes;
1201
1202 delete [] Z_values;
1203 delete [] Rmin;
1204 delete [] Rmax;
1205 Z_values = new G4double[Num_z_planes];
1206 Rmin = new G4double[Num_z_planes];
1207 Rmax = new G4double[Num_z_planes];
1208
1209 for( G4int i = 0; i < Num_z_planes; i++)
1210 {
1211 Z_values[i] = right.Z_values[i];
1212 Rmin[i] = right.Rmin[i];
1213 Rmax[i] = right.Rmax[i];
1214 }
1215 }
1216 return *this;
1217}
Note: See TracBrowser for help on using the repository browser.