Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer << 3 // * DISCLAIMER * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th << 5 // * The following disclaimer summarizes all the specific disclaimers * 6 // * the Geant4 Collaboration. It is provided << 6 // * of contributors to this software. The specific disclaimers,which * 7 // * conditions of the Geant4 Software License << 7 // * govern, are listed with their locations in: * 8 // * LICENSE and available at http://cern.ch/ << 8 // * http://cern.ch/geant4/license * 9 // * include a list of copyright holders. << 10 // * 9 // * * 11 // * Neither the authors of this software syst 10 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 11 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 12 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 13 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file << 14 // * use. * 16 // * for the full disclaimer and the limitatio << 17 // * 15 // * * 18 // * This code implementation is the result << 16 // * This code implementation is the intellectual property of the * 19 // * technical work of the GEANT4 collaboratio << 17 // * GEANT4 collaboration. * 20 // * By using, copying, modifying or distri << 18 // * By copying, distributing or modifying the Program (or any work * 21 // * any work based on the software) you ag << 19 // * based on the Program) you indicate your acceptance of this * 22 // * use in resulting scientific publicati << 20 // * statement, and all its terms. * 23 // * acceptance of all terms of the Geant4 Sof << 24 // ******************************************* 21 // ******************************************************************** 25 // 22 // 26 // G4EllipticalTube implementation << 27 // 23 // 28 // Author: David C. Williams (davidw@scipp.ucs << 24 // $Id: G4EllipticalTube.cc,v 1.25 2005/11/09 15:04:28 gcosmo Exp $ 29 // Revision: Evgueni Tcherniaev (evgueni.tcher << 25 // GEANT4 tag $Name: geant4-08-00-patch-01 $ >> 26 // >> 27 // >> 28 // -------------------------------------------------------------------- >> 29 // GEANT 4 class source file >> 30 // >> 31 // >> 32 // G4EllipticalTube.cc >> 33 // >> 34 // Implementation of a CSG volume representing a tube with elliptical cross >> 35 // section (geant3 solid 'ELTU') >> 36 // 30 // ------------------------------------------- 37 // -------------------------------------------------------------------- 31 38 32 #include "G4EllipticalTube.hh" 39 #include "G4EllipticalTube.hh" 33 40 34 #if !(defined(G4GEOM_USE_UELLIPTICALTUBE) && d << 35 << 36 #include "G4GeomTools.hh" << 37 #include "G4RandomTools.hh" << 38 #include "G4ClippablePolygon.hh" 41 #include "G4ClippablePolygon.hh" 39 #include "G4AffineTransform.hh" 42 #include "G4AffineTransform.hh" >> 43 #include "G4SolidExtentList.hh" 40 #include "G4VoxelLimits.hh" 44 #include "G4VoxelLimits.hh" 41 #include "G4BoundingEnvelope.hh" << 45 #include "meshdefs.hh" 42 46 43 #include "Randomize.hh" 47 #include "Randomize.hh" 44 48 45 #include "G4VGraphicsScene.hh" 49 #include "G4VGraphicsScene.hh" >> 50 #include "G4Polyhedron.hh" 46 #include "G4VisExtent.hh" 51 #include "G4VisExtent.hh" 47 52 48 #include "G4AutoLock.hh" << 49 << 50 namespace << 51 { << 52 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZE << 53 } << 54 << 55 using namespace CLHEP; 53 using namespace CLHEP; 56 54 57 ////////////////////////////////////////////// << 58 // 55 // 59 // Constructor 56 // Constructor 60 << 57 // 61 G4EllipticalTube::G4EllipticalTube( const G4St << 58 G4EllipticalTube::G4EllipticalTube( const G4String &name, 62 G4do << 59 G4double theDx, 63 G4do << 60 G4double theDy, 64 G4do << 61 G4double theDz ) 65 : G4VSolid(name), fDx(Dx), fDy(Dy), fDz(Dz) << 62 : G4VSolid( name ), fCubicVolume(0.), fpPolyhedron(0) 66 { << 63 { 67 CheckParameters(); << 64 dx = theDx; >> 65 dy = theDy; >> 66 dz = theDz; 68 } 67 } 69 68 70 ////////////////////////////////////////////// << 69 71 // 70 // 72 // Fake default constructor - sets only member 71 // Fake default constructor - sets only member data and allocates memory 73 // for usage restri 72 // for usage restricted to object persistency. 74 << 73 // 75 G4EllipticalTube::G4EllipticalTube( __void__& 74 G4EllipticalTube::G4EllipticalTube( __void__& a ) 76 : G4VSolid(a), halfTolerance(0.), fDx(0.), f << 75 : G4VSolid(a), fCubicVolume(0.), fpPolyhedron(0) 77 fRsph(0.), fDDx(0.), fDDy(0.), fSx(0.), fS << 78 fQ1(0.), fQ2(0.), fScratch(0.) << 79 { 76 { 80 } 77 } 81 78 82 ////////////////////////////////////////////// << 83 // 79 // 84 // Destructor 80 // Destructor 85 << 86 G4EllipticalTube::~G4EllipticalTube() << 87 { << 88 delete fpPolyhedron; fpPolyhedron = nullptr; << 89 } << 90 << 91 ////////////////////////////////////////////// << 92 // 81 // 93 // Copy constructor << 82 G4EllipticalTube::~G4EllipticalTube() {delete fpPolyhedron;} 94 83 95 G4EllipticalTube::G4EllipticalTube(const G4Ell << 96 : G4VSolid(rhs), halfTolerance(rhs.halfToler << 97 fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz), << 98 fCubicVolume(rhs.fCubicVolume), fSurfaceAr << 99 fRsph(rhs.fRsph), fDDx(rhs.fDDx), fDDy(rhs << 100 fSx(rhs.fSx), fSy(rhs.fSy), fR(rhs.fR), << 101 fQ1(rhs.fQ1), fQ2(rhs.fQ2), fScratch(rhs.f << 102 { << 103 } << 104 84 105 ////////////////////////////////////////////// << 106 // 85 // 107 // Assignment operator << 86 // CalculateExtent 108 << 109 G4EllipticalTube& G4EllipticalTube::operator = << 110 { << 111 // Check assignment to self << 112 // << 113 if (this == &rhs) { return *this; } << 114 << 115 // Copy base class data << 116 // << 117 G4VSolid::operator=(rhs); << 118 << 119 // Copy data << 120 // << 121 halfTolerance = rhs.halfTolerance; << 122 fDx = rhs.fDx; << 123 fDy = rhs.fDy; << 124 fDz = rhs.fDz; << 125 fCubicVolume = rhs.fCubicVolume; << 126 fSurfaceArea = rhs.fSurfaceArea; << 127 << 128 fRsph = rhs.fRsph; << 129 fDDx = rhs.fDDx; << 130 fDDy = rhs.fDDy; << 131 fSx = rhs.fSx; << 132 fSy = rhs.fSy; << 133 fR = rhs.fR; << 134 fQ1 = rhs.fQ1; << 135 fQ2 = rhs.fQ2; << 136 fScratch = rhs.fScratch; << 137 << 138 fRebuildPolyhedron = false; << 139 delete fpPolyhedron; fpPolyhedron = nullptr << 140 << 141 return *this; << 142 } << 143 << 144 ////////////////////////////////////////////// << 145 // 87 // 146 // Check dimensions << 88 G4bool >> 89 G4EllipticalTube::CalculateExtent( const EAxis axis, >> 90 const G4VoxelLimits &voxelLimit, >> 91 const G4AffineTransform &transform, >> 92 G4double &min, G4double &max ) const >> 93 { >> 94 G4SolidExtentList extentList( axis, voxelLimit ); >> 95 >> 96 // >> 97 // We are going to divide up our elliptical face into small >> 98 // pieces >> 99 // >> 100 >> 101 // >> 102 // Choose phi size of our segment(s) based on constants as >> 103 // defined in meshdefs.hh >> 104 // >> 105 G4int numPhi = kMaxMeshSections; >> 106 G4double sigPhi = twopi/numPhi; >> 107 >> 108 // >> 109 // We have to be careful to keep our segments completely outside >> 110 // of the elliptical surface. To do so we imagine we have >> 111 // a simple (unit radius) circular cross section (as in G4Tubs) >> 112 // and then "stretch" the dimensions as necessary to fit the ellipse. >> 113 // >> 114 G4double rFudge = 1.0/std::cos(0.5*sigPhi); >> 115 G4double dxFudge = dx*rFudge, >> 116 dyFudge = dy*rFudge; >> 117 >> 118 // >> 119 // As we work around the elliptical surface, we build >> 120 // a "phi" segment on the way, and keep track of two >> 121 // additional polygons for the two ends. >> 122 // >> 123 G4ClippablePolygon endPoly1, endPoly2, phiPoly; >> 124 >> 125 G4double phi = 0, >> 126 cosPhi = std::cos(phi), >> 127 sinPhi = std::sin(phi); >> 128 G4ThreeVector v0( dxFudge*cosPhi, dyFudge*sinPhi, +dz ), >> 129 v1( dxFudge*cosPhi, dyFudge*sinPhi, -dz ), >> 130 w0, w1; >> 131 transform.ApplyPointTransform( v0 ); >> 132 transform.ApplyPointTransform( v1 ); >> 133 do >> 134 { >> 135 phi += sigPhi; >> 136 if (numPhi == 1) phi = 0; // Try to avoid roundoff >> 137 cosPhi = std::cos(phi), >> 138 sinPhi = std::sin(phi); >> 139 >> 140 w0 = G4ThreeVector( dxFudge*cosPhi, dyFudge*sinPhi, +dz ); >> 141 w1 = G4ThreeVector( dxFudge*cosPhi, dyFudge*sinPhi, -dz ); >> 142 transform.ApplyPointTransform( w0 ); >> 143 transform.ApplyPointTransform( w1 ); >> 144 >> 145 // >> 146 // Add a point to our z ends >> 147 // >> 148 endPoly1.AddVertexInOrder( v0 ); >> 149 endPoly2.AddVertexInOrder( v1 ); >> 150 >> 151 // >> 152 // Build phi polygon >> 153 // >> 154 phiPoly.ClearAllVertices(); >> 155 >> 156 phiPoly.AddVertexInOrder( v0 ); >> 157 phiPoly.AddVertexInOrder( v1 ); >> 158 phiPoly.AddVertexInOrder( w1 ); >> 159 phiPoly.AddVertexInOrder( w0 ); >> 160 >> 161 if (phiPoly.PartialClip( voxelLimit, axis )) >> 162 { >> 163 // >> 164 // Get unit normal >> 165 // >> 166 phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() ); >> 167 >> 168 extentList.AddSurface( phiPoly ); >> 169 } >> 170 >> 171 // >> 172 // Next vertex >> 173 // >> 174 v0 = w0; >> 175 v1 = w1; >> 176 } while( --numPhi > 0 ); 147 177 148 void G4EllipticalTube::CheckParameters() << 149 { << 150 // Check dimensions << 151 // 178 // 152 halfTolerance = 0.5*kCarTolerance; // half t << 179 // Process the end pieces 153 G4double dmin = 2*kCarTolerance; << 180 // 154 if (fDx < dmin || fDy < dmin || fDz < dmin) << 181 if (endPoly1.PartialClip( voxelLimit, axis )) 155 { 182 { 156 std::ostringstream message; << 183 static const G4ThreeVector normal(0,0,+1); 157 message << "Invalid (too small or negative << 184 endPoly1.SetNormal( transform.TransformAxis(normal) ); 158 << GetName() << 185 extentList.AddSurface( endPoly1 ); 159 << "\n Dx = " << fDx << 160 << "\n Dy = " << fDy << 161 << "\n Dz = " << fDz; << 162 G4Exception("G4EllipticalTube::CheckParame << 163 FatalException, message); << 164 } 186 } 165 << 187 166 // Set pre-calculatated values << 188 if (endPoly2.PartialClip( voxelLimit, axis )) >> 189 { >> 190 static const G4ThreeVector normal(0,0,-1); >> 191 endPoly2.SetNormal( transform.TransformAxis(normal) ); >> 192 extentList.AddSurface( endPoly2 ); >> 193 } >> 194 167 // 195 // 168 halfTolerance = 0.5*kCarTolerance; // half t << 196 // Return min/max value 169 fRsph = std::sqrt(fDx * fDx + fDy * fDy + fD << 197 // 170 fDDx = fDx * fDx; // X semi-axis squared << 198 return extentList.GetExtent( min, max ); 171 fDDy = fDy * fDy; // Y semi-axis squared << 172 << 173 fR = std::min(fDx, fDy); // resulting radius << 174 fSx = fR / fDx; // X scale factor << 175 fSy = fR / fDy; // Y scale factor << 176 << 177 fQ1 = 0.5 / fR; // distance approxiamtion di << 178 fQ2 = 0.5 * (fR + halfTolerance * halfTolera << 179 fScratch = 2. * fR * fR * DBL_EPSILON; // sc << 180 // fScratch = (B * B / A) * (2. + halfTolera << 181 } 199 } 182 200 183 ////////////////////////////////////////////// << 184 // << 185 // Get bounding box << 186 201 187 void G4EllipticalTube::BoundingLimits( G4Three << 202 // 188 G4Three << 203 // Inside >> 204 // >> 205 // Note that for this solid, we've decided to define the tolerant >> 206 // surface as that which is bounded by ellipses with axes >> 207 // at +/- 0.5*kCarTolerance. >> 208 // >> 209 EInside G4EllipticalTube::Inside( const G4ThreeVector& p ) const 189 { 210 { 190 pMin.set(-fDx,-fDy,-fDz); << 211 static const G4double halfTol = 0.5*kCarTolerance; 191 pMax.set( fDx, fDy, fDz); << 212 >> 213 // >> 214 // Check z extents: are we outside? >> 215 // >> 216 G4double absZ = std::fabs(p.z()); >> 217 if (absZ > dz+halfTol) return kOutside; >> 218 >> 219 // >> 220 // Check x,y: are we outside? >> 221 // >> 222 // G4double x = p.x(), y = p.y(); >> 223 >> 224 if (CheckXY(p.x(), p.y(), +halfTol) > 1.0) return kOutside; >> 225 >> 226 // >> 227 // We are either inside or on the surface: recheck z extents >> 228 // >> 229 if (absZ > dz-halfTol) return kSurface; >> 230 >> 231 // >> 232 // Recheck x,y >> 233 // >> 234 if (CheckXY(p.x(), p.y(), -halfTol) > 1.0) return kSurface; >> 235 >> 236 return kInside; 192 } 237 } 193 238 194 ////////////////////////////////////////////// << 195 // << 196 // Calculate extent under transform and specif << 197 239 198 G4bool << 240 // 199 G4EllipticalTube::CalculateExtent( const EAxis << 241 // SurfaceNormal 200 const G4Vox << 242 // 201 const G4Aff << 243 G4ThreeVector G4EllipticalTube::SurfaceNormal( const G4ThreeVector& p ) const 202 G4dou << 203 { 244 { 204 G4ThreeVector bmin, bmax; << 205 G4bool exist; << 206 << 207 // Check bounding box (bbox) << 208 // 245 // 209 BoundingLimits(bmin,bmax); << 246 // Which of the three surfaces are we closest to (approximately)? 210 G4BoundingEnvelope bbox(bmin,bmax); << 211 #ifdef G4BBOX_EXTENT << 212 return bbox.CalculateExtent(pAxis,pVoxelLimi << 213 #endif << 214 if (bbox.BoundingBoxVsVoxelLimits(pAxis, pVo << 215 { << 216 return exist = pMin < pMax; << 217 } << 218 << 219 G4double dx = fDx; << 220 G4double dy = fDy; << 221 G4double dz = fDz; << 222 << 223 // Set bounding envelope (benv) and calculat << 224 // 247 // 225 const G4int NSTEPS = 24; // number of steps << 248 G4double distZ = std::fabs(p.z()) - dz; 226 G4double ang = twopi/NSTEPS; << 249 227 << 250 G4double rxy = CheckXY( p.x(), p.y() ); 228 G4double sinHalf = std::sin(0.5*ang); << 251 G4double distR2 = (rxy < DBL_MIN) ? DBL_MAX : 1.0/rxy; 229 G4double cosHalf = std::cos(0.5*ang); << 230 G4double sinStep = 2.*sinHalf*cosHalf; << 231 G4double cosStep = 1. - 2.*sinHalf*sinHalf; << 232 G4double sx = dx/cosHalf; << 233 G4double sy = dy/cosHalf; << 234 << 235 G4double sinCur = sinHalf; << 236 G4double cosCur = cosHalf; << 237 G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS << 238 for (G4int k=0; k<NSTEPS; ++k) << 239 { << 240 baseA[k].set(sx*cosCur,sy*sinCur,-dz); << 241 baseB[k].set(sx*cosCur,sy*sinCur, dz); << 242 252 243 G4double sinTmp = sinCur; << 253 // 244 sinCur = sinCur*cosStep + cosCur*sinStep; << 254 // Closer to z? 245 cosCur = cosCur*cosStep - sinTmp*sinStep; << 255 // 246 } << 256 if (distZ*distZ < distR2) >> 257 return G4ThreeVector( 0.0, 0.0, p.z() < 0 ? -1.0 : 1.0 ); 247 258 248 std::vector<const G4ThreeVectorList *> polyg << 259 // 249 polygons[0] = &baseA; << 260 // Closer to x/y 250 polygons[1] = &baseB; << 261 // 251 G4BoundingEnvelope benv(bmin, bmax, polygons << 262 return G4ThreeVector( p.x()*dy*dy, p.y()*dx*dx, 0.0 ).unit(); 252 exist = benv.CalculateExtent(pAxis, pVoxelLi << 253 return exist; << 254 } 263 } 255 264 256 ////////////////////////////////////////////// << 265 257 // 266 // 258 // Determine where is point: inside, outside o << 267 // DistanceToIn(p,v) 259 // 268 // 260 << 269 // Unlike DistanceToOut(p,v), it is possible for the trajectory 261 EInside G4EllipticalTube::Inside( const G4Thre << 270 // to miss. The geometric calculations here are quite simple. 262 { << 271 // More difficult is the logic required to prevent particles 263 G4double x = p.x() * fSx; << 272 // from sneaking (or leaking) between the elliptical and end 264 G4double y = p.y() * fSy; << 273 // surfaces. 265 G4double distR = fQ1 * (x * x + y * y) - fQ2 << 266 G4double distZ = std::abs(p.z()) - fDz; << 267 G4double dist = std::max(distR, distZ); << 268 << 269 if (dist > halfTolerance) return kOutside; << 270 return (dist > -halfTolerance) ? kSurface : << 271 } << 272 << 273 ////////////////////////////////////////////// << 274 // 274 // 275 // Return unit normal at surface closest to p << 275 // Keep in mind that the true distance is allowed to be 276 << 276 // negative if the point is currently on the surface. For oblique 277 G4ThreeVector G4EllipticalTube::SurfaceNormal( << 277 // angles, it can be very negative. >> 278 // >> 279 G4double G4EllipticalTube::DistanceToIn( const G4ThreeVector& p, >> 280 const G4ThreeVector& v ) const 278 { 281 { 279 G4ThreeVector norm(0, 0, 0); << 282 static const G4double halfTol = 0.5*kCarTolerance; 280 G4int nsurf = 0; << 283 >> 284 // >> 285 // Check z = -dz planer surface >> 286 // >> 287 G4double sigz = p.z()+dz; 281 288 282 // check lateral surface << 289 if (sigz < halfTol) 283 G4double x = p.x() * fSx; << 284 G4double y = p.y() * fSy; << 285 G4double distR = fQ1 * (x * x + y * y) - fQ2 << 286 if (std::abs(distR) <= halfTolerance) << 287 { 290 { 288 norm = G4ThreeVector(p.x() * fDDy, p.y() * << 291 // 289 ++nsurf; << 292 // We are "behind" the shape in z, and so can >> 293 // potentially hit the rear face. Correct direction? >> 294 // >> 295 if (v.z() <= 0) >> 296 { >> 297 // >> 298 // As long as we are far enough away, we know we >> 299 // can't intersect >> 300 // >> 301 if (sigz < 0) return kInfinity; >> 302 >> 303 // >> 304 // Otherwise, we don't intersect unless we are >> 305 // on the surface of the ellipse >> 306 // >> 307 if (CheckXY(p.x(),p.y(),-halfTol) <= 1.0) return kInfinity; >> 308 } >> 309 else >> 310 { >> 311 // >> 312 // How far? >> 313 // >> 314 G4double s = -sigz/v.z(); >> 315 >> 316 // >> 317 // Where does that place us? >> 318 // >> 319 G4double xi = p.x() + s*v.x(), >> 320 yi = p.y() + s*v.y(); >> 321 >> 322 // >> 323 // Is this on the surface (within ellipse)? >> 324 // >> 325 if (CheckXY(xi,yi) <= 1.0) >> 326 { >> 327 // >> 328 // Yup. Return s, unless we are on the surface >> 329 // >> 330 return (sigz < -halfTol) ? s : 0; >> 331 } >> 332 else if (xi*dy*dy*v.x() + yi*dx*dx*v.y() >= 0) >> 333 { >> 334 // >> 335 // Else, if we are traveling outwards, we know >> 336 // we must miss >> 337 // >> 338 return kInfinity; >> 339 } >> 340 } 290 } 341 } 291 342 292 // check lateral bases << 343 // 293 G4double distZ = std::abs(p.z()) - fDz; << 344 // Check z = +dz planer surface 294 if (std::abs(distZ) <= halfTolerance) << 345 // >> 346 sigz = p.z() - dz; >> 347 >> 348 if (sigz > -halfTol) 295 { 349 { 296 norm.setZ(p.z() < 0 ? -1. : 1.); << 350 if (v.z() >= 0) 297 ++nsurf; << 351 { >> 352 if (sigz > 0) return kInfinity; >> 353 if (CheckXY(p.x(),p.y(),-halfTol) <= 1.0) return kInfinity; >> 354 } >> 355 else { >> 356 G4double s = -sigz/v.z(); >> 357 >> 358 G4double xi = p.x() + s*v.x(), >> 359 yi = p.y() + s*v.y(); >> 360 >> 361 if (CheckXY(xi,yi) <= 1.0) >> 362 { >> 363 return (sigz > -halfTol) ? s : 0; >> 364 } >> 365 else if (xi*dy*dy*v.x() + yi*dx*dx*v.y() >= 0) >> 366 { >> 367 return kInfinity; >> 368 } >> 369 } 298 } 370 } >> 371 >> 372 // >> 373 // Check intersection with the elliptical tube >> 374 // >> 375 G4double s[2]; >> 376 G4int n = IntersectXY( p, v, s ); >> 377 >> 378 if (n==0) return kInfinity; >> 379 >> 380 // >> 381 // Is the original point on the surface? >> 382 // >> 383 if (std::fabs(p.z()) < dz+halfTol) { >> 384 if (CheckXY( p.x(), p.y(), halfTol ) < 1.0) >> 385 { >> 386 // >> 387 // Well, yes, but are we traveling inwards at this point? >> 388 // >> 389 if (p.x()*dy*dy*v.x() + p.y()*dx*dx*v.y() < 0) return 0; >> 390 } >> 391 } >> 392 >> 393 // >> 394 // We are now certain that point p is not on the surface of >> 395 // the solid (and thus std::fabs(s[0]) > halfTol). >> 396 // Return kInfinity if the intersection is "behind" the point. >> 397 // >> 398 if (s[0] < 0) return kInfinity; >> 399 >> 400 // >> 401 // Check to see if we intersect the tube within >> 402 // dz, but only when we know it might miss >> 403 // >> 404 G4double zi = p.z() + s[0]*v.z(); 299 405 300 // return normal << 406 if (v.z() < 0) 301 if (nsurf == 1) return norm; << 302 else if (nsurf > 1) return norm.unit(); // e << 303 else << 304 { 407 { 305 // Point is not on the surface << 408 if (zi < -dz) return kInfinity; 306 // << 409 } 307 #ifdef G4SPECDEBUG << 410 else if (v.z() > 0) 308 std::ostringstream message; << 411 { 309 G4long oldprc = message.precision(16); << 412 if (zi > +dz) return kInfinity; 310 message << "Point p is not on surface (!?) << 311 << GetName() << G4endl; << 312 message << "Position:\n"; << 313 message << " p.x() = " << p.x()/mm << " << 314 message << " p.y() = " << p.y()/mm << " << 315 message << " p.z() = " << p.z()/mm << " << 316 G4cout.precision(oldprc); << 317 G4Exception("G4EllipticalTube::SurfaceNorm << 318 JustWarning, message ); << 319 DumpInfo(); << 320 #endif << 321 return ApproxSurfaceNormal(p); << 322 } 413 } 323 } << 324 414 325 ////////////////////////////////////////////// << 415 return s[0]; 326 // << 327 // Find surface nearest to point and return co << 328 // The algorithm is similar to the algorithm u << 329 // This method normally should not be called. << 330 << 331 G4ThreeVector << 332 G4EllipticalTube::ApproxSurfaceNormal( const G << 333 { << 334 G4double x = p.x() * fSx; << 335 G4double y = p.y() * fSy; << 336 G4double distR = fQ1 * (x * x + y * y) - fQ2 << 337 G4double distZ = std::abs(p.z()) - fDz; << 338 if (distR > distZ && (x * x + y * y) > 0) << 339 return G4ThreeVector(p.x() * fDDy, p.y() * << 340 else << 341 return {0, 0, (p.z() < 0 ? -1. : 1.)}; << 342 } 416 } 343 417 344 ////////////////////////////////////////////// << 345 // << 346 // Calculate distance to shape from outside, a << 347 // return kInfinity if no intersection, or dis << 348 418 349 G4double G4EllipticalTube::DistanceToIn( const << 419 // 350 const << 420 // DistanceToIn(p) >> 421 // >> 422 // The distance from a point to an ellipse (in 2 dimensions) is a >> 423 // surprisingly complicated quadric expression (this is easy to >> 424 // appreciate once one understands that there may be up to >> 425 // four lines normal to the ellipse intersecting any point). To >> 426 // solve it exactly would be rather time consuming. This method, >> 427 // however, is supposed to be a quick check, and is allowed to be an >> 428 // underestimate. >> 429 // >> 430 // So, I will use the following underestimate of the distance >> 431 // from an outside point to an ellipse. First: find the intersection "A" >> 432 // of the line from the origin to the point with the ellipse. >> 433 // Find the line passing through "A" and tangent to the ellipse >> 434 // at A. The distance of the point p from the ellipse will be approximated >> 435 // as the distance to this line. >> 436 // >> 437 G4double G4EllipticalTube::DistanceToIn( const G4ThreeVector& p ) const 351 { 438 { 352 G4double offset = 0.; << 439 static const G4double halfTol = 0.5*kCarTolerance; 353 G4ThreeVector pcur = p; << 440 354 << 441 if (CheckXY( p.x(), p.y(), +halfTol ) < 1.0) 355 // Check if point is flying away << 356 // << 357 G4double safex = std::abs(pcur.x()) - fDx; << 358 G4double safey = std::abs(pcur.y()) - fDy; << 359 G4double safez = std::abs(pcur.z()) - fDz; << 360 << 361 if (safez >= -halfTolerance && pcur.z() * v. << 362 if (safey >= -halfTolerance && pcur.y() * v. << 363 if (safex >= -halfTolerance && pcur.x() * v. << 364 << 365 // Relocate point, if required << 366 // << 367 G4double Dmax = 32. * fRsph; << 368 if (std::max(std::max(safex, safey), safez) << 369 { 442 { 370 offset = (1. - 1.e-08) * pcur.mag() - 2. * << 443 // 371 pcur += offset * v; << 444 // We are inside or on the surface of the 372 G4double dist = DistanceToIn(pcur, v); << 445 // elliptical cross section in x/y. Check z 373 return (dist == kInfinity) ? kInfinity : d << 446 // >> 447 if (p.z() < -dz-halfTol) >> 448 return -p.z()-dz; >> 449 else if (p.z() > dz+halfTol) >> 450 return p.z()-dz; >> 451 else >> 452 return 0; // On any surface here (or inside) 374 } 453 } 375 << 454 376 // Scale elliptical tube to cylinder << 377 // 455 // 378 G4double px = pcur.x() * fSx; << 456 // Find point on ellipse 379 G4double py = pcur.y() * fSy; << 380 G4double pz = pcur.z(); << 381 G4double vx = v.x() * fSx; << 382 G4double vy = v.y() * fSy; << 383 G4double vz = v.z(); << 384 << 385 // Set coefficients of quadratic equation: A << 386 // 457 // 387 G4double rr = px * px + py * py; << 458 G4double qnorm = CheckXY( p.x(), p.y() ); 388 G4double A = vx * vx + vy * vy; << 459 if (qnorm < DBL_MIN) return 0; // This should never happen 389 G4double B = px * vx + py * vy; << 460 390 G4double C = rr - fR * fR; << 461 G4double q = 1.0/std::sqrt(qnorm); 391 G4double D = B * B - A * C; << 462 392 << 463 G4double xe = q*p.x(), ye = q*p.y(); 393 // Check if point is flying away relative to << 464 394 // 465 // 395 G4double distR = fQ1 * rr - fQ2; << 466 // Get tangent to ellipse 396 G4bool parallelToZ = (A < DBL_EPSILON || std << 397 if (distR >= -halfTolerance && (B >= 0. || p << 398 << 399 // Find intersection with Z planes << 400 // 467 // 401 G4double invz = (vz == 0) ? DBL_MAX : -1./v << 468 G4double tx = -ye*dx*dx, ty = +xe*dy*dy; 402 G4double dz = std::copysign(fDz, invz); << 469 G4double tnorm = std::sqrt( tx*tx + ty*ty ); 403 G4double tzmin = (pz - dz) * invz; << 470 404 G4double tzmax = (pz + dz) * invz; << 405 << 406 // Solve qudratic equation. There are two ca << 407 // 1) trajectory parallel to Z axis (A = 0 << 408 // 2) touch (D = 0) or no intersection (D << 409 // 471 // 410 if (parallelToZ) return (tzmin<halfTolerance << 472 // Calculate distance 411 if (D <= A * A * fScratch) return kInfinity; << 473 // 412 << 474 G4double distR = ( (p.x()-xe)*ty - (p.y()-ye)*tx )/tnorm; 413 // Find roots of quadratic equation << 475 414 G4double tmp = -B - std::copysign(std::sqrt( << 476 // 415 G4double t1 = tmp / A; << 477 // Add the result in quadrature if we are, in addition, 416 G4double t2 = C / tmp; << 478 // outside the z bounds of the shape 417 G4double trmin = std::min(t1, t2); << 479 // 418 G4double trmax = std::max(t1, t2); << 480 // We could save some time by returning the maximum rather 419 << 481 // than the quadrature sum 420 // Return distance << 482 // 421 G4double tin = std::max(tzmin, trmin); << 483 if (p.z() < -dz) 422 G4double tout = std::min(tzmax, trmax); << 484 return std::sqrt( (p.z()+dz)*(p.z()+dz) + distR*distR ); >> 485 else if (p.z() > dz) >> 486 return std::sqrt( (p.z()-dz)*(p.z()-dz) + distR*distR ); 423 487 424 if (tout <= tin + halfTolerance) return kInf << 488 return distR; 425 return (tin<halfTolerance) ? offset : tin + << 426 } 489 } 427 490 428 ////////////////////////////////////////////// << 429 // << 430 // Estimate distance to the surface from outsi << 431 // returns 0 if point is inside << 432 << 433 G4double G4EllipticalTube::DistanceToIn( const << 434 { << 435 // safety distance to bounding box << 436 G4double distX = std::abs(p.x()) - fDx; << 437 G4double distY = std::abs(p.y()) - fDy; << 438 G4double distZ = std::abs(p.z()) - fDz; << 439 G4double distB = std::max(std::max(distX, di << 440 // return (distB < 0) ? 0 : distB; << 441 << 442 // safety distance to lateral surface << 443 G4double x = p.x() * fSx; << 444 G4double y = p.y() * fSy; << 445 G4double distR = std::sqrt(x * x + y * y) - << 446 << 447 // return SafetyToIn << 448 G4double dist = std::max(distB, distR); << 449 return (dist < 0) ? 0 : dist; << 450 } << 451 << 452 ////////////////////////////////////////////// << 453 // << 454 // Calculate distance to shape from inside and << 455 // at exit point, if required << 456 // - when leaving the surface, return 0 << 457 491 >> 492 // >> 493 // DistanceToOut(p,v) >> 494 // >> 495 // This method can be somewhat complicated for a general shape. >> 496 // For a convex one, like this, there are several simplifications, >> 497 // the most important of which is that one can treat the surfaces >> 498 // as infinite in extent when deciding if the p is on the surface. >> 499 // 458 G4double G4EllipticalTube::DistanceToOut( cons 500 G4double G4EllipticalTube::DistanceToOut( const G4ThreeVector& p, 459 cons 501 const G4ThreeVector& v, 460 cons 502 const G4bool calcNorm, 461 << 503 G4bool *validNorm, 462 << 504 G4ThreeVector *norm ) const 463 { 505 { 464 // Check if point flying away relative to Z << 506 static const G4double halfTol = 0.5*kCarTolerance; >> 507 465 // 508 // 466 G4double pz = p.z(); << 509 // Our normal is always valid 467 G4double vz = v.z(); << 468 G4double distZ = std::abs(pz) - fDz; << 469 if (distZ >= -halfTolerance && pz * vz > 0) << 470 { << 471 if (calcNorm) << 472 { << 473 *validNorm = true; << 474 n->set(0, 0, (pz < 0) ? -1. : 1.); << 475 } << 476 return 0.; << 477 } << 478 G4double tzmax = (vz == 0) ? DBL_MAX : (std: << 479 << 480 // Scale elliptical tube to cylinder << 481 // 510 // 482 G4double px = p.x() * fSx; << 511 if (calcNorm) *validNorm = true; 483 G4double py = p.y() * fSy; << 512 484 G4double vx = v.x() * fSx; << 513 G4double sBest = kInfinity; 485 G4double vy = v.y() * fSy; << 514 const G4ThreeVector *nBest=0; 486 << 515 487 // Check if point is flying away relative to << 488 // 516 // 489 G4double rr = px * px + py * py; << 517 // Might we intersect the -dz surface? 490 G4double B = px * vx + py * vy; << 518 // 491 G4double distR = fQ1 * rr - fQ2; << 519 if (v.z() < 0) 492 if (distR >= -halfTolerance && B > 0.) << 493 { 520 { 494 if (calcNorm) << 521 static const G4ThreeVector normHere(0.0,0.0,-1.0); 495 { << 522 // 496 *validNorm = true; << 523 // Yup. What distance? 497 *n = G4ThreeVector(px * fDDy, py * fDDx, << 524 // >> 525 sBest = -(p.z()+dz)/v.z(); >> 526 >> 527 // >> 528 // Are we on the surface? If so, return zero >> 529 // >> 530 if (p.z() < -dz+halfTol) { >> 531 if (calcNorm) *norm = normHere; >> 532 return 0; 498 } 533 } 499 return 0.; << 534 else >> 535 nBest = &normHere; 500 } 536 } 501 << 537 502 // Just in case check if point is outside, n << 503 // 538 // 504 if (std::max(distZ, distR) > halfTolerance) << 539 // How about the +dz surface? >> 540 // >> 541 if (v.z() > 0) 505 { 542 { 506 #ifdef G4SPECDEBUG << 543 static const G4ThreeVector normHere(0.0,0.0,+1.0); 507 std::ostringstream message; << 544 // 508 G4long oldprc = message.precision(16); << 545 // Yup. What distance? 509 message << "Point p is outside (!?) of sol << 546 // 510 << GetName() << G4endl; << 547 G4double s = (dz-p.z())/v.z(); 511 message << "Position: " << p << G4endl;; << 548 512 message << "Direction: " << v; << 549 // 513 G4cout.precision(oldprc); << 550 // Are we on the surface? If so, return zero 514 G4Exception("G4EllipticalTube::DistanceToO << 551 // 515 JustWarning, message ); << 552 if (p.z() > +dz-halfTol) { 516 DumpInfo(); << 553 if (calcNorm) *norm = normHere; 517 #endif << 554 return 0; 518 if (calcNorm) << 519 { << 520 *validNorm = true; << 521 *n = ApproxSurfaceNormal(p); << 522 } 555 } 523 return 0.; << 556 >> 557 // >> 558 // Best so far? >> 559 // >> 560 if (s < sBest) { sBest = s; nBest = &normHere; } 524 } 561 } 525 << 562 526 // Set coefficients of quadratic equation: A << 527 // 563 // 528 G4double A = vx * vx + vy * vy; << 564 // Check furthest intersection with ellipse 529 G4double C = rr - fR * fR; << 530 G4double D = B * B - A * C; << 531 << 532 // Solve qudratic equation. There are two sp << 533 // 1) trajectory parallel to Z axis (A = 0 << 534 // 2) touch (D = 0) or no intersection (D << 535 // 565 // 536 G4bool parallelToZ = (A < DBL_EPSILON || std << 566 G4double s[2]; 537 if (parallelToZ) // 1) << 567 G4int n = IntersectXY( p, v, s ); >> 568 >> 569 if (n == 0) 538 { 570 { 539 if (calcNorm) << 571 if (sBest == kInfinity) 540 { 572 { 541 *validNorm = true; << 573 G4cout.precision(16) ; 542 n->set(0, 0, (vz < 0) ? -1. : 1.); << 574 G4cout << G4endl ; >> 575 DumpInfo(); >> 576 G4cout << "Position:" << G4endl << G4endl ; >> 577 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ; >> 578 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ; >> 579 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ; >> 580 G4cout << "Direction:" << G4endl << G4endl; >> 581 G4cout << "v.x() = " << v.x() << G4endl; >> 582 G4cout << "v.y() = " << v.y() << G4endl; >> 583 G4cout << "v.z() = " << v.z() << G4endl << G4endl; >> 584 G4cout << "Proposed distance :" << G4endl << G4endl; >> 585 G4cout << "snxt = " << sBest/mm << " mm" << G4endl << G4endl; >> 586 G4Exception( "G4EllipticalTube::DistanceToOut(p,v,...)", >> 587 "Notification", JustWarning, "Point p is outside !?" ); 543 } 588 } 544 return tzmax; << 589 if (calcNorm) *norm = *nBest; >> 590 return sBest; 545 } 591 } 546 if (D <= A * A * fScratch) // 2) << 592 else if (s[n-1] > sBest) 547 { 593 { 548 if (calcNorm) << 594 if (calcNorm) *norm = *nBest; 549 { << 595 return sBest; 550 *validNorm = true; << 596 } 551 *n = G4ThreeVector(px * fDDy, py * fDDx, << 597 sBest = s[n-1]; 552 } << 598 553 return 0.; << 599 // 554 } << 600 // Intersection with ellipse. Get normal at intersection point. 555 << 556 // Find roots of quadratic equation << 557 G4double tmp = -B - std::copysign(std::sqrt( << 558 G4double t1 = tmp / A; << 559 G4double t2 = C / tmp; << 560 G4double trmax = std::max(t1, t2); << 561 << 562 // Return distance << 563 G4double tmax = std::min(tzmax, trmax); << 564 << 565 // Set normal, if required, and return dista << 566 // 601 // 567 if (calcNorm) 602 if (calcNorm) 568 { 603 { 569 *validNorm = true; << 604 G4ThreeVector ip = p + sBest*v; 570 G4ThreeVector pnew = p + tmax * v; << 605 *norm = G4ThreeVector( ip.x()*dy*dy, ip.y()*dx*dx, 0.0 ).unit(); 571 if (tmax == tzmax) << 606 } 572 n->set(0, 0, (pnew.z() < 0) ? -1. : 1.); << 607 573 else << 608 // 574 *n = G4ThreeVector(pnew.x() * fDDy, pnew << 609 // Do we start on the surface? >> 610 // >> 611 if (CheckXY( p.x(), p.y(), -halfTol ) > 1.0) >> 612 { >> 613 // >> 614 // Well, yes, but are we traveling outwards at this point? >> 615 // >> 616 if (p.x()*dy*dy*v.x() + p.y()*dx*dx*v.y() > 0) return 0; 575 } 617 } 576 return tmax; << 618 >> 619 return sBest; 577 } 620 } 578 621 579 ////////////////////////////////////////////// << 622 580 // 623 // 581 // Estimate distance to the surface from insid << 624 // DistanceToOut(p) 582 // returns 0 if point is outside << 625 // >> 626 // See DistanceToIn(p) for notes on the distance from a point >> 627 // to an ellipse in two dimensions. >> 628 // >> 629 // The approximation used here for a point inside the ellipse >> 630 // is to find the intersection with the ellipse of the lines >> 631 // through the point and parallel to the x and y axes. The >> 632 // distance of the point from the line connecting the two >> 633 // intersecting points is then used. 583 // 634 // 584 << 585 G4double G4EllipticalTube::DistanceToOut( cons 635 G4double G4EllipticalTube::DistanceToOut( const G4ThreeVector& p ) const 586 { 636 { 587 #ifdef G4SPECDEBUG << 637 static const G4double halfTol = 0.5*kCarTolerance; 588 if( Inside(p) == kOutside ) << 638 >> 639 // >> 640 // We need to calculate the distances to all surfaces, >> 641 // and then return the smallest >> 642 // >> 643 // Check -dz and +dz surface >> 644 // >> 645 G4double sBest = dz - std::fabs(p.z()); >> 646 if (sBest < halfTol) return 0; >> 647 >> 648 // >> 649 // Check elliptical surface: find intersection of >> 650 // line through p and parallel to x axis >> 651 // >> 652 G4double radical = 1.0 - p.y()*p.y()/dy/dy; >> 653 if (radical < +DBL_MIN) return 0; >> 654 >> 655 G4double xi = dx*std::sqrt( radical ); >> 656 if (p.x() < 0) xi = -xi; >> 657 >> 658 // >> 659 // Do the same with y axis >> 660 // >> 661 radical = 1.0 - p.x()*p.x()/dx/dx; >> 662 if (radical < +DBL_MIN) return 0; >> 663 >> 664 G4double yi = dy*std::sqrt( radical ); >> 665 if (p.y() < 0) yi = -yi; >> 666 >> 667 // >> 668 // Get distance from p to the line connecting >> 669 // these two points >> 670 // >> 671 G4double xdi = p.x() - xi, >> 672 ydi = yi - p.y(); >> 673 >> 674 G4double normi = std::sqrt( xdi*xdi + ydi*ydi ); >> 675 if (normi < halfTol) return 0; >> 676 xdi /= normi; >> 677 ydi /= normi; >> 678 >> 679 G4double s = 0.5*(xdi*(p.y()-yi) - ydi*(p.x()-xi)); >> 680 if (xi*yi < 0) s = -s; >> 681 >> 682 if (s < sBest) sBest = s; >> 683 >> 684 // >> 685 // Return best answer >> 686 // >> 687 return sBest < halfTol ? 0 : sBest; >> 688 } >> 689 >> 690 >> 691 // >> 692 // IntersectXY >> 693 // >> 694 // Decide if and where the x/y trajectory hits the elliptical cross >> 695 // section. >> 696 // >> 697 // Arguments: >> 698 // p - (in) Point on trajectory >> 699 // v - (in) Vector along trajectory >> 700 // s - (out) Up to two points of intersection, where the >> 701 // intersection point is p + s*v, and if there are >> 702 // two intersections, s[0] < s[1]. May be negative. >> 703 // Returns: >> 704 // The number of intersections. If 0, the trajectory misses. If 1, the >> 705 // trajectory just grazes the surface. >> 706 // >> 707 // Solution: >> 708 // One needs to solve: ( (p.x + s*v.x)/dx )**2 + ( (p.y + s*v.y)/dy )**2 = 1 >> 709 // >> 710 // The solution is quadratic: a*s**2 + b*s + c = 0 >> 711 // >> 712 // a = (v.x/dx)**2 + (v.y/dy)**2 >> 713 // b = 2*p.x*v.x/dx**2 + 2*p.y*v.y/dy**2 >> 714 // c = (p.x/dx)**2 + (p.y/dy)**2 - 1 >> 715 // >> 716 G4int G4EllipticalTube::IntersectXY( const G4ThreeVector &p, >> 717 const G4ThreeVector &v, >> 718 G4double s[2] ) const >> 719 { >> 720 G4double px = p.x(), py = p.y(); >> 721 G4double vx = v.x(), vy = v.y(); >> 722 >> 723 G4double a = (vx/dx)*(vx/dx) + (vy/dy)*(vy/dy); >> 724 G4double b = 2.0*( px*vx/dx/dx + py*vy/dy/dy ); >> 725 G4double c = (px/dx)*(px/dx) + (py/dy)*(py/dy) - 1.0; >> 726 >> 727 if (a < DBL_MIN) return 0; // Trajectory parallel to z axis >> 728 >> 729 G4double radical = b*b - 4*a*c; >> 730 >> 731 if (radical < -DBL_MIN) return 0; // No solution >> 732 >> 733 if (radical < DBL_MIN) 589 { 734 { 590 std::ostringstream message; << 735 // 591 G4long oldprc = message.precision(16); << 736 // Grazes surface 592 message << "Point p is outside (!?) of sol << 737 // 593 << "Position:\n" << 738 s[0] = -b/a/2.0; 594 << " p.x() = " << p.x()/mm << " << 739 return 1; 595 << " p.y() = " << p.y()/mm << " << 740 } 596 << " p.z() = " << p.z()/mm << " << 741 597 message.precision(oldprc) ; << 742 radical = std::sqrt(radical); 598 G4Exception("G4ElliptocalTube::DistanceToO << 743 599 JustWarning, message); << 744 G4double q = -0.5*( b + (b < 0 ? -radical : +radical) ); 600 DumpInfo(); << 745 G4double sa = q/a; 601 } << 746 G4double sb = c/q; 602 #endif << 747 if (sa < sb) { s[0] = sa; s[1] = sb; } else { s[0] = sb; s[1] = sa; } 603 // safety distance to Z-bases << 748 return 2; 604 G4double distZ = fDz - std::abs(p.z()); << 605 << 606 // safety distance lateral surface << 607 G4double x = p.x() * fSx; << 608 G4double y = p.y() * fSy; << 609 G4double distR = fR - std::sqrt(x * x + y * << 610 << 611 // return SafetyToOut << 612 G4double dist = std::min(distZ, distR); << 613 return (dist < 0) ? 0 : dist; << 614 } 749 } 615 750 616 ////////////////////////////////////////////// << 751 617 // 752 // 618 // GetEntityType 753 // GetEntityType 619 << 754 // 620 G4GeometryType G4EllipticalTube::GetEntityType 755 G4GeometryType G4EllipticalTube::GetEntityType() const 621 { 756 { 622 return {"G4EllipticalTube"}; << 757 return G4String("G4EllipticalTube"); 623 } 758 } 624 759 625 ////////////////////////////////////////////// << 626 // << 627 // Make a clone of the object << 628 760 629 G4VSolid* G4EllipticalTube::Clone() const << 630 { << 631 return new G4EllipticalTube(*this); << 632 } << 633 << 634 ////////////////////////////////////////////// << 635 // 761 // 636 // Return volume << 762 // GetCubicVolume 637 << 763 // 638 G4double G4EllipticalTube::GetCubicVolume() 764 G4double G4EllipticalTube::GetCubicVolume() 639 { 765 { 640 if (fCubicVolume == 0.) << 766 if(fCubicVolume != 0.) ; 641 { << 767 else fCubicVolume = G4VSolid::GetCubicVolume(); 642 fCubicVolume = twopi * fDx * fDy * fDz; << 643 } << 644 return fCubicVolume; 768 return fCubicVolume; 645 } 769 } 646 770 647 ////////////////////////////////////////////// << 648 // << 649 // Return cached surface area << 650 << 651 G4double G4EllipticalTube::GetCachedSurfaceAre << 652 { << 653 G4ThreadLocalStatic G4double cached_Dx = 0; << 654 G4ThreadLocalStatic G4double cached_Dy = 0; << 655 G4ThreadLocalStatic G4double cached_Dz = 0; << 656 G4ThreadLocalStatic G4double cached_area = 0 << 657 if (cached_Dx != fDx || cached_Dy != fDy || << 658 { << 659 cached_Dx = fDx; << 660 cached_Dy = fDy; << 661 cached_Dz = fDz; << 662 cached_area = 2.*(pi*fDx*fDy + G4GeomTools << 663 } << 664 return cached_area; << 665 } << 666 771 667 ////////////////////////////////////////////// << 668 // 772 // 669 // Return surface area << 773 // Stream object contents to an output stream 670 << 671 G4double G4EllipticalTube::GetSurfaceArea() << 672 { << 673 if(fSurfaceArea == 0.) << 674 { << 675 fSurfaceArea = GetCachedSurfaceArea(); << 676 } << 677 return fSurfaceArea; << 678 } << 679 << 680 ////////////////////////////////////////////// << 681 // 774 // 682 // Stream object contents to output stream << 683 << 684 std::ostream& G4EllipticalTube::StreamInfo(std 775 std::ostream& G4EllipticalTube::StreamInfo(std::ostream& os) const 685 { 776 { 686 G4long oldprc = os.precision(16); << 687 os << "------------------------------------- 777 os << "-----------------------------------------------------------\n" 688 << " *** Dump for solid - " << GetName 778 << " *** Dump for solid - " << GetName() << " ***\n" 689 << " ================================= 779 << " ===================================================\n" 690 << " Solid type: G4EllipticalTube\n" 780 << " Solid type: G4EllipticalTube\n" 691 << " Parameters: \n" 781 << " Parameters: \n" 692 << " length Z: " << fDz/mm << " mm \n" << 782 << " length Z: " << dz/mm << " mm \n" 693 << " lateral surface equation: \n" << 783 << " surface equation in X and Y: \n" 694 << " (X / " << fDx << ")^2 + (Y / " << 784 << " (X / " << dx << ")^2 + (Y / " << dy << ")^2 = 1 \n" 695 << "------------------------------------- 785 << "-----------------------------------------------------------\n"; 696 os.precision(oldprc); << 697 786 698 return os; 787 return os; 699 } 788 } 700 789 701 790 702 ////////////////////////////////////////////// << 703 // 791 // 704 // Pick up a random point on the surface << 792 // GetPointOnSurface 705 << 793 // >> 794 // Randomly generates a point on the surface, >> 795 // with ~ uniform distribution across surface. >> 796 // 706 G4ThreeVector G4EllipticalTube::GetPointOnSurf 797 G4ThreeVector G4EllipticalTube::GetPointOnSurface() const 707 { 798 { 708 // Select surface (0 - base at -Z, 1 - base << 799 G4double xRand, yRand, zRand, phi, cosphi, sinphi, zArea, cArea,p, chose; 709 // << 710 G4double sbase = pi * fDx * fDy; << 711 G4double ssurf = GetCachedSurfaceArea(); << 712 G4double select = ssurf * G4UniformRand(); << 713 800 714 G4int k = 0; << 801 phi = RandFlat::shoot(0., 2.*pi); 715 if (select > sbase) k = 1; << 802 cosphi = std::cos(phi); 716 if (select > 2. * sbase) k = 2; << 803 sinphi = std::sin(phi); 717 << 804 718 // Pick random point on selected surface (re << 805 // the ellipse perimeter from: "http://mathworld.wolfram.com/Ellipse.html" 719 // << 806 // m = (dx - dy)/(dx + dy); 720 G4ThreeVector p; << 807 // k = 1.+1./4.*m*m+1./64.*sqr(m)*sqr(m)+1./256.*sqr(m)*sqr(m)*sqr(m); 721 switch (k) { << 808 // p = pi*(a+b)*k; 722 case 0: // base at -Z << 809 723 { << 810 // perimeter below from "http://www.efunda.com/math/areas/EllipseGen.cfm" 724 G4TwoVector rho = G4RandomPointInEllipse << 811 725 p.set(rho.x(), rho.y(), -fDz); << 812 p = 2.*pi*std::sqrt(0.5*(dx*dx+dy*dy)); 726 break; << 813 727 } << 814 cArea = 2.*dz*p; 728 case 1: // base at +Z << 815 zArea = pi*dx*dy; 729 { << 816 730 G4TwoVector rho = G4RandomPointInEllipse << 817 xRand = dx*cosphi; 731 p.set(rho.x(), rho.y(), fDz); << 818 yRand = dy*sinphi; 732 break; << 819 zRand = RandFlat::shoot(dz, -1.*dz); 733 } << 820 734 case 2: // lateral surface << 821 chose = RandFlat::shoot(0.,2.*zArea+cArea); 735 { << 822 736 G4TwoVector rho = G4RandomPointOnEllipse << 823 if( (chose>=0) && (chose < cArea) ) 737 p.set(rho.x(), rho.y(), (2. * G4UniformR << 824 { 738 break; << 825 return G4ThreeVector (xRand,yRand,zRand); 739 } << 826 } >> 827 else if( (chose >= cArea) && (chose < cArea + zArea) ) >> 828 { >> 829 xRand = RandFlat::shoot(-1.*dx,dx); >> 830 yRand = std::sqrt(1.-sqr(xRand/dx)); >> 831 yRand = RandFlat::shoot(-1.*yRand, yRand); >> 832 return G4ThreeVector (xRand,yRand,dz); >> 833 } >> 834 else >> 835 { >> 836 xRand = RandFlat::shoot(-1.*dx,dx); >> 837 yRand = std::sqrt(1.-sqr(xRand/dx)); >> 838 yRand = RandFlat::shoot(-1.*yRand, yRand); >> 839 return G4ThreeVector (xRand,yRand,-1.*dz); 740 } 840 } 741 return p; << 742 } 841 } 743 842 744 843 745 ////////////////////////////////////////////// << 746 // 844 // 747 // CreatePolyhedron 845 // CreatePolyhedron 748 << 846 // 749 G4Polyhedron* G4EllipticalTube::CreatePolyhedr 847 G4Polyhedron* G4EllipticalTube::CreatePolyhedron() const 750 { 848 { 751 // create cylinder with radius=1... 849 // create cylinder with radius=1... 752 // 850 // 753 G4Polyhedron* eTube = new G4PolyhedronTube(0 << 851 G4Polyhedron* eTube = new G4PolyhedronTube(0.,1.,dz); 754 852 755 // apply non-uniform scaling... 853 // apply non-uniform scaling... 756 // 854 // 757 eTube->Transform(G4Scale3D(fDx, fDy, 1.)); << 855 eTube->Transform(G4Scale3D(dx,dy,1.)); 758 return eTube; << 856 return eTube; 759 } 857 } 760 858 761 ////////////////////////////////////////////// << 859 762 // 860 // 763 // GetPolyhedron 861 // GetPolyhedron 764 << 862 // 765 G4Polyhedron* G4EllipticalTube::GetPolyhedron 863 G4Polyhedron* G4EllipticalTube::GetPolyhedron () const 766 { 864 { 767 if (fpPolyhedron == nullptr || << 865 if (!fpPolyhedron || 768 fRebuildPolyhedron || << 769 fpPolyhedron->GetNumberOfRotationStepsAt 866 fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() != 770 fpPolyhedron->GetNumberOfRotationSteps() 867 fpPolyhedron->GetNumberOfRotationSteps()) 771 { << 868 { 772 G4AutoLock l(&polyhedronMutex); << 869 delete fpPolyhedron; 773 delete fpPolyhedron; << 870 fpPolyhedron = CreatePolyhedron(); 774 fpPolyhedron = CreatePolyhedron(); << 871 } 775 fRebuildPolyhedron = false; << 776 l.unlock(); << 777 } << 778 return fpPolyhedron; 872 return fpPolyhedron; 779 } 873 } 780 874 781 ////////////////////////////////////////////// << 875 782 // 876 // 783 // DescribeYourselfTo 877 // DescribeYourselfTo 784 << 878 // 785 void G4EllipticalTube::DescribeYourselfTo( G4V 879 void G4EllipticalTube::DescribeYourselfTo( G4VGraphicsScene& scene ) const 786 { 880 { 787 scene.AddSolid (*this); 881 scene.AddSolid (*this); 788 } 882 } 789 883 790 ////////////////////////////////////////////// << 884 791 // 885 // 792 // GetExtent 886 // GetExtent 793 << 887 // 794 G4VisExtent G4EllipticalTube::GetExtent() cons 888 G4VisExtent G4EllipticalTube::GetExtent() const 795 { 889 { 796 return { -fDx, fDx, -fDy, fDy, -fDz, fDz }; << 890 return G4VisExtent( -dx, dx, -dy, dy, -dz, dz ); 797 } 891 } 798 << 799 #endif // !defined(G4GEOM_USE_UELLIPTICALTUBE) << 800 892