Import Geant4 0.1.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-08 15:09:25 +02:00
parent b97f8d0df7
commit aaa409b6ee
2922 changed files with 55107 additions and 81674 deletions
+3 -2
View File
@@ -1,4 +1,4 @@
# $Id: GNUmakefile,v 2.0 1998/07/02 17:02:56 gunter Exp $
# $Id: GNUmakefile,v 1.2 1999/04/15 12:23:43 johna Exp $
# ----------------------------------------------------------------
# GNUmakefile for geometry/CSG library. Gabriele Cosmo, 16/11/96.
# ----------------------------------------------------------------
@@ -11,7 +11,8 @@ endif
include $(G4INSTALL)/config/architecture.gmk
CPPFLAGS += -I$(G4BASE)/graphics_reps/include \
CPPFLAGS += -I$(G4BASE)/intercoms/include \
-I$(G4BASE)/graphics_reps/include \
-I$(G4BASE)/global/management/include \
-I$(G4BASE)/global/HEPRandom/include \
-I$(G4BASE)/global/HEPGeometry/include \
+71
View File
@@ -0,0 +1,71 @@
$Id: History,v 1.6 1999/05/21 19:32:36 japost Exp $
-------------------------------------------------------------------
=========================================================
Geant4 - an Object-Oriented Toolkit for Simulation in HEP
=========================================================
Sub-Category History file
-------------------------
This file should be used by G4 developers and category coordinators
to briefly summarize all major modifications introduced in the code
and keep track of all directory-tags.
It DOES NOT substitute the CVS log-message one should put at every
committal in the CVS repository !
----------------------------------------------------------
* Reverse chronological order (last date on top), please *
----------------------------------------------------------
May 18, 99 David Wiliams
Replaced 1/DBL_MAX with DBL_MIN (valid correction, seen in tests for STL)
in G4PolyPhiFace.cc, G4PolyconeSide.cc and G4PolyhedraSide.cc
Apr 29, 99 David Wiliams
G4Polyhedra and G4Polycone (and G4VCSGfaceted) modified:
1. Implemented correct copy constructors and assignment operators.
2. Fix some leaks for tracks that pass exactly through an edge.
Some leaks still remain: particularly if a track passes through
a corner and between the curved edges of G4Polycone.
3. G4Polyhedra argument numSide changed to G4int (from G4double)
Apr 13, 99 Vladimir Grichine and Simone Giani
Minor consistency fix to 8 basic CSG solids:
Tolerance used in calculation of extent but not in one place, and not another
- this tripped up the client code.
Feb 16, 99 David Williams
Repaired bugs in G4Polycone (G4PolyconeSide.cc) as found in
test/testG4Polycone and missed in below.
Updated definition of DistanceToIn(p) and DistanceToOut(p) to
return zero when the point p is on the surface of the solid.
Feb 12, 99 David Williams
src/G4PolyconeSide.cc updated (revision 1.4) to fix a bug discovered by
test/testG4Polycone.
Feb 9, 99 David C. Williams (davidw@scipp.ucsc.edu)
I've committed new versions of the CSG Polycone and Polyhedra in the
geant4 repository, including a new utility class called
G4ReduciblePolygon. The new versions fix several subtle bugs which my
"test3" batch geometry testing code uncovered. In addition, the new class
G4ReduciblePolygon is used to run strict tests on the validity of input
parameters.
To fix a bug in Polyhedra, I had to back out some fancy code that
allowed it to calculate intersections at a speed that was independent of
the number of sides. The new version now runs at a speed proportional to
the number of sides, and is thus much slower for polyhedras with many
sides. I can fix this, but I thought it would be best to get the bug fixes
in as soon as possible.
Feb 10, 99 John Apostolakis
History file created.
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Box.hh,v 2.1 1998/07/12 02:56:49 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Box.hh,v 1.1 1999/01/07 16:07:51 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Box
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4CSGSolid.hh,v 2.0 1998/07/02 17:01:58 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4CSGSolid.hh,v 1.1 1999/01/07 16:07:51 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4CSGSolid
@@ -4,6 +4,14 @@
// Declaration of a utility class of a polycon that can be clipped
// by a voxel
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4ClippablePolycon_hh
#define G4ClippablePolycon_hh
@@ -23,18 +31,37 @@ typedef RWTValOrderedVector<G4ThreeVector> G4ThreeVectorList;
class G4ClippablePolygon {
public:
G4ClippablePolygon() {;}
~G4ClippablePolygon() {;}
virtual ~G4ClippablePolygon() {;}
void AddVertexInOrder( const G4ThreeVector vertex );
void ClearAllVertices();
virtual void AddVertexInOrder( const G4ThreeVector vertex );
virtual void ClearAllVertices();
void Clip( const G4VoxelLimits &voxelLimit );
virtual void SetNormal( const G4ThreeVector &newNormal ) { normal = newNormal; }
virtual const G4ThreeVector GetNormal() const { return normal; }
void GetExtent( const EAxis axis,
G4double &min, G4double &max );
virtual const G4bool Clip( const G4VoxelLimits &voxelLimit );
virtual const G4bool PartialClip( const G4VoxelLimits &voxelLimit, const EAxis IgnoreMe );
virtual void ClipAlongOneAxis( const G4VoxelLimits &voxelLimit, const EAxis axis );
virtual const G4bool GetExtent( const EAxis axis,
G4double &min, G4double &max ) const;
virtual const G4ThreeVector *GetMinPoint( const EAxis axis ) const;
virtual const G4ThreeVector *GetMaxPoint( const EAxis axis ) const;
virtual const G4int GetNumVertices() const { return vertices.entries(); }
virtual const G4bool Empty() const { return vertices.entries()==0; }
virtual const G4bool InFrontOf( const G4ClippablePolygon &other, EAxis axis ) const;
virtual const G4bool BehindOf( const G4ClippablePolygon &other, EAxis axis ) const;
virtual const G4bool GetPlanerExtent( const G4ThreeVector &pointOnPlane,
const G4ThreeVector &planeNormal,
G4double &min, G4double &max ) const;
private:
protected:
G4ThreeVectorList vertices;
G4ThreeVector normal;
void ClipToSimpleLimits( G4ThreeVectorList& pPolygon,
G4ThreeVectorList& outputPolygon,
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Cons.hh,v 2.0 1998/07/02 17:01:56 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Cons.hh,v 1.1 1999/01/07 16:07:52 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Cons
//
@@ -5,6 +5,14 @@
// is clearly outside a polyhedra or ploycone or deciding if
// a trajectory is clearly going to miss said shapes.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4EnclosingCylinder_hh
#define G4EnclosingCylinder_hh
@@ -12,15 +20,17 @@
#include "geomdefs.hh"
#include "G4ThreeVector.hh"
class G4ReduciblePolygon;
class G4EnclosingCylinder {
public:
G4EnclosingCylinder( const G4double r[], const G4double z[], const G4int n,
G4EnclosingCylinder( const G4ReduciblePolygon *rz,
const G4bool phiIsOpen,
const G4double startPhi, const G4double totalPhi );
~G4EnclosingCylinder();
G4bool Outside( const G4ThreeVector &p ) const;
G4bool Misses( const G4ThreeVector &p, const G4ThreeVector &v ) const;
G4bool MustBeOutside( const G4ThreeVector &p ) const;
G4bool ShouldMiss( const G4ThreeVector &p, const G4ThreeVector &v ) const;
protected:
G4double radius; // radius of our cylinder
@@ -34,6 +44,8 @@ class G4EnclosingCylinder {
dx1, dy1;
G4double rx2, ry2,
dx2, dy2;
G4bool concave; // True, if x/y cross section is concave
};
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Hype.hh,v 2.1 1998/07/12 02:56:49 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Hype.hh,v 1.1 1999/01/07 16:07:52 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
//
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Para.hh,v 2.0 1998/07/02 17:01:59 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Para.hh,v 1.1 1999/01/07 16:07:52 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Para
//
@@ -8,13 +8,23 @@
// the z axis. It has boundaries that are straight lines of arbitrary length
// and direction, but with corners aways on the same side of the z axis.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4PolyPhiFace_hh
#define G4PolyPhiFace_hh
#include "G4VCSGface.hh"
class G4ReduciblePolygon;
typedef struct {
G4double r, z; // position
G4double x, y, r, z; // position
G4double rNorm,
zNorm; // r/z normal
G4ThreeVector norm3D; // 3D normal
@@ -30,9 +40,12 @@ typedef struct {
class G4PolyPhiFace : public G4VCSGface {
public:
G4PolyPhiFace( const G4double *r, const G4double *z, const G4int n,
const G4double phi, const G4double deltaPhi, const G4bool start );
G4PolyPhiFace( const G4ReduciblePolygon *rz,
const G4double phi, const G4double deltaPhi, const G4double phiOther );
virtual ~G4PolyPhiFace();
G4PolyPhiFace( const G4PolyPhiFace &source );
G4PolyPhiFace *operator=( const G4PolyPhiFace &source );
G4bool Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
@@ -51,7 +64,11 @@ class G4PolyPhiFace : public G4VCSGface {
void CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &tranform,
G4double &min, G4double &max );
G4SolidExtentList &extentList );
G4VCSGface *Clone() { return new G4PolyPhiFace(*this); }
void Diagnose( G4VSolid *solid );
protected:
G4PolyPhiFaceEdge *edges; // The edges of the face
@@ -62,11 +79,25 @@ class G4PolyPhiFace : public G4VCSGface {
G4ThreeVector surface; // Point on surface
G4double rMin, rMax, // Extent in r
zMin, zMax; // Extent in z
G4bool allBehind; // True if the entire polycone/polyhedra is behind the place
// of this face
G4bool InsideEdgesExact( const G4double r, const G4double z,
const G4double normSign, const G4ThreeVector &p, const G4ThreeVector &v );
G4bool InsideEdges( const G4double r, const G4double z );
G4bool InsideEdges( const G4double r, const G4double z,
G4double *distRZ2, G4PolyPhiFaceVertex **base3Dnorm=0,
G4ThreeVector **head3Dnorm=0 );
inline G4double ExactZOrder( const G4double z,
const G4double qx, const G4double qy, const G4double qz,
const G4ThreeVector &v,
const G4double normSign,
const G4PolyPhiFaceVertex *vert ) const;
void CopyStuff( const G4PolyPhiFace &source );
};
#include "G4PolyPhiFace.icc"
#endif
@@ -0,0 +1,44 @@
//
// G4PolyPhiFace.icc
//
// Implementation of inline methods of G4PolyPhiFace
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
//
// ExactZOrder
//
// Decide precisely whether a trajectory passes to the left, right, or exactly
// passes through the z position of a vertex point in our face.
//
// Result is only determined within an arbitrary (positive) factor.
// > 0 to the right
// < 0 to the left
// = 0 exactly on top of
// In 99.9999% of the cases, a trivial calculation is used. In difficult
// cases, a precise, compliant calculation is relied on.
//
inline G4double G4PolyPhiFace::ExactZOrder( const G4double z,
const G4double qx, const G4double qy, const G4double qz,
const G4ThreeVector &v,
const G4double normSign,
const G4PolyPhiFaceVertex *vert ) const {
G4double answer = vert->z - z;
if (fabs(answer) < kCarTolerance) {
G4ThreeVector qa( qx - vert->x + radial.x(),
qy - vert->y + radial.y(), qz - vert->z ),
qb( qx - vert->x, qy - vert->y, qz - vert->z );
G4ThreeVector qacb = qa.cross(qb);
answer = normSign*qacb.dot(v)*(normal.y()*radial.x()-normal.x()*radial.y());
}
return answer;
}
@@ -2,7 +2,15 @@
// G4Polycone.hh
//
// Declaration of a CSG type "PCON" geant volume, inherited from
// class G4CSGSolid
// class G4VCSGSolid
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4Polycone_hh
@@ -11,6 +19,9 @@
#include "G4VCSGfaceted.hh"
#include "G4PolyconeSide.hh"
class G4EnclosingCylinder;
class G4ReduciblePolygon;
class G4VCSGface;
class G4Polycone : public G4VCSGfaceted
@@ -33,6 +44,19 @@ class G4Polycone : public G4VCSGfaceted
virtual ~G4Polycone();
G4Polycone( const G4Polycone &source );
const G4Polycone &operator=( const G4Polycone &source );
//
// A couple overrides to speed things up
//
EInside Inside( const G4ThreeVector &p ) const;
G4double DistanceToIn( const G4ThreeVector &p, const G4ThreeVector &v ) const;
G4double DistanceToIn( const G4ThreeVector &p ) const { return G4VCSGfaceted::DistanceToIn(p); }
//
// The usual G4VCSGface stuff
//
void ComputeDimensions( G4VPVParameterisation* p,
const G4int n,
const G4VPhysicalVolume* pRep);
@@ -42,6 +66,9 @@ class G4Polycone : public G4VCSGfaceted
G4Polyhedron* CreatePolyhedron() const;
G4NURBS* CreateNURBS() const;
//
// Access routines
//
inline G4double GetStartPhi() const { return startPhi; }
inline G4double GetEndPhi() const { return endPhi; }
inline G4bool IsOpen() const { return phiIsOpen; }
@@ -61,27 +88,34 @@ class G4Polycone : public G4VCSGfaceted
//
// The following is temporary until graphics_reps is brought up to this design
//
typedef struct {
struct G4PolyconeHistorical {
G4PolyconeHistorical() {;}
~G4PolyconeHistorical();
G4PolyconeHistorical( const G4PolyconeHistorical &source );
G4double Start_angle;
G4double Opening_angle;
G4int Num_z_planes;
G4double *Z_values;
G4double *Rmin;
G4double *Rmax;
G4bool exist;
} G4PolyconeKluge;
};
G4PolyconeKluge original_parameters;
G4PolyconeHistorical *original_parameters;
//
// Generic initializer, call by all constructors
// Our quick test
//
G4EnclosingCylinder *enclosingCylinder;
//
// Generic initializer, called by all constructors
//
void Create( const G4double phiStart, // initial phi starting angle
const G4double phiTotal, // total phi angle
const G4int numRZ, // number corners in r,z space
const G4double r[], // r coordinate of these corners
const G4double z[] ); // z coordinate of these corners
G4ReduciblePolygon *rz ); // r/z coordinate of these corners
void CopyStuff( const G4Polycone &source );
};
#endif
@@ -21,13 +21,16 @@ class G4PolyconeSide : public G4VCSGface {
const G4PolyconeSideRZ *head,
const G4PolyconeSideRZ *nextRZ,
const G4double phiStart, const G4double deltaPhi,
const G4bool phiIsOpen );
const G4bool phiIsOpen, const G4bool isAllBehind=false );
virtual ~G4PolyconeSide();
G4PolyconeSide( const G4PolyconeSide &source );
G4PolyconeSide *operator=( const G4PolyconeSide &source );
G4bool Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &normal, G4bool &allBehind );
G4ThreeVector &normal, G4bool &isAllBehind );
G4double Distance( const G4ThreeVector &p, const G4bool outgoing );
@@ -41,27 +44,45 @@ class G4PolyconeSide : public G4VCSGface {
void CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &tranform,
G4double &min, G4double &max );
G4SolidExtentList &extentList );
G4VCSGface *Clone() { return new G4PolyconeSide( *this ); }
protected:
G4double r[2], z[2]; // r, z parameters, in specified order
G4double startPhi, // Start phi (0 to 2pi), if phiIsOpen
deltaPhi; // Delta phi (0 to 2pi), if phiIsOpen
G4bool phiIsOpen; // True if there is a phi slice
G4bool allBehind; // True if the entire solid is "behind" this face
G4IntersectingCone *cone; // Our intersecting utility class
G4double rNorm, zNorm; // Normal to surface in r,z space
G4double rS, zS; // Unit vector along surface in r,z space
G4double length; // Length of face in r,z space
G4double prevRS,
prevZS; // Unit vector along previous polyconeSide
G4double nextRS,
nextZS; // Unit vector along next polyconeSide
G4double rNormEdge[2],
zNormEdge[2]; // Normal to edges
G4ThreeVector *corners; // The coordinates of the corners (if phiIsOpen)
G4double DistanceAway( const G4ThreeVector &p, const G4bool opposite,
G4double &distOutside2, G4double *rzNorm );
G4double &distOutside2, G4double *rzNorm=0 );
G4bool PointOnCone( const G4ThreeVector &p, G4ThreeVector &normal );
G4bool PointOnCone( const G4ThreeVector &hit, const G4double normSign,
const G4ThreeVector &p, const G4ThreeVector &v, G4ThreeVector &normal );
void CopyStuff( const G4PolyconeSide &source );
static void FindLineIntersect( const G4double x1, const G4double y1,
const G4double tx1, const G4double ty1,
const G4double x2, const G4double y2,
const G4double tx2, const G4double ty2,
G4double &x, G4double &y );
};
@@ -4,6 +4,14 @@
// Declaration of a CSG type "PCON" geant volume, inherited from
// class G4CSGSolid
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4Polyhedra_hh
#define G4Polyhedra_hh
@@ -12,13 +20,14 @@
#include "G4PolyhedraSide.hh"
class G4EnclosingCylinder;
class G4ReduciblePolygon;
class G4Polyhedra : public G4VCSGfaceted {
public:
G4Polyhedra( G4String name,
const G4double phiStart, // initial phi starting angle
const G4double phiTotal, // total phi angle
const G4double numSide, // number sides
const G4int numSide, // number sides
const G4int numZPlanes, // number of z planes
const G4double zPlane[], // position of z planes
const G4double rInner[], // tangent distance to inner surface
@@ -27,12 +36,15 @@ class G4Polyhedra : public G4VCSGfaceted {
G4Polyhedra( G4String name,
const G4double phiStart, // initial phi starting angle
const G4double phiTotal, // total phi angle
const G4double numSide, // number sides
const G4int numSide, // number sides
const G4int numRZ, // number corners in r,z space
const G4double r[], // r coordinate of these corners
const G4double z[] ); // z coordinate of these corners
virtual ~G4Polyhedra();
G4Polyhedra( const G4Polyhedra &source );
const G4Polyhedra &operator=( const G4Polyhedra &source );
//
// A couple overrides to speed things up
@@ -66,12 +78,16 @@ class G4Polyhedra : public G4VCSGfaceted {
G4double endPhi; // end phi value (0 < endPhi-phiStart < 2pi)
G4bool phiIsOpen; // true if there is a phi segment
G4int numCorner; // number RZ points
G4PolyhedraSideRZ *corners; // corner r,z points
G4PolyhedraSideRZ *corners; // our corners
//
// The following is temporary until graphics_reps is brought up to this design
//
typedef struct {
struct G4PolyhedraHistorical {
G4PolyhedraHistorical() {;}
~G4PolyhedraHistorical();
G4PolyhedraHistorical( const G4PolyhedraHistorical &source );
G4double Start_angle;
G4double Opening_angle;
G4int numSide;
@@ -79,10 +95,9 @@ class G4Polyhedra : public G4VCSGfaceted {
G4double *Z_values;
G4double *Rmin;
G4double *Rmax;
G4bool exist;
} G4PolyhedraKluge;
};
G4PolyhedraKluge original_parameters;
G4PolyhedraHistorical *original_parameters;
//
// Our quick test
@@ -94,10 +109,11 @@ class G4Polyhedra : public G4VCSGfaceted {
//
void Create( const G4double phiStart, // initial phi starting angle
const G4double phiTotal, // total phi angle
const G4double numSide, // number sides
const G4int numRZ, // number corners in r,z space
const G4double r[], // r coordinate of these corners
const G4double z[] ); // z coordinate of these corners
const G4int numSide, // number sides
G4ReduciblePolygon *rz ); // rz coordinates
void CopyStuff( const G4Polyhedra &source );
void DeleteStuff();
};
#endif
@@ -3,6 +3,14 @@
//
// Declaration of a face that represents one segmented side of a polyhedra
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4PolyhedraSide_hh
#define G4PolyhedraSide_hh
@@ -22,9 +30,12 @@ class G4PolyhedraSide : public G4VCSGface {
const G4PolyhedraSideRZ *nextRZ,
const G4int numSide,
const G4double phiStart, const G4double phiTotal,
const G4bool phiIsOpen );
const G4bool phiIsOpen, const G4bool isAllBehind=false );
virtual ~G4PolyhedraSide();
G4PolyhedraSide( const G4PolyhedraSide &source );
G4PolyhedraSide *operator=( const G4PolyhedraSide &source );
G4bool Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
@@ -42,7 +53,9 @@ class G4PolyhedraSide : public G4VCSGface {
void CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &tranform,
G4double &min, G4double &max );
G4SolidExtentList &extentList );
G4VCSGface *Clone() { return new G4PolyhedraSide( *this ); }
protected:
//
@@ -70,8 +83,10 @@ class G4PolyhedraSide : public G4VCSGface {
G4int numSide; // Number sides
G4double r[2], z[2]; // r, z parameters, in specified order
G4double startPhi, // Start phi (0 to 2pi), if phiIsOpen
deltaPhi; // Delta phi (0 to 2pi), if phiIsOpen
deltaPhi, // Delta phi (0 to 2pi), if phiIsOpen
endPhi; // End phi (>startPhi), if phiIsOpen
G4bool phiIsOpen; // True if there is a phi slice
G4bool allBehind; // True if the entire solid is "behind" this face
G4IntersectingCone *cone; // Our intersecting cone
@@ -93,14 +108,16 @@ class G4PolyhedraSide : public G4VCSGface {
G4int ClosestPhiSegment( const G4double phi );
G4int PhiSegment( const G4double phi );
G4double DistanceToOneSide( const G4ThreeVector &p,
const G4PolyhedraSideVec vec,
const G4PolyhedraSideVec &vec,
G4double *normDist );
G4double DistanceAway( const G4ThreeVector &p,
const G4PolyhedraSideVec vec,
const G4PolyhedraSideVec &vec,
G4double *normDist );
void CopyStuff( const G4PolyhedraSide &source );
};
@@ -0,0 +1,132 @@
//
// G4ReduciblePolygon.hh
//
// Declaration of a utility class used to specify, test, reduce,
// and/or otherwise manipulate a 2D polygon.
//
// For this class, a polygon consists of n > 2 points in 2D
// space (a,b). The polygon is always closed by connecting the
// last point to the first. A G4ReduciblePolygon is guaranteed
// to fulfill this definition in all instances.
//
// Illegal manipulations (such that a valid polygon would be
// produced) result in an error return if possible and
// otherwise a G4Exception.
//
// The set of manipulations is limited currently to what
// is needed for G4Polycone and G4Polyhedra.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4ReduciblePolygon_hh
#define G4ReduciblePolygon_hh
#include "globals.hh"
class G4ReduciblePolygon {
friend class G4ReduciblePolygonIterator;
public:
//
// Creator: via simple a/b arrays
//
G4ReduciblePolygon( const G4double a[], const G4double b[], const G4int n );
//
// Creator: a special version for G4Polygon and G4Polycone
// that takes two a points at planes of b
// (where a==r and b==z for the GEANT3 classic PCON and PGON)
//
G4ReduciblePolygon( const G4double rmin[], const G4double rmax[], const G4double z[], const G4int n );
virtual ~G4ReduciblePolygon();
//
// Queries
//
inline G4int NumVertices() const { return numVertices; }
inline G4double Amin() const { return aMin; }
inline G4double Amax() const { return aMax; }
inline G4double Bmin() const { return bMin; }
inline G4double Bmax() const { return bMax; }
void CopyVertices( G4double a[], G4double b[] ) const;
//
// Manipulations
//
void ScaleA( const G4double scale );
void ScaleB( const G4double scale );
G4bool RemoveDuplicateVertices( const G4double tolerance );
G4bool RemoveRedundantVertices( const G4double tolerance );
//
// Tests
//
G4double Area();
G4bool CrossesItself( const G4double tolerance );
G4bool BisectedBy( const G4double a1, const G4double b1,
const G4double a2, const G4double b2, const G4double tolerance );
void Print(); // Debugging only
protected:
void Create( const G4double a[], const G4double b[], const G4int n );
void CalculateMaxMin();
//
// Below are member values that are *always* kept up to date (please!)
//
G4double aMin, aMax, bMin, bMax;
G4int numVertices;
//
// A subclass which holds the vertices in a single-linked list
//
// Yeah, call me an old-fashioned c hacker, but I cannot make
// myself use the rogue tools for this trivial list.
//
struct ABVertex;
friend struct ABVertex;
struct ABVertex {
G4double a, b;
ABVertex *next;
};
ABVertex *vertexHead;
};
//
// A companion class for iterating over the vertices of our polygon.
// It is simple enough that all routines are declared inline here.
//
class G4ReduciblePolygonIterator {
public:
G4ReduciblePolygonIterator( const G4ReduciblePolygon *theSubject ) { subject = theSubject; current=0; }
inline void Begin() { current = subject->vertexHead; }
inline G4bool Next() { if (current) current = current->next; return Valid(); }
inline G4bool Valid() const { return current!=0; }
inline G4double GetA() const { return current->a; }
inline G4double GetB() const { return current->b; }
protected:
const G4ReduciblePolygon *subject; // Who are we iterating over
G4ReduciblePolygon::ABVertex *current; // Current vertex
};
#endif
@@ -0,0 +1,52 @@
//
// G4SolidExtentList.hh
//
// Declaration of a list of (voxel) extents along one axis
//
// This utility class is designed for one specific purpose: to
// calculate the extent of a CSG solid for a voxel
// (G4VSolid::CalculateExtent).
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#ifndef G4SolidExtentList_hh
#define G4SolidExtentList_hh
#include "globals.hh"
#include "G4ClippablePolygon.hh"
class G4SolidExtentList {
public:
G4SolidExtentList();
G4SolidExtentList( const EAxis targetAxis, const G4VoxelLimits &voxelLimits );
~G4SolidExtentList();
void AddSurface( const G4ClippablePolygon &surface );
G4bool GetExtent( G4double &min, G4double &max ) const;
protected:
EAxis axis; // Target axis
G4bool limited; // True if limited
G4double minLimit; // ... min limit
G4double maxLimit; // ... max limit
G4ClippablePolygon minSurface, // Minimum surface within limits
maxSurface, // Maximum
minAbove, // Minimum surface totally above max limit
maxBelow; // Maximum surface totally below min limit
};
#endif
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Sphere.hh,v 2.0 1998/07/02 17:02:02 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Sphere.hh,v 1.1 1999/01/07 16:07:54 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Sphere
//
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Torus.hh,v 2.1 1998/07/12 02:56:50 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Torus.hh,v 1.1 1999/01/07 16:07:54 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Torus
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Trap.hh,v 2.1 1998/07/12 02:56:50 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Trap.hh,v 1.1 1999/01/07 16:07:54 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Trap
//
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Trd.hh,v 2.1 1998/07/12 02:56:51 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Trd.hh,v 1.1 1999/01/07 16:07:54 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Trd
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Tubs.hh,v 2.1 1998/07/12 02:56:52 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Tubs.hh,v 1.1 1999/01/07 16:07:54 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Tubs
@@ -92,13 +92,16 @@
// pVoxelLimit - (in) Limits along x, y, and/or z axes
// pTransform - (in) A coordinate transformation on which
// to apply to the shape before testing
// min - (in/out) If the face has any point on its
// min - (out) If the face has any point on its
// surface after tranformation and limits
// along pAxis
// that is smaller than the value of min,
// than it is used to replace min.
// max - (in/out) Same as min, except for the largest
// point.
// Undefined if the return value is false.
// max - (out) Same as min, except for the largest
// point. Undefined if the return value is false.
//
// return value = true if anything remains of the face
//
// Calculate the extent of the face for the voxel navigator.
// In analogy with CalculateExtent for G4VCSGfaceted, this is
@@ -109,11 +112,29 @@
// 2. Clip the face to those boundaries as specified in
// pVoxelLimit. This may include limits in any number
// of x, y, or z axes.
// 3. If nothing remains of the face after clipping, return.
// 4. Check the extent of the remaining surface along
// axis pAxis and check these values against min and max,
// modifying them as necessary.
//
// 3. For each part of the face that remains (there could
// be many separate pieces in general):
// 4. Check to see if the piece overlaps the currently
// existing limits along axis pAxis. For
// pVoxelLimit.IsLimited(pAxis) = false, there are
// no limits.
// 5. For a piece that does overlap, update min/max
// accordingly (within confines of pre-existing
// limits) along the direction pAxis.
// 6. If min/max were updated, return true
//
// -------------------------------------------------------------------
// G3VCSGface *Clone()
//
// This method is invoked by G4CSGfaceted during the copy constructor
// or the assignment operator. Its purpose is to return a pointer
// (of type G4VCSGface) to a duplicate copy of the face. The implementation
// is straight forward for inherited classes. Example:
//
// G4VCSGface G4PolySideFace::Clone() { return new G4PolySideFace(*this); }
//
// Of course, this assumes the copy constructor of G4PolySideFace is
// correctly implemented.
//
// Implementation notes:
// * distance.
@@ -132,7 +153,7 @@
// A, C, F, and H: closest distance is the distance to
// the adjacent corner.
//
// B, D, E, and F: closest distance is the distance to
// B, D, E, and G: closest distance is the distance to
// the adjacent line.
//
// I: normal distance to plane
@@ -200,6 +221,14 @@
// and save the answer that is smallest. If there is more than one answer,
// or if allBehind is false for the one answer, return validNorm as false.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4VSolid.hh"
@@ -209,6 +238,7 @@
class G4VoxelLimits;
class G4AffineTransform;
class G4SolidExtentList;
class G4VCSGface {
public:
@@ -232,7 +262,9 @@ class G4VCSGface {
virtual void CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &tranform,
G4double &min, G4double &max ) = 0;
G4SolidExtentList &extentList ) = 0;
virtual G4VCSGface* Clone() = 0;
};
#endif
@@ -17,6 +17,9 @@ class G4VCSGfaceted : public G4CSGSolid
G4VCSGfaceted( G4String name) : G4CSGSolid(name) {;}
virtual ~G4VCSGfaceted();
G4VCSGfaceted( const G4VCSGfaceted &source );
const G4VCSGfaceted &operator=( const G4VCSGfaceted &source );
virtual G4bool CalculateExtent( const EAxis pAxis,
const G4VoxelLimits& pVoxelLimit,
const G4AffineTransform& pTransform,
@@ -46,7 +49,9 @@ class G4VCSGfaceted : public G4CSGSolid
G4VCSGface **faces;
virtual G4double DistanceTo( const G4ThreeVector &p, const G4bool outgoing ) const;
void CopyStuff( const G4VCSGfaceted &source );
void DeleteStuff();
};
#endif
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Box.cc,v 2.3 1998/10/09 13:24:45 japost Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Box.cc,v 1.2 1999/04/13 11:05:04 sgiani Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
//
@@ -77,8 +77,8 @@ G4bool G4Box::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fDx;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -101,8 +101,8 @@ G4bool G4Box::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fDy;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -125,8 +125,8 @@ G4bool G4Box::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4CSGSolid.cc,v 2.0 1998/07/02 17:02:11 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4CSGSolid.cc,v 1.1 1999/01/07 16:07:55 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
#include "G4CSGSolid.hh"
@@ -1,7 +1,15 @@
//
// G4ClippablePolygon.cc
//
// Based on code from G4VSolid (P. Kent, V. Grichine, J. Allison)
// Includes code from G4VSolid (P. Kent, V. Grichine, J. Allison)
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4ClippablePolygon.hh"
@@ -26,80 +34,347 @@ void G4ClippablePolygon::ClearAllVertices()
}
//
// Clip
//
void G4ClippablePolygon::Clip( const G4VoxelLimits &voxelLimit )
{
//
// Heh. Do we have anything to do?
//
if (!voxelLimit.IsLimited()) return;
const G4bool G4ClippablePolygon::Clip( const G4VoxelLimits &voxelLimit )
{
if (voxelLimit.IsLimited()) {
ClipAlongOneAxis( voxelLimit, kXAxis );
ClipAlongOneAxis( voxelLimit, kYAxis );
ClipAlongOneAxis( voxelLimit, kZAxis );
}
//
// Loop over all axes
//
static EAxis axes[3] = { kXAxis, kYAxis, kZAxis };
EAxis *axis = axes;
do {
if (voxelLimit.IsLimited(*axis)) {
G4ThreeVectorList tempPolygon;
//
// Build a "simple" voxelLimit that includes only the min extent
// and apply this to our vertices, producing result in tempPolygon
//
G4VoxelLimits simpleLimit1;
simpleLimit1.AddLimit( *axis, voxelLimit.GetMinExtent(*axis), kInfinity );
ClipToSimpleLimits( vertices, tempPolygon, simpleLimit1 );
//
// If nothing is left from the above clip, we might as well return now
// (but with an empty vertices)
//
if (tempPolygon.entries() == 0) {
vertices.clear();
return;
}
//
// Now do the same, but using a "simple" limit that includes only the max extent.
// Apply this to out tempPolygon, producing result in vertices.
//
G4VoxelLimits simpleLimit2;
simpleLimit2.AddLimit( *axis, -kInfinity, voxelLimit.GetMaxExtent(*axis) );
ClipToSimpleLimits( tempPolygon, vertices, simpleLimit2 );
//
// If nothing is left, return now
//
if (vertices.entries() == 0) return;
}
} while( ++axis < axes + sizeof(axes)/sizeof(EAxis) );
return (vertices.entries() > 0);
}
//
// PartialClip
//
// Clip, while ignoring the indicated axis
//
const G4bool G4ClippablePolygon::PartialClip( const G4VoxelLimits &voxelLimit, const EAxis IgnoreMe )
{
if (voxelLimit.IsLimited()) {
if (IgnoreMe != kXAxis) ClipAlongOneAxis( voxelLimit, kXAxis );
if (IgnoreMe != kYAxis) ClipAlongOneAxis( voxelLimit, kYAxis );
if (IgnoreMe != kZAxis) ClipAlongOneAxis( voxelLimit, kZAxis );
}
return (vertices.entries() > 0);
}
//
// GetExtent
//
void G4ClippablePolygon::GetExtent( const EAxis axis,
G4double &min, G4double &max )
const G4bool G4ClippablePolygon::GetExtent( const EAxis axis,
G4double &min, G4double &max ) const
{
//
// Okay, how many entries do we have?
//
G4int noLeft = vertices.entries();
//
// Return false if nothing is left
//
if (noLeft == 0) return false;
//
// Initialize min and max to our first vertex
//
min = max = vertices(0).operator()( axis );
//
// Compare to the rest
//
G4int i;
for( i=0; i<noLeft; i++ ) {
for( i=1; i<noLeft; i++ ) {
G4double component = vertices(i).operator()( axis );
if (component < min )
min = component;
else if (component > max )
max = component;
}
return true;
}
//
// GetMinPoint
//
// Returns pointer to minimum point along the specified axis.
// Take care! Do not use pointer after destroying parent polygon.
//
const G4ThreeVector *G4ClippablePolygon::GetMinPoint( const EAxis axis ) const
{
G4int noLeft = vertices.entries();
if (noLeft==0) G4Exception( "G4ClippablePolygon::GetMinPoint -- empty polygon" );
const G4ThreeVector *answer = &(vertices[0]);
G4double min = answer->operator()(axis);
G4int i;
for( i=1; i<noLeft; i++ ) {
G4double component = vertices(i).operator()( axis );
if (component < min) {
answer = &(vertices[i]);
min = component;
}
}
return answer;
}
//
// GetMaxPoint
//
// Returns pointer to maximum point along the specified axis.
// Take care! Do not use pointer after destroying parent polygon.
//
const G4ThreeVector *G4ClippablePolygon::GetMaxPoint( const EAxis axis ) const
{
G4int noLeft = vertices.entries();
if (noLeft==0) G4Exception( "G4ClippablePolygon::GetMaxPoint -- empty polygon" );
const G4ThreeVector *answer = &(vertices[0]);
G4double max = answer->operator()(axis);
G4int i;
for( i=1; i<noLeft; i++ ) {
G4double component = vertices(i).operator()( axis );
if (component > max) {
answer = &(vertices[i]);
max = component;
}
}
return answer;
}
//
// InFrontOf
//
// Decide if this polygon is in "front" of another when
// viewed along the specified axis. For our purposes here,
// it is sufficient to use the minimum extent of the
// polygon along the axis to determine this.
//
// In case the minima of the two polygons are equal,
// we use a more sophisticated test.
//
// Note that it is possible for the two following
// statements to both return true or both return false:
// polygon1.InFrontOf(polygon2)
// polygon2.BehindOf(polygon1)
//
const G4bool G4ClippablePolygon::InFrontOf( const G4ClippablePolygon &other, EAxis axis ) const
{
//
// If things are empty, do something semi-sensible
//
G4int noLeft = vertices.entries();
if (noLeft==0) return false;
if (other.Empty()) return true;
//
// Get minimum of other polygon
//
const G4ThreeVector *minPointOther = other.GetMinPoint( axis );
const G4double minOther = minPointOther->operator()(axis);
//
// Get minimum of this polygon
//
const G4ThreeVector *minPoint = GetMinPoint( axis );
const G4double min = minPoint->operator()(axis);
//
// Easy decision
//
if (min < minOther-kCarTolerance) return true; // Clear winner
if (minOther < min-kCarTolerance) return false; // Clear loser
//
// We have a tie (this will not be all that rare since our
// polygons are connected)
//
// Check to see if there is a vertex in the other polygon
// that is behind this one (or vice versa)
//
G4bool answer;
G4ThreeVector normalOther = other.GetNormal();
if (fabs(normalOther(axis)) > fabs(normal(axis))) {
G4double minP, maxP;
GetPlanerExtent( *minPointOther, normalOther, minP, maxP );
answer = (normalOther(axis) > 0) ? (minP < -kCarTolerance) : (maxP > +kCarTolerance);
}
else {
G4double minP, maxP;
other.GetPlanerExtent( *minPoint, normal, minP, maxP );
answer = (normal(axis) > 0) ? (maxP > +kCarTolerance) : (minP < -kCarTolerance);
}
return answer;
}
//
// BehindOf
//
// Decide if this polygon is behind another.
// See notes in method "InFrontOf"
//
const G4bool G4ClippablePolygon::BehindOf( const G4ClippablePolygon &other, EAxis axis ) const
{
//
// If things are empty, do something semi-sensible
//
G4int noLeft = vertices.entries();
if (noLeft==0) return false;
if (other.Empty()) return true;
//
// Get minimum of other polygon
//
const G4ThreeVector *maxPointOther = other.GetMaxPoint( axis );
const G4double maxOther = maxPointOther->operator()(axis);
//
// Get minimum of this polygon
//
const G4ThreeVector *maxPoint = GetMaxPoint( axis );
const G4double max = maxPoint->operator()(axis);
//
// Easy decision
//
if (max > maxOther+kCarTolerance) return true; // Clear winner
if (maxOther > max+kCarTolerance) return false; // Clear loser
//
// We have a tie (this will not be all that rare since our
// polygons are connected)
//
// Check to see if there is a vertex in the other polygon
// that is in front of this one (or vice versa)
//
G4bool answer;
G4ThreeVector normalOther = other.GetNormal();
if (fabs(normalOther(axis)) > fabs(normal(axis))) {
G4double minP, maxP;
GetPlanerExtent( *maxPointOther, normalOther, minP, maxP );
answer = (normalOther(axis) > 0) ? (maxP > +kCarTolerance) : (minP < -kCarTolerance);
}
else {
G4double minP, maxP;
other.GetPlanerExtent( *maxPoint, normal, minP, maxP );
answer = (normal(axis) > 0) ? (minP < -kCarTolerance) : (maxP > +kCarTolerance);
}
return answer;
}
//
// GetPlanerExtent
//
// Get min/max distance in or out of a plane
//
const G4bool G4ClippablePolygon::GetPlanerExtent( const G4ThreeVector &pointOnPlane,
const G4ThreeVector &planeNormal,
G4double &min, G4double &max ) const
{
//
// Okay, how many entries do we have?
//
G4int noLeft = vertices.entries();
//
// Return false if nothing is left
//
if (noLeft == 0) return false;
//
// Initialize min and max to our first vertex
//
min = max = planeNormal.dot(vertices(0)-pointOnPlane);
//
// Compare to the rest
//
G4int i;
for( i=1; i<noLeft; i++ ) {
G4double component = planeNormal.dot(vertices(i) - pointOnPlane);
if (component < min )
min = component;
else if (component > max )
max = component;
}
return true;
}
//
// Clip along just one axis, as specified in voxelLimit
//
void G4ClippablePolygon::ClipAlongOneAxis( const G4VoxelLimits &voxelLimit, const EAxis axis )
{
if (!voxelLimit.IsLimited(axis)) return;
G4ThreeVectorList tempPolygon;
//
// Build a "simple" voxelLimit that includes only the min extent
// and apply this to our vertices, producing result in tempPolygon
//
G4VoxelLimits simpleLimit1;
simpleLimit1.AddLimit( axis, voxelLimit.GetMinExtent(axis), kInfinity );
ClipToSimpleLimits( vertices, tempPolygon, simpleLimit1 );
//
// If nothing is left from the above clip, we might as well return now
// (but with an empty vertices)
//
if (tempPolygon.entries() == 0) {
vertices.clear();
return;
}
//
// Now do the same, but using a "simple" limit that includes only the max extent.
// Apply this to out tempPolygon, producing result in vertices.
//
G4VoxelLimits simpleLimit2;
simpleLimit2.AddLimit( axis, -kInfinity, voxelLimit.GetMaxExtent(axis) );
ClipToSimpleLimits( tempPolygon, vertices, simpleLimit2 );
//
// If nothing is left, return now
//
if (vertices.entries() == 0) return;
}
// pVoxelLimits must be only limited along one axis, and either the maximum
// along the axis must be +kInfinity, or the minimum -kInfinity
void G4ClippablePolygon::ClipToSimpleLimits( G4ThreeVectorList& pPolygon,
+226 -210
View File
@@ -5,17 +5,20 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Cons.cc,v 2.3 1998/10/09 17:17:19 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Cons.cc,v 1.4 1999/04/29 09:46:34 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Cons
//
// Implementation for G4Cons class
//
// History:
// ~1994 P. Kent: main part of geometry functions
// 13.9.96 V. Grichine: final modifications to commit
//
// 28.04.99 V. Grichine bugs fixed in Distance ToOut(p,v,...) and
// Distance ToIn(p,v)
// 09.10.98 V. Grichine modifications in Distance ToOut(p,v,...)
// 13.09.96 V. Grichine: final modifications to commit
// ~1994 P. Kent: main part of geometry functions
#include "G4Cons.hh"
@@ -308,8 +311,8 @@ G4bool G4Cons::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin > pVoxelLimit.GetMaxZExtent()
|| zMax < pVoxelLimit.GetMinZExtent())
if (zMin > pVoxelLimit.GetMaxZExtent()+kCarTolerance
|| zMax < pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -332,8 +335,8 @@ G4bool G4Cons::CalculateExtent(const EAxis pAxis,
xMin = 2*xoffset-xMax ;
if (pVoxelLimit.IsXLimited())
{
if (xMin > pVoxelLimit.GetMaxXExtent()
|| xMax < pVoxelLimit.GetMinXExtent())
if (xMin > pVoxelLimit.GetMaxXExtent()+kCarTolerance
|| xMax < pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -356,8 +359,8 @@ G4bool G4Cons::CalculateExtent(const EAxis pAxis,
RMax = yMax - yoffset ; // is equal to max radius due to Zmax/Zmin cuttings
if (pVoxelLimit.IsYLimited())
{
if (yMin > pVoxelLimit.GetMaxYExtent()
|| yMax < pVoxelLimit.GetMinYExtent())
if (yMin > pVoxelLimit.GetMaxYExtent()+kCarTolerance
|| yMax < pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -619,8 +622,8 @@ G4ThreeVector G4Cons::SurfaceNormal( const G4ThreeVector& p) const
return norm;
}
// ---------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
//
// Calculate distance to shape from outside, along normalised vector
// - return kInfinity if no intersection, or intersection distance <= tolerance
//
@@ -720,61 +723,65 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p,
tolIDz=fDz-kCarTolerance/2;
tolODz=fDz+kCarTolerance/2;
if (fabs(p.z())>=tolIDz)
{
if (p.z()*v.z()<0) // at +Z going in -Z or visa versa
{
s=(fabs(p.z())-fDz)/fabs(v.z()); // Z intersect distance
xi=p.x()+s*v.x(); // Intersection coords
yi=p.y()+s*v.y();
rho2=xi*xi+yi*yi;
// Check validity of intersection
{
if (p.z()*v.z()<0) // at +Z going in -Z or visa versa
{
s=(fabs(p.z())-fDz)/fabs(v.z()); // Z intersect distance
// Calculate (outer) tolerant radi^2 at intersecion
if (v.z()>0)
{
tolORMin=fRmin1-kRadTolerance;
tolORMax2=(fRmax1+kRadTolerance)*(fRmax1+kRadTolerance);
}
else
{
tolORMin=fRmin2-kRadTolerance;
tolORMax2=(fRmax2+kRadTolerance)*(fRmax2+kRadTolerance);
}
if (tolORMin>0)
{
if(s<0.0) s = 0.0 ; // negative dist -> zero
xi=p.x()+s*v.x(); // Intersection coords
yi=p.y()+s*v.y();
rho2=xi*xi+yi*yi;
// Check validity of intersection
//
// Calculate (outer) tolerant radi^2 at intersecion
if (v.z()>0)
{
tolORMin=fRmin1-kRadTolerance;
tolORMax2=(fRmax1+kRadTolerance)*(fRmax1+kRadTolerance);
}
else
{
tolORMin=fRmin2-kRadTolerance;
tolORMax2=(fRmax2+kRadTolerance)*(fRmax2+kRadTolerance);
}
if ( tolORMin > 0 )
{
tolORMin2=tolORMin*tolORMin;
}
else
{
tolORMin2=0;
}
if (tolORMin2<=rho2&&rho2<=tolORMax2)
{
if (seg&&rho2)
{
}
else
{
tolORMin2=0;
}
if (tolORMin2 <= rho2 && rho2 <= tolORMax2)
{
if (seg&&rho2)
{
// Psi = angle made with central (average) phi of shape
cosPsi=(xi*cosCPhi+yi*sinCPhi)/sqrt(rho2);
if (cosPsi>=cosHDPhiOT)
{
return s;
}
}
else
{
return s;
}
}
}
else
cosPsi=(xi*cosCPhi+yi*sinCPhi)/sqrt(rho2);
if (cosPsi >= cosHDPhiOT)
{
return snxt; // On/outside extent, and heading away
// -> cannot intersect
return s ;
}
}
// -> Can not intersect z surfaces
}
else
{
return s ;
}
}
}
else // On/outside extent, and heading away -> cannot intersect
{
return snxt ;
}
}
//
// -> Can not intersect z surfaces
@@ -943,7 +950,7 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p,
}
else // travel || cone surface from its origin
{
return kInfinity ;
s = kInfinity ;
}
}
@@ -1249,7 +1256,7 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p,
return snxt;
}
// -------------------------------------------------------------------------------------------
/* ****************************************************************************************
@@ -1705,8 +1712,8 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p) const
return safe;
}
// -----------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////
//
// Calculate distance to surface of shape from `inside', allowing for tolerance
// - Only Calc rmax intersection if no valid rmin intersection
@@ -1737,55 +1744,54 @@ G4double G4Cons::DistanceToOut(const G4ThreeVector& p,
// Z plane intersection
//
if (v.z()>0)
{
pdist=fDz-p.z();
if (pdist>kCarTolerance/2)
{
snxt=pdist/v.z();
side=kPZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,1);
*validNorm=true;
}
return snxt=0;
}
}
{
pdist=fDz-p.z();
if (pdist > kCarTolerance*0.5)
{
snxt=pdist/v.z();
side=kPZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,1);
*validNorm=true;
}
return snxt=0;
}
}
else if (v.z()<0)
{
pdist=fDz+p.z();
if (pdist>kCarTolerance/2)
{
snxt=-pdist/v.z();
side=kMZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,-1);
*validNorm=true;
}
return snxt=0;
}
}
{
pdist=fDz+p.z();
if (pdist > kCarTolerance*0.5)
{
snxt=-pdist/v.z();
side=kMZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,-1);
*validNorm=true;
}
return snxt=0;
}
}
else
{
snxt=kInfinity; // Travel perpendicular to z axis
side=kNull;
}
{
snxt=kInfinity; // Travel perpendicular to z axis
side=kNull;
}
//
// Radial Intersections
//
//
// Intersection with outer cone (possible return) and
// inner cone (must also check phi)
//
// Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
//
// Intersects with x^2+y^2=(a*z+b)^2
@@ -1812,138 +1818,146 @@ G4double G4Cons::DistanceToOut(const G4ThreeVector& p,
nt2=t2-tanRMax*v.z()*rout;
nt3=t3-rout*rout;
if (nt1)
{
{
//
// Equation quadratic => 2 roots : second root must be leaving
//
b=nt2/nt1;
c=nt3/nt1;
d=b*b-c;
if (d>=0)
{
b=nt2/nt1;
c=nt3/nt1;
d=b*b-c;
if ( d >= 0 )
{
// Check if on outer cone & heading outwards
// NOTE: Should use rho-rout>-kRadtolerance/2
if (nt3>-kRadTolerance/2&&nt2>=0)
{
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
else
{
// NOTE: Should use rho-rout>-kRadtolerance/2
if (nt3 > -kRadTolerance*0.5 && nt2 >= 0 )
{
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
else
{
// // -*-* ORIG ROOT CODE
// sr=-b+sqrt(d);
// sider=kRMax;
// // -*-* ORIG ROOT CODE
// Patch 4.4.95 - root above cross-over point
sider=kRMax;
sr=-b+sqrt(d);
zi=p.z()+sr*v.z();
ri=tanRMax*zi+rMaxAv;
if( (ri>=0)
&& (-kRadTolerance/2 <= sr)
&& ( sr <= kRadTolerance/2) )
{
// An intersection within the tolerance
// we will Store it in case it is good -
//
slentol = sr;
sidetol= kRMax;
}
if ( (ri<0)
|| (sr<kRadTolerance/2) )
{
sr2=-b+sqrt(d);
// Safety: if both roots -ve ensure that sr cannot `win' distancetoout
zi=p.z()+sr2*v.z();
ri=tanRMax*zi+rMaxAv;
if (ri>=0&&sr2>kRadTolerance/2)
{
sr=sr2;
}
else
{
sr=kInfinity;
if( (-kRadTolerance/2 <= sr2)
&&( sr2 <= kRadTolerance/2) )
{
// An intersection within the
// tolerance. Storing it
// in case it is good.
slentol = sr2;
sidetol= kRMax;
}
}
}
}
}
else
sider=kRMax ;
sr=-b - sqrt(d); // was +srqrt(d), vmg 28.04.99
zi=p.z()+sr*v.z();
ri=tanRMax*zi+rMaxAv;
if ( (ri >= 0)
&& (-kRadTolerance/2 <= sr)
&& ( sr <= kRadTolerance/2) )
{
// An intersection within the tolerance
// we will Store it in case it is good -
//
slentol = sr;
sidetol= kRMax;
}
if ( (ri < 0) || (sr < kRadTolerance/2) )
{
// Safety: if both roots -ve ensure that sr cannot `win' distancetoout
sr2=-b+sqrt(d);
zi=p.z()+sr2*v.z();
ri=tanRMax*zi+rMaxAv;
if (ri>=0&&sr2>kRadTolerance/2)
{
sr=sr2;
}
else
{
sr = kInfinity ;
if( (-kRadTolerance/2 <= sr2)
&& ( sr2 <= kRadTolerance/2) )
{
// An intersection within the tolerance. Storing it in case it is good.
slentol = sr2;
sidetol= kRMax;
}
}
}
}
}
else
{
// No intersection with outer cone & not parallel -> already outside, no
// intersection
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
}
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
}
else if (nt2)
{
{
//
// Linear case (only one intersection) => point outside outer cone
//
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
else
{
{
// No intersection -> parallel to outer cone => Z or inner cone intersection
sr=kInfinity;
}
sr=kInfinity;
}
// Check possible intersection within tolerance
if( slentol <= kCarTolerance/2 )
if ( slentol <= kCarTolerance/2 )
{
// An intersection within the tolerance was found.
// We must accept it only if the momentum points outwards.
//
// An intersection within the tolerance was found.
// We must accept it only if the momentum points outwards.
//
// G4ThreeVector ptTol; // The point of the intersection
// ptTol= p + slentol*v;
// ri=tanRMax*zi+rMaxAv;
//
// Calculate a normal vector, as below
// G4ThreeVector ptTol; // The point of the intersection
// ptTol= p + slentol*v;
// ri=tanRMax*zi+rMaxAv;
xi=p.x()+slentol*v.x();
yi=p.y()+slentol*v.y();
risec=sqrt(xi*xi+yi*yi)*secRMax;
G4ThreeVector Normal=G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax);
// Calculate a normal vector, as below
xi=p.x()+slentol*v.x();
yi=p.y()+slentol*v.y();
risec=sqrt(xi*xi+yi*yi)*secRMax;
G4ThreeVector Normal=G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax);
if( Normal.dot(v) > 0 )
{
if ( Normal.dot(v) > 0 )
{
// We will leave the Cone immediatelly
if(calcNorm)
{
*n= Normal.unit();
*validNorm=true;
}
if ( calcNorm )
{
*n= Normal.unit();
*validNorm=true;
}
return snxt = 0.0;
}
else
else
{
// On the surface, but not heading out
// so we ignore this intersection (as it is within tolerance).
@@ -2651,3 +2665,5 @@ G4NURBS* G4Cons::CreateNURBS () const
}
// ******************************* End of G4Cons.cc file **********************************
@@ -3,27 +3,31 @@
//
// Implementation of a utility class for a quick check of geometry
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4EnclosingCylinder.hh"
#include "G4ReduciblePolygon.hh"
//
// Constructor
//
G4EnclosingCylinder::G4EnclosingCylinder( const G4double r[], const G4double z[], const G4int n,
G4EnclosingCylinder::G4EnclosingCylinder( const G4ReduciblePolygon *rz,
const G4bool thePhiIsOpen,
const G4double theStartPhi, const G4double theTotalPhi )
{
//
// Obtain larges r and smallest and larges z
// Obtain largest r and smallest and largest z
//
radius = r[0];
zLo = zHi = z[0];
const G4double *rr = r, *zz = z;
while( ++zz, ++rr < r+n ) {
if (*rr > radius) radius = *rr;
if (*zz > zHi ) zHi = *zz;
if (*zz < zLo ) zLo = *zz;
}
radius = rz->Amax();
zHi = rz->Bmax();
zLo = rz->Bmin();
//
// Save phi info
@@ -41,6 +45,8 @@ G4EnclosingCylinder::G4EnclosingCylinder( const G4double r[], const G4double z[]
ry2 = sin(startPhi+totalPhi);
dx2 = -ry2*10*kCarTolerance;
dy2 = +rx2*10*kCarTolerance;
concave = totalPhi > M_PI;
}
//
@@ -64,16 +70,21 @@ G4EnclosingCylinder::~G4EnclosingCylinder() {;}
//
// If one is not certain, return false
//
G4bool G4EnclosingCylinder::Outside( const G4ThreeVector &p ) const
G4bool G4EnclosingCylinder::MustBeOutside( const G4ThreeVector &p ) const
{
if (p.perp() > radius) return true;
if (p.z() < zLo) return true;
if (p.z() > zHi) return true;
if (phiIsOpen) {
if ( ((p.x()-dx1)*ry1 - (p.y()-dy1)*rx1) > 0) return false;
if ( ((p.x()-dx2)*ry2 - (p.y()-dy2)*rx2) < 0) return false;
return true;
if (concave) {
if ( ((p.x()-dx1)*ry1 - (p.y()-dy1)*rx1) < 0) return false;
if ( ((p.x()-dx2)*ry2 - (p.y()-dy2)*rx2) > 0) return false;
}
else {
if ( ((p.x()-dx1)*ry1 - (p.y()-dy1)*rx1) > 0) return true;
if ( ((p.x()-dx2)*ry2 - (p.y()-dy2)*rx2) < 0) return true;
}
}
return false;
@@ -87,9 +98,9 @@ G4bool G4EnclosingCylinder::Outside( const G4ThreeVector &p ) const
//
// If one is not sure, return false
//
G4bool G4EnclosingCylinder::Misses( const G4ThreeVector &p, const G4ThreeVector &v ) const
G4bool G4EnclosingCylinder::ShouldMiss( const G4ThreeVector &p, const G4ThreeVector &v ) const
{
if (!Outside(p)) return false;
if (!MustBeOutside(p)) return false;
G4double cross = p.x()*v.y() - p.y()*v.x();
if (cross > radius) return true;
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Hype.cc,v 2.2 1998/07/13 16:52:46 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Hype.cc,v 1.2 1999/04/16 09:29:54 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Hype: this class implements in G4 the volume equivalent
// to the HYPE volume in Geant 3, i.e. a tube with
@@ -137,8 +137,8 @@ G4bool G4Hype::CalculateExtent(const EAxis pAxis,
//G4cout << "xMin, xMax : " << xMin << " " << xMax << endl;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent() ||
xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance ||
xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -162,8 +162,8 @@ G4bool G4Hype::CalculateExtent(const EAxis pAxis,
yMax=yoffset+endOuterRadius;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -186,8 +186,8 @@ G4bool G4Hype::CalculateExtent(const EAxis pAxis,
zMax=zoffset+halfLenZ;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -4,6 +4,14 @@
// Implementation of a utility class which calculates the intersection
// of an arbitrary line with a fixed cone
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4IntersectingCone.hh"
//
@@ -168,7 +176,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, const G4ThreeVe
//
// The radical is roughly zero: check for special, very rare, cases
//
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6/B)) && (a < 1/kInfinity) ) {
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6/B)) && (a < -1/kInfinity) ) {
*s1 = -0.5*b/a;
return 1;
}
@@ -255,7 +263,7 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, const G4ThreeVe
//
// The radical is roughly zero: check for special, very rare, cases
//
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6*B)) && (a < 1/kInfinity) ) {
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6*B)) && (a < -1/kInfinity) ) {
*s1 = -0.5*b/a;
return 1;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Para.cc,v 2.1 1998/07/12 02:56:56 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Para.cc,v 1.2 1999/04/16 09:29:54 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Para
//
@@ -175,8 +175,8 @@ G4bool G4Para::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -207,8 +207,8 @@ G4bool G4Para::CalculateExtent(const EAxis pAxis,
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -244,8 +244,8 @@ G4bool G4Para::CalculateExtent(const EAxis pAxis,
// xMax/Min = f(yMax/Min) ?
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
+360 -88
View File
@@ -4,10 +4,20 @@
// Implementation of the face that bounds a polycone or polyhedra at
// its phi opening.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4PolyPhiFace.hh"
#include "G4ClippablePolygon.hh"
#include "G4ReduciblePolygon.hh"
#include "G4AffineTransform.hh"
#include "G4SolidExtentList.hh"
//
// Constructor
@@ -19,10 +29,21 @@
// | | +--> z
// [0]---------[3]
//
G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
const G4int n, const G4double phi,
const G4double deltaPhi, const G4bool start )
G4PolyPhiFace::G4PolyPhiFace( const G4ReduciblePolygon *rz, const G4double phi,
const G4double deltaPhi, const G4double phiOther )
{
numEdges = rz->NumVertices();
rMin = rz->Amin();
rMax = rz->Amax();
zMin = rz->Bmin();
zMax = rz->Bmax();
//
// Is this the "starting" phi edge of the two?
//
G4bool start = (phiOther > phi);
//
// Build radial vector
//
@@ -33,41 +54,37 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
//
G4double zSign = start ? 1 : -1;
normal = G4ThreeVector( zSign*radial.y(), -zSign*radial.x(), 0 );
//
// Is allBehind?
//
allBehind = (zSign*(cos(phiOther)*radial.y() - sin(phiOther)*radial.x()) < 0);
//
// Adjacent edges
//
G4double midPhi = phi + (start ? +0.5 : -0.5)*deltaPhi;
G4double cosMid = cos(midPhi),
sinMid = sin(midPhi);
//
// Allocate corners
//
corners = new G4PolyPhiFaceVertex[n];
corners = new G4PolyPhiFaceVertex[numEdges];
//
// Fill their positions, avoiding duplicates
// Fill them
//
rMin = kInfinity; rMax = -kInfinity;
zMin = kInfinity; zMax = -kInfinity;
const G4double *rOne = r, *zOne = z,
*rNext, *zNext;
G4PolyPhiFaceVertex *corn = corners;
do {
rNext = rOne + 1;
zNext = zOne + 1;
if (rNext == r+n) {rNext = r; zNext = z;}
if (*rNext == *rOne && *zNext == *zOne) continue;
corn->r = *rOne;
corn->z = *zOne;
corn++;
if (*rOne < rMin) rMin = *rOne;
if (*rOne > rMax) rMax = *rOne;
if (*zOne < zMin) zMin = *zOne;
if (*zOne > zMax) zMax = *zOne;
} while( rOne=rNext, zOne=zNext, rOne != r );
numEdges = corn-corners;
G4ReduciblePolygonIterator iterRZ(rz);
G4PolyPhiFaceVertex *corn = corners;
iterRZ.Begin();
do {
corn->r = iterRZ.GetA();
corn->z = iterRZ.GetB();
corn->x = corn->r*radial.x();
corn->y = corn->r*radial.y();
} while( ++corn, iterRZ.Next() );
//
// Allocate edges
@@ -77,17 +94,16 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
//
// Fill them
//
G4double midPhi = phi + (start ? +0.5 : -0.5)*deltaPhi;
G4double cosMid = cos(midPhi),
sinMid = sin(midPhi);
G4double rFact = cos(0.5*deltaPhi);
G4ThreeVector sideNorm;
G4double rFactNormalize = 1.0/sqrt(1.0+rFact*rFact);
G4PolyPhiFaceVertex *prev = corners+numEdges-1,
*here = corners;
G4PolyPhiFaceEdge *edge = edges;
do {
edge->v0 = prev;
G4ThreeVector sideNorm;
edge->v0 = prev;
edge->v1 = here;
G4double dr = here->r - prev->r,
@@ -98,44 +114,84 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
edge->tr = dr/edge->length;
edge->tz = dz/edge->length;
sideNorm = G4ThreeVector( dz*rFact*cosMid, dz*rFact*sinMid, -dr );
sideNorm = sideNorm.unit();
if ((here->r < DBL_MIN) && (prev->r < DBL_MIN)) {
//
// Sigh! Always exceptions!
// This edge runs at r==0, so its adjoing surface is not a
// PolyconeSide or PolyhedraSide, but the opposite PolyPhiFace.
//
G4double zSignOther = start ? -1 : 1;
sideNorm = G4ThreeVector( zSignOther*sin(phiOther),
-zSignOther*cos(phiOther), 0 );
}
else {
sideNorm = G4ThreeVector( edge->tz*cosMid, edge->tz*sinMid, -edge->tr*rFact );
sideNorm *= rFactNormalize;
}
sideNorm += normal;
edge->norm3D = sideNorm.unit();
} while( edge++, prev=here, ++here < corners+numEdges );
//
// Go back an fill in corner "normals", which are just the
// average of the normals of the ajoining edges
// Go back and fill in corner "normals"
//
G4PolyPhiFaceEdge *prevEdge = edges+numEdges-1;
edge = edges;
do {
//
// Calculate vertex 2D normals (on the phi surface)
//
G4double rPart = prevEdge->tr + edge->tr;
G4double zPart = prevEdge->tz + edge->tz;
G4double norm = sqrt( rPart*rPart + zPart*zPart );
edge->v0->rNorm = +zPart/norm;
edge->v0->zNorm = -rPart/norm;
G4double rNorm = +zPart/norm;
G4double zNorm = -rPart/norm;
edge->v0->rNorm = rNorm;
edge->v0->zNorm = zNorm;
//
// Corner normal should be average of normals of connecting edges,
// or, equivalently, the average of all connecting faces.
// Calculate the 3D normals.
//
// prevEdge->norm3D = normal + side1.normal = A
// edge->norm3D = normal + side2.normal = B
// A + B - normal = normal + side1.normal + side2.normal
// Find the vector perpendicular to the z axis
// that defines the plane that contains the vertex normal
//
G4ThreeVector xyVector;
G4ThreeVector norm3D = prevEdge->norm3D + edge->norm3D - normal;
edge->v0->norm3D = norm3D.unit();
if (edge->v0->r < DBL_MIN) {
//
// This is a vertex at r==0, which is a special
// case. The normal we will construct lays in the
// plane at the center of the phi opening.
//
// We also know that rNorm < 0
//
G4double zSignOther = start ? -1 : 1;
G4ThreeVector normalOther( zSignOther*sin(phiOther),
-zSignOther*cos(phiOther), 0 );
xyVector = - normal - normalOther;
}
else {
//
// This is a vertex at r > 0. The plane
// is the average of the normal and the
// normal of the adjacent phi face
//
xyVector = G4ThreeVector( cosMid, sinMid, 0 );
if (rNorm < 0)
xyVector -= normal;
else
xyVector += normal;
}
//
// Combine it with the r/z direction from the face
//
edge->v0->norm3D = rNorm*xyVector.unit() + G4ThreeVector( 0, 0, zNorm );
} while( prevEdge=edge, ++edge < edges+numEdges );
//
// Complain if something is obviously wrong
//
if (numEdges <= 2)
G4Exception( "G4PolyPhiFace: more than two unique corners must be specified" );
//
// Build point on surface
//
@@ -145,12 +201,104 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
}
//
// Diagnose
//
// Throw an exception if something is found inconsistent with
// the solid.
//
// For debugging purposes only
//
void G4PolyPhiFace::Diagnose( G4VSolid *owner )
{
G4PolyPhiFaceVertex *corner = corners;
do {
G4ThreeVector test(corner->x, corner->y, corner->z);
test -= 1E-6*corner->norm3D;
if (owner->Inside(test) != kInside)
G4Exception( "G4PolyPhiFace::Diagnose -- Bad vertex normal found" );
} while( ++corner < corners+numEdges );
}
//
// Destructor
//
G4PolyPhiFace::~G4PolyPhiFace()
{
delete [] edges;
delete [] corners;
}
//
// Copy constructor
//
G4PolyPhiFace::G4PolyPhiFace( const G4PolyPhiFace &source )
{
CopyStuff( source );
}
//
// Assignment operator
//
G4PolyPhiFace *G4PolyPhiFace::operator=( const G4PolyPhiFace &source )
{
if (this == &source) return this;
delete [] edges;
delete [] corners;
CopyStuff( source );
return this;
}
//
// CopyStuff (protected)
//
void G4PolyPhiFace::CopyStuff( const G4PolyPhiFace &source )
{
//
// The simple stuff
//
numEdges = source.numEdges;
normal = source.normal;
radial = source.radial;
surface = source.surface;
rMin = source.rMin;
rMax = source.rMax;
zMin = source.zMin;
zMax = source.zMax;
allBehind = source.allBehind;
//
// Corner dynamic array
//
corners = new G4PolyPhiFaceVertex[numEdges];
G4PolyPhiFaceVertex *corn = corners,
*sourceCorn = source.corners;
do {
*corn = *sourceCorn;
} while( ++sourceCorn, ++corn < corners+numEdges );
//
// Edge dynamic array
//
edges = new G4PolyPhiFaceEdge[numEdges];
G4PolyPhiFaceVertex *prev = corners+numEdges-1,
*here = corners;
G4PolyPhiFaceEdge *edge = edges,
*sourceEdge = source.edges;
do {
*edge = *sourceEdge;
edge->v0 = prev;
edge->v1 = here;
} while( ++sourceEdge, ++edge, prev=here, ++here < corners+numEdges );
}
@@ -160,14 +308,14 @@ G4PolyPhiFace::~G4PolyPhiFace()
G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &aNormal, G4bool &allBehind )
G4ThreeVector &aNormal, G4bool &isAllBehind )
{
G4double normSign = outgoing ? +1 : -1;
//
// These don't change
//
allBehind = true;
isAllBehind = allBehind;
aNormal = normal;
//
@@ -185,7 +333,7 @@ G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
G4ThreeVector ps = p - surface;
distFromSurface = -normSign*ps.dot(normal);
if (distFromSurface < surfTolerance) return false;
if (distFromSurface < -surfTolerance) return false;
//
// Calculate precise distance to intersection with the side
@@ -203,7 +351,7 @@ G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
//
// And is it inside the r/z extent?
//
return InsideEdges( r, ip.z() );
return InsideEdgesExact( r, ip.z(), normSign, p, v );
}
@@ -219,7 +367,10 @@ G4double G4PolyPhiFace::Distance( const G4ThreeVector &p, const G4bool outgoing
G4ThreeVector ps = p - surface;
G4double distPhi = -normSign*normal.dot(ps);
if (distPhi <= 0) return kInfinity;
if (distPhi < -0.5*kCarTolerance)
return kInfinity;
else if (distPhi < 0)
distPhi = 0.0;
//
// Calculate projected point in r,z
@@ -270,30 +421,15 @@ EInside G4PolyPhiFace::Inside( const G4ThreeVector &p, const G4double tolerance,
G4double distRZ2;
G4PolyPhiFaceVertex *base3Dnorm;
G4ThreeVector *head3Dnorm;
G4bool wereIn = InsideEdges( r, p.z(), &distRZ2, &base3Dnorm, &head3Dnorm );
if (wereIn) {
if (InsideEdges( r, p.z(), &distRZ2, &base3Dnorm, &head3Dnorm )) {
//
// Looks like we're inside. Distance is distance in phi.
//
*bestDistance = fabs(distPhi);
}
else {
//
// We're outside the extent of the face,
// so the distance is penalized by distance from edges in RZ
//
*bestDistance = sqrt( distPhi*distPhi + distRZ2 );
}
//
// Can we be on the surface? Yes, but only if we're inside, or
// close to inside by tolerance
//
if (wereIn || distRZ2 < tolerance*tolerance ) {
//
// Yup, answer depends on distPhi, and we can use tolerance
// to decide if we are on the surface
// Use distPhi to decide fate
//
if (distPhi < -tolerance) return kInside;
if (distPhi < tolerance) return kSurface;
@@ -301,14 +437,29 @@ EInside G4PolyPhiFace::Inside( const G4ThreeVector &p, const G4double tolerance,
}
else {
//
// Nope. we can only be in or out, and we must
// used the edge normal to decide
// We're outside the extent of the face,
// so the distance is penalized by distance from edges in RZ
//
*bestDistance = sqrt( distPhi*distPhi + distRZ2 );
//
// Use edge normal to decide fate
//
G4ThreeVector cc( base3Dnorm->r*radial.x(),
base3Dnorm->r*radial.y(),
base3Dnorm->z );
cc = p - cc;
return head3Dnorm->dot(cc) < 0 ? kInside : kOutside;
G4double normDist = head3Dnorm->dot(cc);
if ( distRZ2 > tolerance*tolerance ) {
//
// We're far enough away that kSurface is not possible
//
return normDist < 0 ? kInside : kOutside;
}
if (normDist < -tolerance) return kInside;
if (normDist < tolerance) return kSurface;
return kOutside;
}
}
@@ -382,7 +533,7 @@ G4double G4PolyPhiFace::Extent( const G4ThreeVector axis )
void G4PolyPhiFace::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max )
G4SolidExtentList &extentList )
{
//
// Construct a (sometimes big) clippable polygon,
@@ -402,18 +553,139 @@ void G4PolyPhiFace::CalculateExtent( const EAxis axis,
//
// Clip away
//
polygon.Clip( voxelLimit );
//
// Get extent
//
polygon.GetExtent( axis, min, max );
if (polygon.PartialClip( voxelLimit, axis )) {
//
// Add it to the list
//
polygon.SetNormal( transform.TransformAxis(normal) );
extentList.AddSurface( polygon );
}
}
//
//-------------------------------------------------------
//
// InsideEdgesExact
//
// Decide if the point in r,z is inside the edges of our face,
// **but** do so consistently with other faces.
//
// This routine has functionality similar to InsideEdges, but uses
// an algorithm to decide if a trajectory falls inside or outside the
// face that uses only the trajectory p,v values and the three dimensional
// points representing the edges of the polygon. The objective is to plug up
// any leaks between touching G4PolyPhiFaces (at r==0) and any other face
// that uses the same convention.
//
// See: "Computational Geometry in C (Second Edition)"
// http://cs.smith.edu/~orourke/
//
G4bool G4PolyPhiFace::InsideEdgesExact( const G4double r, const G4double z,
const G4double normSign, const G4ThreeVector &p, const G4ThreeVector &v )
{
//
// Quick check of extent
//
if ( r < rMin-kCarTolerance ||
r > rMax+kCarTolerance ) return false;
if ( z < zMin-kCarTolerance ||
z > zMax+kCarTolerance ) return false;
//
// Exact check: loop over all vertices
//
G4double qx = p.x() + v.x(),
qy = p.y() + v.y(),
qz = p.z() + v.z();
int answer = 0;
G4PolyPhiFaceVertex *corn = corners,
*prev = corners+numEdges-1;
G4double cornZ, prevZ;
prevZ = ExactZOrder( z, qx, qy, qz, v, normSign, prev );
do {
//
// Get z order of this vertex, and compare to previous vertex
//
cornZ = ExactZOrder( z, qx, qy, qz, v, normSign, corn );
if (cornZ < 0) {
if (prevZ < 0) continue;
}
else if (cornZ > 0) {
if (prevZ > 0) continue;
}
else {
//
// By chance, we overlap exactly (within precision) with
// the current vertex. Continue if the same happened previously
// (e.g. the previous vertex had the same z value)
//
if (prevZ == 0) continue;
//
// Otherwise, to decide what to do, we need to know what is
// coming up next. Specifically, we need to find the next vertex
// with a non-zero z order.
//
// One might worry about infinite loops, but the above conditional
// should prevent it
//
G4PolyPhiFaceVertex *next = corn;
G4double nextZ;
do {
next++;
if (next == corners+numEdges) next = corners;
nextZ = ExactZOrder( z, qx, qy, qz, v, normSign, next );
} while( nextZ == 0 );
//
// If we won't be changing direction, go to the next vertex
//
if (nextZ*prevZ < 0) continue;
}
//
// We overlap in z with the side of the face that stretches from
// vertex "prev" to "corn". On which side (left or right) do
// we lay with respect to this segment?
//
G4ThreeVector qa( qx - prev->x, qy - prev->y, qz - prev->z ),
qb( qx - corn->x, qy - corn->y, qz - corn->z );
G4double aboveOrBelow = normSign*qa.cross(qb).dot(v);
if (aboveOrBelow > 0)
answer++;
else if (aboveOrBelow < 0)
answer--;
else {
//
// A precisely zero answer here means we exactly
// intersect (within roundoff) the edge of the face.
// Return true in this case.
//
return true;
}
} while( prevZ = cornZ, prev=corn, ++corn < corners+numEdges );
// G4int fanswer = abs(answer);
// if (fanswer==1 || fanswer>2) {
// G4cerr << "G4PolyPhiFace::InsideEdgesExact: answer is " << answer << endl;
// }
return answer!=0;
}
//
// InsideEdges (don't care aboud distance)
//
+240 -77
View File
@@ -3,11 +3,21 @@
//
// Implementation of a CSG polycone
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4Polycone.hh"
#include "G4PolyconeSide.hh"
#include "G4PolyPhiFace.hh"
#include "G4Polyhedron.hh"
#include "G4EnclosingCylinder.hh"
#include "G4ReduciblePolygon.hh"
//
@@ -22,46 +32,34 @@ G4Polycone::G4Polycone( G4String name,
const G4double rOuter[] ) : G4VCSGfaceted( name )
{
//
// Real ugly
// Some historical ugliness
//
original_parameters.exist = true;
original_parameters = new G4PolyconeHistorical();
original_parameters.Start_angle = phiStart;
original_parameters.Opening_angle = phiTotal;
original_parameters.Num_z_planes = numZPlanes;
original_parameters.Z_values = new G4double[numZPlanes];
original_parameters.Rmin = new G4double[numZPlanes];
original_parameters.Rmax = new G4double[numZPlanes];
original_parameters->Start_angle = phiStart;
original_parameters->Opening_angle = phiTotal;
original_parameters->Num_z_planes = numZPlanes;
original_parameters->Z_values = new G4double[numZPlanes];
original_parameters->Rmin = new G4double[numZPlanes];
original_parameters->Rmax = new G4double[numZPlanes];
G4int i;
for (i=0; i<numZPlanes; i++) {
original_parameters.Z_values[i] = zPlane[i];
original_parameters.Rmin[i] = rInner[i];
original_parameters.Rmax[i] = rOuter[i];
original_parameters->Z_values[i] = zPlane[i];
original_parameters->Rmin[i] = rInner[i];
original_parameters->Rmax[i] = rOuter[i];
}
//
// Translate GEANT3 into generic parameters
// Duplicate vertices and divided surfaces are (or should be) dealt with
// by routine "Create."
// Build RZ polygon using special PCON/PGON GEANT3 constructor
//
G4double *r = new G4double[numZPlanes*2];
G4double *z = new G4double[numZPlanes*2];
G4ReduciblePolygon *rz = new G4ReduciblePolygon( rInner, rOuter, zPlane, numZPlanes );
G4double *rOut = r + numZPlanes,
*zOut = z + numZPlanes,
*rIn = rOut-1,
*zIn = zOut-1;
for( i=0; i < numZPlanes; i++, rOut++, zOut++, rIn--, zIn-- ) {
*rOut = rOuter[i];
*rIn = rInner[i];
*zOut = *zIn = zPlane[i];
}
//
// Do the real work
//
Create( phiStart, phiTotal, rz );
Create( phiStart, phiTotal, numZPlanes*2, r, z );
delete [] r;
delete [] z;
delete rz;
}
@@ -75,9 +73,13 @@ G4Polycone::G4Polycone( G4String name,
const G4double r[],
const G4double z[] ) : G4VCSGfaceted( name )
{
original_parameters.exist = false;
original_parameters = 0;
G4ReduciblePolygon *rz = new G4ReduciblePolygon( r, z, numRZ );
Create( phiStart, phiTotal, numRZ, r, z );
Create( phiStart, phiTotal, rz );
delete rz;
}
@@ -88,10 +90,29 @@ G4Polycone::G4Polycone( G4String name,
//
void G4Polycone::Create( const G4double phiStart,
const G4double phiTotal,
const G4int numRZ,
const G4double r[],
const G4double z[] )
G4ReduciblePolygon *rz )
{
//
// Perform checks of rz values
//
if (rz->Amin() < 0.0)
G4Exception( "G4Polycone: Illegal input parameters: All R values must be >= 0" );
G4double rzArea = rz->Area();
if (rzArea < -kCarTolerance)
G4Exception( "G4Polycone: Illegal input parameters: R/Z values must be specified clockwise" );
else if (rzArea < -kCarTolerance)
G4Exception( "G4Polycone: Illegal input parameters: R/Z cross section is zero or near zero" );
if ((!rz->RemoveDuplicateVertices( kCarTolerance )) ||
(!rz->RemoveRedundantVertices( kCarTolerance )) )
G4Exception( "G4Polycone: Illegal input parameters: Too few unique R/Z values" );
if (rz->CrossesItself(1/kInfinity))
G4Exception( "G4Polycone: Illegal input parameters: R/Z segments cross" );
numCorner = rz->NumVertices();
//
// Phi opening? Account for some possible roundoff, and interpret
// nonsense value as representing no phi opening
@@ -115,35 +136,21 @@ void G4Polycone::Create( const G4double phiStart,
}
//
// Allocate corner array. We may not end up using all of this array,
// since we delete duplicate corners, but that's not so bad
// Allocate corner array.
//
corners = new G4PolyconeSideRZ[numRZ];
corners = new G4PolyconeSideRZ[numCorner];
//
// Copy corners, avoiding duplicates on the way
//
// We should also look for divided conical surfaces...
// We must also look for overlapping surfaces...
// Copy corners
//
G4ReduciblePolygonIterator iterRZ(rz);
G4PolyconeSideRZ *next = corners;
const G4double *rOne = r;
const G4double *zOne = z;
const G4double *rNext, *zNext;
G4bool notFinished;
iterRZ.Begin();
do {
rNext = rOne + 1;
zNext = zOne + 1;
if (notFinished = (rNext < r+numRZ)) {
if (*rNext == *rOne && *zNext == *zOne) continue;
}
next->r = *rOne;
next->z = *zOne;
next++;
} while( rOne=rNext, zOne=zNext, notFinished );
numCorner = next - corners;
next->r = iterRZ.GetA();
next->z = iterRZ.GetB();
} while( ++next, iterRZ.Next() );
//
// Allocate face pointer array
@@ -168,22 +175,46 @@ void G4Polycone::Create( const G4double phiStart,
if (corner->r < 1/kInfinity && next->r < 1/kInfinity) continue;
//
// We must decide here if we can dare declare one of our faces
// as having a "valid" normal (i.e. allBehind = true). This
// is never possible if the face faces "inward" in r.
//
G4bool allBehind;
if (corner->z > next->z) {
allBehind = false;
}
else {
//
// Otherwise, it is only true if the line passing
// through the two points of the segment do not
// split the r/z cross section
//
allBehind = !rz->BisectedBy( corner->r, corner->z,
next->r, next->z, kCarTolerance );
}
*face++ = new G4PolyconeSide( prev, corner, next, nextNext,
startPhi, endPhi-startPhi, phiIsOpen );
startPhi, endPhi-startPhi, phiIsOpen, allBehind );
} while( prev=corner, corner=next, corner > corners );
if (phiIsOpen) {
//
// Construct phi open edges
//
*face++ = new G4PolyPhiFace( r, z, numRZ, startPhi, 0, true );
*face++ = new G4PolyPhiFace( r, z, numRZ, endPhi, 0, false );
*face++ = new G4PolyPhiFace( rz, startPhi, 0, endPhi );
*face++ = new G4PolyPhiFace( rz, endPhi, 0, startPhi );
}
//
// We might have dropped a face or two: recalculate numFace
//
numFace = face-faces;
//
// Make enclosingCylinder
//
enclosingCylinder = new G4EnclosingCylinder( rz, phiIsOpen, phiStart, phiTotal );
}
@@ -194,11 +225,116 @@ G4Polycone::~G4Polycone()
{
delete [] corners;
if (original_parameters.exist) {
delete [] original_parameters.Z_values;
delete [] original_parameters.Rmin;
delete [] original_parameters.Rmax;
if (original_parameters) delete original_parameters;
}
//
// Copy constructor
//
G4Polycone::G4Polycone( const G4Polycone &source ) : G4VCSGfaceted( source )
{
CopyStuff( source );
}
//
// Assignment operator
//
const G4Polycone &G4Polycone::operator=( const G4Polycone &source )
{
if (this == &source) return *this;
G4VCSGfaceted::operator=( source );
delete [] corners;
if (original_parameters) delete original_parameters;
delete enclosingCylinder;
CopyStuff( source );
return *this;
}
//
// CopyStuff
//
void G4Polycone::CopyStuff( const G4Polycone &source )
{
//
// Simple stuff
//
startPhi = source.startPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
numCorner = source.numCorner;
//
// The corner array
//
corners = new G4PolyconeSideRZ[numCorner];
G4PolyconeSideRZ *corn = corners,
*sourceCorn = source.corners;
do {
*corn = *sourceCorn;
} while( ++sourceCorn, ++corn < corners+numCorner );
//
// Original parameters
//
if (source.original_parameters) {
original_parameters = new G4PolyconeHistorical( *source.original_parameters );
}
//
// Enclosing cylinder
//
enclosingCylinder = new G4EnclosingCylinder( *source.enclosingCylinder );
}
//
// Inside
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
EInside G4Polycone::Inside( const G4ThreeVector &p ) const
{
//
// Quick test
//
if (enclosingCylinder->MustBeOutside(p)) return kOutside;
//
// Long answer
//
return G4VCSGfaceted::Inside(p);
}
//
// DistanceToIn
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
G4double G4Polycone::DistanceToIn( const G4ThreeVector &p, const G4ThreeVector &v ) const
{
//
// Quick test
//
if (enclosingCylinder->ShouldMiss(p,v)) return kInfinity;
//
// Long answer
//
return G4VCSGfaceted::DistanceToIn( p, v );
}
@@ -218,22 +354,19 @@ void G4Polycone::ComputeDimensions( G4VPVParameterisation* p,
G4Polyhedron *G4Polycone::CreatePolyhedron() const
{
//
// It is *really* unfortunate how the design in /graphics_reps is
// written to parallel the design in /geometry/solids. Ugly, ugly, ugly.
//
// This has to be fixed, but I won't do it now. Fake it for the moment.
// This has to be fixed in visualization. Fake it for the moment.
//
if (original_parameters.exist) {
if (original_parameters) {
return new G4PolyhedronPcon( original_parameters.Start_angle,
original_parameters.Opening_angle,
original_parameters.Num_z_planes,
original_parameters.Z_values,
original_parameters.Rmin,
original_parameters.Rmax);
return new G4PolyhedronPcon( original_parameters->Start_angle,
original_parameters->Opening_angle,
original_parameters->Num_z_planes,
original_parameters->Z_values,
original_parameters->Rmin,
original_parameters->Rmax);
}
else {
G4Exception( "G4Polycone: waiting for graphics_reps to catch up" );
G4cerr << "G4Polycone: visualization of this type of G4Polycone is not supported at this time" << endl;
return 0;
}
}
@@ -246,3 +379,33 @@ G4NURBS *G4Polycone::CreateNURBS() const
{
return 0;
}
//
// G4Polycone:G4PolyconeHistorical stuff
//
G4Polycone::G4PolyconeHistorical::~G4PolyconeHistorical()
{
delete [] Z_values;
delete [] Rmin;
delete [] Rmax;
}
G4Polycone::G4PolyconeHistorical::G4PolyconeHistorical( const G4Polycone::G4PolyconeHistorical &source )
{
Start_angle = source.Start_angle;
Opening_angle = source.Opening_angle;
Num_z_planes = source.Num_z_planes;
Z_values = new G4double[Num_z_planes];
Rmin = new G4double[Num_z_planes];
Rmax = new G4double[Num_z_planes];
G4int i;
for( i = 0; i < Num_z_planes; i++) {
Z_values[i] = source.Z_values[i];
Rmin[i] = source.Rmin[i];
Rmax[i] = source.Rmax[i];
}
}
+438 -66
View File
@@ -3,12 +3,21 @@
//
// Implemenation of the face representing one conical side of a polycone
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4PolyconeSide.hh"
#include "G4IntersectingCone.hh"
#include "G4ClippablePolygon.hh"
#include "G4AffineTransform.hh"
#include "meshdefs.hh"
#include "G4SolidExtentList.hh"
//
// Constructor
@@ -22,7 +31,8 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
const G4PolyconeSideRZ *nextRZ,
const G4double thePhiStart,
const G4double theDeltaPhi,
const G4bool thePhiIsOpen )
const G4bool thePhiIsOpen,
const G4bool isAllBehind )
{
//
// Record values
@@ -40,11 +50,23 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
//
while (deltaPhi < 0.0) deltaPhi += 2.0*M_PI;
while (startPhi < 0.0) startPhi += 2.0*M_PI;
//
// Calculate corner coordinates
//
corners = new G4ThreeVector[4];
corners[0] = G4ThreeVector( tail->r*cos(startPhi), tail->r*sin(startPhi), tail->z );
corners[1] = G4ThreeVector( head->r*cos(startPhi), head->r*sin(startPhi), head->z );
corners[2] = G4ThreeVector( tail->r*cos(startPhi+deltaPhi), tail->r*sin(startPhi+deltaPhi), tail->z );
corners[3] = G4ThreeVector( head->r*cos(startPhi+deltaPhi), head->r*sin(startPhi+deltaPhi), head->z );
}
else {
deltaPhi = 2*M_PI;
startPhi = 0.0;
}
allBehind = isAllBehind;
//
// Make our intersecting cone
@@ -61,24 +83,28 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
rNorm = +zS;
zNorm = -rS;
G4double rAdj = r[0]-prevRZ->r, zAdj = z[0]-prevRZ->z;
G4double lAdj = sqrt( rAdj*rAdj + zAdj*zAdj );
rAdj /= lAdj;
zAdj /= lAdj;
G4double lAdj;
rNormEdge[0] = rNorm + zAdj;
zNormEdge[0] = zNorm - rAdj;
prevRS = r[0]-prevRZ->r;
prevZS = z[0]-prevRZ->z;
lAdj = sqrt( prevRS*prevRS + prevZS*prevZS );
prevRS /= lAdj;
prevZS /= lAdj;
rNormEdge[0] = rNorm + prevZS;
zNormEdge[0] = zNorm - prevRS;
lAdj = sqrt( rNormEdge[0]*rNormEdge[0] + zNormEdge[0]*zNormEdge[0] );
rNormEdge[0] /= lAdj;
zNormEdge[0] /= lAdj;
rAdj = nextRZ->r-r[1], zAdj = nextRZ->z-z[1];
lAdj = sqrt( rAdj*rAdj + zAdj*zAdj );
rAdj /= lAdj;
zAdj /= lAdj;
rNormEdge[1] = rNorm + zAdj;
zNormEdge[1] = zNorm - rAdj;
nextRS = nextRZ->r-r[1];
nextZS = nextRZ->z-z[1];
lAdj = sqrt( nextRS*nextRS + nextZS*nextZS );
nextRS /= lAdj;
nextZS /= lAdj;
rNormEdge[1] = rNorm + nextZS;
zNormEdge[1] = zNorm - nextRS;
lAdj = sqrt( rNormEdge[1]*rNormEdge[1] + zNormEdge[1]*zNormEdge[1] );
rNormEdge[1] /= lAdj;
zNormEdge[1] /= lAdj;
@@ -91,18 +117,90 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
G4PolyconeSide::~G4PolyconeSide()
{
delete cone;
if (phiIsOpen) delete [] corners;
}
//
// Copy constructor
//
G4PolyconeSide::G4PolyconeSide( const G4PolyconeSide &source )
{
CopyStuff( source );
}
//
// Assignment operator
//
G4PolyconeSide *G4PolyconeSide::operator=( const G4PolyconeSide &source )
{
if (this == &source) return this;
delete cone;
if (phiIsOpen) delete [] corners;
CopyStuff( source );
return this;
}
//
// CopyStuff
//
void G4PolyconeSide::CopyStuff( const G4PolyconeSide &source )
{
r[0] = source.r[0];
r[1] = source.r[1];
z[0] = source.z[0];
z[1] = source.z[1];
startPhi = source.startPhi;
deltaPhi = source.deltaPhi;
phiIsOpen = source.phiIsOpen;
allBehind = source.allBehind;
cone = new G4IntersectingCone( *source.cone );
rNorm = source.rNorm;
zNorm = source.zNorm;
rS = source.rS;
zS = source.zS;
length = source.length;
prevRS = source.prevRS;
prevZS = source.prevZS;
nextRS = source.nextRS;
nextZS = source.nextZS;
rNormEdge[0] = source.rNormEdge[0];
rNormEdge[1] = source.rNormEdge[1];
zNormEdge[0] = source.zNormEdge[0];
zNormEdge[1] = source.zNormEdge[1];
if (phiIsOpen) {
corners = new G4ThreeVector[4];
corners[0] = source.corners[0];
corners[1] = source.corners[1];
corners[2] = source.corners[2];
corners[3] = source.corners[3];
}
}
//
// Intersect
//
G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &normal, G4bool &allBehind )
G4ThreeVector &normal, G4bool &isAllBehind )
{
G4double s1, s2;
G4double normSign = outgoing ? +1 : -1;
allBehind = true;
isAllBehind = allBehind;
//
// Check for two possible intersections
@@ -115,7 +213,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
G4ThreeVector hit = p + s1*v;
if (PointOnCone( hit, normal )) {
if (PointOnCone( hit, normSign, p, v, normal )) {
//
// Good intersection! What about the normal?
//
@@ -129,7 +227,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
G4bool opposite = (p.x()*hit.x()+p.y()*hit.y() < 0);
G4double distOutside2;
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2, 0 );
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2 );
//
// The distance from the surface is defined along the
@@ -143,7 +241,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
// Apply tolerance, but only if the point is outside
// the edges of the cone
//
if (distFromSurface > (distOutside2 > 0 ? 0 : surfTolerance)) {
if (distFromSurface > (distOutside2 > 0 ? 0 : -surfTolerance)) {
//
// Good intersection. Return now, since it is the closest.
//
@@ -160,7 +258,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
hit = p + s2*v;
if (PointOnCone( hit, normal )) {
if (PointOnCone( hit, normSign, p, v, normal )) {
//
// Good intersection! What about the normal?
//
@@ -174,7 +272,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
G4bool opposite = (p.x()*hit.x()+p.y()*hit.y() < 0);
G4double distOutside2;
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2, 0 );
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2 );
//
// The distance from the surface is defined along the
@@ -188,7 +286,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
// Apply tolerance, but only if the point is outside
// the edges of the cone
//
if (distFromSurface > (distOutside2 > 0 ? 0 : surfTolerance)) {
if (distFromSurface > (distOutside2 > 0 ? 0 : -surfTolerance)) {
//
// Good intersection. Return now, since it is the closest.
//
@@ -213,22 +311,22 @@ G4double G4PolyconeSide::Distance( const G4ThreeVector &p, const G4bool outgoing
//
// We have two tries for each hemisphere. Try the closest first.
//
distFrom = DistanceAway( p, false, distOut2, 0 );
if (distFrom*normSign > 0) {
distFrom = normSign*DistanceAway( p, false, distOut2 );
if (distFrom > -0.5*kCarTolerance ) {
//
// Good answer
//
if (distOut2 > 0)
return sqrt( distFrom*distFrom + distOut2 );
else
else
return fabs(distFrom);
}
//
// Try second side.
//
distFrom = DistanceAway( p, true, distOut2, 0 );
if (distFrom*normSign > 0) {
distFrom = normSign*DistanceAway( p, true, distOut2 );
if (distFrom > -0.5*kCarTolerance) {
if (distOut2 > 0)
return sqrt( distFrom*distFrom + distOut2 );
@@ -252,7 +350,7 @@ EInside G4PolyconeSide::Inside( const G4ThreeVector &p, const G4double tolerance
G4double distFrom[2], distOut2[2], dist2[2];
G4double edgeRZnorm[2];
distFrom[0] = DistanceAway( p, false, distOut2[0], edgeRZnorm );
distFrom[0] = DistanceAway( p, false, distOut2[0], edgeRZnorm );
distFrom[1] = DistanceAway( p, true, distOut2[1], edgeRZnorm+1 );
dist2[0] = distFrom[0]*distFrom[0] + distOut2[0];
@@ -270,7 +368,7 @@ EInside G4PolyconeSide::Inside( const G4ThreeVector &p, const G4double tolerance
//
if ( (fabs(edgeRZnorm[i]) < tolerance) && (distOut2[i] < tolerance*tolerance) )
return kSurface;
else if (edgeRZnorm[i] < 0)
else if (edgeRZnorm[i] < 0)
return kInside;
else
return kOutside;
@@ -285,7 +383,7 @@ G4ThreeVector G4PolyconeSide::Normal( const G4ThreeVector &p, G4double *bestDis
G4ThreeVector dFrom;
G4double dOut2;
dFrom = DistanceAway( p, false, dOut2, 0 );
dFrom = DistanceAway( p, false, dOut2 );
*bestDistance = sqrt( dFrom*dFrom + dOut2 );
@@ -299,7 +397,7 @@ G4ThreeVector G4PolyconeSide::Normal( const G4ThreeVector &p, G4double *bestDis
//
G4double G4PolyconeSide::Extent( const G4ThreeVector axis )
{
if (axis.perp2() < 1.0/kInfinity) {
if (axis.perp2() < DBL_MIN) {
//
// Special case
//
@@ -352,6 +450,7 @@ G4double G4PolyconeSide::Extent( const G4ThreeVector axis )
}
//
// CalculateExtent
//
@@ -360,17 +459,12 @@ G4double G4PolyconeSide::Extent( const G4ThreeVector axis )
void G4PolyconeSide::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max )
G4SolidExtentList &extentList )
{
G4ClippablePolygon polygon;
//
// The following code does not work correctly and needs to be
// fixed... DCW 12/10/98
//
//
// Here we will cheat (ala G4Cons) and divide our conical section
// Here we will approximate (ala G4Cons) and divide our conical section
// into segments, like G4Polyhedra. When doing so, the radius
// is extented far enough such that the segments always lie
// just outside the surface of the conical section we are
@@ -392,54 +486,271 @@ void G4PolyconeSide::CalculateExtent( const EAxis axis,
//
// Determine radius factor to keep segments outside
//
G4double rFudge = 1.0/cos(sigPhi);
G4double rFudge = 1.0/cos(0.5*sigPhi);
//
// Decide which radius to use on each end of the side,
// and whether a transition mesh is required
//
// {r0,z0} - Beginning of this side
// {r1,z1} - Ending of this side
// {r2,z0} - Beginning of transition piece connecting previous
// side (and ends at beginning of this side)
//
// So, order is 2 --> 0 --> 1.
// -------
//
// r2 < 0 indicates that no transition piece is required
//
G4double r0, r1, r2, z0, z1;
r2 = -1; // By default: no transition piece
if (rNorm < -DBL_MIN) {
//
// This side faces *inward*, and so our mesh has
// the same radius
//
r1 = r[1];
z1 = z[1];
z0 = z[0];
r0 = r[0];
r2 = -1;
if (prevZS > DBL_MIN) {
//
// The previous side is facing outwards
//
if ( prevRS*zS - prevZS*rS > 0 ) {
//
// Transition was convex: build transition piece
//
if (r[0] > DBL_MIN) r2 = r[0]*rFudge;
}
else {
//
// Transition was concave: short this side
//
FindLineIntersect( z0, r0, zS, rS,
z0, r0*rFudge, prevZS, prevRS*rFudge, z0, r0 );
}
}
if ( nextZS > DBL_MIN && (rS*nextZS - zS*nextRS < 0) ) {
//
// The next side is facing outwards, forming a
// concave transition: short this side
//
FindLineIntersect( z1, r1, zS, rS,
z1, r1*rFudge, nextZS, nextRS*rFudge, z1, r1 );
}
}
else if (rNorm > DBL_MIN) {
//
// This side faces *outward* and is given a boost to
// it radius
//
r0 = r[0]*rFudge;
z0 = z[0];
r1 = r[1]*rFudge;
z1 = z[1];
if (prevZS < -DBL_MIN) {
//
// The previous side is facing inwards
//
if ( prevRS*zS - prevZS*rS > 0 ) {
//
// Transition was convex: build transition piece
//
if (r[0] > DBL_MIN) r2 = r[0];
}
else {
//
// Transition was concave: short this side
//
FindLineIntersect( z0, r0, zS, rS*rFudge,
z0, r[0], prevZS, prevRS, z0, r0 );
}
}
if ( nextZS < -DBL_MIN && (rS*nextZS - zS*nextRS < 0) ) {
//
// The next side is facing inwards, forming a
// concave transition: short this side
//
FindLineIntersect( z1, r1, zS, rS*rFudge,
z1, r[1], nextZS, nextRS, z1, r1 );
}
}
else {
//
// This side is perpendicular to the z axis (is a disk)
//
// Whether or not r0 needs a rFudge factor depends
// on the normal of the previous edge. Similar with r1
// and the next edge. No transition piece is required.
//
r0 = r[0];
r1 = r[1];
z0 = z[0];
z1 = z[1];
if (prevZS > DBL_MIN) r0 *= rFudge;
if (nextZS > DBL_MIN) r1 *= rFudge;
}
//
// Loop
//
G4double phi = startPhi,
cosPhi = rFudge*cos(phi),
sinPhi = rFudge*sin(phi);
cosPhi = cos(phi),
sinPhi = sin(phi);
G4ThreeVector v0( r[0]*cosPhi, r[0]*sinPhi, z[0] ),
v1( r[1]*cosPhi, r[1]*sinPhi, z[1] ),
w0, w1;
G4ThreeVector v0( r0*cosPhi, r0*sinPhi, z0 ),
v1( r1*cosPhi, r1*sinPhi, z1 ),
v2, w0, w1, w2;
transform.ApplyPointTransform( v0 );
transform.ApplyPointTransform( v1 );
if (r2 >= 0) {
v2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, z0 );
transform.ApplyPointTransform( v2 );
}
do {
G4double min, max;
phi += sigPhi;
cosPhi = rFudge*cos(phi),
sinPhi = rFudge*sin(phi);
if (numPhi == 1) phi = startPhi+deltaPhi; // Try to avoid roundoff
cosPhi = cos(phi),
sinPhi = sin(phi);
w0 = G4ThreeVector( r[0]*cosPhi, r[0]*sinPhi, z[0] );
w1 = G4ThreeVector( r[1]*cosPhi, r[1]*sinPhi, z[1] );
w0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, z0 );
w1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, z1 );
transform.ApplyPointTransform( w0 );
transform.ApplyPointTransform( w1 );
G4ThreeVector deltaV = r0 > r1 ? w0-v0 : w1-v1;
//
// Build polygon, taking special care to keep the vertices
// in order
//
polygon.ClearAllVertices();
polygon.AddVertexInOrder( v0 );
polygon.AddVertexInOrder( v1 );
polygon.AddVertexInOrder( w1 );
polygon.AddVertexInOrder( w0 );
//
// Get extent
//
polygon.Clip( voxelLimit );
polygon.GetExtent( axis, min, max );
if (polygon.PartialClip( voxelLimit, axis )) {
//
// Get dot product of normal with target axis
//
polygon.SetNormal( deltaV.cross(v1-v0).unit() );
extentList.AddSurface( polygon );
}
if (r2 >= 0) {
//
// Repeat, for transition piece
//
w2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, z0 );
transform.ApplyPointTransform( w2 );
polygon.ClearAllVertices();
polygon.AddVertexInOrder( v2 );
polygon.AddVertexInOrder( v0 );
polygon.AddVertexInOrder( w0 );
polygon.AddVertexInOrder( w2 );
if (polygon.PartialClip( voxelLimit, axis )) {
polygon.SetNormal( deltaV.cross(v0-v2).unit() );
extentList.AddSurface( polygon );
}
v2 = w2;
}
//
// Next vertex
//
v0 = w0;
v1 = w1;
} while( --numPhi > 0 );
//
// We are almost done. But, it is important that we leave no
// gaps in the surface of our solid. By using rFudge, however,
// we've done exactly that, if we have a phi segment.
// Add two additional faces if necessary
//
if (phiIsOpen && rNorm > DBL_MIN) {
G4double min, max;
G4double cosPhi = cos(startPhi),
sinPhi = sin(startPhi);
G4ThreeVector a0( r[0]*cosPhi, r[0]*sinPhi, z[0] ),
a1( r[1]*cosPhi, r[1]*sinPhi, z[1] ),
b0( r0*cosPhi, r0*sinPhi, z[0] ),
b1( r1*cosPhi, r1*sinPhi, z[1] );
transform.ApplyPointTransform( a0 );
transform.ApplyPointTransform( a1 );
transform.ApplyPointTransform( b0 );
transform.ApplyPointTransform( b1 );
polygon.ClearAllVertices();
polygon.AddVertexInOrder( a0 );
polygon.AddVertexInOrder( a1 );
polygon.AddVertexInOrder( b0 );
polygon.AddVertexInOrder( b1 );
if (polygon.PartialClip( voxelLimit , axis)) {
G4ThreeVector normal( sinPhi, -cosPhi, 0 );
polygon.SetNormal( transform.TransformAxis( normal ) );
extentList.AddSurface( polygon );
}
cosPhi = cos(startPhi+deltaPhi);
sinPhi = sin(startPhi+deltaPhi);
a0 = G4ThreeVector( r[0]*cosPhi, r[0]*sinPhi, z[0] ),
a1 = G4ThreeVector( r[1]*cosPhi, r[1]*sinPhi, z[1] ),
b0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, z[0] ),
b1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, z[1] );
transform.ApplyPointTransform( a0 );
transform.ApplyPointTransform( a1 );
transform.ApplyPointTransform( b0 );
transform.ApplyPointTransform( b1 );
polygon.ClearAllVertices();
polygon.AddVertexInOrder( a0 );
polygon.AddVertexInOrder( a1 );
polygon.AddVertexInOrder( b0 );
polygon.AddVertexInOrder( b1 );
if (polygon.PartialClip( voxelLimit, axis )) {
G4ThreeVector normal( -sinPhi, cosPhi, 0 );
polygon.SetNormal( transform.TransformAxis( normal ) );
extentList.AddSurface( polygon );
}
}
return;
}
@@ -457,7 +768,7 @@ void G4PolyconeSide::CalculateExtent( const EAxis axis,
// opposite - (in) If true, check opposite hemisphere (see below)
// distOutside - (out) Additional distance outside the edges of the
// surface
// edgeNorm - (out) Edge Status (belowRZ, aboveRZ, inRZ)
// edgeRZnorm - (out) if negative, point is inside
// return value = distance from the conical plane, if extrapolated beyond edges,
// signed by whether the point is in inside or outside the shape
//
@@ -465,7 +776,7 @@ void G4PolyconeSide::CalculateExtent( const EAxis axis,
// * There are two answers, depending on which hemisphere is considered.
//
G4double G4PolyconeSide::DistanceAway( const G4ThreeVector &p, const G4bool opposite,
G4double &distOutside2, G4double *edgeRZnorm )
G4double &distOutside2, G4double *edgeRZnorm )
{
//
// Convert our point to r and z
@@ -520,7 +831,10 @@ G4double G4PolyconeSide::DistanceAway( const G4ThreeVector &p, const G4bool oppo
//
// Add result to our distance
//
distOutside2 += d1*d1*p.perp2();
G4double dist = d1*rx;
distOutside2 += dist*dist;
if (edgeRZnorm) *edgeRZnorm = fabs(dist);
}
}
@@ -533,32 +847,90 @@ G4double G4PolyconeSide::DistanceAway( const G4ThreeVector &p, const G4bool oppo
//
// Decide if a point is on a cone and return normal if it is
//
G4bool G4PolyconeSide::PointOnCone( const G4ThreeVector &p, G4ThreeVector &normal )
G4bool G4PolyconeSide::PointOnCone( const G4ThreeVector &hit, const G4double normSign,
const G4ThreeVector &p, const G4ThreeVector &v,
G4ThreeVector &normal )
{
G4double rx = p.perp();
G4double rx = hit.perp();
//
// Check radial/z extent, as appropriate
//
if (!cone->HitOn( rx, p.z() )) return false;
if (!cone->HitOn( rx, hit.z() )) return false;
if (phiIsOpen) {
G4double phiTolerant = 2.0*kCarTolerance/(rx+kCarTolerance);
//
// Check phi segment
// Check phi segment. Here we have to be careful
// to use the standard method consistent with
// PolyPhiFace. See PolyPhiFace::InsideEdgesExact
//
G4double phi = p.phi();
while( phi < startPhi ) phi += 2*M_PI;
G4double phi = hit.phi();
while( phi < startPhi-phiTolerant ) phi += 2*M_PI;
if (phi > startPhi+deltaPhi) return false;
if (phi > startPhi+deltaPhi+phiTolerant) return false;
if (phi > startPhi+deltaPhi-phiTolerant) {
//
// Exact treatment
//
G4ThreeVector qx = p + v;
G4ThreeVector qa = qx - corners[2],
qb = qx - corners[3];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) < 0) return false;
}
else if (phi < phiTolerant) {
G4ThreeVector qx = p + v;
G4ThreeVector qa = qx - corners[1],
qb = qx - corners[0];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) < 0) return false;
}
}
//
// We have a good hit! Calculate normal
//
if (rx<0) rx = p.perp();
if (rx<0) rx = hit.perp();
if (rx < -1.0/kInfinity)
if (rx < DBL_MIN)
normal = G4ThreeVector( 0, 0, zNorm < 0 ? -1 : 1 );
else
normal = G4ThreeVector( rNorm*p.x()/rx, rNorm*p.y()/rx, zNorm );
normal = G4ThreeVector( rNorm*hit.x()/rx, rNorm*hit.y()/rx, zNorm );
return true;
}
//
// FindLineIntersect
//
// Decide the point at which two 2-dimensional lines intersect
//
// Equation of line: x = x1 + s*tx1
// y = y1 + s*ty1
//
// It is assumed that the lines are *not* parallel
//
void G4PolyconeSide::FindLineIntersect( const G4double x1, const G4double y1,
const G4double tx1, const G4double ty1,
const G4double x2, const G4double y2,
const G4double tx2, const G4double ty2,
G4double &x, G4double &y )
{
//
// The solution is a simple linear equation
//
G4double deter = tx1*ty2 - tx2*ty1;
G4double s1 = ((x2-x1)*ty2 - tx2*(y2-y1))/deter;
G4double s2 = ((x2-x1)*ty1 - tx1*(y2-y1))/deter;
//
// We want the answer to not depend on which order the
// lines were specified. Take average.
//
x = 0.5*( x1+s1*tx1 + x2+s2*tx2 );
y = 0.5*( y1+s1*ty1 + y2+s2*ty2 );
}
+232 -101
View File
@@ -4,22 +4,37 @@
// Implementation of a CSG polyhedra, as an inherited class of G4VCSGfaceted.
//
// To be done:
// * Checks for bad input should be improved. It is now possible for
// users to specify crazy polyhedra parameters without complaint that
// could produce unpredictable results.
// * Cracks: there are probably small cracks in the seams between the
// phi face (G4PolyPhiFace) and sides (G4PolyhedraSide) that are not
// entirely leakproof. Also, I am not sure all vertices are leak proof.
// * Many optimizations are possible, but not implemented.
// * Visualization needs to be updated outside of this routine.
//
// Utility classes:
// * G4EnclosingCylinder: I decided a quick check of geometry would be a
// good idea (for CPU speed). If the quick check fails, the regular
// full-blown G4VCSGfaceted version is invoked.
// * G4ReduciblePolygon: Really meant as a check of input parameters,
// this utility class also "converts" the GEANT3-like PGON/PCON
// arguments into the newer ones.
// Both these classes are implemented outside this file because they are
// shared with G4Polycone.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4Polyhedra.hh"
#include "G4PolyhedraSide.hh"
#include "G4PolyPhiFace.hh"
#include "G4Polyhedron.hh"
#include "G4EnclosingCylinder.hh"
#include "G4ReduciblePolygon.hh"
//
// Constructor (GEANT3 style parameters)
@@ -29,7 +44,7 @@
G4Polyhedra::G4Polyhedra( G4String name,
const G4double phiStart,
const G4double thePhiTotal,
const G4double theNumSide,
const G4int theNumSide,
const G4int numZPlanes,
const G4double zPlane[],
const G4double rInner[],
@@ -41,52 +56,42 @@ G4Polyhedra::G4Polyhedra( G4String name,
// Calculate conversion factor from G3 radius to G4 radius
//
G4double phiTotal = thePhiTotal;
if (phiTotal <=0 || phiTotal > 2*M_PI) phiTotal = 2*M_PI;
if (phiTotal <=0 || phiTotal >= 2*M_PI*(1-DBL_EPSILON)) phiTotal = 2*M_PI;
G4double convertRad = cos(0.5*phiTotal/theNumSide);
//
// Real ugly
// Some historical stuff
//
original_parameters.exist = true;
original_parameters = new G4PolyhedraHistorical;
original_parameters.numSide = theNumSide;
original_parameters.Start_angle = phiStart;
original_parameters.Opening_angle = phiTotal;
original_parameters.Num_z_planes = numZPlanes;
original_parameters.Z_values = new G4double[numZPlanes];
original_parameters.Rmin = new G4double[numZPlanes];
original_parameters.Rmax = new G4double[numZPlanes];
original_parameters->numSide = theNumSide;
original_parameters->Start_angle = phiStart;
original_parameters->Opening_angle = phiTotal;
original_parameters->Num_z_planes = numZPlanes;
original_parameters->Z_values = new G4double[numZPlanes];
original_parameters->Rmin = new G4double[numZPlanes];
original_parameters->Rmax = new G4double[numZPlanes];
G4int i;
for (i=0; i<numZPlanes; i++) {
original_parameters.Z_values[i] = zPlane[i];
original_parameters.Rmin[i] = rInner[i]/convertRad;
original_parameters.Rmax[i] = rOuter[i]/convertRad;
}
//
// Translate GEANT3 into generic parameters
// Duplicate vertices and divided surfaces are (or should be) dealt with
// by routine "Create."
//
G4double *r = new G4double[numZPlanes*2];
G4double *z = new G4double[numZPlanes*2];
G4double *rOut = r + numZPlanes,
*zOut = z + numZPlanes,
*rIn = rOut-1,
*zIn = zOut-1;
for( i=0; i < numZPlanes; i++, rOut++, zOut++, rIn--, zIn-- ) {
*rOut = rOuter[i]/convertRad;
*rIn = rInner[i]/convertRad;
*zOut = *zIn = zPlane[i];
original_parameters->Z_values[i] = zPlane[i];
original_parameters->Rmin[i] = rInner[i]/convertRad;
original_parameters->Rmax[i] = rOuter[i]/convertRad;
}
Create( phiStart, phiTotal, theNumSide, numZPlanes*2, r, z );
delete [] r;
delete [] z;
//
// Build RZ polygon using special PCON/PGON GEANT3 constructor
//
G4ReduciblePolygon *rz = new G4ReduciblePolygon( rInner, rOuter, zPlane, numZPlanes );
rz->ScaleA( 1/convertRad );
//
// Do the real work
//
Create( phiStart, phiTotal, theNumSide, rz );
delete rz;
}
@@ -96,14 +101,18 @@ G4Polyhedra::G4Polyhedra( G4String name,
G4Polyhedra::G4Polyhedra( G4String name,
const G4double phiStart,
const G4double phiTotal,
const G4double theNumSide,
const G4int theNumSide,
const G4int numRZ,
const G4double r[],
const G4double z[] ) : G4VCSGfaceted( name )
{
original_parameters.exist = false;
original_parameters = 0;
Create( phiStart, phiTotal, theNumSide, numRZ, r, z );
G4ReduciblePolygon *rz = new G4ReduciblePolygon( r, z, numRZ );
Create( phiStart, phiTotal, theNumSide, rz );
delete rz;
}
@@ -114,19 +123,40 @@ G4Polyhedra::G4Polyhedra( G4String name,
//
void G4Polyhedra::Create( const G4double phiStart,
const G4double phiTotal,
const G4double theNumSide,
const G4int numRZ,
const G4double r[],
const G4double z[] )
const G4int theNumSide,
G4ReduciblePolygon *rz )
{
//
// Perform checks of rz values
//
if (rz->Amin() < 0.0)
G4Exception( "G4Polyhedra: Illegal input parameters: All R values must be >= 0" );
G4double rzArea = rz->Area();
if (rzArea < -kCarTolerance)
G4Exception( "G4Polyhedra: Illegal input parameters: R/Z values must be specified clockwise" );
else if (rzArea < -kCarTolerance)
G4Exception( "G4Polyhedra: Illegal input parameters: R/Z cross section is zero or near zero" );
if ((!rz->RemoveDuplicateVertices( kCarTolerance )) ||
(!rz->RemoveRedundantVertices( kCarTolerance )) )
G4Exception( "G4Polyhedra: Illegal input parameters: Too few unique R/Z values" );
if (rz->CrossesItself( 1/kInfinity ))
G4Exception( "G4Polyhedra: Illegal input parameters: R/Z segments cross" );
numCorner = rz->NumVertices();
startPhi = phiStart;
while( startPhi < 0 ) startPhi += 2*M_PI;
//
// Phi opening? Account for some possible roundoff, and interpret
// nonsense value as representing no phi opening
//
if (phiTotal <= 0 || phiTotal > 2.0*M_PI-1E-10) {
if (phiTotal <= 0 || phiTotal > 2.0*M_PI*(1-DBL_EPSILON)) {
phiIsOpen = false;
startPhi = 0;
endPhi = 2*M_PI;
endPhi = phiStart+2*M_PI;
}
else {
phiIsOpen = true;
@@ -134,9 +164,6 @@ void G4Polyhedra::Create( const G4double phiStart,
//
// Convert phi into our convention
//
startPhi = phiStart;
while( startPhi < 0 ) startPhi += 2*M_PI;
endPhi = phiStart+phiTotal;
while( endPhi < startPhi ) endPhi += 2*M_PI;
}
@@ -147,35 +174,21 @@ void G4Polyhedra::Create( const G4double phiStart,
numSide = theNumSide;
//
// Allocate corner array. We may not end up using all of this array,
// since we delete duplicate corners, but that's not so bad
// Allocate corner array.
//
corners = new G4PolyhedraSideRZ[numRZ];
corners = new G4PolyhedraSideRZ[numCorner];
//
// Copy corners, avoiding duplicates on the way
//
// We should also look for divided conical surfaces...
// We must also look for overlapping surfaces...
// Copy corners
//
G4ReduciblePolygonIterator iterRZ(rz);
G4PolyhedraSideRZ *next = corners;
const G4double *rOne = r;
const G4double *zOne = z;
const G4double *rNext, *zNext;
G4bool notFinished;
iterRZ.Begin();
do {
rNext = rOne + 1;
zNext = zOne + 1;
if (notFinished = (rNext < r+numRZ)) {
if (*rNext == *rOne && *zNext == *zOne) continue;
}
next->r = *rOne;
next->z = *zOne;
next++;
} while( rOne=rNext, zOne=zNext, notFinished );
numCorner = next - corners;
next->r = iterRZ.GetA();
next->z = iterRZ.GetB();
} while( ++next, iterRZ.Next() );
//
// Allocate face pointer array
@@ -202,6 +215,26 @@ void G4Polyhedra::Create( const G4double phiStart,
if (nextNext >= corners+numCorner) nextNext = corners;
if (corner->r < 1/kInfinity && next->r < 1/kInfinity) continue;
//
// We must decide here if we can dare declare one of our faces
// as having a "valid" normal (i.e. allBehind = true). This
// is never possible if the face faces "inward" in r *unless*
// we have only one side
//
G4bool allBehind;
if ((corner->z > next->z) && (numSide > 1)) {
allBehind = false;
}
else {
//
// Otherwise, it is only true if the line passing
// through the two points of the segment do not
// split the r/z cross section
//
allBehind = !rz->BisectedBy( corner->r, corner->z,
next->r, next->z, kCarTolerance );
}
*face++ = new G4PolyhedraSide( prev, corner, next, nextNext,
numSide, startPhi, endPhi-startPhi, phiIsOpen );
@@ -211,8 +244,8 @@ void G4Polyhedra::Create( const G4double phiStart,
//
// Construct phi open edges
//
*face++ = new G4PolyPhiFace( r, z, numRZ, startPhi, phiTotal/numSide, true );
*face++ = new G4PolyPhiFace( r, z, numRZ, endPhi, phiTotal/numSide, false );
*face++ = new G4PolyPhiFace( rz, startPhi, phiTotal/numSide, endPhi );
*face++ = new G4PolyPhiFace( rz, endPhi, phiTotal/numSide, startPhi );
}
//
@@ -223,8 +256,7 @@ void G4Polyhedra::Create( const G4double phiStart,
//
// Make enclosingCylinder
//
enclosingCylinder = new G4EnclosingCylinder( r, z, numRZ,
phiIsOpen, phiStart, phiTotal );
enclosingCylinder = new G4EnclosingCylinder( rz, phiIsOpen, phiStart, phiTotal );
}
@@ -234,26 +266,92 @@ void G4Polyhedra::Create( const G4double phiStart,
G4Polyhedra::~G4Polyhedra()
{
delete [] corners;
if (original_parameters.exist) {
delete [] original_parameters.Z_values;
delete [] original_parameters.Rmin;
delete [] original_parameters.Rmax;
}
if (original_parameters) delete original_parameters;
delete enclosingCylinder;
}
//
// Copy constructor
//
G4Polyhedra::G4Polyhedra( const G4Polyhedra &source ) : G4VCSGfaceted( source )
{
CopyStuff( source );
}
//
// Assignment operator
//
const G4Polyhedra &G4Polyhedra::operator=( const G4Polyhedra &source )
{
if (this == &source) return *this;
G4VCSGfaceted::operator=( source );
delete [] corners;
if (original_parameters) delete original_parameters;
delete enclosingCylinder;
CopyStuff( source );
return *this;
}
//
// CopyStuff
//
void G4Polyhedra::CopyStuff( const G4Polyhedra &source )
{
//
// Simple stuff
//
numSide = source.numSide;
startPhi = source.startPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
numCorner = source.numCorner;
//
// The corner array
//
corners = new G4PolyhedraSideRZ[numCorner];
G4PolyhedraSideRZ *corn = corners,
*sourceCorn = source.corners;
do {
*corn = *sourceCorn;
} while( ++sourceCorn, ++corn < corners+numCorner );
//
// Original parameters
//
if (source.original_parameters) {
original_parameters = new G4PolyhedraHistorical( *source.original_parameters );
}
//
// Enclosing cylinder
//
enclosingCylinder = new G4EnclosingCylinder( *source.enclosingCylinder );
}
//
// Inside
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
EInside G4Polyhedra::Inside( const G4ThreeVector &p ) const
{
//
// Quick test
//
if (enclosingCylinder->Outside(p)) return kOutside;
if (enclosingCylinder->MustBeOutside(p)) return kOutside;
//
// Long answer
@@ -265,12 +363,15 @@ EInside G4Polyhedra::Inside( const G4ThreeVector &p ) const
//
// DistanceToIn
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
G4double G4Polyhedra::DistanceToIn( const G4ThreeVector &p, const G4ThreeVector &v ) const
{
//
// Quick test
//
if (enclosingCylinder->Misses(p,v)) return kInfinity;
if (enclosingCylinder->ShouldMiss(p,v)) return kInfinity;
//
// Long answer
@@ -295,23 +396,20 @@ void G4Polyhedra::ComputeDimensions( G4VPVParameterisation* p,
G4Polyhedron *G4Polyhedra::CreatePolyhedron() const
{
//
// It is *really* unfortunate how the design in /graphics_reps is
// written to parallel the design in /geometry/solids. Ugly, ugly, ugly.
//
// This has to be fixed, but I won't do it now. Fake it for the moment.
// This has to be fixed in visualization. Fake it for the moment.
//
if (original_parameters.exist) {
if (original_parameters) {
return new G4PolyhedronPgon( original_parameters.Start_angle,
original_parameters.Opening_angle,
original_parameters.numSide,
original_parameters.Num_z_planes,
original_parameters.Z_values,
original_parameters.Rmin,
original_parameters.Rmax);
return new G4PolyhedronPgon( original_parameters->Start_angle,
original_parameters->Opening_angle,
original_parameters->numSide,
original_parameters->Num_z_planes,
original_parameters->Z_values,
original_parameters->Rmin,
original_parameters->Rmax);
}
else {
G4Exception( "G4Polyhedra: waiting for graphics_reps to catch up" );
G4cerr << "G4Polyhedra: visualization of this type of G4Polyhedra is not supported at this time" << endl;
return 0;
}
@@ -325,3 +423,36 @@ G4NURBS *G4Polyhedra::CreateNURBS() const
{
return 0;
}
//
// G4Polyhedra::G4PolyhedraHistorical stuff
//
G4Polyhedra::G4PolyhedraHistorical::~G4PolyhedraHistorical()
{
delete [] Z_values;
delete [] Rmin;
delete [] Rmax;
}
G4Polyhedra::G4PolyhedraHistorical::G4PolyhedraHistorical( const G4PolyhedraHistorical &source )
{
Start_angle = source.Start_angle;
Opening_angle = source.Opening_angle;
numSide = source.numSide;
Num_z_planes = source.Num_z_planes;
Z_values = new G4double[Num_z_planes];
Rmin = new G4double[Num_z_planes];
Rmax = new G4double[Num_z_planes];
G4int i;
for( i = 0; i < Num_z_planes; i++) {
Z_values[i] = source.Z_values[i];
Rmin[i] = source.Rmin[i];
Rmax[i] = source.Rmax[i];
}
}
+296 -148
View File
@@ -3,11 +3,20 @@
//
// Implemenation of the face representing one segmented side of a Polyhedra
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4PolyhedraSide.hh"
#include "G4IntersectingCone.hh"
#include "G4ClippablePolygon.hh"
#include "G4AffineTransform.hh"
#include "G4SolidExtentList.hh"
//
// Constructor
@@ -22,7 +31,8 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
const G4int theNumSide,
const G4double thePhiStart,
const G4double thePhiTotal,
const G4bool thePhiIsOpen )
const G4bool thePhiIsOpen,
const G4bool isAllBehind )
{
//
// Record values
@@ -32,20 +42,16 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
G4double phiTotal;
//
// Set phi to our convention
//
startPhi = thePhiStart;
while (startPhi < 0.0) startPhi += 2.0*M_PI;
phiIsOpen = thePhiIsOpen;
if (phiIsOpen) {
phiTotal = thePhiTotal;
startPhi = thePhiStart;
//
// Set phi values to our conventions
//
while (startPhi < 0.0) startPhi += 2.0*M_PI;
}
else {
phiTotal = 2*M_PI;
startPhi = 0;
}
phiTotal = (phiIsOpen) ? thePhiTotal : 2*M_PI;
allBehind = isAllBehind;
//
// Make our intersecting cone
@@ -57,6 +63,7 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
//
numSide = theNumSide;
deltaPhi = phiTotal/theNumSide;
endPhi = startPhi+phiTotal;
vecs = new G4PolyhedraSideVec[numSide];
@@ -179,82 +186,53 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
edge->normal = eNorm.unit();
//
// Vertex normal is average of norms of attached edges
// Vertex normal is average of norms of adjacent surfaces (all four)
// However, vec->edgeNorm is unit vector in some direction
// as the sum of normals of adjacent PolyhedraSide with vec.
// The normalization used for this vector should be the same
// for vec and prev.
//
eNorm = edge->normal + vec->edgeNorm[0] + prev->edgeNorm[0];
eNorm = vec->edgeNorm[0] + prev->edgeNorm[0];
edge->cornNorm[0] = eNorm.unit();
eNorm = edge->normal + vec->edgeNorm[1] + prev->edgeNorm[1];
eNorm = vec->edgeNorm[1] + prev->edgeNorm[1];
edge->cornNorm[1] = eNorm.unit();
} while( prev=vec, ++vec < vecs + numSide );
if (phiIsOpen) {
G4double rFact = cos(0.5*deltaPhi);
//
// If phi is open, we need to patch up the first and last edges
// If phi is open, we need to patch up normals of the
// first and last edges and their corresponding
// vertices.
//
// We use vectors that are in the plane of the
// face. This should be safe.
//
G4double phi1 = startPhi - 0.5*M_PI;
G4ThreeVector phiNorm( cos(phi1), sin(phi1), 0 );
vec = vecs;
//
// Edge normal is average of vec->normal and the normal
// of the face closing the polyhedra in phi
//
G4ThreeVector eNorm = vec->normal + phiNorm;
vec->edges[0]->normal = eNorm.unit();
G4ThreeVector normvec = vec->edges[0]->corner[0] - vec->edges[0]->corner[1];
normvec = normvec.cross(vec->normal);
if (normvec.dot(vec->surfPhi) > 0) normvec = -normvec;
vec->edges[0]->normal = normvec.unit();
vec->edges[0]->cornNorm[0] = (vec->edges[0]->corner[0] - vec->center).unit();
vec->edges[0]->cornNorm[1] = (vec->edges[0]->corner[1] - vec->center).unit();
//
// We need the edge normals (like above) of the adjacent
// G4PolyhedraSides.
// Repeat for ending phi
//
G4double dr = r[0]-prevRZ->r, dz = z[0]-prevRZ->z;
phi1 = startPhi + 0.5*deltaPhi;
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
//
// Average three line normals for the vertex normal
//
eNorm = eNorm.unit() + vec->edges[0]->normal + vec->edgeNorm[0];
vec->edges[0]->cornNorm[0] = eNorm.unit();
//
// Repeat for edgeNorm[1]
//
dr = nextRZ->r-r[1], dz = nextRZ->z-z[1];
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
eNorm = eNorm.unit() + vec->edges[0]->normal + vec->edgeNorm[1];
vec->edges[0]->cornNorm[1] = eNorm.unit();
//
// That was bad...
//
// But, now repeat for ending phi (edge[1])
//
phi1 = startPhi + phiTotal + 0.5*M_PI;
phiNorm = G4ThreeVector( cos(phi1), sin(phi1), 0 );
vec = vecs + numSide - 1;
eNorm = vec->normal + phiNorm;
vec->edges[1]->normal = eNorm.unit();
dr = r[0]-prevRZ->r, dz = z[0]-prevRZ->z;
phi1 = startPhi + phiTotal - 0.5*deltaPhi;
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
eNorm = eNorm.unit() + vec->edges[1]->normal + vec->edgeNorm[0];
vec->edges[1]->cornNorm[0] = eNorm.unit();
dr = nextRZ->r-r[1], dz = nextRZ->z-z[1];
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
eNorm = eNorm.unit() + vec->edges[1]->normal + vec->edgeNorm[1];
vec->edges[1]->cornNorm[1] = eNorm.unit();
//
// Phew! I need a beer!
//
normvec = vec->edges[1]->corner[0] - vec->edges[1]->corner[1];
normvec = normvec.cross(vec->normal);
if (normvec.dot(vec->surfPhi) < 0) normvec = -normvec;
vec->edges[1]->normal = normvec.unit();
vec->edges[1]->cornNorm[0] = (vec->edges[1]->corner[0] - vec->center).unit();
vec->edges[1]->cornNorm[1] = (vec->edges[1]->corner[1] - vec->center).unit();
}
//
@@ -277,6 +255,85 @@ G4PolyhedraSide::~G4PolyhedraSide()
}
//
// Copy constructor
//
G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSide &source )
{
CopyStuff( source );
}
//
// Assignment operator
//
G4PolyhedraSide *G4PolyhedraSide::operator=( const G4PolyhedraSide &source )
{
if (this == &source) return this;
delete cone;
delete [] vecs;
delete [] edges;
CopyStuff( source );
return this;
}
//
// CopyStuff
//
void G4PolyhedraSide::CopyStuff( const G4PolyhedraSide &source )
{
//
// The simple stuff
//
numSide = source.numSide;
r[0] = source.r[0];
r[1] = source.r[1];
z[0] = source.z[0];
z[1] = source.z[1];
startPhi = source.startPhi;
deltaPhi = source.deltaPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
allBehind = source.allBehind;
lenRZ = source.lenRZ;
lenPhi[0] = source.lenPhi[0];
lenPhi[1] = source.lenPhi[1];
edgeNorm = source.edgeNorm;
cone = new G4IntersectingCone( *source.cone );
//
// Duplicate edges
//
G4int numEdges = phiIsOpen ? numSide+1 : numSide;
edges = new G4PolyhedraSideEdge[numEdges];
G4PolyhedraSideEdge *edge = edges,
*sourceEdge = source.edges;
do {
*edge = *sourceEdge;
} while( ++sourceEdge, ++edge < edges + numEdges);
//
// Duplicate vecs
//
vecs = new G4PolyhedraSideVec[numSide];
G4PolyhedraSideVec *vec = vecs,
*sourceVec = source.vecs;
do {
*vec = *sourceVec;
vec->edges[0] = edges + (sourceVec->edges[0] - source.edges);
vec->edges[1] = edges + (sourceVec->edges[1] - source.edges);
} while( ++sourceVec, ++vec < vecs + numSide );
}
//
// Intersect
//
@@ -287,7 +344,7 @@ G4PolyhedraSide::~G4PolyhedraSide()
// v = (in) direction of line segment (assumed a unit vector)
// A, B = (in) 2d transform variables (see note top of file)
// normSign = (in) desired sign for dot product with normal (see below)
// surfTolerance = (in) minimum distance from the surface (can be < 0, see below)
// surfTolerance = (in) minimum distance from the surface
// vecs = (in) Vector set array
// distance = (out) distance to surface furfilling all requirements
// distFromSurface = (out) distance from the surface
@@ -306,67 +363,121 @@ G4PolyhedraSide::~G4PolyhedraSide()
// we are outside and want to go in, normSign should be set to -1.0.
// Don't set normSign to zero, or you will get no intersections!
//
// * surfTolerance: see notes on argument "surfTolerance" in routine "IntersectSide".
// * surfTolerance: see notes on argument "surfTolerance" in routine "IntersectSidePlane".
// ----HOWEVER---- We should *not* apply this surface tolerance if the starting
// point is not within phi or z of the surface. Specifically, if the starting
// point p angle in x/y places it on a separate side from the intersection or
// if the starting point p is outside the z bounds of the segment, surfTolerance
// must be ignored are we should *always* accept the intersection!
// must be ignored or we should *always* accept the intersection!
// This is simply because the sides do not have infinite extent.
//
//
G4bool G4PolyhedraSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &normal, G4bool &allBehind )
G4ThreeVector &normal, G4bool &isAllBehind )
{
G4int nside, i1, i2, iStart;
G4double normSign = outgoing ? +1 : -1;
allBehind = true; // this is always true for this face
//
// ------------------TO BE IMPLEMENTED---------------------
// Testing the intersection of individual phi faces is
// pretty straight forward. The simple thing therefore is to
// form a loop and check them all in sequence.
//
// But, I worry about one day someone making
// a polygon with a thousands sides. A linear search
// would not be ideal in such a case.
//
// So, it would be nice to be able to quickly decide
// which face would be intersected. One can make a very
// good guess by using the intersection with a cone.
// However, this is only reliable in 99% of the cases.
//
// My solution: make a decent guess as to the one or
// two potential faces might get intersected, and then
// test them. If we have the wrong face, use the test
// to make a better guess.
//
// Since we might have two guesses, form a queue of
// potential intersecting faces. Keep an array of
// already tested faces to avoid doing one more than
// once.
//
// Result: at worst, an iterative search. On average,
// a little more than two tests would be required.
//
G4ThreeVector q = p + v;
G4int face = 0;
G4PolyhedraSideVec *vec = vecs;
do {
//
// Correct normal?
//
G4double dotProd = normSign*v.dot(vec->normal);
if (dotProd <= 0) continue;
//
// Is this face in front of the point along the trajectory?
//
G4ThreeVector delta = p - vec->center;
distFromSurface = -normSign*delta.dot(vec->normal);
if (distFromSurface < -surfTolerance) continue;
//
// phi
// c -------- d ^
// | | |
// a -------- b +---> r/z
//
//
// Do we remain on this particular segment?
//
G4ThreeVector qc = q - vec->edges[1]->corner[0];
G4ThreeVector qd = q - vec->edges[1]->corner[1];
if (normSign*qc.cross(qd).dot(v) < 0) continue;
G4ThreeVector qa = q - vec->edges[0]->corner[0];
G4ThreeVector qb = q - vec->edges[0]->corner[1];
if (normSign*qa.cross(qb).dot(v) > 0) continue;
//
// We found the one and only segment we might be intersecting.
// Do we remain within r/z bounds?
//
if (normSign*qa.cross(qc).dot(v) < 0) return false;
if (normSign*qb.cross(qd).dot(v) > 0) return false;
//
// We allow the face to be slightly behind the trajectory
// (surface tolerance) only if the point p is within
// the vicinity of the face
//
if (distFromSurface < 0) {
G4ThreeVector ps = p - vec->center;
G4double rz = ps.dot(vec->surfRZ);
if (fabs(rz) > lenRZ+surfTolerance) return false;
//
// Is the starting point outside z bounds?
//
iStart = (p.z() < cone->ZLo() || p.z() > cone->ZHi()) ? -1 : 0;
if (iStart==0) {
//
// Which phi segment does the starting point p belong to?
//
iStart = PhiSegment( p.phi() );
}
//
// Check for two possible intersections
//
nside = LineHitsSegments( p, v, &i1, &i2 );
if (nside==0) return false;
//
// Try the first side first. LineHitsSegments is suppose to return
// the nearest intersection first. If this succeeds, we are done.
//
if (IntersectSidePlane( p, v, vecs[i1], normSign,
(i1 == iStart) ? surfTolerance : 0,
distance, distFromSurface )) {
normal = vecs[i1].normal;
return true;
}
if (nside==2) {
//
// No luck? Well, we have the second side
//
if (IntersectSidePlane( p, v, vecs[i2], normSign,
(i2 == iStart) ? surfTolerance : 0,
distance, distFromSurface )) {
normal = vecs[i2].normal;
return true;
G4double pp = ps.dot(vec->surfPhi);
if (fabs(pp) > lenPhi[0] + lenPhi[1]*rz + surfTolerance) return false;
}
}
//
// Intersection found. Return answer.
//
distance = distFromSurface/dotProd;
normal = vec->normal;
isAllBehind = allBehind;
return true;
} while( ++vec, ++face < numSide );
//
// Oh well. Better luck next time.
//
@@ -386,7 +497,7 @@ G4double G4PolyhedraSide::Distance( const G4ThreeVector &p, const G4bool outgoin
G4ThreeVector pdotc = p - vecs[iPhi].center;
G4double normDist = pdotc.dot(vecs[iPhi].normal);
if (normSign*normDist > 0) {
if (normSign*normDist > -0.5*kCarTolerance) {
return DistanceAway( p, vecs[iPhi], &normDist );
}
@@ -448,7 +559,7 @@ G4ThreeVector G4PolyhedraSide::Normal( const G4ThreeVector &p, G4double *bestDi
//
G4double G4PolyhedraSide::Extent( const G4ThreeVector axis )
{
if (axis.perp2() < 1.0/kInfinity) {
if (axis.perp2() < DBL_MIN) {
//
// Special case
//
@@ -505,10 +616,8 @@ G4double G4PolyhedraSide::Extent( const G4ThreeVector axis )
void G4PolyhedraSide::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max )
G4SolidExtentList &extentList )
{
G4ClippablePolygon polygon;
//
// Loop over all sides
//
@@ -518,7 +627,7 @@ void G4PolyhedraSide::CalculateExtent( const EAxis axis,
// Fill our polygon with the four corners of
// this side, after the specified transformation
//
polygon.ClearAllVertices();
G4ClippablePolygon polygon;
polygon.AddVertexInOrder( transform.TransformPoint( vec->edges[0]->corner[0] ) );
polygon.AddVertexInOrder( transform.TransformPoint( vec->edges[0]->corner[1] ) );
@@ -528,9 +637,17 @@ void G4PolyhedraSide::CalculateExtent( const EAxis axis,
//
// Get extent
//
polygon.Clip( voxelLimit );
polygon.GetExtent( axis, min, max );
if (polygon.PartialClip( voxelLimit, axis )) {
//
// Get dot product of normal along target axis
//
polygon.SetNormal( transform.TransformAxis(vec->normal) );
extentList.AddSurface( polygon );
}
} while( ++vec < vecs+numSide );
return;
}
@@ -548,6 +665,21 @@ void G4PolyhedraSide::CalculateExtent( const EAxis axis,
// = +1.0 normal is unchanged
// = -1.0 normal is reversed (now points inward)
//
// Arguments:
// p - (in) Point
// v - (in) Direction
// vec - (in) Description record of the side plane
// normSign - (in) Sign (+/- 1) to apply to normal
// surfTolerance - (in) Surface tolerance (generally > 0, see below)
// distance - (out) Distance along v to intersection
// distFromSurface - (out) Distance from surface normal
//
// Notes:
// surfTolerance - Used to decide if a point is behind the surface,
// a point is allow to be -surfTolerance behind the
// surface (as measured along the normal), but *only*
// if the point is within the r/z bounds + surfTolerance
// of the segment.
//
G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4ThreeVector &v,
const G4PolyhedraSideVec vec,
@@ -570,7 +702,7 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
G4ThreeVector delta = p - vec.center;
distFromSurface = -normSign*delta.dot(vec.normal);
if (distFromSurface < surfTolerance) return false;
if (distFromSurface < -surfTolerance) return false;
//
// Calculate precise distance to intersection with the side
@@ -595,6 +727,7 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
//
G4ThreeVector ic = p + distance*v - vec.center;
G4double atRZ = vec.surfRZ.dot(ic);
if (atRZ < 0) {
if (r[0]==0) return true; // Can't miss!
@@ -605,6 +738,10 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
qb = q - vec.edges[1]->corner[0];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) < 0) return false;
if (distFromSurface < 0) {
if (atRZ < -lenRZ-surfTolerance) return false;
}
}
else if (atRZ > 0) {
if (r[1]==0) return true; // Can't miss!
@@ -616,6 +753,10 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
qb = q - vec.edges[1]->corner[1];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) >= 0) return false;
if (distFromSurface < 0) {
if (atRZ > lenRZ+surfTolerance) return false;
}
}
return true;
@@ -625,7 +766,7 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
//
// LineHitsSegments
//
// Calculate which phi segments a line intersections in three dimensions.
// Calculate which phi segments a line intersects in three dimensions.
// No check is made as to whether the intersections are within the z bounds of
// the segment.
//
@@ -638,16 +779,19 @@ G4int G4PolyhedraSide::LineHitsSegments( const G4ThreeVector &p, const G4ThreeVe
//
G4int n = cone->LineHitsCone( p, v, &s1, &s2 );
//
// Check intersections
//
if (n==0) return 0;
//
// Try first intersection.
//
*i1 = PhiSegment( atan2( p.y() + s1*v.y(), p.x() + s1*v.x() ) );
if (n==1) {
return (*i1 < 0) ? 0 : 1;
}
//
// Try second intersection
//
*i2 = PhiSegment( atan2( p.y() + s2*v.y(), p.x() + s2*v.x() ) );
if (*i1 == *i2) return 0;
@@ -681,7 +825,7 @@ G4int G4PolyhedraSide::ClosestPhiSegment( const G4double phi0 )
G4double phi = phi0;
while( phi < startPhi ) phi += 2*M_PI;
G4double d1 = phi-startPhi-deltaPhi;
G4double d1 = phi-endPhi;
while( phi > startPhi ) phi -= 2*M_PI;
G4double d2 = startPhi-phi;
@@ -725,8 +869,6 @@ G4int G4PolyhedraSide::PhiSegment( const G4double phi0 )
}
//
// DistanceToOneSide
//
@@ -737,7 +879,7 @@ G4int G4PolyhedraSide::PhiSegment( const G4double phi0 )
// Return value = total distance from the side
//
G4double G4PolyhedraSide::DistanceToOneSide( const G4ThreeVector &p,
const G4PolyhedraSideVec vec,
const G4PolyhedraSideVec &vec,
G4double *normDist )
{
G4ThreeVector pc = p - vec.center;
@@ -761,7 +903,7 @@ G4double G4PolyhedraSide::DistanceToOneSide( const G4ThreeVector &p,
// and updates normDist appropriate depending on edge normals.
//
G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
const G4PolyhedraSideVec vec,
const G4PolyhedraSideVec &vec,
G4double *normDist )
{
G4double distOut2;
@@ -796,15 +938,14 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
// Below in RZ
//
*normDist = pc.dot(vec.edgeNorm[0]);
if (pcDotPhi < -lenPhiZ) {
//
// ...and below in phi. Find distance to point (A)
//
G4double distOutPhi = pcDotPhi+lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[0]->cornNorm[0]);
G4ThreeVector pa = p - vec.edges[0]->corner[0];
*normDist = pa.dot(vec.edges[0]->cornNorm[0]);
}
else if (pcDotPhi > lenPhiZ) {
//
@@ -812,14 +953,16 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOutPhi = pcDotPhi-lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[1]->cornNorm[0]);
G4ThreeVector pb = p - vec.edges[1]->corner[0];
*normDist = pb.dot(vec.edges[1]->cornNorm[0]);
}
else {
//
// ...and inside in phi. Find distance to line (C)
//
G4ThreeVector pa = p - vec.edges[0]->corner[0];
distOut2 = distOutZ*distOutZ;
*normDist = pc.dot(vec.edgeNorm[0]);
*normDist = pa.dot(vec.edgeNorm[0]);
}
}
else if (pcDotRZ > lenRZ) {
@@ -834,7 +977,8 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOutPhi = pcDotPhi+lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[0]->cornNorm[1]);
G4ThreeVector pd = p - vec.edges[0]->corner[1];
*normDist = pd.dot(vec.edges[0]->cornNorm[1]);
}
else if (pcDotPhi > lenPhiZ) {
//
@@ -842,14 +986,16 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOutPhi = pcDotPhi-lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[1]->cornNorm[1]);
G4ThreeVector pe = p - vec.edges[1]->corner[1];
*normDist = pe.dot(vec.edges[1]->cornNorm[1]);
}
else {
//
// ...and inside in phi. Find distance to line (F)
//
distOut2 = distOutZ*distOutZ;
*normDist = pc.dot(vec.edgeNorm[1]);
G4ThreeVector pd = p - vec.edges[0]->corner[1];
*normDist = pd.dot(vec.edgeNorm[1]);
}
}
else {
@@ -863,7 +1009,8 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOut = edgeNorm*(pcDotPhi+lenPhiZ);
distOut2 = distOut*distOut;
*normDist = pc.dot(vec.edges[0]->normal);
G4ThreeVector pd = p - vec.edges[0]->corner[1];
*normDist = pd.dot(vec.edges[0]->normal);
}
else if (pcDotPhi > lenPhiZ) {
//
@@ -871,7 +1018,8 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOut = edgeNorm*(pcDotPhi-lenPhiZ);
distOut2 = distOut*distOut;
*normDist = pc.dot(vec.edges[1]->normal);
G4ThreeVector pe = p - vec.edges[1]->corner[1];
*normDist = pe.dot(vec.edges[1]->normal);
}
else {
//
@@ -0,0 +1,462 @@
//
// G4ReduciblePolygon.cc
//
// Implementation of a utility class used to specify, test, reduce,
// and/or otherwise manipulate a 2D polygon.
//
// See G4ReduciblePolygon.hh for more info.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4ReduciblePolygon.hh"
#include "math.h"
//
// Constructor: with simple arrays
//
G4ReduciblePolygon::G4ReduciblePolygon( const G4double a[], const G4double b[], const G4int n )
{
//
// Do all of the real work in Create
//
Create( a, b, n );
}
//
// Constructor: special PGON/PCON case
//
G4ReduciblePolygon::G4ReduciblePolygon( const G4double rmin[], const G4double rmax[],
const G4double z[], const G4int n )
{
//
// Translate
//
G4double *a = new G4double[n*2];
G4double *b = new G4double[n*2];
G4double *rOut = a + n,
*zOut = b + n,
*rIn = rOut-1,
*zIn = zOut-1;
G4int i;
for( i=0; i < n; i++, rOut++, zOut++, rIn--, zIn-- ) {
*rOut = rmax[i];
*rIn = rmin[i];
*zOut = *zIn = z[i];
}
Create( a, b, n*2 );
delete [] a;
delete [] b;
}
//
// Create
//
// To be called by constructors, fill in the list and statistics for a new
// polygon
//
void G4ReduciblePolygon::Create( const G4double a[], const G4double b[], const G4int n )
{
if (n<3) G4Exception( "G4ReduciblePolygon: less than 3 vertices specified" );
const G4double *anext = a, *bnext = b;
ABVertex *prev = 0;
do {
ABVertex *newVertex = new ABVertex;
newVertex->a = *anext;
newVertex->b = *bnext;
newVertex->next = 0;
if (prev==0) {
vertexHead = newVertex;
}
else {
prev->next = newVertex;
}
prev = newVertex;
} while( ++anext, ++bnext < b+n );
numVertices = n;
CalculateMaxMin();
}
//
// Destructor
//
G4ReduciblePolygon::~G4ReduciblePolygon()
{
ABVertex *curr = vertexHead;
while( curr ) {
ABVertex *toDelete = curr;
curr = curr->next;
delete toDelete;
}
}
//
// CopyVertices
//
// Copy contents into simple linear arrays.
// ***** CAUTION ***** Be care to declare the arrays to a large
// enough size!
//
void G4ReduciblePolygon::CopyVertices( G4double a[], G4double b[] ) const
{
G4double *anext = a, *bnext = b;
ABVertex *curr = vertexHead;
while( curr ) {
*anext++ = curr->a;
*bnext++ = curr->b;
curr = curr->next;
}
}
//
// ScaleA
//
// Multiply all a values by a common scale
//
void G4ReduciblePolygon::ScaleA( const G4double scale )
{
ABVertex *curr = vertexHead;
while( curr ) {
curr->a *= scale;
curr = curr->next;
}
}
//
// ScaleB
//
// Multiply all b values by a common scale
//
void G4ReduciblePolygon::ScaleB( const G4double scale )
{
ABVertex *curr = vertexHead;
while( curr ) {
curr->b *= scale;
curr = curr->next;
}
}
//
// RemoveDuplicateVertices
//
// Remove adjacent vertices that are equal. Returns "false" if there
// is a problem (too few vertices remaining).
//
G4bool G4ReduciblePolygon::RemoveDuplicateVertices( const G4double tolerance )
{
ABVertex *curr = vertexHead,
*prev = 0,
*next = curr->next; // A little dangerous
while( curr ) {
next = curr->next;
if (next == 0) next = vertexHead;
if (fabs(curr->a-next->a) < tolerance &&
fabs(curr->b-next->b) < tolerance ) {
//
// Duplicate found: do we have > 3 vertices?
//
if (numVertices <= 3) {
CalculateMaxMin();
return false;
}
//
// Delete
//
ABVertex *toDelete = curr;
curr = curr->next;
delete toDelete;
numVertices--;
if (prev) prev->next = curr; else vertexHead = curr;
}
else {
prev = curr;
curr = curr->next;
}
}
//
// In principle, this is not needed, but why not just play it safe?
//
CalculateMaxMin();
return true;
}
//
// RemoveRedundantVertices
//
// Remove any unneeded vertices, i.e. those vertices which
// are on the line connecting the previous and next vertices.
//
G4bool G4ReduciblePolygon::RemoveRedundantVertices( const G4double tolerance )
{
//
// Under these circumstances, we can quit now!
//
if (numVertices <= 2) return false;
G4double tolerance2 = tolerance*tolerance;
//
// Loop over all vertices
//
ABVertex *curr = vertexHead,
*prev = 0,
*next = curr->next; // A little dangerous
while( curr ) {
next = curr->next;
if (next == 0) next = vertexHead;
G4double da = next->a - curr->a,
db = next->b - curr->b;
//
// Loop over all subsequent vertices, up to curr
//
for(;;) {
//
// Get vertex after next
//
ABVertex *test = next->next;
if (test == 0) test = vertexHead;
//
// If we are back to the original vertex, stop
//
if (test==curr) break;
//
// Test for parallel line segments
//
G4double dat = test->a - curr->a,
dbt = test->b - curr->b;
if (fabs(dat*db-dbt*da)>tolerance2) break;
//
// Redundant vertex found: do we have > 3 vertices?
//
if (numVertices <= 3) {
CalculateMaxMin();
return false;
}
//
// Delete vertex pointed to by next. Carefully!
//
if (curr->next) { // next is not head
if (next->next)
curr->next = test; // next is not tail
else
curr->next = 0; // New tail
}
else
vertexHead = test; // New head
delete next;
numVertices--;
//
// Replace next by the vertex we just tested,
// and keep on going...
//
next = test;
da = dat; db = dbt;
}
curr = curr->next;
}
//
// In principle, this is not needed, but why not just play it safe?
//
CalculateMaxMin();
return true;
}
//
// CrossesItself
//
// Return "true" if the polygon crosses itself
//
// Warning: this routine is not very fast (runs as N**2)
//
G4bool G4ReduciblePolygon::CrossesItself( const G4double tolerance )
{
G4double tolerance2 = tolerance*tolerance;
G4double one = 1.0-tolerance,
zero = tolerance;
//
// Top loop over line segments. By the time we finish
// with the second to last segment, we're done.
//
ABVertex *curr1 = vertexHead, *next1;
while (next1 = curr1->next) {
G4double da1 = next1->a-curr1->a,
db1 = next1->b-curr1->b;
//
// Inner loop over subsequent line segments
//
ABVertex *curr2 = next1->next;
while( curr2 ) {
ABVertex *next2 = curr2->next;
if (next2==0) next2 = vertexHead;
G4double da2 = next2->a-curr2->a,
db2 = next2->b-curr2->b;
G4double a12 = curr2->a-curr1->a,
b12 = curr2->b-curr1->b;
//
// Calculate intersection of the two lines
//
G4double deter = da1*db2 - db1*da2;
if (fabs(deter) > tolerance2) {
G4double s1, s2;
s1 = (a12*db2-b12*da2)/deter;
if (s1 >= zero && s1 < one) {
s2 = -(da1*b12-db1*a12)/deter;
if (s2 >= zero && s2 < one) return true;
}
}
curr2 = curr2->next;
}
curr1 = next1;
}
return false;
}
//
// BisectedBy
//
// Decide if a line through two points crosses the polygon, within tolerance
//
G4bool G4ReduciblePolygon::BisectedBy( const G4double a1, const G4double b1,
const G4double a2, const G4double b2, const G4double tolerance )
{
G4int nNeg = 0, nPos = 0;
G4double a12 = a2-a1, b12 = b2-b1;
G4double len12 = sqrt( a12*a12 + b12*b12 );
a12 /= len12; b12 /= len12;
ABVertex *curr = vertexHead;
do {
G4double av = curr->a - a1,
bv = curr->b - b1;
G4double cross = av*b12 - bv*a12;
if (cross < -tolerance) {
if (nPos) return true;
nNeg++;
}
else if (cross > tolerance) {
if (nNeg) return true;
nPos++;
}
} while( curr = curr->next );
return false;
}
//
// Area
//
// Calculated signed polygon area, where polygons specified in a clockwise manner
// (where x==a, y==b) have negative area
//
// References: [O' Rourke (C)] pp. 18-27; [Gems II] pp. 5-6:
// "The Area of a Simple Polygon", Jon Rokne.
//
G4double G4ReduciblePolygon::Area()
{
G4double answer = 0;
ABVertex *curr = vertexHead, *next;
do {
next = curr->next;
if (next==0) next = vertexHead;
answer += curr->a*next->b - curr->b*next->a;
} while( curr = curr->next );
return 0.5*answer;
}
//
// Print
//
void G4ReduciblePolygon::Print()
{
ABVertex *curr = vertexHead;
do {
G4cerr << curr->a << " " << curr->b << endl;
} while( curr = curr->next );
}
//
// CalculateMaxMin
//
// To be called when the vertices are changed, this
// routine re-calculates global values
//
void G4ReduciblePolygon::CalculateMaxMin()
{
ABVertex *curr = vertexHead;
aMin = aMax = curr->a;
bMin = bMax = curr->b;
curr = curr->next;
while( curr ) {
if (curr->a < aMin)
aMin = curr->a;
else if (curr->a > aMax)
aMax = curr->a;
if (curr->b < bMin)
bMin = curr->b;
else if (curr->b > bMax)
bMax = curr->b;
curr = curr->next;
}
}
@@ -0,0 +1,156 @@
//
// G4SolidExtentList.cc
//
// Implementation of a list of (voxel) extents along one axis
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4SolidExtentList.hh"
#include "G4VoxelLimits.hh"
//
// Constructor (default)
//
G4SolidExtentList::G4SolidExtentList()
{
axis = kZAxis;
limited = false;
minLimit = -DBL_MAX;
maxLimit = +DBL_MAX;
}
//
// Constructor (limited case)
//
G4SolidExtentList::G4SolidExtentList( const EAxis targetAxis, const G4VoxelLimits &voxelLimits )
{
axis = targetAxis;
limited = voxelLimits.IsLimited( axis );
if (limited) {
minLimit = voxelLimits.GetMinExtent( axis );
maxLimit = voxelLimits.GetMaxExtent( axis );
}
else {
minLimit = -DBL_MAX;
maxLimit = +DBL_MAX;
}
}
//
// Destructor
//
G4SolidExtentList::~G4SolidExtentList() {;}
//
// AddSurface
//
//
void G4SolidExtentList::AddSurface( const G4ClippablePolygon &surface )
{
//
// Keep track of four surfaces
//
G4double min, max;
surface.GetExtent( axis, min, max );
if (min > maxLimit) {
//
// Nearest surface beyond maximum limit
//
if (surface.InFrontOf(minAbove,axis)) minAbove = surface;
}
else if (max < minLimit) {
//
// Nearest surface below minimum limit
//
if (surface.BehindOf(maxBelow,axis)) maxBelow = surface;
}
else {
//
// Max and min surfaces inside
//
if (surface.BehindOf(maxSurface,axis)) maxSurface = surface;
if (surface.InFrontOf(minSurface,axis)) minSurface = surface;
}
}
//
// GetExtent
//
// Return extent after processing all surfaces
//
G4bool G4SolidExtentList::GetExtent( G4double &min, G4double &max ) const
{
//
// Did we have any surfaces within the limits?
//
if (minSurface.Empty()) {
//
// Nothing! Do we have anything above?
//
if (minAbove.Empty()) return false;
//
// Yup. Is it facing inwards?
//
if (minAbove.GetNormal().operator()(axis) < 0) return false;
//
// No. We must be entirely within the solid
//
max = maxLimit + kCarTolerance;
min = minLimit - kCarTolerance;
return true;
}
//
// Check max surface
//
if (maxSurface.GetNormal().operator()(axis) < 0) {
//
// Inward facing: max limit must be embedded within solid
//
max = maxLimit + kCarTolerance;
}
else {
G4double sMin, sMax;
maxSurface.GetExtent( axis, sMin, sMax );
max = ( (sMax > maxLimit) ? maxLimit : sMax ) + kCarTolerance;
}
//
// Check min surface
//
if (minSurface.GetNormal().operator()(axis) > 0) {
//
// Inward facing: max limit must be embedded within solid
//
min = minLimit - kCarTolerance;
}
else {
G4double sMin, sMax;
minSurface.GetExtent( axis, sMin, sMax );
min = ( (sMin < minLimit) ? minLimit : sMin ) - kCarTolerance;
}
return true;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Sphere.cc,v 2.5 1998/11/25 15:01:12 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Sphere.cc,v 1.2 1999/04/16 09:29:55 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Sphere
//
@@ -158,8 +158,8 @@ G4bool G4Sphere::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fRmax;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -181,8 +181,8 @@ G4bool G4Sphere::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fRmax;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -205,8 +205,8 @@ G4bool G4Sphere::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fRmax;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Torus.cc,v 2.3 1998/10/12 14:43:11 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Torus.cc,v 1.2 1999/04/16 09:29:55 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Torus
@@ -471,8 +471,8 @@ G4bool G4Torus::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fRmax+fRtor;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -494,8 +494,8 @@ G4bool G4Torus::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fRmax+fRtor;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -518,8 +518,8 @@ G4bool G4Torus::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fRmax;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
+120 -46
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Trap.cc,v 2.1 1998/07/12 02:56:59 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Trap.cc,v 1.3 1999/06/04 17:19:16 sgiani Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Trap
//
@@ -17,6 +17,7 @@
// 9.9.96 V. Grichine: Final modifications before to commit
// 1.11.96 V.Grichine Costructors for Right Angular Wedge from STEP & G4Trd/Para
// 8.12.97 J.Allison Added "nominal" constructor and method SetAllParameters.
// 4.6.99 S.Giani: Fixed CalculateExtent in rotated case.
#include <math.h>
#include "G4Trap.hh"
@@ -490,19 +491,19 @@ G4bool G4Trap::MakePlane( const G4ThreeVector& p1,
// a,b,c correspond to the x/y/z components of the normal vector to the plane
// a=(p2.y()-p1.y())*(p1.z()+p2.z())+(p3.y()-p2.y())*(p2.z()+p3.z());
// a+=(p4.y()-p3.y())*(p3.z()+p4.z())+(p1.y()-p4.y())*(p4.z()+p1.z()); // may be delete ?
a=(p2.y()-p1.y())*(p1.z()+p2.z())+(p3.y()-p2.y())*(p2.z()+p3.z());
a+=(p4.y()-p3.y())*(p3.z()+p4.z())+(p1.y()-p4.y())*(p4.z()+p1.z()); // may be delete ?
// b=(p2.z()-p1.z())*(p1.x()+p2.x())+(p3.z()-p2.z())*(p2.x()+p3.x());
// b+=(p4.z()-p3.z())*(p3.x()+p4.x())+(p1.z()-p4.z())*(p4.x()+p1.x()); // ?
b=(p2.z()-p1.z())*(p1.x()+p2.x())+(p3.z()-p2.z())*(p2.x()+p3.x());
b+=(p4.z()-p3.z())*(p3.x()+p4.x())+(p1.z()-p4.z())*(p4.x()+p1.x()); // ?
// c=(p2.x()-p1.x())*(p1.y()+p2.y())+(p3.x()-p2.x())*(p2.y()+p3.y());
// c+=(p4.x()-p3.x())*(p3.y()+p4.y())+(p1.x()-p4.x())*(p4.y()+p1.y()); // ?
c=(p2.x()-p1.x())*(p1.y()+p2.y())+(p3.x()-p2.x())*(p2.y()+p3.y());
c+=(p4.x()-p3.x())*(p3.y()+p4.y())+(p1.x()-p4.x())*(p4.y()+p1.y()); // ?
// Let create diagonals 4-2 and 3-1 than (4-2)x(3-1) provides vector perpendicular to the
// plane directed to outside !!! and a,b,c, = f(1,2,3,4)
a = +(p4.y() - p2.y())*(p3.z() - p1.z()) - (p3.y() - p1.y())*(p4.z() - p2.z()) ;
b = -(p4.x() - p2.x())*(p3.z() - p1.z()) + (p3.x() - p1.x())*(p4.z() - p2.z()) ;
c = +(p4.x() - p2.x())*(p3.y() - p1.y()) - (p3.x() - p1.x())*(p4.y() - p2.y()) ;
//a = +(p4.y() - p2.y())*(p3.z() - p1.z()) - (p3.y() - p1.y())*(p4.z() - p2.z()) ;
//b = -(p4.x() - p2.x())*(p3.z() - p1.z()) + (p3.x() - p1.x())*(p4.z() - p2.z()) ;
//c = +(p4.x() - p2.x())*(p3.y() - p1.y()) - (p3.x() - p1.x())*(p4.y() - p2.y()) ;
s=sqrt(a*a+b*b+c*c); // so now vector plane.(a,b,c) is unit
plane.a=a/s;
plane.b=b/s;
@@ -538,6 +539,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
const G4AffineTransform& pTransform,
G4double& pMin, G4double& pMax) const
{
G4double xMin, xMax, yMin, yMax, zMin, zMax;
G4bool flag;
if (!pTransform.IsRotated())
@@ -546,9 +549,9 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
// Compute z/x/y/ mins and maxs respecting limits, with early returns
// if outside limits. Then switch() on pAxis
G4int i ;
G4double xoffset,xMin,xMax;
G4double yoffset,yMin,yMax;
G4double zoffset,zMin,zMax;
G4double xoffset;
G4double yoffset;
G4double zoffset;
G4double temp[8] ; // some points for intersection with zMin/zMax
xoffset=pTransform.NetTranslation().x();
@@ -576,8 +579,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -608,8 +611,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -645,8 +648,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
// xMax/Min = f(yMax/Min) ?
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -686,48 +689,119 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
}
else
{
// General rotated case - create and clip mesh to boundaries
// General rotated case -
G4bool existsAfterClip=false;
G4ThreeVectorList *vertices;
pMin=+kInfinity;
pMax=-kInfinity;
// Calculate rotated vertex coordinates
vertices=CreateRotatedVertices(pTransform);
ClipCrossSection(vertices,0,pVoxelLimit,pAxis,pMin,pMax);
ClipCrossSection(vertices,4,pVoxelLimit,pAxis,pMin,pMax);
ClipBetweenSections(vertices,0,pVoxelLimit,pAxis,pMin,pMax);
xMin = +kInfinity; yMin = +kInfinity; zMin = +kInfinity;
xMax = -kInfinity; yMax = -kInfinity; zMax = -kInfinity;
for(G4int nv=0; nv<8; nv++){
if((*vertices)[nv].x() > xMax){xMax = (*vertices)[nv].x();};
if((*vertices)[nv].y() > yMax){yMax = (*vertices)[nv].y();};
if((*vertices)[nv].z() > zMax){zMax = (*vertices)[nv].z();};
if((*vertices)[nv].x() < xMin){xMin = (*vertices)[nv].x();};
if((*vertices)[nv].y() < yMin){yMin = (*vertices)[nv].y();};
if((*vertices)[nv].z() < zMin){zMin = (*vertices)[nv].z();};
};
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
else
{
if (zMin<pVoxelLimit.GetMinZExtent())
{
zMin=pVoxelLimit.GetMinZExtent();
}
if (zMax>pVoxelLimit.GetMaxZExtent())
{
zMax=pVoxelLimit.GetMaxZExtent();
}
}
}
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
else
{
if (yMin<pVoxelLimit.GetMinYExtent())
{
yMin=pVoxelLimit.GetMinYExtent();
}
if (yMax>pVoxelLimit.GetMaxYExtent())
{
yMax=pVoxelLimit.GetMaxYExtent();
}
}
}
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
else
{
if (xMin<pVoxelLimit.GetMinXExtent())
{
xMin=pVoxelLimit.GetMinXExtent();
}
if (xMax>pVoxelLimit.GetMaxXExtent())
{
xMax=pVoxelLimit.GetMaxXExtent();
}
}
}
switch (pAxis)
{
case kXAxis:
pMin=xMin;
pMax=xMax;
break;
case kYAxis:
pMin=yMin;
pMax=yMax;
break;
case kZAxis:
pMin=zMin;
pMax=zMax;
break;
}
if (pMin!=kInfinity||pMax!=-kInfinity)
{
existsAfterClip=true;
// Add 2*tolerance to avoid precision troubles
// Add tolerance to avoid precision troubles
pMin-=kCarTolerance;
pMax+=kCarTolerance;
}
else
{
// Check for case where completely enveloping clipping volume
// If point inside then we are confident that the solid completely
// envelopes the clipping volume. Hence set min/max extents according
// to clipping volume extents along the specified axis.
G4ThreeVector clipCentre(
(pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5,
(pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5,
(pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5);
if (Inside(pTransform.Inverse().TransformPoint(clipCentre))!=kOutside)
{
existsAfterClip=true;
pMin=pVoxelLimit.GetMinExtent(pAxis);
pMax=pVoxelLimit.GetMaxExtent(pAxis);
}
}
};
delete vertices ; // 'new' in the function called
flag = existsAfterClip ;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Trd.cc,v 2.1 1998/07/12 02:57:00 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Trd.cc,v 1.2 1999/04/16 09:29:56 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// Implementation for G4Trd class
@@ -118,8 +118,8 @@ G4bool G4Trd::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -150,8 +150,8 @@ G4bool G4Trd::CalculateExtent(const EAxis pAxis,
}
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -182,8 +182,8 @@ G4bool G4Trd::CalculateExtent(const EAxis pAxis,
}
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
+10 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Tubs.cc,v 2.3 1998/10/09 17:17:21 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Tubs.cc,v 1.7 1999/06/04 12:43:35 japost Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Tubs
@@ -14,6 +14,7 @@
// Implementation
// 18.06.98 n-normalisation in DistanceToOut(p.v) V. Grichine
// 09.10.98 V. Grichine modifications in Distance ToOut(p,v,...)
// 23.03.99 V.Grichine, bug fixed in DistanceToIn(p,v)
#include "G4Tubs.hh"
@@ -137,8 +138,8 @@ G4bool G4Tubs::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fRMax;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -160,8 +161,8 @@ G4bool G4Tubs::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fRMax;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -184,8 +185,8 @@ G4bool G4Tubs::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -662,6 +663,7 @@ G4double G4Tubs::DistanceToIn(const G4ThreeVector& p,
if (p.z()*v.z()<0) // at +Z going in -Z or visa versa
{
s=(fabs(p.z())-fDz)/fabs(v.z()); // Z intersect distance
if(s<0.0) s = 0.0 ; // negative dist -> zero
xi=p.x()+s*v.x(); // Intersection coords
yi=p.y()+s*v.y();
rho2=xi*xi+yi*yi;
+83 -72
View File
@@ -4,43 +4,17 @@
// Implementation of the virtual class of a CSG type shape that is built
// entirely out of G4VCSGface faces.
//
// \begin{preach mode}
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// Do not be fooled by the content, the algorithms in here are not
// very clever. This is obvious if one (tries) to read a good textbook
// on 3D modeling.
//
// GEANT4 has some rather esoteric demands on its geometric models,
// which makes most canned 3D routines not useful. So we have to
// try to invent a few. This is dangerous, because 3D modeling is
// a serious programming game.
//
// One of the real simplifications in the methods I've used here for
// a shape is that each face of a solid is treated separately. Or, at
// least this is the illusion. In fact, for non-convex solids (which
// abound in GEANT4), the face routine Inside cannot be correctly written
// unless each face knows something about all of it's neighbor. Furthermore,
// is is absolutely *crucial* that the algebraic instructions for
// deciding if a track intersection falls outside a face matches
// for the edge between adjacent faces. If not, THERE WILL BE A
// CRACK IN YOUR SOLID, GUARANTEED. It will be small, but it will
// be there.
//
// So? If we were writing a 3D display routine, cracks wouldn't
// matter. But we are writing instead a tracking simulation. One crack,
// and things may fall about very quickly. Probably not, if you generate a
// 100 events, or a thousand, but millions?? *BEWARE*
//
// Note that none of this is obvious in the pretty code below. Such
// invisible interdependencies are a evil sin for a software designer.
// So, I *confess*.
//
// Now, I should explain what you have to do.
//
// \end{preach mode}
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4VCSGfaceted.hh"
#include "G4VCSGface.hh"
#include "G4SolidExtentList.hh"
#include "G4VoxelLimits.hh"
#include "G4AffineTransform.hh"
@@ -56,56 +30,93 @@
//
G4VCSGfaceted::~G4VCSGfaceted()
{
G4VCSGface **face = faces;
do {
delete *face;
} while( ++face < faces + numFace );
DeleteStuff();
}
//
// Copy constructor
//
G4VCSGfaceted::G4VCSGfaceted( const G4VCSGfaceted &source ) : G4CSGSolid( source )
{
CopyStuff( source );
}
//
// Assignment operator
//
const G4VCSGfaceted &G4VCSGfaceted::operator=( const G4VCSGfaceted &source )
{
if (&source == this) return *this;
delete [] faces;
DeleteStuff();
CopyStuff( source );
return *this;
}
//
// CopyStuff (protected)
//
// Copy the contents of source
//
void G4VCSGfaceted::CopyStuff( const G4VCSGfaceted &source )
{
numFace = source.numFace;
if (numFace == 0) return; // odd, but permissable?
faces = new G4VCSGface*[numFace];
G4VCSGface **face = faces,
**sourceFace = source.faces;
do {
*face = (*sourceFace)->Clone();
} while( ++sourceFace, ++face < faces+numFace );
}
//
// DeleteStuff (protected)
//
// Delete all allocated objects
//
void G4VCSGfaceted::DeleteStuff()
{
if (numFace) {
G4VCSGface **face = faces;
do {
delete *face;
} while( ++face < faces + numFace );
delete [] faces;
}
}
//
// CalculateExtent
//
G4bool G4VCSGfaceted::CalculateExtent( const EAxis pAxis,
const G4VoxelLimits& pVoxelLimit,
const G4AffineTransform& pTransform,
G4double &pMin, G4double &pMax ) const
G4bool G4VCSGfaceted::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max ) const
{
//
// Loop over all faces, testing each as we go
//
G4VCSGface **face = faces;
G4double max = -kInfinity, min = +kInfinity;
do {
(*face)->CalculateExtent( pAxis, pVoxelLimit, pTransform, min, max );
} while( ++face < faces + numFace );
G4SolidExtentList extentList( axis, voxelLimit );
//
// Any luck?
// Loop over all faces, checking min/max extent as we go.
//
if (max == -kInfinity) return false;
G4VCSGface **face = faces;
do {
(*face)->CalculateExtent( axis, voxelLimit, transform, extentList );
} while( ++face < faces + numFace );
//
// What are the voxel limits along this particular axis?
// Return min/max value
//
if (pVoxelLimit.IsLimited(pAxis)) {
G4double vMax = pVoxelLimit.GetMaxExtent(pAxis),
vMin = pVoxelLimit.GetMinExtent(pAxis);
if (max < vMin) return false;
if (min > vMax) return false;
pMin = min < vMin ? vMin : min;
pMax = max > vMax ? vMax : max;
}
else {
pMin = min;
pMax = max;
}
return true;
return extentList.GetExtent( min, max );
}
@@ -135,6 +146,7 @@ EInside G4VCSGfaceted::Inside( const G4ThreeVector &p ) const
return answer;
}
//
// SurfaceNormal
//
@@ -155,6 +167,7 @@ G4ThreeVector G4VCSGfaceted::SurfaceNormal( const G4ThreeVector& p) const
return answer;
}
//
// DistanceToIn(p,v)
//
@@ -268,7 +281,7 @@ G4double G4VCSGfaceted::DistanceTo( const G4ThreeVector &p, const G4bool outgoin
if (distance < best) best = distance;
} while( ++face < faces + numFace );
return best;
return (best < 0.5*kCarTolerance) ? 0 : best;
}
@@ -284,8 +297,6 @@ void G4VCSGfaceted::DescribeYourselfTo( G4VGraphicsScene& scene ) const
//
// GetExtent
//
// This routine might need testing
//
G4VisExtent G4VCSGfaceted::GetExtent() const
{
G4ThreeVector plusX(1,0,0), minusX(-1,0,0),