// This code implementation is the intellectual property of // the GEANT4 collaboration. // // By copying, distributing or modifying the Program (or any work // based on the Program) you indicate your acceptance of this statement, // and all its terms. // // $Id: G4Box.cc,v 1.2 1999/12/15 14:49:45 gunter Exp $ // GEANT4 tag $Name: geant4-01-01 $ // // // Implementation for G4Box class // #include "G4Box.hh" //#include "G4VoxelLimits.hh" //#include "G4Transform.hh" //#ifdef G4VISUALIZE //#include "G4VWindow.hh" //#include "G4Polyline.hh" //#endif #include // Private (implementation) enum: Not for external use // Codes for faces (kPX=plus x face,kMY= minus y face etc) enum ESide {kPX,kMX,kPY,kMY,kPZ,kMZ}; // Constructor - check & set half widths G4Box::G4Box(const G4double pX, const G4double pY, const G4double pZ) { fDx=pX; fDy=pY; fDz=pZ; } // Return whether point inside/outside/on surface, using tolerance EInside G4Box::Inside(const G4ThreeVector& p) const { EInside in=kOutside; if (fabs(p.x())<=fDx-kCarTolerance*0.5) { if (fabs(p.y())<=fDy-kCarTolerance*0.5) { if (fabs(p.z())<=fDz-kCarTolerance*0.5) { in=kInside; } else if (fabs(p.z())<=fDz+kCarTolerance*0.5) { in=kSurface; } } else if (fabs(p.y())<=fDy+kCarTolerance*0.5) { if (fabs(p.z())<=fDz+kCarTolerance*0.5) { in=kSurface; } } } else if (fabs(p.x())<=fDx+kCarTolerance*0.5) { if (fabs(p.y())<=fDy+kCarTolerance*0.5) { if (fabs(p.z())<=fDz+kCarTolerance*0.5) { in=kSurface; } } } return in; } // Calculate side nearest to p, and return normal // If two sides are equidistant, normal of first side (x/y/z) // encountered returned G4ThreeVector G4Box::SurfaceNormal( const G4ThreeVector& p) const { G4double distx,disty,distz; G4ThreeVector norm; // Calculate distances as if in 1st octant distx=fabs(fabs(p.x())-fDx); disty=fabs(fabs(p.y())-fDy); distz=fabs(fabs(p.z())-fDz); if (distx<=disty) { if (distx<=distz) { // Closest to X if (p.x()<0) norm=G4ThreeVector(-1.0,0,0); else norm=G4ThreeVector(1.0,0,0); } else { // Closest to Z if (p.z()<0) norm=G4ThreeVector(0,0,-1.0); else norm=G4ThreeVector(0,0,1.0); } } else { if (disty<=distz) { // Closest to Y if (p.y()<0) norm=G4ThreeVector(0,-1.0,0); else norm=G4ThreeVector(0,1.0,0); } else { // Closest to Z if (p.z()<0) norm=G4ThreeVector(0,0,-1.0); else norm=G4ThreeVector(0,0,1.0); } } return norm; } // Calculate distance to box from an outside point // - return kInfinity 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 G4Box::DistanceToIn(const G4ThreeVector& p,const G4ThreeVector& v) const { G4double safx,safy,safz; G4double smin,sminy,sminz; G4double smax,smaxy,smaxz; G4double stmp; 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 >-tol/2 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 direction away from the shape. if ( ((p.x()*v.x()>=0.0) && safx>-kCarTolerance*0.5) || ((p.y()*v.y()>=0.0) && safy>-kCarTolerance*0.5) || ((p.z()*v.z()>=0.0) && safz>-kCarTolerance*0.5)) return kInfinity; // Compute min / max distances for x/y/z travel: // X Planes if (v.x()) { stmp=1.0/fabs(v.x()); smin=safx*stmp; smax=(fDx+fabs(p.x()))*stmp; } else { if (safx<=0.0) { smin=0.0; smax=kInfinity; } else { return kInfinity; // Travel parallel } } // Y Planes if (v.y()) { stmp=1.0/fabs(v.y()); sminy=safy*stmp; smaxy=(fDy+fabs(p.y()))*stmp; if (sminy>smin) smin=sminy; if (smaxysmax) return kInfinity; } else { if (safy>0.0) { return kInfinity; // Travel parallel } } // Z planes if (v.z()) { stmp=1.0/fabs(v.z()); sminz=safz*stmp; smaxz=(fDz+fabs(p.z()))*stmp; if (sminz>smin) smin=sminz; if (smaxzsmax) return kInfinity; } else { if (safz>0.0) { return kInfinity; // Travel parallel } } if (smin<0) { return 0.0; } return smin; } // Appoximate distance to box. // Returns largest perpendicular distance to the closest x/y/z sides of // the box. // - If inside return 0 G4double G4Box::DistanceToIn(const G4ThreeVector& p) const { G4double safex,safey,safez,safe=0.0; safex=fabs(p.x())-fDx; safey=fabs(p.y())-fDy; safez=fabs(p.z())-fDz; if (safex>safe) safe=safex; if (safey>safe) safe=safey; if (safez>safe) safe=safez; return safe; } // Calcluate distance to surface of box from inside // by calculating distances to box's x/y/z planes. // Smallest distance is exact distance to exiting. // - Eliminate one side of each pair by considering direction of v // - when leaving a surface & v.close, return 0 G4double G4Box::DistanceToOut(const G4ThreeVector& p,const G4ThreeVector& v, const G4bool calcNorm, G4bool *validNorm,G4ThreeVector *n) const { ESide side; G4double pdist,stmp,snxt; if (calcNorm) *validNorm=true; // All normals are valid if (v.x()>0) { pdist=fDx-p.x(); if (pdist>kCarTolerance*0.5) { snxt=pdist/v.x(); side=kPX; } else { if (calcNorm) { *n=G4ThreeVector(1,0,0); } return snxt=0; } } else if (v.x()<0) { pdist=fDx+p.x(); if (pdist>kCarTolerance*0.5) { snxt=-pdist/v.x(); side=kMX; } else { if (calcNorm) { *n=G4ThreeVector(-1,0,0); } return snxt=0; } } else { snxt=kInfinity; } if (v.y()>0) { pdist=fDy-p.y(); if (pdist>kCarTolerance*0.5) { stmp=pdist/v.y(); if (stmpkCarTolerance*0.5) { stmp=-pdist/v.y(); if (stmp0) { pdist=fDz-p.z(); if (pdist>kCarTolerance*0.5) { stmp=pdist/v.z(); if (stmpkCarTolerance*0.5) { stmp=-pdist/v.z(); if (stmp