Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4BREPSolidPCone.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 // G4BREPSolidPCone.cc
32 //
33 // ----------------------------------------------------------------------
34 // The polyconical solid G4BREPSolidPCone is a shape defined by a set of
35 // inner and outer conical or cylindrical surface sections and two planes
36 // perpendicular to the Z axis. Each conical surface is defined by its
37 // radius at two different planes perpendicular to the Z-axis. Inner and
38 // outer conical surfaces are defined using common Z planes.
39 // ----------------------------------------------------------------------
40 
41 #include "G4Types.hh"
42 #include <sstream>
43 
44 #include "G4BREPSolidPCone.hh"
45 #include "G4PhysicalConstants.hh"
46 #include "G4SystemOfUnits.hh"
47 #include "G4FCylindricalSurface.hh"
48 #include "G4FConicalSurface.hh"
49 #include "G4CircularCurve.hh"
50 #include "G4FPlane.hh"
51 
52 typedef enum
53 {
54  EInverse = 0,
55  ENormal = 1
57 
59  G4double start_angle,
60  G4double opening_angle,
61  G4int num_z_planes, // sections,
62  G4double z_start,
63  G4double z_values[],
64  G4double RMIN[],
65  G4double RMAX[] )
66  : G4BREPSolid(name)
67 {
68  // Save contructor parameters
69  //
70  constructorParams.start_angle = start_angle;
71  constructorParams.opening_angle = opening_angle;
72  constructorParams.num_z_planes = num_z_planes;
73  constructorParams.z_start = z_start;
74  constructorParams.z_values = 0;
75  constructorParams.RMIN = 0;
76  constructorParams.RMAX = 0;
77 
78  if( num_z_planes > 0 )
79  {
80  constructorParams.z_values = new G4double[num_z_planes];
81  constructorParams.RMIN = new G4double[num_z_planes];
82  constructorParams.RMAX = new G4double[num_z_planes];
83  for( G4int idx = 0; idx < num_z_planes; ++idx )
84  {
85  constructorParams.z_values[idx] = z_values[idx];
86  constructorParams.RMIN[idx] = RMIN[idx];
87  constructorParams.RMAX[idx] = RMAX[idx];
88  }
89  }
90 
91  active=1;
92  InitializePCone();
93 }
94 
96  : G4BREPSolid(a)
97 {
98  constructorParams.start_angle = 0.;
99  constructorParams.opening_angle = 0.;
100  constructorParams.num_z_planes = 0;
101  constructorParams.z_start = 0.;
102  constructorParams.z_values = 0;
103  constructorParams.RMIN = 0;
104  constructorParams.RMAX = 0;
105 }
106 
108 {
109  if( constructorParams.num_z_planes > 0 )
110  {
111  delete [] constructorParams.z_values;
112  delete [] constructorParams.RMIN;
113  delete [] constructorParams.RMAX;
114  }
115 }
116 
118  : G4BREPSolid(rhs)
119 {
120  constructorParams.start_angle = rhs.constructorParams.start_angle;
121  constructorParams.opening_angle = rhs.constructorParams.opening_angle;
122  constructorParams.num_z_planes = rhs.constructorParams.num_z_planes;
123  constructorParams.z_start = rhs.constructorParams.z_start;
124  constructorParams.z_values = 0;
125  constructorParams.RMIN = 0;
126  constructorParams.RMAX = 0;
127  G4int nplanes = constructorParams.num_z_planes;
128  if( nplanes > 0 )
129  {
130  constructorParams.z_values = new G4double[nplanes];
131  constructorParams.RMIN = new G4double[nplanes];
132  constructorParams.RMAX = new G4double[nplanes];
133  for( G4int idx = 0; idx < nplanes; ++idx )
134  {
135  constructorParams.z_values[idx] = rhs.constructorParams.z_values[idx];
136  constructorParams.RMIN[idx] = rhs.constructorParams.RMIN[idx];
137  constructorParams.RMAX[idx] = rhs.constructorParams.RMAX[idx];
138  }
139  }
140 
141  InitializePCone();
142 }
143 
146 {
147  // Check assignment to self
148  //
149  if (this == &rhs) { return *this; }
150 
151  // Copy base class data
152  //
154 
155  // Copy data
156  //
157  constructorParams.start_angle = rhs.constructorParams.start_angle;
158  constructorParams.opening_angle = rhs.constructorParams.opening_angle;
159  constructorParams.num_z_planes = rhs.constructorParams.num_z_planes;
160  constructorParams.z_start = rhs.constructorParams.z_start;
161  G4int nplanes = constructorParams.num_z_planes;
162  if( nplanes > 0 )
163  {
164  delete [] constructorParams.z_values;
165  delete [] constructorParams.RMIN;
166  delete [] constructorParams.RMAX;
167  constructorParams.z_values = new G4double[nplanes];
168  constructorParams.RMIN = new G4double[nplanes];
169  constructorParams.RMAX = new G4double[nplanes];
170  for( G4int idx = 0; idx < nplanes; ++idx )
171  {
172  constructorParams.z_values[idx] = rhs.constructorParams.z_values[idx];
173  constructorParams.RMIN[idx] = rhs.constructorParams.RMIN[idx];
174  constructorParams.RMAX[idx] = rhs.constructorParams.RMAX[idx];
175  }
176  }
177 
178  InitializePCone();
179 
180  return *this;
181 }
182 
183 void G4BREPSolidPCone::InitializePCone()
184 {
185  G4double opening_angle = constructorParams.opening_angle;
186  G4int num_z_planes = constructorParams.num_z_planes;
187  G4double z_start = constructorParams.z_start;
188  G4double* z_values = constructorParams.z_values;
189  G4double* RMIN = constructorParams.RMIN;
190  G4double* RMAX = constructorParams.RMAX;
191 
192  G4int sections= constructorParams.num_z_planes-1;
193  nb_of_surfaces = 2*sections+2;
194 
196  G4ThreeVector Axis(0,0,1);
197  G4ThreeVector Origin(0,0,z_start);
198  G4double Length;
199  G4ThreeVector LocalOrigin(0,0,z_start);
200  G4int a, b = 0;
201 
202  G4ThreeVector PlaneAxis(0, 0, 1);
203  G4ThreeVector PlaneDir (0, 1, 0);
204 
206  // Test delta phi
207 
208  // At the moment (11/03/2002) the phi section is not implemented
209  // so we take a G4 application down if there is a request for such
210  // a configuration
211  //
212  if( opening_angle < 2*pi-perMillion )
213  {
214  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
215  "GeomSolids0001", FatalException,
216  "Sorry, phi-section not supported yet, try to use G4Polycone instead!");
217  }
218 
220  // Test the validity of the R values
221 
222  // RMIN[0] and RMIN[num_z_planes-1] cannot be = 0
223  // when RMIN[0] or RMIN[num_z_planes-1] are = 0
224  //
225  if( ((RMIN[0] == 0) && (RMAX[0] == 0)) ||
226  ((RMIN[num_z_planes-1] == 0) && (RMAX[num_z_planes-1] == 0)) )
227  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
228  "GeomSolids0002", FatalException,
229  "RMIN at the extremities cannot be 0 when RMAX=0 !");
230 
231  // only RMAX[0] and RMAX[num_z_planes-1] can be = 0
232  //
233  for(a = 1; a < num_z_planes-1; a++)
234  if (RMAX[a] == 0)
235  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
236  "GeomSolids0002", FatalException,
237  "RMAX inside the solid cannot be 0 !");
238 
239  // RMAX[a] must be greater than RMIN[a]
240  //
241  for(a = 1; a < num_z_planes-1; a++)
242  if (RMIN[a] >= RMAX[a])
243  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
244  "GeomSolids0002", FatalException,
245  "RMAX must be greater than RMIN in the middle Z planes !");
246 
247  if( (RMIN[num_z_planes-1] > RMAX[num_z_planes-1] )
248  || (RMIN[0] > RMAX[0]) )
249  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
250  "GeomSolids0002", FatalException,
251  "RMAX must be greater or equal than RMIN at the ends !");
252 
253  // Create surfaces
254 
255  for( a = 0; a < sections; a++)
256  {
257  // Surface length
258  //
259  Length = z_values[a+1] - z_values[a];
260 
261  if( Length == 0 )
262  {
263  // We need to create planar surface(s)
264  //
265  if( RMAX[a] != RMAX[a+1] && RMIN[a] != RMIN[a+1] )
266  {
267  // We can have the 8 following configurations here:
268  //
269  // 1. 2. 3. 4.
270  // --+ +-- --+ +--
271  // xx|-> <-|xx xx| |xx
272  // xx+-- --+xx --+ +--
273  // xxxxx xxxxx | |
274  // xxxxx xxxxx +-- --+
275  // xx+-- --+xx |xx xx|
276  // xx|-> <-|xx +-- --+
277  // --+ +--
278  // -------------------------- Z axis
279  //
282  //
283  // 5. 6. 7. 8.
284  // --+ +-- --+ +--
285  // xx|-> <-|xx xx|-> <-|xx
286  // --+-- --+-- xx+-- --+xx
287  // <-|xx xx|-> xxxxx xxxxx
288  // +-- --+ --+xx xx+--
289  // <-|xx xx|->
290  // +-- --+
291  // -------------------------- Z axis
292  //
293  // NOTE: The pictures show only one half of polycone!
294  // The arrows show the expected surface normal direction.
295  // The configuration No. 3 and 4 are not valid solids!
296 
297  // Eliminate the invalid cases 3 and 4.
298  // At this point is guaranteed that each RMIN[i] < RMAX[i]
299  // where i in in interval 0 < i < num_z_planes-1. So:
300  //
301  if( RMIN[a] > RMAX[a+1] || RMAX[a] < RMIN[a+1] )
302  {
303  std::ostringstream message;
304  message << "The values of RMIN[" << a
305  << "] & RMAX[" << a+1 << "] or RMAX[" << a
306  << "] & RMIN[" << a+1 << "]" << G4endl
307  << "generate an invalid configuration for solid: "
308  << GetName() << "!";
309  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
310  "GeomSolids0002", FatalException, message );
311  }
312 
313  ESurfaceSense UpSurfSense, LowSurfSense;
314 
315  // We need to classify all the cases in order to figure out
316  // the planar surface sense
317  //
318  if( RMAX[a] > RMAX[a+1] )
319  {
320  // Cases 1, 5, 7
321  //
322  if( RMIN[a] < RMIN[a+1] )
323  {
324  // Case 1
325  //
326  UpSurfSense = ENormal;
327  LowSurfSense = ENormal;
328  }
329  else if( RMAX[a+1] != RMIN[a])
330  {
331  // Case 7
332  //
333  UpSurfSense = ENormal;
334  LowSurfSense = EInverse;
335  }
336  else
337  {
338  // Case 5
339  //
340  UpSurfSense = ENormal;
341  LowSurfSense = EInverse;
342  }
343  }
344  else
345  {
346  // Cases 2, 6, 8
347  //
348  if( RMIN[a] > RMIN[a+1] )
349  {
350  // Case 2
351  //
352  UpSurfSense = EInverse;
353  LowSurfSense = EInverse;
354  }
355  else if( RMIN[a+1] != RMAX[a] )
356  {
357  // Case 8
358  //
359  UpSurfSense = EInverse;
360  LowSurfSense = ENormal;
361  }
362  else
363  {
364  // Case 6
365  UpSurfSense = EInverse;
366  LowSurfSense = ENormal;
367  }
368  }
369 
370  SurfaceVec[b] =
371  ComputePlanarSurface( RMAX[a], RMAX[a+1], LocalOrigin, PlaneAxis,
372  PlaneDir, UpSurfSense );
373  //SurfaceVec[b]->SetSameSense( UpSurfSense );
374  b++;
375 
376  SurfaceVec[b] =
377  ComputePlanarSurface( RMIN[a], RMIN[a+1], LocalOrigin, PlaneAxis,
378  PlaneDir, LowSurfSense );
379  //SurfaceVec[b]->SetSameSense( LowSurfSense );
380  b++;
381  }
382  else
383  {
384  // The original code creating single planar surface
385  // in case where only either RMAX or RMIN have changed
386  // at the same Z value; e.g.:
387  //
388  // RMAX RMIN
389  // change change
390  //
391  // 1 2 3 4
392  // --+ +-- ----- -----
393  // 00|-> <-|00 00000 00000
394  // 00+-- --+00 --+00 00+--
395  // 00000 00000 <-|00 00|->
396  // +-- --+
397  // --------------------------- Z axis
398  //
399  // NOTE: The picture shows only one half of polycone!
400 
401  G4double R1, R2;
402  ESurfaceSense SurfSense;
403 
404  // test where is the plane surface
405  // if( RMAX[a] != RMAX[a+1] )
406  // {
407  // R1 = RMAX[a];
408  // R2 = RMAX[a+1];
409  // }
410  // else if(RMIN[a] != RMIN[a+1])
411  // {
412  // R1 = RMIN[a];
413  // R2 = RMIN[a+1];
414  // }
415  // else
416  // {
417  // std::ostringstream message;
418  // message << "Error in construction." << G4endl
419  // << "Exactly the same z, rmin and rmax given for "
420  // << "consecutive indices, " << a << " and " << a+1;
421  // G4Exception("G4BREPSolidPCone::InitializePCone()",
422  // "GeomSolids1002", JustWarning, message);
423  // continue;
424  // }
425  if( RMAX[a] != RMAX[a+1] )
426  {
427  // Cases 1, 2
428  //
429  R1 = RMAX[a];
430  R2 = RMAX[a+1];
431  if( R1 > R2 )
432  {
433  // Case 1
434  //
435  SurfSense = ENormal;
436  }
437  else
438  {
439  // Case 2
440  //
441  SurfSense = EInverse;
442  }
443  }
444  else if(RMIN[a] != RMIN[a+1])
445  {
446  // Cases 1, 2
447  //
448  R1 = RMIN[a];
449  R2 = RMIN[a+1];
450  if( R1 > R2 )
451  {
452  // Case 3
453  //
454  SurfSense = EInverse;
455  }
456  else
457  {
458  // Case 4
459  //
460  SurfSense = ENormal;
461  }
462  }
463  else
464  {
465  std::ostringstream message;
466  message << "Error in construction." << G4endl
467  << "Exactly the same z, rmin and rmax given for"
468  << "consecutive indices, " << a << " and " << a+1;
469  G4Exception("G4BREPSolidPCone::G4BREPSolidPCone()",
470  "GeomSolids1001", JustWarning, message);
471  continue;
472  }
473 
474  SurfaceVec[b] =
475  ComputePlanarSurface( R1, R2, LocalOrigin, PlaneAxis,
476  PlaneDir, SurfSense );
477  //SurfaceVec[b]->SetSameSense( SurfSense );
478  b++;
479 
480  // SurfaceVec[b]->SetSameSense(1);
481  nb_of_surfaces--;
482  }
483  }
484  else
485  {
486  // The surface to create is conical or cylindrical
487 
488  // Inner PCone
489  //
490  if(RMIN[a] != RMIN[a+1])
491  {
492  // Create cone
493  //
494  if(RMIN[a] > RMIN[a+1])
495  {
496  G4Vector3D ConeOrigin = G4Vector3D(LocalOrigin) ;
497  SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis, Length,
498  RMIN[a+1], RMIN[a]);
500  }
501  else
502  {
503  G4Vector3D Axis2 = G4Vector3D( -1*Axis );
504  G4Vector3D LocalOrigin2 = G4Vector3D( LocalOrigin + (Length*Axis) );
505  G4Vector3D ConeOrigin = LocalOrigin2;
506  SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis2, Length,
507  RMIN[a], RMIN[a+1]);
509  }
510  b++;
511  }
512  else
513  {
514  if( RMIN[a] == 0 )
515  {
516  // Do not create any surface and decrease nb_of_surfaces
517  //
518  nb_of_surfaces--;
519  }
520  else
521  {
522  // Create cylinder
523  //
524  G4Vector3D CylOrigin = G4Vector3D( LocalOrigin );
525  SurfaceVec[b] = new G4FCylindricalSurface(CylOrigin, Axis,
526  RMIN[a], Length );
528  b++;
529  }
530  }
531 
532  // Outer PCone
533  //
534  if(RMAX[a] != RMAX[a+1])
535  {
536  // Create cone
537  //
538  if(RMAX[a] > RMAX[a+1])
539  {
540  G4Vector3D ConeOrigin = G4Vector3D( LocalOrigin );
541  SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis, Length, RMAX[a+1], RMAX[a]);
543  }
544  else
545  {
546  G4Vector3D Axis2 = G4Vector3D( -1*Axis );
547  G4Vector3D LocalOrigin2 = G4Vector3D( LocalOrigin + (Length*Axis) );
548  G4Vector3D ConeOrigin = LocalOrigin2;
549  SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis2, Length,
550  RMAX[a], RMAX[a+1]);
552  }
553  b++;
554  }
555  else
556  {
557  // Create cylinder
558  //
559  G4Vector3D CylOrigin = G4Vector3D( LocalOrigin );
560 
561  if (RMAX[a] == 0)
562  {
563  // Do not create any surface and decrease nb_of_surfaces
564  //
565  nb_of_surfaces--;
566  }
567  else
568  {
569  SurfaceVec[b] = new G4FCylindricalSurface(CylOrigin, Axis,
570  RMAX[a], Length );
572  b++;
573  }
574  }
575  }
576 
577  // Move surface origin to next section
578  //
579  LocalOrigin = LocalOrigin + (Length*Axis);
580  }
581 
583  // Create two end planes
584 
585  G4CurveVector cv;
587 
588  if(RMIN[0] < RMAX[0])
589  {
590  // Create start G4Plane & boundaries
591  //
592  G4Point3D ArcStart1a = G4Point3D( Origin + (RMIN[0]*PlaneDir) );
593  G4Point3D ArcStart1b = G4Point3D( Origin + (RMAX[0]*PlaneDir) );
594 
595  if( RMIN[0] > 0.0 )
596  {
597  tmp = new G4CircularCurve;
598  tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, Origin), RMIN[0]);
599  tmp->SetBounds(ArcStart1a, ArcStart1a);
600  tmp->SetSameSense(0);
601  cv.push_back(tmp);
602  }
603 
604  tmp = new G4CircularCurve;
605  tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, Origin), RMAX[0]);
606  tmp->SetBounds(ArcStart1b, ArcStart1b);
607  tmp->SetSameSense(1);
608  cv.push_back(tmp);
609 
610  SurfaceVec[nb_of_surfaces-2] = new G4FPlane(PlaneDir, -PlaneAxis, Origin);
613  }
614  else
615  {
616  // RMIN[0] == RMAX[0] so no surface is needed, it is a line!
617  //
618  nb_of_surfaces--;
619  }
620 
621  if(RMIN[sections] < RMAX[sections])
622  {
623  // Create end G4Plane & boundaries
624  //
625  G4Point3D ArcStart2a = G4Point3D( LocalOrigin+(RMIN[sections]*PlaneDir) );
626  G4Point3D ArcStart2b = G4Point3D( LocalOrigin+(RMAX[sections]*PlaneDir) );
627 
628  cv.clear();
629 
630  if( RMIN[sections] > 0.0 )
631  {
632  tmp = new G4CircularCurve;
633  tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, LocalOrigin),
634  RMIN[sections]);
635  tmp->SetBounds(ArcStart2a, ArcStart2a);
636  tmp->SetSameSense(0);
637  cv.push_back(tmp);
638  }
639 
640  tmp = new G4CircularCurve;
641  tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, LocalOrigin),
642  RMAX[sections]);
643  tmp->SetBounds(ArcStart2b, ArcStart2b);
644  tmp->SetSameSense(1);
645  cv.push_back(tmp);
646 
647  SurfaceVec[nb_of_surfaces-1] = new G4FPlane(PlaneDir, PlaneAxis,
648  LocalOrigin);
650 
651  // set sense of the surface
652  //
654  }
655  else
656  {
657  // RMIN[0] == RMAX[0] so no surface is needed, it is a line!
658  //
659  nb_of_surfaces--;
660  }
661 
662  Initialize();
663 }
664 
666 {
667  // Computes the bounding box for solids and surfaces
668  // Converts concave planes to convex
669  //
670  ShortestDistance=1000000;
672 
673  if(!Box || !AxisBox)
674  IsConvex();
675 
676  CalcBBoxes();
677 }
678 
680 {
681  // This function find if the point Pt is inside,
682  // outside or on the surface of the solid
683 
684  G4Vector3D v(1, 0, 0.01);
685  //G4Vector3D v(1, 0, 0); // This will miss the planar surface perp. to Z axis
686  //G4Vector3D v(0, 0, 1); // This works, however considered as hack not a fix
687  G4Vector3D Pttmp(Pt);
688  G4Vector3D Vtmp(v);
689  G4Ray r(Pttmp, Vtmp);
690 
691  // Check if point is inside the PCone bounding box
692  //
693  if( !GetBBox()->Inside(Pttmp) )
694  {
695  return kOutside;
696  }
697 
698  // Set the surfaces to active again
699  //
700  Reset();
701 
702  // Test if the bounding box of each surface is intersected
703  // by the ray. If not, the surface is deactivated.
704  //
706 
707  G4double dist = kInfinity;
708  G4bool isIntersected = false;
709  G4int WhichSurface = 0;
710 
711  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
712 
713  // Chech if the point is on the surface, otherwise
714  // find the nearest intersected suface. If there are not intersections the
715  // point is outside
716 
717  for(G4int a=0; a < nb_of_surfaces; a++)
718  {
719  G4Surface* surface = SurfaceVec[a];
720 
721  if( surface->IsActive() )
722  {
723  G4double hownear = surface->HowNear(Pt);
724 
725  if( std::fabs( hownear ) < sqrHalfTolerance )
726  {
727  return kSurface;
728  }
729 
730  if( surface->Intersect(r) )
731  {
732  isIntersected = true;
733  hownear = surface->GetDistance();
734 
735  if ( std::fabs( hownear ) < dist )
736  {
737  dist = hownear;
738  WhichSurface = a;
739  }
740  }
741  }
742  }
743 
744  if ( !isIntersected )
745  {
746  return kOutside;
747  }
748 
749  // Find the point of intersection on the surface and the normal
750  // !!!! be carefull the distance is std::sqrt(dist) !!!!
751 
752  dist = std::sqrt( dist );
753  G4Vector3D IntersectionPoint = Pttmp + dist*Vtmp;
754  G4Vector3D Normal =
755  SurfaceVec[WhichSurface]->SurfaceNormal( IntersectionPoint );
756 
757  G4double dot = Normal*Vtmp;
758 
759  return ( (dot > 0) ? kInside : kOutside );
760 }
761 
764 {
765  // This function calculates the normal of the closest surface
766  // at a point on the surface
767  // Note : the sense of the normal depends on the sense of the surface
768 
769  G4int isurf;
770  G4bool normflag = false;
771 
772  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
773 
774  // Determine if the point is on the surface
775  //
776  G4double minDist = kInfinity;
777  G4int normSurface = 0;
778  for(isurf = 0; isurf < nb_of_surfaces; isurf++)
779  {
780  G4double dist = std::fabs(SurfaceVec[isurf]->HowNear(Pt));
781  if( minDist > dist )
782  {
783  minDist = dist;
784  normSurface = isurf;
785  }
786  if( dist < sqrHalfTolerance)
787  {
788  // the point is on this surface
789  //
790  normflag = true;
791  break;
792  }
793  }
794 
795  // Calculate the normal at this point, if the point is on the
796  // surface, otherwise compute the normal to the closest surface
797  //
798  if ( normflag ) // point on surface
799  {
801  return norm.unit();
802  }
803  else // point not on surface
804  {
805  G4Surface* nSurface = SurfaceVec[normSurface];
806  G4ThreeVector hitPt = nSurface->GetClosestHit();
807  G4ThreeVector hitNorm = nSurface->SurfaceNormal(hitPt);
808  return hitNorm.unit();
809  }
810 }
811 
813 {
814  // Calculates the shortest distance ("safety") from a point
815  // outside the solid to any boundary of this solid.
816  // Return 0 if the point is already inside.
817 
818  G4double *dists = new G4double[nb_of_surfaces];
819  G4int a;
820 
821  // Set the surfaces to active again
822  //
823  Reset();
824 
825  // Compute the shortest distance of the point to each surfaces
826  // Be careful : it's a signed value
827  //
828  for(a=0; a< nb_of_surfaces; a++)
829  dists[a] = SurfaceVec[a]->HowNear(Pt);
830 
831  G4double Dist = kInfinity;
832 
833  // if dists[] is positive, the point is outside
834  // so take the shortest of the shortest positive distances
835  // dists[] can be equal to 0 : point on a surface
836  // ( Problem with the G4FPlane : there is no inside and no outside...
837  // So, to test if the point is inside to return 0, utilize the Inside
838  // function. But I don`t know if it is really needed because dToIn is
839  // called only if the point is outside )
840  //
841  for(a = 0; a < nb_of_surfaces; a++)
842  if( std::fabs(Dist) > std::fabs(dists[a]) )
843  //if( dists[a] >= 0)
844  Dist = dists[a];
845 
846  delete[] dists;
847 
848  if(Dist == kInfinity)
849  // the point is inside the solid or on a surface
850  //
851  return 0;
852  else
853  return std::fabs(Dist);
854 }
855 
857  register const G4ThreeVector& V) const
858 {
859  // Calculates the distance from a point outside the solid
860  // to the solid`s boundary along a specified direction vector.
861  //
862  // Note : Intersections with boundaries less than the
863  // tolerance must be ignored if the direction
864  // is away from the boundary
865 
866  G4int a;
867 
868  // Set the surfaces to active again
869  //
870  Reset();
871 
872  G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
873  G4Vector3D Pttmp(Pt);
874  G4Vector3D Vtmp(V);
875  G4Ray r(Pttmp, Vtmp);
876 
877  // Test if the bounding box of each surface is intersected
878  // by the ray. If not, the surface become deactive.
879  //
881 
882  ShortestDistance = kInfinity;
883 
884  for(a=0; a< nb_of_surfaces; a++)
885  {
886  if(SurfaceVec[a]->IsActive())
887  {
888  // test if the ray intersect the surface
889  //
890  G4Vector3D Norm = SurfaceVec[a]->SurfaceNormal(Pttmp);
891  G4double hownear = SurfaceVec[a]->HowNear(Pt);
892 
893  if( (Norm * Vtmp) < 0 && std::fabs(hownear) < sqrHalfTolerance )
894  return 0;
895 
896  if( (SurfaceVec[a]->Intersect(r)) )
897  {
898  // if more than 1 surface is intersected,
899  // take the nearest one
900  G4double distance = SurfaceVec[a]->GetDistance();
901 
902  if( distance < ShortestDistance )
903  {
904  if( distance > sqrHalfTolerance )
905  {
906  ShortestDistance = distance;
907  }
908  }
909  }
910  }
911  }
912 
913  // Be careful !
914  // SurfaceVec->Distance is in fact the squared distance
915  //
916  if(ShortestDistance != kInfinity)
917  return( std::sqrt(ShortestDistance) );
918  else
919  // no intersection
920  //
921  return kInfinity;
922 }
923 
925  register const G4ThreeVector& V,
926  const G4bool,
927  G4bool *validNorm,
928  G4ThreeVector *) const
929 {
930  // Calculates the distance from a point inside the solid
931  // to the solid`s boundary along a specified direction vector.
932  // Return 0 if the point is already outside.
933  //
934  // Note : If the shortest distance to a boundary is less
935  // than the tolerance, it is ignored. This allows
936  // for a point within a tolerant boundary to leave
937  // immediately
938 
939  // Set the surfaces to active again
940  //
941  Reset();
942 
943  const G4double sqrHalfTolerance = kCarTolerance*kCarTolerance*0.25;
944  G4Vector3D Ptv = G4Vector3D( Pt );
945  G4int a;
946 
947  // I don`t understand this line
948  //
949  if(validNorm)
950  *validNorm=false;
951 
952  G4Vector3D Pttmp(Pt);
953  G4Vector3D Vtmp(V);
954 
955  G4Ray r(Pttmp, Vtmp);
956 
957  // Test if the bounding box of each surface is intersected
958  // by the ray. If not, the surface become deactive.
959  //
961 
962  ShortestDistance = kInfinity;
963 
964  for(a=0; a< nb_of_surfaces; a++)
965  {
966  if( SurfaceVec[a]->IsActive() )
967  {
968  G4Vector3D Norm = SurfaceVec[a]->SurfaceNormal(Pttmp);
969  G4double hownear = SurfaceVec[a]->HowNear(Pt);
970 
971  if( (Norm * Vtmp) > 0 && std::fabs( hownear ) < sqrHalfTolerance )
972  return 0;
973 
974  // test if the ray intersect the surface
975  //
976  if( SurfaceVec[a]->Intersect(r) )
977  {
978  // if more than 1 surface is intersected,
979  // take the nearest one
980  //
981  G4double distance = SurfaceVec[a]->GetDistance();
982 
983  if( distance < ShortestDistance )
984  {
985  if( distance > sqrHalfTolerance )
986  {
987  ShortestDistance = distance;
988  }
989  }
990  }
991  }
992  }
993 
994  // Be careful !
995  // SurfaceVec->Distance is in fact the squared distance
996  //
997  if(ShortestDistance != kInfinity)
998  return std::sqrt(ShortestDistance);
999  else
1000  // if no intersection is founded, the point is outside
1001  //
1002  return 0;
1003 }
1004 
1006 {
1007  // Calculates the shortest distance ("safety") from a point
1008  // inside the solid to any boundary of this solid.
1009  // Return 0 if the point is already outside.
1010 
1011  G4double *dists = new G4double[nb_of_surfaces];
1012  G4int a;
1013 
1014  // Set the surfaces to active again
1015  Reset();
1016 
1017  // calcul of the shortest distance of the point to each surfaces
1018  // Be careful : it's a signed value
1019  //
1020  for(a=0; a< nb_of_surfaces; a++)
1021  dists[a] = SurfaceVec[a]->HowNear(Pt);
1022 
1023  G4double Dist = kInfinity;
1024 
1025  // if dists[] is negative, the point is inside
1026  // so take the shortest of the shortest negative distances
1027  // dists[] can be equal to 0 : point on a surface
1028  // ( Problem with the G4FPlane : there is no inside and no outside...
1029  // So, to test if the point is outside to return 0, utilize the Inside
1030  // function. But I don`t know if it is really needed because dToOut is
1031  // called only if the point is inside )
1032 
1033  for(a = 0; a < nb_of_surfaces; a++)
1034  if( std::fabs(Dist) > std::fabs(dists[a]) )
1035  //if( dists[a] <= 0)
1036  Dist = dists[a];
1037 
1038  delete[] dists;
1039 
1040  if(Dist == kInfinity)
1041  // the point is ouside the solid or on a surface
1042  //
1043  return 0;
1044  else
1045  return std::fabs(Dist);
1046 }
1047 
1049 {
1050  return new G4BREPSolidPCone(*this);
1051 }
1052 
1053 std::ostream& G4BREPSolidPCone::StreamInfo(std::ostream& os) const
1054 {
1055  // Streams solid contents to output stream.
1056 
1058  << "\n start_angle: " << constructorParams.start_angle
1059  << "\n opening_angle: " << constructorParams.opening_angle
1060  << "\n num_z_planes: " << constructorParams.num_z_planes
1061  << "\n z_start: " << constructorParams.z_start
1062  << "\n z_values: ";
1063  G4int idx;
1064  for( idx = 0; idx < constructorParams.num_z_planes; idx++ )
1065  {
1066  os << constructorParams.z_values[idx] << " ";
1067  }
1068  os << "\n RMIN: ";
1069  for( idx = 0; idx < constructorParams.num_z_planes; idx++ )
1070  {
1071  os << constructorParams.RMIN[idx] << " ";
1072  }
1073  os << "\n RMAX: ";
1074  for( idx = 0; idx < constructorParams.num_z_planes; idx++ )
1075  {
1076  os << constructorParams.RMAX[idx] << " ";
1077  }
1078  os << "\n-----------------------------------------------------------\n";
1079 
1080  return os;
1081 }
1082 
1084 {
1085  Active(1);
1086  ((G4BREPSolidPCone*)this)->intersectionDistance=kInfinity;
1087  StartInside(0);
1088  for(register int a=0;a<nb_of_surfaces;a++)
1089  SurfaceVec[a]->Reset();
1090  ShortestDistance = kInfinity;
1091 }
1092 
1093 G4Surface*
1094 G4BREPSolidPCone::ComputePlanarSurface( G4double r1,
1095  G4double r2,
1096  G4ThreeVector& origin,
1097  G4ThreeVector& planeAxis,
1098  G4ThreeVector& planeDirection,
1099  G4int surfSense )
1100 {
1101  // The planar surface to return
1102  G4Surface* planarFace = 0;
1103 
1104  G4CurveVector cv1;
1105  G4CircularCurve *tmp1, *tmp2;
1106 
1107  // Create plane surface
1108  G4Point3D ArcStart1 = G4Point3D( origin + (r1 * planeDirection) );
1109  G4Point3D ArcStart2 = G4Point3D( origin + (r2 * planeDirection) );
1110 
1111  if(r1 != 0)
1112  {
1113  tmp1 = new G4CircularCurve;
1114  tmp1->Init(G4Axis2Placement3D( planeDirection, planeAxis, origin), r1);
1115  tmp1->SetBounds(ArcStart1, ArcStart1);
1116 
1117  if( surfSense )
1118  tmp1->SetSameSense(1);
1119  else
1120  tmp1->SetSameSense(0);
1121 
1122  cv1.push_back(tmp1);
1123  }
1124 
1125  if(r2 != 0)
1126  {
1127  tmp2 = new G4CircularCurve;
1128  tmp2->Init(G4Axis2Placement3D( planeDirection, planeAxis, origin), r2);
1129  tmp2->SetBounds(ArcStart2, ArcStart2);
1130 
1131  if( surfSense )
1132  tmp2->SetSameSense(0);
1133  else
1134  tmp2->SetSameSense(1);
1135 
1136  cv1.push_back(tmp2);
1137  }
1138 
1139  planarFace = new G4FPlane( planeDirection, planeAxis, origin, surfSense );
1140 
1141  planarFace->SetBoundaries(&cv1);
1142 
1143  return planarFace;
1144 }
1145 
1146 // In graphics_reps:
1147 
1148 #include "G4Polyhedron.hh"
1149 
1151 {
1152  return new G4PolyhedronPcon( constructorParams.start_angle,
1153  constructorParams.opening_angle,
1154  constructorParams.num_z_planes,
1155  constructorParams.z_values,
1156  constructorParams.RMIN,
1157  constructorParams.RMAX );
1158 }