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 // G4CutTubs implementation << 26 // >> 27 // $Id:$ >> 28 // GEANT4 tag $Name: not supported by cvs2svn $ >> 29 // >> 30 // >> 31 // class G4CutTubs >> 32 // >> 33 // History: 27 // 34 // 28 // 01.06.11 T.Nikitina - Derived from G4Tubs 35 // 01.06.11 T.Nikitina - Derived from G4Tubs 29 // 30.10.16 E.Tcherniaev - reimplemented Calcu << 36 // 30 // removed CreateRotat << 37 ///////////////////////////////////////////////////////////////////////// 31 // ------------------------------------------- << 32 38 33 #include "G4CutTubs.hh" 39 #include "G4CutTubs.hh" 34 40 35 #if !defined(G4GEOM_USE_UCTUBS) << 36 << 37 #include "G4GeomTools.hh" << 38 #include "G4VoxelLimits.hh" 41 #include "G4VoxelLimits.hh" 39 #include "G4AffineTransform.hh" 42 #include "G4AffineTransform.hh" 40 #include "G4GeometryTolerance.hh" 43 #include "G4GeometryTolerance.hh" 41 #include "G4BoundingEnvelope.hh" << 42 44 43 #include "G4VPVParameterisation.hh" 45 #include "G4VPVParameterisation.hh" 44 #include "G4QuickRand.hh" << 45 46 46 #include "G4VGraphicsScene.hh" << 47 #include "Randomize.hh" 47 #include "G4Polyhedron.hh" << 48 48 49 #include "G4AutoLock.hh" << 49 #include "meshdefs.hh" 50 50 51 namespace << 51 #include "G4VGraphicsScene.hh" 52 { << 52 #include "G4Polyhedron.hh" 53 G4Mutex zminmaxMutex = G4MUTEX_INITIALIZER; << 53 #include "G4NURBS.hh" 54 } << 54 #include "G4NURBStube.hh" >> 55 #include "G4NURBScylinder.hh" >> 56 #include "G4NURBStubesector.hh" 55 57 56 using namespace CLHEP; 58 using namespace CLHEP; 57 59 58 ////////////////////////////////////////////// 60 ///////////////////////////////////////////////////////////////////////// 59 // 61 // 60 // Constructor - check parameters, convert ang 62 // Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI 61 // - note if pdphi>2PI then reset 63 // - note if pdphi>2PI then reset to 2PI 62 64 63 G4CutTubs::G4CutTubs( const G4String &pName, 65 G4CutTubs::G4CutTubs( const G4String &pName, 64 G4double pRMin, G4double 66 G4double pRMin, G4double pRMax, 65 G4double pDz, 67 G4double pDz, 66 G4double pSPhi, G4double 68 G4double pSPhi, G4double pDPhi, 67 G4ThreeVector pLowNorm,G 69 G4ThreeVector pLowNorm,G4ThreeVector pHighNorm ) 68 : G4CSGSolid(pName), fRMin(pRMin), fRMax(pRM << 70 : G4Tubs(pName, pRMin, pRMax, pDz, pSPhi, pDPhi), 69 fSPhi(0.), fDPhi(0.), fZMin(0.), fZMax(0.) << 71 fPhiFullCutTube(true) 70 { 72 { 71 kRadTolerance = G4GeometryTolerance::GetInst 73 kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance(); 72 kAngTolerance = G4GeometryTolerance::GetInst 74 kAngTolerance = G4GeometryTolerance::GetInstance()->GetAngularTolerance(); 73 75 74 halfCarTolerance = kCarTolerance*0.5; << 75 halfRadTolerance = kRadTolerance*0.5; << 76 halfAngTolerance = kAngTolerance*0.5; << 77 << 78 if (pDz<=0) // Check z-len << 79 { << 80 std::ostringstream message; << 81 message << "Negative Z half-length (" << p << 82 G4Exception("G4CutTubs::G4CutTubs()", "Geo << 83 } << 84 if ( (pRMin >= pRMax) || (pRMin < 0) ) // Ch << 85 { << 86 std::ostringstream message; << 87 message << "Invalid values for radii in so << 88 << G4endl << 89 << " pRMin = " << pRMin << << 90 G4Exception("G4CutTubs::G4CutTubs()", "Geo << 91 } << 92 << 93 // Check angles << 94 // << 95 CheckPhiAngles(pSPhi, pDPhi); << 96 << 97 // Check on Cutted Planes Normals 76 // Check on Cutted Planes Normals 98 // If there is NO CUT, propose to use G4Tubs 77 // If there is NO CUT, propose to use G4Tubs instead 99 // 78 // 100 if ( ( pLowNorm.x() == 0.0) && ( pLowNorm.y( << 79 if(pDPhi<twopi) { fPhiFullCutTube=false; } 101 && ( pHighNorm.x() == 0.0) && (pHighNorm.y << 80 >> 81 if ( ( !pLowNorm.x()) && ( !pLowNorm.y()) >> 82 && ( !pHighNorm.x()) && (!pHighNorm.y()) ) 102 { 83 { 103 std::ostringstream message; 84 std::ostringstream message; 104 message << "Inexisting Low/High Normal to 85 message << "Inexisting Low/High Normal to Z plane or Parallel to Z." 105 << G4endl 86 << G4endl 106 << "Normals to Z plane are " << pL << 87 << "Normals to Z plane are (" << pLowNorm <<" and " 107 << pHighNorm << " in solid: " << G << 88 << pHighNorm << ") in solid: " << GetName(); 108 G4Exception("G4CutTubs::G4CutTubs()", "Geo 89 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids1001", 109 JustWarning, message, "Should 90 JustWarning, message, "Should use G4Tubs!"); 110 } 91 } 111 92 112 // If Normal is (0,0,0),means parallel to R, 93 // If Normal is (0,0,0),means parallel to R, give it value of (0,0,+/-1) 113 // << 94 // 114 if (pLowNorm.mag2() == 0.) { pLowNorm.setZ( 95 if (pLowNorm.mag2() == 0.) { pLowNorm.setZ(-1.); } 115 if (pHighNorm.mag2()== 0.) { pHighNorm.setZ 96 if (pHighNorm.mag2()== 0.) { pHighNorm.setZ(1.); } 116 97 117 // Given Normals to Cut Planes have to be an << 98 // Given Normals to Cut Planes have to be an unit vectors. 118 // Normalize if it is needed. 99 // Normalize if it is needed. 119 // 100 // 120 if (pLowNorm.mag2() != 1.) { pLowNorm = pL 101 if (pLowNorm.mag2() != 1.) { pLowNorm = pLowNorm.unit(); } 121 if (pHighNorm.mag2()!= 1.) { pHighNorm = pH 102 if (pHighNorm.mag2()!= 1.) { pHighNorm = pHighNorm.unit(); } 122 103 123 // Normals to cutted planes have to point ou 104 // Normals to cutted planes have to point outside Solid 124 // 105 // 125 if( (pLowNorm.mag2() != 0.) && (pHighNorm.ma 106 if( (pLowNorm.mag2() != 0.) && (pHighNorm.mag2()!= 0. ) ) 126 { 107 { 127 if( ( pLowNorm.z()>= 0. ) || ( pHighNorm.z 108 if( ( pLowNorm.z()>= 0. ) || ( pHighNorm.z() <= 0.)) 128 { 109 { 129 std::ostringstream message; 110 std::ostringstream message; 130 message << "Invalid Low or High Normal t 111 message << "Invalid Low or High Normal to Z plane; " 131 "has to point outside Solid." 112 "has to point outside Solid." << G4endl 132 << "Invalid Norm to Z plane (" < 113 << "Invalid Norm to Z plane (" << pLowNorm << " or " 133 << pHighNorm << ") in solid: " < 114 << pHighNorm << ") in solid: " << GetName(); 134 G4Exception("G4CutTubs::G4CutTubs()", "G 115 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002", 135 FatalException, message); 116 FatalException, message); 136 } 117 } 137 } 118 } 138 fLowNorm = pLowNorm; 119 fLowNorm = pLowNorm; 139 fHighNorm = pHighNorm; 120 fHighNorm = pHighNorm; 140 121 141 // Check intersection of cut planes, they MU << 122 // Check Intersection of Cutted planes. They MUST NOT Intersect 142 // each other inside the lateral surface << 143 // 123 // 144 if(IsCrossingCutPlanes()) 124 if(IsCrossingCutPlanes()) 145 { 125 { 146 std::ostringstream message; 126 std::ostringstream message; 147 message << "Invalid normals to Z plane in << 127 message << "Invalid Low or High Normal to Z plane; " 148 << "Cut planes are crossing inside << 128 << "Crossing Cutted Planes." << G4endl 149 << " Solid type: G4CutTubs\n" << 129 << "Invalid Norm to Z plane (" << pLowNorm << " and " 150 << " Parameters: \n" << 130 << pHighNorm << ") in solid: " << GetName(); 151 << " inner radius : " << fRMin/ << 152 << " outer radius : " << fRMax/ << 153 << " half length Z: " << fDz/mm << 154 << " starting phi : " << fSPhi/ << 155 << " delta phi : " << fDPhi/ << 156 << " low Norm : " << fLowNo << 157 << " high Norm : " << fHighN << 158 G4Exception("G4CutTubs::G4CutTubs()", "Geo 131 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002", 159 FatalException, message); 132 FatalException, message); 160 } 133 } 161 } 134 } 162 135 163 ////////////////////////////////////////////// 136 /////////////////////////////////////////////////////////////////////// 164 // 137 // 165 // Fake default constructor - sets only member 138 // Fake default constructor - sets only member data and allocates memory 166 // for usage restri 139 // for usage restricted to object persistency. 167 // 140 // 168 G4CutTubs::G4CutTubs( __void__& a ) 141 G4CutTubs::G4CutTubs( __void__& a ) 169 : G4CSGSolid(a) << 142 : G4Tubs(a), >> 143 fLowNorm(G4ThreeVector()), fHighNorm(G4ThreeVector()), >> 144 fPhiFullCutTube(false) 170 { 145 { 171 } 146 } 172 147 173 ////////////////////////////////////////////// 148 ////////////////////////////////////////////////////////////////////////// 174 // 149 // 175 // Destructor 150 // Destructor 176 151 177 G4CutTubs::~G4CutTubs() = default; << 152 G4CutTubs::~G4CutTubs() >> 153 { >> 154 } 178 155 179 ////////////////////////////////////////////// 156 ////////////////////////////////////////////////////////////////////////// 180 // 157 // 181 // Copy constructor 158 // Copy constructor 182 159 183 G4CutTubs::G4CutTubs(const G4CutTubs&) = defau << 160 G4CutTubs::G4CutTubs(const G4CutTubs& rhs) >> 161 : G4Tubs(rhs), >> 162 fLowNorm(rhs.fLowNorm), fHighNorm(rhs.fHighNorm), >> 163 fPhiFullCutTube(rhs.fPhiFullCutTube) >> 164 { >> 165 } 184 166 185 ////////////////////////////////////////////// 167 ////////////////////////////////////////////////////////////////////////// 186 // 168 // 187 // Assignment operator 169 // Assignment operator 188 170 189 G4CutTubs& G4CutTubs::operator = (const G4CutT << 171 G4CutTubs& G4CutTubs::operator = (const G4CutTubs& rhs) 190 { 172 { 191 // Check assignment to self 173 // Check assignment to self 192 // 174 // 193 if (this == &rhs) { return *this; } 175 if (this == &rhs) { return *this; } 194 176 195 // Copy base class data 177 // Copy base class data 196 // 178 // 197 G4CSGSolid::operator=(rhs); << 179 G4Tubs::operator=(rhs); 198 180 199 // Copy data 181 // Copy data 200 // 182 // 201 kRadTolerance = rhs.kRadTolerance; kAngTole << 202 fRMin = rhs.fRMin; fRMax = rhs.fRMax; fDz = << 203 fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi; << 204 fZMin = rhs.fZMin; fZMax = rhs.fZMax; << 205 sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPh << 206 cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = r << 207 sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPh << 208 sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPh << 209 fPhiFullCutTube = rhs.fPhiFullCutTube; << 210 halfCarTolerance = rhs.halfCarTolerance; << 211 halfRadTolerance = rhs.halfRadTolerance; << 212 halfAngTolerance = rhs.halfAngTolerance; << 213 fLowNorm = rhs.fLowNorm; fHighNorm = rhs.fH 183 fLowNorm = rhs.fLowNorm; fHighNorm = rhs.fHighNorm; >> 184 fPhiFullCutTube = rhs.fPhiFullCutTube; 214 185 215 return *this; 186 return *this; 216 } 187 } 217 188 218 ////////////////////////////////////////////// << 189 //////////////////////////////////////////////////////////////////////// 219 // 190 // 220 // Get volume << 191 // Calculate extent under transform and specified limit 221 192 222 G4double G4CutTubs::GetCubicVolume() << 193 G4bool G4CutTubs::CalculateExtent( const EAxis pAxis, >> 194 const G4VoxelLimits& pVoxelLimit, >> 195 const G4AffineTransform& pTransform, >> 196 G4double& pMin, >> 197 G4double& pMax ) const 223 { 198 { 224 constexpr G4int nphi = 200, nrho = 100; << 199 if ( (!pTransform.IsRotated()) && (fDPhi == twopi) && (fRMin == 0) ) 225 << 226 if (fCubicVolume == 0.) << 227 { 200 { 228 // get parameters << 201 // Special case handling for unrotated solid tubes 229 G4double rmin = GetInnerRadius(); << 202 // Compute x/y/z mins and maxs fro bounding box respecting limits, 230 G4double rmax = GetOuterRadius(); << 203 // with early returns if outside limits. Then switch() on pAxis, 231 G4double dz = GetZHalfLength(); << 204 // and compute exact x and y limit for x/y case 232 G4double sphi = GetStartPhiAngle(); << 205 233 G4double dphi = GetDeltaPhiAngle(); << 206 G4double xoffset, xMin, xMax; >> 207 G4double yoffset, yMin, yMax; >> 208 G4double zoffset, zMin, zMax; >> 209 >> 210 G4double diff1, diff2, maxDiff, newMin, newMax; >> 211 G4double xoff1, xoff2, yoff1, yoff2, delta; >> 212 >> 213 xoffset = pTransform.NetTranslation().x(); >> 214 xMin = xoffset - fRMax; >> 215 xMax = xoffset + fRMax; 234 216 235 // calculate volume << 217 if (pVoxelLimit.IsXLimited()) 236 G4double volume = dz*dphi*(rmax*rmax - rmi << 237 if (dphi < twopi) // make recalculation << 238 { 218 { 239 // set values for calculation of h - dis << 219 if ( (xMin > pVoxelLimit.GetMaxXExtent()) 240 // opposite points on bases << 220 || (xMax < pVoxelLimit.GetMinXExtent()) ) 241 G4ThreeVector nbot = GetLowNorm(); << 221 { 242 G4ThreeVector ntop = GetHighNorm(); << 222 return false; 243 G4double nx = nbot.x()/nbot.z() - ntop.x << 223 } 244 G4double ny = nbot.y()/nbot.z() - ntop.y << 224 else >> 225 { >> 226 if (xMin < pVoxelLimit.GetMinXExtent()) >> 227 { >> 228 xMin = pVoxelLimit.GetMinXExtent(); >> 229 } >> 230 if (xMax > pVoxelLimit.GetMaxXExtent()) >> 231 { >> 232 xMax = pVoxelLimit.GetMaxXExtent(); >> 233 } >> 234 } >> 235 } >> 236 yoffset = pTransform.NetTranslation().y(); >> 237 yMin = yoffset - fRMax; >> 238 yMax = yoffset + fRMax; 245 239 246 // compute volume by integration << 240 if ( pVoxelLimit.IsYLimited() ) 247 G4double delrho = (rmax - rmin)/nrho; << 241 { 248 G4double delphi = dphi/nphi; << 242 if ( (yMin > pVoxelLimit.GetMaxYExtent()) 249 volume = 0.; << 243 || (yMax < pVoxelLimit.GetMinYExtent()) ) 250 for (G4int irho=0; irho<nrho; ++irho) << 251 { 244 { 252 G4double r1 = rmin + delrho*irho; << 245 return false; 253 G4double r2 = rmin + delrho*(irho + 1 << 246 } 254 G4double rho = 0.5*(r1 + r2); << 247 else 255 G4double sector = 0.5*delphi*(r2*r2 - << 248 { 256 for (G4int iphi=0; iphi<nphi; ++iphi) << 249 if (yMin < pVoxelLimit.GetMinYExtent()) 257 { 250 { 258 G4double phi = sphi + delphi*(iphi + << 251 yMin = pVoxelLimit.GetMinYExtent(); 259 G4double h = nx*rho*std::cos(phi) + << 252 } 260 volume += sector*h; << 253 if (yMax > pVoxelLimit.GetMaxYExtent()) >> 254 { >> 255 yMax=pVoxelLimit.GetMaxYExtent(); 261 } 256 } 262 } 257 } 263 } 258 } 264 fCubicVolume = volume; << 259 zoffset = pTransform.NetTranslation().z(); 265 } << 260 GetMaxMinZ(zMin,zMax); 266 return fCubicVolume; << 261 zMin += zoffset; 267 } << 262 zMax += zoffset; 268 263 269 ////////////////////////////////////////////// << 264 if ( pVoxelLimit.IsZLimited() ) 270 // << 265 { 271 // Get surface area << 266 if ( (zMin > pVoxelLimit.GetMaxZExtent()) >> 267 || (zMax < pVoxelLimit.GetMinZExtent()) ) >> 268 { >> 269 return false; >> 270 } >> 271 else >> 272 { >> 273 if (zMin < pVoxelLimit.GetMinZExtent()) >> 274 { >> 275 zMin = pVoxelLimit.GetMinZExtent(); >> 276 } >> 277 if (zMax > pVoxelLimit.GetMaxZExtent()) >> 278 { >> 279 zMax = pVoxelLimit.GetMaxZExtent(); >> 280 } >> 281 } >> 282 } >> 283 switch ( pAxis ) // Known to cut cylinder >> 284 { >> 285 case kXAxis : >> 286 { >> 287 yoff1 = yoffset - yMin; >> 288 yoff2 = yMax - yoffset; 272 289 273 G4double G4CutTubs::GetSurfaceArea() << 290 if ( (yoff1 >= 0) && (yoff2 >= 0) ) // Y limits cross max/min x 274 { << 291 { // => no change 275 constexpr G4int nphi = 400; << 292 pMin = xMin; >> 293 pMax = xMax; >> 294 } >> 295 else >> 296 { >> 297 // Y limits don't cross max/min x => compute max delta x, >> 298 // hence new mins/maxs 276 299 277 if (fSurfaceArea == 0.) << 300 delta = fRMax*fRMax - yoff1*yoff1; 278 { << 301 diff1 = (delta>0.) ? std::sqrt(delta) : 0.; 279 // get parameters << 302 delta = fRMax*fRMax - yoff2*yoff2; 280 G4double rmin = GetInnerRadius(); << 303 diff2 = (delta>0.) ? std::sqrt(delta) : 0.; 281 G4double rmax = GetOuterRadius(); << 304 maxDiff = (diff1 > diff2) ? diff1:diff2; 282 G4double dz = GetZHalfLength(); << 305 newMin = xoffset - maxDiff; 283 G4double sphi = GetStartPhiAngle(); << 306 newMax = xoffset + maxDiff; 284 G4double dphi = GetDeltaPhiAngle(); << 307 pMin = (newMin < xMin) ? xMin : newMin; 285 G4ThreeVector nbot = GetLowNorm(); << 308 pMax = (newMax > xMax) ? xMax : newMax; 286 G4ThreeVector ntop = GetHighNorm(); << 309 } 287 << 310 break; 288 // calculate lateral surface area << 311 } 289 G4double sinner = 2.*dz*dphi*rmin; << 312 case kYAxis : 290 G4double souter = 2.*dz*dphi*rmax; << 313 { 291 if (dphi < twopi) // make recalculation << 314 xoff1 = xoffset - xMin; 292 { << 315 xoff2 = xMax - xoffset; 293 // set values for calculation of h - dis << 294 // opposite points on bases << 295 G4double nx = nbot.x()/nbot.z() - ntop.x << 296 G4double ny = nbot.y()/nbot.z() - ntop.y << 297 << 298 // compute lateral surface area by integ << 299 G4double delphi = dphi/nphi; << 300 sinner = 0.; << 301 souter = 0.; << 302 for (G4int iphi=0; iphi<nphi; ++iphi) << 303 { << 304 G4double phi = sphi + delphi*(iphi + 0 << 305 G4double cosphi = std::cos(phi); << 306 G4double sinphi = std::sin(phi); << 307 sinner += rmin*(nx*cosphi + ny*sinphi) << 308 souter += rmax*(nx*cosphi + ny*sinphi) << 309 } << 310 sinner *= delphi*rmin; << 311 souter *= delphi*rmax; << 312 } << 313 // set surface area << 314 G4double scut = (dphi == twopi) ? 0. : 2. << 315 G4double szero = 0.5*dphi*(rmax*rmax - rmi << 316 G4double slow = szero/std::abs(nbot.z()); << 317 G4double shigh = szero/std::abs(ntop.z()); << 318 fSurfaceArea = sinner + souter + 2.*scut + << 319 } << 320 return fSurfaceArea; << 321 } << 322 316 323 ////////////////////////////////////////////// << 317 if ( (xoff1 >= 0) && (xoff2 >= 0) ) // X limits cross max/min y 324 // << 318 { // => no change 325 // Get bounding box << 319 pMin = yMin; >> 320 pMax = yMax; >> 321 } >> 322 else >> 323 { >> 324 // X limits don't cross max/min y => compute max delta y, >> 325 // hence new mins/maxs 326 326 327 void G4CutTubs::BoundingLimits(G4ThreeVector& << 327 delta = fRMax*fRMax - xoff1*xoff1; 328 { << 328 diff1 = (delta>0.) ? std::sqrt(delta) : 0.; 329 G4double rmin = GetInnerRadius(); << 329 delta = fRMax*fRMax - xoff2*xoff2; 330 G4double rmax = GetOuterRadius(); << 330 diff2 = (delta>0.) ? std::sqrt(delta) : 0.; 331 G4double dz = GetZHalfLength(); << 331 maxDiff = (diff1 > diff2) ? diff1 : diff2; 332 G4double dphi = GetDeltaPhiAngle(); << 332 newMin = yoffset - maxDiff; 333 << 333 newMax = yoffset + maxDiff; 334 G4double sinSphi = GetSinStartPhi(); << 334 pMin = (newMin < yMin) ? yMin : newMin; 335 G4double cosSphi = GetCosStartPhi(); << 335 pMax = (newMax > yMax) ? yMax : newMax; 336 G4double sinEphi = GetSinEndPhi(); << 336 } 337 G4double cosEphi = GetCosEndPhi(); << 337 break; 338 << 338 } 339 G4ThreeVector norm; << 339 case kZAxis: 340 G4double mag, topx, topy, dists, diste; << 340 { 341 G4bool iftop; << 341 pMin = zMin; 342 << 342 pMax = zMax; 343 // Find Zmin << 343 break; 344 // << 344 } 345 G4double zmin; << 345 default: 346 norm = GetLowNorm(); << 346 break; 347 mag = std::sqrt(norm.x()*norm.x() + norm.y( << 347 } 348 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag; << 348 pMin -= kCarTolerance; 349 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag; << 349 pMax += kCarTolerance; 350 dists = sinSphi*topx - cosSphi*topy; << 350 return true; 351 diste = -sinEphi*topx + cosEphi*topy; << 352 if (dphi > pi) << 353 { << 354 iftop = true; << 355 if (dists > 0 && diste > 0)iftop = false; << 356 } << 357 else << 358 { << 359 iftop = false; << 360 if (dists <= 0 && diste <= 0) iftop = true << 361 } << 362 if (iftop) << 363 { << 364 zmin = -(norm.x()*topx + norm.y()*topy)/no << 365 } << 366 else << 367 { << 368 G4double z1 = -rmin*(norm.x()*cosSphi + no << 369 G4double z2 = -rmin*(norm.x()*cosEphi + no << 370 G4double z3 = -rmax*(norm.x()*cosSphi + no << 371 G4double z4 = -rmax*(norm.x()*cosEphi + no << 372 zmin = std::min(std::min(std::min(z1,z2),z << 373 } << 374 << 375 // Find Zmax << 376 // << 377 G4double zmax; << 378 norm = GetHighNorm(); << 379 mag = std::sqrt(norm.x()*norm.x() + norm.y( << 380 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag; << 381 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag; << 382 dists = sinSphi*topx - cosSphi*topy; << 383 diste = -sinEphi*topx + cosEphi*topy; << 384 if (dphi > pi) << 385 { << 386 iftop = true; << 387 if (dists > 0 && diste > 0) iftop = false; << 388 } << 389 else << 390 { << 391 iftop = false; << 392 if (dists <= 0 && diste <= 0) iftop = true << 393 } << 394 if (iftop) << 395 { << 396 zmax = -(norm.x()*topx + norm.y()*topy)/no << 397 } << 398 else << 399 { << 400 G4double z1 = -rmin*(norm.x()*cosSphi + no << 401 G4double z2 = -rmin*(norm.x()*cosEphi + no << 402 G4double z3 = -rmax*(norm.x()*cosSphi + no << 403 G4double z4 = -rmax*(norm.x()*cosEphi + no << 404 zmax = std::max(std::max(std::max(z1,z2),z << 405 } << 406 << 407 // Find bounding box << 408 // << 409 if (dphi < twopi) << 410 { << 411 G4TwoVector vmin,vmax; << 412 G4GeomTools::DiskExtent(rmin,rmax, << 413 GetSinStartPhi(),G << 414 GetSinEndPhi(),Get << 415 vmin,vmax); << 416 pMin.set(vmin.x(),vmin.y(), zmin); << 417 pMax.set(vmax.x(),vmax.y(), zmax); << 418 } << 419 else << 420 { << 421 pMin.set(-rmax,-rmax, zmin); << 422 pMax.set( rmax, rmax, zmax); << 423 } 351 } 424 << 352 else // Calculate rotated vertex coordinates 425 // Check correctness of the bounding box << 426 // << 427 if (pMin.x() >= pMax.x() || pMin.y() >= pMax << 428 { 353 { 429 std::ostringstream message; << 354 G4int i, noEntries, noBetweenSections4; 430 message << "Bad bounding box (min >= max) << 355 G4bool existsAfterClip = false; 431 << GetName() << " !" << 356 G4ThreeVectorList* vertices = CreateRotatedVertices(pTransform); 432 << "\npMin = " << pMin << 433 << "\npMax = " << pMax; << 434 G4Exception("G4CutTubs::BoundingLimits()", << 435 JustWarning, message); << 436 DumpInfo(); << 437 } << 438 } << 439 << 440 ////////////////////////////////////////////// << 441 // << 442 // Calculate extent under transform and specif << 443 << 444 G4bool G4CutTubs::CalculateExtent( const EAxis << 445 const G4Vox << 446 const G4Aff << 447 G4dou << 448 G4dou << 449 { << 450 G4ThreeVector bmin, bmax; << 451 G4bool exist; << 452 357 453 // Get bounding box << 358 pMin = kInfinity; 454 BoundingLimits(bmin,bmax); << 359 pMax = -kInfinity; 455 360 456 // Check bounding box << 361 noEntries = vertices->size(); 457 G4BoundingEnvelope bbox(bmin,bmax); << 362 noBetweenSections4 = noEntries - 4; 458 #ifdef G4BBOX_EXTENT << 363 459 return bbox.CalculateExtent(pAxis,pVoxelLimi << 364 for ( i = 0 ; i < noEntries ; i += 4 ) 460 #endif << 365 { 461 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVox << 366 ClipCrossSection(vertices, i, pVoxelLimit, pAxis, pMin, pMax); 462 { << 367 } 463 return exist = pMin < pMax; << 368 for ( i = 0 ; i < noBetweenSections4 ; i += 4 ) 464 } << 369 { 465 << 370 ClipBetweenSections(vertices, i, pVoxelLimit, pAxis, pMin, pMax); 466 // Get parameters of the solid << 371 } 467 G4double rmin = GetInnerRadius(); << 372 if ( (pMin != kInfinity) || (pMax != -kInfinity) ) 468 G4double rmax = GetOuterRadius(); << 373 { 469 G4double dphi = GetDeltaPhiAngle(); << 374 existsAfterClip = true; 470 G4double zmin = bmin.z(); << 375 pMin -= kCarTolerance; // Add 2*tolerance to avoid precision troubles 471 G4double zmax = bmax.z(); << 376 pMax += kCarTolerance; 472 << 377 } 473 // Find bounding envelope and calculate exte << 378 else 474 // << 379 { 475 const G4int NSTEPS = 24; // numbe << 380 // Check for case where completely enveloping clipping volume 476 G4double astep = twopi/NSTEPS; // max a << 381 // If point inside then we are confident that the solid completely 477 G4int ksteps = (dphi <= astep) ? 1 : (G4i << 382 // envelopes the clipping volume. Hence set min/max extents according 478 G4double ang = dphi/ksteps; << 383 // to clipping volume extents along the specified axis. 479 << 384 480 G4double sinHalf = std::sin(0.5*ang); << 385 G4ThreeVector clipCentre( 481 G4double cosHalf = std::cos(0.5*ang); << 386 (pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5, 482 G4double sinStep = 2.*sinHalf*cosHalf; << 387 (pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5, 483 G4double cosStep = 1. - 2.*sinHalf*sinHalf; << 388 (pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5 ); 484 G4double rext = rmax/cosHalf; << 389 485 << 390 if ( Inside(pTransform.Inverse().TransformPoint(clipCentre)) != kOutside ) 486 // bounding envelope for full cylinder consi << 391 { 487 // in other cases it is a sequence of quadri << 392 existsAfterClip = true; 488 if (rmin == 0 && dphi == twopi) << 393 pMin = pVoxelLimit.GetMinExtent(pAxis); 489 { << 394 pMax = pVoxelLimit.GetMaxExtent(pAxis); 490 G4double sinCur = sinHalf; << 395 } 491 G4double cosCur = cosHalf; << 396 } 492 << 397 delete vertices; 493 G4ThreeVectorList baseA(NSTEPS),baseB(NSTE << 398 return existsAfterClip; 494 for (G4int k=0; k<NSTEPS; ++k) << 495 { << 496 baseA[k].set(rext*cosCur,rext*sinCur,zmi << 497 baseB[k].set(rext*cosCur,rext*sinCur,zma << 498 << 499 G4double sinTmp = sinCur; << 500 sinCur = sinCur*cosStep + cosCur*sinStep << 501 cosCur = cosCur*cosStep - sinTmp*sinStep << 502 } << 503 std::vector<const G4ThreeVectorList *> pol << 504 polygons[0] = &baseA; << 505 polygons[1] = &baseB; << 506 G4BoundingEnvelope benv(bmin,bmax,polygons << 507 exist = benv.CalculateExtent(pAxis,pVoxelL << 508 } << 509 else << 510 { << 511 G4double sinStart = GetSinStartPhi(); << 512 G4double cosStart = GetCosStartPhi(); << 513 G4double sinEnd = GetSinEndPhi(); << 514 G4double cosEnd = GetCosEndPhi(); << 515 G4double sinCur = sinStart*cosHalf + cos << 516 G4double cosCur = cosStart*cosHalf - sin << 517 << 518 // set quadrilaterals << 519 G4ThreeVectorList pols[NSTEPS+2]; << 520 for (G4int k=0; k<ksteps+2; ++k) pols[k].r << 521 pols[0][0].set(rmin*cosStart,rmin*sinStart << 522 pols[0][1].set(rmin*cosStart,rmin*sinStart << 523 pols[0][2].set(rmax*cosStart,rmax*sinStart << 524 pols[0][3].set(rmax*cosStart,rmax*sinStart << 525 for (G4int k=1; k<ksteps+1; ++k) << 526 { << 527 pols[k][0].set(rmin*cosCur,rmin*sinCur,z << 528 pols[k][1].set(rmin*cosCur,rmin*sinCur,z << 529 pols[k][2].set(rext*cosCur,rext*sinCur,z << 530 pols[k][3].set(rext*cosCur,rext*sinCur,z << 531 << 532 G4double sinTmp = sinCur; << 533 sinCur = sinCur*cosStep + cosCur*sinStep << 534 cosCur = cosCur*cosStep - sinTmp*sinStep << 535 } << 536 pols[ksteps+1][0].set(rmin*cosEnd,rmin*sin << 537 pols[ksteps+1][1].set(rmin*cosEnd,rmin*sin << 538 pols[ksteps+1][2].set(rmax*cosEnd,rmax*sin << 539 pols[ksteps+1][3].set(rmax*cosEnd,rmax*sin << 540 << 541 // set envelope and calculate extent << 542 std::vector<const G4ThreeVectorList *> pol << 543 polygons.resize(ksteps+2); << 544 for (G4int k=0; k<ksteps+2; ++k) { polygon << 545 G4BoundingEnvelope benv(bmin,bmax,polygons << 546 exist = benv.CalculateExtent(pAxis,pVoxelL << 547 } 399 } 548 return exist; << 549 } 400 } 550 401 551 ////////////////////////////////////////////// << 402 /////////////////////////////////////////////////////////////////////////// 552 // 403 // 553 // Return whether point inside/outside/on surf 404 // Return whether point inside/outside/on surface 554 405 555 EInside G4CutTubs::Inside( const G4ThreeVector 406 EInside G4CutTubs::Inside( const G4ThreeVector& p ) const 556 { 407 { 557 G4ThreeVector vZ = G4ThreeVector(0,0,fDz); << 408 G4double zinLow,zinHigh,r2,pPhi=0.; >> 409 G4double tolRMin,tolRMax; >> 410 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 558 EInside in = kInside; 411 EInside in = kInside; >> 412 static const G4double halfCarTolerance=kCarTolerance*0.5; >> 413 static const G4double halfRadTolerance=kRadTolerance*0.5; >> 414 static const G4double halfAngTolerance=kAngTolerance*0.5; >> 415 >> 416 // Check if point is contained in the cut plane in -/+ Z 559 417 560 // Check the lower cut plane 418 // Check the lower cut plane 561 // 419 // 562 G4double zinLow =(p+vZ).dot(fLowNorm); << 420 zinLow =(p+vZ).dot(fLowNorm); 563 if (zinLow > halfCarTolerance) { return kOu << 421 if (zinLow>halfCarTolerance) { return kOutside; } 564 422 565 // Check the higher cut plane 423 // Check the higher cut plane 566 // 424 // 567 G4double zinHigh = (p-vZ).dot(fHighNorm); << 425 zinHigh = (p-vZ).dot(fHighNorm); 568 if (zinHigh > halfCarTolerance) { return kO << 426 if (zinHigh>halfCarTolerance) { return kOutside; } 569 427 570 // Check radius 428 // Check radius 571 // 429 // 572 G4double r2 = p.x()*p.x() + p.y()*p.y() ; << 430 r2 = p.x()*p.x() + p.y()*p.y() ; 573 431 574 G4double tolRMin = fRMin - halfRadTolerance; << 432 // First check 'generous' boundaries R+tolerance 575 G4double tolRMax = fRMax + halfRadTolerance; << 433 // >> 434 tolRMin = fRMin - halfRadTolerance ; >> 435 tolRMax = fRMax + halfRadTolerance ; 576 if ( tolRMin < 0 ) { tolRMin = 0; } 436 if ( tolRMin < 0 ) { tolRMin = 0; } 577 << 437 578 if (r2 < tolRMin*tolRMin || r2 > tolRMax*tol << 438 if ( ((r2 < tolRMin*tolRMin) || (r2 > tolRMax*tolRMax)) 579 << 439 && (r2 >=halfRadTolerance*halfRadTolerance) ) { return kOutside; } 580 // Check Phi cut << 440 >> 441 // Check Phi 581 // 442 // 582 if(!fPhiFullCutTube) 443 if(!fPhiFullCutTube) 583 { 444 { 584 if ((tolRMin == 0) && (std::fabs(p.x()) <= << 445 // Try outer tolerant phi boundaries only 585 && (std::fabs(p.y()) <= << 446 >> 447 if ( (tolRMin==0) && (std::fabs(p.x())<=halfCarTolerance) >> 448 && (std::fabs(p.y())<=halfCarTolerance) ) 586 { 449 { 587 return kSurface; 450 return kSurface; 588 } 451 } >> 452 >> 453 pPhi = std::atan2(p.y(),p.x()) ; 589 454 590 G4double phi0 = std::atan2(p.y(),p.x()); << 455 if ( pPhi < -halfAngTolerance) { pPhi += twopi; } // 0<=pPhi<2pi 591 G4double phi1 = phi0 - twopi; << 456 if ( fSPhi >= 0 ) 592 G4double phi2 = phi0 + twopi; << 457 { 593 << 458 if ( (std::fabs(pPhi) < halfAngTolerance) 594 in = kOutside; << 459 && (std::fabs(fSPhi + fDPhi - twopi) < halfAngTolerance) ) 595 G4double sphi = fSPhi - halfAngTolerance; << 460 { 596 G4double ephi = sphi + fDPhi + kAngToleran << 461 pPhi += twopi ; // 0 <= pPhi < 2pi 597 if ((phi0 >= sphi && phi0 <= ephi) || << 462 } 598 (phi1 >= sphi && phi1 <= ephi) || << 463 if ( (pPhi <= fSPhi - halfAngTolerance) 599 (phi2 >= sphi && phi2 <= ephi)) in = << 464 || (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) 600 if (in == kOutside) { return kOutside; } << 465 { 601 << 466 in = kOutside ; 602 sphi += kAngTolerance; << 467 } 603 ephi -= kAngTolerance; << 468 else if ( (pPhi <= fSPhi + halfAngTolerance) 604 if ((phi0 >= sphi && phi0 <= ephi) || << 469 || (pPhi >= fSPhi + fDPhi - halfAngTolerance) ) 605 (phi1 >= sphi && phi1 <= ephi) || << 470 { 606 (phi2 >= sphi && phi2 <= ephi)) in = << 471 in=kSurface; 607 if (in == kSurface) { return kSurface; } << 472 } >> 473 } >> 474 else // fSPhi < 0 >> 475 { >> 476 if ( (pPhi <= fSPhi + twopi - halfAngTolerance) >> 477 && (pPhi >= fSPhi + fDPhi + halfAngTolerance) ) >> 478 { >> 479 in = kOutside; >> 480 } >> 481 else >> 482 { >> 483 in = kSurface ; >> 484 } >> 485 } 608 } 486 } 609 487 610 // Check on the Surface for Z 488 // Check on the Surface for Z 611 // 489 // 612 if ((zinLow >= -halfCarTolerance) || (zinHig << 490 if ((zinLow>=-halfCarTolerance) >> 491 || (zinHigh>=-halfCarTolerance)) 613 { 492 { 614 return kSurface; << 493 in=kSurface; 615 } 494 } 616 495 617 // Check on the Surface for R 496 // Check on the Surface for R 618 // 497 // 619 if (fRMin != 0.0) { tolRMin = fRMin + halfRa << 498 if (fRMin) { tolRMin = fRMin + halfRadTolerance ; } 620 else { tolRMin = 0; } << 499 else { tolRMin = 0 ; } 621 tolRMax = fRMax - halfRadTolerance; << 500 tolRMax = fRMax - halfRadTolerance ; 622 if (((r2 <= tolRMin*tolRMin) || (r2 >= tolRM << 501 if ( ((r2 <= tolRMin*tolRMin) || (r2 >= tolRMax*tolRMax))&& 623 (r2 >= halfRadTolerance*halfRadToleranc << 502 (r2 >=halfRadTolerance*halfRadTolerance) ) 624 { 503 { 625 return kSurface; 504 return kSurface; 626 } 505 } 627 506 628 return in; 507 return in; 629 } 508 } 630 509 631 ////////////////////////////////////////////// 510 /////////////////////////////////////////////////////////////////////////// 632 // 511 // 633 // Return unit normal of surface closest to p 512 // Return unit normal of surface closest to p 634 // - note if point on z axis, ignore phi divid 513 // - note if point on z axis, ignore phi divided sides 635 // - unsafe if point close to z axis a rmin=0 514 // - unsafe if point close to z axis a rmin=0 - no explicit checks 636 515 637 G4ThreeVector G4CutTubs::SurfaceNormal( const 516 G4ThreeVector G4CutTubs::SurfaceNormal( const G4ThreeVector& p ) const 638 { 517 { 639 G4int noSurfaces = 0; 518 G4int noSurfaces = 0; 640 G4double rho, pPhi; 519 G4double rho, pPhi; 641 G4double distZLow,distZHigh, distRMin, distR 520 G4double distZLow,distZHigh, distRMin, distRMax; 642 G4double distSPhi = kInfinity, distEPhi = kI 521 G4double distSPhi = kInfinity, distEPhi = kInfinity; 643 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 522 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 644 523 >> 524 static const G4double halfCarTolerance = 0.5*kCarTolerance; >> 525 static const G4double halfAngTolerance = 0.5*kAngTolerance; >> 526 645 G4ThreeVector norm, sumnorm(0.,0.,0.); 527 G4ThreeVector norm, sumnorm(0.,0.,0.); 646 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0); 528 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0); 647 G4ThreeVector nR, nPs, nPe; 529 G4ThreeVector nR, nPs, nPe; 648 530 649 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()); 531 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()); 650 532 651 distRMin = std::fabs(rho - fRMin); 533 distRMin = std::fabs(rho - fRMin); 652 distRMax = std::fabs(rho - fRMax); 534 distRMax = std::fabs(rho - fRMax); 653 535 654 // dist to Low Cut 536 // dist to Low Cut 655 // 537 // 656 distZLow =std::fabs((p+vZ).dot(fLowNorm)); 538 distZLow =std::fabs((p+vZ).dot(fLowNorm)); 657 << 539 658 // dist to High Cut 540 // dist to High Cut 659 // 541 // 660 distZHigh = std::fabs((p-vZ).dot(fHighNorm)) 542 distZHigh = std::fabs((p-vZ).dot(fHighNorm)); 661 543 662 if (!fPhiFullCutTube) // Protected agains << 544 if (!fPhiFullCutTube) // Protected against (0,0,z) 663 { 545 { 664 if ( rho > halfCarTolerance ) 546 if ( rho > halfCarTolerance ) 665 { 547 { 666 pPhi = std::atan2(p.y(),p.x()); 548 pPhi = std::atan2(p.y(),p.x()); 667 << 549 668 if(pPhi < fSPhi- halfCarTolerance) 550 if(pPhi < fSPhi- halfCarTolerance) { pPhi += twopi; } 669 else if(pPhi > fSPhi+fDPhi+ halfCarToler 551 else if(pPhi > fSPhi+fDPhi+ halfCarTolerance) { pPhi -= twopi; } 670 552 671 distSPhi = std::fabs(pPhi - fSPhi); << 553 distSPhi = std::fabs(pPhi - fSPhi); 672 distEPhi = std::fabs(pPhi - fSPhi - fDPh << 554 distEPhi = std::fabs(pPhi - fSPhi - fDPhi); 673 } 555 } 674 else if( fRMin == 0.0 ) << 556 else if( !fRMin ) 675 { 557 { 676 distSPhi = 0.; << 558 distSPhi = 0.; 677 distEPhi = 0.; << 559 distEPhi = 0.; 678 } 560 } 679 nPs = G4ThreeVector( sinSPhi, -cosSPhi, 0 << 561 nPs = G4ThreeVector(std::sin(fSPhi),-std::cos(fSPhi),0); 680 nPe = G4ThreeVector( -sinEPhi, cosEPhi, 0 << 562 nPe = G4ThreeVector(-std::sin(fSPhi+fDPhi),std::cos(fSPhi+fDPhi),0); 681 } 563 } 682 if ( rho > halfCarTolerance ) { nR = G4Three 564 if ( rho > halfCarTolerance ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); } 683 565 684 if( distRMax <= halfCarTolerance ) << 566 if( distRMax <= halfCarTolerance ) 685 { 567 { 686 ++noSurfaces; << 568 noSurfaces ++; 687 sumnorm += nR; 569 sumnorm += nR; 688 } 570 } 689 if( (fRMin != 0.0) && (distRMin <= halfCarTo << 571 if( fRMin && (distRMin <= halfCarTolerance) ) 690 { 572 { 691 ++noSurfaces; << 573 noSurfaces ++; 692 sumnorm -= nR; 574 sumnorm -= nR; 693 } 575 } 694 if( fDPhi < twopi ) << 576 if( fDPhi < twopi ) 695 { 577 { 696 if (distSPhi <= halfAngTolerance) << 578 if (distSPhi <= halfAngTolerance) 697 { 579 { 698 ++noSurfaces; << 580 noSurfaces ++; 699 sumnorm += nPs; 581 sumnorm += nPs; 700 } 582 } 701 if (distEPhi <= halfAngTolerance) << 583 if (distEPhi <= halfAngTolerance) 702 { 584 { 703 ++noSurfaces; << 585 noSurfaces ++; 704 sumnorm += nPe; 586 sumnorm += nPe; 705 } 587 } 706 } 588 } 707 if (distZLow <= halfCarTolerance) << 589 if (distZLow <= halfCarTolerance) 708 { 590 { 709 ++noSurfaces; << 591 noSurfaces ++; 710 sumnorm += fLowNorm; 592 sumnorm += fLowNorm; 711 } 593 } 712 if (distZHigh <= halfCarTolerance) << 594 if (distZHigh <= halfCarTolerance) 713 { 595 { 714 ++noSurfaces; << 596 noSurfaces ++; 715 sumnorm += fHighNorm; 597 sumnorm += fHighNorm; 716 } 598 } 717 if ( noSurfaces == 0 ) 599 if ( noSurfaces == 0 ) 718 { 600 { 719 #ifdef G4CSGDEBUG 601 #ifdef G4CSGDEBUG 720 G4Exception("G4CutTubs::SurfaceNormal(p)", 602 G4Exception("G4CutTubs::SurfaceNormal(p)", "GeomSolids1002", 721 JustWarning, "Point p is not o 603 JustWarning, "Point p is not on surface !?" ); 722 G4int oldprc = G4cout.precision(20); 604 G4int oldprc = G4cout.precision(20); 723 G4cout<< "G4CutTubs::SN ( "<<p.x()<<", "<< 605 G4cout<< "G4CutTubs::SN ( "<<p.x()<<", "<<p.y()<<", "<<p.z()<<" ); " 724 << G4endl << G4endl; 606 << G4endl << G4endl; 725 G4cout.precision(oldprc) ; 607 G4cout.precision(oldprc) ; 726 #endif << 608 #endif 727 norm = ApproxSurfaceNormal(p); 609 norm = ApproxSurfaceNormal(p); 728 } 610 } 729 else if ( noSurfaces == 1 ) { norm = sumnor 611 else if ( noSurfaces == 1 ) { norm = sumnorm; } 730 else { norm = sumnor 612 else { norm = sumnorm.unit(); } 731 613 732 return norm; 614 return norm; 733 } 615 } 734 616 735 ////////////////////////////////////////////// 617 ///////////////////////////////////////////////////////////////////////////// 736 // 618 // 737 // Algorithm for SurfaceNormal() following the 619 // Algorithm for SurfaceNormal() following the original specification 738 // for points not on the surface 620 // for points not on the surface 739 621 740 G4ThreeVector G4CutTubs::ApproxSurfaceNormal( 622 G4ThreeVector G4CutTubs::ApproxSurfaceNormal( const G4ThreeVector& p ) const 741 { 623 { 742 enum ENorm {kNRMin,kNRMax,kNSPhi,kNEPhi,kNZ} << 743 << 744 ENorm side ; 624 ENorm side ; 745 G4ThreeVector norm ; 625 G4ThreeVector norm ; 746 G4double rho, phi ; 626 G4double rho, phi ; 747 G4double distZLow,distZHigh,distZ; 627 G4double distZLow,distZHigh,distZ; 748 G4double distRMin, distRMax, distSPhi, distE 628 G4double distRMin, distRMax, distSPhi, distEPhi, distMin ; 749 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 629 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 750 630 751 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 631 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 752 632 753 distRMin = std::fabs(rho - fRMin) ; 633 distRMin = std::fabs(rho - fRMin) ; 754 distRMax = std::fabs(rho - fRMax) ; 634 distRMax = std::fabs(rho - fRMax) ; 755 635 756 //dist to Low Cut 636 //dist to Low Cut 757 // 637 // 758 distZLow =std::fabs((p+vZ).dot(fLowNorm)); 638 distZLow =std::fabs((p+vZ).dot(fLowNorm)); 759 639 760 //dist to High Cut 640 //dist to High Cut 761 // 641 // 762 distZHigh = std::fabs((p-vZ).dot(fHighNorm)) 642 distZHigh = std::fabs((p-vZ).dot(fHighNorm)); 763 distZ=std::min(distZLow,distZHigh); 643 distZ=std::min(distZLow,distZHigh); 764 644 765 if (distRMin < distRMax) // First minimum 645 if (distRMin < distRMax) // First minimum 766 { 646 { 767 if ( distZ < distRMin ) 647 if ( distZ < distRMin ) 768 { 648 { 769 distMin = distZ ; 649 distMin = distZ ; 770 side = kNZ ; 650 side = kNZ ; 771 } 651 } 772 else 652 else 773 { 653 { 774 distMin = distRMin ; 654 distMin = distRMin ; 775 side = kNRMin ; 655 side = kNRMin ; 776 } 656 } 777 } 657 } 778 else 658 else 779 { 659 { 780 if ( distZ < distRMax ) 660 if ( distZ < distRMax ) 781 { 661 { 782 distMin = distZ ; 662 distMin = distZ ; 783 side = kNZ ; 663 side = kNZ ; 784 } 664 } 785 else 665 else 786 { 666 { 787 distMin = distRMax ; 667 distMin = distRMax ; 788 side = kNRMax ; 668 side = kNRMax ; 789 } 669 } 790 } << 670 } 791 if (!fPhiFullCutTube && (rho != 0.0) ) // << 671 if (!fPhiFullCutTube && rho ) // Protected against (0,0,z) 792 { 672 { 793 phi = std::atan2(p.y(),p.x()) ; 673 phi = std::atan2(p.y(),p.x()) ; 794 674 795 if ( phi < 0 ) { phi += twopi; } 675 if ( phi < 0 ) { phi += twopi; } 796 676 797 if ( fSPhi < 0 ) 677 if ( fSPhi < 0 ) 798 { 678 { 799 distSPhi = std::fabs(phi - (fSPhi + twop 679 distSPhi = std::fabs(phi - (fSPhi + twopi))*rho ; 800 } 680 } 801 else 681 else 802 { 682 { 803 distSPhi = std::fabs(phi - fSPhi)*rho ; 683 distSPhi = std::fabs(phi - fSPhi)*rho ; 804 } 684 } 805 distEPhi = std::fabs(phi - fSPhi - fDPhi)* 685 distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ; 806 << 686 807 if (distSPhi < distEPhi) // Find new minim 687 if (distSPhi < distEPhi) // Find new minimum 808 { 688 { 809 if ( distSPhi < distMin ) 689 if ( distSPhi < distMin ) 810 { 690 { 811 side = kNSPhi ; 691 side = kNSPhi ; 812 } 692 } 813 } 693 } 814 else 694 else 815 { 695 { 816 if ( distEPhi < distMin ) 696 if ( distEPhi < distMin ) 817 { 697 { 818 side = kNEPhi ; 698 side = kNEPhi ; 819 } 699 } 820 } 700 } 821 } << 701 } 822 switch ( side ) 702 switch ( side ) 823 { 703 { 824 case kNRMin : // Inner radius 704 case kNRMin : // Inner radius 825 { << 705 { 826 norm = G4ThreeVector(-p.x()/rho, -p.y()/ 706 norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, 0) ; 827 break ; 707 break ; 828 } 708 } 829 case kNRMax : // Outer radius 709 case kNRMax : // Outer radius 830 { << 710 { 831 norm = G4ThreeVector(p.x()/rho, p.y()/rh 711 norm = G4ThreeVector(p.x()/rho, p.y()/rho, 0) ; 832 break ; 712 break ; 833 } 713 } 834 case kNZ : // + or - dz 714 case kNZ : // + or - dz 835 { << 715 { 836 if ( distZHigh > distZLow ) { norm = fH 716 if ( distZHigh > distZLow ) { norm = fHighNorm ; } 837 else { norm = fL 717 else { norm = fLowNorm; } 838 break ; 718 break ; 839 } 719 } 840 case kNSPhi: 720 case kNSPhi: 841 { 721 { 842 norm = G4ThreeVector(sinSPhi, -cosSPhi, << 722 norm = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0) ; 843 break ; 723 break ; 844 } 724 } 845 case kNEPhi: 725 case kNEPhi: 846 { 726 { 847 norm = G4ThreeVector(-sinEPhi, cosEPhi, << 727 norm = G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0) ; 848 break; 728 break; 849 } 729 } 850 default: // Should never reach this c 730 default: // Should never reach this case ... 851 { 731 { 852 DumpInfo(); 732 DumpInfo(); 853 G4Exception("G4CutTubs::ApproxSurfaceNor 733 G4Exception("G4CutTubs::ApproxSurfaceNormal()", 854 "GeomSolids1002", JustWarnin 734 "GeomSolids1002", JustWarning, 855 "Undefined side for valid su 735 "Undefined side for valid surface normal to solid."); 856 break ; 736 break ; 857 } << 737 } 858 } << 738 } 859 return norm; 739 return norm; 860 } 740 } 861 741 862 ////////////////////////////////////////////// 742 //////////////////////////////////////////////////////////////////// 863 // 743 // 864 // 744 // 865 // Calculate distance to shape from outside, a 745 // Calculate distance to shape from outside, along normalised vector 866 // - return kInfinity if no intersection, or i 746 // - return kInfinity if no intersection, or intersection distance <= tolerance 867 // 747 // 868 // - Compute the intersection with the z plane << 748 // - Compute the intersection with the z planes 869 // - if at valid r, phi, return 749 // - if at valid r, phi, return 870 // 750 // 871 // -> If point is outer outer radius, compute 751 // -> If point is outer outer radius, compute intersection with rmax 872 // - if at valid phi,z return 752 // - if at valid phi,z return 873 // 753 // 874 // -> Compute intersection with inner radius, 754 // -> Compute intersection with inner radius, taking largest +ve root 875 // - if valid (in z,phi), save intersct 755 // - if valid (in z,phi), save intersction 876 // 756 // 877 // -> If phi segmented, compute intersectio 757 // -> If phi segmented, compute intersections with phi half planes 878 // - return smallest of valid phi inter 758 // - return smallest of valid phi intersections and 879 // inner radius intersection 759 // inner radius intersection 880 // 760 // 881 // NOTE: 761 // NOTE: 882 // - 'if valid' implies tolerant checking of i 762 // - 'if valid' implies tolerant checking of intersection points 883 763 884 G4double G4CutTubs::DistanceToIn( const G4Thre 764 G4double G4CutTubs::DistanceToIn( const G4ThreeVector& p, 885 const G4Thre 765 const G4ThreeVector& v ) const 886 { 766 { 887 G4double snxt = kInfinity ; // snxt = d 767 G4double snxt = kInfinity ; // snxt = default return value 888 G4double tolORMin2, tolIRMax2 ; // 'generou 768 G4double tolORMin2, tolIRMax2 ; // 'generous' radii squared 889 G4double tolORMax2, tolIRMin2; 769 G4double tolORMax2, tolIRMin2; 890 const G4double dRmax = 100.*fRMax; 770 const G4double dRmax = 100.*fRMax; 891 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 771 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); >> 772 >> 773 static const G4double halfCarTolerance = 0.5*kCarTolerance; >> 774 static const G4double halfRadTolerance = 0.5*kRadTolerance; 892 775 893 // Intersection point variables 776 // Intersection point variables 894 // 777 // 895 G4double Dist, sd=0, xi, yi, zi, rho2, inum, << 778 G4double Dist, s=0, xi, yi, zi, rho2, inum, iden, cosPsi, Comp,calf ; 896 G4double t1, t2, t3, b, c, d ; // Quadra << 779 G4double t1, t2, t3, b, c, d ; // Quadratic solver variables 897 G4double distZLow,distZHigh; 780 G4double distZLow,distZHigh; 898 // Calculate tolerant rmin and rmax 781 // Calculate tolerant rmin and rmax 899 782 900 if (fRMin > kRadTolerance) 783 if (fRMin > kRadTolerance) 901 { 784 { 902 tolORMin2 = (fRMin - halfRadTolerance)*(fR 785 tolORMin2 = (fRMin - halfRadTolerance)*(fRMin - halfRadTolerance) ; 903 tolIRMin2 = (fRMin + halfRadTolerance)*(fR 786 tolIRMin2 = (fRMin + halfRadTolerance)*(fRMin + halfRadTolerance) ; 904 } 787 } 905 else 788 else 906 { 789 { 907 tolORMin2 = 0.0 ; 790 tolORMin2 = 0.0 ; 908 tolIRMin2 = 0.0 ; 791 tolIRMin2 = 0.0 ; 909 } 792 } 910 tolORMax2 = (fRMax + halfRadTolerance)*(fRMa 793 tolORMax2 = (fRMax + halfRadTolerance)*(fRMax + halfRadTolerance) ; 911 tolIRMax2 = (fRMax - halfRadTolerance)*(fRMa 794 tolIRMax2 = (fRMax - halfRadTolerance)*(fRMax - halfRadTolerance) ; 912 795 913 // Intersection with ZCut surfaces 796 // Intersection with ZCut surfaces 914 797 915 // dist to Low Cut 798 // dist to Low Cut 916 // 799 // 917 distZLow =(p+vZ).dot(fLowNorm); 800 distZLow =(p+vZ).dot(fLowNorm); 918 801 919 // dist to High Cut 802 // dist to High Cut 920 // 803 // 921 distZHigh = (p-vZ).dot(fHighNorm); 804 distZHigh = (p-vZ).dot(fHighNorm); 922 805 923 if ( distZLow >= -halfCarTolerance ) 806 if ( distZLow >= -halfCarTolerance ) 924 { 807 { 925 calf = v.dot(fLowNorm); 808 calf = v.dot(fLowNorm); 926 if (calf<0) 809 if (calf<0) 927 { 810 { 928 sd = -distZLow/calf; << 811 s = -distZLow/calf; 929 if(sd < 0.0) { sd = 0.0; } << 812 if(s < 0.0) { s = 0.0; } 930 813 931 xi = p.x() + sd*v.x() ; << 814 xi = p.x() + s*v.x() ; // Intersection coords 932 yi = p.y() + sd*v.y() ; << 815 yi = p.y() + s*v.y() ; 933 rho2 = xi*xi + yi*yi ; 816 rho2 = xi*xi + yi*yi ; 934 817 935 // Check validity of intersection 818 // Check validity of intersection 936 819 937 if ((tolIRMin2 <= rho2) && (rho2 <= tolI 820 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2)) 938 { 821 { 939 if (!fPhiFullCutTube && (rho2 != 0.0)) << 822 if (!fPhiFullCutTube && rho2) 940 { 823 { 941 // Psi = angle made with central (av 824 // Psi = angle made with central (average) phi of shape 942 // 825 // 943 inum = xi*cosCPhi + yi*sinCPhi ; 826 inum = xi*cosCPhi + yi*sinCPhi ; 944 iden = std::sqrt(rho2) ; 827 iden = std::sqrt(rho2) ; 945 cosPsi = inum/iden ; 828 cosPsi = inum/iden ; 946 if (cosPsi >= cosHDPhiIT) { return << 829 if (cosPsi >= cosHDPhiIT) { return s ; } 947 } 830 } 948 else 831 else 949 { 832 { 950 return sd ; << 833 return s ; 951 } 834 } 952 } 835 } 953 } 836 } 954 else 837 else 955 { 838 { 956 if ( sd<halfCarTolerance ) << 839 if ( s<halfCarTolerance ) 957 { 840 { 958 if(calf>=0) { sd=kInfinity; } << 841 if(calf>=0) { s=kInfinity; } 959 return sd ; // On/outside extent, and << 842 return s ; // On/outside extent, and heading away 960 } // -> cannot intersect << 843 } // -> cannot intersect 961 } 844 } 962 } 845 } 963 846 964 if(distZHigh >= -halfCarTolerance ) 847 if(distZHigh >= -halfCarTolerance ) 965 { 848 { 966 calf = v.dot(fHighNorm); 849 calf = v.dot(fHighNorm); 967 if (calf<0) 850 if (calf<0) 968 { 851 { 969 sd = -distZHigh/calf; << 852 s = -distZHigh/calf; 970 853 971 if(sd < 0.0) { sd = 0.0; } << 854 if(s < 0.0) { s = 0.0; } 972 855 973 xi = p.x() + sd*v.x() ; << 856 xi = p.x() + s*v.x() ; // Intersection coords 974 yi = p.y() + sd*v.y() ; << 857 yi = p.y() + s*v.y() ; 975 rho2 = xi*xi + yi*yi ; 858 rho2 = xi*xi + yi*yi ; 976 859 977 // Check validity of intersection 860 // Check validity of intersection 978 861 979 if ((tolIRMin2 <= rho2) && (rho2 <= tolI 862 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2)) 980 { 863 { 981 if (!fPhiFullCutTube && (rho2 != 0.0)) << 864 if (!fPhiFullCutTube && rho2) 982 { 865 { 983 // Psi = angle made with central (av 866 // Psi = angle made with central (average) phi of shape 984 // 867 // 985 inum = xi*cosCPhi + yi*sinCPhi ; 868 inum = xi*cosCPhi + yi*sinCPhi ; 986 iden = std::sqrt(rho2) ; 869 iden = std::sqrt(rho2) ; 987 cosPsi = inum/iden ; 870 cosPsi = inum/iden ; 988 if (cosPsi >= cosHDPhiIT) { return << 871 if (cosPsi >= cosHDPhiIT) { return s ; } 989 } 872 } 990 else 873 else 991 { 874 { 992 return sd ; << 875 return s ; 993 } 876 } 994 } 877 } 995 } 878 } 996 else 879 else 997 { 880 { 998 if ( sd<halfCarTolerance ) << 881 if ( s<halfCarTolerance ) 999 { << 882 { 1000 if(calf>=0) { sd=kInfinity; } << 883 if(calf>=0) { s=kInfinity; } 1001 return sd ; // On/outside extent, an << 884 return s ; // On/outside extent, and heading away 1002 } // -> cannot intersect << 885 } // -> cannot intersect 1003 } 886 } 1004 } 887 } 1005 888 1006 // -> Can not intersect z surfaces 889 // -> Can not intersect z surfaces 1007 // 890 // 1008 // Intersection with rmax (possible return) 891 // Intersection with rmax (possible return) and rmin (must also check phi) 1009 // 892 // 1010 // Intersection point (xi,yi,zi) on line x= 893 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. 1011 // 894 // 1012 // Intersects with x^2+y^2=R^2 895 // Intersects with x^2+y^2=R^2 1013 // 896 // 1014 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v 897 // 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 1015 // t1 t2 898 // t1 t2 t3 1016 899 1017 t1 = 1.0 - v.z()*v.z() ; 900 t1 = 1.0 - v.z()*v.z() ; 1018 t2 = p.x()*v.x() + p.y()*v.y() ; 901 t2 = p.x()*v.x() + p.y()*v.y() ; 1019 t3 = p.x()*p.x() + p.y()*p.y() ; 902 t3 = p.x()*p.x() + p.y()*p.y() ; 1020 if ( t1 > 0 ) // Check not || to z a 903 if ( t1 > 0 ) // Check not || to z axis 1021 { 904 { 1022 b = t2/t1 ; 905 b = t2/t1 ; 1023 c = t3 - fRMax*fRMax ; 906 c = t3 - fRMax*fRMax ; 1024 << 907 1025 if ((t3 >= tolORMax2) && (t2<0)) // Thi 908 if ((t3 >= tolORMax2) && (t2<0)) // This also handles the tangent case 1026 { 909 { 1027 // Try outer cylinder intersection, c=( 910 // Try outer cylinder intersection, c=(t3-fRMax*fRMax)/t1; 1028 911 1029 c /= t1 ; 912 c /= t1 ; 1030 d = b*b - c ; 913 d = b*b - c ; 1031 914 1032 if (d >= 0) // If real root 915 if (d >= 0) // If real root 1033 { 916 { 1034 sd = c/(-b+std::sqrt(d)); << 917 s = c/(-b+std::sqrt(d)); 1035 if (sd >= 0) // If 'forwards' << 918 if (s >= 0) // If 'forwards' 1036 { 919 { 1037 if ( sd>dRmax ) // Avoid rounding e << 920 if ( s>dRmax ) // Avoid rounding errors due to precision issues on 1038 { // 64 bits systems. << 921 { // 64 bits systems. Split long distances and recompute 1039 G4double fTerm = sd-std::fmod(sd, << 922 G4double fTerm = s-std::fmod(s,dRmax); 1040 sd = fTerm + DistanceToIn(p+fTerm << 923 s = fTerm + DistanceToIn(p+fTerm*v,v); 1041 } << 924 } 1042 // Check z intersection 925 // Check z intersection 1043 // 926 // 1044 zi = p.z() + sd*v.z() ; << 927 zi = p.z() + s*v.z() ; 1045 xi = p.x() + sd*v.x() ; << 928 xi = p.x() + s*v.x() ; 1046 yi = p.y() + sd*v.y() ; << 929 yi = p.y() + s*v.y() ; 1047 if ((-xi*fLowNorm.x()-yi*fLowNorm.y 930 if ((-xi*fLowNorm.x()-yi*fLowNorm.y() 1048 -(zi+fDz)*fLowNorm.z())>-halfC 931 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance) 1049 { 932 { 1050 if ((-xi*fHighNorm.x()-yi*fHighNo 933 if ((-xi*fHighNorm.x()-yi*fHighNorm.y() 1051 +(fDz-zi)*fHighNorm.z())>-ha 934 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance) 1052 { 935 { 1053 // Z ok. Check phi intersection 936 // Z ok. Check phi intersection if reqd 1054 // 937 // 1055 if (fPhiFullCutTube) 938 if (fPhiFullCutTube) 1056 { 939 { 1057 return sd ; << 940 return s ; 1058 } 941 } 1059 else 942 else 1060 { 943 { 1061 xi = p.x() + sd*v.x() ; << 944 xi = p.x() + s*v.x() ; 1062 yi = p.y() + sd*v.y() ; << 945 yi = p.y() + s*v.y() ; 1063 cosPsi = (xi*cosCPhi + yi*sin 946 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ; 1064 if (cosPsi >= cosHDPhiIT) { << 947 if (cosPsi >= cosHDPhiIT) { return s ; } 1065 } 948 } 1066 } // end if std::fabs(zi) 949 } // end if std::fabs(zi) 1067 } 950 } 1068 } // end if (sd>=0) << 951 } // end if (s>=0) 1069 } // end if (d>=0) 952 } // end if (d>=0) 1070 } // end if (r>=fRMax) 953 } // end if (r>=fRMax) 1071 else << 954 else 1072 { 955 { 1073 // Inside outer radius : 956 // Inside outer radius : 1074 // check not inside, and heading throug 957 // check not inside, and heading through tubs (-> 0 to in) 1075 if ((t3 > tolIRMin2) && (t2 < 0) 958 if ((t3 > tolIRMin2) && (t2 < 0) 1076 && (std::fabs(p.z()) <= std::fabs(GetC 959 && (std::fabs(p.z()) <= std::fabs(GetCutZ(p))-halfCarTolerance )) 1077 { 960 { 1078 // Inside both radii, delta r -ve, in 961 // Inside both radii, delta r -ve, inside z extent 1079 962 1080 if (!fPhiFullCutTube) 963 if (!fPhiFullCutTube) 1081 { 964 { 1082 inum = p.x()*cosCPhi + p.y()*sinC 965 inum = p.x()*cosCPhi + p.y()*sinCPhi ; 1083 iden = std::sqrt(t3) ; 966 iden = std::sqrt(t3) ; 1084 cosPsi = inum/iden ; 967 cosPsi = inum/iden ; 1085 if (cosPsi >= cosHDPhiIT) 968 if (cosPsi >= cosHDPhiIT) 1086 { 969 { 1087 // In the old version, the small 970 // In the old version, the small negative tangent for the point 1088 // on surface was not taken in ac 971 // on surface was not taken in account, and returning 0.0 ... 1089 // New version: check the tangent << 972 // New version: check the tangent for the point on surface and 1090 // if no intersection, return kIn 973 // if no intersection, return kInfinity, if intersection instead 1091 // return sd. << 974 // return s. 1092 // 975 // 1093 c = t3-fRMax*fRMax; << 976 c = t3-fRMax*fRMax; 1094 if ( c<=0.0 ) 977 if ( c<=0.0 ) 1095 { 978 { 1096 return 0.0; 979 return 0.0; 1097 } 980 } 1098 else 981 else 1099 { 982 { 1100 c = c/t1 ; 983 c = c/t1 ; 1101 d = b*b-c; 984 d = b*b-c; 1102 if ( d>=0.0 ) 985 if ( d>=0.0 ) 1103 { 986 { 1104 snxt = c/(-b+std::sqrt(d)); / 987 snxt = c/(-b+std::sqrt(d)); // using safe solution 1105 / << 988 // for quadratic equation 1106 if ( snxt < halfCarTolerance 989 if ( snxt < halfCarTolerance ) { snxt=0; } 1107 return snxt ; 990 return snxt ; 1108 } << 991 } 1109 else 992 else 1110 { 993 { 1111 return kInfinity; 994 return kInfinity; 1112 } 995 } 1113 } 996 } 1114 } << 997 } 1115 } 998 } 1116 else 999 else 1117 { << 1000 { 1118 // In the old version, the small ne 1001 // In the old version, the small negative tangent for the point 1119 // on surface was not taken in acco 1002 // on surface was not taken in account, and returning 0.0 ... 1120 // New version: check the tangent f << 1003 // New version: check the tangent for the point on surface and 1121 // if no intersection, return kInfi 1004 // if no intersection, return kInfinity, if intersection instead 1122 // return sd. << 1005 // return s. 1123 // 1006 // 1124 c = t3 - fRMax*fRMax; << 1007 c = t3 - fRMax*fRMax; 1125 if ( c<=0.0 ) 1008 if ( c<=0.0 ) 1126 { 1009 { 1127 return 0.0; 1010 return 0.0; 1128 } 1011 } 1129 else 1012 else 1130 { 1013 { 1131 c = c/t1 ; 1014 c = c/t1 ; 1132 d = b*b-c; 1015 d = b*b-c; 1133 if ( d>=0.0 ) 1016 if ( d>=0.0 ) 1134 { 1017 { 1135 snxt= c/(-b+std::sqrt(d)); // u 1018 snxt= c/(-b+std::sqrt(d)); // using safe solution 1136 // f << 1019 // for quadratic equation 1137 if ( snxt < halfCarTolerance ) 1020 if ( snxt < halfCarTolerance ) { snxt=0; } 1138 return snxt ; 1021 return snxt ; 1139 } << 1022 } 1140 else 1023 else 1141 { 1024 { 1142 return kInfinity; 1025 return kInfinity; 1143 } 1026 } 1144 } 1027 } 1145 } // end if (!fPhiFullCutTube) 1028 } // end if (!fPhiFullCutTube) 1146 } // end if (t3>tolIRMin2) 1029 } // end if (t3>tolIRMin2) 1147 } // end if (Inside Outer Radius) << 1030 } // end if (Inside Outer Radius) 1148 << 1031 1149 if ( fRMin != 0.0 ) // Try inner cylin << 1032 if ( fRMin ) // Try inner cylinder intersection 1150 { 1033 { 1151 c = (t3 - fRMin*fRMin)/t1 ; 1034 c = (t3 - fRMin*fRMin)/t1 ; 1152 d = b*b - c ; 1035 d = b*b - c ; 1153 if ( d >= 0.0 ) // If real root 1036 if ( d >= 0.0 ) // If real root 1154 { 1037 { 1155 // Always want 2nd root - we are outs 1038 // Always want 2nd root - we are outside and know rmax Hit was bad 1156 // - If on surface of rmin also need 1039 // - If on surface of rmin also need farthest root 1157 << 1040 1158 sd =( b > 0. )? c/(-b - std::sqrt(d)) << 1041 s =( b > 0. )? c/(-b - std::sqrt(d)) : (-b + std::sqrt(d)); 1159 if (sd >= -10*halfCarTolerance) // c << 1042 if (s >= -10*halfCarTolerance) // check forwards 1160 { 1043 { 1161 // Check z intersection 1044 // Check z intersection 1162 // 1045 // 1163 if (sd < 0.0) { sd = 0.0; } << 1046 if(s < 0.0) { s = 0.0; } 1164 if (sd>dRmax) // Avoid rounding err << 1047 if ( s>dRmax ) // Avoid rounding errors due to precision issues seen 1165 { // 64 bits systems. S << 1048 { // 64 bits systems. Split long distances and recompute 1166 G4double fTerm = sd-std::fmod(sd, << 1049 G4double fTerm = s-std::fmod(s,dRmax); 1167 sd = fTerm + DistanceToIn(p+fTerm << 1050 s = fTerm + DistanceToIn(p+fTerm*v,v); 1168 } << 1051 } 1169 zi = p.z() + sd*v.z() ; << 1052 zi = p.z() + s*v.z() ; 1170 xi = p.x() + sd*v.x() ; << 1053 xi = p.x() + s*v.x() ; 1171 yi = p.y() + sd*v.y() ; << 1054 yi = p.y() + s*v.y() ; 1172 if ((-xi*fLowNorm.x()-yi*fLowNorm.y 1055 if ((-xi*fLowNorm.x()-yi*fLowNorm.y() 1173 -(zi+fDz)*fLowNorm.z())>-halfC 1056 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance) 1174 { 1057 { 1175 if ((-xi*fHighNorm.x()-yi*fHighNo 1058 if ((-xi*fHighNorm.x()-yi*fHighNorm.y() 1176 +(fDz-zi)*fHighNorm.z())>-ha 1059 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance) 1177 { 1060 { 1178 // Z ok. Check phi 1061 // Z ok. Check phi 1179 // 1062 // 1180 if ( fPhiFullCutTube ) 1063 if ( fPhiFullCutTube ) 1181 { 1064 { 1182 return sd ; << 1065 return s ; 1183 } 1066 } 1184 else 1067 else 1185 { 1068 { 1186 cosPsi = (xi*cosCPhi + yi*sin 1069 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMin ; 1187 if (cosPsi >= cosHDPhiIT) 1070 if (cosPsi >= cosHDPhiIT) 1188 { 1071 { 1189 // Good inner radius isect 1072 // Good inner radius isect 1190 // - but earlier phi isect 1073 // - but earlier phi isect still possible 1191 // 1074 // 1192 snxt = sd ; << 1075 snxt = s ; 1193 } 1076 } 1194 } 1077 } 1195 } // end if std::fabs(zi) 1078 } // end if std::fabs(zi) 1196 } 1079 } 1197 } // end if (sd>=0) << 1080 } // end if (s>=0) 1198 } // end if (d>=0) 1081 } // end if (d>=0) 1199 } // end if (fRMin) 1082 } // end if (fRMin) 1200 } 1083 } 1201 1084 1202 // Phi segment intersection 1085 // Phi segment intersection 1203 // 1086 // 1204 // o Tolerant of points inside phi planes b 1087 // o Tolerant of points inside phi planes by up to kCarTolerance*0.5 1205 // 1088 // 1206 // o NOTE: Large duplication of code betwee 1089 // o NOTE: Large duplication of code between sphi & ephi checks 1207 // -> only diffs: sphi -> ephi, Com 1090 // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane 1208 // intersection check <=0 -> >=0 1091 // intersection check <=0 -> >=0 1209 // -> use some form of loop Constru 1092 // -> use some form of loop Construct ? 1210 // 1093 // 1211 if ( !fPhiFullCutTube ) 1094 if ( !fPhiFullCutTube ) 1212 { 1095 { 1213 // First phi surface (Starting phi) 1096 // First phi surface (Starting phi) 1214 // 1097 // 1215 Comp = v.x()*sinSPhi - v.y()*cosSPhi ; 1098 Comp = v.x()*sinSPhi - v.y()*cosSPhi ; 1216 << 1099 1217 if ( Comp < 0 ) // Component in outwards 1100 if ( Comp < 0 ) // Component in outwards normal dirn 1218 { 1101 { 1219 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) 1102 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ; 1220 1103 1221 if ( Dist < halfCarTolerance ) 1104 if ( Dist < halfCarTolerance ) 1222 { 1105 { 1223 sd = Dist/Comp ; << 1106 s = Dist/Comp ; 1224 1107 1225 if (sd < snxt) << 1108 if (s < snxt) 1226 { 1109 { 1227 if ( sd < 0 ) { sd = 0.0; } << 1110 if ( s < 0 ) { s = 0.0; } 1228 zi = p.z() + sd*v.z() ; << 1111 zi = p.z() + s*v.z() ; 1229 xi = p.x() + sd*v.x() ; << 1112 xi = p.x() + s*v.x() ; 1230 yi = p.y() + sd*v.y() ; << 1113 yi = p.y() + s*v.y() ; 1231 if ((-xi*fLowNorm.x()-yi*fLowNorm.y 1114 if ((-xi*fLowNorm.x()-yi*fLowNorm.y() 1232 -(zi+fDz)*fLowNorm.z())>-halfC 1115 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance) 1233 { 1116 { 1234 if ((-xi*fHighNorm.x()-yi*fHighNo 1117 if ((-xi*fHighNorm.x()-yi*fHighNorm.y() 1235 +(fDz-zi)*fHighNorm.z())>-ha << 1118 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance) 1236 { 1119 { 1237 rho2 = xi*xi + yi*yi ; 1120 rho2 = xi*xi + yi*yi ; 1238 if ( ( (rho2 >= tolIRMin2) && ( 1121 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) ) 1239 || ( (rho2 > tolORMin2) && ( 1122 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2) 1240 && ( v.y()*cosSPhi - v.x()* 1123 && ( v.y()*cosSPhi - v.x()*sinSPhi > 0 ) 1241 && ( v.x()*cosSPhi + v.y()* 1124 && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 ) ) 1242 || ( (rho2 > tolIRMax2) && (r 1125 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2) 1243 && (v.y()*cosSPhi - v.x()*s 1126 && (v.y()*cosSPhi - v.x()*sinSPhi > 0) 1244 && (v.x()*cosSPhi + v.y()*s 1127 && (v.x()*cosSPhi + v.y()*sinSPhi < 0) ) ) 1245 { 1128 { 1246 // z and r intersections good 1129 // z and r intersections good 1247 // - check intersecting with 1130 // - check intersecting with correct half-plane 1248 // 1131 // 1249 if ((yi*cosCPhi-xi*sinCPhi) < << 1132 if ((yi*cosCPhi-xi*sinCPhi) <= halfCarTolerance) { snxt = s; } 1250 } 1133 } 1251 } //two Z conditions 1134 } //two Z conditions 1252 } 1135 } 1253 } 1136 } 1254 } << 1137 } 1255 } 1138 } 1256 << 1139 1257 // Second phi surface (Ending phi) 1140 // Second phi surface (Ending phi) 1258 // 1141 // 1259 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ; 1142 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ; 1260 << 1143 1261 if (Comp < 0 ) // Component in outwards 1144 if (Comp < 0 ) // Component in outwards normal dirn 1262 { 1145 { 1263 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) 1146 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ; 1264 1147 1265 if ( Dist < halfCarTolerance ) 1148 if ( Dist < halfCarTolerance ) 1266 { 1149 { 1267 sd = Dist/Comp ; << 1150 s = Dist/Comp ; 1268 1151 1269 if (sd < snxt) << 1152 if (s < snxt) 1270 { 1153 { 1271 if ( sd < 0 ) { sd = 0; } << 1154 if ( s < 0 ) { s = 0; } 1272 zi = p.z() + sd*v.z() ; << 1155 zi = p.z() + s*v.z() ; 1273 xi = p.x() + sd*v.x() ; << 1156 xi = p.x() + s*v.x() ; 1274 yi = p.y() + sd*v.y() ; << 1157 yi = p.y() + s*v.y() ; 1275 if ((-xi*fLowNorm.x()-yi*fLowNorm.y 1158 if ((-xi*fLowNorm.x()-yi*fLowNorm.y() 1276 -(zi+fDz)*fLowNorm.z())>-halfC 1159 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance) 1277 { 1160 { 1278 if ((-xi*fHighNorm.x()-yi*fHighNo 1161 if ((-xi*fHighNorm.x()-yi*fHighNorm.y() 1279 +(fDz-zi)*fHighNorm.z())>-ha 1162 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance) 1280 { 1163 { 1281 xi = p.x() + sd*v.x() ; << 1164 xi = p.x() + s*v.x() ; 1282 yi = p.y() + sd*v.y() ; << 1165 yi = p.y() + s*v.y() ; 1283 rho2 = xi*xi + yi*yi ; 1166 rho2 = xi*xi + yi*yi ; 1284 if ( ( (rho2 >= tolIRMin2) && ( 1167 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) ) 1285 || ( (rho2 > tolORMin2) && 1168 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2) 1286 && (v.x()*sinEPhi - v.y() 1169 && (v.x()*sinEPhi - v.y()*cosEPhi > 0) 1287 && (v.x()*cosEPhi + v.y() 1170 && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) ) 1288 || ( (rho2 > tolIRMax2) && 1171 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2) 1289 && (v.x()*sinEPhi - v.y() 1172 && (v.x()*sinEPhi - v.y()*cosEPhi > 0) 1290 && (v.x()*cosEPhi + v.y() 1173 && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) ) 1291 { 1174 { 1292 // z and r intersections good 1175 // z and r intersections good 1293 // - check intersecting with 1176 // - check intersecting with correct half-plane 1294 // 1177 // 1295 if ( (yi*cosCPhi-xi*sinCPhi) 1178 if ( (yi*cosCPhi-xi*sinCPhi) >= -halfCarTolerance ) 1296 { 1179 { 1297 snxt = sd; << 1180 snxt = s; 1298 } 1181 } 1299 } //?? >=-halfCarTolerance 1182 } //?? >=-halfCarTolerance 1300 } 1183 } 1301 } // two Z conditions 1184 } // two Z conditions 1302 } 1185 } 1303 } 1186 } 1304 } // Comp < 0 1187 } // Comp < 0 1305 } // !fPhiFullTube << 1188 } // !fPhiFullTube 1306 if ( snxt<halfCarTolerance ) { snxt=0; } 1189 if ( snxt<halfCarTolerance ) { snxt=0; } 1307 1190 1308 return snxt ; 1191 return snxt ; 1309 } 1192 } 1310 << 1193 1311 ///////////////////////////////////////////// 1194 ////////////////////////////////////////////////////////////////// 1312 // 1195 // 1313 // Calculate distance to shape from outside, 1196 // Calculate distance to shape from outside, along normalised vector 1314 // - return kInfinity if no intersection, or 1197 // - return kInfinity if no intersection, or intersection distance <= tolerance 1315 // 1198 // 1316 // - Compute the intersection with the z plan << 1199 // - Compute the intersection with the z planes 1317 // - if at valid r, phi, return 1200 // - if at valid r, phi, return 1318 // 1201 // 1319 // -> If point is outer outer radius, compute 1202 // -> If point is outer outer radius, compute intersection with rmax 1320 // - if at valid phi,z return 1203 // - if at valid phi,z return 1321 // 1204 // 1322 // -> Compute intersection with inner radius, 1205 // -> Compute intersection with inner radius, taking largest +ve root 1323 // - if valid (in z,phi), save intersc 1206 // - if valid (in z,phi), save intersction 1324 // 1207 // 1325 // -> If phi segmented, compute intersecti 1208 // -> If phi segmented, compute intersections with phi half planes 1326 // - return smallest of valid phi inte 1209 // - return smallest of valid phi intersections and 1327 // inner radius intersection 1210 // inner radius intersection 1328 // 1211 // 1329 // NOTE: 1212 // NOTE: 1330 // - Precalculations for phi trigonometry are 1213 // - Precalculations for phi trigonometry are Done `just in time' 1331 // - `if valid' implies tolerant checking of 1214 // - `if valid' implies tolerant checking of intersection points 1332 // Calculate distance (<= actual) to closes 1215 // Calculate distance (<= actual) to closest surface of shape from outside 1333 // - Calculate distance to z, radial planes 1216 // - Calculate distance to z, radial planes 1334 // - Only to phi planes if outside phi extent 1217 // - Only to phi planes if outside phi extent 1335 // - Return 0 if point inside 1218 // - Return 0 if point inside 1336 1219 1337 G4double G4CutTubs::DistanceToIn( const G4Thr 1220 G4double G4CutTubs::DistanceToIn( const G4ThreeVector& p ) const 1338 { 1221 { 1339 G4double safRMin,safRMax,safZLow,safZHigh,s 1222 G4double safRMin,safRMax,safZLow,safZHigh,safePhi,safe,rho,cosPsi; 1340 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 1223 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 1341 1224 1342 // Distance to R 1225 // Distance to R 1343 // 1226 // 1344 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) 1227 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; 1345 1228 1346 safRMin = fRMin- rho ; 1229 safRMin = fRMin- rho ; 1347 safRMax = rho - fRMax ; 1230 safRMax = rho - fRMax ; 1348 1231 1349 // Distances to ZCut(Low/High) 1232 // Distances to ZCut(Low/High) 1350 1233 1351 // Dist to Low Cut 1234 // Dist to Low Cut 1352 // 1235 // 1353 safZLow = (p+vZ).dot(fLowNorm); 1236 safZLow = (p+vZ).dot(fLowNorm); 1354 1237 1355 // Dist to High Cut 1238 // Dist to High Cut 1356 // 1239 // 1357 safZHigh = (p-vZ).dot(fHighNorm); 1240 safZHigh = (p-vZ).dot(fHighNorm); 1358 1241 1359 safe = std::max(safZLow,safZHigh); 1242 safe = std::max(safZLow,safZHigh); 1360 1243 1361 if ( safRMin > safe ) { safe = safRMin; } 1244 if ( safRMin > safe ) { safe = safRMin; } 1362 if ( safRMax> safe ) { safe = safRMax; } 1245 if ( safRMax> safe ) { safe = safRMax; } 1363 1246 1364 // Distance to Phi 1247 // Distance to Phi 1365 // 1248 // 1366 if ( (!fPhiFullCutTube) && ((rho) != 0.0) ) << 1249 if ( (!fPhiFullCutTube) && (rho) ) 1367 { 1250 { 1368 // Psi=angle from central phi to point 1251 // Psi=angle from central phi to point 1369 // 1252 // 1370 cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi) 1253 cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ; 1371 << 1254 1372 if ( cosPsi < cosHDPhi ) << 1255 if ( cosPsi < std::cos(fDPhi*0.5) ) 1373 { 1256 { 1374 // Point lies outside phi range 1257 // Point lies outside phi range 1375 << 1258 1376 if ( (p.y()*cosCPhi - p.x()*sinCPhi) < 1259 if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 ) 1377 { 1260 { 1378 safePhi = std::fabs(p.x()*sinSPhi - 1261 safePhi = std::fabs(p.x()*sinSPhi - p.y()*cosSPhi) ; 1379 } 1262 } 1380 else 1263 else 1381 { 1264 { 1382 safePhi = std::fabs(p.x()*sinEPhi - 1265 safePhi = std::fabs(p.x()*sinEPhi - p.y()*cosEPhi) ; 1383 } 1266 } 1384 if ( safePhi > safe ) { safe = safePh 1267 if ( safePhi > safe ) { safe = safePhi; } 1385 } 1268 } 1386 } 1269 } 1387 if ( safe < 0 ) { safe = 0; } 1270 if ( safe < 0 ) { safe = 0; } 1388 1271 1389 return safe ; 1272 return safe ; 1390 } 1273 } 1391 1274 1392 ///////////////////////////////////////////// 1275 ////////////////////////////////////////////////////////////////////////////// 1393 // 1276 // 1394 // Calculate distance to surface of shape fro 1277 // Calculate distance to surface of shape from `inside', allowing for tolerance 1395 // - Only Calc rmax intersection if no valid 1278 // - Only Calc rmax intersection if no valid rmin intersection 1396 1279 1397 G4double G4CutTubs::DistanceToOut( const G4Th 1280 G4double G4CutTubs::DistanceToOut( const G4ThreeVector& p, 1398 const G4Th 1281 const G4ThreeVector& v, 1399 const G4bo 1282 const G4bool calcNorm, 1400 G4bo << 1283 G4bool *validNorm, 1401 G4Th << 1284 G4ThreeVector *n ) const 1402 { << 1285 { 1403 enum ESide {kNull,kRMin,kRMax,kSPhi,kEPhi,k << 1404 << 1405 ESide side=kNull , sider=kNull, sidephi=kNu 1286 ESide side=kNull , sider=kNull, sidephi=kNull ; 1406 G4double snxt=kInfinity, srd=kInfinity,sz=k << 1287 G4double snxt=kInfinity, sr=kInfinity,sz=kInfinity, sphi=kInfinity ; 1407 G4double deltaR, t1, t2, t3, b, c, d2, roMi 1288 G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ; 1408 G4double distZLow,distZHigh,calfH,calfL; 1289 G4double distZLow,distZHigh,calfH,calfL; 1409 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 1290 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 1410 << 1291 static const G4double halfCarTolerance = kCarTolerance*0.5; >> 1292 static const G4double halfAngTolerance = kAngTolerance*0.5; >> 1293 1411 // Vars for phi intersection: 1294 // Vars for phi intersection: 1412 // 1295 // 1413 G4double pDistS, compS, pDistE, compE, sphi 1296 G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ; 1414 << 1297 1415 // Z plane intersection 1298 // Z plane intersection 1416 // Distances to ZCut(Low/High) 1299 // Distances to ZCut(Low/High) 1417 1300 1418 // dist to Low Cut 1301 // dist to Low Cut 1419 // 1302 // 1420 distZLow =(p+vZ).dot(fLowNorm); 1303 distZLow =(p+vZ).dot(fLowNorm); 1421 1304 1422 // dist to High Cut 1305 // dist to High Cut 1423 // 1306 // 1424 distZHigh = (p-vZ).dot(fHighNorm); 1307 distZHigh = (p-vZ).dot(fHighNorm); 1425 1308 1426 calfH = v.dot(fHighNorm); 1309 calfH = v.dot(fHighNorm); 1427 calfL = v.dot(fLowNorm); 1310 calfL = v.dot(fLowNorm); 1428 1311 1429 if (calfH > 0 ) 1312 if (calfH > 0 ) 1430 { 1313 { 1431 if ( distZHigh < halfCarTolerance ) 1314 if ( distZHigh < halfCarTolerance ) 1432 { 1315 { 1433 snxt = -distZHigh/calfH ; 1316 snxt = -distZHigh/calfH ; 1434 side = kPZ ; 1317 side = kPZ ; 1435 } 1318 } 1436 else 1319 else 1437 { 1320 { 1438 if (calcNorm) 1321 if (calcNorm) 1439 { 1322 { 1440 *n = G4ThreeVector(0,0,1) ; 1323 *n = G4ThreeVector(0,0,1) ; 1441 *validNorm = true ; 1324 *validNorm = true ; 1442 } 1325 } 1443 return snxt = 0 ; 1326 return snxt = 0 ; 1444 } 1327 } 1445 } 1328 } 1446 if ( calfL>0) 1329 if ( calfL>0) 1447 { 1330 { 1448 << 1331 1449 if ( distZLow < halfCarTolerance ) 1332 if ( distZLow < halfCarTolerance ) 1450 { 1333 { 1451 sz = -distZLow/calfL ; 1334 sz = -distZLow/calfL ; 1452 if(sz<snxt){ 1335 if(sz<snxt){ 1453 snxt=sz; 1336 snxt=sz; 1454 side = kMZ ; 1337 side = kMZ ; 1455 } 1338 } 1456 << 1339 1457 } 1340 } 1458 else 1341 else 1459 { 1342 { 1460 if (calcNorm) 1343 if (calcNorm) 1461 { 1344 { 1462 *n = G4ThreeVector(0,0,-1) ; 1345 *n = G4ThreeVector(0,0,-1) ; 1463 *validNorm = true ; 1346 *validNorm = true ; 1464 } 1347 } 1465 return snxt = 0.0 ; 1348 return snxt = 0.0 ; 1466 } 1349 } 1467 } 1350 } 1468 if((calfH<=0)&&(calfL<=0)) 1351 if((calfH<=0)&&(calfL<=0)) 1469 { 1352 { 1470 snxt = kInfinity ; // Travel perpendic 1353 snxt = kInfinity ; // Travel perpendicular to z axis 1471 side = kNull; 1354 side = kNull; 1472 } 1355 } 1473 // Radial Intersections 1356 // Radial Intersections 1474 // 1357 // 1475 // Find intersection with cylinders at rmax 1358 // Find intersection with cylinders at rmax/rmin 1476 // Intersection point (xi,yi,zi) on line x= 1359 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc. 1477 // 1360 // 1478 // Intersects with x^2+y^2=R^2 1361 // Intersects with x^2+y^2=R^2 1479 // 1362 // 1480 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v 1363 // 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 1481 // 1364 // 1482 // t1 t2 1365 // t1 t2 t3 1483 1366 1484 t1 = 1.0 - v.z()*v.z() ; // since v 1367 t1 = 1.0 - v.z()*v.z() ; // since v normalised 1485 t2 = p.x()*v.x() + p.y()*v.y() ; 1368 t2 = p.x()*v.x() + p.y()*v.y() ; 1486 t3 = p.x()*p.x() + p.y()*p.y() ; 1369 t3 = p.x()*p.x() + p.y()*p.y() ; 1487 1370 1488 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fR 1371 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fRMax*fRMax; } 1489 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t 1372 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; } // radius^2 on +-fDz 1490 1373 1491 if ( t1 > 0 ) // Check not parallel 1374 if ( t1 > 0 ) // Check not parallel 1492 { 1375 { 1493 // Calculate srd, r exit distance << 1376 // Calculate sr, r exit distance 1494 << 1377 1495 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax 1378 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) ) 1496 { 1379 { 1497 // Delta r not negative => leaving via 1380 // Delta r not negative => leaving via rmax 1498 1381 1499 deltaR = t3 - fRMax*fRMax ; 1382 deltaR = t3 - fRMax*fRMax ; 1500 1383 1501 // NOTE: Should use rho-fRMax<-kRadTole 1384 // NOTE: Should use rho-fRMax<-kRadTolerance*0.5 1502 // - avoid sqrt for efficiency 1385 // - avoid sqrt for efficiency 1503 1386 1504 if ( deltaR < -kRadTolerance*fRMax ) 1387 if ( deltaR < -kRadTolerance*fRMax ) 1505 { 1388 { 1506 b = t2/t1 ; 1389 b = t2/t1 ; 1507 c = deltaR/t1 ; 1390 c = deltaR/t1 ; 1508 d2 = b*b-c; 1391 d2 = b*b-c; 1509 if( d2 >= 0 ) { srd = c/( -b - std::s << 1392 if( d2 >= 0 ) { sr = c/( -b - std::sqrt(d2)); } 1510 else { srd = 0.; } << 1393 else { sr = 0.; } 1511 sider = kRMax ; 1394 sider = kRMax ; 1512 } 1395 } 1513 else 1396 else 1514 { 1397 { 1515 // On tolerant boundary & heading out 1398 // On tolerant boundary & heading outwards (or perpendicular to) 1516 // outer radial surface -> leaving im 1399 // outer radial surface -> leaving immediately 1517 1400 1518 if ( calcNorm ) << 1401 if ( calcNorm ) 1519 { 1402 { 1520 *n = G4ThreeVector(p.x()/fR 1403 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ; 1521 *validNorm = true ; 1404 *validNorm = true ; 1522 } 1405 } 1523 return snxt = 0 ; // Leaving by rmax 1406 return snxt = 0 ; // Leaving by rmax immediately 1524 } 1407 } 1525 } << 1408 } 1526 else if ( t2 < 0. ) // i.e. t2 < 0; Poss 1409 else if ( t2 < 0. ) // i.e. t2 < 0; Possible rmin intersection 1527 { 1410 { 1528 roMin2 = t3 - t2*t2/t1 ; // min ro2 of << 1411 roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement 1529 1412 1530 if ( (fRMin != 0.0) && (roMin2 < fRMin* << 1413 if ( fRMin && (roMin2 < fRMin*(fRMin - kRadTolerance)) ) 1531 { 1414 { 1532 deltaR = t3 - fRMin*fRMin ; 1415 deltaR = t3 - fRMin*fRMin ; 1533 b = t2/t1 ; 1416 b = t2/t1 ; 1534 c = deltaR/t1 ; 1417 c = deltaR/t1 ; 1535 d2 = b*b - c ; 1418 d2 = b*b - c ; 1536 1419 1537 if ( d2 >= 0 ) // Leaving via rmin 1420 if ( d2 >= 0 ) // Leaving via rmin 1538 { 1421 { 1539 // NOTE: SHould use rho-rmin>kRadTo 1422 // NOTE: SHould use rho-rmin>kRadTolerance*0.5 1540 // - avoid sqrt for efficiency 1423 // - avoid sqrt for efficiency 1541 1424 1542 if (deltaR > kRadTolerance*fRMin) 1425 if (deltaR > kRadTolerance*fRMin) 1543 { 1426 { 1544 srd = c/(-b+std::sqrt(d2)); << 1427 sr = c/(-b+std::sqrt(d2)); 1545 sider = kRMin ; 1428 sider = kRMin ; 1546 } 1429 } 1547 else 1430 else 1548 { 1431 { 1549 if ( calcNorm ) { *validNorm = fa 1432 if ( calcNorm ) { *validNorm = false; } // Concave side 1550 return snxt = 0.0; 1433 return snxt = 0.0; 1551 } 1434 } 1552 } 1435 } 1553 else // No rmin intersect -> must 1436 else // No rmin intersect -> must be rmax intersect 1554 { 1437 { 1555 deltaR = t3 - fRMax*fRMax ; 1438 deltaR = t3 - fRMax*fRMax ; 1556 c = deltaR/t1 ; 1439 c = deltaR/t1 ; 1557 d2 = b*b-c; 1440 d2 = b*b-c; 1558 if( d2 >=0. ) 1441 if( d2 >=0. ) 1559 { 1442 { 1560 srd = -b + std::sqrt(d2) ; << 1443 sr = -b + std::sqrt(d2) ; 1561 sider = kRMax ; 1444 sider = kRMax ; 1562 } 1445 } 1563 else // Case: On the border+t2<kRad 1446 else // Case: On the border+t2<kRadTolerance 1564 // (v is perpendicular t 1447 // (v is perpendicular to the surface) 1565 { 1448 { 1566 if (calcNorm) 1449 if (calcNorm) 1567 { 1450 { 1568 *n = G4ThreeVector(p.x()/fRMax, 1451 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ; 1569 *validNorm = true ; 1452 *validNorm = true ; 1570 } 1453 } 1571 return snxt = 0.0; 1454 return snxt = 0.0; 1572 } 1455 } 1573 } 1456 } 1574 } 1457 } 1575 else if ( roi2 > fRMax*(fRMax + kRadTol 1458 else if ( roi2 > fRMax*(fRMax + kRadTolerance) ) 1576 // No rmin intersect -> must be rm 1459 // No rmin intersect -> must be rmax intersect 1577 { 1460 { 1578 deltaR = t3 - fRMax*fRMax ; 1461 deltaR = t3 - fRMax*fRMax ; 1579 b = t2/t1 ; 1462 b = t2/t1 ; 1580 c = deltaR/t1; 1463 c = deltaR/t1; 1581 d2 = b*b-c; 1464 d2 = b*b-c; 1582 if( d2 >= 0 ) 1465 if( d2 >= 0 ) 1583 { 1466 { 1584 srd = -b + std::sqrt(d2) ; << 1467 sr = -b + std::sqrt(d2) ; 1585 sider = kRMax ; 1468 sider = kRMax ; 1586 } 1469 } 1587 else // Case: On the border+t2<kRadTo 1470 else // Case: On the border+t2<kRadTolerance 1588 // (v is perpendicular to 1471 // (v is perpendicular to the surface) 1589 { 1472 { 1590 if (calcNorm) 1473 if (calcNorm) 1591 { 1474 { 1592 *n = G4ThreeVector(p.x()/fRMax,p. 1475 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ; 1593 *validNorm = true ; 1476 *validNorm = true ; 1594 } 1477 } 1595 return snxt = 0.0; 1478 return snxt = 0.0; 1596 } 1479 } 1597 } 1480 } 1598 } 1481 } 1599 // Phi Intersection 1482 // Phi Intersection 1600 1483 1601 if ( !fPhiFullCutTube ) 1484 if ( !fPhiFullCutTube ) 1602 { 1485 { 1603 // add angle calculation with correctio << 1486 // add angle calculation with correction 1604 // of the difference in domain of atan2 1487 // of the difference in domain of atan2 and Sphi 1605 // 1488 // 1606 vphi = std::atan2(v.y(),v.x()) ; 1489 vphi = std::atan2(v.y(),v.x()) ; 1607 << 1490 1608 if ( vphi < fSPhi - halfAngTolerance ) 1491 if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; } 1609 else if ( vphi > fSPhi + fDPhi + halfAn 1492 else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; } 1610 1493 1611 1494 1612 if ( (p.x() != 0.0) || (p.y() != 0.0) ) << 1495 if ( p.x() || p.y() ) // Check if on z axis (rho not needed later) 1613 { 1496 { 1614 // pDist -ve when inside 1497 // pDist -ve when inside 1615 1498 1616 pDistS = p.x()*sinSPhi - p.y()*cosSPh 1499 pDistS = p.x()*sinSPhi - p.y()*cosSPhi ; 1617 pDistE = -p.x()*sinEPhi + p.y()*cosEP 1500 pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ; 1618 1501 1619 // Comp -ve when in direction of outw 1502 // Comp -ve when in direction of outwards normal 1620 1503 1621 compS = -sinSPhi*v.x() + cosSPhi*v. 1504 compS = -sinSPhi*v.x() + cosSPhi*v.y() ; 1622 compE = sinEPhi*v.x() - cosEPhi*v. 1505 compE = sinEPhi*v.x() - cosEPhi*v.y() ; 1623 << 1506 1624 sidephi = kNull; 1507 sidephi = kNull; 1625 << 1508 1626 if( ( (fDPhi <= pi) && ( (pDistS <= h 1509 if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance) 1627 && (pDistE <= h 1510 && (pDistE <= halfCarTolerance) ) ) 1628 || ( (fDPhi > pi) && ((pDistS <= h << 1511 || ( (fDPhi > pi) && !((pDistS > halfCarTolerance) 1629 || (pDistE <= << 1512 && (pDistE > halfCarTolerance) ) ) ) 1630 { 1513 { 1631 // Inside both phi *full* planes 1514 // Inside both phi *full* planes 1632 << 1515 1633 if ( compS < 0 ) 1516 if ( compS < 0 ) 1634 { 1517 { 1635 sphi = pDistS/compS ; 1518 sphi = pDistS/compS ; 1636 << 1519 1637 if (sphi >= -halfCarTolerance) 1520 if (sphi >= -halfCarTolerance) 1638 { 1521 { 1639 xi = p.x() + sphi*v.x() ; 1522 xi = p.x() + sphi*v.x() ; 1640 yi = p.y() + sphi*v.y() ; 1523 yi = p.y() + sphi*v.y() ; 1641 << 1524 1642 // Check intersecting with corr 1525 // Check intersecting with correct half-plane 1643 // (if not -> no intersect) 1526 // (if not -> no intersect) 1644 // 1527 // 1645 if( (std::fabs(xi)<=kCarToleran 1528 if( (std::fabs(xi)<=kCarTolerance) 1646 && (std::fabs(yi)<=kCarToleran 1529 && (std::fabs(yi)<=kCarTolerance) ) 1647 { 1530 { 1648 sidephi = kSPhi; 1531 sidephi = kSPhi; 1649 if (((fSPhi-halfAngTolerance) 1532 if (((fSPhi-halfAngTolerance)<=vphi) 1650 &&((fSPhi+fDPhi+halfAngTol 1533 &&((fSPhi+fDPhi+halfAngTolerance)>=vphi)) 1651 { 1534 { 1652 sphi = kInfinity; 1535 sphi = kInfinity; 1653 } 1536 } 1654 } 1537 } 1655 else if ( yi*cosCPhi-xi*sinCPhi 1538 else if ( yi*cosCPhi-xi*sinCPhi >=0 ) 1656 { 1539 { 1657 sphi = kInfinity ; 1540 sphi = kInfinity ; 1658 } 1541 } 1659 else 1542 else 1660 { 1543 { 1661 sidephi = kSPhi ; 1544 sidephi = kSPhi ; 1662 if ( pDistS > -halfCarToleran 1545 if ( pDistS > -halfCarTolerance ) 1663 { 1546 { 1664 sphi = 0.0 ; // Leave by sp 1547 sphi = 0.0 ; // Leave by sphi immediately 1665 } << 1548 } 1666 } << 1549 } 1667 } 1550 } 1668 else 1551 else 1669 { 1552 { 1670 sphi = kInfinity ; 1553 sphi = kInfinity ; 1671 } 1554 } 1672 } 1555 } 1673 else 1556 else 1674 { 1557 { 1675 sphi = kInfinity ; 1558 sphi = kInfinity ; 1676 } 1559 } 1677 1560 1678 if ( compE < 0 ) 1561 if ( compE < 0 ) 1679 { 1562 { 1680 sphi2 = pDistE/compE ; 1563 sphi2 = pDistE/compE ; 1681 << 1564 1682 // Only check further if < starti 1565 // Only check further if < starting phi intersection 1683 // 1566 // 1684 if ( (sphi2 > -halfCarTolerance) 1567 if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) ) 1685 { 1568 { 1686 xi = p.x() + sphi2*v.x() ; 1569 xi = p.x() + sphi2*v.x() ; 1687 yi = p.y() + sphi2*v.y() ; 1570 yi = p.y() + sphi2*v.y() ; 1688 << 1571 1689 if ((std::fabs(xi)<=kCarToleran 1572 if ((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance)) 1690 { 1573 { 1691 // Leaving via ending phi 1574 // Leaving via ending phi 1692 // 1575 // 1693 if( (fSPhi-halfAngTolerance > << 1576 if( !((fSPhi-halfAngTolerance <= vphi) 1694 ||(fSPhi+fDPhi+halfAngTo << 1577 &&(fSPhi+fDPhi+halfAngTolerance >= vphi)) ) 1695 { 1578 { 1696 sidephi = kEPhi ; 1579 sidephi = kEPhi ; 1697 if ( pDistE <= -halfCarTole 1580 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; } 1698 else 1581 else { sphi = 0.0 ; } 1699 } 1582 } 1700 } << 1583 } 1701 else // Check intersecting w << 1584 else // Check intersecting with correct half-plane 1702 1585 1703 if ( (yi*cosCPhi-xi*sinCPhi) >= 1586 if ( (yi*cosCPhi-xi*sinCPhi) >= 0) 1704 { 1587 { 1705 // Leaving via ending phi 1588 // Leaving via ending phi 1706 // 1589 // 1707 sidephi = kEPhi ; 1590 sidephi = kEPhi ; 1708 if ( pDistE <= -halfCarTolera 1591 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; } 1709 else 1592 else { sphi = 0.0 ; } 1710 } 1593 } 1711 } 1594 } 1712 } 1595 } 1713 } 1596 } 1714 else 1597 else 1715 { 1598 { 1716 sphi = kInfinity ; 1599 sphi = kInfinity ; 1717 } 1600 } 1718 } 1601 } 1719 else 1602 else 1720 { 1603 { 1721 // On z axis + travel not || to z axi 1604 // On z axis + travel not || to z axis -> if phi of vector direction 1722 // within phi of shape, Step limited 1605 // within phi of shape, Step limited by rmax, else Step =0 1723 << 1606 1724 if ( (fSPhi - halfAngTolerance <= vph 1607 if ( (fSPhi - halfAngTolerance <= vphi) 1725 && (vphi <= fSPhi + fDPhi + halfAn 1608 && (vphi <= fSPhi + fDPhi + halfAngTolerance ) ) 1726 { 1609 { 1727 sphi = kInfinity ; 1610 sphi = kInfinity ; 1728 } 1611 } 1729 else 1612 else 1730 { 1613 { 1731 sidephi = kSPhi ; // arbitrary << 1614 sidephi = kSPhi ; // arbitrary 1732 sphi = 0.0 ; 1615 sphi = 0.0 ; 1733 } 1616 } 1734 } 1617 } 1735 if (sphi < snxt) // Order intersecttio 1618 if (sphi < snxt) // Order intersecttions 1736 { 1619 { 1737 snxt = sphi ; 1620 snxt = sphi ; 1738 side = sidephi ; 1621 side = sidephi ; 1739 } 1622 } 1740 } 1623 } 1741 if (srd < snxt) // Order intersections << 1624 if (sr < snxt) // Order intersections 1742 { 1625 { 1743 snxt = srd ; << 1626 snxt = sr ; 1744 side = sider ; 1627 side = sider ; 1745 } 1628 } 1746 } 1629 } 1747 if (calcNorm) 1630 if (calcNorm) 1748 { 1631 { 1749 switch(side) 1632 switch(side) 1750 { 1633 { 1751 case kRMax: 1634 case kRMax: 1752 // Note: returned vector not normalis 1635 // Note: returned vector not normalised 1753 // (divide by fRMax for unit vector) 1636 // (divide by fRMax for unit vector) 1754 // 1637 // 1755 xi = p.x() + snxt*v.x() ; 1638 xi = p.x() + snxt*v.x() ; 1756 yi = p.y() + snxt*v.y() ; 1639 yi = p.y() + snxt*v.y() ; 1757 *n = G4ThreeVector(xi/fRMax,yi/fRMax, 1640 *n = G4ThreeVector(xi/fRMax,yi/fRMax,0) ; 1758 *validNorm = true ; 1641 *validNorm = true ; 1759 break ; 1642 break ; 1760 1643 1761 case kRMin: 1644 case kRMin: 1762 *validNorm = false ; // Rmin is inco 1645 *validNorm = false ; // Rmin is inconvex 1763 break ; 1646 break ; 1764 1647 1765 case kSPhi: 1648 case kSPhi: 1766 if ( fDPhi <= pi ) 1649 if ( fDPhi <= pi ) 1767 { 1650 { 1768 *n = G4ThreeVector(sinSPhi, 1651 *n = G4ThreeVector(sinSPhi,-cosSPhi,0) ; 1769 *validNorm = true ; 1652 *validNorm = true ; 1770 } 1653 } 1771 else 1654 else 1772 { 1655 { 1773 *validNorm = false ; 1656 *validNorm = false ; 1774 } 1657 } 1775 break ; 1658 break ; 1776 1659 1777 case kEPhi: 1660 case kEPhi: 1778 if (fDPhi <= pi) 1661 if (fDPhi <= pi) 1779 { 1662 { 1780 *n = G4ThreeVector(-sinEPhi,cosEPhi 1663 *n = G4ThreeVector(-sinEPhi,cosEPhi,0) ; 1781 *validNorm = true ; 1664 *validNorm = true ; 1782 } 1665 } 1783 else 1666 else 1784 { 1667 { 1785 *validNorm = false ; 1668 *validNorm = false ; 1786 } 1669 } 1787 break ; 1670 break ; 1788 1671 1789 case kPZ: 1672 case kPZ: 1790 *n = fHighNorm ; 1673 *n = fHighNorm ; 1791 *validNorm = true ; 1674 *validNorm = true ; 1792 break ; 1675 break ; 1793 1676 1794 case kMZ: 1677 case kMZ: 1795 *n = fLowNorm ; 1678 *n = fLowNorm ; 1796 *validNorm = true ; 1679 *validNorm = true ; 1797 break ; 1680 break ; 1798 1681 1799 default: 1682 default: 1800 G4cout << G4endl ; 1683 G4cout << G4endl ; 1801 DumpInfo(); 1684 DumpInfo(); 1802 std::ostringstream message; 1685 std::ostringstream message; 1803 G4long oldprc = message.precision(16) << 1686 G4int oldprc = message.precision(16); 1804 message << "Undefined side for valid 1687 message << "Undefined side for valid surface normal to solid." 1805 << G4endl 1688 << G4endl 1806 << "Position:" << G4endl << 1689 << "Position:" << G4endl << G4endl 1807 << "p.x() = " << p.x()/mm < 1690 << "p.x() = " << p.x()/mm << " mm" << G4endl 1808 << "p.y() = " << p.y()/mm < 1691 << "p.y() = " << p.y()/mm << " mm" << G4endl 1809 << "p.z() = " << p.z()/mm < 1692 << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl 1810 << "Direction:" << G4endl << 1693 << "Direction:" << G4endl << G4endl 1811 << "v.x() = " << v.x() << G 1694 << "v.x() = " << v.x() << G4endl 1812 << "v.y() = " << v.y() << G 1695 << "v.y() = " << v.y() << G4endl 1813 << "v.z() = " << v.z() << G 1696 << "v.z() = " << v.z() << G4endl << G4endl 1814 << "Proposed distance :" << G 1697 << "Proposed distance :" << G4endl << G4endl 1815 << "snxt = " << snxt/mm << 1698 << "snxt = " << snxt/mm << " mm" << G4endl ; 1816 message.precision(oldprc) ; 1699 message.precision(oldprc) ; 1817 G4Exception("G4CutTubs::DistanceToOut 1700 G4Exception("G4CutTubs::DistanceToOut(p,v,..)", "GeomSolids1002", 1818 JustWarning, message); 1701 JustWarning, message); 1819 break ; 1702 break ; 1820 } 1703 } 1821 } 1704 } 1822 if ( snxt<halfCarTolerance ) { snxt=0 ; } 1705 if ( snxt<halfCarTolerance ) { snxt=0 ; } 1823 return snxt ; 1706 return snxt ; 1824 } 1707 } 1825 1708 1826 ///////////////////////////////////////////// 1709 ////////////////////////////////////////////////////////////////////////// 1827 // 1710 // 1828 // Calculate distance (<=actual) to closest s 1711 // Calculate distance (<=actual) to closest surface of shape from inside 1829 1712 1830 G4double G4CutTubs::DistanceToOut( const G4Th 1713 G4double G4CutTubs::DistanceToOut( const G4ThreeVector& p ) const 1831 { 1714 { 1832 G4double safRMin,safRMax,safZLow,safZHigh,s 1715 G4double safRMin,safRMax,safZLow,safZHigh,safePhi,safe,rho; 1833 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 1716 G4ThreeVector vZ=G4ThreeVector(0,0,fDz); 1834 1717 1835 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) 1718 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; // Distance to R 1836 1719 1837 safRMin = rho - fRMin ; 1720 safRMin = rho - fRMin ; 1838 safRMax = fRMax - rho ; 1721 safRMax = fRMax - rho ; 1839 1722 1840 // Distances to ZCut(Low/High) 1723 // Distances to ZCut(Low/High) 1841 1724 1842 // Dist to Low Cut 1725 // Dist to Low Cut 1843 // 1726 // 1844 safZLow = std::fabs((p+vZ).dot(fLowNorm)); 1727 safZLow = std::fabs((p+vZ).dot(fLowNorm)); 1845 1728 1846 // Dist to High Cut 1729 // Dist to High Cut 1847 // 1730 // 1848 safZHigh = std::fabs((p-vZ).dot(fHighNorm)) 1731 safZHigh = std::fabs((p-vZ).dot(fHighNorm)); 1849 safe = std::min(safZLow,safZHigh); 1732 safe = std::min(safZLow,safZHigh); 1850 1733 1851 if ( safRMin < safe ) { safe = safRMin; } 1734 if ( safRMin < safe ) { safe = safRMin; } 1852 if ( safRMax< safe ) { safe = safRMax; } 1735 if ( safRMax< safe ) { safe = safRMax; } 1853 1736 1854 // Check if phi divided, Calc distances clo 1737 // Check if phi divided, Calc distances closest phi plane 1855 // 1738 // 1856 if ( !fPhiFullCutTube ) 1739 if ( !fPhiFullCutTube ) 1857 { 1740 { 1858 if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 ) 1741 if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 ) 1859 { 1742 { 1860 safePhi = -(p.x()*sinSPhi - p.y()*cosSP 1743 safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ; 1861 } 1744 } 1862 else 1745 else 1863 { 1746 { 1864 safePhi = (p.x()*sinEPhi - p.y()*cosEPh 1747 safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ; 1865 } 1748 } 1866 if (safePhi < safe) { safe = safePhi ; } 1749 if (safePhi < safe) { safe = safePhi ; } 1867 } 1750 } 1868 if ( safe < 0 ) { safe = 0; } 1751 if ( safe < 0 ) { safe = 0; } 1869 1752 1870 return safe ; 1753 return safe ; 1871 } 1754 } 1872 1755 >> 1756 ///////////////////////////////////////////////////////////////////////// >> 1757 // >> 1758 // Create a List containing the transformed vertices >> 1759 // Ordering [0-3] -fDz cross section >> 1760 // [4-7] +fDz cross section such that [0] is below [4], >> 1761 // [1] below [5] etc. >> 1762 // Note: >> 1763 // Caller has deletion resposibility >> 1764 >> 1765 G4ThreeVectorList* >> 1766 G4CutTubs::CreateRotatedVertices( const G4AffineTransform& pTransform ) const >> 1767 { >> 1768 G4ThreeVectorList* vertices ; >> 1769 G4ThreeVector vertex0, vertex1, vertex2, vertex3 ; >> 1770 G4double meshAngle, meshRMax, crossAngle, >> 1771 cosCrossAngle, sinCrossAngle, sAngle; >> 1772 G4double rMaxX, rMaxY, rMinX, rMinY, meshRMin ; >> 1773 G4int crossSection, noCrossSections; >> 1774 >> 1775 // Compute no of cross-sections necessary to mesh tube >> 1776 // >> 1777 noCrossSections = G4int(fDPhi/kMeshAngleDefault) + 1 ; >> 1778 >> 1779 if ( noCrossSections < kMinMeshSections ) >> 1780 { >> 1781 noCrossSections = kMinMeshSections ; >> 1782 } >> 1783 else if (noCrossSections>kMaxMeshSections) >> 1784 { >> 1785 noCrossSections = kMaxMeshSections ; >> 1786 } >> 1787 // noCrossSections = 4 ; >> 1788 >> 1789 meshAngle = fDPhi/(noCrossSections - 1) ; >> 1790 // meshAngle = fDPhi/(noCrossSections) ; >> 1791 >> 1792 meshRMax = (fRMax+100*kCarTolerance)/std::cos(meshAngle*0.5) ; >> 1793 meshRMin = fRMin - 100*kCarTolerance ; >> 1794 >> 1795 // If complete in phi, set start angle such that mesh will be at fRMax >> 1796 // on the x axis. Will give better extent calculations when not rotated. >> 1797 >> 1798 if (fPhiFullCutTube && (fSPhi == 0) ) { sAngle = -meshAngle*0.5 ; } >> 1799 else { sAngle = fSPhi ; } >> 1800 >> 1801 vertices = new G4ThreeVectorList(); >> 1802 >> 1803 if ( vertices ) >> 1804 { >> 1805 vertices->reserve(noCrossSections*4); >> 1806 for (crossSection = 0 ; crossSection < noCrossSections ; crossSection++ ) >> 1807 { >> 1808 // Compute coordinates of cross section at section crossSection >> 1809 >> 1810 crossAngle = sAngle + crossSection*meshAngle ; >> 1811 cosCrossAngle = std::cos(crossAngle) ; >> 1812 sinCrossAngle = std::sin(crossAngle) ; >> 1813 >> 1814 rMaxX = meshRMax*cosCrossAngle ; >> 1815 rMaxY = meshRMax*sinCrossAngle ; >> 1816 >> 1817 if(meshRMin <= 0.0) >> 1818 { >> 1819 rMinX = 0.0 ; >> 1820 rMinY = 0.0 ; >> 1821 } >> 1822 else >> 1823 { >> 1824 rMinX = meshRMin*cosCrossAngle ; >> 1825 rMinY = meshRMin*sinCrossAngle ; >> 1826 } >> 1827 vertex0 = G4ThreeVector(rMinX,rMinY,GetCutZ(G4ThreeVector(rMinX,rMinY,-fDz))) ; >> 1828 vertex1 = G4ThreeVector(rMaxX,rMaxY,GetCutZ(G4ThreeVector(rMaxX,rMaxY,-fDz))) ; >> 1829 vertex2 = G4ThreeVector(rMaxX,rMaxY,GetCutZ(G4ThreeVector(rMaxX,rMaxY,+fDz))) ; >> 1830 vertex3 = G4ThreeVector(rMinX,rMinY,GetCutZ(G4ThreeVector(rMinX,rMinY,+fDz))) ; >> 1831 >> 1832 vertices->push_back(pTransform.TransformPoint(vertex0)) ; >> 1833 vertices->push_back(pTransform.TransformPoint(vertex1)) ; >> 1834 vertices->push_back(pTransform.TransformPoint(vertex2)) ; >> 1835 vertices->push_back(pTransform.TransformPoint(vertex3)) ; >> 1836 } >> 1837 } >> 1838 else >> 1839 { >> 1840 DumpInfo(); >> 1841 G4Exception("G4CutTubs::CreateRotatedVertices()", >> 1842 "GeomSolids0003", FatalException, >> 1843 "Error in allocation of vertices. Out of memory !"); >> 1844 } >> 1845 return vertices ; >> 1846 } >> 1847 1873 ///////////////////////////////////////////// 1848 ////////////////////////////////////////////////////////////////////////// 1874 // 1849 // 1875 // Stream object contents to an output stream 1850 // Stream object contents to an output stream 1876 1851 1877 G4GeometryType G4CutTubs::GetEntityType() con 1852 G4GeometryType G4CutTubs::GetEntityType() const 1878 { 1853 { 1879 return {"G4CutTubs"}; << 1854 return G4String("G4CutTubs"); 1880 } 1855 } 1881 1856 1882 ///////////////////////////////////////////// 1857 ////////////////////////////////////////////////////////////////////////// 1883 // 1858 // 1884 // Make a clone of the object 1859 // Make a clone of the object 1885 // 1860 // 1886 G4VSolid* G4CutTubs::Clone() const 1861 G4VSolid* G4CutTubs::Clone() const 1887 { 1862 { 1888 return new G4CutTubs(*this); 1863 return new G4CutTubs(*this); 1889 } 1864 } 1890 1865 1891 ///////////////////////////////////////////// 1866 ////////////////////////////////////////////////////////////////////////// 1892 // 1867 // 1893 // Stream object contents to an output stream 1868 // Stream object contents to an output stream 1894 1869 1895 std::ostream& G4CutTubs::StreamInfo( std::ost 1870 std::ostream& G4CutTubs::StreamInfo( std::ostream& os ) const 1896 { 1871 { 1897 G4long oldprc = os.precision(16); << 1872 G4int oldprc = os.precision(16); 1898 os << "------------------------------------ 1873 os << "-----------------------------------------------------------\n" 1899 << " *** Dump for solid - " << GetNam 1874 << " *** Dump for solid - " << GetName() << " ***\n" 1900 << " ================================ 1875 << " ===================================================\n" 1901 << " Solid type: G4CutTubs\n" 1876 << " Solid type: G4CutTubs\n" 1902 << " Parameters: \n" 1877 << " Parameters: \n" 1903 << " inner radius : " << fRMin/mm << 1878 << " inner radius : " << fRMin/mm << " mm \n" 1904 << " outer radius : " << fRMax/mm << 1879 << " outer radius : " << fRMax/mm << " mm \n" 1905 << " half length Z: " << fDz/mm << " 1880 << " half length Z: " << fDz/mm << " mm \n" 1906 << " starting phi : " << fSPhi/degree 1881 << " starting phi : " << fSPhi/degree << " degrees \n" 1907 << " delta phi : " << fDPhi/degree 1882 << " delta phi : " << fDPhi/degree << " degrees \n" 1908 << " low Norm : " << fLowNorm << 1883 << " low Norm : " << fLowNorm << " \n" 1909 << " high Norm : " <<fHighNorm 1884 << " high Norm : " <<fHighNorm << " \n" 1910 << "------------------------------------ 1885 << "-----------------------------------------------------------\n"; 1911 os.precision(oldprc); 1886 os.precision(oldprc); 1912 1887 1913 return os; 1888 return os; 1914 } 1889 } 1915 1890 1916 ///////////////////////////////////////////// 1891 ///////////////////////////////////////////////////////////////////////// 1917 // 1892 // 1918 // GetPointOnSurface 1893 // GetPointOnSurface 1919 1894 1920 G4ThreeVector G4CutTubs::GetPointOnSurface() 1895 G4ThreeVector G4CutTubs::GetPointOnSurface() const 1921 { 1896 { 1922 // Set min and max z << 1897 G4double xRand, yRand, zRand, phi, cosphi, sinphi, chose, 1923 if (fZMin == 0. && fZMax == 0.) << 1898 aOne, aTwo, aThr, aFou; >> 1899 G4double rRand; >> 1900 >> 1901 aOne = 2.*fDz*fDPhi*fRMax; >> 1902 aTwo = 2.*fDz*fDPhi*fRMin; >> 1903 aThr = 0.5*fDPhi*(fRMax*fRMax-fRMin*fRMin); >> 1904 aFou = 2.*fDz*(fRMax-fRMin); >> 1905 >> 1906 phi = RandFlat::shoot(fSPhi, fSPhi+fDPhi); >> 1907 cosphi = std::cos(phi); >> 1908 sinphi = std::sin(phi); >> 1909 >> 1910 rRand = RandFlat::shoot(fRMin,fRMax); >> 1911 >> 1912 if( (fSPhi == 0) && (fDPhi == twopi) ) { aFou = 0; } >> 1913 >> 1914 chose = RandFlat::shoot(0.,aOne+aTwo+2.*aThr+2.*aFou); >> 1915 >> 1916 if( (chose >=0) && (chose < aOne) ) >> 1917 { >> 1918 xRand = fRMax*cosphi; >> 1919 yRand = fRMax*sinphi; >> 1920 zRand = RandFlat::shoot(GetCutZ(G4ThreeVector(xRand,yRand,-fDz)), >> 1921 GetCutZ(G4ThreeVector(xRand,yRand,fDz))); >> 1922 return G4ThreeVector (xRand, yRand, zRand); >> 1923 } >> 1924 else if( (chose >= aOne) && (chose < aOne + aTwo) ) >> 1925 { >> 1926 xRand = fRMin*cosphi; >> 1927 yRand = fRMin*sinphi; >> 1928 zRand = RandFlat::shoot(GetCutZ(G4ThreeVector(xRand,yRand,-fDz)), >> 1929 GetCutZ(G4ThreeVector(xRand,yRand,fDz))); >> 1930 return G4ThreeVector (xRand, yRand, zRand); >> 1931 } >> 1932 else if( (chose >= aOne + aTwo) && (chose < aOne + aTwo + aThr) ) >> 1933 { >> 1934 xRand = rRand*cosphi; >> 1935 yRand = rRand*sinphi; >> 1936 zRand = GetCutZ(G4ThreeVector(xRand,yRand,fDz)); >> 1937 return G4ThreeVector (xRand, yRand, zRand); >> 1938 } >> 1939 else if( (chose >= aOne + aTwo + aThr) && (chose < aOne + aTwo + 2.*aThr) ) >> 1940 { >> 1941 xRand = rRand*cosphi; >> 1942 yRand = rRand*sinphi; >> 1943 zRand = GetCutZ(G4ThreeVector(xRand,yRand,-fDz)); >> 1944 return G4ThreeVector (xRand, yRand, zRand); >> 1945 } >> 1946 else if( (chose >= aOne + aTwo + 2.*aThr) >> 1947 && (chose < aOne + aTwo + 2.*aThr + aFou) ) >> 1948 { >> 1949 xRand = rRand*std::cos(fSPhi); >> 1950 yRand = rRand*std::sin(fSPhi); >> 1951 zRand = RandFlat::shoot(GetCutZ(G4ThreeVector(xRand,yRand,-fDz)), >> 1952 GetCutZ(G4ThreeVector(xRand,yRand,fDz))); >> 1953 return G4ThreeVector (xRand, yRand, zRand); >> 1954 } >> 1955 else 1924 { 1956 { 1925 G4AutoLock l(&zminmaxMutex); << 1957 xRand = rRand*std::cos(fSPhi+fDPhi); 1926 G4ThreeVector bmin, bmax; << 1958 yRand = rRand*std::sin(fSPhi+fDPhi); 1927 BoundingLimits(bmin,bmax); << 1959 zRand = RandFlat::shoot(GetCutZ(G4ThreeVector(xRand,yRand,-fDz)), 1928 fZMin = bmin.z(); << 1960 GetCutZ(G4ThreeVector(xRand,yRand,fDz))); 1929 fZMax = bmax.z(); << 1961 return G4ThreeVector (xRand, yRand, zRand); 1930 l.unlock(); << 1962 } 1931 } << 1932 << 1933 // Set parameters << 1934 G4double hmax = fZMax - fZMin; << 1935 G4double sphi = fSPhi; << 1936 G4double dphi = fDPhi; << 1937 G4double rmin = fRMin; << 1938 G4double rmax = fRMax; << 1939 G4double rrmax = rmax*rmax; << 1940 G4double rrmin = rmin*rmin; << 1941 << 1942 G4ThreeVector nbot = GetLowNorm(); << 1943 G4ThreeVector ntop = GetHighNorm(); << 1944 << 1945 // Set array of surface areas << 1946 G4double sbase = 0.5*dphi*(rrmax - rrmin); << 1947 G4double sbot = sbase/std::abs(nbot.z()); << 1948 G4double stop = sbase/std::abs(ntop.z()); << 1949 G4double scut = (dphi == twopi) ? 0. : hmax << 1950 G4double ssurf[6] = { scut, scut, sbot, sto << 1951 ssurf[1] += ssurf[0]; << 1952 ssurf[2] += ssurf[1]; << 1953 ssurf[3] += ssurf[2]; << 1954 ssurf[4] += ssurf[3]; << 1955 ssurf[5] += ssurf[4]; << 1956 << 1957 constexpr G4int ntry = 100000; << 1958 for (G4int i=0; i<ntry; ++i) << 1959 { << 1960 // Select surface << 1961 G4double select = ssurf[5]*G4QuickRand(); << 1962 G4int k = 5; << 1963 k -= (G4int)(select <= ssurf[4]); << 1964 k -= (G4int)(select <= ssurf[3]); << 1965 k -= (G4int)(select <= ssurf[2]); << 1966 k -= (G4int)(select <= ssurf[1]); << 1967 k -= (G4int)(select <= ssurf[0]); << 1968 << 1969 // Generate point on selected surface (re << 1970 G4ThreeVector p(0,0,0); << 1971 switch(k) << 1972 { << 1973 case 0: // cut at start phi << 1974 { << 1975 G4double r = rmin + (rmax - rmin)*G4Q << 1976 p.set(r*cosSPhi, r*sinSPhi, fZMin + h << 1977 break; << 1978 } << 1979 case 1: // cut at end phi << 1980 { << 1981 G4double r = rmin + (rmax - rmin)*G4Q << 1982 p.set(r*cosEPhi, r*sinEPhi, fZMin + h << 1983 break; << 1984 } << 1985 case 2: // base at low z << 1986 { << 1987 G4double r = std::sqrt(rrmin + (rrmax << 1988 G4double phi = sphi + dphi*G4QuickRan << 1989 G4double x = r*std::cos(phi); << 1990 G4double y = r*std::sin(phi); << 1991 G4double z = -fDz - (x*nbot.x() + y*n << 1992 return {x, y, z}; << 1993 } << 1994 case 3: // base at high z << 1995 { << 1996 G4double r = std::sqrt(rrmin + (rrmax << 1997 G4double phi = sphi + dphi*G4QuickRan << 1998 G4double x = r*std::cos(phi); << 1999 G4double y = r*std::sin(phi); << 2000 G4double z = fDz - (x*ntop.x() + y*nt << 2001 return {x, y, z}; << 2002 } << 2003 case 4: // external lateral surface << 2004 { << 2005 G4double phi = sphi + dphi*G4QuickRan << 2006 G4double z = fZMin + hmax*G4QuickRand << 2007 G4double x = rmax*std::cos(phi); << 2008 G4double y = rmax*std::sin(phi); << 2009 p.set(x, y, z); << 2010 break; << 2011 } << 2012 case 5: // internal lateral surface << 2013 { << 2014 G4double phi = sphi + dphi*G4QuickRan << 2015 G4double z = fZMin + hmax*G4QuickRand << 2016 G4double x = rmin*std::cos(phi); << 2017 G4double y = rmin*std::sin(phi); << 2018 p.set(x, y, z); << 2019 break; << 2020 } << 2021 } << 2022 if ((ntop.dot(p) - fDz*ntop.z()) > 0.) co << 2023 if ((nbot.dot(p) + fDz*nbot.z()) > 0.) co << 2024 return p; << 2025 } << 2026 // Just in case, if all attempts to generat << 2027 // Normally should never happen << 2028 G4double x = rmax*std::cos(sphi + 0.5*dphi) << 2029 G4double y = rmax*std::sin(sphi + 0.5*dphi) << 2030 G4double z = fDz - (x*ntop.x() + y*ntop.y() << 2031 return {x, y, z}; << 2032 } 1963 } 2033 1964 2034 ///////////////////////////////////////////// 1965 /////////////////////////////////////////////////////////////////////////// 2035 // 1966 // 2036 // Methods for visualisation 1967 // Methods for visualisation 2037 1968 2038 void G4CutTubs::DescribeYourselfTo ( G4VGraph << 1969 void G4CutTubs::DescribeYourselfTo ( G4VGraphicsScene& scene ) const 2039 { 1970 { 2040 scene.AddSolid (*this) ; 1971 scene.AddSolid (*this) ; 2041 } 1972 } 2042 1973 2043 G4Polyhedron* G4CutTubs::CreatePolyhedron () << 1974 G4Polyhedron* G4CutTubs::CreatePolyhedron () const 2044 { 1975 { 2045 typedef G4double G4double3[3]; 1976 typedef G4double G4double3[3]; 2046 typedef G4int G4int4[4]; 1977 typedef G4int G4int4[4]; 2047 1978 2048 auto ph = new G4Polyhedron; << 1979 G4Polyhedron *ph = new G4Polyhedron; 2049 G4Polyhedron *ph1 = new G4PolyhedronTubs (f << 1980 G4Polyhedron *ph1 = G4Tubs::CreatePolyhedron(); 2050 G4int nn=ph1->GetNoVertices(); 1981 G4int nn=ph1->GetNoVertices(); 2051 G4int nf=ph1->GetNoFacets(); 1982 G4int nf=ph1->GetNoFacets(); 2052 auto xyz = new G4double3[nn]; // number of << 1983 G4double3* xyz = new G4double3[nn]; // number of nodes 2053 auto faces = new G4int4[nf] ; // number of << 1984 G4int4* faces = new G4int4[nf] ; // number of faces 2054 1985 2055 for(G4int i=0; i<nn; ++i) << 1986 for(G4int i=0;i<nn;i++) 2056 { 1987 { 2057 xyz[i][0]=ph1->GetVertex(i+1).x(); 1988 xyz[i][0]=ph1->GetVertex(i+1).x(); 2058 xyz[i][1]=ph1->GetVertex(i+1).y(); 1989 xyz[i][1]=ph1->GetVertex(i+1).y(); 2059 G4double tmpZ=ph1->GetVertex(i+1).z(); 1990 G4double tmpZ=ph1->GetVertex(i+1).z(); 2060 if(tmpZ>=fDz-kCarTolerance) 1991 if(tmpZ>=fDz-kCarTolerance) 2061 { 1992 { 2062 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][ 1993 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],fDz)); 2063 } 1994 } 2064 else if(tmpZ<=-fDz+kCarTolerance) 1995 else if(tmpZ<=-fDz+kCarTolerance) 2065 { 1996 { 2066 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][ 1997 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],-fDz)); 2067 } 1998 } 2068 else 1999 else 2069 { 2000 { 2070 xyz[i][2]=tmpZ; 2001 xyz[i][2]=tmpZ; 2071 } 2002 } 2072 } 2003 } 2073 G4int iNodes[4]; 2004 G4int iNodes[4]; 2074 G4int* iEdge = nullptr; << 2005 G4int *iEdge=0; 2075 G4int n; 2006 G4int n; 2076 for(G4int i=0; i<nf ; ++i) << 2007 for(G4int i=0;i<nf;i++) 2077 { 2008 { 2078 ph1->GetFacet(i+1,n,iNodes,iEdge); 2009 ph1->GetFacet(i+1,n,iNodes,iEdge); 2079 for(G4int k=0; k<n; ++k) << 2010 for(G4int k=0;k<n;k++) 2080 { 2011 { 2081 faces[i][k]=iNodes[k]; 2012 faces[i][k]=iNodes[k]; 2082 } 2013 } 2083 for(G4int k=n; k<4; ++k) << 2014 for(G4int k=n;k<4;k++) 2084 { 2015 { 2085 faces[i][k]=0; 2016 faces[i][k]=0; 2086 } 2017 } 2087 } 2018 } 2088 ph->createPolyhedron(nn,nf,xyz,faces); 2019 ph->createPolyhedron(nn,nf,xyz,faces); 2089 2020 2090 delete [] xyz; 2021 delete [] xyz; 2091 delete [] faces; 2022 delete [] faces; 2092 delete ph1; 2023 delete ph1; 2093 2024 2094 return ph; 2025 return ph; 2095 } 2026 } 2096 2027 2097 // Auxilary Methods for Solid 2028 // Auxilary Methods for Solid 2098 << 2029 2099 ///////////////////////////////////////////// << 2030 /////////////////////////////////////////////////////////////////////////// 2100 // << 2031 // Return true if Cutted planes are crossing 2101 // Check set of points on the outer lateral s << 2032 // Check Intersection Points on OX and OY axes 2102 // if the cut planes are crossing inside the << 2103 // << 2104 2033 2105 G4bool G4CutTubs::IsCrossingCutPlanes() const 2034 G4bool G4CutTubs::IsCrossingCutPlanes() const 2106 { 2035 { 2107 constexpr G4int npoints = 30; << 2036 G4double zXLow1,zXLow2,zYLow1,zYLow2; >> 2037 G4double zXHigh1,zXHigh2,zYHigh1,zYHigh2; >> 2038 >> 2039 zXLow1 = GetCutZ(G4ThreeVector(-fRMax, 0,-fDz)); >> 2040 zXLow2 = GetCutZ(G4ThreeVector( fRMax, 0,-fDz)); >> 2041 zYLow1 = GetCutZ(G4ThreeVector( 0,-fRMax,-fDz)); >> 2042 zYLow2 = GetCutZ(G4ThreeVector( 0, fRMax,-fDz)); >> 2043 zXHigh1 = GetCutZ(G4ThreeVector(-fRMax, 0, fDz)); >> 2044 zXHigh2 = GetCutZ(G4ThreeVector( fRMax, 0, fDz)); >> 2045 zYHigh1 = GetCutZ(G4ThreeVector( 0,-fRMax, fDz)); >> 2046 zYHigh2 = GetCutZ(G4ThreeVector( 0, fRMax, fDz)); >> 2047 if ( (zXLow1>zXHigh1) ||(zXLow2>zXHigh2) >> 2048 || (zYLow1>zYHigh1) ||(zYLow2>zYHigh2)) { return true; } 2108 2049 2109 // set values for calculation of h - distan << 2110 // opposite points on bases << 2111 G4ThreeVector nbot = GetLowNorm(); << 2112 G4ThreeVector ntop = GetHighNorm(); << 2113 if (std::abs(nbot.z()) < kCarTolerance) ret << 2114 if (std::abs(ntop.z()) < kCarTolerance) ret << 2115 G4double nx = nbot.x()/nbot.z() - ntop.x()/ << 2116 G4double ny = nbot.y()/nbot.z() - ntop.y()/ << 2117 << 2118 // check points << 2119 G4double cosphi = GetCosStartPhi(); << 2120 G4double sinphi = GetSinStartPhi(); << 2121 G4double delphi = GetDeltaPhiAngle()/npoint << 2122 G4double cosdel = std::cos(delphi); << 2123 G4double sindel = std::sin(delphi); << 2124 G4double hzero = 2.*GetZHalfLength()/GetOut << 2125 for (G4int i=0; i<npoints+1; ++i) << 2126 { << 2127 G4double h = nx*cosphi + ny*sinphi + hzer << 2128 if (h < 0.) return true; << 2129 G4double sintmp = sinphi; << 2130 sinphi = sintmp*cosdel + cosphi*sindel; << 2131 cosphi = cosphi*cosdel - sintmp*sindel; << 2132 } << 2133 return false; 2050 return false; 2134 } 2051 } 2135 2052 2136 ///////////////////////////////////////////// 2053 /////////////////////////////////////////////////////////////////////////// 2137 // 2054 // 2138 // Return real Z coordinate of point on Cutte 2055 // Return real Z coordinate of point on Cutted +/- fDZ plane 2139 2056 2140 G4double G4CutTubs::GetCutZ(const G4ThreeVect 2057 G4double G4CutTubs::GetCutZ(const G4ThreeVector& p) const 2141 { 2058 { 2142 G4double newz = p.z(); // p.z() should be 2059 G4double newz = p.z(); // p.z() should be either +fDz or -fDz 2143 if (p.z()<0) 2060 if (p.z()<0) 2144 { 2061 { 2145 if(fLowNorm.z()!=0.) 2062 if(fLowNorm.z()!=0.) 2146 { 2063 { 2147 newz = -fDz-(p.x()*fLowNorm.x()+p.y()* 2064 newz = -fDz-(p.x()*fLowNorm.x()+p.y()*fLowNorm.y())/fLowNorm.z(); 2148 } 2065 } 2149 } 2066 } 2150 else 2067 else 2151 { 2068 { 2152 if(fHighNorm.z()!=0.) 2069 if(fHighNorm.z()!=0.) 2153 { 2070 { 2154 newz = fDz-(p.x()*fHighNorm.x()+p.y()* 2071 newz = fDz-(p.x()*fHighNorm.x()+p.y()*fHighNorm.y())/fHighNorm.z(); 2155 } 2072 } 2156 } 2073 } 2157 return newz; 2074 return newz; 2158 } 2075 } 2159 #endif << 2076 >> 2077 /////////////////////////////////////////////////////////////////////////// >> 2078 // >> 2079 // Calculate Min and Max Z for CutZ >> 2080 >> 2081 void G4CutTubs::GetMaxMinZ(G4double& zmin,G4double& zmax)const >> 2082 >> 2083 { >> 2084 G4double phiLow = std::atan2(fLowNorm.y(),fLowNorm.x()); >> 2085 G4double phiHigh= std::atan2(fHighNorm.y(),fHighNorm.x()); >> 2086 >> 2087 G4double xc=0, yc=0,z1; >> 2088 G4double z[8]; >> 2089 G4bool in_range_low = false; >> 2090 G4bool in_range_hi = false; >> 2091 >> 2092 G4int i; >> 2093 for (i=0; i<2; i++) >> 2094 { >> 2095 if (phiLow<0) { phiLow+=twopi; } >> 2096 G4double ddp = phiLow-fSPhi; >> 2097 if (ddp<0) { ddp += twopi; } >> 2098 if (ddp <= fDPhi) >> 2099 { >> 2100 xc = fRMin*std::cos(phiLow); >> 2101 yc = fRMin*std::sin(phiLow); >> 2102 z1 = GetCutZ(G4ThreeVector(xc, yc, -fDz)); >> 2103 xc = fRMax*std::cos(phiLow); >> 2104 yc = fRMax*std::sin(phiLow); >> 2105 z1 = std::min(z1, GetCutZ(G4ThreeVector(xc, yc, -fDz))); >> 2106 if (in_range_low) { zmin = std::min(zmin, z1); } >> 2107 else { zmin = z1; } >> 2108 in_range_low = true; >> 2109 } >> 2110 phiLow += pi; >> 2111 if (phiLow>twopi) { phiLow-=twopi; } >> 2112 } >> 2113 for (i=0; i<2; i++) >> 2114 { >> 2115 if (phiHigh<0) { phiHigh+=twopi; } >> 2116 G4double ddp = phiHigh-fSPhi; >> 2117 if (ddp<0) { ddp += twopi; } >> 2118 if (ddp <= fDPhi) >> 2119 { >> 2120 xc = fRMin*std::cos(phiHigh); >> 2121 yc = fRMin*std::sin(phiHigh); >> 2122 z1 = GetCutZ(G4ThreeVector(xc, yc, fDz)); >> 2123 xc = fRMax*std::cos(phiHigh); >> 2124 yc = fRMax*std::sin(phiHigh); >> 2125 z1 = std::min(z1, GetCutZ(G4ThreeVector(xc, yc, fDz))); >> 2126 if (in_range_hi) { zmax = std::min(zmax, z1); } >> 2127 else { zmax = z1; } >> 2128 in_range_hi = true; >> 2129 } >> 2130 phiHigh += pi; >> 2131 if (phiLow>twopi) { phiHigh-=twopi; } >> 2132 } >> 2133 >> 2134 xc = fRMin*std::cos(fSPhi); >> 2135 yc = fRMin*std::sin(fSPhi); >> 2136 z[0] = GetCutZ(G4ThreeVector(xc, yc, -fDz)); >> 2137 z[4] = GetCutZ(G4ThreeVector(xc, yc, fDz)); >> 2138 >> 2139 xc = fRMin*std::cos(fSPhi+fDPhi); >> 2140 yc = fRMin*std::sin(fSPhi+fDPhi); >> 2141 z[1] = GetCutZ(G4ThreeVector(xc, yc, -fDz)); >> 2142 z[5] = GetCutZ(G4ThreeVector(xc, yc, fDz)); >> 2143 >> 2144 xc = fRMax*std::cos(fSPhi); >> 2145 yc = fRMax*std::sin(fSPhi); >> 2146 z[2] = GetCutZ(G4ThreeVector(xc, yc, -fDz)); >> 2147 z[6] = GetCutZ(G4ThreeVector(xc, yc, fDz)); >> 2148 >> 2149 xc = fRMax*std::cos(fSPhi+fDPhi); >> 2150 yc = fRMax*std::sin(fSPhi+fDPhi); >> 2151 z[3] = GetCutZ(G4ThreeVector(xc, yc, -fDz)); >> 2152 z[7] = GetCutZ(G4ThreeVector(xc, yc, fDz)); >> 2153 >> 2154 // Find min/max >> 2155 >> 2156 z1=z[0]; >> 2157 for (i = 1; i < 4; i++) >> 2158 { >> 2159 if(z[i] < z[i-1])z1=z[i]; >> 2160 } >> 2161 >> 2162 if (in_range_low) >> 2163 { >> 2164 zmin = std::min(zmin, z1); >> 2165 } >> 2166 else >> 2167 { >> 2168 zmin = z1; >> 2169 } >> 2170 z1=z[4]; >> 2171 for (i = 1; i < 4; i++) >> 2172 { >> 2173 if(z[4+i] > z[4+i-1]) { z1=z[4+i]; } >> 2174 } >> 2175 >> 2176 if (in_range_hi) { zmax = std::max(zmax, z1); } >> 2177 else { zmax = z1; } >> 2178 } 2160 2179