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 // 26 // class G4Ellipsoid 27 // class G4Ellipsoid 27 // 28 // 28 // Implementation of G4Ellipsoid class << 29 // Implementation for G4Ellipsoid class >> 30 // >> 31 // History: 29 // 32 // 30 // 10.11.99 G.Horton-Smith: first writing, bas 33 // 10.11.99 G.Horton-Smith: first writing, based on G4Sphere class 31 // 25.02.05 G.Guerrieri: Revised << 34 // 25.02.05 G.Guerrieri: Modified for future Geant4 release 32 // 15.12.19 E.Tcherniaev: Complete revision << 35 // 26.10.16 E.Tcherniaev: reimplemented CalculateExtent() using >> 36 // G4BoundingEnvelope, removed CreateRotatedVertices() >> 37 // 33 // ------------------------------------------- 38 // -------------------------------------------------------------------- 34 39 35 #include "G4Ellipsoid.hh" << 36 << 37 #if !(defined(G4GEOM_USE_UELLIPSOID) && define << 38 << 39 #include "globals.hh" 40 #include "globals.hh" 40 41 >> 42 #include "G4Ellipsoid.hh" >> 43 41 #include "G4VoxelLimits.hh" 44 #include "G4VoxelLimits.hh" 42 #include "G4AffineTransform.hh" 45 #include "G4AffineTransform.hh" 43 #include "G4GeometryTolerance.hh" 46 #include "G4GeometryTolerance.hh" 44 #include "G4BoundingEnvelope.hh" 47 #include "G4BoundingEnvelope.hh" 45 #include "G4RandomTools.hh" << 48 46 #include "G4QuickRand.hh" << 49 #include "meshdefs.hh" >> 50 #include "Randomize.hh" 47 51 48 #include "G4VPVParameterisation.hh" 52 #include "G4VPVParameterisation.hh" 49 53 50 #include "G4VGraphicsScene.hh" 54 #include "G4VGraphicsScene.hh" 51 #include "G4VisExtent.hh" 55 #include "G4VisExtent.hh" 52 56 53 #include "G4AutoLock.hh" 57 #include "G4AutoLock.hh" 54 58 55 namespace 59 namespace 56 { 60 { 57 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZ << 61 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER; 58 G4Mutex lateralareaMutex = G4MUTEX_INITIALIZ << 59 } 62 } 60 63 61 using namespace CLHEP; 64 using namespace CLHEP; 62 65 63 ////////////////////////////////////////////// << 66 /////////////////////////////////////////////////////////////////////////////// 64 // 67 // 65 // Constructor << 68 // constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI >> 69 // - note if pDPhi>2PI then reset to 2PI 66 70 67 G4Ellipsoid::G4Ellipsoid(const G4String& name, << 71 G4Ellipsoid::G4Ellipsoid(const G4String& pName, 68 G4double xSemiA << 72 G4double pxSemiAxis, 69 G4double ySemiA << 73 G4double pySemiAxis, 70 G4double zSemiA << 74 G4double pzSemiAxis, 71 G4double zBotto << 75 G4double pzBottomCut, 72 G4double zTopCu << 76 G4double pzTopCut) 73 : G4VSolid(name), fDx(xSemiAxis), fDy(ySemiA << 77 : G4VSolid(pName), fRebuildPolyhedron(false), fpPolyhedron(0), 74 fZBottomCut(zBottomCut), fZTopCut(zTopCut) << 78 fCubicVolume(0.), fSurfaceArea(0.), zBottomCut(0.), zTopCut(0.) 75 { 79 { 76 CheckParameters(); << 80 // note: for users that want to use the full ellipsoid it is useful >> 81 // to include a default for the cuts >> 82 >> 83 kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance(); >> 84 >> 85 halfCarTolerance = kCarTolerance*0.5; >> 86 halfRadTolerance = kRadTolerance*0.5; >> 87 >> 88 // Check Semi-Axis >> 89 if ( (pxSemiAxis<=0.) || (pySemiAxis<=0.) || (pzSemiAxis<=0.) ) >> 90 { >> 91 std::ostringstream message; >> 92 message << "Invalid semi-axis - " << GetName(); >> 93 G4Exception("G4Ellipsoid::G4Ellipsoid()", "GeomSolids0002", >> 94 FatalErrorInArgument, message); >> 95 } >> 96 SetSemiAxis(pxSemiAxis, pySemiAxis, pzSemiAxis); >> 97 >> 98 if ( pzBottomCut == 0 && pzTopCut == 0 ) >> 99 { >> 100 SetZCuts(-pzSemiAxis, pzSemiAxis); >> 101 } >> 102 else if ( (pzBottomCut < pzSemiAxis) && (pzTopCut > -pzSemiAxis) >> 103 && (pzBottomCut < pzTopCut) ) >> 104 { >> 105 SetZCuts(pzBottomCut, pzTopCut); >> 106 } >> 107 else >> 108 { >> 109 std::ostringstream message; >> 110 message << "Invalid z-coordinate for cutting plane - " << GetName(); >> 111 G4Exception("G4Ellipsoid::G4Ellipsoid()", "GeomSolids0002", >> 112 FatalErrorInArgument, message); >> 113 } 77 } 114 } 78 115 79 ////////////////////////////////////////////// << 116 /////////////////////////////////////////////////////////////////////////////// 80 // 117 // 81 // Fake default constructor - sets only member 118 // Fake default constructor - sets only member data and allocates memory 82 // for usage restri << 119 // for usage restricted to object persistency. 83 << 120 // 84 G4Ellipsoid::G4Ellipsoid( __void__& a ) 121 G4Ellipsoid::G4Ellipsoid( __void__& a ) 85 : G4VSolid(a), fDx(0.), fDy(0.), fDz(0.), fZ << 122 : G4VSolid(a), fRebuildPolyhedron(false), fpPolyhedron(0), kRadTolerance(0.), >> 123 halfCarTolerance(0.), halfRadTolerance(0.), fCubicVolume(0.), >> 124 fSurfaceArea(0.), xSemiAxis(0.), ySemiAxis(0.), zSemiAxis(0.), >> 125 semiAxisMax(0.), zBottomCut(0.), zTopCut(0.) 86 { 126 { 87 } 127 } 88 128 89 ////////////////////////////////////////////// << 129 /////////////////////////////////////////////////////////////////////////////// 90 // 130 // 91 // Destructor 131 // Destructor 92 132 93 G4Ellipsoid::~G4Ellipsoid() 133 G4Ellipsoid::~G4Ellipsoid() 94 { 134 { 95 delete fpPolyhedron; fpPolyhedron = nullptr; << 135 delete fpPolyhedron; fpPolyhedron = 0; 96 } 136 } 97 137 98 ////////////////////////////////////////////// << 138 /////////////////////////////////////////////////////////////////////////////// 99 // 139 // 100 // Copy constructor 140 // Copy constructor 101 141 102 G4Ellipsoid::G4Ellipsoid(const G4Ellipsoid& rh 142 G4Ellipsoid::G4Ellipsoid(const G4Ellipsoid& rhs) 103 : G4VSolid(rhs), 143 : G4VSolid(rhs), 104 fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz), << 144 fRebuildPolyhedron(false), fpPolyhedron(0), 105 fZBottomCut(rhs.fZBottomCut), fZTopCut(rhs. << 145 kRadTolerance(rhs.kRadTolerance), 106 halfTolerance(rhs.halfTolerance), << 146 halfCarTolerance(rhs.halfCarTolerance), 107 fXmax(rhs.fXmax), fYmax(rhs.fYmax), << 147 halfRadTolerance(rhs.halfRadTolerance), 108 fRsph(rhs.fRsph), fR(rhs.fR), << 148 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea), 109 fSx(rhs.fSx), fSy(rhs.fSy), fSz(rhs.fSz), << 149 xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis), 110 fZMidCut(rhs.fZMidCut), fZDimCut(rhs.fZDimC << 150 zSemiAxis(rhs.zSemiAxis), semiAxisMax(rhs.semiAxisMax), 111 fQ1(rhs.fQ1), fQ2(rhs.fQ2), << 151 zBottomCut(rhs.zBottomCut), zTopCut(rhs.zTopCut) 112 fCubicVolume(rhs.fCubicVolume), << 113 fSurfaceArea(rhs.fSurfaceArea), << 114 fLateralArea(rhs.fLateralArea) << 115 { 152 { 116 } 153 } 117 154 118 ////////////////////////////////////////////// << 155 /////////////////////////////////////////////////////////////////////////////// 119 // 156 // 120 // Assignment operator 157 // Assignment operator 121 158 122 G4Ellipsoid& G4Ellipsoid::operator = (const G4 << 159 G4Ellipsoid& G4Ellipsoid::operator = (const G4Ellipsoid& rhs) 123 { 160 { 124 // Check assignment to self 161 // Check assignment to self 125 // 162 // 126 if (this == &rhs) { return *this; } 163 if (this == &rhs) { return *this; } 127 164 128 // Copy base class data 165 // Copy base class data 129 // 166 // 130 G4VSolid::operator=(rhs); 167 G4VSolid::operator=(rhs); 131 168 132 // Copy data 169 // Copy data 133 // 170 // 134 fDx = rhs.fDx; << 171 kRadTolerance = rhs.kRadTolerance; 135 fDy = rhs.fDy; << 172 halfCarTolerance = rhs.halfCarTolerance; 136 fDz = rhs.fDz; << 173 halfRadTolerance = rhs.halfRadTolerance; 137 fZBottomCut = rhs.fZBottomCut; << 174 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea; 138 fZTopCut = rhs.fZTopCut; << 175 xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis; 139 << 176 zSemiAxis = rhs.zSemiAxis; semiAxisMax = rhs.semiAxisMax; 140 halfTolerance = rhs.halfTolerance; << 177 zBottomCut = rhs.zBottomCut; zTopCut = rhs.zTopCut; 141 fXmax = rhs.fXmax; << 142 fYmax = rhs.fYmax; << 143 fRsph = rhs.fRsph; << 144 fR = rhs.fR; << 145 fSx = rhs.fSx; << 146 fSy = rhs.fSy; << 147 fSz = rhs.fSz; << 148 fZMidCut = rhs.fZMidCut; << 149 fZDimCut = rhs.fZDimCut; << 150 fQ1 = rhs.fQ1; << 151 fQ2 = rhs.fQ2; << 152 << 153 fCubicVolume = rhs.fCubicVolume; << 154 fSurfaceArea = rhs.fSurfaceArea; << 155 fLateralArea = rhs.fLateralArea; << 156 << 157 fRebuildPolyhedron = false; 178 fRebuildPolyhedron = false; 158 delete fpPolyhedron; fpPolyhedron = nullptr << 179 delete fpPolyhedron; fpPolyhedron = 0; 159 180 160 return *this; 181 return *this; 161 } 182 } 162 183 163 ////////////////////////////////////////////// << 184 //////////////////////////////////////////////////////////////////////// 164 // << 165 // Check parameters and make precalculation << 166 << 167 void G4Ellipsoid::CheckParameters() << 168 { << 169 halfTolerance = 0.5 * kCarTolerance; // half << 170 G4double dmin = 2. * kCarTolerance; << 171 << 172 // Check dimensions << 173 // << 174 if (fDx < dmin || fDy < dmin || fDz < dmin) << 175 { << 176 std::ostringstream message; << 177 message << "Invalid (too small or negative << 178 << GetName() << "\n" << 179 << " semi-axis x: " << fDx << "\n << 180 << " semi-axis y: " << fDy << "\n << 181 << " semi-axis z: " << fDz; << 182 G4Exception("G4Ellipsoid::CheckParameters( << 183 FatalException, message); << 184 } << 185 G4double A = fDx; << 186 G4double B = fDy; << 187 G4double C = fDz; << 188 << 189 // Check cuts << 190 // << 191 if (fZBottomCut == 0. && fZTopCut == 0.) << 192 { << 193 fZBottomCut = -C; << 194 fZTopCut = C; << 195 } << 196 if (fZBottomCut >= C || fZTopCut <= -C || fZ << 197 { << 198 std::ostringstream message; << 199 message << "Invalid Z cuts for Solid: " << 200 << GetName() << "\n" << 201 << " bottom cut: " << fZBottomCut << 202 << " top cut: " << fZTopCut; << 203 G4Exception("G4Ellipsoid::CheckParameters( << 204 FatalException, message); << 205 << 206 } << 207 fZBottomCut = std::max(fZBottomCut, -C); << 208 fZTopCut = std::min(fZTopCut, C); << 209 << 210 // Set extent in x and y << 211 fXmax = A; << 212 fYmax = B; << 213 if (fZBottomCut > 0.) << 214 { << 215 G4double ratio = fZBottomCut / C; << 216 G4double scale = std::sqrt((1. - ratio) * << 217 fXmax *= scale; << 218 fYmax *= scale; << 219 } << 220 if (fZTopCut < 0.) << 221 { << 222 G4double ratio = fZTopCut / C; << 223 G4double scale = std::sqrt((1. - ratio) * << 224 fXmax *= scale; << 225 fYmax *= scale; << 226 } << 227 << 228 // Set scale factors << 229 fRsph = std::max(std::max(A, B), C); // boun << 230 fR = std::min(std::min(A, B), C); // radi << 231 fSx = fR / A; // X scale factor << 232 fSy = fR / B; // Y scale factor << 233 fSz = fR / C; // Z scale factor << 234 << 235 // Scaled cuts << 236 fZMidCut = 0.5 * (fZTopCut + fZBottomCut) * << 237 fZDimCut = 0.5 * (fZTopCut - fZBottomCut) * << 238 << 239 // Coefficients for approximation of distanc << 240 fQ1 = 0.5 / fR; << 241 fQ2 = 0.5 * fR + halfTolerance * halfToleran << 242 << 243 fCubicVolume = 0.; // volume << 244 fSurfaceArea = 0.; // surface area << 245 fLateralArea = 0.; // lateral surface area << 246 } << 247 << 248 ////////////////////////////////////////////// << 249 // 185 // 250 // Dispatch to parameterisation for replicatio 186 // Dispatch to parameterisation for replication mechanism dimension 251 // computation & modification << 187 // computation & modification. 252 188 253 void G4Ellipsoid::ComputeDimensions(G4VPVParam 189 void G4Ellipsoid::ComputeDimensions(G4VPVParameterisation* p, 254 const G4in 190 const G4int n, 255 const G4VP 191 const G4VPhysicalVolume* pRep) 256 { 192 { 257 p->ComputeDimensions(*this,n,pRep); 193 p->ComputeDimensions(*this,n,pRep); 258 } 194 } 259 195 260 ////////////////////////////////////////////// << 196 /////////////////////////////////////////////////////////////////////////////// 261 // 197 // 262 // Get bounding box 198 // Get bounding box 263 199 264 void G4Ellipsoid::BoundingLimits(G4ThreeVector << 200 void G4Ellipsoid::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const 265 G4ThreeVector << 266 { 201 { 267 pMin.set(-fXmax,-fYmax, fZBottomCut); << 202 G4double dx = GetSemiAxisMax(0); 268 pMax.set( fXmax, fYmax, fZTopCut); << 203 G4double dy = GetSemiAxisMax(1); >> 204 G4double dz = GetSemiAxisMax(2); >> 205 G4double zmin = std::max(-dz,GetZBottomCut()); >> 206 G4double zmax = std::min( dz,GetZTopCut()); >> 207 pMin.set(-dx,-dy,zmin); >> 208 pMax.set( dx, dy,zmax); >> 209 >> 210 // Check correctness of the bounding box >> 211 // >> 212 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z()) >> 213 { >> 214 std::ostringstream message; >> 215 message << "Bad bounding box (min >= max) for solid: " >> 216 << GetName() << " !" >> 217 << "\npMin = " << pMin >> 218 << "\npMax = " << pMax; >> 219 G4Exception("G4Ellipsoid::BoundingLimits()", "GeomMgt0001", >> 220 JustWarning, message); >> 221 DumpInfo(); >> 222 } 269 } 223 } 270 224 271 ////////////////////////////////////////////// << 225 /////////////////////////////////////////////////////////////////////////////// 272 // 226 // 273 // Calculate extent under transform and specif << 227 // Calculate extent under transform and specified limit 274 228 275 G4bool 229 G4bool 276 G4Ellipsoid::CalculateExtent(const EAxis pAxis 230 G4Ellipsoid::CalculateExtent(const EAxis pAxis, 277 const G4VoxelLimi 231 const G4VoxelLimits& pVoxelLimit, 278 const G4AffineTra 232 const G4AffineTransform& pTransform, 279 G4double& p 233 G4double& pMin, G4double& pMax) const 280 { 234 { 281 G4ThreeVector bmin, bmax; 235 G4ThreeVector bmin, bmax; 282 236 283 // Get bounding box 237 // Get bounding box 284 BoundingLimits(bmin,bmax); 238 BoundingLimits(bmin,bmax); 285 239 286 // Find extent 240 // Find extent 287 G4BoundingEnvelope bbox(bmin,bmax); 241 G4BoundingEnvelope bbox(bmin,bmax); 288 return bbox.CalculateExtent(pAxis,pVoxelLimi 242 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax); 289 } 243 } 290 244 291 ////////////////////////////////////////////// << 245 /////////////////////////////////////////////////////////////////////////////// 292 // 246 // 293 // Return position of point: inside/outside/on << 247 // Return whether point inside/outside/on surface >> 248 // Split into radius, phi, theta checks >> 249 // Each check modifies `in', or returns as approprate 294 250 295 EInside G4Ellipsoid::Inside(const G4ThreeVecto 251 EInside G4Ellipsoid::Inside(const G4ThreeVector& p) const 296 { 252 { 297 G4double x = p.x() * fSx; << 253 G4double rad2oo, // outside surface outer tolerance 298 G4double y = p.y() * fSy; << 254 rad2oi; // outside surface inner tolerance 299 G4double z = p.z() * fSz; << 255 EInside in; 300 G4double rr = x * x + y * y + z * z; << 301 G4double distZ = std::abs(z - fZMidCut) - fZ << 302 G4double distR = fQ1 * rr - fQ2; << 303 G4double dist = std::max(distZ, distR); << 304 256 305 if (dist > halfTolerance) return kOutside; << 257 // check this side of z cut first, because that's fast 306 return (dist > -halfTolerance) ? kSurface : << 258 // 307 } << 259 if (p.z() < zBottomCut-halfRadTolerance) { return in=kOutside; } >> 260 if (p.z() > zTopCut+halfRadTolerance) { return in=kOutside; } 308 261 309 ////////////////////////////////////////////// << 262 rad2oo= sqr(p.x()/(xSemiAxis+halfRadTolerance)) 310 // << 263 + sqr(p.y()/(ySemiAxis+halfRadTolerance)) 311 // Return unit normal to surface at p << 264 + sqr(p.z()/(zSemiAxis+halfRadTolerance)); 312 265 313 G4ThreeVector G4Ellipsoid::SurfaceNormal( cons << 266 if (rad2oo > 1.0) { return in=kOutside; } 314 { << 267 315 G4ThreeVector norm(0., 0., 0.); << 268 rad2oi= sqr(p.x()*(1.0+halfRadTolerance/xSemiAxis)/xSemiAxis) 316 G4int nsurf = 0; << 269 + sqr(p.y()*(1.0+halfRadTolerance/ySemiAxis)/ySemiAxis) >> 270 + sqr(p.z()*(1.0+halfRadTolerance/zSemiAxis)/zSemiAxis); 317 271 318 // Check cuts << 272 // Check radial surfaces 319 G4double x = p.x() * fSx; << 273 // sets `in' (already checked for rad2oo > 1.0) 320 G4double y = p.y() * fSy; << 274 // 321 G4double z = p.z() * fSz; << 275 if (rad2oi < 1.0) 322 G4double distZ = std::abs(z - fZMidCut) - fZ << 323 if (std::abs(distZ) <= halfTolerance) << 324 { 276 { 325 norm.setZ(std::copysign(1., z - fZMidCut)) << 277 in = ( (p.z() < zBottomCut+halfRadTolerance) 326 ++nsurf; << 278 || (p.z() > zTopCut-halfRadTolerance) ) ? kSurface : kInside; >> 279 if ( rad2oi > 1.0-halfRadTolerance ) { in=kSurface; } 327 } 280 } 328 << 281 else 329 // Check lateral surface << 330 G4double distR = fQ1*(x*x + y*y + z*z) - fQ2 << 331 if (std::abs(distR) <= halfTolerance) << 332 { 282 { 333 // normal = (p.x/a^2, p.y/b^2, p.z/c^2) << 283 in = kSurface; 334 norm += G4ThreeVector(x*fSx, y*fSy, z*fSz) << 335 ++nsurf; << 336 } 284 } >> 285 return in; 337 286 338 // Return normal << 339 if (nsurf == 1) return norm; << 340 else if (nsurf > 1) return norm.unit(); // e << 341 else << 342 { << 343 #ifdef G4SPECSDEBUG << 344 std::ostringstream message; << 345 G4long oldprc = message.precision(16); << 346 message << "Point p is not on surface (!?) << 347 << GetName() << "\n"; << 348 message << "Position:\n"; << 349 message << " p.x() = " << p.x()/mm << " << 350 message << " p.y() = " << p.y()/mm << " << 351 message << " p.z() = " << p.z()/mm << " << 352 G4cout.precision(oldprc); << 353 G4Exception("G4Ellipsoid::SurfaceNormal(p) << 354 JustWarning, message ); << 355 DumpInfo(); << 356 #endif << 357 return ApproxSurfaceNormal(p); << 358 } << 359 } 287 } 360 288 361 ////////////////////////////////////////////// << 289 /////////////////////////////////////////////////////////////////////////////// 362 // 290 // 363 // Find surface nearest to point and return co << 291 // Return unit normal of surface closest to p not protected against p=0 364 // This method normally should not be called. << 365 292 366 G4ThreeVector G4Ellipsoid::ApproxSurfaceNormal << 293 G4ThreeVector G4Ellipsoid::SurfaceNormal( const G4ThreeVector& p) const 367 { 294 { 368 G4double x = p.x() * fSx; << 295 G4double distR, distZBottom, distZTop; 369 G4double y = p.y() * fSy; << 296 370 G4double z = p.z() * fSz; << 297 // normal vector with special magnitude: parallel to normal, units 1/length 371 G4double rr = x * x + y * y + z * z; << 298 // norm*p == 1.0 if on surface, >1.0 if outside, <1.0 if inside 372 G4double distZ = std::abs(z - fZMidCut) - fZ << 299 // 373 G4double distR = std::sqrt(rr) - fR; << 300 G4ThreeVector norm(p.x()/(xSemiAxis*xSemiAxis), 374 if (distR > distZ && rr > 0.) // distR > di << 301 p.y()/(ySemiAxis*ySemiAxis), 375 return G4ThreeVector(x*fSx, y*fSy, z*fSz). << 302 p.z()/(zSemiAxis*zSemiAxis)); 376 else << 303 G4double radius = 1.0/norm.mag(); 377 return { 0., 0., std::copysign(1., z - fZM << 304 >> 305 // approximate distance to curved surface >> 306 // >> 307 distR = std::fabs( (p*norm - 1.0) * radius ) / 2.0; >> 308 >> 309 // Distance to z-cut plane >> 310 // >> 311 distZBottom = std::fabs( p.z() - zBottomCut ); >> 312 distZTop = std::fabs( p.z() - zTopCut ); >> 313 >> 314 if ( (distZBottom < distR) || (distZTop < distR) ) >> 315 { >> 316 return G4ThreeVector(0.,0.,(distZBottom < distZTop) ? -1.0 : 1.0); >> 317 } >> 318 return ( norm *= radius ); 378 } 319 } 379 320 380 ////////////////////////////////////////////// << 321 /////////////////////////////////////////////////////////////////////////////// >> 322 // >> 323 // Calculate distance to shape from outside, along normalised vector >> 324 // - return kInfinity if no intersection, or intersection distance <= tolerance 381 // 325 // 382 // Calculate distance to shape from outside al << 383 326 384 G4double G4Ellipsoid::DistanceToIn(const G4Thr << 327 G4double G4Ellipsoid::DistanceToIn( const G4ThreeVector& p, 385 const G4Thr << 328 const G4ThreeVector& v ) const 386 { 329 { 387 G4double offset = 0.; << 330 G4double distMin = std::min(xSemiAxis,ySemiAxis); 388 G4ThreeVector pcur = p; << 331 const G4double dRmax = 100.*std::min(distMin,zSemiAxis); >> 332 distMin= kInfinity; 389 333 390 // Check if point is flying away, relative t << 334 // check to see if Z plane is relevant 391 // << 335 if (p.z() <= zBottomCut+halfCarTolerance) 392 G4double safex = std::abs(p.x()) - fXmax; << 336 { 393 G4double safey = std::abs(p.y()) - fYmax; << 337 if (v.z() <= 0.0) { return distMin; } 394 G4double safet = p.z() - fZTopCut; << 338 G4double distZ = (zBottomCut - p.z()) / v.z(); 395 G4double safeb = fZBottomCut - p.z(); << 396 << 397 if (safex >= -halfTolerance && p.x() * v.x() << 398 if (safey >= -halfTolerance && p.y() * v.y() << 399 if (safet >= -halfTolerance && v.z() >= 0.) << 400 if (safeb >= -halfTolerance && v.z() <= 0.) << 401 339 402 // Relocate point, if required << 340 if ( (distZ > -halfRadTolerance) && (Inside(p+distZ*v) != kOutside) ) 403 // << 341 { 404 G4double safe = std::max(std::max(std::max(s << 342 // early exit since can't intercept curved surface if we reach here 405 if (safe > 32. * fRsph) << 343 if ( std::fabs(distZ) < halfRadTolerance ) { distZ=0.; } >> 344 return distMin= distZ; >> 345 } >> 346 } >> 347 if (p.z() >= zTopCut-halfCarTolerance) 406 { 348 { 407 offset = (1. - 1.e-08) * safe - 2. * fRsph << 349 if (v.z() >= 0.0) { return distMin;} 408 pcur += offset * v; << 350 G4double distZ = (zTopCut - p.z()) / v.z(); 409 G4double dist = DistanceToIn(pcur, v); << 351 if ( (distZ > -halfRadTolerance) && (Inside(p+distZ*v) != kOutside) ) 410 return (dist == kInfinity) ? kInfinity : d << 352 { >> 353 // early exit since can't intercept curved surface if we reach here >> 354 if ( std::fabs(distZ) < halfRadTolerance ) { distZ=0.; } >> 355 return distMin= distZ; >> 356 } 411 } 357 } >> 358 // if fZCut1 <= p.z() <= fZCut2, then must hit curved surface 412 359 413 // Scale ellipsoid to sphere << 360 // now check curved surface intercept 414 // << 361 G4double A,B,C; 415 G4double px = pcur.x() * fSx; << 416 G4double py = pcur.y() * fSy; << 417 G4double pz = pcur.z() * fSz; << 418 G4double vx = v.x() * fSx; << 419 G4double vy = v.y() * fSy; << 420 G4double vz = v.z() * fSz; << 421 362 422 // Check if point is leaving the solid << 363 A= sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) + sqr(v.z()/zSemiAxis); 423 // << 364 C= sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis) + sqr(p.z()/zSemiAxis) - 1.0; 424 G4double dzcut = fZDimCut; << 365 B= 2.0 * ( p.x()*v.x()/(xSemiAxis*xSemiAxis) 425 G4double pzcut = pz - fZMidCut; << 366 + p.y()*v.y()/(ySemiAxis*ySemiAxis) 426 G4double distZ = std::abs(pzcut) - dzcut; << 367 + p.z()*v.z()/(zSemiAxis*zSemiAxis) ); 427 if (distZ >= -halfTolerance && pzcut * vz >= << 428 368 429 G4double rr = px * px + py * py + pz * pz; << 369 C= B*B - 4.0*A*C; 430 G4double pv = px * vx + py * vy + pz * vz; << 370 if (C > 0.0) 431 G4double distR = fQ1 * rr - fQ2; << 371 { 432 if (distR >= -halfTolerance && pv >= 0.) ret << 372 G4double distR= (-B - std::sqrt(C)) / (2.0*A); >> 373 G4double intZ = p.z()+distR*v.z(); >> 374 if ( (distR > halfRadTolerance) >> 375 && (intZ >= zBottomCut-halfRadTolerance) >> 376 && (intZ <= zTopCut+halfRadTolerance) ) >> 377 { >> 378 distMin = distR; >> 379 } >> 380 else if( (distR >- halfRadTolerance) >> 381 && (intZ >= zBottomCut-halfRadTolerance) >> 382 && (intZ <= zTopCut+halfRadTolerance) ) >> 383 { >> 384 // p is on the curved surface, DistanceToIn returns 0 or kInfinity: >> 385 // DistanceToIn returns 0, if second root is positive (means going inside) >> 386 // If second root is negative, DistanceToIn returns kInfinity (outside) >> 387 // >> 388 distR = (-B + std::sqrt(C) ) / (2.0*A); >> 389 if(distR>0.) { distMin=0.; } >> 390 } >> 391 else >> 392 { >> 393 distR= (-B + std::sqrt(C)) / (2.0*A); >> 394 intZ = p.z()+distR*v.z(); >> 395 if ( (distR > halfRadTolerance) >> 396 && (intZ >= zBottomCut-halfRadTolerance) >> 397 && (intZ <= zTopCut+halfRadTolerance) ) >> 398 { >> 399 G4ThreeVector norm=SurfaceNormal(p); >> 400 if (norm.dot(v)<0.) { distMin = distR; } >> 401 } >> 402 } >> 403 if ( (distMin!=kInfinity) && (distMin>dRmax) ) >> 404 { // Avoid rounding errors due to precision issues on >> 405 // 64 bits systems. Split long distances and recompute >> 406 G4double fTerm = distMin-std::fmod(distMin,dRmax); >> 407 distMin = fTerm + DistanceToIn(p+fTerm*v,v); >> 408 } >> 409 } >> 410 >> 411 if (std::fabs(distMin)<halfRadTolerance) { distMin=0.; } >> 412 return distMin; >> 413 } 433 414 434 G4double A = vx * vx + vy * vy + vz * vz; << 415 /////////////////////////////////////////////////////////////////////////////// 435 G4double B = pv; << 416 // 436 G4double C = rr - fR * fR; << 417 // Calculate distance (<= actual) to closest surface of shape from outside 437 G4double D = B * B - A * C; << 418 // - Return 0 if point inside 438 // scratch^2 = R^2 - (R - halfTolerance)^2 = << 439 G4double EPS = A * A * fR * kCarTolerance; / << 440 if (D <= EPS) return kInfinity; // no inters << 441 419 442 // Find intersection with Z planes << 420 G4double G4Ellipsoid::DistanceToIn(const G4ThreeVector& p) const 443 // << 421 { 444 G4double invz = (vz == 0) ? DBL_MAX : -1./v << 422 G4double distR, distZ; 445 G4double dz = std::copysign(dzcut, invz); << 446 G4double tzmin = (pzcut - dz) * invz; << 447 G4double tzmax = (pzcut + dz) * invz; << 448 423 449 // Find intersection with lateral surface << 424 // normal vector: parallel to normal, magnitude 1/(characteristic radius) 450 // 425 // 451 G4double tmp = -B - std::copysign(std::sqrt( << 426 G4ThreeVector norm(p.x()/(xSemiAxis*xSemiAxis), 452 G4double t1 = tmp / A; << 427 p.y()/(ySemiAxis*ySemiAxis), 453 G4double t2 = C / tmp; << 428 p.z()/(zSemiAxis*zSemiAxis)); 454 G4double trmin = std::min(t1, t2); << 429 G4double radius= 1.0/norm.mag(); 455 G4double trmax = std::max(t1, t2); << 456 430 457 // Return distance << 431 // approximate distance to curved surface ( <= actual distance ) 458 // 432 // 459 G4double tmin = std::max(tzmin, trmin); << 433 distR= (p*norm - 1.0) * radius / 2.0; 460 G4double tmax = std::min(tzmax, trmax); << 461 << 462 if (tmax - tmin <= halfTolerance) return kIn << 463 return (tmin < halfTolerance) ? offset : tmi << 464 } << 465 434 466 ////////////////////////////////////////////// << 435 // Distance to z-cut plane 467 // << 436 // 468 // Estimate distance to surface from outside << 437 distZ= zBottomCut - p.z(); >> 438 if (distZ < 0.0) >> 439 { >> 440 distZ = p.z() - zTopCut; >> 441 } 469 442 470 G4double G4Ellipsoid::DistanceToIn(const G4Thr << 443 // Distance to closest surface from outside 471 { << 444 // 472 G4double px = p.x(); << 445 if (distZ < 0.0) 473 G4double py = p.y(); << 446 { 474 G4double pz = p.z(); << 447 return (distR < 0.0) ? 0.0 : distR; 475 << 448 } 476 // Safety distance to bounding box << 449 else if (distR < 0.0) 477 G4double distX = std::abs(px) - fXmax; << 450 { 478 G4double distY = std::abs(py) - fYmax; << 451 return distZ; 479 G4double distZ = std::max(pz - fZTopCut, fZB << 452 } 480 G4double distB = std::max(std::max(distX, di << 453 else 481 << 454 { 482 // Safety distance to lateral surface << 455 return (distZ < distR) ? distZ : distR; 483 G4double x = px * fSx; << 456 } 484 G4double y = py * fSy; << 485 G4double z = pz * fSz; << 486 G4double distR = std::sqrt(x*x + y*y + z*z) << 487 << 488 // Return safety to in << 489 G4double dist = std::max(distB, distR); << 490 return (dist < 0.) ? 0. : dist; << 491 } 457 } 492 458 493 ////////////////////////////////////////////// << 459 /////////////////////////////////////////////////////////////////////////////// 494 // 460 // 495 // Calculate distance to surface from inside a << 461 // Calculate distance to surface of shape from `inside', allowing for tolerance 496 462 497 G4double G4Ellipsoid::DistanceToOut(const G4Th 463 G4double G4Ellipsoid::DistanceToOut(const G4ThreeVector& p, 498 const G4Th 464 const G4ThreeVector& v, 499 const G4bo 465 const G4bool calcNorm, 500 G4bo << 466 G4bool *validNorm, 501 G4Th << 467 G4ThreeVector *n ) const 502 { 468 { 503 // Check if point flying away relative to Z << 469 G4double distMin; 504 // << 470 enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface; 505 G4double pz = p.z() * fSz; << 471 506 G4double vz = v.z() * fSz; << 472 distMin= kInfinity; 507 G4double dzcut = fZDimCut; << 473 surface= kNoSurf; 508 G4double pzcut = pz - fZMidCut; << 509 G4double distZ = std::abs(pzcut) - dzcut; << 510 if (distZ >= -halfTolerance && pzcut * vz > << 511 { << 512 if (calcNorm) << 513 { << 514 *validNorm = true; << 515 n->set(0., 0., std::copysign(1., pzcut)) << 516 } << 517 return 0.; << 518 } << 519 474 520 // Check if point is flying away relative to << 475 // check to see if Z plane is relevant 521 // 476 // 522 G4double px = p.x() * fSx; << 477 if (v.z() < 0.0) 523 G4double py = p.y() * fSy; << 524 G4double vx = v.x() * fSx; << 525 G4double vy = v.y() * fSy; << 526 G4double rr = px * px + py * py + pz * pz; << 527 G4double pv = px * vx + py * vy + pz * vz; << 528 G4double distR = fQ1 * rr - fQ2; << 529 if (distR >= -halfTolerance && pv > 0.) << 530 { 478 { 531 if (calcNorm) << 479 G4double distZ = (zBottomCut - p.z()) / v.z(); >> 480 if (distZ < 0.0) 532 { 481 { 533 *validNorm = true; << 482 distZ= 0.0; 534 *n = G4ThreeVector(px*fSx, py*fSy, pz*fS << 483 if (!calcNorm) {return 0.0;} 535 } 484 } 536 return 0.; << 485 distMin= distZ; >> 486 surface= kPlaneSurf; 537 } 487 } 538 << 488 if (v.z() > 0.0) 539 // Just in case check if point is outside (n << 540 // << 541 if (std::max(distZ, distR) > halfTolerance) << 542 { 489 { 543 #ifdef G4SPECSDEBUG << 490 G4double distZ = (zTopCut - p.z()) / v.z(); 544 std::ostringstream message; << 491 if (distZ < 0.0) 545 G4long oldprc = message.precision(16); << 546 message << "Point p is outside (!?) of sol << 547 << GetName() << G4endl; << 548 message << "Position: " << p << G4endl;; << 549 message << "Direction: " << v; << 550 G4cout.precision(oldprc); << 551 G4Exception("G4Ellipsoid::DistanceToOut(p, << 552 JustWarning, message ); << 553 DumpInfo(); << 554 #endif << 555 if (calcNorm) << 556 { 492 { 557 *validNorm = true; << 493 distZ= 0.0; 558 *n = ApproxSurfaceNormal(p); << 494 if (!calcNorm) {return 0.0;} 559 } 495 } 560 return 0.; << 496 distMin= distZ; >> 497 surface= kPlaneSurf; 561 } 498 } 562 499 563 // Set coefficients of quadratic equation: A << 500 // normal vector: parallel to normal, magnitude 1/(characteristic radius) >> 501 // >> 502 G4ThreeVector nearnorm(p.x()/(xSemiAxis*xSemiAxis), >> 503 p.y()/(ySemiAxis*ySemiAxis), >> 504 p.z()/(zSemiAxis*zSemiAxis)); >> 505 >> 506 // now check curved surface intercept 564 // 507 // 565 G4double A = vx * vx + vy * vy + vz * vz; << 508 G4double A,B,C; 566 G4double B = pv; << 509 567 G4double C = rr - fR * fR; << 510 A= sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) + sqr(v.z()/zSemiAxis); 568 G4double D = B * B - A * C; << 511 C= (p * nearnorm) - 1.0; 569 // It is expected that the point is located << 512 B= 2.0 * (v * nearnorm); 570 // max term in the expression for discrimina << 571 // max calculation error can be derived as f << 572 // A * (1 + 2e) * R^2 * (1 + 2e) = A * R^2 + << 573 G4double EPS = 4. * A * fR * fR * DBL_EPSILO << 574 513 575 if (D <= EPS) // no intersection << 514 C= B*B - 4.0*A*C; >> 515 if (C > 0.0) 576 { 516 { 577 if (calcNorm) << 517 G4double distR= (-B + std::sqrt(C) ) / (2.0*A); >> 518 if (distR < 0.0) 578 { 519 { 579 *validNorm = true; << 520 distR= 0.0; 580 *n = G4ThreeVector(px*fSx, py*fSy, pz*fS << 521 if (!calcNorm) {return 0.0;} >> 522 } >> 523 if (distR < distMin) >> 524 { >> 525 distMin= distR; >> 526 surface= kCurvedSurf; 581 } 527 } 582 return 0.; << 583 } 528 } 584 529 585 // Find intersection with Z cuts << 530 // set normal if requested 586 // << 587 G4double tzmax = (vz == 0.) ? DBL_MAX : (std << 588 << 589 // Find intersection with lateral surface << 590 // 531 // 591 G4double tmp = -B - std::copysign(std::sqrt( << 592 G4double trmax = (tmp < 0.) ? C/tmp : tmp/A; << 593 << 594 // Find distance and set normal, if required << 595 // << 596 G4double tmax = std::min(tzmax, trmax); << 597 //if (tmax < halfTolerance) tmax = 0.; << 598 << 599 if (calcNorm) 532 if (calcNorm) 600 { 533 { 601 *validNorm = true; << 534 if (surface == kNoSurf) 602 if (tmax == tzmax) << 603 { 535 { 604 G4double pznew = pz + tmax * vz; << 536 *validNorm = false; 605 n->set(0., 0., (pznew > fZMidCut) ? 1. : << 606 } 537 } 607 else 538 else 608 { 539 { 609 G4double nx = (px + tmax * vx) * fSx; << 540 *validNorm = true; 610 G4double ny = (py + tmax * vy) * fSy; << 541 switch (surface) 611 G4double nz = (pz + tmax * vz) * fSz; << 542 { 612 *n = G4ThreeVector(nx, ny, nz).unit(); << 543 case kPlaneSurf: >> 544 *n= G4ThreeVector(0.,0.,(v.z() > 0.0 ? 1. : -1.)); >> 545 break; >> 546 case kCurvedSurf: >> 547 { >> 548 G4ThreeVector pexit= p + distMin*v; >> 549 G4ThreeVector truenorm(pexit.x()/(xSemiAxis*xSemiAxis), >> 550 pexit.y()/(ySemiAxis*ySemiAxis), >> 551 pexit.z()/(zSemiAxis*zSemiAxis)); >> 552 truenorm *= 1.0/truenorm.mag(); >> 553 *n= truenorm; >> 554 } break; >> 555 default: // Should never reach this case ... >> 556 DumpInfo(); >> 557 std::ostringstream message; >> 558 G4int oldprc = message.precision(16); >> 559 message << "Undefined side for valid surface normal to solid." >> 560 << G4endl >> 561 << "Position:" << G4endl >> 562 << " p.x() = " << p.x()/mm << " mm" << G4endl >> 563 << " p.y() = " << p.y()/mm << " mm" << G4endl >> 564 << " p.z() = " << p.z()/mm << " mm" << G4endl >> 565 << "Direction:" << G4endl << G4endl >> 566 << " v.x() = " << v.x() << G4endl >> 567 << " v.y() = " << v.y() << G4endl >> 568 << " v.z() = " << v.z() << G4endl >> 569 << "Proposed distance :" << G4endl >> 570 << " distMin = " << distMin/mm << " mm"; >> 571 message.precision(oldprc); >> 572 G4Exception("G4Ellipsoid::DistanceToOut(p,v,..)", >> 573 "GeomSolids1002", JustWarning, message); >> 574 break; >> 575 } 613 } 576 } 614 } 577 } 615 return tmax; << 578 >> 579 return distMin; 616 } 580 } 617 581 618 ////////////////////////////////////////////// << 582 /////////////////////////////////////////////////////////////////////////////// 619 // 583 // 620 // Estimate distance to surface from inside << 584 // Calculate distance (<=actual) to closest surface of shape from inside 621 585 622 G4double G4Ellipsoid::DistanceToOut(const G4Th 586 G4double G4Ellipsoid::DistanceToOut(const G4ThreeVector& p) const 623 { 587 { 624 // Safety distance in z direction << 588 G4double distR, distZ; 625 G4double distZ = std::min(fZTopCut - p.z(), << 626 589 627 // Safety distance to lateral surface << 590 #ifdef G4SPECSDEBUG 628 G4double x = p.x() * fSx; << 591 if( Inside(p) == kOutside ) 629 G4double y = p.y() * fSy; << 592 { 630 G4double z = p.z() * fSz; << 593 DumpInfo(); 631 G4double distR = fR - std::sqrt(x*x + y*y + << 594 std::ostringstream message; 632 << 595 G4int oldprc = message.precision(16); 633 // Return safety to out << 596 message << "Point p is outside !?" << G4endl 634 G4double dist = std::min(distZ, distR); << 597 << "Position:" << G4endl 635 return (dist < 0.) ? 0. : dist; << 598 << " p.x() = " << p.x()/mm << " mm" << G4endl >> 599 << " p.y() = " << p.y()/mm << " mm" << G4endl >> 600 << " p.z() = " << p.z()/mm << " mm"; >> 601 message.precision(oldprc) ; >> 602 G4Exception("G4Ellipsoid::DistanceToOut(p)", "GeomSolids1002", >> 603 JustWarning, message); >> 604 } >> 605 #endif >> 606 >> 607 // Normal vector: parallel to normal, magnitude 1/(characteristic radius) >> 608 // >> 609 G4ThreeVector norm(p.x()/(xSemiAxis*xSemiAxis), >> 610 p.y()/(ySemiAxis*ySemiAxis), >> 611 p.z()/(zSemiAxis*zSemiAxis)); >> 612 >> 613 // the following is a safe inlined "radius= min(1.0/norm.mag(),p.mag()) >> 614 // >> 615 G4double radius= p.mag(); >> 616 G4double tmp= norm.mag(); >> 617 if ( (tmp > 0.0) && (1.0 < radius*tmp) ) {radius = 1.0/tmp;} >> 618 >> 619 // Approximate distance to curved surface ( <= actual distance ) >> 620 // >> 621 distR = (1.0 - p*norm) * radius / 2.0; >> 622 >> 623 // Distance to z-cut plane >> 624 // >> 625 distZ = p.z() - zBottomCut; >> 626 if (distZ < 0.0) {distZ= zTopCut - p.z();} >> 627 >> 628 // Distance to closest surface from inside >> 629 // >> 630 if ( (distZ < 0.0) || (distR < 0.0) ) >> 631 { >> 632 return 0.0; >> 633 } >> 634 else >> 635 { >> 636 return (distZ < distR) ? distZ : distR; >> 637 } 636 } 638 } 637 639 638 ////////////////////////////////////////////// 640 ////////////////////////////////////////////////////////////////////////// 639 // 641 // 640 // Return entity type << 642 // G4EntityType 641 643 642 G4GeometryType G4Ellipsoid::GetEntityType() co 644 G4GeometryType G4Ellipsoid::GetEntityType() const 643 { 645 { 644 return {"G4Ellipsoid"}; << 646 return G4String("G4Ellipsoid"); 645 } 647 } 646 648 647 ////////////////////////////////////////////// 649 ////////////////////////////////////////////////////////////////////////// 648 // 650 // 649 // Make a clone of the object 651 // Make a clone of the object 650 652 651 G4VSolid* G4Ellipsoid::Clone() const 653 G4VSolid* G4Ellipsoid::Clone() const 652 { 654 { 653 return new G4Ellipsoid(*this); 655 return new G4Ellipsoid(*this); 654 } 656 } 655 657 656 ////////////////////////////////////////////// 658 ////////////////////////////////////////////////////////////////////////// 657 // 659 // 658 // Stream object contents to output stream << 660 // Stream object contents to an output stream 659 661 660 std::ostream& G4Ellipsoid::StreamInfo( std::os 662 std::ostream& G4Ellipsoid::StreamInfo( std::ostream& os ) const 661 { 663 { 662 G4long oldprc = os.precision(16); << 664 G4int oldprc = os.precision(16); 663 os << "------------------------------------- 665 os << "-----------------------------------------------------------\n" 664 << " *** Dump for solid - " << GetName 666 << " *** Dump for solid - " << GetName() << " ***\n" 665 << " ================================= 667 << " ===================================================\n" 666 << " Solid type: " << GetEntityType() << << 668 << " Solid type: G4Ellipsoid\n" 667 << " Parameters: \n" 669 << " Parameters: \n" 668 << " semi-axis x: " << GetDx()/mm << " << 670 669 << " semi-axis y: " << GetDy()/mm << " << 671 << " semi-axis x: " << xSemiAxis/mm << " mm \n" 670 << " semi-axis z: " << GetDz()/mm << " << 672 << " semi-axis y: " << ySemiAxis/mm << " mm \n" 671 << " lower cut in z: " << GetZBottomCu << 673 << " semi-axis z: " << zSemiAxis/mm << " mm \n" 672 << " upper cut in z: " << GetZTopCut() << 674 << " max semi-axis: " << semiAxisMax/mm << " mm \n" >> 675 << " lower cut plane level z: " << zBottomCut/mm << " mm \n" >> 676 << " upper cut plane level z: " << zTopCut/mm << " mm \n" 673 << "------------------------------------- 677 << "-----------------------------------------------------------\n"; 674 os.precision(oldprc); 678 os.precision(oldprc); 675 return os; << 676 } << 677 << 678 ////////////////////////////////////////////// << 679 // << 680 // Return volume << 681 679 682 G4double G4Ellipsoid::GetCubicVolume() << 680 return os; 683 { << 684 if (fCubicVolume == 0.) << 685 { << 686 G4double piAB_3 = CLHEP::pi * fDx * fDy / << 687 fCubicVolume = 4. * piAB_3 * fDz; << 688 if (fZBottomCut > -fDz) << 689 { << 690 G4double hbot = 1. + fZBottomCut / fDz; << 691 fCubicVolume -= piAB_3 * hbot * hbot * ( << 692 } << 693 if (fZTopCut < fDz) << 694 { << 695 G4double htop = 1. - fZTopCut / fDz; << 696 fCubicVolume -= piAB_3 * htop * htop * ( << 697 } << 698 } << 699 return fCubicVolume; << 700 } 681 } 701 682 702 ////////////////////////////////////////////// << 683 //////////////////////////////////////////////////////////////////// 703 // 684 // 704 // Calculate area of lateral surface << 685 // GetPointOnSurface 705 686 706 G4double G4Ellipsoid::LateralSurfaceArea() con << 687 G4ThreeVector G4Ellipsoid::GetPointOnSurface() const 707 { 688 { 708 constexpr G4int NPHI = 1000.; << 689 G4double aTop, aBottom, aCurved, chose, xRand, yRand, zRand, phi; 709 constexpr G4double dPhi = CLHEP::halfpi/NPHI << 690 G4double cosphi, sinphi, costheta, sintheta, alpha, beta, max1, max2, max3; 710 constexpr G4double eps = 4.*DBL_EPSILON; << 711 << 712 G4double aa = fDx*fDx; << 713 G4double bb = fDy*fDy; << 714 G4double cc = fDz*fDz; << 715 G4double ab = fDx*fDy; << 716 G4double cc_aa = cc/aa; << 717 G4double cc_bb = cc/bb; << 718 G4double zmax = std::min(fZTopCut, fDz); << 719 G4double zmin = std::max(fZBottomCut,-fDz); << 720 G4double zmax_c = zmax/fDz; << 721 G4double zmin_c = zmin/fDz; << 722 G4double area = 0.; << 723 << 724 if (aa == bb) // spheroid, use analytical ex << 725 { << 726 G4double k = fDz/fDx; << 727 G4double kk = k*k; << 728 if (kk < 1. - eps) << 729 { << 730 G4double invk = fDx/fDz; << 731 G4double root = std::sqrt(1. - kk); << 732 G4double tmax = zmax_c*root; << 733 G4double tmin = zmin_c*root; << 734 area = CLHEP::pi*ab* << 735 ((zmax_c*std::sqrt(kk + tmax*tmax) - z << 736 (std::asinh(tmax*invk) - std::asinh(t << 737 } << 738 else if (kk > 1. + eps) << 739 { << 740 G4double invk = fDx/fDz; << 741 G4double root = std::sqrt(kk - 1.); << 742 G4double tmax = zmax_c*root; << 743 G4double tmin = zmin_c*root; << 744 area = CLHEP::pi*ab* << 745 ((zmax_c*std::sqrt(kk - tmax*tmax) - z << 746 (std::asin(tmax*invk) - std::asin(tmi << 747 } << 748 else << 749 { << 750 area = CLHEP::twopi*fDx*(zmax - zmin); << 751 } << 752 return area; << 753 } << 754 691 755 // ellipsoid, integration along phi << 692 max1 = xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis; 756 for (G4int i = 0; i < NPHI; ++i) << 693 max1 = max1 > zSemiAxis ? max1 : zSemiAxis; 757 { << 694 if (max1 == xSemiAxis) { max2 = ySemiAxis; max3 = zSemiAxis; } 758 G4double sinPhi = std::sin(dPhi*(i + 0.5)) << 695 else if (max1 == ySemiAxis) { max2 = xSemiAxis; max3 = zSemiAxis; } 759 G4double kk = cc_aa + (cc_bb - cc_aa)*sinP << 696 else { max2 = xSemiAxis; max3 = ySemiAxis; } 760 if (kk < 1. - eps) << 697 761 { << 698 phi = G4RandFlat::shoot(0.,twopi); 762 G4double root = std::sqrt(1. - kk); << 699 763 G4double tmax = zmax_c*root; << 700 cosphi = std::cos(phi); sinphi = std::sin(phi); 764 G4double tmin = zmin_c*root; << 701 costheta = G4RandFlat::shoot(zBottomCut,zTopCut)/zSemiAxis; 765 G4double invk = 1./std::sqrt(kk); << 702 sintheta = std::sqrt(1.-sqr(costheta)); 766 area += 2.*ab*dPhi* << 703 767 ((zmax_c*std::sqrt(kk + tmax*tmax) - z << 704 alpha = 1.-sqr(max2/max1); beta = 1.-sqr(max3/max1); 768 (std::asinh(tmax*invk) - std::asinh(t << 705 769 } << 706 aTop = pi*xSemiAxis*ySemiAxis*(1 - sqr(zTopCut/zSemiAxis)); 770 else if (kk > 1. + eps) << 707 aBottom = pi*xSemiAxis*ySemiAxis*(1 - sqr(zBottomCut/zSemiAxis)); 771 { << 708 772 G4double root = std::sqrt(kk - 1.); << 709 // approximation 773 G4double tmax = zmax_c*root; << 710 // from:" http://www.citr.auckland.ac.nz/techreports/2004/CITR-TR-139.pdf" 774 G4double tmin = zmin_c*root; << 711 aCurved = 4.*pi*max1*max2*(1.-1./6.*(alpha+beta)- 775 G4double invk = 1./std::sqrt(kk); << 712 1./120.*(3.*sqr(alpha)+2.*alpha*beta+3.*sqr(beta))); 776 area += 2.*ab*dPhi* << 713 777 ((zmax_c*std::sqrt(kk - tmax*tmax) - z << 714 aCurved *= 0.5*(1.2*zTopCut/zSemiAxis - 1.2*zBottomCut/zSemiAxis); 778 (std::asin(tmax*invk) - std::asin(tmi << 715 779 } << 716 if( ( zTopCut >= zSemiAxis && zBottomCut <= -1.*zSemiAxis ) 780 else << 717 || ( zTopCut == 0 && zBottomCut ==0 ) ) 781 { << 718 { 782 area += 4.*ab*dPhi*(zmax_c - zmin_c); << 719 aTop = 0; aBottom = 0; 783 } << 720 } >> 721 >> 722 chose = G4RandFlat::shoot(0.,aTop + aBottom + aCurved); >> 723 >> 724 if(chose < aCurved) >> 725 { >> 726 xRand = xSemiAxis*sintheta*cosphi; >> 727 yRand = ySemiAxis*sintheta*sinphi; >> 728 zRand = zSemiAxis*costheta; >> 729 return G4ThreeVector (xRand,yRand,zRand); >> 730 } >> 731 else if(chose >= aCurved && chose < aCurved + aTop) >> 732 { >> 733 xRand = G4RandFlat::shoot(-1.,1.)*xSemiAxis >> 734 * std::sqrt(1-sqr(zTopCut/zSemiAxis)); >> 735 yRand = G4RandFlat::shoot(-1.,1.)*ySemiAxis >> 736 * std::sqrt(1.-sqr(zTopCut/zSemiAxis)-sqr(xRand/xSemiAxis)); >> 737 zRand = zTopCut; >> 738 return G4ThreeVector (xRand,yRand,zRand); 784 } 739 } 785 return area; << 740 else 786 } << 787 << 788 ////////////////////////////////////////////// << 789 // << 790 // Return surface area << 791 << 792 G4double G4Ellipsoid::GetSurfaceArea() << 793 { << 794 if (fSurfaceArea == 0.) << 795 { 741 { 796 G4double piAB = CLHEP::pi * fDx * fDy; << 742 xRand = G4RandFlat::shoot(-1.,1.)*xSemiAxis 797 fSurfaceArea = LateralSurfaceArea(); << 743 * std::sqrt(1-sqr(zBottomCut/zSemiAxis)); 798 if (fZBottomCut > -fDz) << 744 yRand = G4RandFlat::shoot(-1.,1.)*ySemiAxis 799 { << 745 * std::sqrt(1.-sqr(zBottomCut/zSemiAxis)-sqr(xRand/xSemiAxis)); 800 G4double hbot = 1. + fZBottomCut / fDz; << 746 zRand = zBottomCut; 801 fSurfaceArea += piAB * hbot * (2. - hbot << 747 return G4ThreeVector (xRand,yRand,zRand); 802 } << 803 if (fZTopCut < fDz) << 804 { << 805 G4double htop = 1. - fZTopCut / fDz; << 806 fSurfaceArea += piAB * htop * (2. - htop << 807 } << 808 } 748 } 809 return fSurfaceArea; << 810 } 749 } 811 750 812 ////////////////////////////////////////////// << 751 ///////////////////////////////////////////////////////////////////////////// 813 // << 814 // Return random point on surface << 815 << 816 G4ThreeVector G4Ellipsoid::GetPointOnSurface() << 817 { << 818 G4double A = GetDx(); << 819 G4double B = GetDy(); << 820 G4double C = GetDz(); << 821 G4double Zbot = GetZBottomCut(); << 822 G4double Ztop = GetZTopCut(); << 823 << 824 // Calculate cut areas << 825 G4double Hbot = 1. + Zbot / C; << 826 G4double Htop = 1. - Ztop / C; << 827 G4double piAB = CLHEP::pi * A * B; << 828 G4double Sbot = piAB * Hbot * (2. - Hbot); << 829 G4double Stop = piAB * Htop * (2. - Htop); << 830 << 831 // Get area of lateral surface << 832 if (fLateralArea == 0.) << 833 { << 834 G4AutoLock l(&lateralareaMutex); << 835 fLateralArea = LateralSurfaceArea(); << 836 l.unlock(); << 837 } << 838 G4double Slat = fLateralArea; << 839 << 840 // Select surface (0 - bottom cut, 1 - later << 841 G4double select = (Sbot + Slat + Stop) * G4Q << 842 G4int k = 0; << 843 if (select > Sbot) k = 1; << 844 if (select > Sbot + Slat) k = 2; << 845 << 846 // Pick random point on selected surface (re << 847 G4ThreeVector p; << 848 switch (k) << 849 { << 850 case 0: // bootom z-cut << 851 { << 852 G4double scale = std::sqrt(Hbot * (2. - << 853 G4TwoVector rho = G4RandomPointInEllipse << 854 p.set(rho.x(), rho.y(), Zbot); << 855 break; << 856 } << 857 case 1: // lateral surface << 858 { << 859 G4double x, y, z; << 860 G4double mu_max = std::max(std::max(A * << 861 for (G4int i = 0; i < 1000; ++i) << 862 { << 863 // generate random point on unit spher << 864 z = (Zbot + (Ztop - Zbot) * G4QuickRan << 865 G4double rho = std::sqrt((1. + z) * (1 << 866 G4double phi = CLHEP::twopi * G4QuickR << 867 x = rho * std::cos(phi); << 868 y = rho * std::sin(phi); << 869 // check acceptance << 870 G4double xbc = x * B * C; << 871 G4double yac = y * A * C; << 872 G4double zab = z * A * B; << 873 G4double mu = std::sqrt(xbc * xbc + y << 874 if (mu_max * G4QuickRand() <= mu) brea << 875 } << 876 p.set(A * x, B * y, C * z); << 877 break; << 878 } << 879 case 2: // top z-cut << 880 { << 881 G4double scale = std::sqrt(Htop * (2. - << 882 G4TwoVector rho = G4RandomPointInEllipse << 883 p.set(rho.x(), rho.y(), Ztop); << 884 break; << 885 } << 886 } << 887 return p; << 888 } << 889 << 890 ////////////////////////////////////////////// << 891 // 752 // 892 // Methods for visualisation 753 // Methods for visualisation 893 754 894 void G4Ellipsoid::DescribeYourselfTo (G4VGraph 755 void G4Ellipsoid::DescribeYourselfTo (G4VGraphicsScene& scene) const 895 { 756 { 896 scene.AddSolid(*this); 757 scene.AddSolid(*this); 897 } 758 } 898 759 899 ////////////////////////////////////////////// << 900 // << 901 // Return vis extent << 902 << 903 G4VisExtent G4Ellipsoid::GetExtent() const 760 G4VisExtent G4Ellipsoid::GetExtent() const 904 { 761 { 905 return { -fXmax, fXmax, -fYmax, fYmax, fZBot << 762 // Define the sides of the box into which the G4Ellipsoid instance would fit. >> 763 // >> 764 return G4VisExtent (-semiAxisMax, semiAxisMax, >> 765 -semiAxisMax, semiAxisMax, >> 766 -semiAxisMax, semiAxisMax); 906 } 767 } 907 768 908 ////////////////////////////////////////////// << 909 // << 910 // Create polyhedron << 911 << 912 G4Polyhedron* G4Ellipsoid::CreatePolyhedron () 769 G4Polyhedron* G4Ellipsoid::CreatePolyhedron () const 913 { 770 { 914 return new G4PolyhedronEllipsoid(fDx, fDy, f << 771 return new G4PolyhedronEllipsoid(xSemiAxis, ySemiAxis, zSemiAxis, >> 772 zBottomCut, zTopCut); 915 } 773 } 916 774 917 ////////////////////////////////////////////// << 918 // << 919 // Return pointer to polyhedron << 920 << 921 G4Polyhedron* G4Ellipsoid::GetPolyhedron () co 775 G4Polyhedron* G4Ellipsoid::GetPolyhedron () const 922 { 776 { 923 if (fpPolyhedron == nullptr || << 777 if (!fpPolyhedron || 924 fRebuildPolyhedron || 778 fRebuildPolyhedron || 925 fpPolyhedron->GetNumberOfRotationStepsAt 779 fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() != 926 fpPolyhedron->GetNumberOfRotationSteps() 780 fpPolyhedron->GetNumberOfRotationSteps()) 927 { 781 { 928 G4AutoLock l(&polyhedronMutex); 782 G4AutoLock l(&polyhedronMutex); 929 delete fpPolyhedron; 783 delete fpPolyhedron; 930 fpPolyhedron = CreatePolyhedron(); 784 fpPolyhedron = CreatePolyhedron(); 931 fRebuildPolyhedron = false; 785 fRebuildPolyhedron = false; 932 l.unlock(); 786 l.unlock(); 933 } 787 } 934 return fpPolyhedron; 788 return fpPolyhedron; 935 } 789 } 936 << 937 #endif // !defined(G4GEOM_USE_UELLIPSOID) || ! << 938 790