Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // G4Tubs implementation 26 // G4Tubs implementation 27 // 27 // 28 // 1994-95 P.Kent: first implementation 28 // 1994-95 P.Kent: first implementation 29 // 08.08.00 V.Grichine: more stable roots of 2 29 // 08.08.00 V.Grichine: more stable roots of 2-equation in DistanceToOut(p,v,..) 30 // 07.12.00 V.Grichine: phi-section algorithm 30 // 07.12.00 V.Grichine: phi-section algorithm was changed in Inside(p) 31 // 03.05.05 V.Grichine: SurfaceNormal(p) accor 31 // 03.05.05 V.Grichine: SurfaceNormal(p) according to J.Apostolakis proposal 32 // 24.08.16 E.Tcherniaev: reimplemented Calcul 32 // 24.08.16 E.Tcherniaev: reimplemented CalculateExtent(). 33 // ------------------------------------------- 33 // -------------------------------------------------------------------- 34 34 35 #include "G4Tubs.hh" 35 #include "G4Tubs.hh" 36 36 37 #if !defined(G4GEOM_USE_UTUBS) 37 #if !defined(G4GEOM_USE_UTUBS) 38 38 39 #include "G4GeomTools.hh" 39 #include "G4GeomTools.hh" 40 #include "G4VoxelLimits.hh" 40 #include "G4VoxelLimits.hh" 41 #include "G4AffineTransform.hh" 41 #include "G4AffineTransform.hh" 42 #include "G4GeometryTolerance.hh" 42 #include "G4GeometryTolerance.hh" 43 #include "G4BoundingEnvelope.hh" 43 #include "G4BoundingEnvelope.hh" 44 44 45 #include "G4VPVParameterisation.hh" 45 #include "G4VPVParameterisation.hh" 46 #include "G4QuickRand.hh" 46 #include "G4QuickRand.hh" 47 47 48 #include "G4VGraphicsScene.hh" 48 #include "G4VGraphicsScene.hh" 49 #include "G4Polyhedron.hh" 49 #include "G4Polyhedron.hh" 50 50 51 using namespace CLHEP; 51 using namespace CLHEP; 52 52 53 ////////////////////////////////////////////// 53 ///////////////////////////////////////////////////////////////////////// 54 // 54 // 55 // Constructor - check parameters, convert ang 55 // Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI 56 // - note if pdphi>2PI then reset 56 // - note if pdphi>2PI then reset to 2PI 57 57 58 G4Tubs::G4Tubs( const G4String& pName, << 58 G4Tubs::G4Tubs( const G4String &pName, 59 G4double pRMin, G4double 59 G4double pRMin, G4double pRMax, 60 G4double pDz, 60 G4double pDz, 61 G4double pSPhi, G4double 61 G4double pSPhi, G4double pDPhi ) 62 : G4CSGSolid(pName), fRMin(pRMin), fRMax(pR 62 : G4CSGSolid(pName), fRMin(pRMin), fRMax(pRMax), fDz(pDz), 63 fSPhi(0), fDPhi(0), 63 fSPhi(0), fDPhi(0), 64 fInvRmax( pRMax > 0.0 ? 1.0/pRMax : 0.0 ) 64 fInvRmax( pRMax > 0.0 ? 1.0/pRMax : 0.0 ), 65 fInvRmin( pRMin > 0.0 ? 1.0/pRMin : 0.0 ) 65 fInvRmin( pRMin > 0.0 ? 1.0/pRMin : 0.0 ) 66 { 66 { 67 kRadTolerance = G4GeometryTolerance::GetInst 67 kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance(); 68 kAngTolerance = G4GeometryTolerance::GetInst 68 kAngTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance(); 69 69 70 halfCarTolerance=kCarTolerance*0.5; 70 halfCarTolerance=kCarTolerance*0.5; 71 halfRadTolerance=kRadTolerance*0.5; 71 halfRadTolerance=kRadTolerance*0.5; 72 halfAngTolerance=kAngTolerance*0.5; 72 halfAngTolerance=kAngTolerance*0.5; 73 73 74 if (pDz<=0) // Check z-len 74 if (pDz<=0) // Check z-len 75 { 75 { 76 std::ostringstream message; 76 std::ostringstream message; 77 message << "Negative Z half-length (" << p 77 message << "Negative Z half-length (" << pDz << ") in solid: " << GetName(); 78 G4Exception("G4Tubs::G4Tubs()", "GeomSolid 78 G4Exception("G4Tubs::G4Tubs()", "GeomSolids0002", FatalException, message); 79 } 79 } 80 if ( (pRMin >= pRMax) || (pRMin < 0) ) // Ch 80 if ( (pRMin >= pRMax) || (pRMin < 0) ) // Check radii 81 { 81 { 82 std::ostringstream message; 82 std::ostringstream message; 83 message << "Invalid values for radii in so 83 message << "Invalid values for radii in solid: " << GetName() 84 << G4endl 84 << G4endl 85 << " pRMin = " << pRMin << 85 << " pRMin = " << pRMin << ", pRMax = " << pRMax; 86 G4Exception("G4Tubs::G4Tubs()", "GeomSolid 86 G4Exception("G4Tubs::G4Tubs()", "GeomSolids0002", FatalException, message); 87 } 87 } 88 88 89 // Check angles 89 // Check angles 90 // 90 // 91 CheckPhiAngles(pSPhi, pDPhi); 91 CheckPhiAngles(pSPhi, pDPhi); 92 } 92 } 93 93 94 ////////////////////////////////////////////// 94 /////////////////////////////////////////////////////////////////////// 95 // 95 // 96 // Fake default constructor - sets only member 96 // Fake default constructor - sets only member data and allocates memory 97 // for usage restri 97 // for usage restricted to object persistency. 98 // 98 // 99 G4Tubs::G4Tubs( __void__& a ) 99 G4Tubs::G4Tubs( __void__& a ) 100 : G4CSGSolid(a) << 100 : G4CSGSolid(a), kRadTolerance(0.), kAngTolerance(0.), >> 101 fRMin(0.), fRMax(0.), fDz(0.), fSPhi(0.), fDPhi(0.), >> 102 sinCPhi(0.), cosCPhi(0.), cosHDPhi(0.), cosHDPhiOT(0.), cosHDPhiIT(0.), >> 103 sinSPhi(0.), cosSPhi(0.), sinEPhi(0.), cosEPhi(0.), >> 104 fPhiFullTube(false), fInvRmax(0.), fInvRmin(0.), >> 105 halfCarTolerance(0.), halfRadTolerance(0.), >> 106 halfAngTolerance(0.) 101 { 107 { 102 } 108 } 103 109 104 ////////////////////////////////////////////// 110 ////////////////////////////////////////////////////////////////////////// 105 // 111 // 106 // Destructor 112 // Destructor 107 113 108 G4Tubs::~G4Tubs() = default; << 114 G4Tubs::~G4Tubs() >> 115 { >> 116 } 109 117 110 ////////////////////////////////////////////// 118 ////////////////////////////////////////////////////////////////////////// 111 // 119 // 112 // Copy constructor 120 // Copy constructor 113 121 114 G4Tubs::G4Tubs(const G4Tubs&) = default; << 122 G4Tubs::G4Tubs(const G4Tubs& rhs) >> 123 : G4CSGSolid(rhs), >> 124 kRadTolerance(rhs.kRadTolerance), kAngTolerance(rhs.kAngTolerance), >> 125 fRMin(rhs.fRMin), fRMax(rhs.fRMax), fDz(rhs.fDz), >> 126 fSPhi(rhs.fSPhi), fDPhi(rhs.fDPhi), >> 127 sinCPhi(rhs.sinCPhi), cosCPhi(rhs.cosCPhi), cosHDPhi(rhs.cosHDPhi), >> 128 cosHDPhiOT(rhs.cosHDPhiOT), cosHDPhiIT(rhs.cosHDPhiIT), >> 129 sinSPhi(rhs.sinSPhi), cosSPhi(rhs.cosSPhi), >> 130 sinEPhi(rhs.sinEPhi), cosEPhi(rhs.cosEPhi), fPhiFullTube(rhs.fPhiFullTube), >> 131 fInvRmax(rhs.fInvRmax), fInvRmin(rhs.fInvRmin), >> 132 halfCarTolerance(rhs.halfCarTolerance), >> 133 halfRadTolerance(rhs.halfRadTolerance), >> 134 halfAngTolerance(rhs.halfAngTolerance) >> 135 { >> 136 } 115 137 116 ////////////////////////////////////////////// 138 ////////////////////////////////////////////////////////////////////////// 117 // 139 // 118 // Assignment operator 140 // Assignment operator 119 141 120 G4Tubs& G4Tubs::operator = (const G4Tubs& rhs) 142 G4Tubs& G4Tubs::operator = (const G4Tubs& rhs) 121 { 143 { 122 // Check assignment to self 144 // Check assignment to self 123 // 145 // 124 if (this == &rhs) { return *this; } 146 if (this == &rhs) { return *this; } 125 147 126 // Copy base class data 148 // Copy base class data 127 // 149 // 128 G4CSGSolid::operator=(rhs); 150 G4CSGSolid::operator=(rhs); 129 151 130 // Copy data 152 // Copy data 131 // 153 // 132 kRadTolerance = rhs.kRadTolerance; kAngTole 154 kRadTolerance = rhs.kRadTolerance; kAngTolerance = rhs.kAngTolerance; 133 fRMin = rhs.fRMin; fRMax = rhs.fRMax; fDz = 155 fRMin = rhs.fRMin; fRMax = rhs.fRMax; fDz = rhs.fDz; 134 fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi; 156 fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi; 135 sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPh 157 sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPhi; cosHDPhi = rhs.cosHDPhi; 136 cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = r 158 cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = rhs.cosHDPhiIT; 137 sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPh 159 sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPhi; 138 sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPh 160 sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPhi; 139 fPhiFullTube = rhs.fPhiFullTube; 161 fPhiFullTube = rhs.fPhiFullTube; 140 fInvRmax = rhs.fInvRmax; 162 fInvRmax = rhs.fInvRmax; 141 fInvRmin = rhs.fInvRmin; 163 fInvRmin = rhs.fInvRmin; 142 halfCarTolerance = rhs.halfCarTolerance; 164 halfCarTolerance = rhs.halfCarTolerance; 143 halfRadTolerance = rhs.halfRadTolerance; 165 halfRadTolerance = rhs.halfRadTolerance; 144 halfAngTolerance = rhs.halfAngTolerance; 166 halfAngTolerance = rhs.halfAngTolerance; 145 167 146 return *this; 168 return *this; 147 } 169 } 148 170 149 ////////////////////////////////////////////// 171 ///////////////////////////////////////////////////////////////////////// 150 // 172 // 151 // Dispatch to parameterisation for replicatio 173 // Dispatch to parameterisation for replication mechanism dimension 152 // computation & modification. 174 // computation & modification. 153 175 154 void G4Tubs::ComputeDimensions( G4VPVPar 176 void G4Tubs::ComputeDimensions( G4VPVParameterisation* p, 155 const G4int n, 177 const G4int n, 156 const G4VPhysi 178 const G4VPhysicalVolume* pRep ) 157 { 179 { 158 p->ComputeDimensions(*this,n,pRep) ; 180 p->ComputeDimensions(*this,n,pRep) ; 159 } 181 } 160 182 161 ////////////////////////////////////////////// 183 ///////////////////////////////////////////////////////////////////////// 162 // 184 // 163 // Get bounding box 185 // Get bounding box 164 186 165 void G4Tubs::BoundingLimits(G4ThreeVector& pMi 187 void G4Tubs::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const 166 { 188 { 167 G4double rmin = GetInnerRadius(); 189 G4double rmin = GetInnerRadius(); 168 G4double rmax = GetOuterRadius(); 190 G4double rmax = GetOuterRadius(); 169 G4double dz = GetZHalfLength(); 191 G4double dz = GetZHalfLength(); 170 192 171 // Find bounding box 193 // Find bounding box 172 // 194 // 173 if (GetDeltaPhiAngle() < twopi) 195 if (GetDeltaPhiAngle() < twopi) 174 { 196 { 175 G4TwoVector vmin,vmax; 197 G4TwoVector vmin,vmax; 176 G4GeomTools::DiskExtent(rmin,rmax, 198 G4GeomTools::DiskExtent(rmin,rmax, 177 GetSinStartPhi(),G 199 GetSinStartPhi(),GetCosStartPhi(), 178 GetSinEndPhi(),Get 200 GetSinEndPhi(),GetCosEndPhi(), 179 vmin,vmax); 201 vmin,vmax); 180 pMin.set(vmin.x(),vmin.y(),-dz); 202 pMin.set(vmin.x(),vmin.y(),-dz); 181 pMax.set(vmax.x(),vmax.y(), dz); 203 pMax.set(vmax.x(),vmax.y(), dz); 182 } 204 } 183 else 205 else 184 { 206 { 185 pMin.set(-rmax,-rmax,-dz); 207 pMin.set(-rmax,-rmax,-dz); 186 pMax.set( rmax, rmax, dz); 208 pMax.set( rmax, rmax, dz); 187 } 209 } 188 210 189 // Check correctness of the bounding box 211 // Check correctness of the bounding box 190 // 212 // 191 if (pMin.x() >= pMax.x() || pMin.y() >= pMax 213 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z()) 192 { 214 { 193 std::ostringstream message; 215 std::ostringstream message; 194 message << "Bad bounding box (min >= max) 216 message << "Bad bounding box (min >= max) for solid: " 195 << GetName() << " !" 217 << GetName() << " !" 196 << "\npMin = " << pMin 218 << "\npMin = " << pMin 197 << "\npMax = " << pMax; 219 << "\npMax = " << pMax; 198 G4Exception("G4Tubs::BoundingLimits()", "G 220 G4Exception("G4Tubs::BoundingLimits()", "GeomMgt0001", 199 JustWarning, message); 221 JustWarning, message); 200 DumpInfo(); 222 DumpInfo(); 201 } 223 } 202 } 224 } 203 225 204 ////////////////////////////////////////////// 226 ///////////////////////////////////////////////////////////////////////// 205 // 227 // 206 // Calculate extent under transform and specif 228 // Calculate extent under transform and specified limit 207 229 208 G4bool G4Tubs::CalculateExtent( const EAxis 230 G4bool G4Tubs::CalculateExtent( const EAxis pAxis, 209 const G4VoxelL 231 const G4VoxelLimits& pVoxelLimit, 210 const G4Affine 232 const G4AffineTransform& pTransform, 211 G4double 233 G4double& pMin, 212 G4double 234 G4double& pMax ) const 213 { 235 { 214 G4ThreeVector bmin, bmax; 236 G4ThreeVector bmin, bmax; 215 G4bool exist; 237 G4bool exist; 216 238 217 // Get bounding box 239 // Get bounding box 218 BoundingLimits(bmin,bmax); 240 BoundingLimits(bmin,bmax); 219 241 220 // Check bounding box 242 // Check bounding box 221 G4BoundingEnvelope bbox(bmin,bmax); 243 G4BoundingEnvelope bbox(bmin,bmax); 222 #ifdef G4BBOX_EXTENT 244 #ifdef G4BBOX_EXTENT 223 return bbox.CalculateExtent(pAxis,pVoxelLimi 245 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); 224 #endif 246 #endif 225 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVox 247 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax)) 226 { 248 { 227 return exist = pMin < pMax; << 249 return exist = (pMin < pMax) ? true : false; 228 } 250 } 229 251 230 // Get parameters of the solid 252 // Get parameters of the solid 231 G4double rmin = GetInnerRadius(); 253 G4double rmin = GetInnerRadius(); 232 G4double rmax = GetOuterRadius(); 254 G4double rmax = GetOuterRadius(); 233 G4double dz = GetZHalfLength(); 255 G4double dz = GetZHalfLength(); 234 G4double dphi = GetDeltaPhiAngle(); 256 G4double dphi = GetDeltaPhiAngle(); 235 257 236 // Find bounding envelope and calculate exte 258 // Find bounding envelope and calculate extent 237 // 259 // 238 const G4int NSTEPS = 24; // numbe 260 const G4int NSTEPS = 24; // number of steps for whole circle 239 G4double astep = twopi/NSTEPS; // max a 261 G4double astep = twopi/NSTEPS; // max angle for one step 240 G4int ksteps = (dphi <= astep) ? 1 : (G4i 262 G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1; 241 G4double ang = dphi/ksteps; 263 G4double ang = dphi/ksteps; 242 264 243 G4double sinHalf = std::sin(0.5*ang); 265 G4double sinHalf = std::sin(0.5*ang); 244 G4double cosHalf = std::cos(0.5*ang); 266 G4double cosHalf = std::cos(0.5*ang); 245 G4double sinStep = 2.*sinHalf*cosHalf; 267 G4double sinStep = 2.*sinHalf*cosHalf; 246 G4double cosStep = 1. - 2.*sinHalf*sinHalf; 268 G4double cosStep = 1. - 2.*sinHalf*sinHalf; 247 G4double rext = rmax/cosHalf; 269 G4double rext = rmax/cosHalf; 248 270 249 // bounding envelope for full cylinder consi 271 // bounding envelope for full cylinder consists of two polygons, 250 // in other cases it is a sequence of quadri 272 // in other cases it is a sequence of quadrilaterals 251 if (rmin == 0 && dphi == twopi) 273 if (rmin == 0 && dphi == twopi) 252 { 274 { 253 G4double sinCur = sinHalf; 275 G4double sinCur = sinHalf; 254 G4double cosCur = cosHalf; 276 G4double cosCur = cosHalf; 255 277 256 G4ThreeVectorList baseA(NSTEPS),baseB(NSTE 278 G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS); 257 for (G4int k=0; k<NSTEPS; ++k) 279 for (G4int k=0; k<NSTEPS; ++k) 258 { 280 { 259 baseA[k].set(rext*cosCur,rext*sinCur,-dz 281 baseA[k].set(rext*cosCur,rext*sinCur,-dz); 260 baseB[k].set(rext*cosCur,rext*sinCur, dz 282 baseB[k].set(rext*cosCur,rext*sinCur, dz); 261 283 262 G4double sinTmp = sinCur; 284 G4double sinTmp = sinCur; 263 sinCur = sinCur*cosStep + cosCur*sinStep 285 sinCur = sinCur*cosStep + cosCur*sinStep; 264 cosCur = cosCur*cosStep - sinTmp*sinStep 286 cosCur = cosCur*cosStep - sinTmp*sinStep; 265 } 287 } 266 std::vector<const G4ThreeVectorList *> pol 288 std::vector<const G4ThreeVectorList *> polygons(2); 267 polygons[0] = &baseA; 289 polygons[0] = &baseA; 268 polygons[1] = &baseB; 290 polygons[1] = &baseB; 269 G4BoundingEnvelope benv(bmin,bmax,polygons 291 G4BoundingEnvelope benv(bmin,bmax,polygons); 270 exist = benv.CalculateExtent(pAxis,pVoxelL 292 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); 271 } 293 } 272 else 294 else 273 { 295 { 274 G4double sinStart = GetSinStartPhi(); 296 G4double sinStart = GetSinStartPhi(); 275 G4double cosStart = GetCosStartPhi(); 297 G4double cosStart = GetCosStartPhi(); 276 G4double sinEnd = GetSinEndPhi(); 298 G4double sinEnd = GetSinEndPhi(); 277 G4double cosEnd = GetCosEndPhi(); 299 G4double cosEnd = GetCosEndPhi(); 278 G4double sinCur = sinStart*cosHalf + cos 300 G4double sinCur = sinStart*cosHalf + cosStart*sinHalf; 279 G4double cosCur = cosStart*cosHalf - sin 301 G4double cosCur = cosStart*cosHalf - sinStart*sinHalf; 280 302 281 // set quadrilaterals 303 // set quadrilaterals 282 G4ThreeVectorList pols[NSTEPS+2]; 304 G4ThreeVectorList pols[NSTEPS+2]; 283 for (G4int k=0; k<ksteps+2; ++k) pols[k].r 305 for (G4int k=0; k<ksteps+2; ++k) pols[k].resize(4); 284 pols[0][0].set(rmin*cosStart,rmin*sinStart 306 pols[0][0].set(rmin*cosStart,rmin*sinStart, dz); 285 pols[0][1].set(rmin*cosStart,rmin*sinStart 307 pols[0][1].set(rmin*cosStart,rmin*sinStart,-dz); 286 pols[0][2].set(rmax*cosStart,rmax*sinStart 308 pols[0][2].set(rmax*cosStart,rmax*sinStart,-dz); 287 pols[0][3].set(rmax*cosStart,rmax*sinStart 309 pols[0][3].set(rmax*cosStart,rmax*sinStart, dz); 288 for (G4int k=1; k<ksteps+1; ++k) 310 for (G4int k=1; k<ksteps+1; ++k) 289 { 311 { 290 pols[k][0].set(rmin*cosCur,rmin*sinCur, 312 pols[k][0].set(rmin*cosCur,rmin*sinCur, dz); 291 pols[k][1].set(rmin*cosCur,rmin*sinCur,- 313 pols[k][1].set(rmin*cosCur,rmin*sinCur,-dz); 292 pols[k][2].set(rext*cosCur,rext*sinCur,- 314 pols[k][2].set(rext*cosCur,rext*sinCur,-dz); 293 pols[k][3].set(rext*cosCur,rext*sinCur, 315 pols[k][3].set(rext*cosCur,rext*sinCur, dz); 294 316 295 G4double sinTmp = sinCur; 317 G4double sinTmp = sinCur; 296 sinCur = sinCur*cosStep + cosCur*sinStep 318 sinCur = sinCur*cosStep + cosCur*sinStep; 297 cosCur = cosCur*cosStep - sinTmp*sinStep 319 cosCur = cosCur*cosStep - sinTmp*sinStep; 298 } 320 } 299 pols[ksteps+1][0].set(rmin*cosEnd,rmin*sin 321 pols[ksteps+1][0].set(rmin*cosEnd,rmin*sinEnd, dz); 300 pols[ksteps+1][1].set(rmin*cosEnd,rmin*sin 322 pols[ksteps+1][1].set(rmin*cosEnd,rmin*sinEnd,-dz); 301 pols[ksteps+1][2].set(rmax*cosEnd,rmax*sin 323 pols[ksteps+1][2].set(rmax*cosEnd,rmax*sinEnd,-dz); 302 pols[ksteps+1][3].set(rmax*cosEnd,rmax*sin 324 pols[ksteps+1][3].set(rmax*cosEnd,rmax*sinEnd, dz); 303 325 304 // set envelope and calculate extent 326 // set envelope and calculate extent 305 std::vector<const G4ThreeVectorList *> pol 327 std::vector<const G4ThreeVectorList *> polygons; 306 polygons.resize(ksteps+2); 328 polygons.resize(ksteps+2); 307 for (G4int k=0; k<ksteps+2; ++k) polygons[ 329 for (G4int k=0; k<ksteps+2; ++k) polygons[k] = &pols[k]; 308 G4BoundingEnvelope benv(bmin,bmax,polygons 330 G4BoundingEnvelope benv(bmin,bmax,polygons); 309 exist = benv.CalculateExtent(pAxis,pVoxelL 331 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); 310 } 332 } 311 return exist; 333 return exist; 312 } 334 } 313 335 314 ////////////////////////////////////////////// 336 /////////////////////////////////////////////////////////////////////////// 315 // 337 // 316 // Return whether point inside/outside/on surf 338 // Return whether point inside/outside/on surface 317 339 318 EInside G4Tubs::Inside( const G4ThreeVector& p 340 EInside G4Tubs::Inside( const G4ThreeVector& p ) const 319 { 341 { 320 G4double r2,pPhi,tolRMin,tolRMax; 342 G4double r2,pPhi,tolRMin,tolRMax; 321 EInside in = kOutside ; 343 EInside in = kOutside ; 322 344 323 if (std::fabs(p.z()) <= fDz - halfCarToleran 345 if (std::fabs(p.z()) <= fDz - halfCarTolerance) 324 { 346 { 325 r2 = p.x()*p.x() + p.y()*p.y() ; 347 r2 = p.x()*p.x() + p.y()*p.y() ; 326 348 327 if (fRMin != 0.0) { tolRMin = fRMin + half << 349 if (fRMin) { tolRMin = fRMin + halfRadTolerance ; } 328 else { tolRMin = 0 ; } 350 else { tolRMin = 0 ; } 329 351 330 tolRMax = fRMax - halfRadTolerance ; 352 tolRMax = fRMax - halfRadTolerance ; 331 353 332 if ((r2 >= tolRMin*tolRMin) && (r2 <= tolR 354 if ((r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax)) 333 { 355 { 334 if ( fPhiFullTube ) 356 if ( fPhiFullTube ) 335 { 357 { 336 in = kInside ; 358 in = kInside ; 337 } 359 } 338 else 360 else 339 { 361 { 340 // Try inner tolerant phi boundaries ( 362 // Try inner tolerant phi boundaries (=>inside) 341 // if not inside, try outer tolerant p 363 // if not inside, try outer tolerant phi boundaries 342 364 343 if ( (tolRMin==0) && (std::fabs(p.x()) 365 if ( (tolRMin==0) && (std::fabs(p.x())<=halfCarTolerance) 344 && (std::fabs(p.y()) 366 && (std::fabs(p.y())<=halfCarTolerance) ) 345 { 367 { 346 in=kSurface; 368 in=kSurface; 347 } 369 } 348 else 370 else 349 { 371 { 350 pPhi = std::atan2(p.y(),p.x()) ; 372 pPhi = std::atan2(p.y(),p.x()) ; 351 if ( pPhi < -halfAngTolerance ) { p 373 if ( pPhi < -halfAngTolerance ) { pPhi += twopi; } // 0<=pPhi<2pi 352 374 353 if ( fSPhi >= 0 ) 375 if ( fSPhi >= 0 ) 354 { 376 { 355 if ( (std::fabs(pPhi) < halfAngTol 377 if ( (std::fabs(pPhi) < halfAngTolerance) 356 && (std::fabs(fSPhi + fDPhi - tw 378 && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) 357 { 379 { 358 pPhi += twopi ; // 0 <= pPhi < 2 380 pPhi += twopi ; // 0 <= pPhi < 2pi 359 } 381 } 360 if ( (pPhi >= fSPhi + halfAngToler 382 if ( (pPhi >= fSPhi + halfAngTolerance) 361 && (pPhi <= fSPhi + fDPhi - half 383 && (pPhi <= fSPhi + fDPhi - halfAngTolerance) ) 362 { 384 { 363 in = kInside ; 385 in = kInside ; 364 } 386 } 365 else if ( (pPhi >= fSPhi - halfAng 387 else if ( (pPhi >= fSPhi - halfAngTolerance) 366 && (pPhi <= fSPhi + fDPhi + 388 && (pPhi <= fSPhi + fDPhi + halfAngTolerance) ) 367 { 389 { 368 in = kSurface ; 390 in = kSurface ; 369 } 391 } 370 } 392 } 371 else // fSPhi < 0 393 else // fSPhi < 0 372 { 394 { 373 if ( (pPhi <= fSPhi + twopi - half 395 if ( (pPhi <= fSPhi + twopi - halfAngTolerance) 374 && (pPhi >= fSPhi + fDPhi + hal 396 && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} //kOutside 375 else if ( (pPhi <= fSPhi + twopi + 397 else if ( (pPhi <= fSPhi + twopi + halfAngTolerance) 376 && (pPhi >= fSPhi + fDPhi 398 && (pPhi >= fSPhi + fDPhi - halfAngTolerance) ) 377 { 399 { 378 in = kSurface ; 400 in = kSurface ; 379 } 401 } 380 else 402 else 381 { 403 { 382 in = kInside ; 404 in = kInside ; 383 } 405 } 384 } 406 } 385 } 407 } 386 } 408 } 387 } 409 } 388 else // Try generous boundaries 410 else // Try generous boundaries 389 { 411 { 390 tolRMin = fRMin - halfRadTolerance ; 412 tolRMin = fRMin - halfRadTolerance ; 391 tolRMax = fRMax + halfRadTolerance ; 413 tolRMax = fRMax + halfRadTolerance ; 392 414 393 if ( tolRMin < 0 ) { tolRMin = 0; } 415 if ( tolRMin < 0 ) { tolRMin = 0; } 394 416 395 if ( (r2 >= tolRMin*tolRMin) && (r2 <= t 417 if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) ) 396 { 418 { 397 if (fPhiFullTube || (r2 <=halfRadToler 419 if (fPhiFullTube || (r2 <=halfRadTolerance*halfRadTolerance) ) 398 { // Continuous 420 { // Continuous in phi or on z-axis 399 in = kSurface ; 421 in = kSurface ; 400 } 422 } 401 else // Try outer tolerant phi boundar 423 else // Try outer tolerant phi boundaries only 402 { 424 { 403 pPhi = std::atan2(p.y(),p.x()) ; 425 pPhi = std::atan2(p.y(),p.x()) ; 404 426 405 if ( pPhi < -halfAngTolerance) { pP 427 if ( pPhi < -halfAngTolerance) { pPhi += twopi; } // 0<=pPhi<2pi 406 if ( fSPhi >= 0 ) 428 if ( fSPhi >= 0 ) 407 { 429 { 408 if ( (std::fabs(pPhi) < halfAngTol 430 if ( (std::fabs(pPhi) < halfAngTolerance) 409 && (std::fabs(fSPhi + fDPhi - tw 431 && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) 410 { 432 { 411 pPhi += twopi ; // 0 <= pPhi < 2 433 pPhi += twopi ; // 0 <= pPhi < 2pi 412 } 434 } 413 if ( (pPhi >= fSPhi - halfAngToler 435 if ( (pPhi >= fSPhi - halfAngTolerance) 414 && (pPhi <= fSPhi + fDPhi + half 436 && (pPhi <= fSPhi + fDPhi + halfAngTolerance) ) 415 { 437 { 416 in = kSurface ; 438 in = kSurface ; 417 } 439 } 418 } 440 } 419 else // fSPhi < 0 441 else // fSPhi < 0 420 { 442 { 421 if ( (pPhi <= fSPhi + twopi - half 443 if ( (pPhi <= fSPhi + twopi - halfAngTolerance) 422 && (pPhi >= fSPhi + fDPhi + half 444 && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} // kOutside 423 else 445 else 424 { 446 { 425 in = kSurface ; 447 in = kSurface ; 426 } 448 } 427 } 449 } 428 } 450 } 429 } 451 } 430 } 452 } 431 } 453 } 432 else if (std::fabs(p.z()) <= fDz + halfCarTo 454 else if (std::fabs(p.z()) <= fDz + halfCarTolerance) 433 { / 455 { // Check within tolerant r limits 434 r2 = p.x()*p.x() + p.y()*p.y() ; 456 r2 = p.x()*p.x() + p.y()*p.y() ; 435 tolRMin = fRMin - halfRadTolerance ; 457 tolRMin = fRMin - halfRadTolerance ; 436 tolRMax = fRMax + halfRadTolerance ; 458 tolRMax = fRMax + halfRadTolerance ; 437 459 438 if ( tolRMin < 0 ) { tolRMin = 0; } 460 if ( tolRMin < 0 ) { tolRMin = 0; } 439 461 440 if ( (r2 >= tolRMin*tolRMin) && (r2 <= tol 462 if ( (r2 >= tolRMin*tolRMin) && (r2 <= tolRMax*tolRMax) ) 441 { 463 { 442 if (fPhiFullTube || (r2 <=halfRadToleran 464 if (fPhiFullTube || (r2 <=halfRadTolerance*halfRadTolerance)) 443 { // Continuous i 465 { // Continuous in phi or on z-axis 444 in = kSurface ; 466 in = kSurface ; 445 } 467 } 446 else // Try outer tolerant phi boundarie 468 else // Try outer tolerant phi boundaries 447 { 469 { 448 pPhi = std::atan2(p.y(),p.x()) ; 470 pPhi = std::atan2(p.y(),p.x()) ; 449 471 450 if ( pPhi < -halfAngTolerance ) { pPh 472 if ( pPhi < -halfAngTolerance ) { pPhi += twopi; } // 0<=pPhi<2pi 451 if ( fSPhi >= 0 ) 473 if ( fSPhi >= 0 ) 452 { 474 { 453 if ( (std::fabs(pPhi) < halfAngToler 475 if ( (std::fabs(pPhi) < halfAngTolerance) 454 && (std::fabs(fSPhi + fDPhi - twop 476 && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) 455 { 477 { 456 pPhi += twopi ; // 0 <= pPhi < 2pi 478 pPhi += twopi ; // 0 <= pPhi < 2pi 457 } 479 } 458 if ( (pPhi >= fSPhi - halfAngToleran 480 if ( (pPhi >= fSPhi - halfAngTolerance) 459 && (pPhi <= fSPhi + fDPhi + halfAn 481 && (pPhi <= fSPhi + fDPhi + halfAngTolerance) ) 460 { 482 { 461 in = kSurface; 483 in = kSurface; 462 } 484 } 463 } 485 } 464 else // fSPhi < 0 486 else // fSPhi < 0 465 { 487 { 466 if ( (pPhi <= fSPhi + twopi - halfAn 488 if ( (pPhi <= fSPhi + twopi - halfAngTolerance) 467 && (pPhi >= fSPhi + fDPhi + halfA 489 && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) {;} 468 else 490 else 469 { 491 { 470 in = kSurface ; 492 in = kSurface ; 471 } 493 } 472 } 494 } 473 } 495 } 474 } 496 } 475 } 497 } 476 return in; 498 return in; 477 } 499 } 478 500 479 ////////////////////////////////////////////// 501 /////////////////////////////////////////////////////////////////////////// 480 // 502 // 481 // Return unit normal of surface closest to p 503 // Return unit normal of surface closest to p 482 // - note if point on z axis, ignore phi divid 504 // - note if point on z axis, ignore phi divided sides 483 // - unsafe if point close to z axis a rmin=0 505 // - unsafe if point close to z axis a rmin=0 - no explicit checks 484 506 485 G4ThreeVector G4Tubs::SurfaceNormal( const G4T 507 G4ThreeVector G4Tubs::SurfaceNormal( const G4ThreeVector& p ) const 486 { 508 { 487 G4int noSurfaces = 0; 509 G4int noSurfaces = 0; 488 G4double rho, pPhi; 510 G4double rho, pPhi; 489 G4double distZ, distRMin, distRMax; 511 G4double distZ, distRMin, distRMax; 490 G4double distSPhi = kInfinity, distEPhi = kI 512 G4double distSPhi = kInfinity, distEPhi = kInfinity; 491 513 492 G4ThreeVector norm, sumnorm(0.,0.,0.); 514 G4ThreeVector norm, sumnorm(0.,0.,0.); 493 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0); 515 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0); 494 G4ThreeVector nR, nPs, nPe; 516 G4ThreeVector nR, nPs, nPe; 495 517 496 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()); 518 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()); 497 519 498 distRMin = std::fabs(rho - fRMin); 520 distRMin = std::fabs(rho - fRMin); 499 distRMax = std::fabs(rho - fRMax); 521 distRMax = std::fabs(rho - fRMax); 500 distZ = std::fabs(std::fabs(p.z()) - fDz) 522 distZ = std::fabs(std::fabs(p.z()) - fDz); 501 523 502 if (!fPhiFullTube) // Protected against ( 524 if (!fPhiFullTube) // Protected against (0,0,z) 503 { 525 { 504 if ( rho > halfCarTolerance ) 526 if ( rho > halfCarTolerance ) 505 { 527 { 506 pPhi = std::atan2(p.y(),p.x()); 528 pPhi = std::atan2(p.y(),p.x()); 507 529 508 if (pPhi < fSPhi-halfCarTolerance) 530 if (pPhi < fSPhi-halfCarTolerance) { pPhi += twopi; } 509 else if (pPhi > fSPhi+fDPhi+halfCarToler 531 else if (pPhi > fSPhi+fDPhi+halfCarTolerance) { pPhi -= twopi; } 510 532 511 distSPhi = std::fabs( pPhi - fSPhi ); 533 distSPhi = std::fabs( pPhi - fSPhi ); 512 distEPhi = std::fabs( pPhi - fSPhi - fDP 534 distEPhi = std::fabs( pPhi - fSPhi - fDPhi ); 513 } 535 } 514 else if ( fRMin == 0.0 ) << 536 else if ( !fRMin ) 515 { 537 { 516 distSPhi = 0.; 538 distSPhi = 0.; 517 distEPhi = 0.; 539 distEPhi = 0.; 518 } 540 } 519 nPs = G4ThreeVector( sinSPhi, -cosSPhi, 0 541 nPs = G4ThreeVector( sinSPhi, -cosSPhi, 0 ); 520 nPe = G4ThreeVector( -sinEPhi, cosEPhi, 0 542 nPe = G4ThreeVector( -sinEPhi, cosEPhi, 0 ); 521 } 543 } 522 if ( rho > halfCarTolerance ) { nR = G4Three 544 if ( rho > halfCarTolerance ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); } 523 545 524 if( distRMax <= halfCarTolerance ) 546 if( distRMax <= halfCarTolerance ) 525 { 547 { 526 ++noSurfaces; 548 ++noSurfaces; 527 sumnorm += nR; 549 sumnorm += nR; 528 } 550 } 529 if( (fRMin != 0.0) && (distRMin <= halfCarTo << 551 if( fRMin && (distRMin <= halfCarTolerance) ) 530 { 552 { 531 ++noSurfaces; 553 ++noSurfaces; 532 sumnorm -= nR; 554 sumnorm -= nR; 533 } 555 } 534 if( fDPhi < twopi ) 556 if( fDPhi < twopi ) 535 { 557 { 536 if (distSPhi <= halfAngTolerance) 558 if (distSPhi <= halfAngTolerance) 537 { 559 { 538 ++noSurfaces; 560 ++noSurfaces; 539 sumnorm += nPs; 561 sumnorm += nPs; 540 } 562 } 541 if (distEPhi <= halfAngTolerance) 563 if (distEPhi <= halfAngTolerance) 542 { 564 { 543 ++noSurfaces; 565 ++noSurfaces; 544 sumnorm += nPe; 566 sumnorm += nPe; 545 } 567 } 546 } 568 } 547 if (distZ <= halfCarTolerance) 569 if (distZ <= halfCarTolerance) 548 { 570 { 549 ++noSurfaces; 571 ++noSurfaces; 550 if ( p.z() >= 0.) { sumnorm += nZ; } 572 if ( p.z() >= 0.) { sumnorm += nZ; } 551 else { sumnorm -= nZ; } 573 else { sumnorm -= nZ; } 552 } 574 } 553 if ( noSurfaces == 0 ) 575 if ( noSurfaces == 0 ) 554 { 576 { 555 #ifdef G4CSGDEBUG 577 #ifdef G4CSGDEBUG 556 G4Exception("G4Tubs::SurfaceNormal(p)", "G 578 G4Exception("G4Tubs::SurfaceNormal(p)", "GeomSolids1002", 557 JustWarning, "Point p is not o 579 JustWarning, "Point p is not on surface !?" ); 558 G4long oldprc = G4cout.precision(20); << 580 G4int oldprc = G4cout.precision(20); 559 G4cout<< "G4Tubs::SN ( "<<p.x()<<", "<<p.y 581 G4cout<< "G4Tubs::SN ( "<<p.x()<<", "<<p.y()<<", "<<p.z()<<" ); " 560 << G4endl << G4endl; 582 << G4endl << G4endl; 561 G4cout.precision(oldprc) ; 583 G4cout.precision(oldprc) ; 562 #endif 584 #endif 563 norm = ApproxSurfaceNormal(p); 585 norm = ApproxSurfaceNormal(p); 564 } 586 } 565 else if ( noSurfaces == 1 ) { norm = sumnor 587 else if ( noSurfaces == 1 ) { norm = sumnorm; } 566 else { norm = sumnor 588 else { norm = sumnorm.unit(); } 567 589 568 return norm; 590 return norm; 569 } 591 } 570 592 571 ////////////////////////////////////////////// 593 ///////////////////////////////////////////////////////////////////////////// 572 // 594 // 573 // Algorithm for SurfaceNormal() following the 595 // Algorithm for SurfaceNormal() following the original specification 574 // for points not on the surface 596 // for points not on the surface 575 597 576 G4ThreeVector G4Tubs::ApproxSurfaceNormal( con 598 G4ThreeVector G4Tubs::ApproxSurfaceNormal( const G4ThreeVector& p ) const 577 { 599 { 578 ENorm side ; 600 ENorm side ; 579 G4ThreeVector norm ; 601 G4ThreeVector norm ; 580 G4double rho, phi ; 602 G4double rho, phi ; 581 G4double distZ, distRMin, distRMax, distSPhi 603 G4double distZ, distRMin, distRMax, distSPhi, distEPhi, distMin ; 582 604 583 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 605 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 584 606 585 distRMin = std::fabs(rho - fRMin) ; 607 distRMin = std::fabs(rho - fRMin) ; 586 distRMax = std::fabs(rho - fRMax) ; 608 distRMax = std::fabs(rho - fRMax) ; 587 distZ = std::fabs(std::fabs(p.z()) - fDz) 609 distZ = std::fabs(std::fabs(p.z()) - fDz) ; 588 610 589 if (distRMin < distRMax) // First minimum 611 if (distRMin < distRMax) // First minimum 590 { 612 { 591 if ( distZ < distRMin ) 613 if ( distZ < distRMin ) 592 { 614 { 593 distMin = distZ ; 615 distMin = distZ ; 594 side = kNZ ; 616 side = kNZ ; 595 } 617 } 596 else 618 else 597 { 619 { 598 distMin = distRMin ; 620 distMin = distRMin ; 599 side = kNRMin ; 621 side = kNRMin ; 600 } 622 } 601 } 623 } 602 else 624 else 603 { 625 { 604 if ( distZ < distRMax ) 626 if ( distZ < distRMax ) 605 { 627 { 606 distMin = distZ ; 628 distMin = distZ ; 607 side = kNZ ; 629 side = kNZ ; 608 } 630 } 609 else 631 else 610 { 632 { 611 distMin = distRMax ; 633 distMin = distRMax ; 612 side = kNRMax ; 634 side = kNRMax ; 613 } 635 } 614 } 636 } 615 if (!fPhiFullTube && (rho != 0.0) ) // Pro << 637 if (!fPhiFullTube && rho ) // Protected against (0,0,z) 616 { 638 { 617 phi = std::atan2(p.y(),p.x()) ; 639 phi = std::atan2(p.y(),p.x()) ; 618 640 619 if ( phi < 0 ) { phi += twopi; } 641 if ( phi < 0 ) { phi += twopi; } 620 642 621 if ( fSPhi < 0 ) 643 if ( fSPhi < 0 ) 622 { 644 { 623 distSPhi = std::fabs(phi - (fSPhi + twop 645 distSPhi = std::fabs(phi - (fSPhi + twopi))*rho ; 624 } 646 } 625 else 647 else 626 { 648 { 627 distSPhi = std::fabs(phi - fSPhi)*rho ; 649 distSPhi = std::fabs(phi - fSPhi)*rho ; 628 } 650 } 629 distEPhi = std::fabs(phi - fSPhi - fDPhi)* 651 distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ; 630 652 631 if (distSPhi < distEPhi) // Find new minim 653 if (distSPhi < distEPhi) // Find new minimum 632 { 654 { 633 if ( distSPhi < distMin ) 655 if ( distSPhi < distMin ) 634 { 656 { 635 side = kNSPhi ; 657 side = kNSPhi ; 636 } 658 } 637 } 659 } 638 else 660 else 639 { 661 { 640 if ( distEPhi < distMin ) 662 if ( distEPhi < distMin ) 641 { 663 { 642 side = kNEPhi ; 664 side = kNEPhi ; 643 } 665 } 644 } 666 } 645 } 667 } 646 switch ( side ) 668 switch ( side ) 647 { 669 { 648 case kNRMin : // Inner radius 670 case kNRMin : // Inner radius 649 { 671 { 650 norm = G4ThreeVector(-p.x()/rho, -p.y()/ 672 norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, 0) ; 651 break ; 673 break ; 652 } 674 } 653 case kNRMax : // Outer radius 675 case kNRMax : // Outer radius 654 { 676 { 655 norm = G4ThreeVector(p.x()/rho, p.y()/rh 677 norm = G4ThreeVector(p.x()/rho, p.y()/rho, 0) ; 656 break ; 678 break ; 657 } 679 } 658 case kNZ : // + or - dz 680 case kNZ : // + or - dz 659 { 681 { 660 if ( p.z() > 0 ) { norm = G4ThreeVector 682 if ( p.z() > 0 ) { norm = G4ThreeVector(0,0,1) ; } 661 else { norm = G4ThreeVector 683 else { norm = G4ThreeVector(0,0,-1); } 662 break ; 684 break ; 663 } 685 } 664 case kNSPhi: 686 case kNSPhi: 665 { 687 { 666 norm = G4ThreeVector(sinSPhi, -cosSPhi, 688 norm = G4ThreeVector(sinSPhi, -cosSPhi, 0) ; 667 break ; 689 break ; 668 } 690 } 669 case kNEPhi: 691 case kNEPhi: 670 { 692 { 671 norm = G4ThreeVector(-sinEPhi, cosEPhi, 693 norm = G4ThreeVector(-sinEPhi, cosEPhi, 0) ; 672 break; 694 break; 673 } 695 } 674 default: // Should never reach this c 696 default: // Should never reach this case ... 675 { 697 { 676 DumpInfo(); 698 DumpInfo(); 677 G4Exception("G4Tubs::ApproxSurfaceNormal 699 G4Exception("G4Tubs::ApproxSurfaceNormal()", 678 "GeomSolids1002", JustWarnin 700 "GeomSolids1002", JustWarning, 679 "Undefined side for valid su 701 "Undefined side for valid surface normal to solid."); 680 break ; 702 break ; 681 } 703 } 682 } 704 } 683 return norm; 705 return norm; 684 } 706 } 685 707 686 ////////////////////////////////////////////// 708 //////////////////////////////////////////////////////////////////// 687 // 709 // 688 // 710 // 689 // Calculate distance to shape from outside, a 711 // Calculate distance to shape from outside, along normalised vector 690 // - return kInfinity if no intersection, or i 712 // - return kInfinity if no intersection, or intersection distance <= tolerance 691 // 713 // 692 // - Compute the intersection with the z plane 714 // - Compute the intersection with the z planes 693 // - if at valid r, phi, return 715 // - if at valid r, phi, return 694 // 716 // 695 // -> If point is outer outer radius, compute 717 // -> If point is outer outer radius, compute intersection with rmax 696 // - if at valid phi,z return 718 // - if at valid phi,z return 697 // 719 // 698 // -> Compute intersection with inner radius, 720 // -> Compute intersection with inner radius, taking largest +ve root 699 // - if valid (in z,phi), save intersct 721 // - if valid (in z,phi), save intersction 700 // 722 // 701 // -> If phi segmented, compute intersectio 723 // -> If phi segmented, compute intersections with phi half planes 702 // - return smallest of valid phi inter 724 // - return smallest of valid phi intersections and 703 // inner radius intersection 725 // inner radius intersection 704 // 726 // 705 // NOTE: 727 // NOTE: 706 // - 'if valid' implies tolerant checking of i 728 // - 'if valid' implies tolerant checking of intersection points 707 729 708 G4double G4Tubs::DistanceToIn( const G4ThreeVe 730 G4double G4Tubs::DistanceToIn( const G4ThreeVector& p, 709 const G4ThreeVe 731 const G4ThreeVector& v ) const 710 { 732 { 711 G4double snxt = kInfinity ; // snxt = d 733 G4double snxt = kInfinity ; // snxt = default return value 712 G4double tolORMin2, tolIRMax2 ; // 'generou 734 G4double tolORMin2, tolIRMax2 ; // 'generous' radii squared 713 G4double tolORMax2, tolIRMin2, tolODz, tolID 735 G4double tolORMax2, tolIRMin2, tolODz, tolIDz ; 714 const G4double dRmax = 100.*fRMax; 736 const G4double dRmax = 100.*fRMax; 715 737 716 // Intersection point variables 738 // Intersection point variables 717 // 739 // 718 G4double Dist, sd, xi, yi, zi, rho2, inum, i 740 G4double Dist, sd, xi, yi, zi, rho2, inum, iden, cosPsi, Comp ; 719 G4double t1, t2, t3, b, c, d ; // Quadra 741 G4double t1, t2, t3, b, c, d ; // Quadratic solver variables 720 742 721 // Calculate tolerant rmin and rmax 743 // Calculate tolerant rmin and rmax 722 744 723 if (fRMin > kRadTolerance) 745 if (fRMin > kRadTolerance) 724 { 746 { 725 tolORMin2 = (fRMin - halfRadTolerance)*(fR 747 tolORMin2 = (fRMin - halfRadTolerance)*(fRMin - halfRadTolerance) ; 726 tolIRMin2 = (fRMin + halfRadTolerance)*(fR 748 tolIRMin2 = (fRMin + halfRadTolerance)*(fRMin + halfRadTolerance) ; 727 } 749 } 728 else 750 else 729 { 751 { 730 tolORMin2 = 0.0 ; 752 tolORMin2 = 0.0 ; 731 tolIRMin2 = 0.0 ; 753 tolIRMin2 = 0.0 ; 732 } 754 } 733 tolORMax2 = (fRMax + halfRadTolerance)*(fRMa 755 tolORMax2 = (fRMax + halfRadTolerance)*(fRMax + halfRadTolerance) ; 734 tolIRMax2 = (fRMax - halfRadTolerance)*(fRMa 756 tolIRMax2 = (fRMax - halfRadTolerance)*(fRMax - halfRadTolerance) ; 735 757 736 // Intersection with Z surfaces 758 // Intersection with Z surfaces 737 759 738 tolIDz = fDz - halfCarTolerance ; 760 tolIDz = fDz - halfCarTolerance ; 739 tolODz = fDz + halfCarTolerance ; 761 tolODz = fDz + halfCarTolerance ; 740 762 741 if (std::fabs(p.z()) >= tolIDz) 763 if (std::fabs(p.z()) >= tolIDz) 742 { 764 { 743 if ( p.z()*v.z() < 0 ) // at +Z going i 765 if ( p.z()*v.z() < 0 ) // at +Z going in -Z or visa versa 744 { 766 { 745 sd = (std::fabs(p.z()) - fDz)/std::fabs( 767 sd = (std::fabs(p.z()) - fDz)/std::fabs(v.z()) ; // Z intersect distance 746 768 747 if(sd < 0.0) { sd = 0.0; } 769 if(sd < 0.0) { sd = 0.0; } 748 770 749 xi = p.x() + sd*v.x() ; 771 xi = p.x() + sd*v.x() ; // Intersection coords 750 yi = p.y() + sd*v.y() ; 772 yi = p.y() + sd*v.y() ; 751 rho2 = xi*xi + yi*yi ; 773 rho2 = xi*xi + yi*yi ; 752 774 753 // Check validity of intersection 775 // Check validity of intersection 754 776 755 if ((tolIRMin2 <= rho2) && (rho2 <= tolI 777 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2)) 756 { 778 { 757 if (!fPhiFullTube && (rho2 != 0.0)) << 779 if (!fPhiFullTube && rho2) 758 { 780 { 759 // Psi = angle made with central (av 781 // Psi = angle made with central (average) phi of shape 760 // 782 // 761 inum = xi*cosCPhi + yi*sinCPhi ; 783 inum = xi*cosCPhi + yi*sinCPhi ; 762 iden = std::sqrt(rho2) ; 784 iden = std::sqrt(rho2) ; 763 cosPsi = inum/iden ; 785 cosPsi = inum/iden ; 764 if (cosPsi >= cosHDPhiIT) { return 786 if (cosPsi >= cosHDPhiIT) { return sd ; } 765 } 787 } 766 else 788 else 767 { 789 { 768 return sd ; 790 return sd ; 769 } 791 } 770 } 792 } 771 } 793 } 772 else 794 else 773 { 795 { 774 if ( snxt<halfCarTolerance ) { snxt=0; 796 if ( snxt<halfCarTolerance ) { snxt=0; } 775 return snxt ; // On/outside extent, and 797 return snxt ; // On/outside extent, and heading away 776 // -> cannot intersect 798 // -> cannot intersect 777 } 799 } 778 } 800 } 779 801 780 // -> Can not intersect z surfaces 802 // -> Can not intersect z surfaces 781 // 803 // 782 // Intersection with rmax (possible return) 804 // Intersection with rmax (possible return) and rmin (must also check phi) 783 // 805 // 784 // Intersection point (xi,yi,zi) on line x=p 806 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. 785 // 807 // 786 // Intersects with x^2+y^2=R^2 808 // Intersects with x^2+y^2=R^2 787 // 809 // 788 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v. 810 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0 789 // t1 t2 811 // t1 t2 t3 790 812 791 t1 = 1.0 - v.z()*v.z() ; 813 t1 = 1.0 - v.z()*v.z() ; 792 t2 = p.x()*v.x() + p.y()*v.y() ; 814 t2 = p.x()*v.x() + p.y()*v.y() ; 793 t3 = p.x()*p.x() + p.y()*p.y() ; 815 t3 = p.x()*p.x() + p.y()*p.y() ; 794 816 795 if ( t1 > 0 ) // Check not || to z ax 817 if ( t1 > 0 ) // Check not || to z axis 796 { 818 { 797 b = t2/t1 ; 819 b = t2/t1 ; 798 c = t3 - fRMax*fRMax ; 820 c = t3 - fRMax*fRMax ; 799 if ((t3 >= tolORMax2) && (t2<0)) // This 821 if ((t3 >= tolORMax2) && (t2<0)) // This also handles the tangent case 800 { 822 { 801 // Try outer cylinder intersection 823 // Try outer cylinder intersection 802 // c=(t3-fRMax*fRMax)/t1; 824 // c=(t3-fRMax*fRMax)/t1; 803 825 804 c /= t1 ; 826 c /= t1 ; 805 d = b*b - c ; 827 d = b*b - c ; 806 828 807 if (d >= 0) // If real root 829 if (d >= 0) // If real root 808 { 830 { 809 sd = c/(-b+std::sqrt(d)); 831 sd = c/(-b+std::sqrt(d)); 810 if (sd >= 0) // If 'forwards' 832 if (sd >= 0) // If 'forwards' 811 { 833 { 812 if ( sd>dRmax ) // Avoid rounding er 834 if ( sd>dRmax ) // Avoid rounding errors due to precision issues on 813 { // 64 bits systems. 835 { // 64 bits systems. Split long distances and recompute 814 G4double fTerm = sd-std::fmod(sd,d 836 G4double fTerm = sd-std::fmod(sd,dRmax); 815 sd = fTerm + DistanceToIn(p+fTerm* 837 sd = fTerm + DistanceToIn(p+fTerm*v,v); 816 } 838 } 817 // Check z intersection 839 // Check z intersection 818 // 840 // 819 zi = p.z() + sd*v.z() ; 841 zi = p.z() + sd*v.z() ; 820 if (std::fabs(zi)<=tolODz) 842 if (std::fabs(zi)<=tolODz) 821 { 843 { 822 // Z ok. Check phi intersection if 844 // Z ok. Check phi intersection if reqd 823 // 845 // 824 if (fPhiFullTube) 846 if (fPhiFullTube) 825 { 847 { 826 return sd ; 848 return sd ; 827 } 849 } 828 else 850 else 829 { 851 { 830 xi = p.x() + sd*v.x() ; 852 xi = p.x() + sd*v.x() ; 831 yi = p.y() + sd*v.y() ; 853 yi = p.y() + sd*v.y() ; 832 cosPsi = (xi*cosCPhi + yi*sinCPh 854 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ; 833 if (cosPsi >= cosHDPhiIT) { ret 855 if (cosPsi >= cosHDPhiIT) { return sd ; } 834 } 856 } 835 } // end if std::fabs(zi) 857 } // end if std::fabs(zi) 836 } // end if (sd>=0) 858 } // end if (sd>=0) 837 } // end if (d>=0) 859 } // end if (d>=0) 838 } // end if (r>=fRMax) 860 } // end if (r>=fRMax) 839 else 861 else 840 { 862 { 841 // Inside outer radius : 863 // Inside outer radius : 842 // check not inside, and heading through 864 // check not inside, and heading through tubs (-> 0 to in) 843 865 844 if ((t3 > tolIRMin2) && (t2 < 0) && (std 866 if ((t3 > tolIRMin2) && (t2 < 0) && (std::fabs(p.z()) <= tolIDz)) 845 { 867 { 846 // Inside both radii, delta r -ve, ins 868 // Inside both radii, delta r -ve, inside z extent 847 869 848 if (!fPhiFullTube) 870 if (!fPhiFullTube) 849 { 871 { 850 inum = p.x()*cosCPhi + p.y()*sinCP 872 inum = p.x()*cosCPhi + p.y()*sinCPhi ; 851 iden = std::sqrt(t3) ; 873 iden = std::sqrt(t3) ; 852 cosPsi = inum/iden ; 874 cosPsi = inum/iden ; 853 if (cosPsi >= cosHDPhiIT) 875 if (cosPsi >= cosHDPhiIT) 854 { 876 { 855 // In the old version, the small n 877 // In the old version, the small negative tangent for the point 856 // on surface was not taken in acc 878 // on surface was not taken in account, and returning 0.0 ... 857 // New version: check the tangent 879 // New version: check the tangent for the point on surface and 858 // if no intersection, return kInf 880 // if no intersection, return kInfinity, if intersection instead 859 // return sd. 881 // return sd. 860 // 882 // 861 c = t3-fRMax*fRMax; 883 c = t3-fRMax*fRMax; 862 if ( c<=0.0 ) 884 if ( c<=0.0 ) 863 { 885 { 864 return 0.0; 886 return 0.0; 865 } 887 } 866 else 888 else 867 { 889 { 868 c = c/t1 ; 890 c = c/t1 ; 869 d = b*b-c; 891 d = b*b-c; 870 if ( d>=0.0 ) 892 if ( d>=0.0 ) 871 { 893 { 872 snxt = c/(-b+std::sqrt(d)); // 894 snxt = c/(-b+std::sqrt(d)); // using safe solution 873 // 895 // for quadratic equation 874 if ( snxt < halfCarTolerance ) 896 if ( snxt < halfCarTolerance ) { snxt=0; } 875 return snxt ; 897 return snxt ; 876 } 898 } 877 else 899 else 878 { 900 { 879 return kInfinity; 901 return kInfinity; 880 } 902 } 881 } 903 } 882 } 904 } 883 } 905 } 884 else 906 else 885 { 907 { 886 // In the old version, the small neg 908 // In the old version, the small negative tangent for the point 887 // on surface was not taken in accou 909 // on surface was not taken in account, and returning 0.0 ... 888 // New version: check the tangent fo 910 // New version: check the tangent for the point on surface and 889 // if no intersection, return kInfin 911 // if no intersection, return kInfinity, if intersection instead 890 // return sd. 912 // return sd. 891 // 913 // 892 c = t3 - fRMax*fRMax; 914 c = t3 - fRMax*fRMax; 893 if ( c<=0.0 ) 915 if ( c<=0.0 ) 894 { 916 { 895 return 0.0; 917 return 0.0; 896 } 918 } 897 else 919 else 898 { 920 { 899 c = c/t1 ; 921 c = c/t1 ; 900 d = b*b-c; 922 d = b*b-c; 901 if ( d>=0.0 ) 923 if ( d>=0.0 ) 902 { 924 { 903 snxt= c/(-b+std::sqrt(d)); // us 925 snxt= c/(-b+std::sqrt(d)); // using safe solution 904 // fo 926 // for quadratic equation 905 if ( snxt < halfCarTolerance ) { 927 if ( snxt < halfCarTolerance ) { snxt=0; } 906 return snxt ; 928 return snxt ; 907 } 929 } 908 else 930 else 909 { 931 { 910 return kInfinity; 932 return kInfinity; 911 } 933 } 912 } 934 } 913 } // end if (!fPhiFullTube) 935 } // end if (!fPhiFullTube) 914 } // end if (t3>tolIRMin2) 936 } // end if (t3>tolIRMin2) 915 } // end if (Inside Outer Radius) 937 } // end if (Inside Outer Radius) 916 if ( fRMin != 0.0 ) // Try inner cylind << 938 if ( fRMin ) // Try inner cylinder intersection 917 { 939 { 918 c = (t3 - fRMin*fRMin)/t1 ; 940 c = (t3 - fRMin*fRMin)/t1 ; 919 d = b*b - c ; 941 d = b*b - c ; 920 if ( d >= 0.0 ) // If real root 942 if ( d >= 0.0 ) // If real root 921 { 943 { 922 // Always want 2nd root - we are outsi 944 // Always want 2nd root - we are outside and know rmax Hit was bad 923 // - If on surface of rmin also need f 945 // - If on surface of rmin also need farthest root 924 946 925 sd =( b > 0. )? c/(-b - std::sqrt(d)) 947 sd =( b > 0. )? c/(-b - std::sqrt(d)) : (-b + std::sqrt(d)); 926 if (sd >= -halfCarTolerance) // check 948 if (sd >= -halfCarTolerance) // check forwards 927 { 949 { 928 // Check z intersection 950 // Check z intersection 929 // 951 // 930 if(sd < 0.0) { sd = 0.0; } 952 if(sd < 0.0) { sd = 0.0; } 931 if ( sd>dRmax ) // Avoid rounding er 953 if ( sd>dRmax ) // Avoid rounding errors due to precision issues seen 932 { // 64 bits systems. 954 { // 64 bits systems. Split long distances and recompute 933 G4double fTerm = sd-std::fmod(sd,d 955 G4double fTerm = sd-std::fmod(sd,dRmax); 934 sd = fTerm + DistanceToIn(p+fTerm* 956 sd = fTerm + DistanceToIn(p+fTerm*v,v); 935 } 957 } 936 zi = p.z() + sd*v.z() ; 958 zi = p.z() + sd*v.z() ; 937 if (std::fabs(zi) <= tolODz) 959 if (std::fabs(zi) <= tolODz) 938 { 960 { 939 // Z ok. Check phi 961 // Z ok. Check phi 940 // 962 // 941 if ( fPhiFullTube ) 963 if ( fPhiFullTube ) 942 { 964 { 943 return sd ; 965 return sd ; 944 } 966 } 945 else 967 else 946 { 968 { 947 xi = p.x() + sd*v.x() ; 969 xi = p.x() + sd*v.x() ; 948 yi = p.y() + sd*v.y() ; 970 yi = p.y() + sd*v.y() ; 949 cosPsi = (xi*cosCPhi + yi*sinCPh 971 cosPsi = (xi*cosCPhi + yi*sinCPhi)*fInvRmin; 950 if (cosPsi >= cosHDPhiIT) 972 if (cosPsi >= cosHDPhiIT) 951 { 973 { 952 // Good inner radius isect 974 // Good inner radius isect 953 // - but earlier phi isect sti 975 // - but earlier phi isect still possible 954 976 955 snxt = sd ; 977 snxt = sd ; 956 } 978 } 957 } 979 } 958 } // end if std::fabs(zi) 980 } // end if std::fabs(zi) 959 } // end if (sd>=0) 981 } // end if (sd>=0) 960 } // end if (d>=0) 982 } // end if (d>=0) 961 } // end if (fRMin) 983 } // end if (fRMin) 962 } 984 } 963 985 964 // Phi segment intersection 986 // Phi segment intersection 965 // 987 // 966 // o Tolerant of points inside phi planes by 988 // o Tolerant of points inside phi planes by up to kCarTolerance*0.5 967 // 989 // 968 // o NOTE: Large duplication of code between 990 // o NOTE: Large duplication of code between sphi & ephi checks 969 // -> only diffs: sphi -> ephi, Comp 991 // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane 970 // intersection check <=0 -> >=0 992 // intersection check <=0 -> >=0 971 // -> use some form of loop Construc 993 // -> use some form of loop Construct ? 972 // 994 // 973 if ( !fPhiFullTube ) 995 if ( !fPhiFullTube ) 974 { 996 { 975 // First phi surface (Starting phi) 997 // First phi surface (Starting phi) 976 // 998 // 977 Comp = v.x()*sinSPhi - v.y()*cosSPhi ; 999 Comp = v.x()*sinSPhi - v.y()*cosSPhi ; 978 1000 979 if ( Comp < 0 ) // Component in outwards 1001 if ( Comp < 0 ) // Component in outwards normal dirn 980 { 1002 { 981 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ; 1003 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ; 982 1004 983 if ( Dist < halfCarTolerance ) 1005 if ( Dist < halfCarTolerance ) 984 { 1006 { 985 sd = Dist/Comp ; 1007 sd = Dist/Comp ; 986 1008 987 if (sd < snxt) 1009 if (sd < snxt) 988 { 1010 { 989 if ( sd < 0 ) { sd = 0.0; } 1011 if ( sd < 0 ) { sd = 0.0; } 990 zi = p.z() + sd*v.z() ; 1012 zi = p.z() + sd*v.z() ; 991 if ( std::fabs(zi) <= tolODz ) 1013 if ( std::fabs(zi) <= tolODz ) 992 { 1014 { 993 xi = p.x() + sd*v.x() ; 1015 xi = p.x() + sd*v.x() ; 994 yi = p.y() + sd*v.y() ; 1016 yi = p.y() + sd*v.y() ; 995 rho2 = xi*xi + yi*yi ; 1017 rho2 = xi*xi + yi*yi ; 996 1018 997 if ( ( (rho2 >= tolIRMin2) && (rho 1019 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) ) 998 || ( (rho2 > tolORMin2) && (rho 1020 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2) 999 && ( v.y()*cosSPhi - v.x()*sin 1021 && ( v.y()*cosSPhi - v.x()*sinSPhi > 0 ) 1000 && ( v.x()*cosSPhi + v.y()*si 1022 && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 ) ) 1001 || ( (rho2 > tolIRMax2) && (rho 1023 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2) 1002 && (v.y()*cosSPhi - v.x()*sin 1024 && (v.y()*cosSPhi - v.x()*sinSPhi > 0) 1003 && (v.x()*cosSPhi + v.y()*sin 1025 && (v.x()*cosSPhi + v.y()*sinSPhi < 0) ) ) 1004 { 1026 { 1005 // z and r intersections good 1027 // z and r intersections good 1006 // - check intersecting with co 1028 // - check intersecting with correct half-plane 1007 // 1029 // 1008 if ((yi*cosCPhi-xi*sinCPhi) <= 1030 if ((yi*cosCPhi-xi*sinCPhi) <= halfCarTolerance) { snxt = sd; } 1009 } 1031 } 1010 } 1032 } 1011 } 1033 } 1012 } 1034 } 1013 } 1035 } 1014 1036 1015 // Second phi surface (Ending phi) 1037 // Second phi surface (Ending phi) 1016 1038 1017 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi 1039 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ; 1018 1040 1019 if (Comp < 0 ) // Component in outwards 1041 if (Comp < 0 ) // Component in outwards normal dirn 1020 { 1042 { 1021 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) 1043 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ; 1022 1044 1023 if ( Dist < halfCarTolerance ) 1045 if ( Dist < halfCarTolerance ) 1024 { 1046 { 1025 sd = Dist/Comp ; 1047 sd = Dist/Comp ; 1026 1048 1027 if (sd < snxt) 1049 if (sd < snxt) 1028 { 1050 { 1029 if ( sd < 0 ) { sd = 0; } 1051 if ( sd < 0 ) { sd = 0; } 1030 zi = p.z() + sd*v.z() ; 1052 zi = p.z() + sd*v.z() ; 1031 if ( std::fabs(zi) <= tolODz ) 1053 if ( std::fabs(zi) <= tolODz ) 1032 { 1054 { 1033 xi = p.x() + sd*v.x() ; 1055 xi = p.x() + sd*v.x() ; 1034 yi = p.y() + sd*v.y() ; 1056 yi = p.y() + sd*v.y() ; 1035 rho2 = xi*xi + yi*yi ; 1057 rho2 = xi*xi + yi*yi ; 1036 if ( ( (rho2 >= tolIRMin2) && (rh 1058 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) ) 1037 || ( (rho2 > tolORMin2) && ( 1059 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2) 1038 && (v.x()*sinEPhi - v.y()*c 1060 && (v.x()*sinEPhi - v.y()*cosEPhi > 0) 1039 && (v.x()*cosEPhi + v.y()*s 1061 && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) ) 1040 || ( (rho2 > tolIRMax2) && (r 1062 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2) 1041 && (v.x()*sinEPhi - v.y()*c 1063 && (v.x()*sinEPhi - v.y()*cosEPhi > 0) 1042 && (v.x()*cosEPhi + v.y()*s 1064 && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) ) 1043 { 1065 { 1044 // z and r intersections good 1066 // z and r intersections good 1045 // - check intersecting with co 1067 // - check intersecting with correct half-plane 1046 // 1068 // 1047 if ( (yi*cosCPhi-xi*sinCPhi) >= 1069 if ( (yi*cosCPhi-xi*sinCPhi) >= 0 ) { snxt = sd; } 1048 } //?? >= 1070 } //?? >=-halfCarTolerance 1049 } 1071 } 1050 } 1072 } 1051 } 1073 } 1052 } // Comp < 0 1074 } // Comp < 0 1053 } // !fPhiFullTube 1075 } // !fPhiFullTube 1054 if ( snxt<halfCarTolerance ) { snxt=0; } 1076 if ( snxt<halfCarTolerance ) { snxt=0; } 1055 return snxt ; 1077 return snxt ; 1056 } 1078 } 1057 1079 1058 ///////////////////////////////////////////// 1080 ////////////////////////////////////////////////////////////////// 1059 // 1081 // 1060 // Calculate distance to shape from outside, 1082 // Calculate distance to shape from outside, along normalised vector 1061 // - return kInfinity if no intersection, or 1083 // - return kInfinity if no intersection, or intersection distance <= tolerance 1062 // 1084 // 1063 // - Compute the intersection with the z plan 1085 // - Compute the intersection with the z planes 1064 // - if at valid r, phi, return 1086 // - if at valid r, phi, return 1065 // 1087 // 1066 // -> If point is outer outer radius, compute 1088 // -> If point is outer outer radius, compute intersection with rmax 1067 // - if at valid phi,z return 1089 // - if at valid phi,z return 1068 // 1090 // 1069 // -> Compute intersection with inner radius, 1091 // -> Compute intersection with inner radius, taking largest +ve root 1070 // - if valid (in z,phi), save intersc 1092 // - if valid (in z,phi), save intersction 1071 // 1093 // 1072 // -> If phi segmented, compute intersecti 1094 // -> If phi segmented, compute intersections with phi half planes 1073 // - return smallest of valid phi inte 1095 // - return smallest of valid phi intersections and 1074 // inner radius intersection 1096 // inner radius intersection 1075 // 1097 // 1076 // NOTE: 1098 // NOTE: 1077 // - Precalculations for phi trigonometry are 1099 // - Precalculations for phi trigonometry are Done `just in time' 1078 // - `if valid' implies tolerant checking of 1100 // - `if valid' implies tolerant checking of intersection points 1079 // Calculate distance (<= actual) to closes 1101 // Calculate distance (<= actual) to closest surface of shape from outside 1080 // - Calculate distance to z, radial planes 1102 // - Calculate distance to z, radial planes 1081 // - Only to phi planes if outside phi extent 1103 // - Only to phi planes if outside phi extent 1082 // - Return 0 if point inside 1104 // - Return 0 if point inside 1083 1105 1084 G4double G4Tubs::DistanceToIn( const G4ThreeV 1106 G4double G4Tubs::DistanceToIn( const G4ThreeVector& p ) const 1085 { 1107 { 1086 G4double safe=0.0, rho, safe1, safe2, safe3 1108 G4double safe=0.0, rho, safe1, safe2, safe3 ; 1087 G4double safePhi, cosPsi ; 1109 G4double safePhi, cosPsi ; 1088 1110 1089 rho = std::sqrt(p.x()*p.x() + p.y()*p.y() 1111 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 1090 safe1 = fRMin - rho ; 1112 safe1 = fRMin - rho ; 1091 safe2 = rho - fRMax ; 1113 safe2 = rho - fRMax ; 1092 safe3 = std::fabs(p.z()) - fDz ; 1114 safe3 = std::fabs(p.z()) - fDz ; 1093 1115 1094 if ( safe1 > safe2 ) { safe = safe1; } 1116 if ( safe1 > safe2 ) { safe = safe1; } 1095 else { safe = safe2; } 1117 else { safe = safe2; } 1096 if ( safe3 > safe ) { safe = safe3; } 1118 if ( safe3 > safe ) { safe = safe3; } 1097 1119 1098 if ( (!fPhiFullTube) && ((rho) != 0.0) ) << 1120 if ( (!fPhiFullTube) && (rho) ) 1099 { 1121 { 1100 // Psi=angle from central phi to point 1122 // Psi=angle from central phi to point 1101 // 1123 // 1102 cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/ 1124 cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ; 1103 1125 1104 if ( cosPsi < cosHDPhi ) 1126 if ( cosPsi < cosHDPhi ) 1105 { 1127 { 1106 // Point lies outside phi range 1128 // Point lies outside phi range 1107 1129 1108 if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 1130 if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 ) 1109 { 1131 { 1110 safePhi = std::fabs(p.x()*sinSPhi - p 1132 safePhi = std::fabs(p.x()*sinSPhi - p.y()*cosSPhi) ; 1111 } 1133 } 1112 else 1134 else 1113 { 1135 { 1114 safePhi = std::fabs(p.x()*sinEPhi - p 1136 safePhi = std::fabs(p.x()*sinEPhi - p.y()*cosEPhi) ; 1115 } 1137 } 1116 if ( safePhi > safe ) { safe = safePhi 1138 if ( safePhi > safe ) { safe = safePhi; } 1117 } 1139 } 1118 } 1140 } 1119 if ( safe < 0 ) { safe = 0; } 1141 if ( safe < 0 ) { safe = 0; } 1120 return safe ; 1142 return safe ; 1121 } 1143 } 1122 1144 1123 ///////////////////////////////////////////// 1145 ////////////////////////////////////////////////////////////////////////////// 1124 // 1146 // 1125 // Calculate distance to surface of shape fro 1147 // Calculate distance to surface of shape from `inside', allowing for tolerance 1126 // - Only Calc rmax intersection if no valid 1148 // - Only Calc rmax intersection if no valid rmin intersection 1127 1149 1128 G4double G4Tubs::DistanceToOut( const G4Three 1150 G4double G4Tubs::DistanceToOut( const G4ThreeVector& p, 1129 const G4Three 1151 const G4ThreeVector& v, 1130 const G4bool 1152 const G4bool calcNorm, 1131 G4bool* 1153 G4bool* validNorm, 1132 G4Three 1154 G4ThreeVector* n ) const 1133 { 1155 { 1134 ESide side=kNull , sider=kNull, sidephi=kNu 1156 ESide side=kNull , sider=kNull, sidephi=kNull ; 1135 G4double snxt, srd=kInfinity, sphi=kInfinit 1157 G4double snxt, srd=kInfinity, sphi=kInfinity, pdist ; 1136 G4double deltaR, t1, t2, t3, b, c, d2, roMi 1158 G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ; 1137 1159 1138 // Vars for phi intersection: 1160 // Vars for phi intersection: 1139 1161 1140 G4double pDistS, compS, pDistE, compE, sphi 1162 G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ; 1141 1163 1142 // Z plane intersection 1164 // Z plane intersection 1143 1165 1144 if (v.z() > 0 ) 1166 if (v.z() > 0 ) 1145 { 1167 { 1146 pdist = fDz - p.z() ; 1168 pdist = fDz - p.z() ; 1147 if ( pdist > halfCarTolerance ) 1169 if ( pdist > halfCarTolerance ) 1148 { 1170 { 1149 snxt = pdist/v.z() ; 1171 snxt = pdist/v.z() ; 1150 side = kPZ ; 1172 side = kPZ ; 1151 } 1173 } 1152 else 1174 else 1153 { 1175 { 1154 if (calcNorm) 1176 if (calcNorm) 1155 { 1177 { 1156 *n = G4ThreeVector(0,0,1) ; 1178 *n = G4ThreeVector(0,0,1) ; 1157 *validNorm = true ; 1179 *validNorm = true ; 1158 } 1180 } 1159 return snxt = 0 ; 1181 return snxt = 0 ; 1160 } 1182 } 1161 } 1183 } 1162 else if ( v.z() < 0 ) 1184 else if ( v.z() < 0 ) 1163 { 1185 { 1164 pdist = fDz + p.z() ; 1186 pdist = fDz + p.z() ; 1165 1187 1166 if ( pdist > halfCarTolerance ) 1188 if ( pdist > halfCarTolerance ) 1167 { 1189 { 1168 snxt = -pdist/v.z() ; 1190 snxt = -pdist/v.z() ; 1169 side = kMZ ; 1191 side = kMZ ; 1170 } 1192 } 1171 else 1193 else 1172 { 1194 { 1173 if (calcNorm) 1195 if (calcNorm) 1174 { 1196 { 1175 *n = G4ThreeVector(0,0,-1) ; 1197 *n = G4ThreeVector(0,0,-1) ; 1176 *validNorm = true ; 1198 *validNorm = true ; 1177 } 1199 } 1178 return snxt = 0.0 ; 1200 return snxt = 0.0 ; 1179 } 1201 } 1180 } 1202 } 1181 else 1203 else 1182 { 1204 { 1183 snxt = kInfinity ; // Travel perpendic 1205 snxt = kInfinity ; // Travel perpendicular to z axis 1184 side = kNull; 1206 side = kNull; 1185 } 1207 } 1186 1208 1187 // Radial Intersections 1209 // Radial Intersections 1188 // 1210 // 1189 // Find intersection with cylinders at rmax 1211 // Find intersection with cylinders at rmax/rmin 1190 // Intersection point (xi,yi,zi) on line x= 1212 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. 1191 // 1213 // 1192 // Intersects with x^2+y^2=R^2 1214 // Intersects with x^2+y^2=R^2 1193 // 1215 // 1194 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v 1216 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0 1195 // 1217 // 1196 // t1 t2 1218 // t1 t2 t3 1197 1219 1198 t1 = 1.0 - v.z()*v.z() ; // since v 1220 t1 = 1.0 - v.z()*v.z() ; // since v normalised 1199 t2 = p.x()*v.x() + p.y()*v.y() ; 1221 t2 = p.x()*v.x() + p.y()*v.y() ; 1200 t3 = p.x()*p.x() + p.y()*p.y() ; 1222 t3 = p.x()*p.x() + p.y()*p.y() ; 1201 1223 1202 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fR 1224 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fRMax*fRMax; } 1203 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t 1225 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; } // radius^2 on +-fDz 1204 1226 1205 if ( t1 > 0 ) // Check not parallel 1227 if ( t1 > 0 ) // Check not parallel 1206 { 1228 { 1207 // Calculate srd, r exit distance 1229 // Calculate srd, r exit distance 1208 1230 1209 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax 1231 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) ) 1210 { 1232 { 1211 // Delta r not negative => leaving via 1233 // Delta r not negative => leaving via rmax 1212 1234 1213 deltaR = t3 - fRMax*fRMax ; 1235 deltaR = t3 - fRMax*fRMax ; 1214 1236 1215 // NOTE: Should use rho-fRMax<-kRadTole 1237 // NOTE: Should use rho-fRMax<-kRadTolerance*0.5 1216 // - avoid sqrt for efficiency 1238 // - avoid sqrt for efficiency 1217 1239 1218 if ( deltaR < -kRadTolerance*fRMax ) 1240 if ( deltaR < -kRadTolerance*fRMax ) 1219 { 1241 { 1220 b = t2/t1 ; 1242 b = t2/t1 ; 1221 c = deltaR/t1 ; 1243 c = deltaR/t1 ; 1222 d2 = b*b-c; 1244 d2 = b*b-c; 1223 if( d2 >= 0 ) { srd = c/( -b - std::s 1245 if( d2 >= 0 ) { srd = c/( -b - std::sqrt(d2)); } 1224 else { srd = 0.; } 1246 else { srd = 0.; } 1225 sider = kRMax ; 1247 sider = kRMax ; 1226 } 1248 } 1227 else 1249 else 1228 { 1250 { 1229 // On tolerant boundary & heading out 1251 // On tolerant boundary & heading outwards (or perpendicular to) 1230 // outer radial surface -> leaving im 1252 // outer radial surface -> leaving immediately 1231 1253 1232 if ( calcNorm ) 1254 if ( calcNorm ) 1233 { 1255 { 1234 G4double invRho = FastInverseRxy( p 1256 G4double invRho = FastInverseRxy( p, fInvRmax, kNormTolerance ); 1235 *n = G4ThreeVector(p.x()*in 1257 *n = G4ThreeVector(p.x()*invRho,p.y()*invRho,0) ; 1236 *validNorm = true ; 1258 *validNorm = true ; 1237 } 1259 } 1238 return snxt = 0 ; // Leaving by rmax 1260 return snxt = 0 ; // Leaving by rmax immediately 1239 } 1261 } 1240 } 1262 } 1241 else if ( t2 < 0. ) // i.e. t2 < 0; Poss 1263 else if ( t2 < 0. ) // i.e. t2 < 0; Possible rmin intersection 1242 { 1264 { 1243 roMin2 = t3 - t2*t2/t1 ; // min ro2 of 1265 roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement 1244 1266 1245 if ( (fRMin != 0.0) && (roMin2 < fRMin* << 1267 if ( fRMin && (roMin2 < fRMin*(fRMin - kRadTolerance)) ) 1246 { 1268 { 1247 deltaR = t3 - fRMin*fRMin ; 1269 deltaR = t3 - fRMin*fRMin ; 1248 b = t2/t1 ; 1270 b = t2/t1 ; 1249 c = deltaR/t1 ; 1271 c = deltaR/t1 ; 1250 d2 = b*b - c ; 1272 d2 = b*b - c ; 1251 1273 1252 if ( d2 >= 0 ) // Leaving via rmin 1274 if ( d2 >= 0 ) // Leaving via rmin 1253 { 1275 { 1254 // NOTE: SHould use rho-rmin>kRadTo 1276 // NOTE: SHould use rho-rmin>kRadTolerance*0.5 1255 // - avoid sqrt for efficiency 1277 // - avoid sqrt for efficiency 1256 1278 1257 if (deltaR > kRadTolerance*fRMin) 1279 if (deltaR > kRadTolerance*fRMin) 1258 { 1280 { 1259 srd = c/(-b+std::sqrt(d2)); 1281 srd = c/(-b+std::sqrt(d2)); 1260 sider = kRMin ; 1282 sider = kRMin ; 1261 } 1283 } 1262 else 1284 else 1263 { 1285 { 1264 if ( calcNorm ) { 1286 if ( calcNorm ) { 1265 *validNorm = false; 1287 *validNorm = false; 1266 } // Concave side 1288 } // Concave side 1267 return snxt = 0.0; 1289 return snxt = 0.0; 1268 } 1290 } 1269 } 1291 } 1270 else // No rmin intersect -> must 1292 else // No rmin intersect -> must be rmax intersect 1271 { 1293 { 1272 deltaR = t3 - fRMax*fRMax ; 1294 deltaR = t3 - fRMax*fRMax ; 1273 c = deltaR/t1 ; 1295 c = deltaR/t1 ; 1274 d2 = b*b-c; 1296 d2 = b*b-c; 1275 if( d2 >=0. ) 1297 if( d2 >=0. ) 1276 { 1298 { 1277 srd = -b + std::sqrt(d2) ; 1299 srd = -b + std::sqrt(d2) ; 1278 sider = kRMax ; 1300 sider = kRMax ; 1279 } 1301 } 1280 else // Case: On the border+t2<kRad 1302 else // Case: On the border+t2<kRadTolerance 1281 // (v is perpendicular t 1303 // (v is perpendicular to the surface) 1282 { 1304 { 1283 if (calcNorm) 1305 if (calcNorm) 1284 { 1306 { 1285 G4double invRho = FastInverseRx 1307 G4double invRho = FastInverseRxy( p, fInvRmax, kNormTolerance ); 1286 *n = G4ThreeVector(p.x()*invRho 1308 *n = G4ThreeVector(p.x()*invRho,p.y()*invRho,0) ; 1287 *validNorm = true ; 1309 *validNorm = true ; 1288 } 1310 } 1289 return snxt = 0.0; 1311 return snxt = 0.0; 1290 } 1312 } 1291 } 1313 } 1292 } 1314 } 1293 else if ( roi2 > fRMax*(fRMax + kRadTol 1315 else if ( roi2 > fRMax*(fRMax + kRadTolerance) ) 1294 // No rmin intersect -> must be rm 1316 // No rmin intersect -> must be rmax intersect 1295 { 1317 { 1296 deltaR = t3 - fRMax*fRMax ; 1318 deltaR = t3 - fRMax*fRMax ; 1297 b = t2/t1 ; 1319 b = t2/t1 ; 1298 c = deltaR/t1; 1320 c = deltaR/t1; 1299 d2 = b*b-c; 1321 d2 = b*b-c; 1300 if( d2 >= 0 ) 1322 if( d2 >= 0 ) 1301 { 1323 { 1302 srd = -b + std::sqrt(d2) ; 1324 srd = -b + std::sqrt(d2) ; 1303 sider = kRMax ; 1325 sider = kRMax ; 1304 } 1326 } 1305 else // Case: On the border+t2<kRadTo 1327 else // Case: On the border+t2<kRadTolerance 1306 // (v is perpendicular to 1328 // (v is perpendicular to the surface) 1307 { 1329 { 1308 if (calcNorm) 1330 if (calcNorm) 1309 { 1331 { 1310 G4double invRho = FastInverseRxy( 1332 G4double invRho = FastInverseRxy( p, fInvRmax, kNormTolerance ); 1311 *n = G4ThreeVector(p.x()*invRho,p 1333 *n = G4ThreeVector(p.x()*invRho,p.y()*invRho,0) ; 1312 *validNorm = true ; 1334 *validNorm = true ; 1313 } 1335 } 1314 return snxt = 0.0; 1336 return snxt = 0.0; 1315 } 1337 } 1316 } 1338 } 1317 } 1339 } 1318 1340 1319 // Phi Intersection 1341 // Phi Intersection 1320 1342 1321 if ( !fPhiFullTube ) 1343 if ( !fPhiFullTube ) 1322 { 1344 { 1323 // add angle calculation with correctio 1345 // add angle calculation with correction 1324 // of the difference in domain of atan2 1346 // of the difference in domain of atan2 and Sphi 1325 // 1347 // 1326 vphi = std::atan2(v.y(),v.x()) ; 1348 vphi = std::atan2(v.y(),v.x()) ; 1327 1349 1328 if ( vphi < fSPhi - halfAngTolerance ) 1350 if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; } 1329 else if ( vphi > fSPhi + fDPhi + halfAn 1351 else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; } 1330 1352 1331 1353 1332 if ( (p.x() != 0.0) || (p.y() != 0.0) ) << 1354 if ( p.x() || p.y() ) // Check if on z axis (rho not needed later) 1333 { 1355 { 1334 // pDist -ve when inside 1356 // pDist -ve when inside 1335 1357 1336 pDistS = p.x()*sinSPhi - p.y()*cosSPh 1358 pDistS = p.x()*sinSPhi - p.y()*cosSPhi ; 1337 pDistE = -p.x()*sinEPhi + p.y()*cosEP 1359 pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ; 1338 1360 1339 // Comp -ve when in direction of outw 1361 // Comp -ve when in direction of outwards normal 1340 1362 1341 compS = -sinSPhi*v.x() + cosSPhi*v.y( 1363 compS = -sinSPhi*v.x() + cosSPhi*v.y() ; 1342 compE = sinEPhi*v.x() - cosEPhi*v.y( 1364 compE = sinEPhi*v.x() - cosEPhi*v.y() ; 1343 1365 1344 sidephi = kNull; 1366 sidephi = kNull; 1345 1367 1346 if( ( (fDPhi <= pi) && ( (pDistS <= h 1368 if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance) 1347 && (pDistE <= h 1369 && (pDistE <= halfCarTolerance) ) ) 1348 || ( (fDPhi > pi) && ((pDistS <= h << 1370 || ( (fDPhi > pi) && !((pDistS > halfCarTolerance) 1349 || (pDistE <= << 1371 && (pDistE > halfCarTolerance) ) ) ) 1350 { 1372 { 1351 // Inside both phi *full* planes 1373 // Inside both phi *full* planes 1352 1374 1353 if ( compS < 0 ) 1375 if ( compS < 0 ) 1354 { 1376 { 1355 sphi = pDistS/compS ; 1377 sphi = pDistS/compS ; 1356 1378 1357 if (sphi >= -halfCarTolerance) 1379 if (sphi >= -halfCarTolerance) 1358 { 1380 { 1359 xi = p.x() + sphi*v.x() ; 1381 xi = p.x() + sphi*v.x() ; 1360 yi = p.y() + sphi*v.y() ; 1382 yi = p.y() + sphi*v.y() ; 1361 1383 1362 // Check intersecting with corr 1384 // Check intersecting with correct half-plane 1363 // (if not -> no intersect) 1385 // (if not -> no intersect) 1364 // 1386 // 1365 if((std::fabs(xi)<=kCarToleranc 1387 if((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance)) 1366 { 1388 { 1367 sidephi = kSPhi; 1389 sidephi = kSPhi; 1368 if (((fSPhi-halfAngTolerance) 1390 if (((fSPhi-halfAngTolerance)<=vphi) 1369 &&((fSPhi+fDPhi+halfAngTol 1391 &&((fSPhi+fDPhi+halfAngTolerance)>=vphi)) 1370 { 1392 { 1371 sphi = kInfinity; 1393 sphi = kInfinity; 1372 } 1394 } 1373 } 1395 } 1374 else if ( yi*cosCPhi-xi*sinCPhi 1396 else if ( yi*cosCPhi-xi*sinCPhi >=0 ) 1375 { 1397 { 1376 sphi = kInfinity ; 1398 sphi = kInfinity ; 1377 } 1399 } 1378 else 1400 else 1379 { 1401 { 1380 sidephi = kSPhi ; 1402 sidephi = kSPhi ; 1381 if ( pDistS > -halfCarToleran 1403 if ( pDistS > -halfCarTolerance ) 1382 { 1404 { 1383 sphi = 0.0 ; // Leave by sp 1405 sphi = 0.0 ; // Leave by sphi immediately 1384 } 1406 } 1385 } 1407 } 1386 } 1408 } 1387 else 1409 else 1388 { 1410 { 1389 sphi = kInfinity ; 1411 sphi = kInfinity ; 1390 } 1412 } 1391 } 1413 } 1392 else 1414 else 1393 { 1415 { 1394 sphi = kInfinity ; 1416 sphi = kInfinity ; 1395 } 1417 } 1396 1418 1397 if ( compE < 0 ) 1419 if ( compE < 0 ) 1398 { 1420 { 1399 sphi2 = pDistE/compE ; 1421 sphi2 = pDistE/compE ; 1400 1422 1401 // Only check further if < starti 1423 // Only check further if < starting phi intersection 1402 // 1424 // 1403 if ( (sphi2 > -halfCarTolerance) 1425 if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) ) 1404 { 1426 { 1405 xi = p.x() + sphi2*v.x() ; 1427 xi = p.x() + sphi2*v.x() ; 1406 yi = p.y() + sphi2*v.y() ; 1428 yi = p.y() + sphi2*v.y() ; 1407 1429 1408 if((std::fabs(xi)<=kCarToleranc 1430 if((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance)) 1409 { 1431 { 1410 // Leaving via ending phi 1432 // Leaving via ending phi 1411 // 1433 // 1412 if( (fSPhi-halfAngTolerance > << 1434 if( !((fSPhi-halfAngTolerance <= vphi) 1413 ||(fSPhi+fDPhi+halfAngTo << 1435 &&(fSPhi+fDPhi+halfAngTolerance >= vphi)) ) 1414 { 1436 { 1415 sidephi = kEPhi ; 1437 sidephi = kEPhi ; 1416 if ( pDistE <= -halfCarTole 1438 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; } 1417 else 1439 else { sphi = 0.0 ; } 1418 } 1440 } 1419 } 1441 } 1420 else // Check intersecting w 1442 else // Check intersecting with correct half-plane 1421 1443 1422 if ( (yi*cosCPhi-xi*sinCPhi) >= 1444 if ( (yi*cosCPhi-xi*sinCPhi) >= 0) 1423 { 1445 { 1424 // Leaving via ending phi 1446 // Leaving via ending phi 1425 // 1447 // 1426 sidephi = kEPhi ; 1448 sidephi = kEPhi ; 1427 if ( pDistE <= -halfCarTolera 1449 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; } 1428 else 1450 else { sphi = 0.0 ; } 1429 } 1451 } 1430 } 1452 } 1431 } 1453 } 1432 } 1454 } 1433 else 1455 else 1434 { 1456 { 1435 sphi = kInfinity ; 1457 sphi = kInfinity ; 1436 } 1458 } 1437 } 1459 } 1438 else 1460 else 1439 { 1461 { 1440 // On z axis + travel not || to z axi 1462 // On z axis + travel not || to z axis -> if phi of vector direction 1441 // within phi of shape, Step limited 1463 // within phi of shape, Step limited by rmax, else Step =0 1442 1464 1443 if ( (fSPhi - halfAngTolerance <= vph 1465 if ( (fSPhi - halfAngTolerance <= vphi) 1444 && (vphi <= fSPhi + fDPhi + halfAn 1466 && (vphi <= fSPhi + fDPhi + halfAngTolerance ) ) 1445 { 1467 { 1446 sphi = kInfinity ; 1468 sphi = kInfinity ; 1447 } 1469 } 1448 else 1470 else 1449 { 1471 { 1450 sidephi = kSPhi ; // arbitrary 1472 sidephi = kSPhi ; // arbitrary 1451 sphi = 0.0 ; 1473 sphi = 0.0 ; 1452 } 1474 } 1453 } 1475 } 1454 if (sphi < snxt) // Order intersecttio 1476 if (sphi < snxt) // Order intersecttions 1455 { 1477 { 1456 snxt = sphi ; 1478 snxt = sphi ; 1457 side = sidephi ; 1479 side = sidephi ; 1458 } 1480 } 1459 } 1481 } 1460 if (srd < snxt) // Order intersections 1482 if (srd < snxt) // Order intersections 1461 { 1483 { 1462 snxt = srd ; 1484 snxt = srd ; 1463 side = sider ; 1485 side = sider ; 1464 } 1486 } 1465 } 1487 } 1466 if (calcNorm) 1488 if (calcNorm) 1467 { 1489 { 1468 switch(side) 1490 switch(side) 1469 { 1491 { 1470 case kRMax: 1492 case kRMax: 1471 // Note: returned vector not normalis 1493 // Note: returned vector not normalised 1472 // (divide by fRMax for unit vector) 1494 // (divide by fRMax for unit vector) 1473 // 1495 // 1474 xi = p.x() + snxt*v.x() ; 1496 xi = p.x() + snxt*v.x() ; 1475 yi = p.y() + snxt*v.y() ; 1497 yi = p.y() + snxt*v.y() ; 1476 *n = G4ThreeVector(xi/fRMax,yi/fRMax, 1498 *n = G4ThreeVector(xi/fRMax,yi/fRMax,0) ; 1477 *validNorm = true ; 1499 *validNorm = true ; 1478 break ; 1500 break ; 1479 1501 1480 case kRMin: 1502 case kRMin: 1481 *validNorm = false ; // Rmin is inco 1503 *validNorm = false ; // Rmin is inconvex 1482 break ; 1504 break ; 1483 1505 1484 case kSPhi: 1506 case kSPhi: 1485 if ( fDPhi <= pi ) 1507 if ( fDPhi <= pi ) 1486 { 1508 { 1487 *n = G4ThreeVector(sinSPhi, 1509 *n = G4ThreeVector(sinSPhi,-cosSPhi,0) ; 1488 *validNorm = true ; 1510 *validNorm = true ; 1489 } 1511 } 1490 else 1512 else 1491 { 1513 { 1492 *validNorm = false ; 1514 *validNorm = false ; 1493 } 1515 } 1494 break ; 1516 break ; 1495 1517 1496 case kEPhi: 1518 case kEPhi: 1497 if (fDPhi <= pi) 1519 if (fDPhi <= pi) 1498 { 1520 { 1499 *n = G4ThreeVector(-sinEPhi,cosEPhi 1521 *n = G4ThreeVector(-sinEPhi,cosEPhi,0) ; 1500 *validNorm = true ; 1522 *validNorm = true ; 1501 } 1523 } 1502 else 1524 else 1503 { 1525 { 1504 *validNorm = false ; 1526 *validNorm = false ; 1505 } 1527 } 1506 break ; 1528 break ; 1507 1529 1508 case kPZ: 1530 case kPZ: 1509 *n = G4ThreeVector(0,0,1) ; 1531 *n = G4ThreeVector(0,0,1) ; 1510 *validNorm = true ; 1532 *validNorm = true ; 1511 break ; 1533 break ; 1512 1534 1513 case kMZ: 1535 case kMZ: 1514 *n = G4ThreeVector(0,0,-1) ; 1536 *n = G4ThreeVector(0,0,-1) ; 1515 *validNorm = true ; 1537 *validNorm = true ; 1516 break ; 1538 break ; 1517 1539 1518 default: 1540 default: 1519 G4cout << G4endl ; 1541 G4cout << G4endl ; 1520 DumpInfo(); 1542 DumpInfo(); 1521 std::ostringstream message; 1543 std::ostringstream message; 1522 G4long oldprc = message.precision(16) << 1544 G4int oldprc = message.precision(16); 1523 message << "Undefined side for valid 1545 message << "Undefined side for valid surface normal to solid." 1524 << G4endl 1546 << G4endl 1525 << "Position:" << G4endl << 1547 << "Position:" << G4endl << G4endl 1526 << "p.x() = " << p.x()/mm < 1548 << "p.x() = " << p.x()/mm << " mm" << G4endl 1527 << "p.y() = " << p.y()/mm < 1549 << "p.y() = " << p.y()/mm << " mm" << G4endl 1528 << "p.z() = " << p.z()/mm < 1550 << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl 1529 << "Direction:" << G4endl << 1551 << "Direction:" << G4endl << G4endl 1530 << "v.x() = " << v.x() << G 1552 << "v.x() = " << v.x() << G4endl 1531 << "v.y() = " << v.y() << G 1553 << "v.y() = " << v.y() << G4endl 1532 << "v.z() = " << v.z() << G 1554 << "v.z() = " << v.z() << G4endl << G4endl 1533 << "Proposed distance :" << G 1555 << "Proposed distance :" << G4endl << G4endl 1534 << "snxt = " << snxt/mm << 1556 << "snxt = " << snxt/mm << " mm" << G4endl ; 1535 message.precision(oldprc) ; 1557 message.precision(oldprc) ; 1536 G4Exception("G4Tubs::DistanceToOut(p, 1558 G4Exception("G4Tubs::DistanceToOut(p,v,..)", "GeomSolids1002", 1537 JustWarning, message); 1559 JustWarning, message); 1538 break ; 1560 break ; 1539 } 1561 } 1540 } 1562 } 1541 if ( snxt<halfCarTolerance ) { snxt=0 ; } 1563 if ( snxt<halfCarTolerance ) { snxt=0 ; } 1542 1564 1543 return snxt ; 1565 return snxt ; 1544 } 1566 } 1545 1567 1546 ///////////////////////////////////////////// 1568 ////////////////////////////////////////////////////////////////////////// 1547 // 1569 // 1548 // Calculate distance (<=actual) to closest s 1570 // Calculate distance (<=actual) to closest surface of shape from inside 1549 1571 1550 G4double G4Tubs::DistanceToOut( const G4Three 1572 G4double G4Tubs::DistanceToOut( const G4ThreeVector& p ) const 1551 { 1573 { 1552 G4double safe=0.0, rho, safeR1, safeR2, saf 1574 G4double safe=0.0, rho, safeR1, safeR2, safeZ, safePhi ; 1553 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) 1575 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 1554 1576 1555 #ifdef G4CSGDEBUG 1577 #ifdef G4CSGDEBUG 1556 if( Inside(p) == kOutside ) 1578 if( Inside(p) == kOutside ) 1557 { 1579 { 1558 G4long oldprc = G4cout.precision(16) ; << 1580 G4int oldprc = G4cout.precision(16) ; 1559 G4cout << G4endl ; 1581 G4cout << G4endl ; 1560 DumpInfo(); 1582 DumpInfo(); 1561 G4cout << "Position:" << G4endl << G4end 1583 G4cout << "Position:" << G4endl << G4endl ; 1562 G4cout << "p.x() = " << p.x()/mm << " m 1584 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ; 1563 G4cout << "p.y() = " << p.y()/mm << " m 1585 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ; 1564 G4cout << "p.z() = " << p.z()/mm << " m 1586 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ; 1565 G4cout.precision(oldprc) ; 1587 G4cout.precision(oldprc) ; 1566 G4Exception("G4Tubs::DistanceToOut(p)", " 1588 G4Exception("G4Tubs::DistanceToOut(p)", "GeomSolids1002", 1567 JustWarning, "Point p is outs 1589 JustWarning, "Point p is outside !?"); 1568 } 1590 } 1569 #endif 1591 #endif 1570 1592 1571 if ( fRMin != 0.0 ) << 1593 if ( fRMin ) 1572 { 1594 { 1573 safeR1 = rho - fRMin ; 1595 safeR1 = rho - fRMin ; 1574 safeR2 = fRMax - rho ; 1596 safeR2 = fRMax - rho ; 1575 1597 1576 if ( safeR1 < safeR2 ) { safe = safeR1 ; 1598 if ( safeR1 < safeR2 ) { safe = safeR1 ; } 1577 else { safe = safeR2 ; 1599 else { safe = safeR2 ; } 1578 } 1600 } 1579 else 1601 else 1580 { 1602 { 1581 safe = fRMax - rho ; 1603 safe = fRMax - rho ; 1582 } 1604 } 1583 safeZ = fDz - std::fabs(p.z()) ; 1605 safeZ = fDz - std::fabs(p.z()) ; 1584 1606 1585 if ( safeZ < safe ) { safe = safeZ ; } 1607 if ( safeZ < safe ) { safe = safeZ ; } 1586 1608 1587 // Check if phi divided, Calc distances clo 1609 // Check if phi divided, Calc distances closest phi plane 1588 // 1610 // 1589 if ( !fPhiFullTube ) 1611 if ( !fPhiFullTube ) 1590 { 1612 { 1591 if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 ) 1613 if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 ) 1592 { 1614 { 1593 safePhi = -(p.x()*sinSPhi - p.y()*cosSP 1615 safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ; 1594 } 1616 } 1595 else 1617 else 1596 { 1618 { 1597 safePhi = (p.x()*sinEPhi - p.y()*cosEPh 1619 safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ; 1598 } 1620 } 1599 if (safePhi < safe) { safe = safePhi ; } 1621 if (safePhi < safe) { safe = safePhi ; } 1600 } 1622 } 1601 if ( safe < 0 ) { safe = 0 ; } 1623 if ( safe < 0 ) { safe = 0 ; } 1602 1624 1603 return safe ; 1625 return safe ; 1604 } 1626 } 1605 1627 1606 ///////////////////////////////////////////// 1628 ////////////////////////////////////////////////////////////////////////// 1607 // 1629 // 1608 // Stream object contents to an output stream 1630 // Stream object contents to an output stream 1609 1631 1610 G4GeometryType G4Tubs::GetEntityType() const 1632 G4GeometryType G4Tubs::GetEntityType() const 1611 { 1633 { 1612 return {"G4Tubs"}; << 1634 return G4String("G4Tubs"); 1613 } 1635 } 1614 1636 1615 ///////////////////////////////////////////// 1637 ////////////////////////////////////////////////////////////////////////// 1616 // 1638 // 1617 // Make a clone of the object 1639 // Make a clone of the object 1618 // 1640 // 1619 G4VSolid* G4Tubs::Clone() const 1641 G4VSolid* G4Tubs::Clone() const 1620 { 1642 { 1621 return new G4Tubs(*this); 1643 return new G4Tubs(*this); 1622 } 1644 } 1623 1645 1624 ///////////////////////////////////////////// 1646 ////////////////////////////////////////////////////////////////////////// 1625 // 1647 // 1626 // Stream object contents to an output stream 1648 // Stream object contents to an output stream 1627 1649 1628 std::ostream& G4Tubs::StreamInfo( std::ostrea 1650 std::ostream& G4Tubs::StreamInfo( std::ostream& os ) const 1629 { 1651 { 1630 G4long oldprc = os.precision(16); << 1652 G4int oldprc = os.precision(16); 1631 os << "------------------------------------ 1653 os << "-----------------------------------------------------------\n" 1632 << " *** Dump for solid - " << GetNam 1654 << " *** Dump for solid - " << GetName() << " ***\n" 1633 << " ================================ 1655 << " ===================================================\n" 1634 << " Solid type: G4Tubs\n" 1656 << " Solid type: G4Tubs\n" 1635 << " Parameters: \n" 1657 << " Parameters: \n" 1636 << " inner radius : " << fRMin/mm << 1658 << " inner radius : " << fRMin/mm << " mm \n" 1637 << " outer radius : " << fRMax/mm << 1659 << " outer radius : " << fRMax/mm << " mm \n" 1638 << " half length Z: " << fDz/mm << " 1660 << " half length Z: " << fDz/mm << " mm \n" 1639 << " starting phi : " << fSPhi/degree 1661 << " starting phi : " << fSPhi/degree << " degrees \n" 1640 << " delta phi : " << fDPhi/degree 1662 << " delta phi : " << fDPhi/degree << " degrees \n" 1641 << "------------------------------------ 1663 << "-----------------------------------------------------------\n"; 1642 os.precision(oldprc); 1664 os.precision(oldprc); 1643 1665 1644 return os; 1666 return os; 1645 } 1667 } 1646 1668 1647 ///////////////////////////////////////////// 1669 ///////////////////////////////////////////////////////////////////////// 1648 // 1670 // 1649 // GetPointOnSurface 1671 // GetPointOnSurface 1650 1672 1651 G4ThreeVector G4Tubs::GetPointOnSurface() con 1673 G4ThreeVector G4Tubs::GetPointOnSurface() const 1652 { 1674 { 1653 G4double Rmax = fRMax; 1675 G4double Rmax = fRMax; 1654 G4double Rmin = fRMin; 1676 G4double Rmin = fRMin; 1655 G4double hz = 2.*fDz; // height 1677 G4double hz = 2.*fDz; // height 1656 G4double lext = fDPhi*Rmax; // length of ex 1678 G4double lext = fDPhi*Rmax; // length of external circular arc 1657 G4double lint = fDPhi*Rmin; // length of in 1679 G4double lint = fDPhi*Rmin; // length of internal circular arc 1658 1680 1659 // Set array of surface areas 1681 // Set array of surface areas 1660 // 1682 // 1661 G4double RRmax = Rmax * Rmax; 1683 G4double RRmax = Rmax * Rmax; 1662 G4double RRmin = Rmin * Rmin; 1684 G4double RRmin = Rmin * Rmin; 1663 G4double sbase = 0.5*fDPhi*(RRmax - RRmin); 1685 G4double sbase = 0.5*fDPhi*(RRmax - RRmin); 1664 G4double scut = (fDPhi == twopi) ? 0. : hz* 1686 G4double scut = (fDPhi == twopi) ? 0. : hz*(Rmax - Rmin); 1665 G4double ssurf[6] = { scut, scut, sbase, sb 1687 G4double ssurf[6] = { scut, scut, sbase, sbase, hz*lext, hz*lint }; 1666 ssurf[1] += ssurf[0]; 1688 ssurf[1] += ssurf[0]; 1667 ssurf[2] += ssurf[1]; 1689 ssurf[2] += ssurf[1]; 1668 ssurf[3] += ssurf[2]; 1690 ssurf[3] += ssurf[2]; 1669 ssurf[4] += ssurf[3]; 1691 ssurf[4] += ssurf[3]; 1670 ssurf[5] += ssurf[4]; 1692 ssurf[5] += ssurf[4]; 1671 1693 1672 // Select surface 1694 // Select surface 1673 // 1695 // 1674 G4double select = ssurf[5]*G4QuickRand(); 1696 G4double select = ssurf[5]*G4QuickRand(); 1675 G4int k = 5; 1697 G4int k = 5; 1676 k -= (G4int)(select <= ssurf[4]); << 1698 k -= (select <= ssurf[4]); 1677 k -= (G4int)(select <= ssurf[3]); << 1699 k -= (select <= ssurf[3]); 1678 k -= (G4int)(select <= ssurf[2]); << 1700 k -= (select <= ssurf[2]); 1679 k -= (G4int)(select <= ssurf[1]); << 1701 k -= (select <= ssurf[1]); 1680 k -= (G4int)(select <= ssurf[0]); << 1702 k -= (select <= ssurf[0]); 1681 1703 1682 // Generate point on selected surface 1704 // Generate point on selected surface 1683 // 1705 // 1684 switch(k) 1706 switch(k) 1685 { 1707 { 1686 case 0: // start phi cut 1708 case 0: // start phi cut 1687 { 1709 { 1688 G4double r = Rmin + (Rmax - Rmin)*G4Qui 1710 G4double r = Rmin + (Rmax - Rmin)*G4QuickRand(); 1689 return { r*cosSPhi, r*sinSPhi, hz*G4Qui << 1711 return G4ThreeVector(r*cosSPhi, r*sinSPhi, hz*G4QuickRand() - fDz); 1690 } 1712 } 1691 case 1: // end phi cut 1713 case 1: // end phi cut 1692 { 1714 { 1693 G4double r = Rmin + (Rmax - Rmin)*G4Qui 1715 G4double r = Rmin + (Rmax - Rmin)*G4QuickRand(); 1694 return { r*cosEPhi, r*sinEPhi, hz*G4Qui << 1716 return G4ThreeVector(r*cosEPhi, r*sinEPhi, hz*G4QuickRand() - fDz); 1695 } 1717 } 1696 case 2: // base at -dz 1718 case 2: // base at -dz 1697 { 1719 { 1698 G4double r = std::sqrt(RRmin + (RRmax - 1720 G4double r = std::sqrt(RRmin + (RRmax - RRmin)*G4QuickRand()); 1699 G4double phi = fSPhi + fDPhi*G4QuickRan 1721 G4double phi = fSPhi + fDPhi*G4QuickRand(); 1700 return { r*std::cos(phi), r*std::sin(ph << 1722 return G4ThreeVector(r*std::cos(phi), r*std::sin(phi), -fDz); 1701 } 1723 } 1702 case 3: // base at +dz 1724 case 3: // base at +dz 1703 { 1725 { 1704 G4double r = std::sqrt(RRmin + (RRmax - 1726 G4double r = std::sqrt(RRmin + (RRmax - RRmin)*G4QuickRand()); 1705 G4double phi = fSPhi + fDPhi*G4QuickRan 1727 G4double phi = fSPhi + fDPhi*G4QuickRand(); 1706 return { r*std::cos(phi), r*std::sin(ph << 1728 return G4ThreeVector(r*std::cos(phi), r*std::sin(phi), fDz); 1707 } 1729 } 1708 case 4: // external lateral surface 1730 case 4: // external lateral surface 1709 { 1731 { 1710 G4double phi = fSPhi + fDPhi*G4QuickRan 1732 G4double phi = fSPhi + fDPhi*G4QuickRand(); 1711 G4double z = hz*G4QuickRand() - fDz; 1733 G4double z = hz*G4QuickRand() - fDz; 1712 G4double x = Rmax*std::cos(phi); 1734 G4double x = Rmax*std::cos(phi); 1713 G4double y = Rmax*std::sin(phi); 1735 G4double y = Rmax*std::sin(phi); 1714 return { x,y,z }; << 1736 return G4ThreeVector(x,y,z); 1715 } 1737 } 1716 case 5: // internal lateral surface 1738 case 5: // internal lateral surface 1717 { 1739 { 1718 G4double phi = fSPhi + fDPhi*G4QuickRan 1740 G4double phi = fSPhi + fDPhi*G4QuickRand(); 1719 G4double z = hz*G4QuickRand() - fDz; 1741 G4double z = hz*G4QuickRand() - fDz; 1720 G4double x = Rmin*std::cos(phi); 1742 G4double x = Rmin*std::cos(phi); 1721 G4double y = Rmin*std::sin(phi); 1743 G4double y = Rmin*std::sin(phi); 1722 return { x,y,z }; << 1744 return G4ThreeVector(x,y,z); 1723 } 1745 } 1724 } 1746 } 1725 return {0., 0., 0.}; << 1747 return G4ThreeVector(0., 0., 0.); 1726 } 1748 } 1727 1749 1728 ///////////////////////////////////////////// 1750 /////////////////////////////////////////////////////////////////////////// 1729 // 1751 // 1730 // Methods for visualisation 1752 // Methods for visualisation 1731 1753 1732 void G4Tubs::DescribeYourselfTo ( G4VGraphics 1754 void G4Tubs::DescribeYourselfTo ( G4VGraphicsScene& scene ) const 1733 { 1755 { 1734 scene.AddSolid (*this) ; 1756 scene.AddSolid (*this) ; 1735 } 1757 } 1736 1758 1737 G4Polyhedron* G4Tubs::CreatePolyhedron () con 1759 G4Polyhedron* G4Tubs::CreatePolyhedron () const 1738 { 1760 { 1739 return new G4PolyhedronTubs (fRMin, fRMax, 1761 return new G4PolyhedronTubs (fRMin, fRMax, fDz, fSPhi, fDPhi) ; 1740 } 1762 } 1741 1763 1742 #endif 1764 #endif 1743 1765