Import Geant4 0.0.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-01 15:25:35 +02:00
parent 54d6b71f95
commit b97f8d0df7
3237 changed files with 807095 additions and 0 deletions
@@ -0,0 +1,167 @@
#include "G4Assembly.hh"
G4Assembly::G4Assembly()
{
// ReadSTEPFile();
// CopySTEPData();
}
G4Assembly::~G4Assembly()
{
for(G4int a=0;a<numberOfSolids;a++)
delete placedVec[a];
}
void G4Assembly::SetPlacedVector(G4PlacedVector& pVec)
{
numberOfSolids = pVec.entries();
for(G4int a=0;a<numberOfSolids;a++)
placedVec.append( pVec[a]);
}
@@ -0,0 +1,116 @@
#include "G4Axis2Placement3D.hh"
//G4Axis2Placement3D
G4Axis2Placement3D::G4Axis2Placement3D(){}
G4Axis2Placement3D::~G4Axis2Placement3D(){}
// this function is used in STEPinterface directory
G4Axis2Placement3D::G4Axis2Placement3D(const G4Axis2Placement3D& place)
{
refDirection = place.GetRefDirection();
axis = place.GetAxis();
location = place.GetLocation();
pX = place.GetPX();
pY = place.GetPY();
pZ = place.GetPZ();
toPlacementCoordinates = GetToPlacementCoordinates();
fromPlacementCoordinates = GetFromPlacementCoordinates();
}
/*
G4Axis2Placement3D::G4Axis2Placement3D(const G4ThreeVec Dir,
const G4ThreeVec Axis,
const G4Point3d Pt )
{
dir=Dir;
axis=Axis;
srf_point=Pt;
ComputeNormal();
G4Point3d Pt2 = Pt+Dir;
G4Point3d Pt3 = Pt+Axis;
G4Ray::CalcPlane3Pts(Pl, Pt, Pt2, Pt3);
}
G4Axis2Placement3D::G4Axis2Placement3D(const G4ThreeVec Dir, const G4ThreeVec Axis, const G4Point3d Pt1, const G4Point3d Pt2, const G4Point3d Pt3)
{
dir=Dir;
axis=Axis;
srf_point=Pt1;
ComputeNormal();
G4Ray::CalcPlane3Pts(Pl, Pt1, Pt2, Pt3);
}
*/
/*
void G4Axis2Placement3D::ProjectPlacement(const G4Plane& Pl1, const G4Plane& Pl2)
{
Project(ProjectedDir, dir, Pl1, Pl2);
Project(ProjectedAxis, axis, Pl1, Pl2);
Project(ProjectedSrfPoint, srf_point, Pl1, Pl2);
Project(ProjectedNormal, Normal, Pl1, Pl2);
}
void G4Axis2Placement3D::ComputeNormal()
{
if(dir == axis)
Normal = dir;
else
{
Normal.X(dir.Y()*axis.Z() - dir.Z()*axis.Y());
Normal.Y(dir.X()*axis.Z()- dir.Z()*axis.X());
Normal.Z(dir.X()*axis.Y() - dir.Y()*axis.X());
}
}
G4Point3d G4Axis2Placement3D::EvaluateIntersection(register const G4Ray& rray)
{
// s is solution, line is p + tq, n is G4Plane Normal, r is point on G4Plane
// all parameters are pointers to arrays of three elements
register G4double a, b, t;
register const G4ThreeVec& RayDir = rray.GetDir();
register const G4Point3d& RayStart = rray.GetStart();
G4double dirx = RayDir.X();
G4double diry = RayDir.Y();
G4double dirz = RayDir.Z();
b = Normal.X() * dirx + Normal.Y() * diry + Normal.Z() * dirz;
if (fabs(b) < 0.001)//== 0.0) // or some better test involving a small positive e
// if (b == 0.0) // or some better test involving a small positive e
{
// G4cout << "\nLine is parallel to G4Plane.No Hit.";
G4Point3d hit_point( kInfinity, kInfinity, kInfinity);
return hit_point;
}
G4double startx = RayStart.X();
G4double starty = RayStart.Y();
G4double startz = RayStart.Z();
a = Normal.X() * (srf_point.X() - startx) + Normal.Y() * (srf_point.Y() - starty)
+ Normal.Z() * (srf_point.Z() - startz);
t = a/b;
// substitute t into line equation
// to calculate final solution
G4Point3d hit_point(startx + t * dirx,starty + t * diry,startz + t * dirz);
// G4cout << "\nPLANE HIT POINT :" << hit_point.X() << " " << hit_point.Y() << " " << hit_point.Z();
return hit_point;
}
*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,98 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidBox.cc,v 2.3 1998/10/20 16:33:37 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidBox.hh"
#include "G4FPlane.hh"
#include "G4Point3DVector.hh"
G4BREPSolidBox::G4BREPSolidBox(G4String name,
const G4Point3D& Pt1,
const G4Point3D& Pt2,
const G4Point3D& Pt3,
const G4Point3D& Pt4,
const G4Point3D& Pt5,
const G4Point3D& Pt6,
const G4Point3D& Pt7,
const G4Point3D& Pt8): G4BREPSolid(name)
{
nb_of_surfaces=6;
active=1;PlaneSolid=1;
SurfaceVec = new G4Surface*[6];
G4Point3DVector PVec(4);
PVec[0] = Pt1;
PVec[1] = Pt2;
PVec[2] = Pt3;
PVec[3] = Pt4;
SurfaceVec[0] = new G4FPlane(&PVec);
PVec[2] = Pt6;
PVec[3] = Pt5;
SurfaceVec[1] = new G4FPlane(&PVec);
PVec[0] = Pt2;
PVec[1] = Pt6;
PVec[2] = Pt7;
PVec[3] = Pt3;
SurfaceVec[2] = new G4FPlane(&PVec);
PVec[0] = Pt3;
PVec[1] = Pt7;
PVec[2] = Pt8;
PVec[3] = Pt4;
SurfaceVec[3] = new G4FPlane(&PVec);
PVec[0] = Pt1;
PVec[1] = Pt5;
PVec[2] = Pt8;
PVec[3] = Pt4;
SurfaceVec[4] = new G4FPlane(&PVec);
PVec[0] = Pt5;
PVec[1] = Pt6;
PVec[2] = Pt7;
PVec[3] = Pt8;
SurfaceVec[5] = new G4FPlane(&PVec);
Initialize();
}
EInside G4BREPSolidBox::Inside(register const G4ThreeVector& Pt) const
{
G4Point3D Point(Pt);
// Get the bounding box extent
G4Point3D min = bbox->GetBoxMin();
min = min + -(0.5*kCarTolerance);
G4Point3D max = bbox->GetBoxMax();
max = max + (0.5*kCarTolerance);
if( (Point.x() < min.x() || Point.x() > max.x()) ||
(Point.y() < min.y() || Point.y() > max.y()) ||
(Point.z() < min.z() || Point.z() > max.z()) )
return kOutside;
if( (Point.x() > min.x() && Point.x() < max.x())&&
(Point.y() > min.y() && Point.y() < max.y())&&
(Point.z() > min.z() && Point.z() < max.z()) )
return kInside;
return kSurface;
}
@@ -0,0 +1,181 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidCone.cc,v 2.5 1998/10/29 17:49:33 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidCone.hh"
#include "G4FPlane.hh"
#include "G4FConicalSurface.hh"
#include "G4FCylindricalSurface.hh"
#include "G4CircularCurve.hh"
G4BREPSolidCone::G4BREPSolidCone(G4String name,
const G4ThreeVector& origin,
const G4ThreeVector& axis,
const G4ThreeVector& direction,
const G4double length,
const G4double radius,
const G4double large_radius):G4BREPSolid(name)
{
SurfaceVec = new G4Surface*[3];
G4Point3D ArcStart1 = origin + (radius*direction);
G4Vector3D tmpaxis(axis);
G4Vector3D tmporigin(origin);
G4Point3D paska;
paska= origin + (length*tmpaxis);
G4Point3D origin2(paska.x(), paska.y(), paska.z());
paska= origin2 + (large_radius*tmpaxis);
G4Point3D ArcStart2(paska.x(), paska.y(), paska.z());
G4Ray::Vcross(tmpaxis, axis, direction);
G4ThreeVector axis2(tmpaxis.x(),tmpaxis.y(), tmpaxis.z());
G4CurveVector CVec;
G4CircularCurve* tmp;
tmp = new G4CircularCurve();
tmp->Init(G4Axis2Placement3D(direction, axis2, origin) , large_radius);
tmp->SetBounds(ArcStart1, ArcStart1);
CVec.insert(tmp);
tmp = new G4CircularCurve();
tmp->Init(G4Axis2Placement3D(direction, axis2, origin2), large_radius);
tmp->SetBounds(ArcStart2, ArcStart2);
CVec.insert(tmp);
SurfaceVec[0] = new G4FConicalSurface(tmporigin, axis,
length, radius, large_radius);
SurfaceVec[0]->SetBoundaries(&CVec);
// new G4AdvancedFace("G4FConicalSurface", tmporigin, direction,
// axis, CVec, 1, 0,0,length, radius, large_radius);
// Create end planes & boundaries for cone solid
G4CurveVector CVec2;
tmp = new G4CircularCurve();
tmp->Init(G4Axis2Placement3D(direction, axis2, origin), radius);
tmp->SetBounds(ArcStart1, ArcStart1);
CVec2.insert(tmp);
SurfaceVec[1] = new G4FPlane(tmpaxis, direction, origin2);
//new G4AdvancedFace("G4FPlane" , origin2, direction, tmpaxis, CVec2, 1);
SurfaceVec[1]->SetBoundaries(&CVec2);
CVec2[0] = tmp = new G4CircularCurve();
tmp->Init(G4Axis2Placement3D(direction, axis2, origin2), large_radius);
tmp->SetBounds(ArcStart2, ArcStart2);
SurfaceVec[2] = new G4FPlane(tmpaxis, direction, origin);
//new G4AdvancedFace("G4FPlane", origin, direction, tmpaxis, CVec2, 1);
SurfaceVec[2]->SetBoundaries(&CVec2);
nb_of_surfaces = 3;
active=1;
Initialize();
}
void G4BREPSolidCone::Initialize()
{
// Calc bounding box for solids and surfaces
// Convert concave planes to convex
ShortestDistance=1000000;
CheckSurfaceNormals();
if(!Box || !AxisBox)
IsConvex();
CalcBBoxes();
}
EInside G4BREPSolidCone::Inside(register const G4ThreeVector& Pt) const
{
G4double dist1 = SurfaceVec[0]->HowNear(Pt);
G4double dist2 = SurfaceVec[1]->ClosestDistanceToPoint(Pt);
G4double dist3 = SurfaceVec[2]->ClosestDistanceToPoint(Pt);
if(dist1 > dist2) dist1 = dist2;
if(dist1 > dist3) dist1 = dist3;
if(dist1 > 0) return kInside;
if(dist1 < 0) return kOutside;
return kSurface;
}
G4ThreeVector G4BREPSolidCone::SurfaceNormal(const G4ThreeVector& Pt) const
{
G4Vector3D n = SurfaceVec[0]->Normal(Pt);
G4ThreeVector norm(n.x(), n.y(), n.z());
return norm;
}
G4double G4BREPSolidCone::DistanceToIn(const G4ThreeVector& Pt) const
{
G4double dist1 = fabs(SurfaceVec[0]->HowNear(Pt));
G4double dist2 = fabs(SurfaceVec[1]->ClosestDistanceToPoint(Pt));
G4double dist3 = fabs(SurfaceVec[2]->ClosestDistanceToPoint(Pt));
if(dist1 > dist2) dist1 = dist2;
if(dist1 > dist3) dist1 = dist3;
return dist1;
}
G4double G4BREPSolidCone::DistanceToIn(register const G4ThreeVector& Pt,
register const G4ThreeVector& V) const
{
Reset();
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(V);
// G4double kInfinity = 10e20;
G4Ray r(Pttmp, Vtmp);
if(SurfaceVec[0]->Intersect( r ))
{
ShortestDistance = SurfaceVec[0]->Distance();
return ShortestDistance;
}
return kInfinity;
}
G4double G4BREPSolidCone::DistanceToOut(register const G4ThreeVector& Pt,
register const G4ThreeVector& V,
const G4bool calcNorm,
G4bool *validNorm,
G4ThreeVector *n) const
{
if(validNorm)
*validNorm = false;
Reset();
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(V);
// G4double kInfinity = 10e20;
G4Ray r(Pttmp, Vtmp);
if(SurfaceVec[0]->Intersect( r ))
{
ShortestDistance = SurfaceVec[0]->Distance();
return ShortestDistance;
}
return kInfinity;
}
G4double G4BREPSolidCone::DistanceToOut(const G4ThreeVector& Pt) const
{
G4double dist1 = fabs(SurfaceVec[0]->HowNear(Pt));
G4double dist2 = fabs(SurfaceVec[1]->ClosestDistanceToPoint(Pt));
G4double dist3 = fabs(SurfaceVec[2]->ClosestDistanceToPoint(Pt));
if(dist1 > dist2) dist1 = dist2;
if(dist1 > dist3) dist1 = dist3;
return dist1;
}
@@ -0,0 +1,84 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidCylinder.cc,v 2.6 1998/11/27 17:41:38 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidCylinder.hh"
#include "G4CircularCurve.hh"
#include "G4FPlane.hh"
#include "G4FCylindricalSurface.hh"
G4BREPSolidCylinder::G4BREPSolidCylinder(G4String name,
const G4ThreeVector& origin,
const G4ThreeVector& axis,
const G4ThreeVector& direction,
const G4double& radius,
const G4double& length)
:G4BREPSolid(name)
{
SurfaceVec = new G4Surface*[3];
G4CurveVector cv;
G4CircularCurve* tmp;
// Creation of the cylindrical surface
SurfaceVec[0] = new G4FCylindricalSurface(origin, axis, radius , length);
//SurfaceVec[0]->SetBoundaries(&cv);
//cv.clear();
// Creation of the first circlular surface, which origin is origin
G4Point3D ArcStart1 = origin + ( radius*direction );
G4Vector3D axis1 = axis.cross( direction );
tmp = new G4CircularCurve;
tmp->Init( G4Axis2Placement3D(direction, axis1, origin), radius );
tmp->SetBounds(ArcStart1, ArcStart1);
cv.insert(tmp);
SurfaceVec[1] = new G4FPlane(direction, axis1, origin);
SurfaceVec[1]->SetBoundaries(&cv);
cv.clear();
// Creation of the second circlular surfac
G4Point3D origin2 = origin + ( length*axis );
G4Point3D ArcStart2 = origin2 + ( radius*direction );
G4Vector3D axis2 = axis1;
tmp = new G4CircularCurve;
tmp->Init( G4Axis2Placement3D(direction, axis2, origin2), radius);
tmp->SetBounds(ArcStart2, ArcStart2);
cv.insert(tmp);
SurfaceVec[2] = new G4FPlane(direction, axis2, origin2);
SurfaceVec[2]->SetBoundaries(&cv);
cv.clear();
nb_of_surfaces = 3;
active=1;
Initialize();
}
@@ -0,0 +1,641 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidPCone.cc,v 2.27 1998/12/11 13:40:43 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidPCone.hh"
#include "G4FCylindricalSurface.hh"
#include "G4FConicalSurface.hh"
#include "G4CircularCurve.hh"
#include "G4FPlane.hh"
G4BREPSolidPCone::G4BREPSolidPCone(G4String name,
const G4double start_angle,
const G4double opening_angle,
const int num_z_planes, // sections,
const G4double z_start,
const G4double z_values[],
const G4double RMIN[],
const G4double RMAX[]
): G4BREPSolid(name)
{
const int sections= num_z_planes-1;
nb_of_surfaces = 2*sections+2;
SurfaceVec = new G4Surface*[nb_of_surfaces];
G4ThreeVector Axis(0,0,1);
G4ThreeVector Origin(0,0,z_start);
G4double Length;
G4ThreeVector LocalOrigin(0,0,z_start);
G4int a, b = 0;
G4ThreeVector PlaneAxis(0, 0, 1);
G4ThreeVector PlaneDir (0, 1, 0);
///////////////////////////////////////////////////
// Temporary
for (G4int x = 0; x <= sections; x++)
{
G4cout<<"Z"<<x<<"="<<z_values[x];
G4cout<<" Rmin"<<x<<"="<<RMIN[x];
G4cout<<" Rmax"<<x<<"="<<RMAX[x]<<endl;
}
G4cout<<"start angle ="<<start_angle<<endl;
G4cout<<"open angle ="<<opening_angle<<endl;
G4cout<<"zstart ="<<z_start<<endl;
///////////////////////////////////////////////////
// Test the validity of the R values
// RMIN[0] and RMIN[num_z_planes-1] cannot be = 0
// when RMIN[0] or RMIN[num_z_planes-1] are = 0
if( ((RMIN[0] == 0) && (RMAX[0] == 0)) ||
((RMIN[num_z_planes-1] == 0) && (RMAX[num_z_planes-1] == 0)) )
G4Exception("RMIN at the extremities can not be nul when RMAX = 0");
// only RMAX[0] and RMAX[num_z_planes-1] can be = 0
for(a = 1; a < num_z_planes-1; a++)
if (RMAX[a] == 0)
G4Exception("RMAX inside the solid can not be nul");
// RMAX[a] must be greater than RMIN[a]
for(a = 0; a < num_z_planes; a++)
if (RMIN[a] >= RMAX[a])
G4Exception("RMAX must be greater than RMIN");
///////////////////////////////////////////////////
// Create cylindrical et conical surfaces
for(a=0; a<sections; a++)
{
// Surface length
Length = z_values[a+1] - z_values[a];
if (Length == 0)
{
// The surface to create is planar
G4double R1, R2;
// test where is the plane surface
if(RMAX[a] != RMAX[a+1])
{
R1 = RMAX[a];
R2 = RMAX[a+1];
}
else if(RMIN[a] != RMIN[a+1])
{
R1 = RMIN[a];
R2 = RMIN[a+1];
}
else
{
G4cerr << "Error in construction of G4BREPSolidPCone: "
<< "Exactly the same z, rmin and rmax given for "
<< "consecutive indices, " << a << " and " << a+1 << endl;
// G4Exception("G4BREPSolidPCone constructor: Error in parameter values");
continue;
}
// Create plane surface
G4Point3D ArcStart1 = LocalOrigin + (R1*PlaneDir);
G4Point3D ArcStart2 = LocalOrigin + (R2*PlaneDir);
G4CurveVector cv1;
G4CircularCurve *tmp1, *tmp2;
if(R1 != 0)
{
tmp1 = new G4CircularCurve;
tmp1->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, LocalOrigin), R1);
tmp1->SetBounds(ArcStart1, ArcStart1);
if(R1>R2)
tmp1->SetSameSense(1);
else
tmp1->SetSameSense(0);
cv1.append(tmp1);
}
if(R2 != 0)
{
tmp2 = new G4CircularCurve;
tmp2->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, LocalOrigin), R2);
tmp2->SetBounds(ArcStart2, ArcStart2);
if(R1>R2)
tmp2->SetSameSense(0);
else
tmp2->SetSameSense(1);
cv1.append(tmp2);
}
SurfaceVec[b] = new G4FPlane(PlaneDir, PlaneAxis, LocalOrigin);
SurfaceVec[b]->SetBoundaries(&cv1);
nb_of_surfaces--;
b++;
}
else
{
// The surface to create is conical or cylindrical
// Inner PCone
if(RMIN[a] != RMIN[a+1])
{
// Create cone
if(RMIN[a] > RMIN[a+1])
{
G4Vector3D ConeOrigin = LocalOrigin ;
SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis, Length,
RMIN[a+1], RMIN[a]);
}
else
{
G4Vector3D Axis2 = (-1*Axis);
G4Vector3D LocalOrigin2 = LocalOrigin + (Length*Axis);
G4Vector3D ConeOrigin = LocalOrigin2 ;
SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis2,
Length, RMIN[a], RMIN[a+1]);
}
b++;
}
else
{
if (RMIN[a] == 0)
{
// Do not create any surface
// and decrease nb_of_surfaces
nb_of_surfaces--;
}
else
{
// Create cylinder
G4Vector3D CylOrigin = LocalOrigin ;
SurfaceVec[b] = new G4FCylindricalSurface(CylOrigin, Axis,
RMIN[a], Length );
b++;
}
}
// Outer PCone
if(RMAX[a] != RMAX[a+1])
{
// Create cone
if(RMAX[a] > RMAX[a+1])
{
G4Vector3D ConeOrigin = LocalOrigin ;
SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis,
Length, RMAX[a+1], RMAX[a]);
}
else
{
G4Vector3D Axis2 = (-1*Axis);
G4Vector3D LocalOrigin2 = LocalOrigin + (Length*Axis);
G4Vector3D ConeOrigin = LocalOrigin2 ;
SurfaceVec[b] = new G4FConicalSurface(ConeOrigin, Axis2,
Length, RMAX[a], RMAX[a+1]);
}
b++;
}
else
{
// Create cylinder
G4Vector3D CylOrigin = LocalOrigin ;
if (RMAX[a] == 0)
{
// Do not create any surface
// and decrease nb_of_surfaces
nb_of_surfaces--;
}
else
{
// Create cylinder
G4Vector3D CylOrigin = LocalOrigin ;
SurfaceVec[b] = new G4FCylindricalSurface(CylOrigin, Axis,
RMAX[a], Length );
b++;
}
}
}
// Move surface origin to next section
LocalOrigin = LocalOrigin + (Length*Axis);
}
///////////////////////////////////////////////////
// Create two end planes
// Create start G4Plane & boundaries
G4Point3D ArcStart1a = Origin + (RMIN[0]*PlaneDir);
G4Point3D ArcStart1b = Origin + (RMAX[0]*PlaneDir);
G4CurveVector cv;
G4CircularCurve* tmp;
tmp = new G4CircularCurve;
tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, Origin), RMIN[0]);
tmp->SetBounds(ArcStart1a, ArcStart1a);
tmp->SetSameSense(0);
cv.append(tmp);
tmp = new G4CircularCurve;
tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, Origin), RMAX[0]);
tmp->SetBounds(ArcStart1b, ArcStart1b);
tmp->SetSameSense(1);
cv.append(tmp);
SurfaceVec[nb_of_surfaces-2] = new G4FPlane(PlaneDir, PlaneAxis, Origin);
SurfaceVec[nb_of_surfaces-2]->SetBoundaries(&cv);
// Create end G4Plane & boundaries
G4Point3D ArcStart2a = LocalOrigin + (RMIN[sections]*PlaneDir);
G4Point3D ArcStart2b = LocalOrigin + (RMAX[sections]*PlaneDir);
cv.clear();
tmp = new G4CircularCurve;
tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, LocalOrigin),
RMIN[sections]);
tmp->SetBounds(ArcStart2a, ArcStart2a);
tmp->SetSameSense(0);
cv.append(tmp);
tmp = new G4CircularCurve;
tmp->Init(G4Axis2Placement3D(PlaneDir, PlaneAxis, LocalOrigin),
RMAX[sections]);
tmp->SetBounds(ArcStart2b, ArcStart2b);
tmp->SetSameSense(1);
cv.append(tmp);
SurfaceVec[nb_of_surfaces-1]= new G4FPlane(PlaneDir, PlaneAxis, LocalOrigin);
SurfaceVec[nb_of_surfaces-1]->SetBoundaries(&cv);
active=1;
Initialize();
// Store the original parameters, to be used in visualisation
original_parameters.Start_angle= start_angle;
original_parameters.Opening_angle= opening_angle;
original_parameters.Num_z_planes= num_z_planes;
// original_parameters.z_start= z_start;
original_parameters.Z_values= new G4double[num_z_planes];
original_parameters.Rmin= new G4double[nb_of_surfaces];
original_parameters.Rmax= new G4double[nb_of_surfaces];
for(int is=0;is<num_z_planes;is++)
{
original_parameters.Z_values[is]= z_values[is];
original_parameters.Rmin[is]= RMIN[is];
original_parameters.Rmax[is]= RMAX[is];
}
// z_values[0] should be equal to z_start, for consistency
// with what the constructor does.
// Otherwise the z_values that are given are used
// shifted by z_values[0] - z_start:
// (because z_values are only used in
// line 26: Length = z_values[a+1] - z_values[a];
// ) // JA Apr 2, 97
/*
if( z_values[0] != z_start )
{
G4cerr << "ERROR in creating G4BREPSolidPCone: "
<< " z_values[0]= " << z_values[0] << " is not equal to "
<< " z_start= " , z_start;
// G4Exception(" Error in creating G4BREPSolidPCone: z_values[0] must be equal to z_start" );
original_parameters.Z_values[0]= z_start;
}
*/
}
G4BREPSolidPCone::~G4BREPSolidPCone()
{
delete[] original_parameters.Z_values;
delete[] original_parameters.Rmin;
delete[] original_parameters.Rmax;
}
void G4BREPSolidPCone::Initialize()
{
// Calc bounding box for solids and surfaces
// Convert concave planes to convex
ShortestDistance=1000000;
CheckSurfaceNormals();
if(!Box || !AxisBox)
IsConvex();
CalcBBoxes();
}
EInside G4BREPSolidPCone::Inside(register const G4ThreeVector& Pt) const
{
// Check if point lies between end planes of PCone
G4double dist1 = SurfaceVec[nb_of_surfaces-1]->ClosestDistanceToPoint(Pt);
G4double dist2 = SurfaceVec[nb_of_surfaces-2]->ClosestDistanceToPoint(Pt);
if((dist1 < -kCarTolerance && dist2 <-kCarTolerance)||
(dist1 > kCarTolerance && dist2 >kCarTolerance) )
return kOutside;
G4Vector3D v(1,0,0);
G4double Dist;
G4double halfTolerance = kCarTolerance*0.5;
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(v);
G4Ray r(Pttmp, Vtmp);
TestSurfaceBBoxes(r);
G4int hits=0;
for(G4int a=0; a < nb_of_surfaces; a++)
{
if(SurfaceVec[a]->Active())
if(SurfaceVec[a]->Intersect(r))
{
if(SurfaceVec[a]->Distance() < kCarTolerance)
return kSurface;
hits++;
}
}
// Set the surfaces to active again
for(G4int b=0; b < nb_of_surfaces; b++)
SurfaceVec[b]->Reset();
if(hits&1)
return kInside;
return kOutside;
}
G4ThreeVector G4BREPSolidPCone::SurfaceNormal(const G4ThreeVector& Pt) const
{
G4cout<<" SurfaceNormal() of G4BREPSolidPCone modified by L. Broglia";
G4Vector3D Ptv = Pt;
G4Vector3D n(0,0,0);
G4double zCoord = Pt.z();
const G4int num_z_planes = original_parameters.Num_z_planes;
G4int iplane;
// Find the appropriate z "slice"
//
for(iplane=0; iplane< num_z_planes; iplane++)
if ( (zCoord < original_parameters.Z_values[iplane+1]) &&
(zCoord >= original_parameters.Z_values[iplane]) )
break;
G4Vector3D norm;
G4Ray r( Pt, G4Vector3D(1, 0, 0) );
// We must find which is the correct surface, the inner or the outer one
// (if they exist)
for(iplane = 0; iplane < num_z_planes; iplane++)
{
// check if the point is on the surface
if(SurfaceVec[iplane]->Intersect(r))
if(SurfaceVec[iplane]->Distance() < kCarTolerance)
// the point is on the surface
break;
}
norm = SurfaceVec[iplane]->SurfaceNormal(Pt);
n = G4ThreeVector ( norm.x(), norm.y(), norm.z());
n = n.unit();
/*
if ( SurfaceVec[innerSurface]->WithinBoundary(Ptv) == 1 )
{
norm = SurfaceVec[ innersurface ]->SurfaceNormal(Pt);
}
else if ( SurfaceVec[outerSurface]->WithinBoundary(Ptv) == 1 )
{
norm = SurfaceVec[ outerSurface]->SurfaceNormal(Pt);
}
// Check if it is on one of the top/bottom planes
//
if ( fabs(zCoord - original_parameters.Z_values[0]) < kCarTolerance )
{
// n = G4ThreeVector (0., 0., sign( original_parameters.Z_values[0]
// -original_parameters.Z_values[1]) );
n = G4ThreeVector (0., 0., original_parameters.Z_values[0]
-original_parameters.Z_values[1] );
n = n.unit();
}
else if (fabs(zCoord - original_parameters.Z_values[num_z_planes-1]) <
kCarTolerance)
{
n = G4ThreeVector(0., 0., original_parameters.Z_values[num_z_planes]
-original_parameters.Z_values[num_z_planes-1] );
n = n.unit();
}
*/
return n;
}
G4double G4BREPSolidPCone::DistanceToIn(const G4ThreeVector& Pt) const
{
G4double *dists = new G4double[nb_of_surfaces];
G4double halfTolerance = kCarTolerance*0.5;
G4int a;
for(a=0; a< nb_of_surfaces;a++)
dists[a] = fabs(SurfaceVec[a]->HowNear(Pt));
G4double Dist=kInfinity;
for(a=0; a< nb_of_surfaces;a++)
if(Dist>dists[a]) Dist = dists[a];
delete[] dists;
// Set the surfaces to active again
for(G4int b=0; b < nb_of_surfaces; b++)
SurfaceVec[b]->Reset();
return Dist;
}
G4double G4BREPSolidPCone::DistanceToIn(register const G4ThreeVector& Pt,
register const G4ThreeVector& V) const
{
int a;
Reset();
G4double halfTolerance = kCarTolerance*0.5;
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(V);
// G4double kInfinity = ;
G4Ray r(Pttmp, Vtmp);
TestSurfaceBBoxes(r);
ShortestDistance = kInfinity;
for(a=0; a< nb_of_surfaces;a++)
{
if(SurfaceVec[a]->Active())
if(SurfaceVec[a]->Intersect( r ))
{
if(ShortestDistance > SurfaceVec[a]->Distance())
if(SurfaceVec[a]->Distance()> halfTolerance)
{
ShortestDistance = SurfaceVec[a]->Distance();
}
else
{
G4Vector3D Norm = SurfaceVec[a]->SurfaceNormal(Pttmp);
if((Norm * Vtmp)<0)
ShortestDistance = SurfaceVec[a]->Distance();
}
}
}
// Set the surfaces to active again
for(G4int b=0; b < nb_of_surfaces; b++)
SurfaceVec[b]->Reset();
if(ShortestDistance != kInfinity)
return sqrt(ShortestDistance);
return kInfinity;
}
G4double G4BREPSolidPCone::DistanceToOut(register const G4ThreeVector& Pt,
register const G4ThreeVector& V,
const G4bool calcNorm,
G4bool *validNorm,
G4ThreeVector *n ) const
{
const G4double halfTolerance = kCarTolerance*0.5;
G4Vector3D Ptv = Pt;
G4double wb = 0.0;
G4int a;
for( a=0; a< nb_of_surfaces-2; a++)
{
wb = fabs( SurfaceVec[a]->HowNear(Ptv) );
// If we are on a surface and exiting it return Zero
if ( (wb < halfTolerance) && (V.dot(SurfaceVec[a]->Normal(Ptv))>0) )
{
return (0.0);
}
}
if(validNorm)
*validNorm=false;
Reset();
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(V);
// G4double kInfinity = 10e20;
G4Ray r(Pttmp, Vtmp);
TestSurfaceBBoxes(r);
ShortestDistance = kInfinity;
for(a=0; a< nb_of_surfaces;a++)
if(SurfaceVec[a]->Active())
if(SurfaceVec[a]->Intersect( r ))
if(ShortestDistance > SurfaceVec[a]->Distance()&&
SurfaceVec[a]->Distance()> halfTolerance)
ShortestDistance = SurfaceVec[a]->Distance();
// Set the surfaces to active again
for(G4int b=0; b < nb_of_surfaces; b++)
SurfaceVec[b]->Reset();
if(ShortestDistance != kInfinity)
return sqrt(ShortestDistance);
return kInfinity;
}
G4double G4BREPSolidPCone::DistanceToOut(const G4ThreeVector& Pt) const
{
int a;
G4double *dists = new G4double[nb_of_surfaces];
G4double halfTolerance = kCarTolerance*0.5;
for(a=0; a< nb_of_surfaces; a++)
dists[a] = fabs(SurfaceVec[a]->HowNear(Pt));
G4double Dist=kInfinity;
for(a=0; a< nb_of_surfaces;a++)
if( Dist>dists[a] ) Dist = dists[a];
// Set the surfaces to active again
for(G4int b=0; b < nb_of_surfaces; b++)
SurfaceVec[b]->Reset();
// If we are on a surface, the return value Dist must be zero!
delete[] dists;
return Dist;
}
// In graphics_reps:
#include "G4Polyhedron.hh"
G4Polyhedron* G4BREPSolidPCone::CreatePolyhedron() const
{
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);
}
@@ -0,0 +1,484 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidPolyhedra.cc,v 2.11 1998/12/11 13:40:46 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidPolyhedra.hh"
#include "G4FPlane.hh"
G4BREPSolidPolyhedra::G4BREPSolidPolyhedra(G4String name,
const G4double phi1,
const G4double dphi,
const int sides,
const int num_z_planes,
const G4double z_start,
const G4double z_values[],
const G4double RMIN[],
const G4double RMAX[]
) : G4BREPSolid(name)
{
const int sections= num_z_planes - 1;
if(dphi == 2*pi)
nb_of_surfaces = 2*(sections * sides) + 2;
else
nb_of_surfaces = 2*(sections * sides) + 4;
SurfaceVec = new G4Surface*[nb_of_surfaces];
G4Vector3D Axis(0,0,1);
G4Vector3D YAxis(0,1,0);
G4Vector3D TmpAxis;
G4Point3D Origin(0,0,z_start);
G4Point3D LocalOrigin(0,0,z_start);
G4double Length;
int Count =0;
G4double PartAngle = (dphi - phi1)/sides;
///////////////////////////////////////////////////
// Temporary
for (G4int x = 0; x <= sections; x++)
{
cout<<"Z"<<x<<"="<<z_values[x];
cout<<" Rmin"<<x<<"="<<RMIN[x];
cout<<" Rmax"<<x<<"="<<RMAX[x]<<endl;
}
cout<<"phi1 ="<<phi1<<endl;
cout<<"dphi ="<<dphi<<endl;
cout<<"sides ="<<sides<<endl;
cout<<"zstart ="<<z_start<<endl;
///////////////////////////////////////////////////
for(G4int a=0;a<sections;a++)
{
TmpAxis= YAxis;
TmpAxis.rotateZ(phi1);
Length = z_values[a+1] - z_values[a];
// Create sides
for(int b=0;b<sides;b++)
{
G4Point3DVector PointList(4);
// Create inner side
// Calc points for the planar surface boundary
PointList[0] = LocalOrigin + (RMIN[a] * TmpAxis);
PointList[1] = LocalOrigin + (Length*Axis) + (RMIN[a+1] * TmpAxis);
TmpAxis.rotateZ(PartAngle);
PointList[2] = LocalOrigin + (Length*Axis) + (RMIN[a+1] * TmpAxis);
PointList[3] = LocalOrigin + (RMIN[a] * TmpAxis);
SurfaceVec[Count] = new G4FPlane( &PointList);
Count++;
// Rotate axis back for the other surface point calculation
TmpAxis.rotateZ(-PartAngle);
// Calc points for the planar surface boundary
G4Point3DVector PointList2(4);
PointList2[0] = LocalOrigin + (RMAX[a] * TmpAxis);
PointList2[1] = LocalOrigin + (Length*Axis) + (RMAX[a+1] * TmpAxis);
TmpAxis.rotateZ(PartAngle);
PointList2[2] = LocalOrigin + (Length*Axis) + (RMAX[a+1] * TmpAxis);
PointList2[3] = LocalOrigin + (RMAX[a] * TmpAxis);
SurfaceVec[Count] = new G4FPlane(&PointList2);
Count++;
}
LocalOrigin = LocalOrigin + (Length*Axis);
}
// Create end planes
if(dphi == 2*pi)
{
// Create only end planes
G4Point3DVector EndPointList(sides);
G4Point3DVector InnerPointList(sides);
G4Point3DVector EndPointList2(sides);
G4Point3DVector InnerPointList2(sides);
TmpAxis = YAxis;
TmpAxis.rotateZ(phi1);
TmpAxis.rotateZ(dphi);
for(int c=0;c<sides;c++)
{
// outer polyline for origin end
EndPointList[c] = Origin + (RMAX[0] * TmpAxis);
InnerPointList[c] = Origin + (RMIN[0] * TmpAxis);
EndPointList2[c] = LocalOrigin + (RMAX[sections] * TmpAxis);
InnerPointList2[c] = LocalOrigin + (RMIN[sections] * TmpAxis);
TmpAxis.rotateZ(-PartAngle);
}
SurfaceVec[nb_of_surfaces-2] =
new G4FPlane(&EndPointList, &InnerPointList);
SurfaceVec[nb_of_surfaces-1] =
new G4FPlane(&EndPointList2, &InnerPointList2);
}
else
{
TmpAxis = YAxis;
TmpAxis.rotateZ(phi1);
TmpAxis.rotateZ(dphi);
// Create end planes & two planes for the "missing" part
G4Point3DVector EndPointList(sides+2);
G4Point3DVector InnerPointList(sides+2);
G4Point3DVector EndPointList2(sides+2);
G4Point3DVector InnerPointList2(sides+2);
TmpAxis = YAxis;
for(int c=0;c<sides+1;c++)
{
// outer polyline for origin end
EndPointList[c] = Origin + (RMAX[0] * TmpAxis);
InnerPointList[c] = Origin + (RMIN[0] * TmpAxis);
EndPointList2[c] = LocalOrigin + (RMAX[sections] * TmpAxis);
InnerPointList2[c] = LocalOrigin + (RMIN[sections] * TmpAxis);
TmpAxis.rotateZ(-PartAngle);
}
// Create the extra points on the axis
TmpAxis = YAxis;
TmpAxis.rotateZ(phi1);
EndPointList[sides+1] = Origin;
InnerPointList[sides+1] = Origin;
EndPointList2[sides+1] = LocalOrigin;
InnerPointList2[sides+1] = LocalOrigin;
int points = sides+2;
SurfaceVec[nb_of_surfaces-4] =
new G4FPlane(&EndPointList, &InnerPointList);
SurfaceVec[nb_of_surfaces-3] =
new G4FPlane(&EndPointList2, &InnerPointList2);
// Create the planars for the "gap"
TmpAxis = YAxis;
G4ThreeVector TmpAxis2 = YAxis;
TmpAxis.rotateZ(phi1);
TmpAxis2.rotateZ(phi1);
TmpAxis2.rotateZ(dphi);
LocalOrigin=Origin;
points = sections*2+2;
G4Point3DVector GapPointList(points);
G4Point3DVector GapPointList2(points);
Count=0;
for(int d=0;d<sections+1;d++)
{
GapPointList[Count] = LocalOrigin + (RMAX[d]*TmpAxis);
GapPointList[points-1-Count] = LocalOrigin + (RMIN[d]*TmpAxis);
GapPointList2[Count] = LocalOrigin + (RMAX[d]*TmpAxis2);
GapPointList2[points-1-Count] = LocalOrigin + (RMIN[d]*TmpAxis2);
Count++;
Length = z_values[d+1] - z_values[d];
LocalOrigin = LocalOrigin+(Length*Axis);
}
SurfaceVec[nb_of_surfaces-2] = new G4FPlane(&GapPointList);
SurfaceVec[nb_of_surfaces-1] = new G4FPlane(&GapPointList2);
}
// Store the original parameters, to be used in visualisation
// Note radii are scaled because this BREP uses the radius of the
// inscribed circle but graphics_reps/G4Polyhedron uses the radius of
// the circumscribed circle.
original_parameters.Start_angle= phi1;
original_parameters.Opening_angle= dphi;
original_parameters.Sides= sides;
original_parameters.Num_z_planes= num_z_planes;
original_parameters.Z_values= new G4double[num_z_planes];
original_parameters.Rmin= new G4double[num_z_planes];
original_parameters.Rmax= new G4double[num_z_planes];
G4double rFactor = cos(dphi/(2*sides));
for(int is=0;is<num_z_planes;is++)
{
original_parameters.Z_values[is]= z_values[is];
original_parameters.Rmin[is]= RMIN[is]/rFactor;
original_parameters.Rmax[is]= RMAX[is]/rFactor;
}
// z_values[0] should be equal to z_start, for consistency
// with what the constructor does.
// Otherwise the z_values that are shifted by (z_values[0] - z_start) ,
// because z_values are only used in the form
// length = z_values[d+1] - z_values[d]; // JA Apr 2, 97
if( z_values[0] != z_start )
{
G4cerr << "ERROR in creating G4BREPSolidPolyhedra: " <<
" z_values[0]= " << z_values[0] << " is not equal to " <<
" z_start= " , z_start;
// G4Exception(" Error in creating G4BREPSolidPolyhedra: z_values[0] must be equal to z_start" );
original_parameters.Z_values[0]= z_start;
}
active=1;
Initialize();
}
G4BREPSolidPolyhedra::~G4BREPSolidPolyhedra()
{
delete[] original_parameters.Z_values;
delete[] original_parameters.Rmin;
delete[] original_parameters.Rmax;
}
void G4BREPSolidPolyhedra::Initialize()
{
// Calc bounding box for solids and surfaces
// Convert concave planes to convex
ShortestDistance=1000000;
CheckSurfaceNormals();
if(!Box || !AxisBox)
IsConvex();
CalcBBoxes();
}
EInside G4BREPSolidPolyhedra::Inside(register const G4ThreeVector& Pt) const
{
G4double *dists = new G4double[nb_of_surfaces];
G4double Dist = kInfinity;
G4double tmpdist=kInfinity;
G4double halfTolerance = kCarTolerance*0.5;
for(int a=0; a< nb_of_surfaces;a++)
{
tmpdist = (SurfaceVec[a]->HowNear(Pt));
if(fabs(Dist) > fabs(tmpdist))
Dist = tmpdist;
}
if(Dist > halfTolerance)
return kOutside;
if(Dist < -halfTolerance)
return kInside;
return kSurface;
}
G4ThreeVector G4BREPSolidPolyhedra::SurfaceNormal
(const G4ThreeVector& Pt) const
{
G4cout<<" SurfaceNormal() of G4BREPSolidPolyhedra modified by L. Broglia";
/*
//G4Exception(" SurfaceNormal() of G4BREPSolidPolyhedra is not yet implemented." );
#ifdef WILL_IMPLEMENT
G4double zCoord= Pt.z();
G4int a, zSlice, phiSlice;
// Try to find the appropriate z "slice"
for(a=0; a< nb_of_surfaces-2;a++)
if ( (zCoord < original_parameters.Z_values[a+1])
&&(zCoord >= original_parameters.Z_values[a]) )
break;
zSlice= a;
// Try to find the appropriate phi plane
phiSlice = 0;
unsigned int isurface=0;
G4ThreeVec norm = SurfaceVec[isurface]->SurfaceNormal(Pt);
G4ThreeVector normalVector = G4ThreeVector ( norm.GetX(),
norm.GetY(),
norm.GetZ());
#else
G4ThreeVector normalVector = G4ThreeVector ( 0.0, 0.0, 1.0);
#endif
*/
G4Vector3D Ptv = Pt;
G4Vector3D n(0,0,0);
G4double zCoord = Pt.z();
const G4int num_z_planes = original_parameters.Num_z_planes;
G4int iplane;
// Find the appropriate z "slice"
//
for(iplane=0; iplane< num_z_planes; iplane++)
if ( (zCoord < original_parameters.Z_values[iplane+1]) &&
(zCoord >= original_parameters.Z_values[iplane]) )
break;
G4Vector3D norm;
G4Ray r( Pt, G4Vector3D(1, 0, 0) );
// We must find which is the correct surface, the inner or the outer one
// (if they exist)
for(iplane = 0; iplane < num_z_planes; iplane++)
{
// check if the point is on the surface
if(SurfaceVec[iplane]->Intersect(r))
if(SurfaceVec[iplane]->Distance() < kCarTolerance)
// the point is on the surface
break;
}
norm = SurfaceVec[iplane]->SurfaceNormal(Pt);
n = G4ThreeVector ( norm.x(), norm.y(), norm.z());
n = n.unit();
return n;
}
G4double G4BREPSolidPolyhedra::DistanceToIn(const G4ThreeVector& Pt) const
{
G4double Dist=kInfinity;
G4double tmpdist=kInfinity;
G4double halfTolerance = kCarTolerance*0.5;
for(int a=0; a< nb_of_surfaces;a++)
{
tmpdist = fabs(SurfaceVec[a]->HowNear(Pt));
if(Dist>tmpdist && tmpdist> halfTolerance) Dist = tmpdist;
}
return Dist;
}
G4double G4BREPSolidPolyhedra::DistanceToIn(register const G4ThreeVector& Pt,
register const G4ThreeVector& V
) const
{
Reset();
G4Point3D Pttmp(Pt);
G4Vector3D Vtmp(V);
G4double halfTolerance = kCarTolerance*0.5;
// G4double kInfinity = kInfinity;
G4Ray r(Pttmp, Vtmp);
TestSurfaceBBoxes(r);
QuickSort(SurfaceVec, 0, nb_of_surfaces-1);
ShortestDistance = kInfinity;
for(int a=0; a< nb_of_surfaces;a++)
{
if(SurfaceVec[a]->Active())
// L. Broglia : old
// if(SurfaceVec[a]->Intersect(r))
if( (G4FPlane*)(SurfaceVec[a])->Evaluate(r) )
if(ShortestDistance > SurfaceVec[a]->Distance())
if(SurfaceVec[a]->Distance() > halfTolerance)
ShortestDistance = SurfaceVec[a]->Distance();
else
{
G4ThreeVector Norm = SurfaceVec[a]->SurfaceNormal(Pttmp);
if((Norm * Vtmp)<0)
ShortestDistance = SurfaceVec[a]->Distance();
}
}
if(ShortestDistance != kInfinity)
return sqrt(ShortestDistance);
return kInfinity;
}
G4double G4BREPSolidPolyhedra::DistanceToOut(register const G4ThreeVector& Pt,
register const G4ThreeVector& V,
const G4bool calcNorm,
G4bool *validNorm,
G4ThreeVector *n) const
{
if(validNorm)
*validNorm = false;
Reset();
G4double halfTolerance = kCarTolerance*0.5;
G4Point3D Pttmp(Pt);
G4Vector3D Vtmp(V);
// G4double kInfinity = 10e20;
G4Ray r(Pttmp, Vtmp);
TestSurfaceBBoxes(r);
QuickSort(SurfaceVec, 0, nb_of_surfaces-1);
ShortestDistance = kInfinity;
for(int a=0; a< nb_of_surfaces;a++)
{
if(SurfaceVec[a]->Active())
if(SurfaceVec[a]->Intersect(r))
if(ShortestDistance > SurfaceVec[a]->Distance()&&
SurfaceVec[a]->Distance() > halfTolerance)
ShortestDistance = SurfaceVec[a]->Distance();
}
if(ShortestDistance != kInfinity)
return sqrt(ShortestDistance);
return kInfinity;
}
G4double G4BREPSolidPolyhedra::DistanceToOut(const G4ThreeVector& Pt) const
{
G4double Dist=kInfinity;
G4double tmpdist=kInfinity;
G4double halfTolerance = kCarTolerance*0.5;
for(int a=0; a< nb_of_surfaces;a++)
{
tmpdist = fabs(SurfaceVec[a]->HowNear(Pt));
if(Dist>tmpdist && tmpdist> halfTolerance)
Dist = tmpdist;
}
return Dist;
}
// In graphics_reps:
#include "G4Polyhedron.hh"
G4Polyhedron* G4BREPSolidPolyhedra::CreatePolyhedron() const
{
return new G4PolyhedronPgon( original_parameters.Start_angle,
original_parameters.Opening_angle,
original_parameters.Sides,
original_parameters.Num_z_planes,
original_parameters.Z_values,
original_parameters.Rmin,
original_parameters.Rmax);
}
@@ -0,0 +1,110 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidSphere.cc,v 2.2 1998/10/20 16:33:39 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidSphere.hh"
#include "G4SphericalSurface.hh"
G4BREPSolidSphere::G4BREPSolidSphere(const G4String name,
const G4Vector3D& o,
const G4Vector3D& xhat,
const G4Vector3D& zhat,
G4double r): G4BREPSolid(name)
{
SurfaceVec = new G4Surface*[1];
G4double ph1 = 0;
G4double ph2 = 2*M_PI;
G4double th1 = 0;
G4double th2 = M_PI;
SurfaceVec[0] = new G4SphericalSurface(o, xhat, zhat, r, ph1, ph2, th1, th2);
nb_of_surfaces = 1;
active=1;
Initialize();
}
EInside G4BREPSolidSphere::Inside(register const G4ThreeVector& Pt) const
{
G4double Dist = SurfaceVec[0]->HowNear(Pt);
if(Dist > 0+kCarTolerance) return kInside;
if(Dist < 0-kCarTolerance) return kOutside;
return kSurface;
}
G4ThreeVector G4BREPSolidSphere::SurfaceNormal(const G4ThreeVector& Pt) const
{
G4Vector3D n = SurfaceVec[0]->Normal(Pt);
G4ThreeVector norm(n.x(), n.y(), n.z());
return norm;
}
G4double G4BREPSolidSphere::DistanceToIn(const G4ThreeVector& Pt) const
{
return fabs(SurfaceVec[0]->HowNear(Pt));
}
G4double G4BREPSolidSphere::DistanceToIn(register const G4ThreeVector& Pt,
register const G4ThreeVector& V) const
{
SphReset();
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(V);
G4Ray r(Pttmp, Vtmp);
int Result = SurfaceVec[0]->Intersect( r );
if(Result>0)
{
ShortestDistance = SurfaceVec[0]->Distance();
return sqrt(ShortestDistance);
}
return kInfinity;
}
G4double G4BREPSolidSphere::DistanceToOut(register const G4ThreeVector& Pt,
register const G4ThreeVector& V,
const G4bool calcNorm,
G4bool *validNorm,
G4ThreeVector *n) const
{
if(validNorm)
*validNorm = false;
SphReset();
G4Vector3D Pttmp(Pt);
G4Vector3D Vtmp(V);
G4Ray r(Pttmp, Vtmp);
if(SurfaceVec[0]->Intersect( r ))
{
if(calcNorm)
{
*validNorm = true;
*n = SurfaceNormal(Pt);
}
ShortestDistance = SurfaceVec[0]->Distance();
return sqrt(ShortestDistance);
}
return kInfinity;
}
G4double G4BREPSolidSphere::DistanceToOut(const G4ThreeVector& Pt) const
{
return fabs(SurfaceVec[0]->HowNear(Pt));
}
@@ -0,0 +1,28 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BREPSolidTorus.cc,v 2.1 1998/10/20 16:33:39 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BREPSolidTorus.hh"
#include "G4ToroidalSurface.hh"
G4BREPSolidTorus::G4BREPSolidTorus(const G4String name,
const G4ThreeVector& origin,
const G4ThreeVector& axis,
const G4ThreeVector& direction,
G4double MinRadius,
G4double MaxRadius): G4BREPSolid(name)
{
SurfaceVec = new G4Surface*[1];
SurfaceVec[0] = new G4ToroidalSurface( origin, axis, direction,
MinRadius, MaxRadius);
nb_of_surfaces = 1;
active = 1;
Initialize();
}
@@ -0,0 +1,240 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BSplineCurve.cc,v 2.8 1998/12/15 15:45:15 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BSplineCurve.hh"
#include "G4ControlPoints.hh"
#include "G4KnotVector.hh"
G4BSplineCurve::G4BSplineCurve()
{
}
void G4BSplineCurve::Init(G4int degree0, G4Point3DVector* controlPointsList0,
G4doubleVector* knots0,
G4doubleVector* weightsData0)
{
degree= degree0;
G4int nbpoints = controlPointsList0->length();
controlPointsList = new G4Point3DVector(nbpoints);
G4int a;
for(a = 0; a < nbpoints; a++)
{
(*controlPointsList)[a] = (*controlPointsList0)[a];
}
G4int nbknots = knots0->length();
knots = new G4doubleVector(nbknots);
for(a = 0; a < nbknots; a++)
{
(*knots)[a] = (*knots0)[a];
}
G4int nbweights = weightsData0->length();
weightsData = new G4doubleVector(nbweights);
for(a = 0; a < nbweights; a++)
{
(*weightsData)[a] = (*weightsData0)[a];
}
SetBounds((*knots)[0], (*knots)[knots->length()-1]);
}
G4BSplineCurve::~G4BSplineCurve()
{
delete controlPointsList;
delete knots;
if (weightsData) delete weightsData;
}
/*
void G4BSplineCurve::CalcCurvePlaneNormal()
{
//Calc Normal for surface which is used for the projection
G4ThreeVec norm;
G4Point3d Pt1 = ControlPointList->get(0,0);
G4Point3d Pt2 = ControlPointList->get(0,1);
G4Point3d Pt3 = ControlPointList->get(0,2);
G4Point3d a(Pt2.X()-Pt1.X(), Pt2.Y()-Pt1.Y(), Pt2.Z()-Pt1.Z());
G4Point3d b(Pt3.X()-Pt1.X(), Pt3.Y()-Pt1.Y(), Pt3.Z()-Pt1.Z());
norm.X((a.Y()*b.Z() - a.Z()*b.Y()));
norm.Y((a.X()*b.Z() - a.Z()*b.X()));
norm.Z((a.X()*b.Y() - a.Y()*b.X()));
}
*/
G4Curve* G4BSplineCurve::Project(const G4Transform3D& tr)
{
// just transform + project all control points
// what about self intersections?
G4int n = controlPointsList->length();
G4Point3DVector* newControlPointsList = new G4Point3DVector(n);
for (G4int i=0; i<n; i++)
{
G4Point3D& p= (*newControlPointsList)(i);
p= tr*(*controlPointsList)(i);
p.setZ(0);
}
G4doubleVector* newKnots= new G4doubleVector(*knots);
G4doubleVector* newWeightsData=
weightsData ? new G4doubleVector(*weightsData) : 0;
G4BSplineCurve* r= new G4BSplineCurve;
r->Init(degree, newControlPointsList, newKnots, newWeightsData);
if (IsBounded())
{
r->SetBounds(GetPStart(), GetPEnd());
}
return r;
}
/*
void G4BSplineCurve::ProjectCurve(const G4Plane& Pl1, const G4Plane& Pl2)
{
int rows = ControlPointList->GetRows();
int cols = ControlPointList->GetCols();
int NumberOfPoints = cols * rows;
ProjectedControlPoints = new G4Point2d*[NumberOfPoints];
// Loop through points and do projection
for(int a = 0; a<NumberOfPoints;a++)
{
// Create 2d-point
ProjectedControlPoints[a] = new G4Point2d;
// Project 3d points into 2d
Project((*ProjectedControlPoints[a]), ControlPointList->get(0,a), Pl1, Pl2);
}
}
*/
/*
int G4BSplineCurve::Inside( const G4Point3d& Hit, const G4Ray& rayref)
{
const G4Plane& Pl1 = rayref.GetPlane(0);
const G4Plane& Pl2 = rayref.GetPlane(1);
register G4double DistA1, DistA2, DistB1, DistB2;
// Calc distance from Start point to ray planes
DistA1 = Start.PlaneDistance(Pl1);
// Calc distance from End point to ray planes
DistB1 = End.PlaneDistance(Pl1);
if((DistA1<0 && DistB1>0)||(DistA1>0 && DistB1 <0))
{
DistA2 = Start.PlaneDistance(Pl2);
DistB2 = End.PlaneDistance(Pl2);
// This checks the line Start-End of the convex hull
if(DistA2<0&&DistB2<0)
return 1;
}
// Test for the other lines of the convex hull
// If one of them is on a different side than the
// previously checked line, the curve has to be evaluated
// against the G4Plane.
int Points = ControlPointList->GetCols();
G4Point *CPoint1, *CPoint2;
register G4double CDistA1,CDistA2, CDistB1, CDistB2;
int Flag=0;
for(int a=0;a<Points-1;a++)
{
CPoint1 = &ControlPointList->get(0,a);
CPoint2 = &ControlPointList->get(0,a+1);
CDistA1 = CPoint1->PlaneDistance(Pl1);
CDistB1 = CPoint2->PlaneDistance(Pl1);
if((CDistA1<0 && CDistB1>0)||(CDistA1>0 && CDistB1<0))
{
CDistA2 = CPoint1->PlaneDistance(Pl2);
CDistB2 = CPoint2->PlaneDistance(Pl2);
if (!(CDistA2<0&&CDistB2<0))
{
Flag=1;
break;
}
}
}
if(!Flag)
return 1;
else
{
// Evaluate curve & Pl1 intersection, Calc the intersections distance
// from Pl2 to check which side it lies on.
G4Point3d IntPoint;
// G4cout << "\nG4B_SplineCurve.cc:Inside - Evaluation not yet implemented!!!\n";
// IntPoint = ...
G4double IntDist = IntPoint.PlaneDistance(Pl2);
if(IntDist<0)
return 1;
}
return 0;
}
*/
void G4BSplineCurve::InitBounded()
{
// just like in the old functions
G4int pointCount = controlPointsList->length();
bBox.Init( (*controlPointsList)(0) );
for (G4int i=1; i<pointCount; i++)
{
bBox.Extend( (*controlPointsList)(i) );
}
}
/*
G4Point3d G4BSplineCurve::GetBoundMin()
{
G4Point3d Min = PINFINITY;
int PointCount = ControlPointList->GetCols();
G4Point3d Tmp;
for(int a=0;a<PointCount;a++)
{
Tmp = ControlPointList->get(0,a);
Min > Tmp;
}
return Min;
}
G4Point3d G4BSplineCurve::GetBoundMax()
{
G4Point3d Max = -PINFINITY;
G4Point3d Tmp;
int PointCount = ControlPointList->GetCols();
for(int a=0;a<PointCount;a++)
{
Tmp = ControlPointList->get(0,a);
Max > Tmp;
}
return Max;
}
*/
G4bool G4BSplineCurve::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
G4Exception("G4BSplineCurve::Tangent");
return false;
}
@@ -0,0 +1,12 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BSplineCurveWithKnots.cc,v 2.1 1998/07/02 17:53:59 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BSplineCurveWithKnots.hh"
@@ -0,0 +1,626 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BSplineSurface.cc,v 2.10 1998/11/24 16:41:23 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "EntityInst.h"
#include "G4BSplineSurface.hh"
#include "G4BezierSurface.hh"
class G4ControlPoints;
class G4BoundingBox;
G4BSplineSurface::G4BSplineSurface()
{
distance = kInfinity;
dir=ROW;
first_hit = Hit=(G4UVHit*)0;
ctl_points = (G4ControlPoints*)0;
}
G4BSplineSurface::G4BSplineSurface(char* nurbfilename, G4Ray& rayref)
{
distance = kInfinity;
Hit=(G4UVHit*)0;
first_hit = Hit;
}
G4BSplineSurface::G4BSplineSurface(const G4BSplineSurface &tmp)
{
distance = tmp.distance;
Hit=(G4UVHit*)0;
first_hit=Hit;
// next=this;
order[0] = tmp.order[0];
order[1] = tmp.order[1];
dir = tmp.dir;
u_knots = new G4KnotVector(*tmp.u_knots);
v_knots = new G4KnotVector(*tmp.v_knots);
ctl_points = new G4ControlPoints(*tmp.ctl_points);
}
G4BSplineSurface::G4BSplineSurface(G4int u, G4int v, G4KnotVector& u_kv,
G4KnotVector& v_kv,G4ControlPoints& cp)
{
order[0] = u+1;
order[1] = v+1;
u_knots = new G4KnotVector(u_kv);
v_knots = new G4KnotVector(v_kv);
ctl_points = new G4ControlPoints(cp);
}
G4BSplineSurface::~G4BSplineSurface()
{
delete u_knots;
delete v_knots;
delete ctl_points;
G4UVHit* temphit=Hit;
while(Hit!=(G4UVHit*)0)
{
Hit=Hit->next;
delete temphit;
temphit=Hit;
}
delete temphit;// remove last
}
int G4BSplineSurface::Intersect(const G4Ray& rayref)
{
Intersected = 1;
FindIntersections(rayref);
G4BezierSurface *bez_ptr;
bezier_list.MoveToFirst();
distance = kInfinity;
while( bezier_list.index != (G4Surface*)0)
{
bez_ptr = (G4BezierSurface*)bezier_list.GetSurface();
if(bez_ptr->Active())
if(distance > bez_ptr->Distance())
{
// Put data from closest bezier to b-spline data struct
closest_hit = bez_ptr->AveragePoint();
distance = bez_ptr->Distance();
}
else
{
// Set other beziers as inactive
bez_ptr->Active(0);
// Remove beziers that are not closest
// bezier_list.RemoveSurface(bez_ptr);
}
bezier_list.Step();
}
bezier_list.MoveToFirst();
if(bezier_list.number_of_elements)
return 1;
else
{
active=0;
return 0;
}
}
G4Point3D G4BSplineSurface::FinalIntersection()
{
// Compute the real intersection point.
G4BezierSurface* bez_ptr;
while ( bezier_list.number_of_elements > 0 &&
bezier_list.index != (G4Surface*)0)
{
bez_ptr = (G4BezierSurface*)bezier_list.GetSurface();
int tmp = 0;
// L. Broglia
// Modify G4BezierSurface intersection function name
// tmp = bez_ptr->Intersect( bezier_list);
tmp = bez_ptr->BIntersect( bezier_list);
if(!tmp)
{
bezier_list.RemoveSurface(bez_ptr);
if(bezier_list.index != (G4Surface*)0)
bezier_list.index->Active(1);
}
else
if(tmp==1)
{
active=1;
// Hit found
AddHit(bez_ptr->GetU(), bez_ptr->GetV());
// Delete beziers
bezier_list.EmptyList();
}
else
if(tmp==2)
{
// The bezier was split so the last
// two surfaces in the List should
// be bbox tested and if passed
// clipped in both dirs.
// Move to first
bezier_list.MoveToFirst();
// Find the second last.
if(bezier_list.index != bezier_list.last)
while ( ((G4SurfaceList*)bezier_list.index)->next !=
bezier_list.last) bezier_list.Step();
G4BezierSurface* tmp = (G4BezierSurface*) bezier_list.GetSurface();
tmp->CalcBBox();
// L. Broglia tmp->bbox->Test();
int result=0;
if(tmp->bbox->GetTestResult())
{
// Clip
while(!result)
result = tmp->ClipBothDirs();
}
else
{
bezier_list.RemoveSurface(tmp);
}
// Second surface
tmp = (G4BezierSurface*) bezier_list.GetLastSurface();
tmp->CalcBBox();
// L. Broglia tmp->bbox->Test();
if(tmp->bbox->GetTestResult())
{
result = 0;
while(!result)
result = tmp->ClipBothDirs();
}
else
{
bezier_list.RemoveSurface(tmp);
}
bezier_list.RemoveSurface(bez_ptr);
bezier_list.MoveToFirst();
}
bezier_list.Step();
}//While....
Hit = first_hit;
G4Point3D result;
if(Hit == (G4UVHit*)0)
active = 0;
else
{
while(Hit != (G4UVHit*)0)
{
// L. Broglia
// Modify function name
// result = Evaluate();
result = BSEvaluate();
Hit = Hit->next;
}
Hit = first_hit;
}
return result;
}
void G4BSplineSurface::CalcBBox()
{
// Finds the bounds of the b-spline surface iow
// calculates the bounds for a bounding box
// to the surface. The bounding box is used
// for a preliminary check of intersection.
register G4Point3D box_min = PINFINITY;
register G4Point3D box_max =-PINFINITY;
// Loop to search the whole control point mesh
// for the minimum and maximum values for x, y and z.
for(register int a = ctl_points->GetRows()-1; a>=0;a--)
for(register int b = ctl_points->GetCols()-1; b>=0;b--)
{
G4Point3D tmp = ctl_points->Get3D(a,b);
if((box_min.x()) > (tmp.x())) box_min.setX(tmp.x());
if((box_min.y()) > (tmp.y())) box_min.setY(tmp.y());
if((box_min.z()) > (tmp.z())) box_min.setZ(tmp.z());
if((box_max.x()) < (tmp.x())) box_max.setX(tmp.x());
if((box_max.y()) < (tmp.y())) box_max.setY(tmp.y());
if((box_max.z()) < (tmp.z())) box_max.setZ(tmp.z());
}
bbox = new G4BoundingBox3D( box_min, box_max);
}
G4ProjectedSurface* G4BSplineSurface::CopyToProjectedSurface
(const G4Ray& rayref)
{
G4ProjectedSurface* proj_srf = new G4ProjectedSurface() ;
proj_srf->PutOrder(0,GetOrder(0));
proj_srf->PutOrder(1,GetOrder(1));
proj_srf->dir = dir;
proj_srf->u_knots = new G4KnotVector(*u_knots);
proj_srf->v_knots = new G4KnotVector(*v_knots);
proj_srf->ctl_points = new G4ControlPoints
(2, ctl_points->GetRows(), ctl_points->GetCols());
const G4Plane& plane1 = rayref.GetPlane(1);
const G4Plane& plane2 = rayref.GetPlane(2);
ProjectNURBSurfaceTo2D(plane1, plane2, proj_srf);
return proj_srf;
}
void G4BSplineSurface::FindIntersections(const G4Ray& rayref)
{
// Do the projection to 2D
G4ProjectedSurface* proj_srf = CopyToProjectedSurface(rayref);
// Put surface in projected List
projected_list.AddSurface(proj_srf);
// Loop through List of projected surfaces
while(projected_list.number_of_elements > 0)
{
// Get first in List
proj_srf = (G4ProjectedSurface*)projected_list.GetSurface();
// Create the bounding box for the projected surface.
proj_srf->CalcBBox();
// L. Broglia proj_srf->bbox->Test();
// Check bbox test result is ok
if(proj_srf->bbox->GetTestResult())
// Convert the projected surface to a bezier. Split if necessary.
proj_srf->ConvertToBezier(projected_list, bezier_list);
// Remove projected surface
projected_list.RemoveSurface(proj_srf);
}
// Loop through the bezier List
G4BezierSurface* bez_ptr;
distance = INFINITY;
while(bezier_list.index != (G4Surface*)0)
{
bez_ptr = (G4BezierSurface*)bezier_list.GetSurface();
// Add a temporary Hit
AddHit(bez_ptr->UAverage(), bez_ptr->VAverage());
// Evaluate Hit
// L. Broglia
// Modify function name
// bez_ptr->SetAveragePoint(Evaluate());
bez_ptr->SetAveragePoint(BSEvaluate());
// Calculate distance to ray origin
bez_ptr->CalcDistance(rayref.GetStart());
// Put closest to b_splines distance value
if(bez_ptr->Distance() < distance) distance = bez_ptr->Distance();
// Remove the temporary Hit
delete Hit;
first_hit = Hit = (G4UVHit*)0;
// Move to next in the List
bezier_list.Step();
}
bezier_list.MoveToFirst();
if(bezier_list.number_of_elements == 0)
{
active=0;
return;
}
// Check that approx Hit is in direction of ray
const G4Point3D& Pt = rayref.GetStart();
const G4Vector3D& Dir = rayref.GetDir();
G4Point3D TestPoint = (0.00001*Dir) + Pt;
G4BezierSurface* Bsrf = (G4BezierSurface*)bezier_list.GetSurface(0);
G4Point3D AveragePoint = Bsrf->AveragePoint();
G4double TestDistance = TestPoint.distance2(AveragePoint);
if(TestDistance > distance)
// Hit behind ray starting point, no intersection.
active=0;
}
void G4BSplineSurface::AddHit(G4double u, G4double v)
{
if(Hit == (G4UVHit*)0)
{
first_hit = new G4UVHit(u,v);
first_hit->next = (G4UVHit*)0;
Hit = first_hit;
}
else
{
Hit->next = new G4UVHit(u,v);
Hit = Hit->next;
Hit->next=(G4UVHit*)0;
}
}
void G4BSplineSurface::ProjectNURBSurfaceTo2D
(const G4Plane& plane1, const G4Plane& plane2,
register G4ProjectedSurface* proj_srf)
{
// Projects the nurb surface so that the z-axis = ray.
/* L. Broglia
G4Point* tmp = (G4Point*)&ctl_points->get(0,0);
*/
G4PointRat tmp = ctl_points->GetRat(0,0);
int rational = tmp.GetType();// Get the type of control point
register G4Point3D psrfcoords;
register int rows = ctl_points->GetRows();
register int cols = ctl_points->GetCols();
for (register int i=0; i< rows; i++)
for(register int j=0; j < cols;j++)
{
if ( rational==4 ) // 4 coordinates
{
G4PointRat& srfcoords = ctl_points->GetRat(i, j);
// L. Broglia
// Changes for new G4PointRat
// Calculate the x- and y-coordinates for the new
// 2-D surface.
psrfcoords.setX(( srfcoords.x() * plane1.a
+srfcoords.y() * plane1.b
+srfcoords.z() * plane1.c
-srfcoords.w() * plane1.d));
psrfcoords.setY(( srfcoords.x() * plane2.a
+srfcoords.y() * plane2.b
+srfcoords.z() * plane2.c
-srfcoords.w() * plane2.d));
proj_srf->ctl_points->put(i,j,psrfcoords);
}
else // 3 coordinates
{
G4Point3D srfcoords = ctl_points->Get3D(i, j);
psrfcoords.setX(( srfcoords.x() * plane1.a
+srfcoords.y() * plane1.b
+srfcoords.z() * plane1.c
- plane1.d));
psrfcoords.setY(( srfcoords.x() * plane2.a
+srfcoords.y() * plane2.b
+srfcoords.z() * plane2.c
- plane2.d));
proj_srf->ctl_points->put(i,j,psrfcoords);
}
}
}
/* L. Broglia
Changes for new G4PointRat
G4Point& G4BSplineSurface::InternalEvalCrv(int i, G4ControlPoints* crv)*/
G4PointRat& G4BSplineSurface::InternalEvalCrv(int i, G4ControlPoints* crv)
{
if ( ord <= 1 )
return crv->GetRat(i, k_index);
register int j = k_index;
while ( j > (k_index - ord + 1))
{
register G4double k1, k2;
k1 = tmp_knots->GetKnot((j + ord - 1));
k2 = tmp_knots->GetKnot(j);
if ((abs(k1 - k2)) > kCarTolerance )
{
/* L. Broglia
register G4PointRat* pts1 = &crv->get(i,j-1);
register G4PointRat* pts2 = &crv->get(i,j );
if(pts1->GetType()==3)
{
crv->CalcValues(k1, param, *(G4Point3D*)pts1, k2, *(G4Point3D*)pts2);
crv->put(0, j, *(G4Point3D*)pts2);
}
else
{
crv->CalcValues(k1, param, *(G4PointRat*)pts1, k2, *(G4PointRat*)pts2);
crv->put(0, j, *(G4PointRat*)pts2);
}
*/
register G4PointRat* pts1 = &crv->GetRat(i,j-1);
register G4PointRat* pts2 = &crv->GetRat(i,j );
}
j--;
}
ord = ord-1;
return InternalEvalCrv(0, crv); // Recursion
}
G4Point3D G4BSplineSurface::BSEvaluate()
{
register int i;
register int row_size = ctl_points->GetRows();
register G4ControlPoints *diff_curve;
register G4ControlPoints* curves;
G4Point3D result;
/* L. Broglia
G4Point* tmp = (G4Point*)&ctl_points->get(0,0);
*/
G4PointRat* tmp = &ctl_points->GetRat(0,0);
register int point_type = tmp->GetType();
diff_curve = new G4ControlPoints(point_type, row_size, 1);
k_index = u_knots->GetKnotIndex(Hit->u, GetOrder(ROW) );
ord = GetOrder(ROW);
if(k_index==-1)
{
delete diff_curve;
active = 0;
return result;
}
curves=new G4ControlPoints(*ctl_points);
tmp_knots = u_knots;
param = Hit->u;
if(point_type == 4)
{
for ( i = 0; i < row_size; i++)
{
ord = GetOrder(ROW);
register G4PointRat rtr_pt = (G4PointRat&) InternalEvalCrv(i, curves);
diff_curve->put(0,i,rtr_pt);
}
k_index = v_knots->GetKnotIndex( Hit->v, GetOrder(COL) );
if(k_index==-1)
{
delete diff_curve;
delete curves;
active = 0;
return result;
}
ord = GetOrder(COL);
tmp_knots = v_knots;
param = Hit->v;
// Evaluate the diff_curve...
G4PointRat rat_result = (G4PointRat&) InternalEvalCrv(0, diff_curve);
// Calc the 3D values.
// L. Broglia
// Changes for new G4PointRat
result.setX(rat_result.x()/rat_result.w());
result.setY(rat_result.y()/rat_result.w());
result.setZ(rat_result.z()/rat_result.w());
}
else
if(point_type == 3)
{
for ( i = 0; i < row_size; i++)
{
ord = GetOrder(ROW);
G4Point3D rtr_pt = (G4Point3D&) InternalEvalCrv(i, curves);
diff_curve->put(0,i,rtr_pt);
}
k_index = v_knots->GetKnotIndex( Hit->v, GetOrder(COL) );
if(k_index==-1)
{
delete diff_curve;
delete curves;
active = 0;
return result;
}
ord = GetOrder(COL);
tmp_knots = v_knots;
param = Hit->v;
// Evaluate the diff_curve...
result = (G4Point3D&) InternalEvalCrv(0, diff_curve);
}
delete diff_curve;
delete curves;
closest_hit = result;
return result;
}
G4Point3D G4BSplineSurface::Evaluation(const G4Ray& rayref)
{
// Delete old UVhits
G4UVHit* temphit=Hit;
while(Hit!=(G4UVHit*)0)
{
Hit=Hit->next;
delete temphit;
temphit=Hit;
}
delete temphit;
// Get the real Hit point
closest_hit = FinalIntersection();
// The following part (commented out) is old bullshit
// Chech that Hit is not in a void i.e. InnerBoundary.
// for(int a=0; a<NumberOfInnerBoundaries;a++)
// if(InnerBoundary[a]->Inside(closest_hit, rayref))
// {
// Active(0);
// Distance(kInfinity);
// return closest_hit;
// }
return closest_hit;
}
G4double G4BSplineSurface::ClosestDistanceToPoint(const G4Point3D& Pt)
{
G4double PointDistance=0;
PointDistance = ctl_points->ClosestDistanceToPoint(Pt);
return PointDistance;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,12 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4BoundedSurface.cc,v 2.3 1998/10/20 16:33:42 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4BoundedSurface.hh"
@@ -0,0 +1,322 @@
#include "G4BoundingBox3D.hh"
#include "geomdefs.hh"
const G4BoundingBox3D G4BoundingBox3D::
space( G4Point3D(-kInfinity, -kInfinity, -kInfinity),
G4Point3D(+kInfinity, +kInfinity, +kInfinity) );
/////////////////////////////////////////////////////////////////////////////
G4BoundingBox3D::G4BoundingBox3D() { distance =0; }
G4BoundingBox3D::G4BoundingBox3D(const G4Point3D& p1, const G4Point3D& p2)
{
Init(p1, p2);
}
G4BoundingBox3D::G4BoundingBox3D(const G4Point3D& p)
{
Init(p);
}
G4BoundingBox3D::~G4BoundingBox3D() {}
void G4BoundingBox3D::Init(const G4Point3D& p1, const G4Point3D& p2)
{
// L. Broglia
// Maybe temporary
// Create a BBox bigger than the reality
box_min.setX( min(p1.x(), p2.x()) - kCarTolerance );
box_min.setY( min(p1.y(), p2.y()) - kCarTolerance );
box_min.setZ( min(p1.z(), p2.z()) - kCarTolerance );
box_max.setX( max(p1.x(), p2.x()) + kCarTolerance );
box_max.setY( max(p1.y(), p2.y()) + kCarTolerance );
box_max.setZ( max(p1.z(), p2.z()) + kCarTolerance );
// Calc half spaces
GeantBox = (box_max - box_min)*0.5;
MiddlePoint = (box_min + box_max)*0.5;
distance = 0;
}
void G4BoundingBox3D::Init(const G4Point3D& p)
{
box_min= box_max= MiddlePoint= p;
GeantBox= G4Point3D(0, 0, 0);
distance= 0;
}
/////////////////////////////////////////////////////////////////////////////
void G4BoundingBox3D::Extend(const G4Point3D& p)
{
// L. Broglia
// Maybe temporary
// Create a BBox bigger than the reality
if (p.x() < box_min.x())
box_min.setX( p.x() - kCarTolerance );
else if (p.x() > box_max.x())
box_max.setX( p.x() + kCarTolerance );
if (p.y() < box_min.y())
box_min.setY( p.y() - kCarTolerance );
else if (p.y() > box_max.y())
box_max.setY( p.y() + kCarTolerance );
if (p.z() < box_min.z())
box_min.setZ( p.z() - kCarTolerance );
else if (p.z() > box_max.z())
box_max.setZ( p.z() + kCarTolerance );
// L. Broglia
// Now re-calculate GeantBox and MiddlePoint
GeantBox = (box_max - box_min)*0.5;
MiddlePoint = (box_min + box_max)*0.5;
}
////////////////////////////////////////////////////////////////////////////
int G4BoundingBox3D::Test(const G4Ray& rayref)
{
const G4Point3D& tmp_ray_start = rayref.GetStart();
const G4Vector3D& tmp_ray_dir = rayref.GetDir();
G4Point3D ray_start = tmp_ray_start ;
G4Vector3D ray_dir = tmp_ray_dir ;
G4double rayx,rayy,rayz;
rayx = ray_start.x();
rayy = ray_start.y();
rayz = ray_start.z();
// Test if ray starting point is in the bbox or not
if((rayx < box_min.x()) || (rayx > box_max.x()) ||
(rayy < box_min.y()) || (rayy > box_max.y()) ||
(rayz < box_min.z()) || (rayz > box_max.z()) )
{
// Outside, check for intersection with bbox
// Adapt ray_starting point to box
const G4Point3D ray_start2 = ray_start - MiddlePoint;
distance = DistanceToIn(ray_start2, ray_dir);
if(!distance)
test_result = 0; // Miss
else
test_result = 1; // Starting point outside box & hits box
}
else
{
// Inside
// G4cout << "\nRay starting point Inside bbox.";
test_result = 1;
distance = 0;
}
return test_result;
}
///////////////////////////////////////////////////////////////////////////////
// Does an intersection exist?
//
// ALGORITHM:
//
// Check that if point lies outside x/y/z extent of box, travel is towards
// the box (ie. there is a possiblity of an intersection)
int G4BoundingBox3D::BoxIntersect(const G4Point3D& gbox,
const G4Point3D& p ,
const G4Vector3D& v ) const
{
G4double safx, safy, safz;
G4double fdx, fdy, fdz;
fdx = GeantBox.x();
fdy = GeantBox.y();
fdz = GeantBox.z();
safx=fabs(p.x())-fdx; // minimum distance to x surface of shape
safy=fabs(p.y())-fdy;
safz=fabs(p.z())-fdz;
// Will we Intersect?
// If safx/y/z is >=0 the point is outside/on the box's x/y/z extent.
// If both p.X()/y/z and v.X()/y/z repectively are both positive/negative,
// travel is in a G4ThreeVec away from the shape.
if ( ( (p.x()*v.x()>=0.0 ) && safx>0.0 ) ||
( (p.y()*v.y()>=0.0 ) && safy>0.0 ) ||
( (p.z()*v.z()>=0.0 ) && safz>0.0 ) )
return 0; // No intersection
else
return 1; // Possible intersection
}
///////////////////////////////////////////////////////////////////////////////
// Distance to in
// Calculate distance to box from outside - return kBig if no intersection
//
// ALGORITHM:
//
// Check that if point lies outside x/y/z extent of box, travel is towards
// the box (ie. there is a possiblity of an intersection)
//
// Calculate pairs of minimum and maximum distances for x/y/z travel for
// intersection with the box's x/y/z extent.
// If there is a valid intersection, it is given by the maximum min distance
// (ie. distance to satisfy x/y/z intersections) *if* <= minimum max distance
// (ie. distance after which 1+ of x/y/z intersections not satisfied)
//
// NOTE:
//
// `Inside' safe - meaningful answers given if point is Inside the exact
// shape.
//G4double G4BoundingBox::distance_to_in(const G4Point3d& gbox, const G4Point3d& p, const G4ThreeVec& v) const
G4double G4BoundingBox3D::DistanceToIn(const G4Point3D& p,
const G4Vector3D& v) const
{
G4double safx, safy, safz, snxt = 0; // snxt = default return value
G4double smin, sminx, sminy, sminz;
G4double smax, smaxx, smaxy, smaxz;
G4double stmp;
G4double kBig = 10e20;
G4double fdx,fdy,fdz;
fdx = GeantBox.x();
fdy = GeantBox.y();
fdz = GeantBox.z();
safx = fabs(p.x())-fdx; // minimum distance to x surface of shape
safy = fabs(p.y())-fdy;
safz = fabs(p.z())-fdz;
// Will we Intersect?
// If safx/y/z is >=0 the point is outside/on the box's x/y/z extent.
// If both p.X()/y/z and v.X()/y/z repectively are both positive/negative,
// travel is in a G4ThreeVec away from the shape.
if ( ( ( p.x()*v.x()>=0.0 ) && safx>0.0) ||
( ( p.y()*v.y()>=0.0 ) && safy>0.0) ||
( ( p.z()*v.z()>=0.0 ) && safz>0.0) )
return snxt;
// Compute min / max distance for x/y/z travel:
if (safx<0.0)
{
// Inside x extent => Calc distance until trajectory leaves extent
sminx=0.0;
if (v.x())
smaxx = fdx/fabs(v.x()) - p.x()/v.x();
else
smaxx = kBig;
}
else
{
// Outside extent or on boundary
if (v.x()==0)
return snxt; // Travel parallel
else
{
stmp = fabs(v.x());
sminx = safx/stmp;
smaxx = (fdx+fabs(p.x()))/stmp;
}
}
if (safy<0.0)
{
// Inside y extent => Calc distance until trajectory leaves extent
sminy=0.0;
if (v.y())
smaxy = fdy/fabs(v.y()) - p.y()/v.y();
else
smaxy = kBig;
}
else
{
// Outside extent or on boundary
if (v.y()==0)
return snxt; // Travel parallel
else
{
stmp = fabs(v.y());
sminy = safy/stmp;
smaxy = (fdy+fabs(p.y()))/stmp;
}
}
if (safz<0.0)
{
// Inside z extent => Calc distance until trajectory leaves extent
sminz=0.0;
if (v.z())
smaxz = fdz/fabs(v.z()) - p.z()/v.z();
else
smaxz = kBig;
}
else
{
// Outside extent or on boundary
if (v.z()==0)
return snxt; // Travel parallel
else
{
stmp = fabs(v.z());
sminz = safz/stmp;
smaxz = (fdz+fabs(p.z()))/stmp;
}
}
// Find minimum allowed Dist given min/max pairs
if (sminx>sminy)
smin = sminx; // MAX(sminx,sminy,sminz)
else
smin = sminy;
if (sminz>smin)
smin=sminz;
if (smaxx<smaxy)
smax = smaxx; // MIN(smaxx,smaxy,smaxz)
else
smax = smaxy;
if (smaxz<smax)
smax = smaxz;
// If smin <= kCarTolerance then only clipping `tolerant' Area
// -> no intersection
G4double kCarTolerance = 0;
if (smin>kCarTolerance && smin<=smax)
snxt=smin;
return snxt;
}
@@ -0,0 +1,67 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4CircularCurve.cc,v 2.4 1998/10/20 16:33:43 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4CircularCurve.hh"
#include "G4Ellipse.hh"
// G4CircularCurve
G4CircularCurve::G4CircularCurve() {}
G4CircularCurve::~G4CircularCurve() {}
//////////////////////////////////////////////////////////////////////////////
void G4CircularCurve::InitBounded()
{
// the bbox must include the start and endpoints as well as the
// extreme points if they lie on the curve
bBox.Init(GetStart(), GetEnd());
// the parameter values
// belonging to the points with an extreme x, y and z coordinate
for (G4int i=0; i<3; i++)
{
G4double u = atan2(position.GetPY()(i), position.GetPX()(i));
if (IsPOn(u))
bBox.Extend(GetPoint(u));
if (IsPOn(u+pi))
bBox.Extend(GetPoint(u+pi));
}
}
//////////////////////////////////////////////////////////////////////////////
G4Curve* G4CircularCurve::Project(const G4Transform3D& tr)
{
G4Ellipse e;
e.Init(position, radius, radius);
e.SetBounds(GetPStart(), GetPEnd());
return e.Project(tr);
}
//////////////////////////////////////////////////////////////////////////////
G4bool G4CircularCurve::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
// The tangent is computed from the 3D point representation
// for all conics. An alternaive implementation (based on
// the parametric point) might be worthwhile adding
// for efficiency.
const G4Axis2Placement3D& pos= *(GetPosition());
G4Point3D p= pos.GetToPlacementCoordinates() * cp.GetPoint();
v= -p.y()*pos.GetPX() + p.x()*pos.GetPY();
return true;
}
@@ -0,0 +1,107 @@
#include "G4CompositeCurve.hh"
#include "G4Line.hh"
G4CompositeCurve::G4CompositeCurve(){}
G4CompositeCurve::G4CompositeCurve(const G4Point3DVector& vertices)
{
G4CurveVector cv;
G4Line* l;
for (G4int i=0; i<vertices.length(); i++)
{
G4Point3D p1= vertices[i];
G4Point3D p2= vertices[(i+1) % vertices.length()];
G4Line* l= new G4Line;
l->Init(p1, p2-p1);
l->SetBounds(p1, p2);
cv.insert(l);
}
Init(cv);
}
G4CompositeCurve::~G4CompositeCurve(){}
G4Curve* G4CompositeCurve::Project(const G4Transform3D& tr)
{
G4CurveVector newSegments;
for (G4int i=0; i<segments.entries(); i++)
{
G4Curve* c= segments[i]->Project(tr);
if (c==0)
{
newSegments.clearAndDestroy();
return 0;
}
newSegments.insert(c);
}
G4CompositeCurve* r= new G4CompositeCurve;
r->Init(newSegments);
return r;
}
void G4CompositeCurve::IntersectRay2D(const G4Ray& ray,
G4CurveRayIntersection& is)
{
is.Reset();
for (G4int i=0; i<segments.entries(); i++)
{
G4Curve& c= *(segments(i));
G4CurveRayIntersection isTmp(c, ray);
c.IntersectRay2D(ray, isTmp);
if (isTmp.GetDistance() < is.GetDistance())
is= isTmp;
}
lastIntersection= is;
}
G4bool G4CompositeCurve::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
if (lastIntersection.GetDistance() == kInfinity)
return false;
return lastIntersection.GetCurve().Tangent(lastIntersection, v);
// should be true
// cp is ignored for the moment
}
void G4CompositeCurve::InitBounded()
{
const G4BoundingBox3D* b= segments[0]->BBox();
bBox.Init(b->GetBoxMin(), b->GetBoxMax());
for (G4int i=1; i<segments.entries(); i++)
{
b= segments[i]->BBox();
bBox.Extend(b->GetBoxMin());
bBox.Extend(b->GetBoxMax());
}
// init for efficient parameter <-> 3D point conversions
}
@@ -0,0 +1,34 @@
#include "G4Conic.hh"
// G4Conic
G4Conic::G4Conic (): pShift(0) {}
G4Conic::G4Conic (STEPentity& Ent){};
G4Conic::~G4Conic() {}
/*
void G4ConicalCurve::ProjectCurve(const G4Plane& Pl1, const G4Plane& Pl2)
{
// Curve start
Project(ProjStart, Start, Pl1, Pl2);
// Curve end
Project(ProjEnd, End, Pl1, Pl2);
// Placement
Position.ProjectPlacement(Pl1,Pl2);
}
int G4ConicalCurve::HitPartOfCurve(G4double Angle, G4double Solution, const G4Point2d& ProjHit)
{
// Check if Solution1 is part of the curve i.e. in the "pie"
G4double TmpSol1 = Solution - ProjHit.X();
G4Point2d ArcHit1(TmpSol1, ProjHit.Y());
G4double Cross1 = CrossProduct( ProjStart, ArcHit1);
G4double Cross2 = CrossProduct( ArcHit1 , ProjEnd);
if( (Angle<=0 && Cross1<=0 && Cross2 <=0) ||
(Angle> 0 && !(Cross1>=0 && Cross2 >=0)) )
// Solution1 is on the curve
return 1;
return 0;
}
*/
@@ -0,0 +1,552 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4ConicalSurface.cc,v 2.6 1998/11/13 13:58:30 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
/* /usr/local/gismo/repo/geometry/G4ConicalSurface.cc,v 1.6 1994/08/03 17:15:01 burnett Exp */
// File: G4ConicalSurface.cc
// Author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// G4ConicalSurface::G4ConicalSurface()
// G4ConicalSurface::G4ConicalSurface( const G4Vector3D& o,
// const G4Vector3D& a, G4double e )
// G4ConicalSurface::PrintOn( ostream& os ) const
// G4ConicalSurface::HowNear( const G4Vector3D& x ) const
// G4ConicalSurface::distanceAlongRay( int which_way, const Ray* ry,
// G4Vector3D& p ) const
// G4ConicalSurface::Inside( const G4Vector3D& x ) const
// G4ConicalSurface::WithinBoundary( const G4Vector3D& x ) const
// G4ConicalSurface::SetAngle( G4double e )
//
// End ---------------------------------------------------------------
#include "G4ConicalSurface.hh"
#include "G4Sort.hh"
#include "G4Globals.hh"
G4ConicalSurface::G4ConicalSurface() : G4Surface()
{
// default constructor
// default axis is ( 1.0, 0.0, 0.0 ), default angle is 1.0 radians
axis = G4Vector3D( 1.0, 0.0, 0.0 );
angle = 1.0;
}
G4ConicalSurface::G4ConicalSurface( const G4Point3D& o,
const G4Vector3D& a,
G4double e ) //: G4Surface( o )
{
// Normal constructor
// require axis to be a unit vector
/* L. Broglia
G4double amag = a.Magnitude();
include/G4ThreeVec.hh: G4double Magnitude() const
{ return sqrt( x*x + y*y + z*z ); }
This function is mag2 for HepThreeVector
*/
G4double amag = a.mag2();
if ( amag != 0.0 )
/* L. Broglia
axis = a / amag; // this makes the axis a unit vector
*/
axis = a*(1/amag);
else {
G4cerr << "Error in G4ConicalSurface::G4ConicalSurface"
<<"--axis has zero length\n"
<< "\tDefault axis ( 1.0, 0.0, 0.0 ) is used.\n";
axis = G4Vector3D( 1.0, 0.0, 0.0 );
}
// Require angle to range from 0 to PI/2
if ( ( e > 0.0 ) && ( e < ( 0.5 * M_PI ) ) )
angle = e;
else {
G4cerr << "Error in G4ConicalSurface::G4ConicalSurface"
<< "--asked for angle out of allowed range of 0 to PI/2\n"
<< "\tDefault angle of 1.0 is used.\n";
angle = 1.0;
}
}
void G4ConicalSurface::CalcBBox()
{
// Created by L. Broglia
// copy of G4FPlane::CalcBBox()
bbox= new G4BoundingBox3D(surfaceBoundary.BBox().GetBoxMin(),
surfaceBoundary.BBox().GetBoxMax());
}
void G4ConicalSurface::PrintOn( ostream& os ) const
{
// printing function using C++ ostream class
os << "G4ConicalSurface surface with origin: " << origin << "\t"
<< "angle: " << angle << " radians \tand axis " << axis << "\n";
}
G4double G4ConicalSurface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to the semi-infinite G4ConicalSurface.
// The distance will be positive if the point is Inside the G4ConicalSurface,
// negative if the point is outside.
// Note that this may not be correct for a bounded conical object
// subclassed to G4ConicalSurface.
G4Vector3D d = x - origin;
G4double l = d * axis;
G4Vector3D q = origin + l * axis;
G4Vector3D v = x - q;
/* L. Broglia
G4double Dist = ( l * tan( angle ) - v.Magnitude() ) * cos ( angle );
*/
G4double Dist = ( l*tan(angle) - v.mag2() ) * cos(angle);
return Dist;
}
int G4ConicalSurface::Intersect( const G4Ray& ry )
{
// Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4ConicalSurface. The input variable which_way should be set to +1 to
// indicate leaving a G4ConicalSurface, -1 to indicate entering a
// G4ConicalSurface.
// p is the point of intersection of the Ray with the G4ConicalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4ConicalSurface at the intersection point, it will not leave the
// G4ConicalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4ConicalSurface at the intersection point, it will not enter the
// G4ConicalSurface.
// This method is called by all finite shapes sub-classed to
// G4ConicalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
int which_way = -1; //Originally a parameter.Read explanation above.
distance = FLT_MAXX;
// G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
// p = lv;
closest_hit = lv;
// Origin and G4Vector3D unit vector of Ray.
// G4Vector3D x = ry->position();
G4Vector3D x = ry.GetStart();
// G4Vector3D dhat = ry->direction( 0.0 );
G4Vector3D dhat = ry.GetDir();
// Cone angle and axis unit vector.
G4double ta = tan( GetAngle() );
G4Vector3D ahat = GetAxis();
int isoln = 0,
maxsoln = 2;
// array of solutions in distance along the Ray
// G4double s[2] = { -1.0, -1.0 };
G4double s[2];
s[0] = -1.0;
s[1] = -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D gamma = x - GetOrigin();
G4double T = 1.0 + ta * ta;
G4double ga = gamma * ahat;
G4double da = dhat * ahat;
G4double A = 1.0 - T * da * da;
G4double B = 2.0 * ( gamma * dhat - T * ga * da );
G4double C = gamma * gamma - T * ga * ga;
// if quadratic term vanishes, just do the simple solution
if ( fabs( A ) < FLT_EPSILO )
{
if ( B == 0.0 )
return 1;
else
s[0] = -C / B;
}
// Normal quadratic case, no intersection if radical is less than zero
else
{
G4double radical = B * B - 4.0 * A * C;
if ( radical < 0.0 )
return 1;
else
{
G4double root = sqrt( radical );
s[0] = ( - B + root ) / ( 2. * A );
s[1] = ( - B - root ) / ( 2. * A );
}
}
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4ConicalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ )
{
if ( s[isoln] >= 0.0 )
{
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return 1;
distance = s[isoln];
closest_hit = ry.GetPoint( distance );
// Following line necessary to select non-reflective solutions.
if (( ahat * ( closest_hit - GetOrigin() ) > 0.0 ) &&
((( dhat * SurfaceNormal( closest_hit ) * which_way )) >= 0.0 ) &&
( fabs(HowNear( closest_hit )) < 0.1) )
return 1;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
distance = FLT_MAXX;
closest_hit = lv;
return 0;
}
/*
G4double G4ConicalSurface::distanceAlongHelix(int which_way, const Helix* hx,
G4Vector3D& p ) const
{ // Distance along a Helix to leave or enter a G4ConicalSurface.
// The input variable which_way should be set to +1 to
// indicate leaving a G4ConicalSurface, -1 to indicate entering a
// G4ConicalSurface.
// p is the point of intersection of the Helix with the G4ConicalSurface.
// If the G4Vector3D of the Helix is opposite to that of the Normal to
// the G4ConicalSurface at the intersection point, it will not leave the
// G4ConicalSurface.
// Similarly, if the G4Vector3D of the Helix is along that of the Normal
// to the G4ConicalSurface at the intersection point, it will not enter the
// G4ConicalSurface.
// This method is called by all finite shapes sub-classed to
// G4ConicalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
// Possible negative distance solutions are discarded.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
p = lv;
int isoln = 0, maxsoln = 4;
// Array of solutions in turning angle
// G4double s[4] = { -1.0, -1.0, -1.0, -1.0 };
G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
// Flag set to 1 if exact solution is found
int exact = 0;
// Helix parameters
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D oh = hx->position(); // origin of Helix
G4Vector3D dh = hx->direction( 0.0 ); // initial G4Vector3D of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.Magnitude();
G4double rhp = rh / prpmag;
// G4ConicalSurface parameters
G4double ta = tan( GetAngle() ); // tangent of angle of G4ConicalSurface
G4Vector3D oc = GetOrigin(); // origin of G4ConicalSurface
G4Vector3D ac = GetAxis(); // axis of G4ConicalSurface
// Calculate quantities of use later on
G4Vector3D alpha = rhp * prp;
G4Vector3D beta = rhp * dh;
G4Vector3D gamma = oh - oc;
G4double T = 1.0 + ta * ta;
G4double gc = gamma * ac;
G4double bc = beta * ac;
// General approximate solution for sin(s)-->s and cos(s)-->1-s**2/2,
// keeping only terms to second order in s
G4double A = gamma * alpha - T * ( gc * alpha * ac - bc * bc ) +
beta * beta;
G4double B = 2.0 * ( gamma * beta - gc * bc * T );
G4double C = gamma * gamma - gc * gc * T;
// Solution for no quadratic term
if ( fabs( A ) < FLT_EPSILO )
{
if ( B == 0.0 )
return Dist;
else
s[0] = -C / B;
}
// General quadratic solutions
else {
G4double radical = B * B - 4.0 * A * C;
if ( radical < 0.0 )
// Radical is less than zero, either there is no intersection, or the
// approximation doesn't hold, so try a cruder technique to find a
// possible intersection point using the gropeAlongHelix function.
s[0] = gropeAlongHelix( hx );
// Normal non-negative radical solutions
else {
G4double root = sqrt( radical );
s[0] = ( -B + root ) / ( 2.0 * A );
s[1] = ( -B - root ) / ( 2.0 * A );
if ( rh < 0.0 ) {
s[0] = -s[0];
s[1] = -s[1];
}
s[2] = s[0] + 2.0 * M_PI;
s[3] = s[1] + 2.0 * M_PI;
}
}
//
// Order the possible solutions by increasing turning angle
// (G4Sorting routines are in support/G4Sort.h).
G4Sort_double( s, isoln, maxsoln-1 );
//
// Now loop over each positive solution, keeping the first one (smallest
// distance along the Helix) which is within the boundary of the sub-shape.
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
// Calculate distance along Helix and position and G4Vector3D vectors.
Dist = s[isoln] * fabs( rhp );
p = hx->position( Dist );
G4Vector3D d = hx->direction( Dist );
if ( exact == 0 ) { // only for approximate solns
// Now do approximation to get remaining distance to correct this solution.
// Iterate it until the accuracy is below the user-set surface precision.
G4double delta = 0.;
G4double delta0 = FLT_MAXX;
int dummy = 1;
int iter = 0;
int in0 = Inside( hx->position() );
int in1 = Inside( p );
G4double sc = Scale();
while ( dummy ) {
iter++;
// Terminate loop after 50 iterations and Reset distance to large number,
// indicating no intersection with G4ConicalSurface.
// This generally occurs if the Helix curls too tightly to Intersect it.
if ( iter > 50 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Find distance from the current point along the above-calculated
// G4Vector3D using a Ray.
// The G4Vector3D of the Ray and the Sign of the distance are determined
// by whether the starting point of the Helix is Inside or outside of
// the G4ConicalSurface.
in1 = Inside( p );
if ( in1 ) { // current point Inside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( 1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( 1, r, p );
delete r;
}
}
else { // current point outside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( -1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( -1, r, p );
delete r;
}
}
// Test if distance is less than the surface precision, if so Terminate loop.
if ( fabs( delta / sc ) <= SURFACE_PRECISION )
break;
// If delta has not changed sufficiently from the previous iteration,
// skip out of this loop.
if ( fabs( ( delta - delta0 ) / sc ) <=
SURFACE_PRECISION )
break;
// If delta has increased in absolute value from the previous iteration
// either the Helix doesn't Intersect the G4ConicalSurface or the approximate solution
// is too far from the real solution. Try groping for a solution. If not
// found, Reset distance to large number, indicating no intersection with
// the G4ConicalSurface.
if ( fabs( delta ) > fabs( delta0 ) ) {
Dist = fabs( rhp ) *
gropeAlongHelix( hx );
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
}
else
p = hx->position( Dist );
break;
}
// Set old delta to new one.
delta0 = delta;
// Add distance to G4ConicalSurface to distance along Helix.
Dist += delta;
// Negative distance along Helix means Helix doesn't Intersect G4ConicalSurface.
// Reset distance to large number, indicating no intersection with G4ConicalSurface.
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Recalculate point along Helix and the G4Vector3D.
p = hx->position( Dist );
d = hx->direction( Dist );
} // end of while loop
} // end of exact == 0 condition
// Now have best value of distance along Helix and position for this
// solution, so test if it is within the boundary of the sub-shape
// and require that it point in the correct G4Vector3D with respect to
// the Normal to the G4ConicalSurface.
if ( ( Dist < FLT_MAXX ) &&
( ( hx->direction( Dist ) * Normal( p ) *
which_way ) >= 0.0 ) &&
( WithinBoundary( p ) == 1 ) )
return Dist;
} // end of if s[isoln] >= 0.0 condition
} // end of for loop over solutions
// If one gets here, there is no solution, so set distance along Helix
// and position to large numbers.
Dist = FLT_MAXX;
p = lv;
return Dist;
}
*/
G4Vector3D G4ConicalSurface::SurfaceNormal( const G4Point3D& p ) const
{
// return the Normal unit vector to the G4ConicalSurface at a point p
// on (or nearly on) the G4ConicalSurface
G4Vector3D s = p - origin;
/* L. Broglia
G4double smag = s.Magnitude();
*/
G4double smag = s.mag2();
// if the point happens to be at the origin, calculate a unit vector Normal
// to the axis, with zero z component
if ( smag == 0.0 )
{
G4double ax = axis.x();
G4double ay = axis.y();
G4double ap = sqrt( ax * ax + ay * ay );
if ( ap == 0.0 )
return G4Vector3D( 1.0, 0.0, 0.0 );
else
return G4Vector3D( ay / ap, -ax / ap, 0.0 );
}
// otherwise do the calculation of the Normal to the conical surface
else
{
G4double l = s * axis;
/* L. Broglia
s = s / smag;
*/
s = s*(1/smag);
G4Vector3D q = origin + l * axis;
G4Vector3D v = p - q;
/* L. Broglia
G4double sl = v.Magnitude() * sin( angle );
*/
G4double sl = v.mag2() * sin( angle );
G4Vector3D n = v - sl * s;
/* L. Broglia
G4double nmag = n.Magnitude();
*/
G4double nmag = n.mag2();
if ( nmag != 0.0 )
/* L. Broglia
n = n / nmag;
*/
n=n*(1/nmag);
return n;
}
}
int G4ConicalSurface::Inside ( const G4Vector3D& x ) const
{
// Return 0 if point x is outside G4ConicalSurface, 1 if Inside.
// Outside means that the distance to the G4ConicalSurface would be negative.
// Use the HowNear function to calculate this distance.
if ( HowNear( x ) >= -0.5*kCarTolerance )
return 1;
else
return 0;
}
int G4ConicalSurface::WithinBoundary( const G4Vector3D& x ) const
{
// return 1 if point x is on the G4ConicalSurface, otherwise return zero
// base this on the surface precision factor set in support/globals.h
if ( fabs( HowNear( x ) / Scale() ) <= SURFACE_PRECISION )
return 1;
else
return 0;
}
void G4ConicalSurface::SetAngle( G4double e )
{
// Reset the angle of the G4ConicalSurface
// Require angle to range from 0 to PI/2
// if ( ( e > 0.0 ) && ( e < ( 0.5 * M_PI ) ) )
if ( (e > 0.0) && (e <= ( 0.5 * M_PI)) )
angle = e;
// use old value (do not change angle) if out of the range,
//but Print message
else
{
G4cerr << "Error in G4ConicalSurface::SetAngle"
<< "--asked for angle out of allowed range of 0 to PI/2\n"
<< "\tDefault angle of " << angle << " is used.\n";
}
}
@@ -0,0 +1,141 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4ControlPoints.cc,v 2.6 1998/11/04 14:49:55 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// Modif 8 oct 98 : A.Floquet
// G4PointRat datas are made of
// . a point 3D
// . a additional value : the scale factor which is set to 1 by default
// G4ControlPoints includes only G4PointRat which in turn are made
// of G4Point3D
//
#include "G4ControlPoints.hh"
G4ControlPoints::G4ControlPoints()
{
nr=nc=0;
data=(G4PointRat**)0;
}
G4ControlPoints::G4ControlPoints( int rows, int columns)
{
nr=rows;
nc=columns;
data = (G4PointRat**) new G4PointRat *[nr*nc];
for(int a =0; a<nr*nc;a++)
data[a]=new G4PointRat;
}
G4ControlPoints::G4ControlPoints( int point_type, int rows, int columns)
{
// point_type is maintained only for compatibility
// G4ControlPoints is now a array of G4pointRat only
nr=rows;
nc=columns;
data = (G4PointRat**)new G4PointRat *[nr*nc];
for(int a = 0; a < nr*nc ; a++ )
data[a]=new G4PointRat;
}
G4ControlPoints::G4ControlPoints(const G4ControlPoints& old_points)
{
// copy constructor
nr = old_points.GetRows(); nc=old_points.GetCols();
data = (G4PointRat**)new G4PointRat *[nr*nc];
G4int a, b;
for (a = 0; a < nr*nc ; a++ )
data[a] = new G4PointRat;
for ( a = 0; a < nr ; a++ )
for ( b = 0; b < nc ; b++ )
put( a, b, old_points.GetRat(a,b));
}
G4ControlPoints::~G4ControlPoints()
{
for( int a = 0; a < nr*nc; a++)
delete data[a];
delete[] data;
}
void G4ControlPoints::SetWeights(G4double* weights)
{
for ( int a = 0; a < nr*nc; a++ )
(data[a])->setW(weights[a]);
}
void G4ControlPoints::CalcValues ( G4double k1, G4double param,
G4PointRat& pts1, G4double k2,
G4PointRat& pts2 )
{
pts2.setX(Calc(k1,param,pts1.x(),k2,pts2.x()));
pts2.setY(Calc(k1,param,pts1.y(),k2,pts2.y()));
pts2.setZ(Calc(k1,param,pts1.z(),k2,pts2.z()));
pts2.setW(Calc(k1,param,pts1.w(),k2,pts2.w()));
}
void G4ControlPoints::CalcValues(G4double k1, G4double param, G4Point3D& pts1,
G4double k2, G4Point3D& pts2)
{
pts2.setX(Calc(k1,param,pts1.x(),k2,pts2.x()));
pts2.setY(Calc(k1,param,pts1.y(),k2,pts2.y()));
pts2.setZ(Calc(k1,param,pts1.z(),k2,pts2.z()));
}
G4double G4ControlPoints::ClosestDistanceToPoint( const G4Point3D& Pt)
{
// Square distance
G4double PointDist=1.e20;
G4double TmpDist;
G4Point3D Pt2;
for(int a=0;a<nr;a++)
for(int b=0;b<nc;b++)
{
Pt2 = Get3D(a,b);
TmpDist = Pt.distance2(Pt2);
PointDist = ( PointDist > TmpDist ) ? TmpDist : PointDist;
}
return PointDist;
}
@@ -0,0 +1,17 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Curve.cc,v 2.3 1998/11/06 15:31:26 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4Curve.hh"
G4Curve::G4Curve():bounded(false),bBox(G4BoundingBox3D::space),
sameSense(true){}
G4Curve::~G4Curve(){}
@@ -0,0 +1,5 @@
#include "G4CurvePoint.hh"
const G4int G4CurvePoint::pFlag= 1;
const G4int G4CurvePoint::uFlag= 2;
const G4int G4CurvePoint::allFlags= 0xFF; // lots of bits...
@@ -0,0 +1,3 @@
#include "G4CurveRayIntersection.hh"
const G4int G4CurveRayIntersection::dFlag= 4;
@@ -0,0 +1,887 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4CylindricalSurface.cc,v 2.7 1998/12/10 11:02:55 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
/* /usr/local/gismo/repo/geometry/G4CylindricalSurface.cc,v 1.24 1994/08/03 17:15:09 burnett Exp */
// File: G4CylindricalSurface.cc
// Author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// G4CylindricalSurface::G4CylindricalSurface()
// G4CylindricalSurface::G4CylindricalSurface( const G4Vector3D& o,
// const G4Vector3D& a,
// G4double r )
// G4CylindricalSurface::PrintOn( ostream& os ) const
// G4CylindricalSurface::HowNear( const G4Vector3D& x ) const
// G4CylindricalSurface::distanceAlongRay( int which_way, const Ray* ry,
// G4Vector3D& p ) const
// G4CylindricalSurface::distanceAlongHelix( int which_way,
// const Helix* hx,
// G4Vector3D& p ) const
// G4CylindricalSurface::Normal( const G4Vector3D& p ) const
// G4CylindricalSurface::Inside( const G4Vector3D& x ) const
// G4CylindricalSurface::WithinBoundary( const G4Vector3D& x ) const
// G4CylindricalSurface::Scale() const
// G4CylindricalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, G4ThreeMat& m, int inverse )
// G4CylindricalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, int inverse )
// G4CylindricalSurface::SetRadius( G4double r )
// G4CylindricalSurface::gropeAlongHelix( const Helix* hx ) const
//
// End ---------------------------------------------------------------
#include "G4CylindricalSurface.hh"
#include "G4Sort.hh"
#include "G4Globals.hh"
G4CylindricalSurface::G4CylindricalSurface() : G4Surface()
{
// default constructor
// default axis is ( 1.0, 0.0, 0.0 ), default radius is 1.0
axis = G4Vector3D( 1.0, 0.0, 0.0 );
radius = 1.0;
}
G4CylindricalSurface::G4CylindricalSurface( const G4Vector3D& o,
const G4Vector3D& a,
G4double r ) //: G4Surface( o )
{
// Normal constructor
// require axis to be a unit vector
G4double amag = a.mag();
if ( amag != 0.0 )
axis = a * (1/ amag); // this makes the axis a unit vector
else
{
G4cerr << "Error in G4CylindricalSurface::G4CylindricalSurface--axis "
<<"has zero length\n"
<< "\tDefault axis ( 1.0, 0.0, 0.0 ) is used.\n";
axis = G4Vector3D( 1.0, 0.0, 0.0 );
}
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4CylindricalSurface::G4CylindricalSurface"
<< "--asked for negative radius\n"
<< "\tDefault radius of 1.0 is used.\n";
radius = 1.0;
}
origin =o;
}
void G4CylindricalSurface::PrintOn( ostream& os ) const
{
// printing function using C++ ostream class
os << "G4CylindricalSurface surface with origin: " << origin << "\t"
<< "radius: " << radius << "\tand axis " << axis << "\n";
}
//int G4Surface::Intersect(const G4Ray& ry)
int G4CylindricalSurface::Intersect(const G4Ray& ry)
{
// L. Broglia : copy of G4FCylindricalSurface::Intersect
// Distance along a Ray (straight line with G4ThreeVec) to leave or enter
// a G4CylindricalSurface. The input variable which_way should be set
// to +1 to indicate leaving a G4CylindricalSurface, -1 to indicate
// entering a G4CylindricalSurface.
// p is the point of intersection of the Ray with the G4CylindricalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4CylindricalSurface at the intersection point, it will not leave
// the G4CylindricalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4CylindricalSurface at the intersection point, it will not enter
// the G4CylindricalSurface.
// This method is called by all finite shapes sub-classed to
// G4CylindricalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
// int which_way = -1;
//Originally a parameter.Read explanation above.
int which_way=1;
if(!Inside(ry.GetStart()))
which_way = -1;
distance = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
closest_hit = lv;
// Origin and G4Vector3D unit vector of Ray.
G4Vector3D x = ry.GetStart();
G4Vector3D dhat = ry.GetDir();
// Axis unit vector of the G4CylindricalSurface.
G4Vector3D ahat = GetAxis();
int isoln = 0,
maxsoln = 2;
// array of solutions in distance along the Ray
G4double s[2];
s[0] = -1.0;
s[1] = -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double radiu = GetRadius();
//quit with no intersection if the radius of the G4CylindricalSurface is zero
// if ( radiu <= 0.0 )
// return 0;
G4double dsq = d * d;
G4double da = d * ahat;
G4double dasq = da * da;
G4double rsq = radiu * radiu;
G4double qsq = dsq - dasq;
G4double dira = dhat * ahat;
G4double a = 1.0 - dira * dira;
if ( a <= 0.0 )
return 0;
G4double b = 2. * ( d * dhat - da * dira );
G4double c = rsq - qsq;
G4double radical = b * b + 4. * a * c;
if ( radical < 0.0 )
return 0;
G4double root = sqrt( radical );
s[0] = ( - b + root ) / ( 2. * a );
s[1] = ( - b - root ) / ( 2. * a );
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4CylindricalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ )
{
if ( s[isoln] >= kCarTolerance*0.5 )
{
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return 0;
distance = s[isoln];
closest_hit = ry.GetPoint( distance );
G4double tmp = dhat * (Normal( closest_hit ));
if ((tmp * which_way) >= 0.0 )
if ( WithinBoundary( closest_hit ) == 1 )
distance = distance*distance;
return 1;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
distance = FLT_MAXX;
closest_hit = lv;
return 0;
}
G4double G4CylindricalSurface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to the infinite G4CylindricalSurface.
// The distance will be positive if the point is Inside the
// G4CylindricalSurface, negative if the point is outside.
// Note that this may not be correct for a bounded cylindrical object
// subclassed to G4CylindricalSurface.
G4Vector3D d = x - origin;
G4double dA = d * axis;
G4double rad = sqrt( d.mag2() - dA*dA );
G4double hownear = fabs( radius - rad );
return hownear;
}
/*
G4double G4CylindricalSurface::distanceAlongRay( int which_way, const G4Ray* ry,
G4Vector3D& p ) const
{ // Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4CylindricalSurface. The input variable which_way should be set to +1 to
// indicate leaving a G4CylindricalSurface, -1 to indicate entering a G4CylindricalSurface.
// p is the point of intersection of the Ray with the G4CylindricalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4CylindricalSurface at the intersection point, it will not leave the G4CylindricalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4CylindricalSurface at the intersection point, it will not enter the
// G4CylindricalSurface.
// This method is called by all finite shapes sub-classed to G4CylindricalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
p = lv;
// Origin and G4Vector3D unit vector of Ray.
G4Vector3D x = ry->Position();
G4Vector3D dhat = ry->Direction( 0.0 );
// Axis unit vector of the G4CylindricalSurface.
G4Vector3D ahat = GetAxis();
int isoln = 0, maxsoln = 2;
// array of solutions in distance along the Ray
// G4double s[2] = { -1.0, -1.0 };
G4double s[2];s[0] = -1.0; s[1]= -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double radius = GetRadius();
// quit with no intersection if the radius of the G4CylindricalSurface is zero
if ( radius <= 0.0 )
return Dist;
G4double dsq = d * d;
G4double da = d * ahat;
G4double dasq = da * da;
G4double rsq = radius * radius;
G4double qsq = dsq - dasq;
G4double dira = dhat * ahat;
G4double a = 1.0 - dira * dira;
if ( a <= 0.0 )
return Dist;
G4double b = 2. * ( d * dhat - da * dira );
G4double c = rsq - qsq;
G4double radical = b * b + 4. * a * c;
if ( radical < 0.0 )
return Dist;
G4double root = sqrt( radical );
s[0] = ( - b + root ) / ( 2. * a );
s[1] = ( - b - root ) / ( 2. * a );
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4CylindricalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return Dist;
Dist = s[isoln];
p = ry->Position( Dist );
if ( ( ( dhat * Normal( p ) * which_way ) >= 0.0 )
&& ( WithinBoundary( p ) == 1 ) )
return Dist;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
p = lv;
return FLT_MAXX;
}
*/
/*
G4double G4CylindricalSurface::distanceAlongHelix( int which_way, const Helix* hx,
G4Vector3D& p ) const
{ // Distance along a Helix to leave or enter a G4CylindricalSurface.
// The input variable which_way should be set to +1 to
// indicate leaving a G4CylindricalSurface, -1 to indicate entering a G4CylindricalSurface.
// p is the point of intersection of the Helix with the G4CylindricalSurface.
// If the G4Vector3D of the Helix is opposite to that of the Normal to
// the G4CylindricalSurface at the intersection point, it will not leave the G4CylindricalSurface.
// Similarly, if the G4Vector3D of the Helix is along that of the Normal
// to the G4CylindricalSurface at the intersection point, it will not enter the
// G4CylindricalSurface.
// This method is called by all finite shapes sub-classed to G4CylindricalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
// Possible negative distance solutions are discarded.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
G4Vector3D zerovec; // zero G4Vector3D
p = lv;
int isoln = 0, maxsoln = 4;
// Array of solutions in turning angle
// G4double s[4] = { -1.0, -1.0, -1.0, -1.0 };
G4double s[4];s[0]=-1.0;s[1]= -1.0;s[2]= -1.0;s[3]= -1.0;
// Flag set to 1 if exact solution is found
int exact = 0;
// Helix parameters
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D ah = hx->GetAxis(); // axis of Helix
G4Vector3D oh = hx->position(); // origin of Helix
G4Vector3D dh = hx->direction( 0.0 ); // initial G4Vector3D of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.Magnitude();
G4double rhp = rh / prpmag;
// G4CylindricalSurface parameters
G4double rc = GetRadius(); // radius of G4CylindricalSurface
if ( rc == 0.0 ) // quit if zero radius
return Dist;
G4Vector3D oc = GetOrigin(); // origin of G4CylindricalSurface
G4Vector3D ac = GetAxis(); // axis of G4CylindricalSurface
//
// Calculate quantities of use later on.
G4Vector3D alpha = rhp * prp;
G4Vector3D beta = rhp * dh;
G4Vector3D gamma = oh - oc;
// Declare variables used later on in several places.
G4double rcd2 = 0.0, alpha2 = 0.0;
G4double A = 0.0, B = 0.0, C = 0.0, F = 0.0, G = 0.0, H = 0.0;
G4double CoverB = 0.0, radical = 0.0, root = 0.0, s1 = 0.0, s2 = 0.0;
G4Vector3D ghat;
//
// Set flag for special cases
int special_case = 0; // 0 means general case
//
// Test to see if axes of Helix and G4CylindricalSurface are parallel, in which case
// there are exact solutions.
if ( ( fabs( ah.AngleBetween(ac) ) < FLT_EPSILO )
|| ( fabs( ah.AngleBetween(ac) - M_PI ) < FLT_EPSILO ) ) {
special_case = 1;
// If, in addition, gamma is a zero vector or is parallel to the G4CylindricalSurface
// axis, this simplifies the previous case.
if ( gamma == zerovec ) {
special_case = 3;
ghat = gamma;
}
else {
ghat = gamma / gamma.Magnitude();
if ( ( fabs( ghat.AngleBetween(ac) ) < FLT_EPSILO )
|| ( fabs( ghat.AngleBetween(ac) - M_PI ) <
FLT_EPSILO ) )
special_case = 3;
}
// Test to see if, in addition to the axes of the Helix and G4CylindricalSurface being
// parallel, the axis of the G4CylindricalSurface is perpendicular to the initial
// G4Vector3D of the Helix.
if ( fabs( ( ac * dh ) ) < FLT_EPSILO ) {
// And, if, in addition to all this, the difference in origins of the Helix
// and G4CylindricalSurface is perpendicular to the initial G4Vector3D of the Helix,
// there is a separate special case.
if ( fabs( ( ghat * dh ) ) < FLT_EPSILO )
special_case = 4;
}
} // end of section with axes of Helix and G4CylindricalSurface parallel
//
// Another peculiar case occurs if the axis of the G4CylindricalSurface and the initial
// G4Vector3D of the Helix line up and their origins are the same. This will
// require a higher order approximation than the general case.
if ( ( ( fabs( dh.AngleBetween(ac) ) < FLT_EPSILO )
|| ( fabs( dh.AngleBetween(ac) - M_PI ) < FLT_EPSILO ) )
&& ( gamma == zerovec ) )
special_case = 2;
//
// Now all the special cases have been tagged, so solutions are found
// for each case. Exact solutions are indicated by setting exact = 1.
// [For some reason switch doesn't work here, so do series of if's.]
if ( special_case == 0 ) { // approximate quadratic solutions
A = beta * beta - ( beta * ac ) * ( beta * ac )
+ gamma * alpha - ( gamma * ac ) * ( alpha * ac );
B = 2.0 * gamma * beta
- 2.0 * ( gamma * ac ) * ( beta * ac );
C = gamma * gamma
- ( gamma * ac ) * ( gamma * ac ) - rc * rc;
if ( fabs( A ) < FLT_EPSILO ) { // no quadratic term
if ( B == 0.0 ) // no intersection, quit
return Dist;
else // B != 0
s[0] = -C / B;
}
else { // A != 0, general quadratic solution
radical = B * B - 4.0 * A * C;
if ( radical < 0.0 ) // no solution, quit
return Dist;
root = sqrt( radical );
s[0] = ( -B + root ) / ( 2.0 * A );
s[1] = ( -B - root ) / ( 2.0 * A );
if ( rh < 0.0 ) {
s[0] = -s[0];
s[1] = -s[1];
}
s[2] = s[0] + 2.0 * M_PI;
s[3] = s[1] + 2.0 * M_PI;
}
}
//
else if ( special_case == 1 ) { // exact solutions
exact = 1;
H = 2.0 * ( alpha * alpha + gamma * alpha );
F = gamma * gamma
- ( ( gamma * ac ) * ( gamma * ac ) )
- rc * rc + H;
G = 2.0 * rhp *
( gamma * dh - ( gamma * ac ) * ( ac * dh ) );
A = G * G + H * H;
B = -2.0 * F * H;
C = F * F - G * G;
if ( fabs( A ) < FLT_EPSILO ) { // no quadratic term
if ( B == 0.0 ) // no intersection, quit
return Dist;
else { // B != 0
CoverB = -C / B;
if ( fabs( CoverB ) > 1.0 )
return Dist;
s[0] = acos( CoverB );
}
}
else { // A != 0, general quadratic solution
// Try a different method of calculation using F, G, and H to avoid
// precision problems.
// radical = B * B - 4.0 * A * C;
// if ( radical < 0.0 ) {
if ( fabs( H ) > FLT_EPSILO ) {
G4double r1 = G / H;
G4double r2 = F / H;
G4double radsq = 1.0 + r1*r1 - r2*r2;
if ( radsq < 0.0 )
return Dist;
root = G * sqrt( radsq );
G4double denominator = H * ( 1.0 + r1*r1 );
s1 = ( F + root ) / denominator;
s2 = ( F - root ) / denominator;
}
else
return Dist;
// } // end radical < 0 condition
// else {
// root = sqrt( radical );
// s1 = ( -B + root ) / ( 2.0 * A );
// s2 = ( -B - root ) / ( 2.0 * A );
// }
if ( fabs( s1 ) <= 1.0 ) {
s[0] = acos( s1 );
s[2] = 2.0 * M_PI - s[0];
}
if ( fabs( s2 ) <= 1.0 ) {
s[1] = acos( s2 );
s[3] = 2.0 * M_PI - s[1];
}
// Must take only solutions which satisfy original unsquared equation:
// Gsin(s) - Hcos(s) + F = 0. Take best solution of pair and set false
// solutions to -1. Only do this if the result is significantly different
// from zero.
G4double temp1 = 0.0, temp2 = 0.0;
G4double rsign = 1.0;
if ( rh < 0.0 ) rsign = -1.0;
if ( s[0] > 0.0 ) {
temp1 = G * rsign * sin( s[0] )
- H * cos( s[0] ) + F;
temp2 = G * rsign * sin( s[2] )
- H * cos( s[2] ) + F;
if ( fabs( temp1 ) > fabs( temp2 ) )
if ( fabs( temp1 ) > FLT_EPSILO )
s[0] = -1.0;
else
if ( fabs( temp2 ) > FLT_EPSILO )
s[2] = -1.0;
}
if ( s[1] > 0.0 ) {
temp1 = G * rsign * sin( s[1] )
- H * cos( s[1] ) + F;
temp2 = G * rsign * sin( s[3] )
- H * cos( s[3] ) + F;
if ( fabs( temp1 ) > fabs( temp2 ) )
if ( fabs( temp1 ) > FLT_EPSILO )
s[1] = -1.0;
else
if ( fabs( temp2 ) > FLT_EPSILO )
s[3] = -1.0;
}
}
}
//
else if ( special_case == 2 ) { // approximate solution
G4Vector3D e = ah.cross( ac );
G4double re = fabs( rhp ) * e.Magnitude();
s[0] = sqrt( 2.0 * rc / re );
}
//
else if ( special_case == 3 ) { // exact solutions
exact = 1;
alpha2 = alpha * alpha;
rcd2 = rhp * rhp * ( 1.0 - ( (ac*dh) * (ac*dh) ) );
A = alpha2 - rcd2;
B = - 2.0 * alpha2;
C = alpha2 + rcd2 - rc*rc;
if ( fabs( A ) < FLT_EPSILO ) { // no quadratic term
if ( B == 0.0 ) // no intersection, quit
return Dist;
else { // B != 0
CoverB = -C / B;
if ( fabs( CoverB ) > 1.0 )
return Dist;
s[0] = acos( CoverB );
}
}
else { // A != 0, general quadratic solution
radical = B * B - 4.0 * A * C;
if ( radical < 0.0 )
return Dist;
root = sqrt( radical );
s1 = ( -B + root ) / ( 2.0 * A );
s2 = ( -B - root ) / ( 2.0 * A );
if ( fabs( s1 ) <= 1.0 )
s[0] = acos( s1 );
if ( fabs( s2 ) <= 1.0 )
s[1] = acos( s2 );
}
}
//
else if ( special_case == 4 ) { // exact solution
exact = 1;
F = gamma * gamma
- ( ( gamma * ac ) * ( gamma * ac ) )
- rc * rc;
G = 2.0 * ( rhp * rhp + gamma * alpha );
if ( G == 0.0 ) // no intersection, quit
return Dist;
G4double cs = 1.0 + ( F / G );
if ( fabs( cs ) > 1.0 ) // no intersection, quit
return Dist;
s[0] = acos( cs );
}
//
else // shouldn't get here
return Dist;
//
// **************************************************************************
//
// Order the possible solutions by increasing turning angle
// (G4Sorting routines are in support/G4Sort.h).
G4Sort_double( s, isoln, maxsoln-1 );
//
// Now loop over each positive solution, keeping the first one (smallest
// distance along the Helix) which is within the boundary of the sub-shape.
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
// Calculate distance along Helix and position and G4Vector3D vectors.
Dist = s[isoln] * fabs( rhp );
p = hx->position( Dist );
G4Vector3D d = hx->direction( Dist );
if ( exact == 0 ) { // only for approximate solns
// Now do approximation to get remaining distance to correct this solution
// iterate it until the accuracy is below the user-set surface precision.
G4double delta = 0.0;
G4double delta0 = FLT_MAXX;
int dummy = 1;
int iter = 0;
int in0 = Inside( hx->position ( 0.0 ) );
int in1 = Inside( p );
G4double sc = Scale();
while ( dummy ) {
iter++;
// Terminate loop after 50 iterations and Reset distance to large number,
// indicating no intersection with G4CylindricalSurface.
// This generally occurs if the Helix curls too tightly to Intersect it.
if ( iter > 50 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Find distance from the current point along the above-calculated
// G4Vector3D using a Ray.
// The G4Vector3D of the Ray and the Sign of the distance are determined
// by whether the starting point of the Helix is Inside or outside of
// the G4CylindricalSurface.
in1 = Inside( p );
if ( in1 ) { // current point Inside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( 1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( 1, r, p );
delete r;
}
}
else { // current point outside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( -1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( -1, r, p );
delete r;
}
}
// Test if distance is less than the surface precision, if so Terminate loop.
if ( fabs( delta / sc ) <= SURFACE_PRECISION )
break;
// If delta has not changed sufficiently from the previous iteration,
// skip out of this loop.
if ( fabs( ( delta - delta0 ) / sc ) <=
SURFACE_PRECISION )
break;
// If delta has increased in absolute value from the previous iteration
// either the Helix doesn't Intersect the G4CylindricalSurface or the approximate solution
// is too far from the real solution. Try groping for a solution. If not
// found, Reset distance to large number, indicating no intersection with
// the G4CylindricalSurface.
if ( fabs( delta ) > fabs( delta0 ) ) {
Dist = fabs( rhp ) *
gropeAlongHelix( hx );
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
}
else
p = hx->position( Dist );
break;
}
// Set old delta to new one.
delta0 = delta;
// Add distance to G4CylindricalSurface to distance along Helix.
Dist += delta;
// Negative distance along Helix means Helix doesn't Intersect G4CylindricalSurface.
// Reset distance to large number, indicating no intersection with G4CylindricalSurface.
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Recalculate point along Helix and the G4Vector3D.
p = hx->position( Dist );
d = hx->direction( Dist );
} // end of while loop
} // end of exact == 0 condition
// Now have best value of distance along Helix and position for this
// solution, so test if it is within the boundary of the sub-shape
// and require that it point in the correct G4Vector3D with respect to
// the Normal to the G4CylindricalSurface.
if ( ( Dist < FLT_MAXX ) &&
( ( hx->direction( Dist ) * Normal( p ) *
which_way ) >= 0.0 ) &&
( WithinBoundary( p ) == 1 ) )
return Dist;
} // end of if s[isoln] >= 0.0 condition
} // end of for loop over solutions
// if one gets here, there is no solution, so set distance along Helix
// and position to large numbers
Dist = FLT_MAXX;
p = lv;
return Dist;
}
*/
G4Vector3D G4CylindricalSurface::Normal( const G4Vector3D& p ) const
{
// return the Normal unit vector to the G4CylindricalSurface
// at a point p on (or nearly on) the G4CylindricalSurface
G4Vector3D n = ( p - origin ) - ( ( p - origin ) * axis ) * axis;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/nmag);
return n;
}
G4Vector3D G4CylindricalSurface::SurfaceNormal( const G4Point3D& p ) const
{
// return the Normal unit vector to the G4CylindricalSurface at a point
// p on (or nearly on) the G4CylindricalSurface
G4Vector3D n = ( p - origin ) - ( ( p - origin ) * axis ) * axis;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/nmag);
return n;
}
int G4CylindricalSurface::Inside ( const G4Vector3D& x ) const
{
// Return 0 if point x is outside G4CylindricalSurface, 1 if Inside.
// Outside means that the distance to the G4CylindricalSurface would
// be negative.
// Use the HowNear function to calculate this distance.
if ( HowNear( x ) >= -0.5*kCarTolerance )
return 1;
else
return 0;
}
int G4CylindricalSurface::WithinBoundary( const G4Vector3D& x ) const
{
// return 1 if point x is on the G4CylindricalSurface, otherwise return zero
// base this on the surface precision factor set in support/globals.h
if ( fabs( HowNear( x ) / Scale() ) <= SURFACE_PRECISION )
return 1;
else
return 0;
}
G4double G4CylindricalSurface::Scale() const
{
// Returns the radius of a G4CylindricalSurface unless it is zero, in which
// case returns the arbitrary number 1.0.
// This is ok since derived finite-sized classes will overwrite this.
// Used for Scale-invariant tests of surface thickness.
if ( radius == 0.0 )
return 1.0;
else
return radius;
}
//void G4CylindricalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, G4ThreeMat& m, int inverse )
// // rotate G4CylindricalSurface first about global x-axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z-axis by angle gamma
// by creating and using G4ThreeMat objects in Surface::rotate
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
// the axis is rotated here, the origin is rotated by calling
// Surface::rotate
// G4Surface::rotate( alpha, beta, gamma, m, inverse );
// axis = m * axis;
//}
//void G4CylindricalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, int inverse )
//{ // rotate G4CylindricalSurface first about global x-axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z-axis by angle gamma
// by creating and using G4ThreeMat objects in Surface::rotate
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
// the axis is rotated here, the origin is rotated by calling
// Surface::rotate
// G4ThreeMat m;
// G4Surface::rotate( alpha, beta, gamma, m, inverse );
// axis = m * axis;
//}
void G4CylindricalSurface::SetRadius( G4double r )
{
// Reset the radius of the G4CylindricalSurface
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
// use old value (do not change radius) if out of the range,
// but Print message
else
{
G4cerr << "Error in G4CylindricalSurface::SetRadius"
<< "--asked for negative radius\n"
<< "\tDefault radius of " << radius << " is used.\n";
}
}
/*
G4double G4CylindricalSurface::gropeAlongHelix( const Helix* hx ) const
{ // Grope for a solution of a Helix intersecting a G4CylindricalSurface.
// This function returns the turning angle (in radians) where the
// intersection occurs with only positive values allowed, or -1.0 if
// no intersection is found.
// The idea is to start at the beginning of the Helix, then take steps
// of some fraction of a turn. If at the end of a Step, the current position
// along the Helix and the previous position are on opposite sides of the
// G4CylindricalSurface, then the solution must lie somewhere in between.
int one_over_f = 8; // one over fraction of a turn to go in each Step
G4double turn_angle = 0.0;
G4double dist_along = 0.0;
G4double d_new;
G4double fk = 1.0 / G4double( one_over_f );
G4double scal = Scale();
G4double d_old = HowNear( hx->position( dist_along ) );
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.Magnitude();
G4double rhp = rh / prpmag;
int max_iter = one_over_f * HELIX_MAX_TURNS;
// Take up to a user-settable number of turns along the Helix,
// groping for an intersection point.
for ( int k = 1; k < max_iter; k++ ) {
turn_angle = 2.0 * M_PI * k / one_over_f;
dist_along = turn_angle * fabs( rhp );
d_new = HowNear( hx->position( dist_along ) );
if ( ( d_old < 0.0 && d_new > 0.0 ) ||
( d_old > 0.0 && d_new < 0.0 ) ) {
d_old = d_new;
// Old and new points are on opposite sides of the G4CylindricalSurface, therefore
// a solution lies in between, use a binary search to pin the point down
// to the surface precision, but don't do more than 50 iterations.
int itr = 0;
while ( fabs( d_new / scal ) > SURFACE_PRECISION ) {
itr++;
if ( itr > 50 )
return turn_angle;
turn_angle -= fk * M_PI;
dist_along = turn_angle * fabs( rhp );
d_new = HowNear( hx->position( dist_along ) );
if ( ( d_old < 0.0 && d_new > 0.0 ) ||
( d_old > 0.0 && d_new < 0.0 ) )
fk *= -0.5;
else
fk *= 0.5;
d_old = d_new;
} // end of while loop
return turn_angle; // this is the best solution
} // end of if condition
} // end of for loop
// Get here only if no solution is found, so return -1.0 to indicate that.
return -1.0;
}
*/
@@ -0,0 +1,114 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Ellipse.cc,v 2.9 1998/12/08 14:04:24 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4Ellipse.hh"
// G4Ellipse
G4Ellipse::G4Ellipse(){}
G4Curve* G4Ellipse::Project(const G4Transform3D& tr)
{
G4Point3D newLocation = tr*position.GetLocation();
newLocation.setZ(0);
G4double axisZ = ( tr*position.GetPZ() ).unit().z();
if (abs(axisZ)<kAngTolerance)
return 0;
G4Vector3D newAxis(0, 0, axisZ>0? +1: -1);
// get the parameter of an endpoint of an axis
// (this is a point the distance of which from the center is extreme)
G4Vector3D xPrime= tr*position.GetPX();
xPrime.setZ(0);
G4Vector3D yPrime= tr*position.GetPY();
yPrime.setZ(0);
G4Vector3D a = semiAxis1*xPrime;
G4Vector3D b = semiAxis2*yPrime;
G4double u = atan2( 2*a*b, a.mag2()-b.mag2() ) / 2;
// get the coordinate axis directions and the semiaxis lengths
G4Vector3D sAxis1 = a*cos(u)+b*sin(u);
G4Vector3D sAxis2 = a*cos(u+pi/2)+b*sin(u+pi/2);
G4double newSemiAxis1 = sAxis1.mag();
G4double newSemiAxis2 = sAxis2.mag();
G4Vector3D newRefDirection = sAxis1;
// create the new ellipse
G4Axis2Placement3D newPosition;
newPosition.Init(newRefDirection, newAxis, newLocation);
G4Ellipse* r= new G4Ellipse;
r->Init(newPosition, newSemiAxis1, newSemiAxis2);
// introduce the shift in the parametrization
// maybe the Sign must be changed?
r->SetPShift(u);
// set the bounds when necessary
if (IsBounded())
r->SetBounds(GetPStart(), GetPEnd());
// L. Broglia
// copy sense of the curve
r->SetSameSense(GetSameSense());
return r;
}
G4Ellipse::~G4Ellipse(){}
void G4Ellipse::InitBounded()
{
// original implementation
// const G4Point3D& center = position.GetLocation();
// G4double maxEntent = max(semiAxis1, semiAxis2);
// G4Vector3D halfExtent(maxEntent, maxEntent, maxEntent);
// bBox.Init(center+halfExtent, center-halfExtent);
// the bbox must include the start and endpoints as well as the
// extreme points if they lie on the curve
bBox.Init(GetStart(), GetEnd());
// the parameter values
// belonging to the points with an extreme x, y and z coordinate
for (G4int i=0; i<3; i++)
{
G4double u= atan2(position.GetPY()(i)*semiAxis2,
position.GetPX()(i)*semiAxis1);
if (IsPOn(u))
bBox.Extend(GetPoint(u));
if (IsPOn(u+pi))
bBox.Extend(GetPoint(u+pi));
}
}
G4bool G4Ellipse::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
// The tangent is computed from the 3D point representation
// for all conics. An alternaive implementation (based on
// the parametric point) might be worthwhile adding
// for efficiency.
const G4Axis2Placement3D& pos = *(GetPosition());
G4Point3D p= pos.GetToPlacementCoordinates() * cp.GetPoint();
v=forTangent*p.y()*pos.GetPX() + p.x()*pos.GetPY();
if(GetSameSense())
v = -v;
return true;
}
@@ -0,0 +1,488 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4FConicalSurface.cc,v 2.16 1998/12/10 17:26:41 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
/* /usr/local/gismo/repo/geometry/G4FConicalSurface.cc,v 1.2 1993/02/05 00:38:39 alanb Exp */
// File: G4FConicalSurface.cc
// Author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// G4FConicalSurface::G4FConicalSurface( const G4Point3D& o,
// const G4Vector3D& a,
// G4double l, G4double sr, G4double lr )
// G4FConicalSurface::G4FConicalSurface( const G4FConicalSurface& c )
// G4FConicalSurface::PrintOn( ostream& os ) const
// G4FConicalSurface::operator==( const G4FConicalSurface& c )
// G4FConicalSurface::WithinBoundary( const G4Vector3D& x ) const
// G4FConicalSurface::Scale() const
// G4FConicalSurface::Area() const
// G4FConicalSurface::resize( G4double l, G4double sr, G4double lr )
//
// End ---------------------------------------------------------------
#include "G4FConicalSurface.hh"
#include "G4Sort.hh"
#include "G4CircularCurve.hh"
G4FConicalSurface::G4FConicalSurface(const G4Point3D& o,
const G4Vector3D& a,
G4double l,
G4double sr,
G4double lr
) //: G4ConicalSurface( o, a, 1.0 )
//: G4Surface( o ) doesn`t exist
{
// Make a G4FConicalSurface with origin o, axis a, length l, small radius
// sr, and large radius lr. The angle is calculated below and the SetAngle
// function of G4ConicalSurface is used to set it properly from the default
// value used above in the initialization.
// L. Broglia
// Position.SetSrfPoint(o);
// Position.SetAxis(a);
// Create the position with origin o, axis a, and a direction wich
// is not important
G4Vector3D dir(1,1,1);
Position.Init(dir, a, o);
origin = o;
// Require length to be nonnegative
// if ( l > 0.0 )
if (l >=0)
length = l;
else
{
G4cerr << "Error in G4FConicalSurface::G4FConicalSurface"
<< "--asked for negative length\n"
<< "\tDefault length of 0.0 is used.\n";
length = 0.0;
}
// Require small radius to be non-negative (i.e., allow zero)
if ( sr >= 0.0 )
small_radius = sr;
else
{
G4cerr << "Error in G4FConicalSurface::G4FConicalSurface"
<< "--asked for negative small radius\n"
<< "\tDefault value of 0.0 is used.\n";
small_radius = 0.0;
}
// Require large radius to exceed small radius
if ( lr > small_radius )
large_radius = lr;
else
{
G4cerr << "Error in G4FConicalSurface::G4FConicalSurface"
<< "--large radius must exceed small radius\n"
<< "\tDefault value of small radius +1 is used.\n";
large_radius = small_radius + 1.0;
}
// Calculate the angle of the G4ConicalSurface from the length and radii
tan_angle = ( large_radius - small_radius ) / length ;
}
G4FConicalSurface::G4FConicalSurface( const G4FConicalSurface& c )
//: G4ConicalSurface( c.origin, c.GetAxis(), c.GetAngle() )
{
// copy constructor
small_radius = c.small_radius;
large_radius = c.large_radius;
length = c.length;
tan_angle = c.tan_angle;
}
// Modified by L. Broglia (01/12/98)
void G4FConicalSurface::CalcBBox()
{
G4Point3D Max = -PINFINITY;
G4Point3D Min = PINFINITY;
G4Point3D Tmp;
G4double delta = small_radius / tan_angle;
G4Point3D Origin = Position.GetLocation();
G4Point3D EndOrigin = Origin + (length * Position.GetAxis());
G4double radius = large_radius;
G4Point3D Radius(radius, radius, 0);
// Default BBox
G4Point3D Tolerance(kCarTolerance, kCarTolerance, kCarTolerance);
G4Point3D BoxMin(Origin-Tolerance);
G4Point3D BoxMax(Origin+Tolerance);
bbox = new G4BoundingBox3D();
bbox->Init(BoxMin, BoxMax);
Tmp = (Origin - Radius);
bbox->Extend(Tmp);
Tmp = Origin + Radius;
bbox->Extend(Tmp);
Tmp = EndOrigin - Radius;
bbox->Extend(Tmp);
Tmp = EndOrigin + Radius;
bbox->Extend(Tmp);
}
void G4FConicalSurface::PrintOn( ostream& os ) const
{
// printing function using C++ ostream class
os << "G4FConicalSurface with origin: " << origin << "\t"
<< "and axis: " << Position.GetAxis() << "\n"
<< "\t small radius: " << small_radius
<< "\t large radius: " << large_radius
<< "\t and length: " << length << "\n";
}
int G4FConicalSurface::operator==( const G4FConicalSurface& c )
{
return ( origin == c.origin &&
Position.GetAxis() == c.Position.GetAxis() &&
small_radius == c.small_radius &&
large_radius == c.large_radius &&
length == c.length &&
tan_angle == c.tan_angle );
}
int G4FConicalSurface::WithinBoundary( const G4Vector3D& x ) const
{
// return 1 if point x is within the boundaries of the G4FConicalSurface
// return 0 otherwise (assume it is on the G4ConicalSurface)
G4Vector3D q = x - origin;
G4double qmag = q.mag();
G4double s = sin( atan2(large_radius-small_radius, length) );
G4double ls = small_radius / s;
G4double ll = large_radius / s;
if ( ( qmag >= ls ) && ( qmag <= ll ) )
return 1;
else
return 0;
}
G4double G4FConicalSurface::Scale() const
{
// Returns the small radius of a G4FConicalSurface unless it is zero, in
// which case returns the large radius.
// Used for Scale-invariant tests of surface thickness.
if ( small_radius == 0.0 )
return large_radius;
else
return small_radius;
}
G4double G4FConicalSurface::Area() const
{
// Returns the Area of a G4FConicalSurface
G4double rdif = large_radius - small_radius;
return ( M_PI * ( small_radius + large_radius ) *
sqrt( length * length + rdif * rdif ) );
}
void G4FConicalSurface::resize( G4double l, G4double sr, G4double lr )
{
// Resize a G4FConicalSurface to a new length l, and new radii sr and lr.
// Must Reset angle of the G4ConicalSurface as well based on these new
// values.
// Require length to be non-negative
// if ( l > 0.0 )
if ( l >= 0.0 )
length = l;
else
{
G4cerr << "Error in G4FConicalSurface::resize"
<< "--asked for negative length\n"
<< "\tOriginal value of " << length << " is retained.\n";
}
// Require small radius to be non-negative (i.e., allow zero)
if ( sr >= 0.0 )
small_radius = sr;
else
{
G4cerr << "Error in G4FConicalSurface::resize"
<< "--asked for negative small radius\n"
<< "\tOriginal value of " << small_radius
<< " is retained.\n";
}
// Require large radius to exceed small radius
if ( lr > small_radius )
large_radius = lr;
else
{
G4double r = small_radius + 1.0;
lr = ( large_radius <= small_radius ) ? r : large_radius;
large_radius = lr;
G4cerr << "Error in G4FConicalSurface::G4FConicalSurface"
<< "--large radius must exceed small radius\n"
<< "\tDefault value of " << large_radius << " is used.\n";
}
// Calculate the angle of the G4ConicalSurface from the length and radii
tan_angle = ( large_radius - small_radius ) / length ;
}
int G4FConicalSurface::Intersect(const G4Ray& ry )
{
// Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4FConicalSurface. The input variable which_way should be set to +1 to
// indicate leaving a G4ConicalSurface, -1 to indicate entering a
// G4ConicalSurface.
// p is the point of intersection of the Ray with the G4ConicalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4FConicalSurface at the intersection point, it will not leave the
// G4FConicalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4ConicalSurface at the intersection point, it will not enter the
// G4ConicalSurface.
// This method is called by all finite shapes sub-classed to
// G4ConicalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
int which_way;
if(Inside(ry.GetStart()))
which_way = 1;
else
which_way = -1;
distance = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
closest_hit = lv;
// Origin and G4Vector3D unit vector of Ray.
G4Vector3D x = ry.GetStart();
G4Vector3D dhat = ry.GetDir();
// Cone angle and axis unit vector.
G4double ta = tan_angle;
G4Vector3D ahat = Position.GetAxis();
int isoln = 0, maxsoln = 2;
// array of solutions in distance along the Ray
G4double s[2];
s[0]=-1.0;
s[1]=-1.0;
// L. Broglia
// calculate the two solutions (quadratic equation)
G4Vector3D gamma = x - Position.GetLocation();
G4double T = 1.0 + ta * ta;
G4double ga = gamma * ahat;
G4double da = dhat * ahat;
/*
G4double A = 1.0 - T * da * da;
G4double B = 2.0 * ( gamma * dhat - T * ga * da );
G4double C = gamma * gamma - T * ga * ga;
*/
G4double A = - 1.0 + T * da * da;
G4double B = 2 * ( -gamma * dhat + T * ga * da - large_radius * ta * da);
G4double C = ( -gamma * gamma + T * ga * ga
- 2 * large_radius * ta * ga
+ large_radius * large_radius );
// if quadratic term vanishes, just do the simple solution
if ( fabs( A ) < FLT_EPSILO )
if ( B == 0.0 )
return 1;
else
s[0] = -C / B;
// Normal quadratic case, no intersection if radical is less than zero
else
{
G4double radical = B * B - 4.0 * A * C;
if ( radical < 0.0 )
return 0;
else
{
G4double root = sqrt( radical );
s[0] = ( - B + root ) / ( 2. * A );
s[1] = ( - B - root ) / ( 2. * A );
}
}
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4ConicalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ )
{
if ( s[isoln] >= kCarTolerance*0.5 )
{
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return 0;
distance = s[isoln];
closest_hit = ry.GetPoint( distance );
// Following line necessary to select non-reflective solutions.
if ((( ahat * ( closest_hit - Position.GetLocation() ) > 0.0 ) &&
((( dhat * SurfaceNormal( closest_hit ) * which_way ) >= 0.0 )) &&
( fabs(HowNear( closest_hit )) < 0.1)) )
{
if ( WithinBoundary ( closest_hit ) == 1 )
{
distance = distance*distance;
return 1;
}
}
distance = distance*distance;
return 1;
}
else
if ( s[isoln] >= -kCarTolerance*0.5 )
{
// the point is on the surface
distance = 0;
return 1;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
distance = FLT_MAXX;
closest_hit = lv;
return 0;
}
G4double G4FConicalSurface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to the semi-infinite G4FConicalSurface.
// The distance will be positive if the point is Inside the G4ConicalSurface,
// negative if the point is outside.
// Note that this may not be correct for a bounded conical object
// subclassed to G4ConicalSurface.
G4Vector3D d = x - origin;
G4double dA = d * Position.GetAxis();
G4double rad = sqrt( d.mag2() - dA*dA );
G4double teta = atan2( (large_radius - small_radius) , length );
G4double radiu = fabs( rad - large_radius + dA*tan_angle );
G4double hownear ;
if (dA > length)
hownear =dA - length;
else if (dA < 0)
hownear =dA;
else
hownear = radiu * cos(teta);
return hownear;
}
// Add by L. Broglia
// Verify this function
G4Vector3D G4FConicalSurface::SurfaceNormal( const G4Point3D& p ) const
{
// return the Normal unit vector to the G4ConicalSurface at a point p
// on (or nearly on) the G4ConicalSurface
G4Vector3D s = p - origin;
G4double smag = s.mag2();
// if the point happens to be at the origin, calculate a unit vector Normal
// to the axis, with zero z component
if ( smag == 0.0 )
{
G4double ax = Position.GetAxis().x();
G4double ay = Position.GetAxis().y();
G4double ap = sqrt( ax * ax + ay * ay );
if ( ap == 0.0 )
return G4Vector3D( 1.0, 0.0, 0.0 );
else
return G4Vector3D( ay / ap, -ax / ap, 0.0 );
}
// otherwise do the calculation of the Normal to the conical surface
else
{
G4double l = s * Position.GetAxis();
s = s*(1/smag);
G4Vector3D q = origin + l * Position.GetAxis();
G4Vector3D v = p - q;
G4double sl = v.mag2() *
sin( atan2((large_radius - small_radius), length) );
G4Vector3D n = v - sl * s;
G4double nmag = n.mag2();
if ( nmag != 0.0 )
n=n*(1/nmag);
return n;
}
}
// Add by L. Broglia
int G4FConicalSurface::Inside ( const G4Vector3D& x ) const
{
// Return 0 if point x is outside G4ConicalSurface, 1 if Inside.
// Outside means that the distance to the G4ConicalSurface would be negative.
// Use the HowNear function to calculate this distance.
if ( HowNear( x ) >= -0.5*kCarTolerance )
return 1;
else
return 0;
}
@@ -0,0 +1,359 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4FCylindricalSurface.cc,v 2.14 1998/12/10 17:26:42 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
/* /usr/local/gismo/repo/geometry/FG4Cylinder.cc,v 1.1 1992/10/27 22:02:29 alanb Exp */
// File: FG4Cylinder.cc
// Author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// FG4Cylinder::FG4Cylinder( const G4Point3D& o, const G4ThreeVec& a,
// G4double r, G4double l )
// FG4Cylinder::FG4Cylinder( const FG4Cylinder& c )
// FG4Cylinder::PrintOn( ostream& os ) const
// FG4Cylinder::operator==( const FG4Cylinder& c )
// FG4Cylinder::WithinBoundary( const G4ThreeVec& x ) const
// FG4Cylinder::Scale() const
// FG4Cylinder::resize( G4double r, G4double l )
//
// End ---------------------------------------------------------------
#include "G4FCylindricalSurface.hh"
#include "G4Sort.hh"
G4FCylindricalSurface::G4FCylindricalSurface( const G4Point3D& o,
const G4Vector3D& a,
const G4double r,
const G4double l
)
{
// make a G4FCylindricalSurface with origin o, axis a,
// radius r, and length l
G4Vector3D dir(1,1,1);
Position.Init(dir, a, o);
origin = o;
// Require length to be positive or zero
// if ( l > 0.0 )
if ( l >= 0.0 )
length = l;
else
{
G4cerr << "Error in G4FCylindricalSurface::G4FCylindricalSurface"
<< "--asked for negative length\n"
<< "\tDefault length of 0.0 is used.\n";
length = 0.0;
}
// Require radius to be non-negative (i.e., allow zero)
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4FCylindricalSurface::G4FCylindricalSurface"
<< "--asked for negative radius\n"
<< "\tDefault value of 0.0 is used.\n";
radius = 0.0;
}
}
// copy constructor
G4FCylindricalSurface::G4FCylindricalSurface( const G4FCylindricalSurface& c )
{
length = c.length;
}
// printing function using C++ ostream class
void G4FCylindricalSurface::PrintOn( ostream& os ) const
{
os << "G4FCylindricalSurface with origin: " << origin << "\t"
<< "and axis: " << Position.GetAxis() << "\n"
<< "\t radius: " << radius << "\t and length: "
<< length << "\n";
}
int G4FCylindricalSurface::operator==( const G4FCylindricalSurface& c )
{
/* return ( origin == c.origin &&
axis == c.axis &&
radius == c.radius &&
length == c.length );*/
return 1;
}
// Added 18.7-95
// Modified by L. Broglia (01/12/98)
void G4FCylindricalSurface::CalcBBox()
{
// Finds the bounds of the surface iow
// calculates the bounds for a bounding box
// to the surface. The bounding box is used
// for a preliminary check of intersection.
G4Point3D Max = -PINFINITY;
G4Point3D Min = PINFINITY;
G4Point3D Tmp;
G4Point3D Origin = Position.GetLocation();
G4Point3D EndOrigin = Origin + (length*Position.GetAxis());
G4Point3D Radius(radius, radius, 0);
// Default BBox
G4Point3D Tolerance(kCarTolerance, kCarTolerance, kCarTolerance);
G4Point3D BoxMin(Origin-Tolerance);
G4Point3D BoxMax(Origin+Tolerance);
bbox = new G4BoundingBox3D();
bbox->Init(BoxMin, BoxMax);
Tmp = (Origin - Radius);
bbox->Extend(Tmp);
Tmp = Origin + Radius;
bbox->Extend(Tmp);
Tmp = EndOrigin - Radius;
bbox->Extend(Tmp);
Tmp = EndOrigin + Radius;
bbox->Extend(Tmp);
}
int G4FCylindricalSurface::Intersect( const G4Ray& ry )
{
// Distance along a Ray (straight line with G4ThreeVec) to leave or enter
// a G4CylindricalSurface. The input variable which_way should be set
// to +1 to indicate leaving a G4CylindricalSurface, -1 to indicate
// entering a G4CylindricalSurface.
// p is the point of intersection of the Ray with the G4CylindricalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4CylindricalSurface at the intersection point, it will not leave
// the G4CylindricalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4CylindricalSurface at the intersection point, it will not enter
// the G4CylindricalSurface.
// This method is called by all finite shapes sub-classed to
// G4CylindricalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
// int which_way = -1;
//Originally a parameter.Read explanation above.
int which_way=1;
if(!Inside(ry.GetStart()))
which_way = -1;
distance = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
closest_hit = lv;
// Origin and G4Vector3D unit vector of Ray.
G4Vector3D x = ry.GetStart();
G4Vector3D dhat = ry.GetDir();
// Axis unit vector of the G4CylindricalSurface.
G4Vector3D ahat = GetAxis();
int isoln = 0,
maxsoln = 2;
// array of solutions in distance along the Ray
G4double s[2];
s[0] = -1.0;
s[1] = -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double radiu = GetRadius();
//quit with no intersection if the radius of the G4CylindricalSurface is zero
// if ( radiu <= 0.0 )
// return 0;
G4double dsq = d * d;
G4double da = d * ahat;
G4double dasq = da * da;
G4double rsq = radiu * radiu;
G4double qsq = dsq - dasq;
G4double dira = dhat * ahat;
G4double a = 1.0 - dira * dira;
if ( a <= 0.0 )
return 0;
G4double b = 2. * ( d * dhat - da * dira );
G4double c = rsq - qsq;
G4double radical = b * b + 4. * a * c;
if ( radical < 0.0 )
return 0;
G4double root = sqrt( radical );
s[0] = ( - b + root ) / ( 2. * a );
s[1] = ( - b - root ) / ( 2. * a );
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4CylindricalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ )
{
if ( s[isoln] >= kCarTolerance*0.5 )
{
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return 0;
distance = s[isoln];
closest_hit = ry.GetPoint( distance );
G4double tmp = dhat * (Normal( closest_hit ));
// L. Broglia
// After this test, somtimes we have the distance,
// sometimes we have the squared distance
// For the moment, I delete this test
//if ((tmp * which_way) >= 0.0 )
//if ( WithinBoundary( closest_hit ) == 1 )
distance = distance*distance;
return 1;
}
else
if ( s[isoln] >= -kCarTolerance*0.5 )
{
// the point is on the surface
distance = 0;
return 1;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
distance = FLT_MAXX;
closest_hit = lv;
return 0;
}
G4double G4FCylindricalSurface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to the infinite G4CylindricalSurface.
// The distance will be positive if the point is Inside the
// G4FCylindricalSurface, negative if the point is outside.
G4Vector3D d = x - origin;
G4double dA = d * Position.GetAxis();
G4double rad = sqrt( d.mag2() - dA*dA );
G4double hownear;
if(dA > length)
hownear = length - dA;
else if(dA < 0)
hownear = dA;
else
hownear = radius - rad;
return hownear;
}
int G4FCylindricalSurface::WithinBoundary( const G4Vector3D& x ) const
{
// return 1 if point x is within the boundaries of the G4FCylindricalSurface
// return 0 otherwise (assume it is on the cylinder)
if ( fabs( ( x - Position.GetLocation()) * Position.GetAxis() ) <= 0.5 * length )
return 1;
else
return 0;
}
G4double G4FCylindricalSurface::Scale() const
{
// Returns the radius of a G4FCylindricalSurface unless it is zero, in which
// case returns the length.
// Used for Scale-invariant tests of surface thickness.
if ( radius == 0.0 )
return length;
else
return radius;
}
G4Vector3D G4FCylindricalSurface::SurfaceNormal( const G4Point3D& p ) const
{
// return the Normal unit vector to the G4CylindricalSurface at a point
// p on (or nearly on) the G4CylindricalSurface
G4Vector3D n = ( p - Position.GetLocation() ) -
( ( p - Position.GetLocation()) * Position.GetAxis() ) *Position.GetAxis();
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/nmag);
return n;
}
int G4FCylindricalSurface::Inside ( const G4Vector3D& x ) const
{
// Return 0 if point x is outside G4CylindricalSurface, 1 if Inside.
// Outside means that the distance to the G4CylindricalSurface would
// be negative.
// Use the HowNear function to calculate this distance.
if ( HowNear( x ) >= -0.5*kCarTolerance )
return 1;
else
return 0;
}
void G4FCylindricalSurface::resize( G4double r, G4double l )
{
// Resize a G4FCylindricalSurface to a new radius r and new length l
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4FCylindricalSurface::resize"
<< "--asked for negative radius\n"
<< "\tOriginal value of " << radius << " is retained.\n";
}
// Require length to be positive
if ( l > 0.0 )
length = l;
else
{
G4cerr << "Error in G4FCylindricalSurface::resize"
<< "--asked for negative or zero length\n"
<< "\tOriginal value of " << length << " is retained.\n";
}
}
@@ -0,0 +1,304 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4FPlane.cc,v 2.30 1998/12/11 08:29:07 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4FPlane.hh"
#include "G4CompositeCurve.hh"
G4FPlane::G4FPlane( const G4Vector3D& direction,
const G4Vector3D& axis ,
const G4Point3D& Pt0 ):pplace(direction, axis, Pt0)
{
G4Point3D Pt1 = Pt0 + direction;
// The plane include direction and axis is the normal,
// so axis^direction is included in the plane
G4Point3D Pt2 = Pt0 + axis.cross(direction);
G4Ray::CalcPlane3Pts( Pl, Pt0, Pt1, Pt2 );
active = 1;
CalcNormal();
distance = kInfinity;
Type = 1;
}
G4FPlane::G4FPlane(const G4Point3DVector* pVec, const G4Point3DVector* iVec)
: pplace( (*pVec)[0]-(*pVec)[1], // direction
((*pVec)[pVec->length()-1]-(*pVec)[0])
.cross((*pVec)[0]-(*pVec)[1]), // axis
(*pVec)[0] ) // location
{
G4Ray::CalcPlane3Pts( Pl, (*pVec)[0], (*pVec)[1], (*pVec)[2] );
G4CurveVector bounds;
G4CompositeCurve* polygon;
projectedBoundary = new G4SurfaceBoundary;
polygon= new G4CompositeCurve(*pVec);
bounds.insert(polygon);
if (iVec)
{
polygon= new G4CompositeCurve(*iVec);
bounds.insert(polygon);
}
SetBoundaries(&bounds);
CalcNormal();
IsConvex();
distance = kInfinity;
Type=1;
}
void G4FPlane::CalcBBox()
{
// This is needed since the bounds are used for the Solid
// bbox calculation. The bbox test is NOT performed for
// planar surfaces.
// Finds the bounds of the G4Plane surface iow
// calculates the bounds for a bounding box
// to the surface. The bounding box is used
// for a preliminary check of intersection.
bbox= new G4BoundingBox3D(surfaceBoundary.BBox().GetBoxMin(),
surfaceBoundary.BBox().GetBoxMax());
}
void G4FPlane::CalcNormal()
{
/*
// Calc Normal for surface which is used for the projection
// Make planes
G4Vector3D norm;
G4Vector3D RefDirection = pplace.GetRefDirection();
G4Vector3D Axis = pplace.GetAxis();
// L. Broglia : before in G4Placement
if( RefDirection == Axis )
norm = RefDirection;
else
{
// L. Broglia : error on setY, and it`s better to use cross function
// norm.setX( RefDirection.y() * Axis.z() - RefDirection.z() * Axis.y() );
// norm.setY( RefDirection.x() * Axis.z() - RefDirection.z() * Axis.x() );
// norm.setZ( RefDirection.x() * Axis.y() - RefDirection.y() * Axis.x() );
norm = RefDirection.cross(Axis);
}
// const G4Point3D& tmp = pplace.GetSrfPoint();
const G4Point3D tmp = pplace.GetLocation();
*/
// L. Broglia
// The direction of the normal is the axis of his location
// Its sense depend on the orientation of the bounded curve
const G4Point3D tmp = pplace.GetLocation();
G4Vector3D norm;
G4int sense = GetSameSense();
if (sense)
norm = pplace.GetAxis();
else
norm = - pplace.GetAxis();
NormalX = new G4Ray(tmp, norm);
NormalX->RayCheck();
NormalX->CreatePlanes();
}
void G4FPlane::Project()
{
// Project
const G4Plane& Plane1 = NormalX->GetPlane(1);
const G4Plane& Plane2 = NormalX->GetPlane(2);
// probably not necessary
// projections of the boundary should be handled by the intersection
// OuterBoundary->ProjectBoundaryTo2D(Plane1, Plane2, 0);
}
int G4FPlane::IsConvex()
{
return -1;
}
int G4FPlane::Intersect(const G4Ray& rayref)
{
Intersected =1;
// closest_hit = pplace.EvaluateIntersection(rayref);
// L. Broglia : before in G4Placement
// s is solution, line is p + tq, n is G4Plane Normal, r is point on G4Plane
// all parameters are pointers to arrays of three elements
hitpoint = PINFINITY;
register G4double a, b, t;
register const G4Vector3D& RayDir = rayref.GetDir();
register const G4Point3D& RayStart = rayref.GetStart();
G4double dirx = RayDir.x();
G4double diry = RayDir.y();
G4double dirz = RayDir.z();
G4Vector3D norm = (*NormalX).GetDir();
G4Point3D srf_point = pplace.GetLocation();
b = norm.x() * dirx + norm.y() * diry + norm.z() * dirz;
if ( fabs(b) < 0.001 )
{
// G4cout << "\nLine is parallel to G4Plane.No Hit.";
}
else
{
G4double startx = RayStart.x();
G4double starty = RayStart.y();
G4double startz = RayStart.z();
a = norm.x() * (srf_point.x() - startx) +
norm.y() * (srf_point.y() - starty) +
norm.z() * (srf_point.z() - startz) ;
t = a/b;
// substitute t into line equation
// to calculate final solution
G4double solx,soly,solz;
solx = startx + t * dirx;
soly = starty + t * diry;
solz = startz + t * dirz;
if(((dirx < 0 && solx < startx)||(dirx >= 0 && solx >= startx))&&
((diry < 0 && soly < starty)||(diry >= 0 && soly >= starty))&&
((dirz < 0 && solz < startz)||(dirz >= 0 && solz >= startz)))
hitpoint= G4Point3D(solx,soly, solz);
}
// closest_hit is a public Point3D in G4Surface
closest_hit = hitpoint;
if(closest_hit.x() == kInfinity)
{
active=0;
Distance(kInfinity);
return 0;
}
else
{
Distance( RayStart.distance2(closest_hit) );
if(distance < kCarTolerance*0.5)
{
// the point is on the surface
active=1; //active=0;
Distance(0); //Distance(kInfinity);
return 1; //return 0;
}
G4Point3D hit = closest_hit;
// project the hit to the xy plane,
// with the same projection that took the boundary
// into projectedBoundary
G4Point3D projectedHit= pplace.GetToPlacementCoordinates() * hit;
// test ray from the hit on the xy plane
// check if it intersects the boundary
G4Ray testRay(projectedHit, G4Vector3D(1, 0, 0));
G4CurveRayIntersection is;
projectedBoundary->IntersectRay2D(testRay, is);
// if not, we are outside
if ( is.GetDistance() >= kInfinity )
{
active=0;
Distance(kInfinity);
return 0;
}
// if yes, we have to check on which side of the intersected
// curve the hit lies
G4Vector3D tangent;
projectedBoundary->Tangent(is, tangent);
// L. Broglia
// Now replace tangent into the pplace
tangent = pplace.GetFromPlacementCoordinates() * tangent;
// (let's assume that the tangent is defined)
// criterion for outside: (d x t).z() < 0
// d = hit - is & t = tangent
G4Point3D Is = pplace.GetFromPlacementCoordinates() * (is.GetPoint());
G4Vector3D d = hit - Is;
if ( (d.cross(tangent)).z() < 0 )
{
active=0;
Distance(kInfinity);
return 0;
}
// a real intersection point
return 1;
}
}
G4double G4FPlane::ClosestDistanceToPoint(const G4Point3D& Pt)
{
// Calculates signed distance of point Pt to G4Plane Pl
// Be careful, the equation of the plane is :
// ax + by + cz = d
return ( Pt.x()*Pl.a + Pt.y()*Pl.b + Pt.z()*Pl.c - Pl.d);
}
void G4FPlane::InitBounded()
{
// L. Broglia
projectedBoundary =
surfaceBoundary.Project( pplace.GetToPlacementCoordinates() );
}
G4double G4FPlane::HowNear( const G4Vector3D& x ) const
{
const G4Point3D Pt = x;
//G4double d = ClosestDistanceToPoint(Pt);
//return d;
return ( Pt.x()*Pl.a + Pt.y()*Pl.b + Pt.z()*Pl.c - Pl.d);
}
@@ -0,0 +1,128 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Hyperbola.cc,v 2.8 1998/10/29 17:49:38 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4Hyperbola.hh"
G4Hyperbola::G4Hyperbola(){}
G4Curve* G4Hyperbola::Project(const G4Transform3D& tr)
{
G4Exception("G4Hyperbola::Project");
G4Point3D newLocation= tr*position.GetLocation();
newLocation.setZ(0);
G4double axisZ= (tr*position.GetPZ()).unit().z();
if (abs(axisZ)<kAngTolerance)
{
return 0;
}
G4Vector3D newAxis(0, 0, axisZ>0? +1: -1);
// get the parameter of an endpoint of an axis
// (this is a point the distance of which from the center is extreme)
G4Vector3D xPrime = tr*position.GetPX();
xPrime.setZ(0);
G4Vector3D yPrime = tr*position.GetPY();
yPrime.setZ(0);
G4Vector3D a = semiAxis*xPrime;
G4Vector3D b = semiImagAxis*yPrime;
G4double xval = -2*a*b/(a.mag2()+b.mag2());
#ifdef WIN32
G4double u= (0.5*log((1+xval)/(1-xval)))/2;
#else
G4double u= atanh( xval ) / 2;
#endif
// get the coordinate axis directions and the semiaxis lengths
G4Vector3D sAxis= a*cosh(u)+b*sinh(u);
//!!!!!!!!!!!!
G4Vector3D sImagAxis= a*cosh(u+pi/2)+b*sinh(u+pi/2);
//!!!!!!!!!!!!
G4double newSemiAxis = sAxis.mag();
G4double newSemiImagAxis = sImagAxis.mag();
G4Vector3D newRefDirection = sAxis;
// create the new hyperbola
G4Axis2Placement3D newPosition;
newPosition.Init(newRefDirection, newAxis, newLocation);
G4Hyperbola* r= new G4Hyperbola;
r->Init(newPosition, newSemiAxis, newSemiImagAxis);
// introduce the shift in the parametrization
// maybe the Sign must be changed?
r->SetPShift(u);
// set the bounds when necessary
if (IsBounded())
r->SetBounds(GetPStart(), GetPEnd());
return r;
}
void G4Hyperbola::InitBounded()
{
// the bbox must include the start and endpoints as well as the
// extreme points if they lie on the curve
bBox.Init(GetStart(), GetEnd());
// the parameter values
// belonging to the points with an extreme x, y and z coordinate
for (G4int i=0; i<3; i++)
{
G4double x_i= position.GetPX()(i);
if (abs(x_i) <= kAngTolerance)
{
G4double tanhu= - (semiImagAxis*position.GetPY()(i)) / (semiAxis*x_i);
if (abs(tanhu)<=1)
{
#ifdef WIN32
G4double u= 0.5*log((1+tanhu)/(1-tanhu));
#else
G4double u= atanh(tanhu);
#endif
if (IsPOn(u)) bBox.Extend(GetPoint(u));
}
}
}
}
G4Hyperbola::~G4Hyperbola(){}
G4bool G4Hyperbola::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
// The tangent is computed from the 3D point representation
// for all conics. An alternaive implementation (based on
// the parametric point) might be worthwhile adding
// for efficiency.
const G4Axis2Placement3D& pos= *(GetPosition());
G4Point3D p= pos.GetToPlacementCoordinates() * cp.GetPoint();
v= forTangent*p.y()*pos.GetPX() + p.x()*pos.GetPY();
return true;
}
@@ -0,0 +1,145 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4KnotVector.cc,v 2.4 1998/10/20 16:33:51 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4KnotVector.hh"
G4KnotVector::G4KnotVector()
{
knots=(G4double*)0;
}
G4KnotVector::G4KnotVector(const int sz)
{
k_size=sz;
knots = new G4double[k_size];
for(int a=0;a<k_size;a++)
knots[a]=0;
}
G4KnotVector::~G4KnotVector() { delete [] knots;}
//Copy constructor
G4KnotVector::G4KnotVector(const G4KnotVector& old_kv)
{
k_size = old_kv.GetSize();
knots = new G4double[k_size];
for(register int a=0; a < old_kv.k_size; a++)knots[a]=old_kv.knots[a];
}
int G4KnotVector::GetKnotIndex(G4double k_value,const int order)
{
int i, knot_index;
G4double knt;
if ( k_value < ( knt = knots[order - 1]))
if (ApxEq( k_value, knt))
k_value = knt;
else
return -1;
if ( k_value > ( knt = knots[k_size - order + 1]))
if (ApxEq( k_value, knt))
k_value = knt;
else
return -1;
if ( k_value == knots[k_size - order + 1] )
knot_index = k_size - order - 1;
else if ( k_value == knots[ order - 1] )
knot_index = order - 1;
else
{
knot_index = 0;
for ( i = 0; i < k_size - 1; i++)
if((knots[i]<k_value) && (k_value <= knots[i+1]))
knot_index = i;
}
return knot_index;
}
G4KnotVector* G4KnotVector::MultiplyKnotVector(const int num,
const G4double val)
{
int n;
G4double* knots_to_add;
n = CheckKnotVector( val );
knots_to_add = new G4double[num-n];
for (int i = 0; i < num - n; i++)
knots_to_add[i] = val;
G4KnotVector* new_kv = new G4KnotVector();
new_kv->k_size = num - n + GetSize();
new_kv->knots = MergeKnotVector(knots_to_add, num-n);
delete [] knots_to_add;
return new_kv;
}
G4double* G4KnotVector::MergeKnotVector(const G4double* knots_to_add,
const int add_size )
{
G4double *newknots;
int kv1_ptr = 0,
kv2_ptr = 0,
newptr;
int old_size = k_size;
newknots = new G4double[k_size + add_size];
for ( newptr = 0; newptr < k_size+add_size; newptr++)
if ( kv1_ptr >= add_size )
newknots[newptr] = knots[kv2_ptr++];
else if ( kv2_ptr >= old_size )
newknots[newptr] = knots_to_add[kv1_ptr++];
else if ( knots_to_add[kv1_ptr] < knots[kv2_ptr])
newknots[newptr] = knots_to_add[kv1_ptr++];
else
newknots[newptr] = knots[kv2_ptr++];
return newknots;
}
int G4KnotVector::CheckKnotVector(const G4double val)
{
int num = 0;
for ( int i = 0; i < k_size; i++)
{
// if ( abs(val - knots[i]) < kCarTolerance)
if ( val == knots[i] )
num++;
}
return num;
}
void G4KnotVector::ExtractKnotVector( G4KnotVector* kv,
const int upper,const int lower)
{
delete[] kv->knots;
kv->k_size = upper-lower;
kv->knots = new G4double[kv->k_size];
for ( int i = lower; i < upper; i++)
kv->knots[i-lower] = knots[i];
}
@@ -0,0 +1,45 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Line.cc,v 2.6 1998/12/15 10:33:55 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4Line.hh"
G4Line::G4Line (){}
G4Line::~G4Line (){}
G4Curve* G4Line::Project(const G4Transform3D& tr)
{
G4Vector3D newDir= tr*dir;
if (abs(newDir.x())+abs(newDir.y()) < kCarTolerance)
return 0;
G4Point3D newPnt= tr*pnt;
newDir.setZ(0);
newPnt.setZ(0);
G4Line* r= new G4Line();
r->Init(newDir, newPnt);
r->SetBounds(GetPStart(), GetPEnd());
return r;
}
////////////////////////////////////////////////////////////////////////////
G4bool G4Line::Tangent(G4CurvePoint& cp, G4Vector3D& vec)
{
if(GetSameSense())
vec = -dir;
else
vec = dir;
return true;
}
@@ -0,0 +1,63 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4NISTStepReader.cc,v 2.4 1998/11/04 14:49:56 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4NISTStepReader.hh"
void G4NISTStepReader::ReadSTEPFile(G4String STEPfilename)
{
// Reads the Step file into the nist toolkit class library
// if the comments below look canned, it's because they're taken
// straight from the treg source... ;-)
// This has to be Done before anything else. This initializes
// all of the registry information for the schema you are using.
// The SchemaInit() function is generated by fedex_plus... see
// extern statement above.
Registry *registry = new Registry(SchemaInit);
// The nifty thing about the Registry is that it basically keeps a List
// of everything in your schema. What this means is that we can go
// through the Registry and instantiate, say, one of everything, without
// knowing at coding-time what entities there are to instantiate. So,
// this test could be linked with other class libraries produced from
// other schema, rather than the example, and run happily.
// InstMgr InstanceList;
STEPfile *sfile = new STEPfile(*registry, InstanceList);
// The STEPfile is actually an object that manages the relationship
// between what's instantiated in the instance manager, and how that
// information gets passed to the outside, e.g., a file on disk.
// First we're going to read in the data from the input STEPfile,
// and Print it to stdout
// Reading the STEPfile instantiates all the objects in it.
// The instances get pointers into the InstMgr, and each type
// and entity gets a pointer into the registry.
G4cout << "\n### Reading exchange file from " << STEPfilename << endl;
sfile->ReadExchangeFile(STEPfilename);
// Just checking... ;-)
G4cout << "\n### The InstMgr says there are ";
G4cout << InstanceList.InstanceCount() << " instantiated objects" << endl;
// G4cout << "\n### Here is the exchange file:" << endl << endl;
// sfile->WriteExchangeFile(G4cout);
delete sfile;
delete registry;
}
void G4NISTStepReader::SaveSTEPFile(){}
void G4NISTStepReader::UpdateSTEPFile(){}
@@ -0,0 +1,44 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4OsloMatrix.cc,v 2.1 1998/10/20 16:33:53 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4OsloMatrix.hh"
Matrix::Matrix()
{
nr=nc=0;
data=0;
}
Matrix::Matrix(int rows, int columns)
{
nr=rows;
nc=columns;
data = new G4double[nr*nc];
for(int a =0; a<nr*nc;a++)
data[a]=0;
}
Matrix::Matrix(G4double vec[])
{
nr = 4;
nc = 4;
data = new G4double[nr*nc];
for(int a=0;a<nr*nc;a++)
data[a]=vec[a];
}
Matrix::~Matrix(){;}
@@ -0,0 +1,92 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Parabola.cc,v 2.8 1998/10/29 17:49:38 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4Parabola.hh"
G4Parabola::G4Parabola(){}
G4Parabola::~G4Parabola(){}
G4Curve* G4Parabola::Project(const G4Transform3D& tr)
{
G4double axisZ= (tr*position.GetPZ()).unit().z();
if (abs(axisZ)<kAngTolerance)
return 0;
G4Vector3D newAxis(0, 0, axisZ>0? +1: -1);
G4Vector3D xPrime= tr*position.GetPX();
xPrime.setZ(0);
G4Vector3D yPrime= tr*position.GetPY();
yPrime.setZ(0);
G4double u= -(xPrime*yPrime)/xPrime.mag2();
G4Point3D newLocation= tr*position.GetLocation()+
focalDist*(u*u*xPrime+2*u*yPrime);
newLocation.setZ(0);
G4Vector3D newRefDirection= xPrime;
G4double newFocalDist= (focalDist*((2*u+1)*xPrime+2*yPrime)).mag()/sqrt(5.);
// create the new parabola
G4Axis2Placement3D newPosition;
newPosition.Init(newRefDirection, newAxis, newLocation);
G4Parabola* r= new G4Parabola;
r->Init(newPosition, newFocalDist);
// introduce the shift in the parametrization
// maybe the Sign must be changed?
r->SetPShift(u);
// set the bounds when necessary
if (IsBounded())
r->SetBounds(GetPStart(), GetPEnd());
return r;
}
void G4Parabola::InitBounded()
{
// the bbox must include the start and endpoints as well as the
// extreme points if they lie on the curve
bBox.Init(GetStart(), GetEnd());
// the parameter values
// belonging to the points with an extreme x, y and z coordinate
for (G4int i=0; i<3; i++)
{
G4double x_i= position.GetPX()(i);
if (abs(x_i) <= kAngTolerance)
{
G4double u= - position.GetPY()(i) / x_i;
if (IsPOn(u))
bBox.Extend(GetPoint(u));
}
}
}
G4bool G4Parabola::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
// The tangent is computed from the 3D point representation
// for all conics. An alternaive implementation (based on
// the parametric point) might be worthwhile adding
// for efficiency.
const G4Axis2Placement3D& pos= *(GetPosition());
G4Point3D p= pos.GetToPlacementCoordinates() * cp.GetPoint();
v= p.y()*pos.GetPX() + (2*focalDist)*pos.GetPY();
return true;
}
@@ -0,0 +1,76 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4PlacedSolid.cc,v 2.2 1998/10/29 17:49:39 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4PlacedSolid.hh"
G4PlacedSolid::G4PlacedSolid()
{
solid =0;
solidRotation =0;
solidTranslation =0;
}
G4PlacedSolid::G4PlacedSolid(G4BREPSolid* s, G4Axis2Placement3D* p)
{
solid =s;
if(p)
{
G4double x,y,z;
G4Point3D srfpoint = p->GetLocation();
x = srfpoint.x();
y = srfpoint.y();
z = srfpoint.z();
solidTranslation = new G4ThreeVector(x,y,z);
G4Vector3D tmpvec = p->GetAxis();
x = tmpvec.x();
y = tmpvec.y();
z = tmpvec.z();
G4ThreeVector x_axis(x,y,z);
if( (x<kCarTolerance)&&
(y<kCarTolerance)&&
(z<kCarTolerance) )
solidRotation=0;
else
{
tmpvec = p->GetRefDirection();
x = tmpvec.x();
y = tmpvec.y();
z = tmpvec.z();
G4ThreeVector y_axis(x,y,z);
solidRotation = new HepRotation();
solidRotation->rotateAxes(x_axis, y_axis, x_axis.cross(y_axis));
}
}
else
{
solidTranslation=0;
solidRotation=0;
}
}
G4PlacedSolid::~G4PlacedSolid()
{
//delete solid;
if(solidRotation)
delete solidRotation;
if(solidTranslation)
delete solidTranslation;
}
@@ -0,0 +1,44 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4PointRat.cc,v 2.2 1998/10/20 16:33:56 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
//
// Modif 8 oct 98 : A.Floquet
// G4PointRat datas are made of
// . a point 3D
// . a additional value : the scale factor which is set to 1 by default
//
#include "G4PointRat.hh"
G4PointRat::G4PointRat():pt3d(){s=1;}
G4PointRat::G4PointRat(const G4Point3D& tmp):pt3d(tmp){s=1;}
G4PointRat::~G4PointRat(){}
void G4PointRat::operator=(const G4PointRat& a)
{ pt3d.setX(a.x());
pt3d.setY(a.y());
pt3d.setZ(a.z());
s=a.w();
}
void G4PointRat::operator=(const G4Point3D& a)
{ pt3d = a;
s=1;
}
void G4PointRat::CopyRationalValue(const RealNode& RNode)
{
s = RNode.value;
}
@@ -0,0 +1,739 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4ProjectedSurface.cc,v 2.3 1998/10/20 16:33:56 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4ProjectedSurface.hh"
int G4ProjectedSurface::Splits=0;
G4ProjectedSurface::~G4ProjectedSurface()
{
delete u_knots;
delete v_knots;
delete ctl_points;
G4OsloMatrix* temp_oslo;
if(oslo_m!=(G4OsloMatrix*)0)
{
while(oslo_m->next != oslo_m)
{
temp_oslo = oslo_m;
oslo_m = oslo_m->next;
delete temp_oslo;
}
delete oslo_m;
}
delete bbox;
}
G4ProjectedSurface::G4ProjectedSurface()
{
distance = 0;
oslo_m =(G4OsloMatrix*)0;
}
G4ProjectedSurface::G4ProjectedSurface(const G4ProjectedSurface &tmp)
{
distance = tmp.distance;
oslo_m =(G4OsloMatrix*)0;
// next=this;
order[0] = tmp.order[0];
order[1] = tmp.order[1];
dir = tmp.dir;
u_knots = new G4KnotVector(*tmp.u_knots);
v_knots = new G4KnotVector(*tmp.v_knots);
ctl_points = new G4ControlPoints(*tmp.ctl_points);
bbox = new G4BoundingBox3D();
}
void G4ProjectedSurface::CopySurface()
// Copies the projected surface into a bezier surface
// and adds it to the List of bezier surfaces.
{
G4BezierSurface *bez = new G4BezierSurface();
bez->Distance(distance);
bez->PutOrder(0, order[0]);
bez->PutOrder(1, order[1]);
bez->Dir(dir);
bez->u_knots = new G4KnotVector(*u_knots);
bez->v_knots = new G4KnotVector(*v_knots);
bez->ctl_points = new G4ControlPoints(*ctl_points);
bezier_list->AddSurface(bez);
}
void G4ProjectedSurface::CalcBBox()
{
// Finds the bounds of the 2D-projected nurb iow
// calculates the bounds for a bounding rectangle
// to the surface. The bounding rectangle is used
// for a preliminary check of intersection.
// Loop to search the whole control point mesh
// for the minimum and maximum values for x and y.
G4double box_minx,box_miny,box_maxx,box_maxy;
box_minx = INFINITY;
box_miny = INFINITY;
box_maxx = -INFINITY;
box_maxy = -INFINITY;
G4double bminx,bminy,bmaxx,bmaxy,tmpx,tmpy;
bminx = box_minx; bminy = box_miny;
bmaxx = box_maxx; bmaxy = box_maxy;
for(register int a = ctl_points->GetRows()-1; a>=0;a--)
for(register int b = ctl_points->GetCols()-1; b>=0;b--)
{
/* L. Broglia
G4Point2d& tmp = (G4Point2d&)ctl_points->get(a,b);
*/
G4Point3D tmp = ctl_points->Get3D(a,b);
tmpx = tmp.x(); tmpy = tmp.y();
if(bminx > tmpx) box_minx=tmpx;
if(bmaxx < tmpx) box_maxx=tmpx;
if(bminy > tmpy) box_miny=tmpy;
if(bmaxy < tmpy) box_maxy=tmpy;
}
G4Point3D box_min(box_minx,box_miny);
G4Point3D box_max(box_maxx,box_maxy);
delete bbox;
bbox = new G4BoundingBox3D(box_min, box_max);
}
void G4ProjectedSurface::ConvertToBezier(G4SurfaceList& proj_list,
G4SurfaceList& bez_list)
{
projected_list = &proj_list;
bezier_list = &bez_list;
// Check wether the surface is a bezier surface by checking
// if internal knots exist.
if(CheckBezier())
{
// Make it a G4BezierSurface -object and add it to the bezier
// surface List
CopySurface();
// Retrieve a pointer to the newly added surface iow the
// last in the List
G4BezierSurface* bez_ptr = (G4BezierSurface*)bezier_list->GetLastSurface();
// Do the first clip to the bezier.
bez_ptr->ClipSurface();
G4double dMin = bez_ptr->SMin();
G4double dMax = bez_ptr->SMax();
G4double dMaxMinusdMin = dMax - dMin;
if(( dMaxMinusdMin > kCarTolerance ))
{
if( dMaxMinusdMin > 0.8 )
{
// The clipping routine selected a larger Area than one
// knot interval which indicates that we have a case of
// multiple intersections. The projected surface has to
// be split again in order to separate the intersections
// to different surfaces.
// Check tolerance of clipping
// G4cout << "\nClip Area too big -> Split";
dir = bez_ptr->dir;
bezier_list->RemoveSurface(bez_ptr);
SplitNURBSurface();
return;
//}
}
else
if( dMin > 0.0 || dMax < 0.0 )
{
// The ray intersects with the bounding box
// but not with the surface itself.
// G4cout << "\nConvex hull missed.";
bezier_list->RemoveSurface(bez_ptr);
return;
}
}
else
if(dMaxMinusdMin < kCarTolerance && dMaxMinusdMin > -kCarTolerance)
{
bezier_list->RemoveSurface(bez_ptr);
return;
}
bez_ptr->LocalizeClipValues();
bez_ptr->SetValues();
// Other G4ThreeVec clipping and testing.
bez_ptr->ChangeDir();//bez->dir = !bez_ptr->dir;
bez_ptr->ClipSurface();
// G4cout<<"\nSMIN: " << bez_ptr->smin << " SMAX: "
// << bez_ptr->smax << " DIR: " << bez_ptr->dir;
dMin = bez_ptr->SMin();
dMax = bez_ptr->SMax();
dMaxMinusdMin = dMax-dMin;
if((dMaxMinusdMin > kCarTolerance ))// ||
// (dMaxMinusdMin < -kCarTolerance))
{
if( (dMaxMinusdMin) > 0.8 )
{
// G4cout << "\nClip Area too big -> Split";
dir = bez_ptr->dir;//1.2 klo 18.30
// dir=!dir;
bezier_list->RemoveSurface(bez_ptr);
SplitNURBSurface();
return;
//}
}
else
if( dMin > 1.0 || dMax < 0.0 )
{
// G4cout << "\nConvex hull missed.";
bezier_list->RemoveSurface(bez_ptr);
return;
}
}
else
if(dMaxMinusdMin < kCarTolerance && dMaxMinusdMin > -kCarTolerance)
{
bezier_list->RemoveSurface(bez_ptr);
return;
}
bez_ptr->LocalizeClipValues();
bez_ptr->SetValues();
bez_ptr->CalcAverage();
}
else
{
// Split the surface into two new surfaces. The G4ThreeVec
// is set in the CheckBezier function.
// G4cout << "\nNot a bezier surface -> Split";
SplitNURBSurface();
}
}
int G4ProjectedSurface::CheckBezier()
{
// Checks if the surface is a bezier surface by
// checking wether internal knots exist. If no internal
// knots exist the quantity of knots is 2*order of the
// surface. Returns 1 if the surface
// is a bezier.
if( u_knots->GetSize() > (2.0 * GetOrder(ROW)))
{dir=0;return 0;}
if( v_knots->GetSize() > (2.0 * GetOrder(COL)))
{dir=1;return 0;}
return 1;
}
void G4ProjectedSurface::SplitNURBSurface()
{
// Divides the surface in two parts. Uses the oslo-algorithm to calculate
// the new knotvectors and controlpoints for the subsurfaces.
// G4cout << "\nProjected splitted.";
register G4double value;
register int i;
register int k_index;
register G4ProjectedSurface *srf1, *srf2;
register int nr,nc;
if ( dir == ROW )
{
value = u_knots->GetKnot((u_knots->GetSize()-1)/2);
for( i = 0; i < u_knots->GetSize(); i++)
if( (abs(value - u_knots->GetKnot(i))) < kCarTolerance )
{
k_index = i;
break;
}
if ( k_index == 0)
{
value = ( value + u_knots->GetKnot(u_knots->GetSize() -1))/2.0;
k_index = GetOrder(ROW);
}
new_knots = u_knots->MultiplyKnotVector(GetOrder(ROW), value);
ord = GetOrder(ROW);
CalcOsloMatrix();
srf1 = new G4ProjectedSurface(*this);
//srf1->dir=ROW;
srf1->dir=COL;
new_knots->ExtractKnotVector(srf1->u_knots,
k_index + srf1->GetOrder(ROW),0);
nr= srf1->v_knots->GetSize() - srf1->GetOrder(COL);
nc= srf1->u_knots->GetSize() - srf1->GetOrder(ROW);
delete srf1->ctl_points;
srf1->ctl_points= new G4ControlPoints(2, nr, nc);
srf2 = new G4ProjectedSurface(*this);
//srf2->dir = ROW;
srf2->dir = COL;
new_knots->ExtractKnotVector(srf2->u_knots,
new_knots->GetSize(), k_index);
nr= srf2->v_knots->GetSize() - srf2->GetOrder(COL);
nc= srf2->u_knots->GetSize() - srf2->GetOrder(ROW);
delete srf2->ctl_points;
srf2->ctl_points = new G4ControlPoints(2, nr, nc);
lower = 0;
upper = k_index;
MapSurface(srf1);
lower = k_index;
upper = new_knots->GetSize() - srf2->GetOrder(ROW);
MapSurface(srf2);
}
else // G4ThreeVec = col
{
value = v_knots->GetKnot((v_knots->GetSize() -1)/2);
for( i = 0; i < v_knots->GetSize(); i++)
if( (abs(value - v_knots->GetKnot(i))) < kCarTolerance )
{
k_index = i;
break;
}
if ( k_index == 0)
{
value = ( value + v_knots->GetKnot(v_knots->GetSize() -1))/2.0;
k_index = GetOrder(COL);
}
new_knots = v_knots->MultiplyKnotVector( GetOrder(COL), value );
ord = GetOrder(COL);
CalcOsloMatrix();
srf1 = new G4ProjectedSurface(*this);
//srf1->dir = COL;
srf1->dir = ROW;
new_knots->ExtractKnotVector(srf1->v_knots,
k_index + srf1->GetOrder(COL), 0);
nr = srf1->v_knots->GetSize() - srf1->GetOrder(COL);
nc = srf1->u_knots->GetSize() - srf1->GetOrder(ROW);
delete srf1->ctl_points;
srf1->ctl_points = new G4ControlPoints(2, nr, nc);
srf2 = new G4ProjectedSurface(*this);
//srf2->dir = COL;
srf2->dir = ROW;
new_knots->ExtractKnotVector(srf2->v_knots, new_knots->GetSize(), k_index);
nr = srf2->v_knots->GetSize() - srf2->GetOrder(COL);
nc = srf2->u_knots->GetSize() - srf2->GetOrder(ROW);
delete srf2->ctl_points;
srf2->ctl_points = new G4ControlPoints(2,nr, nc);
lower = 0;
upper = k_index;
MapSurface(srf1);
lower = k_index;
upper = new_knots->GetSize() - srf2->GetOrder(COL);
MapSurface(srf2);
}
// Check that surfaces are ok.
int col_size = srf1->ctl_points->GetCols();
int row_size = srf1->ctl_points->GetRows();
/* L. Broglia
// get three cornerpoints of the controlpoint mesh.
G4Point2d pt1 = srf1->ctl_points->get(0,0);
G4Point2d pt2 = srf1->ctl_points->get(0,col_size-1);
G4Point2d pt3 = srf1->ctl_points->get(row_size-1,0);
// Calc distance between points
G4double pointDist1 = pt1.Distance(pt2);
G4double pointDist2 = pt1.Distance(pt3);
*/
// get three cornerpoints of the controlpoint mesh.
G4Point3D pt1 = srf1->ctl_points->Get3D(0,0);
G4Point3D pt2 = srf1->ctl_points->Get3D(0,col_size-1);
G4Point3D pt3 = srf1->ctl_points->Get3D(row_size-1,0);
// Calc distance squared between points
G4double pointDist1 = pt1.distance2(pt2);
G4double pointDist2 = pt1.distance2(pt3);
// Add surfaces to List of projected surfaces
if(pointDist1 > kCarTolerance && pointDist2 > kCarTolerance)
projected_list->AddSurface(srf1);
else
delete srf1;
col_size = srf2->ctl_points->GetCols();
row_size = srf2->ctl_points->GetRows();
/* L. Broglia
// get three cornerpoints of the controlpoint mesh.
pt1 = srf2->ctl_points->get(0,0);
pt2 = srf2->ctl_points->get(0,col_size-1);
pt3 = srf2->ctl_points->get(row_size-1,0);
// Calc distance between points
pointDist1 = pt1.Distance(pt2);
pointDist2 = pt1.Distance(pt3);
*/
// get three cornerpoints of the controlpoint mesh.
pt1 = srf2->ctl_points->Get3D(0,0);
pt2 = srf2->ctl_points->Get3D(0,col_size-1);
pt3 = srf2->ctl_points->Get3D(row_size-1,0);
// Calc distance squared between points
pointDist1 = pt1.distance2(pt2);
pointDist2 = pt1.distance2(pt3);
// Add surfaces to List of projected surfaces
if(pointDist1 > kCarTolerance && pointDist2 > kCarTolerance)
projected_list->AddSurface(srf2);
else
delete srf2;
delete new_knots;
Splits++;
}
void G4ProjectedSurface::CalcOsloMatrix()
{
// This algorithm is described in the paper "Making the Oslo-algorithm
// more efficient" in SIAM J.NUMER.ANAL. Vol.23, No. 3, June '86
// Calculates the oslo-matrix , which is used in mapping the new
// knotvector- and controlpoint-values.
register G4KnotVector *ah;
static G4KnotVector *newknots;
register int i;
register int j;
register int mu, muprim;
register int v, p;
register int iu, il, ih, n1;
register int ahi;
register G4double beta1;
register G4double tj;
ah = new G4KnotVector(ord*(ord + 1)/2);
newknots = new G4KnotVector(ord * 2 );
n1 = new_knots->GetSize() - ord;
mu = 0;
if(oslo_m!=(G4OsloMatrix*)0)
{
G4OsloMatrix* tmp;
while(oslo_m!=oslo_m->next)
{
tmp=oslo_m->next;
delete oslo_m;
oslo_m=tmp;
}
}
delete oslo_m;
oslo_m = new G4OsloMatrix();
register G4OsloMatrix* o_ptr = oslo_m;
register G4KnotVector* old_knots;
if(dir)
old_knots = v_knots;
else
old_knots = u_knots;
for (j = 0; j < n1; j++)
{
if ( j != 0 )
{
oslo_m->next = new G4OsloMatrix();
oslo_m = oslo_m->next;
}
//while (old_knots->GetKnot(mu + 1) <= new_knots->GetKnot(j))
while ( (new_knots->GetKnot(j) - old_knots->GetKnot(mu + 1)) >
kCarTolerance )
mu = mu + 1; // find the bounding mu
i = j + 1;
muprim = mu;
while ( ((abs(new_knots->GetKnot(i) - old_knots->GetKnot(muprim))) <
kCarTolerance) && i < (j + ord) )
{
i++;
muprim--;
}
ih = muprim + 1;
for (v = 0, p = 1; p < ord; p++)
{
// if (new_knots->GetKnot(j + p) == old_knots->GetKnot(ih))
if ( (abs((new_knots->GetKnot(j + p)) - (old_knots->GetKnot(ih)))) <
kCarTolerance )
ih++;
else
newknots->PutKnot(++v - 1,new_knots->GetKnot(j + p));
}
ahi = AhIndex(0, ord - 1,ord);
ah->PutKnot(ahi, 1.0);
for (p = 1; p <= v; p++)
{
beta1 = 0.0;
tj = newknots->GetKnot(p-1);
if (p - 1 >= muprim)
{
beta1 = AhIndex(p - 1, ord - muprim,ord);
beta1 = ((tj - old_knots->GetKnot(0)) * beta1) /
(old_knots->GetKnot(p + ord - v) - old_knots->GetKnot(0));
}
i = muprim - p + 1;
il = Amax (1, i);
i = n1 - 1 + v - p;
iu = Amin (muprim, i);
for (i = il; i <= iu; i++)
{
register G4double d1, d2;
register G4double beta;
d1 = tj - old_knots->GetKnot(i);
d2 = old_knots->GetKnot(i + p + ord - v - 1) - tj;
beta = ah->GetKnot(AhIndex(p - 1, i + ord - muprim - 1,ord)) /
(d1 + d2);
ah->PutKnot(AhIndex(p, i + ord - muprim - 2,ord), d2 * beta + beta1) ;
beta1 = d1 * beta;
}
ah->PutKnot(AhIndex(p, iu + ord - muprim - 1,ord), beta1);
if (iu < muprim)
{
register G4double kkk;
register G4double ahv;
kkk = old_knots->GetKnot(n1 - 1 + ord);
ahv = AhIndex (p - 1, iu + ord - muprim,ord);
ah->PutKnot(AhIndex(p, iu + ord - muprim - 1,ord),
beta1 + (kkk - tj) * ahv /
(kkk - old_knots->GetKnot(iu + 1)));
}
}
delete oslo_m->o_vec;
oslo_m->o_vec = new G4KnotVector(v+1);
oslo_m->offset = Amax(muprim - v, 0);
oslo_m->osize = v;
for ( i = v, p = 0; i >= 0; i--)
oslo_m->o_vec->PutKnot ( p++, ah->GetKnot(AhIndex (v, (ord-1) - i,ord)));
}
delete ah;
delete newknots;
oslo_m->next = oslo_m;
oslo_m = o_ptr;
}
void G4ProjectedSurface::MapSurface(G4ProjectedSurface* srf)
{
// This algorithm is described in the paper "Making the Oslo-algorithm
// more efficient" in SIAM J.NUMER.ANAL. Vol.23, No. 3, June '86
// Maps the new controlpoints into the new surface.
register G4ControlPoints *c_ptr;
register G4OsloMatrix *o_ptr;
register G4ControlPoints* new_pts;
register G4ControlPoints* old_pts;
new_pts = srf->ctl_points;
// Copy the old points so they can be used in calculating the new ones.
// In this version, where the splitted surfaces are given
// as parameters the copying is not necessary.
old_pts = new G4ControlPoints(*ctl_points);
register int j, // j loop
i; // oslo loop
c_ptr = new_pts;
register int size; // The number of rows or columns,
// depending on processing order
if(!dir)
size=new_pts->GetRows();
else
size=new_pts->GetCols();
for( register int a=0; a<size;a++)
{
if ( lower != 0)
for ( i = 0, o_ptr = oslo_m; i < lower; i++, o_ptr = o_ptr->next);
else
o_ptr = oslo_m;
if(!dir)// Direction ROW
{
for ( j = lower; j < upper; j++, o_ptr = o_ptr->next)
{
register G4double o_scale;
register int x;
x=a;
/* L. Broglia
register G4Point2d o_pts = (G4Point2d&)old_pts->get(x,o_ptr->offset);
register G4Point2d tempc = (G4Point2d&)c_ptr->get(j/upper,
(j)%upper-lower);
*/
register G4Point3D o_pts = old_pts->Get3D(x, o_ptr->offset);
register G4Point3D tempc = c_ptr->Get3D(j/upper, (j)%upper-lower);
o_scale = o_ptr->o_vec->GetKnot(0);
tempc.setX(o_pts.x() * o_scale);
tempc.setY(o_pts.y() * o_scale);
for ( i = 1; i <= o_ptr->osize; i++)
{
o_scale = o_ptr->o_vec->GetKnot(i);
/* L. Broglia
o_pts = (G4Point2d&)old_pts->get(x,i+o_ptr->offset);
tempc.X(tempc.X() + o_scale * o_pts.X());
tempc.Y(tempc.Y() + o_scale * o_pts.Y());
*/
o_pts = old_pts->Get3D(x,i+o_ptr->offset);
tempc.setX(tempc.x() + o_scale * o_pts.x());
tempc.setY(tempc.y() + o_scale * o_pts.y());
}
c_ptr->put(a,(j)%upper-lower,tempc);
}
}
else // dir = COL
{
for ( j = lower; j < upper; j++, o_ptr = o_ptr->next)
{
register G4double o_scale;
register int x;
x=a;
/* L.Broglia
register G4Point2d o_pts = (G4Point2d&)old_pts->get(o_ptr->offset,x);
register G4Point2d tempc = (G4Point2d&)c_ptr->get((j)%upper-lower,
j/upper);
*/
register G4Point3D o_pts = old_pts->Get3D(o_ptr->offset,x);
register G4Point3D tempc = c_ptr->Get3D((j)%upper-lower, j/upper);
o_scale = o_ptr->o_vec->GetKnot(0);
tempc.setX(o_pts.x() * o_scale);
tempc.setY(o_pts.y() * o_scale);
for ( i = 1; i <= o_ptr->osize; i++)
{
o_scale = o_ptr->o_vec->GetKnot(i);
o_pts= old_pts->Get3D(i+o_ptr->offset,a);
tempc.setX(tempc.x() + o_scale * o_pts.x());
tempc.setY(tempc.y() + o_scale * o_pts.y());
}
c_ptr->put((j)%upper-lower,a,tempc);
}
}
}
delete old_pts;
}
+253
View File
@@ -0,0 +1,253 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Ray.cc,v 2.5 1998/10/29 17:49:40 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4Ray.hh"
#include "G4PointRat.hh"
/*
define in .icc
void G4Ray::SetStart(const G4Point3D& p)
{
SetStart(G4Point3D(p.x(),p.y(),p.z()));
}
G4Ray::G4Ray(const G4Point3D& s, const G4Vector3D& d)
{
SetStart(s);
SetDir(G4Vector3D(d.x(),d.y(),d.z()));
}
void G4Ray::Init(const G4Point3D& s, const G4Vector3D& d)
{
SetStart(s); SetDir(G4Vector3D(d.x(),d.y(),d.z()));
}
*/
const G4Plane& G4Ray::GetPlane(const int number_of_plane)const
{
if(number_of_plane==1)
return plane2;
else
return plane1;
}
void G4Ray::CreatePlanes()
{
// Creates two orthogonal planes(plane1,plane2) the ray (rray)
// situated in the intersection of the planes. The planes are
// used to project the surface (nurb) in two dimensions.
G4Vector3D RayDir = dir;
G4Point3D RayOrigin = start;
G4Point3D p1, p2, p3, p4;
G4Vector3D dir1, dir2;
G4Vector3D invdir = PINFINITY ;
if(!NearZero(RayDir.x(), SQRT_SMALL_FASTF))
invdir.setX(1.0 / RayDir.x());
if(!NearZero(RayDir.y(), SQRT_SMALL_FASTF))
invdir.setY(1.0 / RayDir.y());
if(!NearZero(RayDir.z(), SQRT_SMALL_FASTF))
invdir.setZ(1.0 / RayDir.z());
MatVecOrtho(dir1, RayDir);
Vcross( dir2, RayDir, dir1);
Vmove(p1, RayOrigin);
Vadd2(p2, RayOrigin, RayDir);
Vadd2(p3, RayOrigin, dir1);
Vadd2(p4, RayOrigin, dir2);
CalcPlane3Pts( plane1, p1, p3, p2);
CalcPlane3Pts( plane2, p1, p2, p4);
}
void G4Ray::MatVecOrtho(register G4Vector3D &out,register const G4Vector3D in )
{
register G4double f;
int i_Which;
if(NearZero(in.x(), 0.0001) && NearZero(in.y(), 0.0001) &&
NearZero(in.z(), 0.0001) )
{
Vsetall( out, 0 );
return;
}
// Find component closest to zero
f = fabs(in.x());
i_Which=0;
if( fabs(in.y()) < f )
{
f = fabs(in.y());
i_Which=1;
}
if( fabs(in.z()) < f )
i_Which=2;
if(!i_Which)
f = hypot( in.y(), in.z() );
else
if(i_Which==1)
f = hypot( in.z(), in.x() );
else
f = hypot( in.x(), in.y() );
if( NearZero( f, SMALL ) )
{
Vsetall( out, 0 );
return;
}
f = 1.0/f;
if(!i_Which)
{
out.setX(0.0);
out.setY(-in.z()*f);
out.setZ( in.y()*f);
}
else
if(i_Which==1)
{
out.setY(0.0);
out.setZ(-in.x()*f);
out.setX( in.y()*f);
}
else
{
out.setZ(0.0);
out.setX(-in.z()*f);
out.setY( in.y()*f);
}
}
// CALC_PLANE_3PTS
//
// Find the equation of a G4Plane that contains three points.
// Note that Normal vector created is expected to point out (see vmath.h),
// so the vector from A to C had better be counter-clockwise
// (about the point A) from the vector from A to B.
// This follows the outward-pointing Normal convention, and the
// right-hand rule for cross products.
//
//
// C
// *
// |\
// | \
// ^ N | \
// | \ | \
// | \ | \
// |C-A \ | \
// | \ | \
// | \ | \
// \| \
// *---------*
// A B
// ----->
// B-A
//
// If the points are given in the order A B C (eg, *counter*-clockwise),
// then the outward pointing surface Normal N = (B-A) x (C-A).
//
// Explicit Return -
// 0 OK
// -1 Failure. At least two of the points were not distinct,
// or all three were colinear.
//
// Implicit Return -
// G4Plane The G4Plane equation is stored here.
int G4Ray::CalcPlane3Pts(G4Plane &plane1,
const G4Point3D& a,
const G4Point3D& b,
const G4Point3D& c )
{
// Creates the two orthogonal planes which are needed in projecting the
// surface into 2D.
G4Vector3D B_A;
G4Vector3D C_A;
G4Vector3D C_B;
register G4double mag;
Vsub2( B_A, b, a );
Vsub2( C_A, c, a );
Vsub2( C_B, c, b );
Vcross( plane1, B_A, C_A );
// Ensure unit length Normal
if( (mag = Magnitude(plane1)) <= SQRT_SMALL_FASTF )
return(-1);// FAIL
mag = 1/mag;
G4Plane pl2(plane1);
Vscale( plane1, pl2, mag );
// Find distance from the origin to the G4Plane
plane1.d = Vdot( plane1, a );
return(0); //ok
}
void G4Ray::RayCheck()
{
// Check that the ray has a G4Vector3D...
if (dir==G4Vector3D(0, 0, 0))
{
G4cout << "\nZero direction given. Exiting...\n";
exit(1);
}
// Make sure that the vector is unit length
dir= dir.unit();
r_min = 0;
r_max = 0;
}
@@ -0,0 +1,49 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4RectangularTrimmedSurface.cc,v 2.3 1998/10/20 16:33:58 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "SdaiCONFIG_CONTROL_DESIGN.h"
#include "G4RectangularTrimmedSurface.hh"
#include "G4FPlane.hh"
#include "G4BSplineSurface.hh"
#include "G4ToroidalSurface.hh"
#include "G4SphericalSurface.hh"
G4RectangularTrimmedSurface::G4RectangularTrimmedSurface(){}
G4RectangularTrimmedSurface::~G4RectangularTrimmedSurface()
{
delete BasisSurface;
}
void G4RectangularTrimmedSurface::CalcBBox()
{
BasisSurface->CalcBBox();
bbox = BasisSurface->bbox;
}
int G4RectangularTrimmedSurface::Intersect(const G4Ray& Rayref)
{
if(BasisSurface->Intersect(Rayref))
{
G4double UHit = BasisSurface->GetUHit();
G4double VHit = BasisSurface->GetVHit();
if((TrimU1<=UHit)&&(TrimU2>=UHit)&&(TrimV1<=VHit)&&(TrimV2>=VHit))
{
closest_hit = BasisSurface->closest_hit;
return 1;
}
}
return 0;
}
@@ -0,0 +1,59 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4Sort.cc,v 2.1 1998/10/20 16:33:59 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
// File: G4Sort.cc
// Author: Alan Breakstone
//
// Description
//
// Routines to G4Sort arrays of various kinds of numbers
//
#include "G4Sort.hh"
void G4Sort_double( G4double v[], int left, int right )
{
// G4Sort elements in array from v[left] to v[right]
// used recursively
// algorithm comes from Kernighan and Ritchie, "The C Programming
// Language", second edition, p.87
int i, last;
if ( left >= right ) // do nothing if array contains
return; // fewer than two elements
swap_double( v, left, ( left + right ) / 2 ); // move part. elt.
last = left; // to v[0]
for ( i = left+1; i <= right; i++ ) // partition
if ( v[i] < v[left] )
swap_double( v, ++last, i );
swap_double( v, left, last ); // restore partition element
G4Sort_double( v, left, last-1 );
G4Sort_double( v, last+1, right );
return;
}
void swap_double( G4double v[], int i, int j )
{
/* interchange elements i and j in an array */
G4double temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
@@ -0,0 +1,881 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4SphericalSurface.cc,v 2.8 1998/11/11 11:22:03 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
/* $Header: /private/Net/unixhub/u1/ea/liml/gismo/gismo-0.2/geometry/RCS/G4SphericalSurface.cc,v 1.10 1992/08 */
// File: G4SphericalSurface.cc
// Author: Lorraine Lim
// Additional author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// G4SphericalSurface::G4SphericalSurface()
// G4SphericalSurface::G4SphericalSurface( const G4Vector3D& o, const G4Vector3D& xhat,
// const G4Vector3D& zhat,
// G4double r, G4double ph1, G4double ph2,
// G4double th1, G4double th2 )
// G4SphericalSurface::PrintOn( ostream& os ) const
// G4SphericalSurface::HowNear( const G4Vector3D& x ) const
// G4SphericalSurface::distanceAlongRay( int which_way, const Ray* ry,
// G4Vector3D& p ) const
// G4SphericalSurface::distanceAlongHelix( int which_way, const Helix* hx,
// G4Vector3D& p ) const
// G4SphericalSurface::Normal( const G4Vector3D& p ) const
// G4SphericalSurface::Inside( const G4Vector3D& x ) const
// G4SphericalSurface::WithinBoundary( const G4Vector3D& x ) const
// G4SphericalSurface::Scale() const
// G4SphericalSurface::Area() const
// G4SphericalSurface::resize( G4double r, G4double ph1, G4double ph2,
// G4double th1, G4double th2 )
// G4SphericalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, G4ThreeMat& m, int inverse )
// G4SphericalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, int inverse )
// G4SphericalSurface::gropeAlongHelix( const Helix* hx ) const
//
// End ---------------------------------------------------------------
#include "G4SphericalSurface.hh"
/*
G4SphericalSurface::G4SphericalSurface() : G4Surface()
{ // default constructor
// default x_axis is ( 1.0, 0.0, 0.0 ), z_axis is ( 0.0, 0.0, 1.0 ),
// default radius is 1.0
// default phi_1 is 0, phi_2 is 2*PI
// default theta_1 is 0, theta_2 is PI
x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
radius = 1.0;
phi_1 = 0.0;
phi_2 = 2*M_PI;
theta_1 = 0.0;
theta_2 = M_PI;
// OuterBoundary = new G4BREPPolyline();
}
*/
G4SphericalSurface::G4SphericalSurface( const G4Vector3D& o,
const G4Vector3D& xhat,
const G4Vector3D& zhat,
G4double r,
G4double ph1, G4double ph2,
G4double th1, G4double th2)
//: G4Surface( o )
{
// Normal constructor
G4double twopi = 2.0 * M_PI;
// Require both x_axis and z_axis to be unit vectors
G4double xhatmag = xhat.mag();
if ( xhatmag != 0.0 )
x_axis = xhat * (1/ xhatmag); // this makes the x_axis a unit vector
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface--"
<<"x_axis has zero length\n"
<< "\tDefault x_axis of (1, 0, 0) is used.\n";
x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
}
G4double zhatmag = zhat.mag();
if (zhatmag != 0.0)
z_axis = zhat *(1/ zhatmag); // this makes the z_axis a unit vector
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface--"
<<"z_axis has zero length\n"
<< "\tDefault z_axis of (0, 0, 1) is used. \n";
z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
}
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--radius cannot be less than zero.\n"
<< "\tDefault radius of 1.0 is used.\n";
radius = 1.0;
}
// Require phi_1 in the range: 0 <= phi_1 < 2*PI
// and phi_2 in the range: phi_1 < phi_2 <= phi_1 + 2*PI
if ( ( ph1 >= 0.0 ) && ( ph1 < 2*M_PI ) )
phi_1 = ph1;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--lower azimuthal limit is out of range\n"
<< "\tDefault angle of 0 is used.\n";
phi_1 = 0.0;
}
if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) )
phi_2 = ph2;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--upper azimuthal limit is out of range\n"
<< "\tDefault angle of 2*PI is used.\n";
phi_2 = twopi;
}
// Require theta_1 in the range: 0 <= theta_1 < PI
// and theta-2 in the range: theta_1 < theta_2 <= theta_1 + PI
if ( ( th1 >= 0.0 ) && ( th1 < M_PI ) )
theta_1 = th1;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--lower polar limit is out of range\n"
<< "\tDefault angle of 0 is used.\n";
theta_1 = 0.0;
}
if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + M_PI ) ) )
theta_2 =th2;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--upper polar limit is out of range\n"
<< "\tDefault angle of PI is used.\n";
theta_2 = M_PI;
}
}
void G4SphericalSurface::PrintOn( ostream& os ) const
{
// printing function using C++ ostream class
os << "G4SphericalSurface surface with origin: " << origin << "\t"
<< "radius: " << radius << "\n"
<< "\t local x_axis: " << x_axis
<< "\t local z_axis: " << z_axis << "\n"
<< "\t lower azimuthal limit: " << phi_1 << " radians\n"
<< "\t upper azimuthal limit: " << phi_2 << " radians\n"
<< "\t lower polar limit : " << theta_1 << " radians\n"
<< "\t upper polar limit : " << theta_2 << " radians\n";
}
G4double G4SphericalSurface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to the G4SphericalSurface.
// The distance will be positive if the point is Inside the
// G4SphericalSurface, negative if the point is outside.
G4Vector3D d = x - origin;
G4double rad = d.mag();
return (radius - rad);
}
/*
G4double G4SphericalSurface::distanceAlongRay( int which_way, const G4Ray* ry,
G4Vector3D& p ) const
{ // Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4SphericalSurface. The input variable which_way should be set to +1 to
// indicate leaving a G4SphericalSurface, -1 to indicate entering a G4SphericalSurface.
// p is the point of intersection of the Ray with the G4SphericalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4SphericalSurface at the intersection point, it will not leave the
// G4SphericalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4SphericalSurface at the intersection point, it will not enter the
// G4SphericalSurface.
// This method is called by all finite shapes sub-classed to G4SphericalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
p = lv;
// Origin and G4Vector3D unit vector of Ray.
G4Vector3D x = ry->Position( 0.0 );
G4Vector3D dhat = ry->Direction( 0.0 );
int isoln = 0, maxsoln = 2;
// array of solutions in distance along the Ray
// G4double s[2] = { -1.0, -1.0 };
G4double s[2];s[0] = -1.0; s[1]= -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double radius = GetRadius();
// quit with no intersection if the radius of the G4SphericalSurface is zero
if ( radius <= 0.0 )
return Dist;
G4double dsq = d * d;
G4double rsq = radius * radius;
G4double b = d * dhat;
G4double c = dsq - rsq;
G4double radical = b * b - c;
// quit with no intersection if the radical is negative
if ( radical < 0.0 )
return Dist;
G4double root = sqrt( radical );
s[0] = -b + root;
s[1] = -b - root;
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4SphericalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return Dist;
Dist = s[isoln];
p = ry->Position( Dist );
if ( ( ( dhat * Normal( p ) * which_way ) >= 0.0 )
&& ( WithinBoundary( p ) == 1 ) )
return Dist;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
p = lv;
return FLT_MAXX;
}
*/
void G4SphericalSurface::CalcBBox()
{
G4double x_min = origin.x() - radius;
G4double y_min = origin.y() - radius;
G4double z_min = origin.z() - radius;
G4double x_max = origin.x() + radius;
G4double y_max = origin.y() + radius;
G4double z_max = origin.z() + radius;
G4Point3D Min(x_min, y_min, z_min);
G4Point3D Max(x_max, y_max, z_max);
bbox = new G4BoundingBox3D( Min, Max);
}
int G4SphericalSurface::Intersect( const G4Ray& ry )
{
// Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4SphericalSurface. The input variable which_way should be set to +1
// to indicate leaving a G4SphericalSurface, -1 to indicate entering a
// G4SphericalSurface.
// p is the point of intersection of the Ray with the G4SphericalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4SphericalSurface at the intersection point, it will not leave the
// G4SphericalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4SphericalSurface at the intersection point, it will not enter
// the G4SphericalSurface.
// This method is called by all finite shapes sub-classed to
// G4SphericalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
int which_way = (int)HowNear(ry.GetStart());
//Originally a parameter.Read explanation above.
if(!which_way)which_way =-1;
distance = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
// p = lv;
closest_hit = lv;
// Origin and G4Vector3D unit vector of Ray.
// G4Vector3D x = ry->position( 0.0 );
G4Vector3D x=ry.GetStart();
// G4Vector3D dhat = ry->direction( 0.0 );
G4Vector3D dhat = ry.GetDir();
int isoln = 0, maxsoln = 2;
// array of solutions in distance along the Ray
G4double s[2];
s[0] = -1.0 ;
s[1] = -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double r = GetRadius();
// quit with no intersection if the radius of the G4SphericalSurface is zero
if ( r <= 0.0 )
return 0;
G4double dsq = d * d;
G4double rsq = r * r;
G4double b = d * dhat;
G4double c = dsq - rsq;
G4double radical = b * b - c;
// quit with no intersection if the radical is negative
if ( radical < 0.0 )
return 0;
G4double root = sqrt( radical );
s[0] = -b + root;
s[1] = -b - root;
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
// G4Sort_double( s, isoln, maxsoln-1 );
if(s[0] > s[1])
{
G4double tmp =s[0];
s[0] = s[1];
s[1] = tmp;
}
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4SphericalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ )
{
if ( s[isoln] >= kCarTolerance*0.5 )
{
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return 0;
distance = s[isoln];
closest_hit = ry.GetPoint( distance );
if ( ( ( dhat * Normal( closest_hit ) * which_way ) >= 0.0 ) &&
( WithinBoundary( closest_hit ) == 1 ) )
{
distance = distance*distance;
return 1;
}
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
// p = lv;
// return FLT_MAXX;
distance = FLT_MAXX;
closest_hit = lv;
return 0;
}
/*
G4double G4SphericalSurface::distanceAlongHelix( int which_way, const Helix* hx,
G4Vector3D& p ) const
{ // Distance along a Helix to leave or enter a G4SphericalSurface.
// The input variable which_way should be set to +1 to
// indicate leaving a G4SphericalSurface, -1 to indicate entering a G4SphericalSurface.
// p is the point of intersection of the Helix with the G4SphericalSurface.
// If the G4Vector3D of the Helix is opposite to that of the Normal to
// the G4SphericalSurface at the intersection point, it will not leave the
// G4SphericalSurface.
// Similarly, if the G4Vector3D of the Helix is along that of the Normal
// to the G4SphericalSurface at the intersection point, it will not enter the
// G4SphericalSurface.
// This method is called by all finite shapes sub-classed to G4SphericalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
// Possible negative distance solutions are discarded.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
p = lv;
int isoln = 0, maxsoln = 4;
// Array of solutions in turning angle
// G4double s[4] = { -1.0, -1.0, -1.0, -1.0 };
G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
// Helix parameters
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D oh = hx->position( 0.0 ); // origin of Helix
G4Vector3D dh = hx->direction( 0.0 ); // initial G4Vector3D of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.mag();
G4double rhp = rh / prpmag;
// G4SphericalSurface parameters
G4double rs = GetRadius(); // radius of G4SphericalSurface
if ( rs == 0.0 ) // quit if zero radius
return Dist;
G4Vector3D os = GetOrigin(); // origin of G4SphericalSurface
//
// Calculate quantities of use later on
G4Vector3D alpha = rhp * prp;
G4Vector3D beta = rhp * dh;
G4Vector3D gamma = oh - os;
//
// Only consider approximate solutions to quadratic order in the turning
// angle along the Helix
G4double A = beta * beta + gamma * alpha;
G4double B = 2.0 * gamma * beta;
G4double C = gamma * gamma - rs * rs;
// Case if quadratic term is zero
if ( fabs( A ) < FLT_EPSILO ) {
if ( B == 0.0 ) // no intersection, quit
return Dist;
else // B != 0
s[0] = -C / B;
}
// General quadratic solution, A != 0
else {
G4double radical = B * B - 4.0 * A * C;
if ( radical < 0.0 ) // no intersection, quit
return Dist;
G4double root = sqrt( radical );
s[0] = ( -B + root ) / ( 2.0 * A );
s[1] = ( -B - root ) / ( 2.0 * A );
if ( rh < 0.0 ) {
s[0] = -s[0];
s[1] = -s[1];
}
s[2] = s[0] + 2.0 * M_PI;
s[3] = s[1] + 2.0 * M_PI;
}
//
// Order the possible solutions by increasing turning angle
// (G4Sorting routines are in support/G4Sort.h).
G4Sort_double( s, isoln, maxsoln-1 );
//
// Now loop over each positive solution, keeping the first one (smallest
// distance along the Helix) which is within the boundary of the sub-shape.
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
// Calculate distance along Helix and position and G4Vector3D vectors.
Dist = s[isoln] * fabs( rhp );
p = hx->position( Dist );
G4Vector3D d = hx->direction( Dist );
// Now do approximation to get remaining distance to correct this solution
// iterate it until the accuracy is below the user-set surface precision.
G4double delta = 0.;
G4double delta0 = FLT_MAXX;
int dummy = 1;
int iter = 0;
int in0 = Inside( hx->position ( 0.0 ) );
int in1 = Inside( p );
G4double sc = Scale();
while ( dummy ) {
iter++;
// Terminate loop after 50 iterations and Reset distance to large number,
// indicating no intersection with G4SphericalSurface.
// This generally occurs if the Helix curls too tightly to Intersect it.
if ( iter > 50 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Find distance from the current point along the above-calculated
// G4Vector3D using a Ray.
// The G4Vector3D of the Ray and the Sign of the distance are determined
// by whether the starting point of the Helix is Inside or outside of
// the G4SphericalSurface.
in1 = Inside( p );
if ( in1 ) { // current point Inside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( 1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( 1, r, p );
delete r;
}
}
else { // current point outside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( -1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( -1, r, p );
delete r;
}
}
// Test if distance is less than the surface precision, if so Terminate loop.
if ( fabs( delta / sc ) <= SURFACE_PRECISION )
break;
// Ff delta has not changed sufficiently from the previous iteration,
// skip out of this loop.
if ( fabs( ( delta - delta0 ) / sc ) <=
SURFACE_PRECISION )
break;
// If delta has increased in absolute value from the previous iteration
// either the Helix doesn't Intersect the G4SphericalSurface or the approximate
// solution is too far from the real solution. Try groping for a solution.
// If not found, Reset distance to large number, indicating no intersection
// with the G4SphericalSurface.
if ( ( fabs( delta ) > fabs( delta0 ) ) ) {
Dist = fabs( rhp ) *
gropeAlongHelix( hx );
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
}
else
p = hx->position( Dist );
break;
}
// Set old delta to new one.
delta0 = delta;
// Add distance to G4SphericalSurface to distance along Helix.
Dist += delta;
// Negative distance along Helix means Helix doesn't Intersect G4SphericalSurface.
// Reset distance to large number, indicating no intersection with G4SphericalSurface.
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Recalculate point along Helix and the G4Vector3D.
p = hx->position( Dist );
d = hx->direction( Dist );
} // end of while loop
// Now have best value of distance along Helix and position for this
// solution, so test if it is within the boundary of the sub-shape
// and require that it point in the correct G4Vector3D with respect to
// the Normal to the G4SphericalSurface.
if ( ( Dist < FLT_MAXX ) &&
( ( hx->direction( Dist ) * Normal( p ) *
which_way ) >= 0.0 ) &&
( WithinBoundary( p ) == 1 ) )
return Dist;
} // end of if s[isoln] >= 0.0 condition
} // end of for loop over solutions
// If one gets here, there is no solution, so set distance along Helix
// and position to large numbers.
Dist = FLT_MAXX;
p = lv;
return Dist;
}
*/
/*
G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
{ // Return the Normal unit vector to the G4SphericalSurface at a point p on
// (or nearly on) the G4SphericalSurface.
G4Vector3D n = p - origin;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n / nmag;
// If the point p happens to coincide with the origin (which is possible
// if the radius is zero), set the Normal to the z-axis unit vector.
else
n = G4Vector3D( 0.0, 0.0, 1.0 );
return n;
}
*/
G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
{
// Return the Normal unit vector to the G4SphericalSurface at a point p on
// (or nearly on) the G4SphericalSurface.
G4Vector3D n = p - origin;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/ nmag);
// If the point p happens to coincide with the origin (which is possible
// if the radius is zero), set the Normal to the z-axis unit vector.
else
n = G4Vector3D( 0.0, 0.0, 1.0 );
return n;
}
G4Vector3D G4SphericalSurface::SurfaceNormal( const G4Point3D& p ) const
{
// Return the Normal unit vector to the G4SphericalSurface at a point p on
// (or nearly on) the G4SphericalSurface.
G4Vector3D n = p - origin;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/ nmag);
// If the point p happens to coincide with the origin (which is possible
// if the radius is zero), set the Normal to the z-axis unit vector.
else
n = G4Vector3D( 0.0, 0.0, 1.0 );
return n;
}
int G4SphericalSurface::Inside ( const G4Vector3D& x ) const
{
// Return 0 if point x is outside G4SphericalSurface, 1 if Inside.
// Outside means that the distance to the G4SphericalSurface would
// be negative.
// Use the HowNear function to calculate this distance.
if ( HowNear( x ) >= 0.0 )
return 1;
else
return 0;
}
int G4SphericalSurface::WithinBoundary( const G4Vector3D& x ) const
{
// return 1 if point x is on the G4SphericalSurface, otherwise return zero
// (x is assumed to lie on the surface of the G4SphericalSurface, so one
// only checks the angular limits)
G4Vector3D y_axis = z_axis.cross( x_axis );
// components of x in the local coordinate system of the G4SphericalSurface
G4double px = x * x_axis;
G4double py = x * y_axis;
G4double pz = x * z_axis;
// check if within polar angle limits
G4double theta = acos( pz / x.mag() ); // acos in range 0 to PI
// Normal case
if ( theta_2 <= M_PI )
{
if ( ( theta < theta_1 ) || ( theta > theta_2 ) )
return 0;
}
// this is for the case that theta_2 is greater than PI
else
{
theta += M_PI;
if ( ( theta < theta_1 ) || ( theta > theta_2 ) )
return 0;
}
// now check if within azimuthal angle limits
G4double phi = atan2( py, px ); // atan2 in range -PI to PI
G4double twopi = 2.0 * M_PI;
if ( phi < 0.0 )
phi += twopi;
// Normal case
if ( ( phi >= phi_1 ) && ( phi <= phi_2 ) )
return 1;
// this is for the case that phi_2 is greater than 2*PI
phi += twopi;
if ( ( phi >= phi_1 ) && ( phi <= phi_2 ) )
return 1;
// get here if not within azimuthal limits
return 0;
}
G4double G4SphericalSurface::Scale() const
{
// Returns the radius of a G4SphericalSurface unless it is zero, in which
// case returns the arbitrary number 1.0.
// Used for Scale-invariant tests of surface thickness.
if ( radius == 0.0 )
return 1.0;
else
return radius;
}
G4double G4SphericalSurface::Area() const
{
// Returns the Area of a G4SphericalSurface
return ( 2.0*( theta_2 - theta_1 )*( phi_2 - phi_1)*radius*radius/M_PI );
}
void G4SphericalSurface::resize( G4double r,
G4double ph1, G4double ph2,
G4double th1, G4double th2 )
{
// Resize the G4SphericalSurface to new radius r, new lower and upper
// azimuthal angle limits ph1 and ph2, and new lower and upper polar
// angle limits th1 and th2.
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4SphericalSurface::resize"
<< "--radius cannot be less than zero.\n"
<< "\tOriginal value of " << radius << " is retained.\n";
}
// Require azimuthal angles to be within bounds
G4double twopi = 2.0 * M_PI;
if ( ( ph1 >= 0.0 ) && ( ph1 < twopi ) )
phi_1 = ph1;
else
{
G4cerr << "Error in G4SphericalSurface::resize"
<< "--lower azimuthal limit out of range\n"
<< "\tOriginal value of " << phi_1 << " is retained.\n";
}
if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) )
phi_2 = ph2;
else
{
ph2 = ( phi_2 <= phi_1 ) ? ( phi_1 + FLT_EPSILO ) : phi_2;
phi_2 = ph2;
G4cerr << "Error in G4SphericalSurface::resize"
<< "--upper azimuthal limit out of range\n"
<< "\tValue of " << phi_2 << " is used.\n";
}
// Require polar angles to be within bounds
if ( ( th1 >= 0.0 ) && ( th1 < M_PI ) )
theta_1 = th1;
else
{
G4cerr << "Error in G4SphericalSurface::resize"
<< "--lower polar limit out of range\n"
<< "\tOriginal value of " << theta_1 << " is retained.\n";
}
if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + M_PI ) ) )
theta_2 = th2;
else
{
th2 = ( theta_2 <= theta_1 ) ? ( theta_1 + FLT_EPSILO ) : theta_2;
theta_2 = th2;
G4cerr << "Error in G4SphericalSurface::resize"
<< "--upper polar limit out of range\n"
<< "\tValue of " << theta_2 << " is used.\n";
}
}
/*
void G4SphericalSurface::rotate( G4double alpha, G4double beta,
G4double gamma, G4ThreeMat& m, int inverse )
{ // rotate G4SphericalSurface first about global x_axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z_axis by angle gamma
// by creating and using G4ThreeMat objects in Surface::rotate
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
// the axis is rotated here, the origin is rotated by calling
// Surface::rotate
G4Surface::rotate( alpha, beta, gamma, m, inverse );
x_axis = m * x_axis;
z_axis = m * z_axis;
}
*/
/*
void G4SphericalSurface::rotate( G4double alpha, G4double beta,
G4double gamma, int inverse )
{ // rotate G4SphericalSurface first about global x_axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z_axis by angle gamma
// by creating and using G4ThreeMat objects in Surface::rotate
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
// the axis is rotated here, the origin is rotated by calling
// Surface::rotate
G4ThreeMat m;
G4Surface::rotate( alpha, beta, gamma, m, inverse );
x_axis = m * x_axis;
z_axis = m * z_axis;
}
*/
/*
G4double G4SphericalSurface::gropeAlongHelix( const Helix* hx ) const
{ // Grope for a solution of a Helix intersecting a G4SphericalSurface.
// This function returns the turning angle (in radians) where the
// intersection occurs with only positive values allowed, or -1.0 if
// no intersection is found.
// The idea is to start at the beginning of the Helix, then take steps
// of some fraction of a turn. If at the end of a Step, the current position
// along the Helix and the previous position are on opposite sides of the
// G4SphericalSurface, then the solution must lie somewhere in between.
int one_over_f = 8; // one over fraction of a turn to go in each Step
G4double turn_angle = 0.0;
G4double dist_along = 0.0;
G4double d_new;
G4double fk = 1.0 / G4double( one_over_f );
G4double scal = Scale();
G4double d_old = HowNear( hx->position( dist_along ) );
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.mag();
G4double rhp = rh / prpmag;
int max_iter = one_over_f * HELIX_MAX_TURNS;
// Take up to a user-settable number of turns along the Helix,
// groping for an intersection point.
for ( int k = 1; k < max_iter; k++ ) {
turn_angle = 2.0 * M_PI * k / one_over_f;
dist_along = turn_angle * fabs( rhp );
d_new = HowNear( hx->position( dist_along ) );
if ( ( d_old < 0.0 && d_new > 0.0 ) ||
( d_old > 0.0 && d_new < 0.0 ) ) {
d_old = d_new;
// Old and new points are on opposite sides of the G4SphericalSurface, therefore
// a solution lies in between, use a binary search to pin the point down
// to the surface precision, but don't do more than 50 iterations.
int itr = 0;
while ( fabs( d_new / scal ) > SURFACE_PRECISION ) {
itr++;
if ( itr > 50 )
return turn_angle;
turn_angle -= fk * M_PI;
dist_along = turn_angle * fabs( rhp );
d_new = HowNear( hx->position( dist_along ) );
if ( ( d_old < 0.0 && d_new > 0.0 ) ||
( d_old > 0.0 && d_new < 0.0 ) )
fk *= -0.5;
else
fk *= 0.5;
d_old = d_new;
} // end of while loop
return turn_angle; // this is the best solution
} // end of if condition
} // end of for loop
// Get here only if no solution is found, so return -1.0 to indicate that.
return -1.0;
}
*/
@@ -0,0 +1,324 @@
#include "G4Surface.hh"
#include "G4CompositeCurve.hh"
G4Surface::G4Surface(): FLT_MAXX(kInfinity), FLT_EPSILO(0.0001)
{
AdvancedFace=0;
active = 1;
distance = 1.0e20;
Type=0;
bbox = (G4BoundingBox3D*)0;
}
G4Surface::~G4Surface() {}
//void G4Surface::read_surface(fstream& tmp){;}
G4Point3D G4Surface::Evaluation(const G4Ray& rayref){return closest_hit;}
int G4Surface::Evaluate(const G4Ray& rayref){return 0;}
void G4Surface::SetBoundaries(G4CurveVector* boundaries)
{
surfaceBoundary.Init(*boundaries);
InitBounded();
}
void G4Surface::CalcBBox()
{
// Finds the bounds of the surface iow
// calculates the bounds for a bounding box
// to the surface. The bounding box is used
// for a preliminary check of intersection.
bbox = new G4BoundingBox3D(surfaceBoundary.BBox().GetBoxMin(),
surfaceBoundary.BBox().GetBoxMax());
// old implementation
// G4Point3d BoundaryMax = OuterBoundary->GetBoundsMax();
// G4Point3d BoundaryMin = OuterBoundary->GetBoundsMin();
// bbox = new G4BoundingBox( BoundaryMin, BoundaryMax);
// return;
}
G4Vector3D G4Surface::Normal( const G4Vector3D& ) const
{ // return the Normal unit vector to a Surface at the point p on
// (or nearly on) the Surface.
// The default is not well defined, so return ( 0, 0, 0 ).
return G4Vector3D( 0.0, 0.0, 0.0 );
}
int G4Surface::Intersect(const G4Ray& rayref)
{
int Result = 0;
G4Exception("G4Surface::Intersect is not implemented. It should not be called. ");
#ifdef NEW_IMPLEMENTATION
// get the intersection
// Result = Intersect(rayref);
// Check that the point is within the polyline
// Get Normal at Hitpoint
const G4Vector3D& Vec = Normal(closest_hit);
G4Ray Normal(closest_hit, Vec);
// Project points & Hit
// OuterBoundary->ProjectBoundaryTo2D(Normal.GetPlane(1),
// Normal.GetPlane(2), 0);
G4Point3D Hit = closest_hit.Project(Normal.GetPlane(1),
Normal.GetPlane(2) );
// Check point in polygon
// Result = OuterBoundary->Inside(Hit, rayref);
#endif
return Result;
}
G4double G4Surface::ClosestDistanceToPoint(const G4Point3D& Pt)
{
// in fact, a squared distance is returned
// a bit suspicious, this function
// the distance is almost always an overestimate
G4double pointDistance= kInfinity;
G4double tmpDistance;
const G4CurveVector& bounds= surfaceBoundary.GetBounds();
G4int entr = bounds.entries();
for (G4int i=0; i<entr; i++)
{
G4Curve* c= bounds(i);
if (c->GetEntityType() == "G4CompositeCurve")
{
G4CompositeCurve* cc= (G4CompositeCurve*)c;
const G4CurveVector& segments= cc->GetSegments();
for (G4int i=0; i<segments.entries(); i++)
{
G4Curve* ccc= segments(i);
tmpDistance= (G4Point3D(Pt.x(), Pt.y(), Pt.z())-ccc->GetEnd()).mag2();
if (pointDistance > tmpDistance)
{
pointDistance= tmpDistance;
}
}
}
else
{
tmpDistance= (G4Point3D(Pt.x(), Pt.y(), Pt.z())-c->GetEnd()).mag2();
if (pointDistance > tmpDistance)
{
pointDistance= tmpDistance;
}
}
}
// L. Broglia
// Be carreful ! pointdistance is the squared distance
return sqrt(pointDistance);
// G4double PointDistance=INFINITY;
// G4double TmpDistance=0;
// PointDistance = OuterBoundary->ClosestDistanceToPoint(Pt);
// TmpDistance =0;
// for(int a=0;a<NumberOfInnerBoundaries;a++)
// {
// TmpDistance = InnerBoundary[a]->ClosestDistanceToPoint(Pt);
// if(PointDistance > TmpDistance) PointDistance = TmpDistance;
// }
// return PointDistance;
//G4double G4Boundary::ClosestDistanceToPoint(const G4ThreeVec& Pt)
//{
// G4double PointDistance = INFINITY;
// G4double TmpDistance = 0;
// for(int a =0; a < NumberOfPoints;a++)
// {
// G4Point3d& Pt2 = GetPoint(a);
// TmpDistance = Pt2.Distance(Pt);
// if(PointDistance > TmpDistance)PointDistance = TmpDistance;
// }
// return PointDistance;
//}
}
// Gismo members, modified by J.Sulkimo
// Author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// operator<<( ostream& os, const Surface& s )
// Surface::PrintOn( ostream& os ) const
// Surface::HowNear( const G4ThreeVec& x ) const
// Surface::distanceAlongRay( int which_way, const Ray* ry,
// G4ThreeVec& p ) const
// Surface::distanceAlongHelix( int which_way, const Helix* hx,
// G4ThreeVec& p ) const
// Surface::Normal() const
// Surface::Normal( const G4ThreeVec& p ) const
// Surface::Inside( const G4ThreeVec& p ) const
// Surface::move( const G4ThreeVec& p )
// Surface::rotate( G4double alpha, G4double beta,
// G4double gamma, G4ThreeMat& m, int inverse )
// Surface::rotate( G4double alpha, G4double beta,
// G4double gamma, int inverse )
//
// End ---------------------------------------------------------------
ostream& operator<<( ostream& os, const G4Surface& s )
{
// overwrite output operator << to Print out Surface objects
// using the PrintOn function defined below
// s.PrintOn( os );
return os;
}
G4double G4Surface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to a Surface.
// The default for a Surface is the distance from the point to the origin.
G4Vector3D p = x - origin;
return p.mag();
}
/*
G4double G4Surface::distanceAlongRay( int which_way, const G4Ray* ry,
G4ThreeVec& p ) const
{ // Distance along a Ray (straight line with G4ThreeVec) to leave or enter
// a Surface. The input variable which_way should be set to +1 to indicate
// leaving a Surface, -1 to indicate entering a Surface.
// p is the point of intersection of the Ray with the Surface.
// This is a default function which just gives the distance
// between the origin of the Ray and the origin of the Surface.
// Since a generic Surface doesn't have a well-defined Normal, no
// further checks are Done.
// This should always be overwritten for derived classes so Print out
// a warning message if this is called.
G4cout << "WARNING from Surface::distanceAlongRay\n"
<< " This function should be overwritten by a derived class.\n"
<< " Using the Surface base class default.\n";
p = GetOrigin();
G4ThreeVec d = ry->Position() - p;
return d.Magnitude();
}
G4double G4Surface::distanceAlongHelix( int which_way, const Helix* hx,
G4ThreeVec& p ) const
{ // Distance along a Helix to leave or enter a Surface.
// The input variable which_way should be set to +1 to indicate
// leaving a Surface, -1 to indicate entering a Surface.
// p is the point of intersection of the Helix with the Surface.
// This is a default function which just gives the distance
// between the origin of the Helix and the origin of the Surface.
// Since a generic Surface doesn't have a well-defined Normal, no
// further checks are Done.
// This should always be overwritten for derived classes so Print out
// a warning message if this is called.
G4cout << "WARNING from Surface::distanceAlongHelix\n"
<< " This function should be overwritten by a derived class.\n"
<< " Using the Surface base class default.\n";
p = GetOrigin();
G4ThreeVec d = hx->position() - p;
return d.Magnitude();
}
*/
/*
G4ThreeVec G4Surface::Normal() const
{ // return the Normal unit vector to a Surface
// (This is only meaningful for Surfaces for which the Normal does
// not depend on location on the Surface).
// The default is not well defined, so return ( 0, 0, 0 ).
return G4ThreeVec( 0.0, 0.0, 0.0 );
}
*/
/*
G4ThreeVec G4Surface::Normal( const G4ThreeVec& ) const
{ // return the Normal unit vector to a Surface at the point p on
// (or nearly on) the Surface.
// The default is not well defined, so return ( 0, 0, 0 ).
return G4ThreeVec( 0.0, 0.0, 0.0 );
}
int G4Surface::Inside( const G4ThreeVec& ) const
{ // return 0 if point p is outside Surface, 1 if Inside
// default is not well defined, so return 0
return 0;
}
void G4Surface::move( const G4ThreeVec& p )
{ // translate origin of Surface by vector p
origin += p;
}
void G4Surface::rotate( G4double alpha, G4double beta,
G4double gamma, G4ThreeMat& m, int inverse )
{ // rotate Surface first about global x-axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z-axis by angle gamma
// by creating and using G4ThreeMat objects
// angles are assumed to be given in radians
// returns also the overall rotation matrix for use by subclasses
// if inverse is non-zero, the order of rotations is reversed
// for a generic Surface, only the origin is rotated
// G4double ax[3][3] = { 0., 0., 0., 0., 0., 0., 0., 0., 0. };
G4double ax[3][3];
G4double ay[3][3];
G4double az[3][3];
// G4double ay[3][3] = { 0., 0., 0., 0., 0., 0., 0., 0., 0. };
// G4double az[3][3] = { 0., 0., 0., 0., 0., 0., 0., 0., 0. };
ax[0][0] = 1.;
ax[1][1] = cos( alpha );
ax[2][2] = ax[1][1];
ax[2][1] = sin( alpha );
ax[1][2] = -ax[2][1];
ay[1][1] = 1.;
ay[0][0] = cos( beta );
ay[2][2] = ay[0][0];
ay[0][2] = sin( beta );
ay[2][0] = -ay[0][2];
az[2][2] = 1.;
az[0][0] = cos( gamma );
az[1][1] = az[0][0];
az[1][0] = sin( gamma );
az[0][1] = -az[1][0];
G4ThreeMat &Rx = *new G4ThreeMat( ax ); // x-rotation matrix
G4ThreeMat &Ry = *new G4ThreeMat( ay ); // y-rotation matrix
G4ThreeMat &Rz = *new G4ThreeMat( az ); // z-rotation matrix
if ( inverse )
m = Rx * ( Ry * Rz );
else
m = Rz * ( Ry * Rx );
origin = m * origin;
}
void G4Surface::rotate( G4double alpha, G4double beta,
G4double gamma, int inverse )
{ // rotate Surface first about global x-axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z-axis by angle gamma
// by creating and using G4ThreeMat objects
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
G4ThreeMat m;
// Just call the above function to do this rotation
rotate( alpha, beta, gamma, m, inverse );
}
*/
@@ -0,0 +1,141 @@
#include "G4SurfaceBoundary.hh"
#include "geomdefs.hh"
#include "G4CompositeCurve.hh"
G4SurfaceBoundary::G4SurfaceBoundary(){}
void G4SurfaceBoundary::Init(const G4CurveVector& bounds0)
{
bounds= bounds0;
lastIntersection.Reset();
const G4BoundingBox3D* b= bounds[0]->BBox();
bBox.Init(b->GetBoxMin(), b->GetBoxMax());
G4int i;
for ( i=1; i<bounds.entries(); i++)
{
b= bounds[i]->BBox();
bBox.Extend(b->GetBoxMin());
bBox.Extend(b->GetBoxMax());
}
// the points array is probably unused, so the following code is useless
G4int cnt= 0;
G4int entr = bounds.entries();
for (i=0; i < entr; i++)
{
G4Curve* c = bounds(i);
if (c->GetEntityType() == "G4CompositeCurve")
{
G4CompositeCurve* cc = (G4CompositeCurve*)c;
const G4CurveVector& segments = cc->GetSegments();
cnt+= segments.entries();
}
else
cnt++;
}
points.reshape(cnt);
G4int j= 0;
for (i=0; i<bounds.entries(); i++)
{
G4Curve* c= bounds(i);
if (c->GetEntityType() == "G4CompositeCurve")
{
G4CompositeCurve* cc = (G4CompositeCurve*)c;
const G4CurveVector& segments = cc->GetSegments();
for (G4int i=0; i<segments.entries(); i++)
{
G4Curve* ccc = segments(i);
G4Point3D p = ccc->GetEnd();
points[j]= p;
j++;
}
}
else
{
G4Point3D p= c->GetEnd();
points[j]= p;
j++;
}
}
}
G4SurfaceBoundary::~G4SurfaceBoundary() {}
G4SurfaceBoundary* G4SurfaceBoundary::Project(const G4Transform3D& tr)
{
G4CurveVector newBounds;
for (G4int i=0; i<bounds.entries(); i++)
{
G4Curve* c= bounds[i]->Project(tr);
if (c==0)
{
newBounds.clearAndDestroy();
return 0;
}
// L. Broglia
c->SetSameSense( bounds[i]->GetSameSense() );
newBounds.insert(c);
}
G4SurfaceBoundary* lof= new G4SurfaceBoundary;
lof->Init(newBounds);
return lof;
}
void G4SurfaceBoundary::IntersectRay2D(const G4Ray& ray,
G4CurveRayIntersection& is)
{
is.Reset();
G4int entr = bounds.entries();
for (G4int i=0; i < entr; i++)
{
G4Curve& c = *bounds.at(i);
G4CurveRayIntersection isTmp(c, ray);
c.IntersectRay2D(ray, isTmp);
if (fabs(isTmp.GetDistance()) < fabs(is.GetDistance()))
is= isTmp;
}
lastIntersection= is;
}
G4bool G4SurfaceBoundary::Tangent(G4CurvePoint& cp, G4Vector3D& v)
{
if (lastIntersection.GetDistance() == kInfinity)
return false;
return lastIntersection.GetCurve().Tangent(lastIntersection, v);
// should be true
// cp is ignored for the moment
}
void G4SurfaceBoundary::SplitWithPlane(const G4Point3D& p0,
const G4Vector3D& n,
G4SurfaceBoundary*& new1,
G4SurfaceBoundary*& new2)
{
G4Exception("To be implemented");
}
@@ -0,0 +1,249 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4SurfaceList.cc,v 2.2 1998/10/20 16:34:01 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4SurfaceList.hh"
G4SurfaceList::G4SurfaceList()
{
first = index = last = (G4Surface*)0;
number_of_elements=0;
}
G4SurfaceList::~G4SurfaceList() { EmptyList(); }
void G4SurfaceList::MoveToFirst(G4Surface* srf)
{
if(number_of_elements)
{
RemovePointer();
srf->next = first;
first = srf;
index=first;
number_of_elements++;
}
}
void G4SurfaceList::AddSurface(G4Surface* srf)
{
if(first == (G4Surface*)0)
{
index = srf;
first = srf;
last = srf;
first->next = (G4Surface*)0;
}
else
{
srf->next = last->next;
last->next = srf;
last = last->next;
}
number_of_elements++;
index=first;
}
G4Surface* G4SurfaceList::GetSurface()
{
return index;
}
G4Surface* G4SurfaceList::GetSurface(int number)
{
index = first;
for(int a=0;a<number;a++)
Step();
return index;
}
G4Surface* G4SurfaceList::GetLastSurface()
{
return last;
}
void G4SurfaceList::RemoveSurface(G4Surface* srf)
{
if(srf!=(G4Surface*)0)
{
number_of_elements--;
temp = first;
if(srf == first)
{
first=first->next;
index = first;
if(number_of_elements == 0)last = first;
delete srf;
return;
}
else
{
while(temp->next != srf) temp = temp->next;
index = srf->next;
temp->next = index;
if(srf == last) last = temp;
index = first;
delete srf;
}
}
}
void G4SurfaceList::RemovePointer()
{
// Remove the current pointer from the List
// Do not delete the object itself
if(number_of_elements)
if(first != index)
{
temp = first;
// Find previous
while(temp->next != index) temp = temp->next;
// Hop over the one to be removed
temp->next = index->next;
// Correct the index pointer
index = temp->next;
}
else
{
// Hop over the first
first = first->next;
index = first;
}
number_of_elements--;
}
void G4SurfaceList::EmptyList()
{
//Deletes all surfaces in List
while (first != (G4Surface*)0)
{
temp = first;
first = first->next;
delete temp;
number_of_elements--;
}
last = index = first;
}
void G4SurfaceList::MoveToFirst()
{
index = first;
}
void G4SurfaceList::Step()
{
if(index!=(G4Surface*)0)
index = index->next;
}
void G4SurfaceList::G4SortList()
{
if(number_of_elements == 1) return;
// First create a vector of the surface distances
// to the ray origin
G4Surface** distances = new G4Surface*[number_of_elements];
int x = 0;
MoveToFirst();
// Copy surface pointers to vector
if(number_of_elements > 1)
{
while(x < number_of_elements)
{
distances[x] = index;
index = index->next;
x++;
}
MoveToFirst();
// Sort List of pointers using quick G4Sort
QuickG4Sort( distances, 0, number_of_elements-1 );
// Organize the linked List of surfaces according
// to the quickG4Sorted List.
x = 0;
first = distances[x];
last = first;
x++;
while (x < number_of_elements)
{
last->next = distances[x];
last = last ->next;
x++;
}
last->next = (G4Surface*)0;
MoveToFirst();
}
delete[] distances;
}
void G4SurfaceList::QuickG4Sort(G4Surface** Dist, int left, int right)
{
register int i=left;
register int j=right;
G4Surface* elem1;
G4Surface* elem2 = Dist[(left+right)/2];
do
{
while ( (Dist[i]->Distance() < elem2->Distance()) && (i < right) )
i++;
while ( (elem2->Distance() < Dist[j]->Distance()) && (j > left))
j--;
if(i<=j)
{
elem1 = Dist[i];
Dist[i] = Dist[j];
Dist[j] = elem1;
i++;
j--;
}
} while (i<=j);
if( left < j )
QuickG4Sort(Dist, left, j );
if( i < right )
QuickG4Sort(Dist, i, right);
}
@@ -0,0 +1,3 @@
#include "G4SurfaceOfLinearExtrusion.hh"
@@ -0,0 +1,2 @@
#include "G4SurfaceOfRevolution.hh"
@@ -0,0 +1,262 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4ThreeMat.cc,v 2.2 1998/10/20 16:34:01 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
/* G4ThreeMat.cc,v 1.5 1993/08/02 22:21:27 atwood Exp */
// File: G4ThreeMat.cc
// Author: Alan Breakstone
// Contents -------------------------------------------------------------
//
// G4ThreeMat::G4ThreeMat()
// G4ThreeMat::G4ThreeMat( G4double a[3][3] )
// operator<<( ostream&, const G4ThreeMat& m );
// G4ThreeMat::PrintOn( ostream& os ) const
// operator==( const G4ThreeMat& m )
// G4ThreeMat::operator=( const G4ThreeMat& m )
// G4ThreeMat::operator-()
// G4ThreeMat::operator+=( const G4ThreeMat& m2 )
// G4ThreeMat::operator-=( const G4ThreeMat& m2 )
// operator+( const G4ThreeMat& m1, const G4ThreeMat& m2 )
// operator-( const G4ThreeMat& m1, const G4ThreeMat& m2 )
// operator*( G4double x, const G4ThreeMat& m )
// operator*( const G4ThreeMat& m, const G4ThreeVec& v )
// operator*( const G4ThreeMat& m1, const G4ThreeMat& m2 )
// G4ThreeMat::Determinant()
//
// End ------------------------------------------------------------------
#include "G4ThreeMat.hh"
G4ThreeMat::G4ThreeMat()
{
// default (null) constructor
for ( int i = 0; i < 3 ; i++ )
{
row[i] = G4Vector3D( 0., 0., 0. );
column[i] = G4Vector3D( 0., 0., 0. );
for ( int j = 0; j < 3 ; j++ )
element[i][j] = 0.;
}
}
G4ThreeMat::G4ThreeMat( G4double a[3][3] )
{
// constructor to make matrix from array
for ( int i = 0; i < 3 ; i++ )
{
row[i] = G4Vector3D( a[i][0], a[i][1], a[i][2] );
column[i] = G4Vector3D( a[0][i], a[1][i], a[2][i] );
for ( int j = 0; j < 3 ; j++ )
element[i][j] = a[i][j];
}
}
G4ThreeMat::G4ThreeMat( const G4ThreeMat& m )
{
// copy constructor
for ( int i = 0; i < 3 ; i++ )
{
row[i] = m.row[i];
column[i] = m.column[i];
for ( int j = 0; j < 3 ; j++ )
element[i][j] = m.element[i][j];
}
}
ostream& operator<<( ostream& os, const G4ThreeMat& m )
{
// overwrite output operator << to Print out G4ThreeMat objects
// using the PrintOn function defined below
m.PrintOn( os );
return os;
}
void G4ThreeMat::PrintOn( ostream& os ) const
{
// printing function using C++ ostream class
os << "[ " << element[0][0] << "\t"
<< element[0][1] << "\t"
<< element[0][2] << "\n "
<< element[1][0] << "\t"
<< element[1][1] << "\t"
<< element[1][2] << "\n "
<< element[2][0] << "\t"
<< element[2][1] << "\t"
<< element[2][2] << " ]\n";
/*
for ( int i = 0; i < 3; i++ ) {
os << "row [" << i << "] " << row[i] << "\n"
<< "column[" << i << "] " << column[i] << "\n";
}
*/
}
int G4ThreeMat::operator==( const G4ThreeMat& m )
{
for ( int i = 0; i < 3 ; i++ )
{
for ( int j = 0; j < 3 ; j++ )
{
if ( element[i][j] != m.element[i][j] )
return 0;
}
}
return 1;
}
void G4ThreeMat::operator=( const G4ThreeMat& m )
{
// assignment operator
for ( int i = 0; i < 3 ; i++ )
{
row[i] = m.row[i];
column[i] = m.column[i];
for ( int j = 0; j < 3 ; j++ )
element[i][j] = m.element[i][j];
}
}
G4ThreeMat G4ThreeMat::operator-()
{
// unary - operator, change Sign of all elements
G4double a[3][3];
for ( int i = 0; i < 3 ; i++ )
{
for ( int j = 0; j < 3 ; j++ )
a[i][j] = -element[i][j];
}
return G4ThreeMat( a );
}
G4ThreeMat G4ThreeMat::operator+=( const G4ThreeMat& m2 )
{
// overload += operator
for ( int i = 0; i < 3 ; i++ )
{
this->row[i] += m2.row[i];
this->column[i] += m2.column[i];
for ( int j = 0; j < 3 ; j++ )
this->element[i][j] += m2.element[i][j];
}
return *this;
}
G4ThreeMat G4ThreeMat::operator-=( const G4ThreeMat& m2 )
{
// overload -= operator
for ( int i = 0; i < 3 ; i++ )
{
this->row[i] -= m2.row[i];
this->column[i] -= m2.column[i];
for ( int j = 0; j < 3 ; j++ )
this->element[i][j] -= m2.element[i][j];
}
return *this;
}
G4ThreeMat operator+( const G4ThreeMat& m1, const G4ThreeMat& m2 )
{
// overload binary + operator
G4double a[3][3];
for ( int i = 0; i < 3 ; i++ )
{
for ( int j = 0; j < 3 ; j++ )
a[i][j] = m1.element[i][j] + m2.element[i][j];
}
return G4ThreeMat( a );
}
G4ThreeMat operator-( const G4ThreeMat& m1, const G4ThreeMat& m2 )
{
// overload binary - operator
G4double a[3][3];
for ( int i = 0; i < 3 ; i++ )
{
for ( int j = 0; j < 3 ; j++ )
a[i][j] = m1.element[i][j] - m2.element[i][j];
}
return G4ThreeMat( a );
}
G4ThreeMat operator*( G4double x, const G4ThreeMat& m )
{
// overload binary * operator for constant Times matrix
G4double a[3][3];
for ( int i = 0; i < 3 ; i++ ){
for ( int j = 0; j < 3 ; j++ ) {
a[i][j] = x * m.element[i][j];
}
}
return G4ThreeMat( a );
}
G4Vector3D operator*( const G4ThreeMat& m, const G4Vector3D& v )
{
// overload binary * operator for matrix Times vector
G4double a[3];
for ( int i = 0; i < 3 ; i++ ){
a[i] = m.row[i] * v;
}
return G4Vector3D( a[0], a[1], a[2] );
}
G4ThreeMat operator*( const G4ThreeMat& m1, const G4ThreeMat& m2 )
{
// overload binary * operator for matrix Times matrix
G4double a[3][3];
for ( int i = 0; i < 3 ; i++ ){
for ( int j = 0; j < 3 ; j++ ) {
a[i][j] = m1.row[i] * m2.column[j];
}
}
return G4ThreeMat( a );
}
G4double G4ThreeMat::Determinant()
{
// Determinant of a three by three matrix
return element[0][0] * ( element[1][1] * element[2][2]
- element[2][1] * element[1][2] )
- element[0][1] * ( element[1][0] * element[2][2]
- element[2][0] * element[1][2] )
+ element[0][2] * ( element[1][0] * element[2][1]
- element[2][0] * element[1][1] );
}
@@ -0,0 +1,445 @@
// This code implementation is the intellectual property of
// the RD44 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.
//
// $Id: G4ToroidalSurface.cc,v 2.7 1998/10/29 17:49:41 broglia Exp $
// GEANT4 tag $Name: geant4-00 $
//
#include "G4ToroidalSurface.hh"
G4ToroidalSurface::G4ToroidalSurface(): EQN_EPS(1e-9){}
G4ToroidalSurface::G4ToroidalSurface(const G4Vector3D& Location,
const G4Vector3D& Ax,
const G4Vector3D& Dir,
const G4double MinRad,
const G4double MaxRad): EQN_EPS(1e-9)
{
Placement.Init(Dir, Ax, Location);
MinRadius = MinRad;
MaxRadius = MaxRad;
TransMatrix= new Matrix(4,4);
}
G4ToroidalSurface::~G4ToroidalSurface(){}
void G4ToroidalSurface::CalcBBox()
{
// L. Broglia
// G4Point3D Origin = Placement.GetSrfPoint();
G4Point3D Origin = Placement.GetLocation();
G4Point3D Min(Origin.x()-MaxRadius,
Origin.y()-MaxRadius,
Origin.z()-MaxRadius);
G4Point3D Max(Origin.x()+MaxRadius,
Origin.y()+MaxRadius,
Origin.z()+MaxRadius);
bbox = new G4BoundingBox3D(Min,Max);
}
G4double G4ToroidalSurface::ClosestDistanceToPoint(const G4Point3D &Pt)
{
// L. Broglia
// G4Point3D Origin = Placement.GetSrfPoint();
G4Point3D Origin = Placement.GetLocation();
G4double Dist = Pt.distance(Origin);
return ((Dist - MaxRadius)*(Dist - MaxRadius));
}
int G4ToroidalSurface::Intersect(const G4Ray& Ray)
{
// ---- inttor - Intersect a ray with a torus. ------------------------
// from GraphicsGems II by
// Description:
// Inttor determines the intersection of a ray with a torus.
//
// On entry:
// raybase = The coordinate defining the base of the
// intersecting ray.
// raycos = The G4Vector3D cosines of the above ray.
// center = The center location of the torus.
// radius = The major radius of the torus.
// rplane = The minor radius in the G4Plane of the torus.
// rnorm = The minor radius Normal to the G4Plane of the torus.
// tran = A 4x4 transformation matrix that will position
// the torus at the origin and orient it such that
// the G4Plane of the torus lyes in the x-z G4Plane.
//
// On return:
// nhits = The number of intersections the ray makes with
// the torus.
// rhits = The entering/leaving distances of the
// intersections.
//
// Returns: True if the ray intersects the torus.
//
// --------------------------------------------------------------------
// Variables. Should be optimized later...
G4Point3D Base = Ray.GetStart(); // Base of the intersection ray
G4Vector3D DCos = Ray.GetDir(); // Direction cosines of the ray
int nhits=0; // Number of intersections
G4double rhits[4]; // Intersection distances
G4double hits[4]; // Ordered intersection distances
G4double rho, a0, b0; // Related constants
G4double f, l, t, g, q, m, u; // Ray dependent terms
G4double C[5]; // Quartic coefficients
// Transform the intersection ray
// MultiplyPointByMatrix (Base); // Matriisi puuttuu viela!
// MultiplyVectorByMatrix (DCos);
// Compute constants related to the torus.
G4double rnorm = MaxRadius - MinRadius; // ei tietoa onko oikein...
rho = MinRadius*MinRadius / (rnorm*rnorm);
a0 = 4. * MaxRadius*MaxRadius;
b0 = MaxRadius*MaxRadius - MinRadius*MinRadius;
// Compute ray dependent terms.
f = 1. - DCos.y()*DCos.y();
l = 2. * (Base.x()*DCos.x() + Base.z()*DCos.z());
t = Base.x()*Base.x() + Base.z()*Base.z();
g = f + rho * DCos.y()*DCos.y();
q = a0 / (g*g);
m = (l + 2.*rho*DCos.y()*Base.y()) / g;
u = (t + rho*Base.y()*Base.y() + b0) / g;
// Compute the coefficients of the quartic.
C[4] = 1.0;
C[3] = 2. * m;
C[2] = m*m + 2.*u - q*f;
C[1] = 2.*m*u - q*l;
C[0] = u*u - q*t;
// Use quartic root solver found in "Graphics Gems" by Jochen Schwarze.
nhits = SolveQuartic (C,rhits);
// SolveQuartic returns root pairs in reversed order.
m = rhits[0]; u = rhits[1]; rhits[0] = u; rhits[1] = m;
m = rhits[2]; u = rhits[3]; rhits[2] = u; rhits[3] = m;
// return (*nhits != 0);
if(nhits != 0)
{
// Convert Hit distances to intersection points
/*
G4Point3D** IntersectionPoints = new G4Point3D*[nhits];
for(int a=0;a<nhits;a++)
{
G4double Dist = rhits[a];
IntersectionPoints[a] = new G4Point3D((Base - Dist * DCos));
}
// Check wether any of the hits are on the actual surface
// Start with checking for the intersections that are Inside the bbox
G4Point3D* Hit;
int InsideBox[2]; // Max 2 intersections on the surface
int Counter=0;
*/
G4Point3D BoxMin = bbox->GetBoxMin();
G4Point3D BoxMax = bbox->GetBoxMax();
G4Point3D Hit;
int c1 = 0;
int c2;
G4double tempVec[4];
for(int a=0;a<nhits;a++)
{
while ( (c1 < 4) && (hits[c1] <= rhits[a]) )
{
tempVec[c1]=hits[c1];
c1++;
}
for(c2=c1+1;c2<4;c2++)
tempVec[c2]=hits[c2-1];
if(c1<4)
{
tempVec[c1]=rhits[a];
for(c2=0;c2<4;c2++)
hits[c2]=tempVec[c2];
}
}
for(int b=0;b<nhits;b++)
{
// Hit = IntersectionPoints[b];
if(hits[b] >=kCarTolerance*0.5)
{
Hit = Base + (hits[b]*DCos);
// InsideBox[Counter]=b;
if( (Hit.x() > BoxMin.x()) &&
(Hit.x() < BoxMax.x()) &&
(Hit.y() > BoxMin.y()) &&
(Hit.y() < BoxMax.y()) &&
(Hit.z() > BoxMin.z()) &&
(Hit.z() < BoxMax.z()) )
{
closest_hit = Hit;
distance = hits[b]*hits[b];
return 1;
}
// Counter++;
}
}
// If two Inside bbox, find closest
int Closest=0;
// if(Counter>1)
// if(rhits[InsideBox[0]] > rhits[InsideBox[1]])
// Closest=1;
// Project polygon and do point in polygon
// Projection also for curves etc.
// Should probably be implemented in the curve class.
G4Plane Plane1 = Ray.GetPlane(1);
G4Plane Plane2 = Ray.GetPlane(2);
// Point in polygon
return 1;
}
return 0;
}
int G4ToroidalSurface::SolveQuartic(G4double c[], G4double s[] )
{
// From Graphics Gems I by Jochen Schwartz
G4double coeffs[ 4 ];
G4double z, u, v, sub;
G4double A, B, C, D;
G4double sq_A, p, q, r;
int i, num;
// Normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0
A = c[ 3 ] / c[ 4 ];
B = c[ 2 ] / c[ 4 ];
C = c[ 1 ] / c[ 4 ];
D = c[ 0 ] / c[ 4 ];
// substitute x = y - A/4 to eliminate cubic term:
// x^4 + px^2 + qx + r = 0
sq_A = A * A;
p = - 3.0/8 * sq_A + B;
q = 1.0/8 * sq_A * A - 1.0/2 * A * B + C;
r = - 3.0/256*sq_A*sq_A + 1.0/16*sq_A*B - 1.0/4*A*C + D;
if (IsZero(r))
{
// no absolute term: y(y^3 + py + q) = 0
coeffs[ 0 ] = q;
coeffs[ 1 ] = p;
coeffs[ 2 ] = 0;
coeffs[ 3 ] = 1;
num = SolveCubic(coeffs, s);
s[ num++ ] = 0;
}
else
{
// solve the resolvent cubic ...
coeffs[ 0 ] = 1.0/2 * r * p - 1.0/8 * q * q;
coeffs[ 1 ] = - r;
coeffs[ 2 ] = - 1.0/2 * p;
coeffs[ 3 ] = 1;
(void) SolveCubic(coeffs, s);
// ... and take the one real solution ...
z = s[ 0 ];
// ... to Build two quadric equations
u = z * z - r;
v = 2 * z - p;
if (IsZero(u))
u = 0;
else if (u > 0)
u = sqrt(u);
else
return 0;
if (IsZero(v))
v = 0;
else if (v > 0)
v = sqrt(v);
else
return 0;
coeffs[ 0 ] = z - u;
coeffs[ 1 ] = q < 0 ? -v : v;
coeffs[ 2 ] = 1;
num = SolveQuadric(coeffs, s);
coeffs[ 0 ]= z + u;
coeffs[ 1 ] = q < 0 ? v : -v;
coeffs[ 2 ] = 1;
num += SolveQuadric(coeffs, s + num);
}
// resubstitute
sub = 1.0/4 * A;
for (i = 0; i < num; ++i)
s[ i ] -= sub;
return num;
}
int G4ToroidalSurface::SolveCubic(G4double c[], G4double s[] )
{
// From Graphics Gems I bu Jochen Schwartz
int i, num;
G4double sub;
G4double A, B, C;
G4double sq_A, p, q;
G4double cb_p, D;
// Normal form: x^3 + Ax^2 + Bx + C = 0
A = c[ 2 ] / c[ 3 ];
B = c[ 1 ] / c[ 3 ];
C = c[ 0 ] / c[ 3 ];
// substitute x = y - A/3 to eliminate quadric term:
// x^3 +px + q = 0
sq_A = A * A;
p = 1.0/3 * (- 1.0/3 * sq_A + B);
q = 1.0/2 * (2.0/27 * A * sq_A - 1.0/3 * A * B + C);
// use Cardano's formula
cb_p = p * p * p;
D = q * q + cb_p;
if (IsZero(D))
{
if (IsZero(q)) // one triple solution
{
s[ 0 ] = 0;
num = 1;
}
else // one single and one G4double solution
{
G4double u = cbrt(-q);
s[ 0 ] = 2 * u;
s[ 1 ] = - u;
num = 2;
}
}
else if (D < 0) // Casus irreducibilis: three real solutions
{
G4double phi = 1.0/3 * acos(-q / sqrt(-cb_p));
G4double t = 2 * sqrt(-p);
s[ 0 ] = t * cos(phi);
s[ 1 ] = - t * cos(phi + M_PI / 3);
s[ 2 ] = - t * cos(phi - M_PI / 3);
num = 3;
}
else // one real solution
{
G4double sqrt_D = sqrt(D);
G4double u = cbrt(sqrt_D - q);
G4double v = - cbrt(sqrt_D + q);
s[ 0 ] = u + v;
num = 1;
}
// resubstitute
sub = 1.0/3 * A;
for (i = 0; i < num; ++i)
s[ i ] -= sub;
return num;
}
int G4ToroidalSurface::SolveQuadric(G4double c[], G4double s[] )
{
// From Graphics Gems I by Jochen Schwartz
G4double p, q, D;
// Normal form: x^2 + px + q = 0
p = c[ 1 ] / (2 * c[ 2 ]);
q = c[ 0 ] / c[ 2 ];
D = p * p - q;
if (IsZero(D))
{
s[ 0 ] = - p;
return 1;
}
else if (D < 0)
{
return 0;
}
else if (D > 0)
{
G4double sqrt_D = sqrt(D);
s[ 0 ] = sqrt_D - p;
s[ 1 ] = - sqrt_D - p;
return 2;
}
return 0;
}