Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4BREPSolidPolyhedra.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // $Id$
27 //
28 // ----------------------------------------------------------------------
29 // GEANT 4 class source file
30 //
31 // G4BREPSolidPolyhedra.cc
32 //
33 // ----------------------------------------------------------------------
34 // The polygonal solid G4BREPSolidPolyhedra is a shape defined by an inner
35 // and outer polygonal surface and two planes perpendicular to the Z axis.
36 // Each polygonal surface is created by linking a series of polygons created
37 // at different planes perpendicular to the Z-axis. All these polygons all
38 // have the same number of sides (sides) and are defined at the same Z planes
39 // for both inner and outer polygonal surfaces.
40 // ----------------------------------------------------------------------
41 //
42 // History
43 // -------
44 //
45 // Bug-fix #266 by R.Chytracek:
46 // - The situation when phi1 = 0 dphi1 = 2*pi and all RMINs = 0.0 is handled
47 // now. In this case the inner planes are not created. The fix goes even
48 // further this means it considers more than 2 z-planes and inner planes
49 // are not created whenever two consecutive RMINs are = 0.0 .
50 //
51 // Corrections by S.Giani:
52 // - Xaxis now corresponds to phi=0
53 // - partial angle = phiTotal / Nsides
54 // - end planes exact boundary calculation for phiTotal < 2pi
55 // (also including case with RMIN=RMAX)
56 // - Xaxis now properly rotated to compute correct scope of vertixes
57 // - corrected surface orientation for outer faces parallel to Z
58 // - completed explicit setting of the orientation for all faces
59 // - some comparison between doubles avoided by using tolerances
60 // - visualisation parameters made consistent with the use made by
61 // constructor of the input arguments (i.e. circumscribed radius).
62 // ----------------------------------------------------------------------
63 
64 #include <sstream>
65 
66 #include "G4BREPSolidPolyhedra.hh"
67 #include "G4PhysicalConstants.hh"
68 #include "G4SystemOfUnits.hh"
69 #include "G4FPlane.hh"
70 
72  G4double start_angle,
73  G4double opening_angle,
74  G4int sides,
75  G4int num_z_planes,
76  G4double z_start,
77  G4double z_values[],
78  G4double RMIN[],
79  G4double RMAX[] )
80  : G4BREPSolid(name)
81 {
82  // Store the original parameters, to be used in visualisation
83  // Note radii are not scaled because this BREP uses the radius of the
84  // circumscribed circle and also graphics_reps/G4Polyhedron uses the
85  // radius of the circumscribed circle.
86 
87  // Save contructor parameters
88  //
89  constructorParams.start_angle = start_angle;
90  constructorParams.opening_angle = opening_angle;
91  constructorParams.sides = sides;
92  constructorParams.num_z_planes = num_z_planes;
93  constructorParams.z_start = z_start;
94  constructorParams.z_values = 0;
95  constructorParams.RMIN = 0;
96  constructorParams.RMAX = 0;
97 
98  if( num_z_planes > 0 )
99  {
100  constructorParams.z_values = new G4double[num_z_planes];
101  constructorParams.RMIN = new G4double[num_z_planes];
102  constructorParams.RMAX = new G4double[num_z_planes];
103  for( G4int idx = 0; idx < num_z_planes; ++idx )
104  {
105  constructorParams.z_values[idx] = z_values[idx];
106  constructorParams.RMIN[idx] = RMIN[idx];
107  constructorParams.RMAX[idx] = RMAX[idx];
108  }
109  }
110 
111  // z_values[0] should be equal to z_start, for consistency
112  // with what the constructor does.
113  // Otherwise the z_values that are shifted by (z_values[0] - z_start) ,
114  // because z_values are only used in the form
115  // length = z_values[d+1] - z_values[d]; // JA Apr 2, 97
116 
117  if( z_values[0] != z_start )
118  {
119  std::ostringstream message;
120  message << "Construction Error. z_values[0] must be equal to z_start!"
121  << G4endl
122  << " Wrong solid parameters: "
123  << " z_values[0]= " << z_values[0] << " is not equal to "
124  << " z_start= " << z_start << ".";
125  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
126  "GeomSolids1002", JustWarning, message );
127  if( num_z_planes <= 0 ) { constructorParams.z_values = new G4double[1]; }
128  constructorParams.z_values[0]= z_start;
129  }
130 
131  active=1;
132  InitializePolyhedra();
133 }
134 
136  : G4BREPSolid(a)
137 {
138  constructorParams.start_angle = 0.;
139  constructorParams.opening_angle = 0.;
140  constructorParams.sides = 0;
141  constructorParams.num_z_planes = 0;
142  constructorParams.z_start = 0.;
143  constructorParams.z_values = 0;
144  constructorParams.RMIN = 0;
145  constructorParams.RMAX = 0;
146 }
147 
149 {
150  if( constructorParams.num_z_planes > 0 )
151  {
152  delete [] constructorParams.z_values;
153  delete [] constructorParams.RMIN;
154  delete [] constructorParams.RMAX;
155  }
156 }
157 
159  : G4BREPSolid(rhs)
160 {
161  constructorParams.start_angle = rhs.constructorParams.start_angle;
162  constructorParams.opening_angle = rhs.constructorParams.opening_angle;
163  constructorParams.sides = rhs.constructorParams.sides;
164  constructorParams.num_z_planes = rhs.constructorParams.num_z_planes;
165  constructorParams.z_start = rhs.constructorParams.z_start;
166  constructorParams.z_values = 0;
167  constructorParams.RMIN = 0;
168  constructorParams.RMAX = 0;
169  G4int num_z_planes = constructorParams.num_z_planes;
170  if( num_z_planes > 0 )
171  {
172  constructorParams.z_values = new G4double[num_z_planes];
173  constructorParams.RMIN = new G4double[num_z_planes];
174  constructorParams.RMAX = new G4double[num_z_planes];
175  for( G4int idx = 0; idx < num_z_planes; ++idx )
176  {
177  constructorParams.z_values[idx] = rhs.constructorParams.z_values[idx];
178  constructorParams.RMIN[idx] = rhs.constructorParams.RMIN[idx];
179  constructorParams.RMAX[idx] = rhs.constructorParams.RMAX[idx];
180  }
181  }
182 
183  InitializePolyhedra();
184 }
185 
188 {
189  // Check assignment to self
190  //
191  if (this == &rhs) { return *this; }
192 
193  // Copy base class data
194  //
196 
197  // Copy data
198  //
199  constructorParams.start_angle = rhs.constructorParams.start_angle;
200  constructorParams.opening_angle = rhs.constructorParams.opening_angle;
201  constructorParams.sides = rhs.constructorParams.sides;
202  constructorParams.num_z_planes = rhs.constructorParams.num_z_planes;
203  constructorParams.z_start = rhs.constructorParams.z_start;
204  G4int num_z_planes = constructorParams.num_z_planes;
205  if( num_z_planes > 0 )
206  {
207  delete [] constructorParams.z_values;
208  delete [] constructorParams.RMIN;
209  delete [] constructorParams.RMAX;
210  constructorParams.z_values = new G4double[num_z_planes];
211  constructorParams.RMIN = new G4double[num_z_planes];
212  constructorParams.RMAX = new G4double[num_z_planes];
213  for( G4int idx = 0; idx < num_z_planes; ++idx )
214  {
215  constructorParams.z_values[idx] = rhs.constructorParams.z_values[idx];
216  constructorParams.RMIN[idx] = rhs.constructorParams.RMIN[idx];
217  constructorParams.RMAX[idx] = rhs.constructorParams.RMAX[idx];
218  }
219  }
220 
221  InitializePolyhedra();
222 
223  return *this;
224 }
225 
226 void G4BREPSolidPolyhedra::InitializePolyhedra()
227 {
228  G4double start_angle = constructorParams.start_angle;
229  G4double opening_angle = constructorParams.opening_angle;
230  G4int sides = constructorParams.sides;
231  G4int num_z_planes = constructorParams.num_z_planes;
232  G4double z_start = constructorParams.z_start;
233  G4double* z_values = constructorParams.z_values;
234  G4double* RMIN = constructorParams.RMIN;
235  G4double* RMAX = constructorParams.RMAX;
236  G4int sections = num_z_planes - 1;
237 
238  if( opening_angle >= 2*pi-perMillion )
239  {
240  nb_of_surfaces = 2*(sections * sides) + 2;
241  }
242  else
243  {
244  nb_of_surfaces = 2*(sections * sides) + 4;
245  }
246 
247  G4int MaxNbOfSurfaces = nb_of_surfaces;
248  G4Surface** MaxSurfaceVec = new G4Surface*[MaxNbOfSurfaces];
249 
250  G4Vector3D Axis(0,0,1);
251  G4Vector3D XAxis(1,0,0);
252  G4Vector3D TmpAxis;
253  G4Point3D Origin(0,0,z_start);
254  G4Point3D LocalOrigin(0,0,z_start);
255  G4double Length;
256  G4int Count = 0 ;
257  G4double PartAngle = (opening_angle)/sides;
258 
259 
261  // Preconditions check
262 
263  // Detecting minimal required number of sides
264  //
265  if( sides < 3 )
266  {
267  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
268  "InvalidSetup", FatalException,
269  "The solid must have at least 3 sides!" );
270  }
271 
272  // Detecting minimal required number of z-sections
273  //
274  if( num_z_planes < 2 )
275  {
276  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
277  "GeomSolids0002", FatalException,
278  "The solid must have at least 2 z-sections!" );
279  }
280 
281  // Detect invalid configurations at the ends of polyhedra which
282  // would not lead to a valid solid creation and likely to a crash
283  //
284  if( z_values[0] == z_values[1]
285  || z_values[sections-1] == z_values[sections] )
286  {
287  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
288  "GeomSolids0002", FatalException,
289  "The solid must have the first 2 and the last 2 z-values different!" );
290  }
291 
292  // Find out how the z-values sequence is ordered
293  //
294  G4bool increasing;
295  if( z_values[0] < z_values[1] )
296  {
297  increasing = true;
298  }
299  else
300  {
301  increasing = false;
302  }
303 
304  // Detecting polyhedra teeth.
305  // It's forbidden to specify unordered, e.g. non-increasing or
306  // non-decreasing sequence of z-values. It may be provided by a
307  // specific solid in a future.
308  //
309  for( G4int idx = 0; idx < sections; idx++ )
310  {
311  if( ( z_values[idx] > z_values[idx+1] && increasing ) ||
312  ( z_values[idx] < z_values[idx+1] && !increasing ) )
313  {
314  // ERROR! Invalid sequence of z-values
315  //
316  std::ostringstream message;
317  message << "Unordered, non-increasing or non-decreasing sequence."
318  << G4endl
319  << " Unordered z_values sequence detected !" << G4endl
320  << " Check z_values with indexes: "
321  << idx << " " << (idx+1) << ".";
322  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
323  "GeomSolids0002", FatalException, message );
324  }
325  }
326 
328 #ifdef G4_EXPERIMENTAL_CODE
329  // There is one problem when sequence of z values is not increasing in a
330  // regular way, in other words, it's not purely increasing or decreasing
331  // Irregular sequence can be provided in order to define a polyhedra having
332  // teeth as shown on the picture bellow
333  // In this sequence can happen the following:
334  // z[a-1] > z[a] < z[a+1] && z[a+1] >= z[a-1]
335  // One has to check the RMAX and RMIN values due to the possible
336  // intersections.
337  //
338  // 1 2 3
339  // ___ ___ ____
340  // 00/ 00/ _ 000/
341  // 0/ 0/ |0 00|
342  // V___ V__+0 00+--
343  // 0000 00000 00000
344  // ---- ----- -----
345  // ------------------------------------ z-axis
346  //
347  //
348  // NOTE: This picture doesn't show all the possible configurations of
349  // a polyhedra having teeth when looking at its profile.
350  // The picture shows only one half of the polyhedra's profile
352 
353  // Experimental code! Not recommended for production, it's incomplete!
354  // The task is to identify invalid combination of z, RMIN and RMAX values
355  // in the case of toothydra :-)
356  //
357  G4int toothIdx;
358 
359  for( G4int idx = 1; idx < sections+1; idx++ )
360  {
361  if( z_values[idx-1] > z_values[idx] )
362  {
363  G4double toothdist = std::fabs( z_values[idx-1] - z_values[idx] );
364  G4double aftertoothdist = std::fabs( z_values[idx+1] - z_values[idx] );
365  if( toothdist > aftertoothdist )
366  {
367  // Check for possible intersection
368  //
369  if( RMAX[idx-1] < RMAX[idx+1] || RMIN[idx-1] > RMIN[idx+1] )
370  {
371  // ERROR! The surface conflict!
372  //
373  std::ostringstream message;
374  message << "Unordered sequence of z_values detected." << G4endl
375  << " Conflicting RMAX or RMIN values!" << G4endl
376  << " Check z_values with indexes: "
377  << (idx-1) << " " << idx << " " << (idx+1) << ".";
378  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
379  "GeomSolids0002", FatalException, message );
380  }
381  }
382  }
383  }
384 #endif // G4_EXPERIMENTAL_CODE
385 
387  for(G4int a=0;a<sections;a++)
388  {
389  Length = z_values[a+1] - z_values[a];
390 
391  if( Length != 0.0 )
392  {
393  TmpAxis= XAxis;
394  TmpAxis.rotateZ(start_angle);
395 
396  // L. Broglia: Be careful in the construction of the planes,
397  // see G4FPlane
398  //
399  for( G4int b = 0; b < sides; b++ )
400  {
401  // Create inner side by calculation of points for the planar surface
402  // boundary. The order of the points gives the surface sense -> changed
403  // to explicit sense set-up by R. Chytracek, 12/02/2002
404  // We must check if a pair of two consecutive RMINs is not = 0.0,
405  // this means no inner plane exists!
406  //
407  if( RMIN[a] != 0.0 )
408  {
409  if( RMIN[a+1] != 0.0 )
410  {
411  // Standard case
412  //
413  MaxSurfaceVec[Count] =
414  CreateTrapezoidalSurface( RMIN[a], RMIN[a+1],
415  LocalOrigin, Length,
416  TmpAxis, PartAngle, EInverse );
417  }
418  else
419  {
420  // The special case of r1 > r2 where we end at the
421  // point (0,0,z[a+1])
422  //
423  MaxSurfaceVec[Count] =
424  CreateTriangularSurface( RMIN[a], RMIN[a+1],
425  LocalOrigin, Length,
426  TmpAxis, PartAngle, EInverse );
427  }
428  }
429  else if( RMIN[a+1] != 0.0 )
430  {
431  // The special case of r1 < r2 where we start at the
432  // point ( 0,0,z[a])
433  //
434  MaxSurfaceVec[Count] =
435  CreateTriangularSurface( RMIN[a], RMIN[a+1], LocalOrigin, Length,
436  TmpAxis, PartAngle, EInverse );
437  }
438  else
439  {
440  // Insert nothing into the vector of sufaces, we'll replicate
441  // the vector anyway later
442  //
443  MaxSurfaceVec[Count] = 0;
444 
445  // We need to reduce the number of planes by 1,
446  // one we have just skipped
447  //
448  nb_of_surfaces--;
449  }
450 
451  if( MaxSurfaceVec[Count] != 0 )
452  {
453  // Rotate axis back for the other surface point calculation
454  // only in the case any of the Create* methods above have been
455  // called because they modify the passed in TmpAxis
456  //
457  TmpAxis.rotateZ(-PartAngle);
458  }
459 
460  Count++;
461 
462  // Create outer side
463 
464  if( RMAX[a] != 0.0 )
465  {
466  if( RMAX[a+1] != 0.0 )
467  {
468  // Standard case
469  //
470  MaxSurfaceVec[Count] =
471  CreateTrapezoidalSurface( RMAX[a], RMAX[a+1],
472  LocalOrigin, Length,
473  TmpAxis, PartAngle, ENormal );
474  }
475  else
476  {
477  // The special case of r1 > r2 where we end
478  // at the point (0,0,z[a+1])
479  //
480  MaxSurfaceVec[Count] =
481  CreateTriangularSurface( RMAX[a], RMAX[a+1],
482  LocalOrigin, Length,
483  TmpAxis, PartAngle, ENormal );
484  }
485  }
486  else if( RMAX[a+1] != 0.0 )
487  {
488  // The special case of r1 < r2 where we start
489  // at the point ( 0,0,z[a])
490  //
491  MaxSurfaceVec[Count] =
492  CreateTriangularSurface( RMAX[a], RMAX[a+1], LocalOrigin, Length,
493  TmpAxis, PartAngle, ENormal );
494  }
495  else
496  {
497  // Two consecutive RMAX values can't be zero as
498  // it's against the definition of BREP polyhedra
499  //
500  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
501  "GeomSolids0002", FatalException,
502  "Two consecutive RMAX values cannot be zero!" );
503  }
504 
505  Count++;
506  } // End of for loop over sides
507  }
508  else
509  {
510  // Create planar surfaces perpendicular to z-axis
511 
512  ESurfaceSense OuterSurfSense, InnerSurfSense;
513 
514  if( RMAX[a] != RMAX[a+1] && RMIN[a] != RMIN[a+1] )
515  {
516  // We're about to create a planar surface perpendicular to z-axis
517  // We can have the 8 following configurations here:
518  //
519  // 1. 2. 3. 4.
520  // --+ +-- --+ +--
521  // xx|-> <-|xx xx| |xx
522  // xx+-- --+xx --+ +--
523  // xxxxx xxxxx | |
524  // xxxxx xxxxx +-- --+
525  // xx+-- --+xx |xx xx|
526  // xx|-> <-|xx +-- --+
527  // --+ +--
528  // -------------------------- Z axis
529  //
532  //
533  // 5. 6. 7. 8.
534  // --+ +-- --+ +--
535  // xx|-> <-|xx xx|-> <-|xx
536  // --+-- --+-- xx+-- --+xx
537  // <-|xx xx|-> xxxxx xxxxx
538  // +-- --+ --+xx xx+--
539  // <-|xx xx|->
540  // +-- --+
541  // -------------------------- Z axis
542  //
543  // NOTE: The pictures shows only one half of polyhedra!
544  // The arrows show the expected surface normal direction.
545  // The configuration No. 3 and 4 are not valid solids!
546 
547  // Eliminate the invalid cases 3 and 4.
548  // At this point is guaranteed that each RMIN[i] < RMAX[i]
549  // where i in in interval 0 < i < num_z_planes-1. So:
550  //
551  if( RMIN[a] > RMAX[a+1] || RMAX[a] < RMIN[a+1] )
552  {
553  std::ostringstream message;
554  message << "The values of RMIN[" << a << "] & RMAX[" << a+1
555  << "] or RMAX[" << a << "] & RMIN[" << a+1 << "]" << G4endl
556  << "generate an invalid configuration of solid: "
557  << GetName() << "!";
558  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
559  "GeomSolids0002", FatalException, message );
560  }
561 
562  // We need to clasify all the cases in order to figure out
563  // the planar surface sense
564  //
565  if( RMAX[a] > RMAX[a+1] )
566  {
567  // Cases 1, 5, 7
568  //
569  if( RMIN[a] < RMIN[a+1] )
570  {
571  // Case 1
572  OuterSurfSense = EInverse;
573  InnerSurfSense = EInverse;
574  }
575  else if( RMAX[a+1] != RMIN[a])
576  {
577  // Case 7
578  OuterSurfSense = EInverse;
579  InnerSurfSense = ENormal;
580  }
581  else
582  {
583  // Case 5
584  OuterSurfSense = EInverse;
585  InnerSurfSense = ENormal;
586  }
587  }
588  else
589  {
590  // Cases 2, 6, 8
591  if( RMIN[a] > RMIN[a+1] )
592  {
593  // Case 2
594  OuterSurfSense = ENormal;
595  InnerSurfSense = ENormal;
596  }
597  else if( RMIN[a+1] != RMAX[a] )
598  {
599  // Case 8
600  OuterSurfSense = ENormal;
601  InnerSurfSense = EInverse;
602  }
603  else
604  {
605  // Case 6
606  OuterSurfSense = ENormal;
607  InnerSurfSense = EInverse;
608  }
609  }
610 
611  TmpAxis= XAxis;
612  TmpAxis.rotateZ(start_angle);
613 
614  // Compute the outer planar surface
615  //
616  MaxSurfaceVec[Count] =
617  ComputePlanarSurface( RMAX[a], RMAX[a+1], LocalOrigin, TmpAxis,
618  sides, PartAngle, OuterSurfSense );
619  if( MaxSurfaceVec[Count] == 0 )
620  {
621  // No surface was created
622  //
623  nb_of_surfaces--;
624  }
625  Count++;
626 
627  TmpAxis= XAxis;
628  TmpAxis.rotateZ(start_angle);
629 
630  // Compute the inner planar surface
631  //
632  MaxSurfaceVec[Count] =
633  ComputePlanarSurface( RMIN[a], RMIN[a+1], LocalOrigin, TmpAxis,
634  sides, PartAngle, InnerSurfSense );
635  if( MaxSurfaceVec[Count] == 0 )
636  {
637  // No surface was created
638  //
639  nb_of_surfaces--;
640  }
641  Count++;
642 
643  // Since we can create here at maximum 2 surfaces
644  // we need to reflect this in the total
645  //
646  nb_of_surfaces -= (2*(sides-1));
647  }
648  else
649  {
650  // The case where only one of the radius values has changed
651  //
652  // RMAX RMIN
653  // change change
654  //
655  // 1 2 3 4
656  // --+ +-- ----- -----
657  // 00|-> <-|00 00000 00000
658  // 00+-- --+00 --+00 00+--
659  // 00000 00000 <-|00 00|->
660  // +-- --+
661  // --------------------------- Z axis
662  //
663  // NOTE: The picture shows only one half of polyhedra!
664 
665  G4double R1, R2;
666  ESurfaceSense SurfSense;
667 
668  // The case by case classification
669  //
670  if( RMAX[a] != RMAX[a+1] )
671  {
672  // Cases 1, 2
673  //
674  R1 = RMAX[a];
675  R2 = RMAX[a+1];
676  if( R1 > R2 )
677  {
678  // Case 1
679  //
680  SurfSense = EInverse;
681  }
682  else
683  {
684  // Case 2
685  //
686  SurfSense = ENormal;
687  }
688  }
689  else if(RMIN[a] != RMIN[a+1])
690  {
691  // Cases 3, 4
692  //
693  R1 = RMIN[a];
694  R2 = RMIN[a+1];
695  if( R1 > R2 )
696  {
697  // Case 3
698  //
699  SurfSense = ENormal;
700  }
701  else
702  {
703  // Case 4
704  //
705  SurfSense = EInverse;
706  }
707  }
708  else
709  {
710  std::ostringstream message;
711  message << "Error in construction." << G4endl
712  << " Exactly the same z, rmin and rmax given for"
713  << G4endl
714  << " consecutive indices, " << a << " and " << a+1;
715  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
716  "GeomSolids1001", JustWarning, message );
717  continue;
718  }
719  TmpAxis= XAxis;
720  TmpAxis.rotateZ(start_angle);
721 
722  MaxSurfaceVec[Count] =
723  ComputePlanarSurface( R1, R2, LocalOrigin, TmpAxis,
724  sides, PartAngle, SurfSense );
725  if( MaxSurfaceVec[Count] == 0 )
726  {
727  // No surface was created
728  //
729  nb_of_surfaces--;
730  }
731  Count++;
732 
733  // Since we can create here at maximum 1 surface
734  // we need to reflect this in the total
735  //
736  nb_of_surfaces -= ((2*sides) - 1);
737  }
738  } // End of if( Length != 0.0 )
739 
740  LocalOrigin = LocalOrigin + (Length*Axis);
741 
742  } // End of for loop over z sections
743 
744  if(opening_angle >= 2*pi-perMillion)
745  {
746  // Create the end planes for the configuration where delta phi >= 2*PI
747 
748  TmpAxis = XAxis;
749  TmpAxis.rotateZ(start_angle);
750 
751  MaxSurfaceVec[Count] =
752  ComputePlanarSurface( RMIN[0], RMAX[0], Origin, TmpAxis,
753  sides, PartAngle, ENormal );
754 
755  if( MaxSurfaceVec[Count] == 0 )
756  {
757  // No surface was created
758  //
759  nb_of_surfaces--;
760  }
761  Count++;
762 
763  // Reset plane axis
764  //
765  TmpAxis = XAxis;
766  TmpAxis.rotateZ(start_angle);
767 
768  MaxSurfaceVec[Count] =
769  ComputePlanarSurface( RMIN[sections], RMAX[sections],
770  LocalOrigin, TmpAxis,
771  sides, PartAngle, EInverse );
772 
773  if( MaxSurfaceVec[Count] == 0 )
774  {
775  // No surface was created
776  //
777  nb_of_surfaces--;
778  }
779  Count++;
780  }
781  else
782  {
783  // If delta phi < 2*PI then create a single boundary
784  // (case with RMIN=0 included)
785 
786  // Create the lateral planars
787  //
788  TmpAxis = XAxis;
789  G4Vector3D TmpAxis2 = XAxis;
790  TmpAxis.rotateZ(start_angle);
791  TmpAxis2.rotateZ(start_angle);
792  TmpAxis2.rotateZ(start_angle);
793 
794  LocalOrigin = Origin;
795  G4int points = sections*2+2;
796  G4int PointCount = 0;
797 
798  G4Point3DVector GapPointList(points);
799  G4Point3DVector GapPointList2(points);
800 
801  for(G4int d=0;d<sections+1;d++)
802  {
803  GapPointList[PointCount] = LocalOrigin + (RMAX[d]*TmpAxis);
804  GapPointList[points-1-PointCount] = LocalOrigin + (RMIN[d]*TmpAxis);
805 
806  GapPointList2[PointCount] = LocalOrigin + (RMAX[d]*TmpAxis2);
807  GapPointList2[points-1-PointCount] = LocalOrigin + (RMIN[d]*TmpAxis2);
808 
809  PointCount++;
810 
811  Length = z_values[d+1] - z_values[d];
812  LocalOrigin = LocalOrigin+(Length*Axis);
813  }
814 
815  // Add the lateral planars to the surfaces list and set/reverse sense
816  //
817  MaxSurfaceVec[Count++] = new G4FPlane( &GapPointList, 0, ENormal );
818  MaxSurfaceVec[Count++] = new G4FPlane( &GapPointList2, 0, EInverse );
819 
820  TmpAxis = XAxis;
821  TmpAxis.rotateZ(start_angle);
822  TmpAxis.rotateZ(opening_angle);
823 
824  // Create end planes
825  //
826  G4Point3DVector EndPointList ((sides+1)*2);
827  G4Point3DVector EndPointList2((sides+1)*2);
828 
829  for(G4int c=0;c<sides+1;c++)
830  {
831  // outer polylines for origin end and opposite side
832  EndPointList[c] = Origin + (RMAX[0] * TmpAxis);
833  EndPointList[(sides+1)*2-1-c] = Origin + (RMIN[0] * TmpAxis);
834  EndPointList2[c] = LocalOrigin + (RMAX[sections] * TmpAxis);
835  EndPointList2[(sides+1)*2-1-c] = LocalOrigin + (RMIN[sections] * TmpAxis);
836  TmpAxis.rotateZ(-PartAngle);
837  }
838 
839  // Add the end planes to the surfaces list
840  // Note the surface sense in this case is reversed
841  // It's because here we have created the end planes in reversed order
842  // than it's done by ComputePlanarSurface() method
843  //
844  if(RMAX[0]-RMIN[0] >= perMillion)
845  {
846  MaxSurfaceVec[Count] = new G4FPlane( &EndPointList, 0, EInverse );
847  }
848  else
849  {
850  MaxSurfaceVec[Count] = 0;
851  nb_of_surfaces--;
852  }
853 
854  Count++;
855 
856  if(RMAX[sections]-RMIN[sections] >= perMillion)
857  {
858  MaxSurfaceVec[Count] = new G4FPlane( &EndPointList2, 0, ENormal );
859  }
860  else
861  {
862  MaxSurfaceVec[Count] = 0;
863  nb_of_surfaces--;
864  }
865  }
866 
867  // Now let's replicate the relevant surfaces into
868  // G4BREPSolid's vector of surfaces
869  //
871  G4int sf = 0; G4int zeroCount = 0;
872  for( G4int srf = 0; srf < MaxNbOfSurfaces; srf++ )
873  {
874  if( MaxSurfaceVec[srf] != 0 )
875  {
876  if( sf < nb_of_surfaces )
877  {
878  SurfaceVec[sf] = MaxSurfaceVec[srf];
879  }
880  sf++;
881  }
882  else
883  {
884  zeroCount++;
885  }
886  }
887 
888  if( sf != nb_of_surfaces )
889  {
890  std::ostringstream message;
891  message << "Bad number of surfaces!" << G4endl
892  << " sf : " << sf
893  << " nb_of_surfaces: " << nb_of_surfaces
894  << " Count : " << Count;
895  G4Exception( "G4BREPSolidPolyhedra::G4BREPSolidPolyhedra()",
896  "GeomSolids0002", FatalException, message);
897  }
898 
899  // Clean up the temporary vector of surfaces
900  //
901  delete [] MaxSurfaceVec;
902 
903  Initialize();
904 }
905 
907 {
908  // Calc bounding box for solids and surfaces
909  // Convert concave planes to convex
910  //
911  ShortestDistance=1000000;
913  if(!Box || !AxisBox)
914  IsConvex();
915 
916  CalcBBoxes();
917 }
918 
920 {
921  Active(1);
922  ((G4BREPSolidPolyhedra*)this)->intersectionDistance=kInfinity;
923  StartInside(0);
924  for(register G4int a=0;a<nb_of_surfaces;a++)
925  SurfaceVec[a]->Reset();
926  ShortestDistance = kInfinity;
927 }
928 
930 {
931  // This function find if the point Pt is inside,
932  // outside or on the surface of the solid
933 
934  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
935 
936  G4Vector3D v(1, 0, 0.01);
937  G4Vector3D Pttmp(Pt);
938  G4Vector3D Vtmp(v);
939  G4Ray r(Pttmp, Vtmp);
940 
941  // Check if point is inside the Polyhedra bounding box
942  //
943  if( !GetBBox()->Inside(Pttmp) )
944  {
945  return kOutside;
946  }
947 
948  // Set the surfaces to active again
949  //
950  Reset();
951 
952  // Test if the bounding box of each surface is intersected
953  // by the ray. If not, the surface is deactivated.
954  //
956 
957  G4int hits=0, samehit=0;
958 
959  for(G4int a=0; a < nb_of_surfaces; a++)
960  {
961  G4Surface* surface = SurfaceVec[a];
962 
963  if(surface->IsActive())
964  {
965  // count the number of intersections.
966  // if this number is odd, the start of the ray is
967  // inside the volume bounded by the surfaces, so
968  // increment the number of intersection by 1 if the
969  // point is not on the surface and if this intersection
970  // was not found before
971  //
972  if( (surface->Intersect(r)) & 1 )
973  {
974  // test if the point is on the surface
975  //
976  if(surface->GetDistance() < sqrHalfTolerance)
977  {
978  return kSurface;
979  }
980  // test if this intersection was found before
981  //
982  for(G4int i=0; i<a; i++)
983  {
984  if(surface->GetDistance() == SurfaceVec[i]->GetDistance())
985  {
986  samehit++;
987  break;
988  }
989  }
990 
991  // count the number of surfaces intersected by the ray
992  //
993  if(!samehit)
994  {
995  hits++;
996  }
997  }
998  }
999  }
1000 
1001  // if the number of surfaces intersected is odd,
1002  // the point is inside the solid
1003  //
1004  return ( (hits&1) ? kInside : kOutside );
1005 }
1006 
1009 {
1010  // This function calculates the normal of the closest surface
1011  // to the given point
1012  // Note : the sense of the normal depends on the sense of the surface
1013 
1014  G4int iplane;
1015  G4bool normflag = false;
1016  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
1017 
1018  // Determine if the point is on the surface
1019  //
1020  G4double minDist = kInfinity;
1021  G4int normPlane = 0;
1022  for(iplane = 0; iplane < nb_of_surfaces; iplane++)
1023  {
1024  G4double dist = std::fabs(SurfaceVec[iplane]->HowNear(Pt));
1025  if( minDist > dist )
1026  {
1027  minDist = dist;
1028  normPlane = iplane;
1029  }
1030  if( dist < sqrHalfTolerance)
1031  {
1032  // the point is on this surface, so take this as the
1033  // the surface to consider for computing the normal
1034  //
1035  normflag = true;
1036  break;
1037  }
1038  }
1039 
1040  // Calculate the normal at this point, if the point is on the
1041  // surface, otherwise compute the normal to the closest surface
1042  //
1043  if ( normflag ) // point on surface
1044  {
1045  G4ThreeVector norm = SurfaceVec[iplane]->SurfaceNormal(Pt);
1046  return norm.unit();
1047  }
1048  else // point not on surface
1049  {
1050  G4FPlane* nPlane = (G4FPlane*)(SurfaceVec[normPlane]);
1051  G4ThreeVector hitPt = nPlane->GetSrfPoint();
1052  G4ThreeVector hitNorm = nPlane->SurfaceNormal(hitPt);
1053  return hitNorm.unit();
1054  }
1055 }
1056 
1058 {
1059  // Calculates the shortest distance ("safety") from a point
1060  // outside the solid to any boundary of this solid.
1061  // Return 0 if the point is already inside.
1062 
1063  G4double *dists = new G4double[nb_of_surfaces];
1064  G4int a;
1065 
1066  // Set the surfaces to active again
1067  //
1068  Reset();
1069 
1070  // compute the shortest distance of the point to each surfaces
1071  // Be careful : it's a signed value
1072  //
1073  for(a=0; a< nb_of_surfaces; a++)
1074  dists[a] = SurfaceVec[a]->HowNear(Pt);
1075 
1076  G4double Dist = kInfinity;
1077 
1078  // if dists[] is positive, the point is outside
1079  // so take the shortest of the shortest positive distances
1080  // dists[] can be equal to 0 : point on a surface
1081  // ( Problem with the G4FPlane : there is no inside and no outside...
1082  // So, to test if the point is inside to return 0, utilize the Inside
1083  // function. But I don`t know if it is really needed because dToIn is
1084  // called only if the point is outside )
1085  //
1086  for(a = 0; a < nb_of_surfaces; a++)
1087  if( std::fabs(Dist) > std::fabs(dists[a]) )
1088  //if( dists[a] >= 0)
1089  Dist = dists[a];
1090 
1091  delete[] dists;
1092 
1093  if(Dist == kInfinity)
1094  {
1095  // the point is inside the solid or on a surface
1096  //
1097  return 0;
1098  }
1099  else
1100  {
1101  return std::fabs(Dist);
1102  }
1103 }
1104 
1105 G4double
1107  register const G4ThreeVector& V) const
1108 {
1109  // Calculates the distance from a point outside the solid
1110  // to the solid`s boundary along a specified direction vector.
1111  //
1112  // Note : Intersections with boundaries less than the
1113  // tolerance must be ignored if the direction
1114  // is away from the boundary
1115 
1116  G4int a;
1117 
1118  // Set the surfaces to active again
1119  //
1120  Reset();
1121 
1122  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
1123  G4Vector3D Pttmp(Pt);
1124  G4Vector3D Vtmp(V);
1125  G4Ray r(Pttmp, Vtmp);
1126 
1127  // Test if the bounding box of each surface is intersected
1128  // by the ray. If not, the surface become deactive.
1129  //
1130  TestSurfaceBBoxes(r);
1131 
1132  ShortestDistance = kInfinity;
1133 
1134  for(a=0; a< nb_of_surfaces; a++)
1135  {
1136  if( SurfaceVec[a]->IsActive() )
1137  {
1138  // test if the ray intersect the surface
1139  //
1140  if( SurfaceVec[a]->Intersect(r) )
1141  {
1142  G4double surfDistance = SurfaceVec[a]->GetDistance();
1143 
1144  // if more than 1 surface is intersected,
1145  // take the nearest one
1146  //
1147  if( surfDistance < ShortestDistance )
1148  {
1149  if( surfDistance > sqrHalfTolerance )
1150  {
1151  ShortestDistance = surfDistance;
1152  }
1153  else
1154  {
1155  // the point is within the boundary
1156  // ignore it if the direction is away from the boundary
1157  //
1158  G4Vector3D Norm = SurfaceVec[a]->SurfaceNormal(Pttmp);
1159 
1160  if( (Norm * Vtmp) < 0 )
1161  {
1162  ShortestDistance = surfDistance;
1163 // ShortestDistance = surfDistance==0
1164 // ? sqrHalfTolerance
1165 // : surfDistance;
1166  }
1167  }
1168  }
1169  }
1170  }
1171  }
1172 
1173  // Be careful !
1174  // SurfaceVec->Distance is in fact the squared distance
1175  //
1176  if(ShortestDistance != kInfinity)
1177  {
1178  return std::sqrt(ShortestDistance);
1179  }
1180  else // no intersection
1181  {
1182  return kInfinity;
1183  }
1184 }
1185 
1186 G4double
1188  register const G4ThreeVector& V,
1189  const G4bool,
1190  G4bool *validNorm,
1191  G4ThreeVector * ) const
1192 {
1193  // Calculates the distance from a point inside the solid
1194  // to the solid`s boundary along a specified direction vector.
1195  // Return 0 if the point is already outside (even number of
1196  // intersections greater than the tolerance).
1197  //
1198  // Note : If the shortest distance to a boundary is less
1199  // than the tolerance, it is ignored. This allows
1200  // for a point within a tolerant boundary to leave
1201  // immediately
1202 
1203  G4int parity = 0;
1204 
1205  // Set the surfaces to active again
1206  //
1207  Reset();
1208 
1209  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
1210  G4Vector3D Ptv = Pt;
1211  G4int a;
1212 
1213  // I don`t understand this line
1214  //
1215  if(validNorm)
1216  *validNorm=false;
1217 
1218  G4Vector3D Pttmp(Pt);
1219  G4Vector3D Vtmp(V);
1220 
1221  G4Ray r(Pttmp, Vtmp);
1222 
1223  // Test if the bounding box of each surface is intersected
1224  // by the ray. If not, the surface become deactive.
1225  //
1226  TestSurfaceBBoxes(r);
1227 
1228  ShortestDistance = kInfinity; // this is actually the square of the distance
1229 
1230  for(a=0; a< nb_of_surfaces; a++)
1231  {
1232  G4double surfDistance = SurfaceVec[a]->GetDistance();
1233 
1234  if(SurfaceVec[a]->IsActive())
1235  {
1236  G4int intersects = SurfaceVec[a]->Intersect(r);
1237 
1238  // test if the ray intersects the surface
1239  //
1240  if( intersects != 0 )
1241  {
1242  parity += 1;
1243 
1244  // if more than 1 surface is intersected, take the nearest one
1245  //
1246  if( surfDistance < ShortestDistance )
1247  {
1248  if( surfDistance > sqrHalfTolerance )
1249  {
1250  ShortestDistance = surfDistance;
1251  }
1252  else
1253  {
1254  // the point is within the boundary: ignore it
1255  //
1256  parity -= 1;
1257  }
1258  }
1259  }
1260  }
1261  }
1262 
1263  G4double distance = 0.;
1264 
1265  // Be careful !
1266  // SurfaceVec->Distance is in fact the squared distance
1267  //
1268  // This condition was changed in order to give not zero answer
1269  // when particle is passing the border of two Touching Surfaces
1270  // and the distance to this surfaces is not zero.
1271  // parity is for the points on the boundary,
1272  // parity is counting only surfDistance<kCarTolerance/2.
1273  //
1274  // if((ShortestDistance != kInfinity) && (parity&1))
1275  //
1276  //
1277  if((ShortestDistance != kInfinity) || (parity&1))
1278  {
1279  distance = std::sqrt(ShortestDistance);
1280  }
1281 
1282  return distance;
1283 }
1284 
1286 {
1287  // Calculates the shortest distance ("safety") from a point
1288  // inside the solid to any boundary of this solid.
1289  // Return 0 if the point is already outside.
1290 
1291  G4double *dists = new G4double[nb_of_surfaces];
1292  G4int a;
1293 
1294  // Set the surfaces to active again
1295  //
1296  Reset();
1297 
1298  // calculate the shortest distance of the point to each surfaces
1299  // Be careful : it's a signed value
1300  //
1301  for(a=0; a< nb_of_surfaces; a++)
1302  {
1303  dists[a] = SurfaceVec[a]->HowNear(Pt);
1304  }
1305 
1306  G4double Dist = kInfinity;
1307 
1308  // if dists[] is negative, the point is inside
1309  // so take the shortest of the shortest negative distances
1310  // dists[] can be equal to 0 : point on a surface
1311  // ( Problem with the G4FPlane : there is no inside and no outside...
1312  // So, to test if the point is outside to return 0, utilize the Inside
1313  // function. But I don`t know if it is really needed because dToOut is
1314  // called only if the point is inside )
1315 
1316  for(a = 0; a < nb_of_surfaces; a++)
1317  {
1318  if( std::fabs(Dist) > std::fabs(dists[a]) )
1319  {
1320  //if( dists[a] <= 0)
1321  Dist = dists[a];
1322  }
1323  }
1324 
1325  delete[] dists;
1326 
1327  if(Dist == kInfinity)
1328  {
1329  // the point is ouside the solid or on a surface
1330  //
1331  return 0;
1332  }
1333  else
1334  {
1335  // return Dist;
1336  return std::fabs(Dist);
1337  }
1338 }
1339 
1341 {
1342  return new G4BREPSolidPolyhedra(*this);
1343 }
1344 
1345 std::ostream& G4BREPSolidPolyhedra::StreamInfo(std::ostream& os) const
1346 {
1347  // Streams solid contents to output stream.
1348 
1350  << "\n start_angle: " << constructorParams.start_angle
1351  << "\n opening_angle: " << constructorParams.opening_angle
1352  << "\n sides: " << constructorParams.sides
1353  << "\n num_z_planes: " << constructorParams.num_z_planes
1354  << "\n z_start: " << constructorParams.z_start
1355  << "\n z_values: ";
1356  G4int idx;
1357  for( idx = 0; idx < constructorParams.num_z_planes; idx++ )
1358  {
1359  os << constructorParams.z_values[idx] << " ";
1360  }
1361  os << "\n RMIN: ";
1362  for( idx = 0; idx < constructorParams.num_z_planes; idx++ )
1363  {
1364  os << constructorParams.RMIN[idx] << " ";
1365  }
1366  os << "\n RMAX: ";
1367  for( idx = 0; idx < constructorParams.num_z_planes; idx++ )
1368  {
1369  os << constructorParams.RMAX[idx] << " ";
1370  }
1371  os << "\n-----------------------------------------------------------\n";
1372 
1373  return os;
1374 }
1375 
1376 G4Surface*
1377 G4BREPSolidPolyhedra::CreateTrapezoidalSurface( G4double r1,
1378  G4double r2,
1379  const G4Point3D& origin,
1380  G4double distance,
1381  G4Vector3D& xAxis,
1382  G4double partAngle,
1383  ESurfaceSense sense )
1384 {
1385  // The surface to be returned
1386  //
1387  G4Surface* trapsrf = 0;
1388  G4Point3DVector PointList(4);
1389  G4Vector3D zAxis(0,0,1);
1390 
1391  PointList[0] = origin + ( r1 * xAxis);
1392  PointList[3] = origin + ( distance * zAxis) + (r2 * xAxis);
1393 
1394  xAxis.rotateZ( partAngle );
1395 
1396  PointList[2] = origin + ( distance * zAxis) + (r2 * xAxis);
1397  PointList[1] = origin + ( r1 * xAxis);
1398 
1399  // Return the planar trapezoidal surface
1400  //
1401  trapsrf = new G4FPlane( &PointList, 0, sense );
1402 
1403  return trapsrf;
1404 }
1405 
1406 G4Surface*
1407 G4BREPSolidPolyhedra::CreateTriangularSurface( G4double r1,
1408  G4double r2,
1409  const G4Point3D& origin,
1410  G4double distance,
1411  G4Vector3D& xAxis,
1412  G4double partAngle,
1413  ESurfaceSense sense )
1414 {
1415  // The surface to be returned
1416  //
1417  G4Surface* trapsrf = 0;
1418  G4Point3DVector PointList(3);
1419  G4Vector3D zAxis(0,0,1);
1420 
1421  PointList[0] = origin + ( r1 * xAxis);
1422  PointList[2] = origin + ( distance * zAxis) + (r2 * xAxis);
1423 
1424  xAxis.rotateZ( partAngle );
1425 
1426  if( r1 < r2 )
1427  {
1428  PointList[1] = origin + ( distance * zAxis) + (r2 * xAxis);
1429  }
1430  else
1431  {
1432  PointList[1] = origin + ( r1 * xAxis);
1433  }
1434 
1435  // Return the planar trapezoidal surface
1436  //
1437  trapsrf = new G4FPlane( &PointList, 0, sense );
1438 
1439  return trapsrf;
1440 }
1441 
1442 G4Surface*
1443 G4BREPSolidPolyhedra::ComputePlanarSurface( G4double r1,
1444  G4double r2,
1445  const G4Point3D& origin,
1446  G4Vector3D& xAxis,
1447  G4int sides,
1448  G4double partAngle,
1449  ESurfaceSense sense )
1450 {
1451  // This method can be called only when r1 != r2,
1452  // otherwise it returns 0 which means that no surface can be
1453  // created out of the given radius pair.
1454  // This method requires the xAxis to be pre-rotated properly.
1455 
1456  G4Point3DVector OuterPointList( sides );
1457  G4Point3DVector InnerPointList( sides );
1458 
1459  G4double rIn, rOut;
1460  G4Surface* planarSrf = 0;
1461 
1462  if( r1 < r2 )
1463  {
1464  rIn = r1;
1465  rOut = r2;
1466  }
1467  else if( r1 > r2 )
1468  {
1469  rIn = r2;
1470  rOut = r1;
1471  }
1472  else
1473  {
1474  // Invalid precondition, the radius values are r1 == r2,
1475  // which means we can create only polyline but no surface
1476  //
1477  return 0;
1478  }
1479 
1480  for( G4int pidx = 0; pidx < sides; pidx++ )
1481  {
1482  // Outer polyline
1483  //
1484  OuterPointList[pidx] = origin + ( rOut * xAxis);
1485  // Inner polyline
1486  //
1487  InnerPointList[pidx] = origin + ( rIn * xAxis);
1488  xAxis.rotateZ( partAngle );
1489  }
1490 
1491  if( rIn != 0.0 && rOut != 0.0 )
1492  {
1493  // Standard case
1494  //
1495  planarSrf = new G4FPlane( &OuterPointList, &InnerPointList, sense );
1496  }
1497  else if( rOut != 0.0 )
1498  {
1499  // Special case where inner radius is zero so no polyline
1500  // is actually created
1501  //
1502  planarSrf = new G4FPlane( &OuterPointList, 0, sense );
1503  }
1504  else
1505  {
1506  // No surface being created
1507  // This should not happen as filtered out by precondition check above
1508  }
1509 
1510  return planarSrf;
1511 }
1512 
1513 // In graphics_reps:
1514 
1515 #include "G4Polyhedron.hh"
1516 
1518 {
1519  return new G4PolyhedronPgon( constructorParams.start_angle,
1520  constructorParams.opening_angle,
1521  constructorParams.sides,
1522  constructorParams.num_z_planes,
1523  constructorParams.z_values,
1524  constructorParams.RMIN,
1525  constructorParams.RMAX);
1526 }