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 // Implementation of G4PolyconeSide, the face 26 // Implementation of G4PolyconeSide, the face representing 27 // one conical side of a polycone 27 // one conical side of a polycone 28 // 28 // 29 // Author: David C. Williams (davidw@scipp.ucs 29 // Author: David C. Williams (davidw@scipp.ucsc.edu) 30 // ------------------------------------------- 30 // -------------------------------------------------------------------- 31 31 32 #include "G4PolyconeSide.hh" 32 #include "G4PolyconeSide.hh" 33 #include "meshdefs.hh" 33 #include "meshdefs.hh" 34 #include "G4PhysicalConstants.hh" 34 #include "G4PhysicalConstants.hh" 35 #include "G4IntersectingCone.hh" 35 #include "G4IntersectingCone.hh" 36 #include "G4ClippablePolygon.hh" 36 #include "G4ClippablePolygon.hh" 37 #include "G4AffineTransform.hh" 37 #include "G4AffineTransform.hh" 38 #include "G4SolidExtentList.hh" 38 #include "G4SolidExtentList.hh" 39 #include "G4GeometryTolerance.hh" 39 #include "G4GeometryTolerance.hh" 40 40 41 #include "Randomize.hh" 41 #include "Randomize.hh" 42 42 43 // This new field helps to use the class G4PlS 43 // This new field helps to use the class G4PlSideManager. 44 // 44 // 45 G4PlSideManager G4PolyconeSide::subInstanceMan 45 G4PlSideManager G4PolyconeSide::subInstanceManager; 46 46 47 // This macro changes the references to fields 47 // This macro changes the references to fields that are now encapsulated 48 // in the class G4PlSideData. 48 // in the class G4PlSideData. 49 // 49 // 50 #define G4MT_pcphix ((subInstanceManager.offse 50 #define G4MT_pcphix ((subInstanceManager.offset[instanceID]).fPhix) 51 #define G4MT_pcphiy ((subInstanceManager.offse 51 #define G4MT_pcphiy ((subInstanceManager.offset[instanceID]).fPhiy) 52 #define G4MT_pcphiz ((subInstanceManager.offse 52 #define G4MT_pcphiz ((subInstanceManager.offset[instanceID]).fPhiz) 53 #define G4MT_pcphik ((subInstanceManager.offse 53 #define G4MT_pcphik ((subInstanceManager.offset[instanceID]).fPhik) 54 54 55 // Returns the private data instance manager. 55 // Returns the private data instance manager. 56 // 56 // 57 const G4PlSideManager& G4PolyconeSide::GetSubI 57 const G4PlSideManager& G4PolyconeSide::GetSubInstanceManager() 58 { 58 { 59 return subInstanceManager; 59 return subInstanceManager; 60 } 60 } 61 61 62 // Constructor 62 // Constructor 63 // 63 // 64 // Values for r1,z1 and r2,z2 should be specif 64 // Values for r1,z1 and r2,z2 should be specified in clockwise 65 // order in (r,z). 65 // order in (r,z). 66 // 66 // 67 G4PolyconeSide::G4PolyconeSide( const G4Polyco 67 G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ* prevRZ, 68 const G4Polyco 68 const G4PolyconeSideRZ* tail, 69 const G4Polyco 69 const G4PolyconeSideRZ* head, 70 const G4Polyco 70 const G4PolyconeSideRZ* nextRZ, 71 G4double 71 G4double thePhiStart, 72 G4double 72 G4double theDeltaPhi, 73 G4bool t 73 G4bool thePhiIsOpen, 74 G4bool i 74 G4bool isAllBehind ) 75 { 75 { 76 instanceID = subInstanceManager.CreateSubIns 76 instanceID = subInstanceManager.CreateSubInstance(); 77 77 78 kCarTolerance = G4GeometryTolerance::GetInst 78 kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance(); 79 G4MT_pcphix = 0.0; G4MT_pcphiy = 0.0; G4MT_p 79 G4MT_pcphix = 0.0; G4MT_pcphiy = 0.0; G4MT_pcphiz = 0.0; G4MT_pcphik = 0.0; 80 80 81 // 81 // 82 // Record values 82 // Record values 83 // 83 // 84 r[0] = tail->r; z[0] = tail->z; 84 r[0] = tail->r; z[0] = tail->z; 85 r[1] = head->r; z[1] = head->z; 85 r[1] = head->r; z[1] = head->z; 86 86 87 phiIsOpen = thePhiIsOpen; 87 phiIsOpen = thePhiIsOpen; 88 if (phiIsOpen) 88 if (phiIsOpen) 89 { 89 { 90 deltaPhi = theDeltaPhi; 90 deltaPhi = theDeltaPhi; 91 startPhi = thePhiStart; 91 startPhi = thePhiStart; 92 92 93 // 93 // 94 // Set phi values to our conventions 94 // Set phi values to our conventions 95 // 95 // 96 while (deltaPhi < 0.0) // Loop checking 96 while (deltaPhi < 0.0) // Loop checking, 13.08.2015, G.Cosmo 97 deltaPhi += twopi; 97 deltaPhi += twopi; 98 while (startPhi < 0.0) // Loop checking 98 while (startPhi < 0.0) // Loop checking, 13.08.2015, G.Cosmo 99 startPhi += twopi; 99 startPhi += twopi; 100 100 101 // 101 // 102 // Calculate corner coordinates 102 // Calculate corner coordinates 103 // 103 // 104 ncorners = 4; 104 ncorners = 4; 105 corners = new G4ThreeVector[ncorners]; 105 corners = new G4ThreeVector[ncorners]; 106 106 107 corners[0] = G4ThreeVector( tail->r*std::c 107 corners[0] = G4ThreeVector( tail->r*std::cos(startPhi), 108 tail->r*std::s 108 tail->r*std::sin(startPhi), tail->z ); 109 corners[1] = G4ThreeVector( head->r*std::c 109 corners[1] = G4ThreeVector( head->r*std::cos(startPhi), 110 head->r*std::s 110 head->r*std::sin(startPhi), head->z ); 111 corners[2] = G4ThreeVector( tail->r*std::c 111 corners[2] = G4ThreeVector( tail->r*std::cos(startPhi+deltaPhi), 112 tail->r*std::s 112 tail->r*std::sin(startPhi+deltaPhi), tail->z ); 113 corners[3] = G4ThreeVector( head->r*std::c 113 corners[3] = G4ThreeVector( head->r*std::cos(startPhi+deltaPhi), 114 head->r*std::s 114 head->r*std::sin(startPhi+deltaPhi), head->z ); 115 } 115 } 116 else 116 else 117 { 117 { 118 deltaPhi = twopi; 118 deltaPhi = twopi; 119 startPhi = 0.0; 119 startPhi = 0.0; 120 } 120 } 121 121 122 allBehind = isAllBehind; 122 allBehind = isAllBehind; 123 123 124 // 124 // 125 // Make our intersecting cone 125 // Make our intersecting cone 126 // 126 // 127 cone = new G4IntersectingCone( r, z ); 127 cone = new G4IntersectingCone( r, z ); 128 128 129 // 129 // 130 // Calculate vectors in r,z space 130 // Calculate vectors in r,z space 131 // 131 // 132 rS = r[1]-r[0]; zS = z[1]-z[0]; 132 rS = r[1]-r[0]; zS = z[1]-z[0]; 133 length = std::sqrt( rS*rS + zS*zS); 133 length = std::sqrt( rS*rS + zS*zS); 134 rS /= length; zS /= length; 134 rS /= length; zS /= length; 135 135 136 rNorm = +zS; 136 rNorm = +zS; 137 zNorm = -rS; 137 zNorm = -rS; 138 138 139 G4double lAdj; 139 G4double lAdj; 140 140 141 prevRS = r[0]-prevRZ->r; 141 prevRS = r[0]-prevRZ->r; 142 prevZS = z[0]-prevRZ->z; 142 prevZS = z[0]-prevRZ->z; 143 lAdj = std::sqrt( prevRS*prevRS + prevZS*pre 143 lAdj = std::sqrt( prevRS*prevRS + prevZS*prevZS ); 144 prevRS /= lAdj; 144 prevRS /= lAdj; 145 prevZS /= lAdj; 145 prevZS /= lAdj; 146 146 147 rNormEdge[0] = rNorm + prevZS; 147 rNormEdge[0] = rNorm + prevZS; 148 zNormEdge[0] = zNorm - prevRS; 148 zNormEdge[0] = zNorm - prevRS; 149 lAdj = std::sqrt( rNormEdge[0]*rNormEdge[0] 149 lAdj = std::sqrt( rNormEdge[0]*rNormEdge[0] + zNormEdge[0]*zNormEdge[0] ); 150 rNormEdge[0] /= lAdj; 150 rNormEdge[0] /= lAdj; 151 zNormEdge[0] /= lAdj; 151 zNormEdge[0] /= lAdj; 152 152 153 nextRS = nextRZ->r-r[1]; 153 nextRS = nextRZ->r-r[1]; 154 nextZS = nextRZ->z-z[1]; 154 nextZS = nextRZ->z-z[1]; 155 lAdj = std::sqrt( nextRS*nextRS + nextZS*nex 155 lAdj = std::sqrt( nextRS*nextRS + nextZS*nextZS ); 156 nextRS /= lAdj; 156 nextRS /= lAdj; 157 nextZS /= lAdj; 157 nextZS /= lAdj; 158 158 159 rNormEdge[1] = rNorm + nextZS; 159 rNormEdge[1] = rNorm + nextZS; 160 zNormEdge[1] = zNorm - nextRS; 160 zNormEdge[1] = zNorm - nextRS; 161 lAdj = std::sqrt( rNormEdge[1]*rNormEdge[1] 161 lAdj = std::sqrt( rNormEdge[1]*rNormEdge[1] + zNormEdge[1]*zNormEdge[1] ); 162 rNormEdge[1] /= lAdj; 162 rNormEdge[1] /= lAdj; 163 zNormEdge[1] /= lAdj; 163 zNormEdge[1] /= lAdj; 164 } 164 } 165 165 166 // Fake default constructor - sets only member 166 // Fake default constructor - sets only member data and allocates memory 167 // for usage restri 167 // for usage restricted to object persistency. 168 // 168 // 169 G4PolyconeSide::G4PolyconeSide( __void__& ) 169 G4PolyconeSide::G4PolyconeSide( __void__& ) 170 : startPhi(0.), deltaPhi(0.), 170 : startPhi(0.), deltaPhi(0.), 171 rNorm(0.), zNorm(0.), rS(0.), zS(0.), leng << 171 cone(0), rNorm(0.), zNorm(0.), rS(0.), zS(0.), length(0.), 172 prevRS(0.), prevZS(0.), nextRS(0.), nextZS 172 prevRS(0.), prevZS(0.), nextRS(0.), nextZS(0.), 173 kCarTolerance(0.), instanceID(0) 173 kCarTolerance(0.), instanceID(0) 174 { 174 { 175 r[0] = r[1] = 0.; 175 r[0] = r[1] = 0.; 176 z[0] = z[1] = 0.; 176 z[0] = z[1] = 0.; 177 rNormEdge[0]= rNormEdge[1] = 0.; 177 rNormEdge[0]= rNormEdge[1] = 0.; 178 zNormEdge[0]= zNormEdge[1] = 0.; 178 zNormEdge[0]= zNormEdge[1] = 0.; 179 } 179 } 180 180 181 // Destructor 181 // Destructor 182 // 182 // 183 G4PolyconeSide::~G4PolyconeSide() 183 G4PolyconeSide::~G4PolyconeSide() 184 { 184 { 185 delete cone; 185 delete cone; 186 if (phiIsOpen) { delete [] corners; } 186 if (phiIsOpen) { delete [] corners; } 187 } 187 } 188 188 189 // Copy constructor 189 // Copy constructor 190 // 190 // 191 G4PolyconeSide::G4PolyconeSide( const G4Polyco 191 G4PolyconeSide::G4PolyconeSide( const G4PolyconeSide& source ) >> 192 : G4VCSGface() 192 { 193 { 193 instanceID = subInstanceManager.CreateSubIns 194 instanceID = subInstanceManager.CreateSubInstance(); 194 195 195 CopyStuff( source ); 196 CopyStuff( source ); 196 } 197 } 197 198 198 // Assignment operator 199 // Assignment operator 199 // 200 // 200 G4PolyconeSide& G4PolyconeSide::operator=( con 201 G4PolyconeSide& G4PolyconeSide::operator=( const G4PolyconeSide& source ) 201 { 202 { 202 if (this == &source) { return *this; } 203 if (this == &source) { return *this; } 203 204 204 delete cone; 205 delete cone; 205 if (phiIsOpen) { delete [] corners; } 206 if (phiIsOpen) { delete [] corners; } 206 207 207 CopyStuff( source ); 208 CopyStuff( source ); 208 209 209 return *this; 210 return *this; 210 } 211 } 211 212 212 // CopyStuff 213 // CopyStuff 213 // 214 // 214 void G4PolyconeSide::CopyStuff( const G4Polyco 215 void G4PolyconeSide::CopyStuff( const G4PolyconeSide& source ) 215 { 216 { 216 r[0] = source.r[0]; 217 r[0] = source.r[0]; 217 r[1] = source.r[1]; 218 r[1] = source.r[1]; 218 z[0] = source.z[0]; 219 z[0] = source.z[0]; 219 z[1] = source.z[1]; 220 z[1] = source.z[1]; 220 221 221 startPhi = source.startPhi; 222 startPhi = source.startPhi; 222 deltaPhi = source.deltaPhi; 223 deltaPhi = source.deltaPhi; 223 phiIsOpen = source.phiIsOpen; 224 phiIsOpen = source.phiIsOpen; 224 allBehind = source.allBehind; 225 allBehind = source.allBehind; 225 226 226 kCarTolerance = source.kCarTolerance; 227 kCarTolerance = source.kCarTolerance; 227 fSurfaceArea = source.fSurfaceArea; 228 fSurfaceArea = source.fSurfaceArea; 228 229 229 cone = new G4IntersectingCone( *source.co 230 cone = new G4IntersectingCone( *source.cone ); 230 231 231 rNorm = source.rNorm; 232 rNorm = source.rNorm; 232 zNorm = source.zNorm; 233 zNorm = source.zNorm; 233 rS = source.rS; 234 rS = source.rS; 234 zS = source.zS; 235 zS = source.zS; 235 length = source.length; 236 length = source.length; 236 prevRS = source.prevRS; 237 prevRS = source.prevRS; 237 prevZS = source.prevZS; 238 prevZS = source.prevZS; 238 nextRS = source.nextRS; 239 nextRS = source.nextRS; 239 nextZS = source.nextZS; 240 nextZS = source.nextZS; 240 241 241 rNormEdge[0] = source.rNormEdge[0]; 242 rNormEdge[0] = source.rNormEdge[0]; 242 rNormEdge[1] = source.rNormEdge[1]; 243 rNormEdge[1] = source.rNormEdge[1]; 243 zNormEdge[0] = source.zNormEdge[0]; 244 zNormEdge[0] = source.zNormEdge[0]; 244 zNormEdge[1] = source.zNormEdge[1]; 245 zNormEdge[1] = source.zNormEdge[1]; 245 246 246 if (phiIsOpen) 247 if (phiIsOpen) 247 { 248 { 248 ncorners = 4; 249 ncorners = 4; 249 corners = new G4ThreeVector[ncorners]; 250 corners = new G4ThreeVector[ncorners]; 250 251 251 corners[0] = source.corners[0]; 252 corners[0] = source.corners[0]; 252 corners[1] = source.corners[1]; 253 corners[1] = source.corners[1]; 253 corners[2] = source.corners[2]; 254 corners[2] = source.corners[2]; 254 corners[3] = source.corners[3]; 255 corners[3] = source.corners[3]; 255 } 256 } 256 } 257 } 257 258 258 // Intersect 259 // Intersect 259 // 260 // 260 G4bool G4PolyconeSide::Intersect( const G4Thre 261 G4bool G4PolyconeSide::Intersect( const G4ThreeVector& p, 261 const G4Thre 262 const G4ThreeVector& v, 262 G4bool 263 G4bool outgoing, 263 G4doub 264 G4double surfTolerance, 264 G4doub 265 G4double& distance, 265 G4doub 266 G4double& distFromSurface, 266 G4Thre 267 G4ThreeVector& normal, 267 G4bool 268 G4bool& isAllBehind ) 268 { 269 { 269 G4double s1=0., s2=0.; << 270 G4double s1, s2; 270 G4double normSign = outgoing ? +1 : -1; 271 G4double normSign = outgoing ? +1 : -1; 271 272 272 isAllBehind = allBehind; 273 isAllBehind = allBehind; 273 274 274 // 275 // 275 // Check for two possible intersections 276 // Check for two possible intersections 276 // 277 // 277 G4int nside = cone->LineHitsCone( p, v, &s1, 278 G4int nside = cone->LineHitsCone( p, v, &s1, &s2 ); 278 if (nside == 0) return false; 279 if (nside == 0) return false; 279 280 280 // 281 // 281 // Check the first side first, since it is ( 282 // Check the first side first, since it is (supposed to be) closest 282 // 283 // 283 G4ThreeVector hit = p + s1*v; 284 G4ThreeVector hit = p + s1*v; 284 285 285 if (PointOnCone( hit, normSign, p, v, normal 286 if (PointOnCone( hit, normSign, p, v, normal )) 286 { 287 { 287 // 288 // 288 // Good intersection! What about the norma 289 // Good intersection! What about the normal? 289 // 290 // 290 if (normSign*v.dot(normal) > 0) 291 if (normSign*v.dot(normal) > 0) 291 { 292 { 292 // 293 // 293 // We have a valid intersection, but it 294 // We have a valid intersection, but it could very easily 294 // be behind the point. To decide if we 295 // be behind the point. To decide if we tolerate this, 295 // we have to see if the point p is on t 296 // we have to see if the point p is on the surface near 296 // the intersecting point. 297 // the intersecting point. 297 // 298 // 298 // What does it mean exactly for the poi 299 // What does it mean exactly for the point p to be "near" 299 // the intersection? It means that if we 300 // the intersection? It means that if we draw a line from 300 // p to the hit, the line remains entire 301 // p to the hit, the line remains entirely within the 301 // tolerance bounds of the cone. To test 302 // tolerance bounds of the cone. To test this, we can 302 // ask if the normal is correct near p. 303 // ask if the normal is correct near p. 303 // 304 // 304 G4double pr = p.perp(); 305 G4double pr = p.perp(); 305 if (pr < DBL_MIN) pr = DBL_MIN; 306 if (pr < DBL_MIN) pr = DBL_MIN; 306 G4ThreeVector pNormal( rNorm*p.x()/pr, r 307 G4ThreeVector pNormal( rNorm*p.x()/pr, rNorm*p.y()/pr, zNorm ); 307 if (normSign*v.dot(pNormal) > 0) 308 if (normSign*v.dot(pNormal) > 0) 308 { 309 { 309 // 310 // 310 // p and intersection in same hemisphe 311 // p and intersection in same hemisphere 311 // 312 // 312 G4double distOutside2; 313 G4double distOutside2; 313 distFromSurface = -normSign*DistanceAw 314 distFromSurface = -normSign*DistanceAway( p, false, distOutside2 ); 314 if (distOutside2 < surfTolerance*surfT 315 if (distOutside2 < surfTolerance*surfTolerance) 315 { 316 { 316 if (distFromSurface > -surfTolerance 317 if (distFromSurface > -surfTolerance) 317 { 318 { 318 // 319 // 319 // We are just inside or away from 320 // We are just inside or away from the 320 // surface. Accept *any* value of 321 // surface. Accept *any* value of distance. 321 // 322 // 322 distance = s1; 323 distance = s1; 323 return true; 324 return true; 324 } 325 } 325 } 326 } 326 } 327 } 327 else 328 else 328 distFromSurface = s1; 329 distFromSurface = s1; 329 330 330 // 331 // 331 // Accept positive distances 332 // Accept positive distances 332 // 333 // 333 if (s1 > 0) 334 if (s1 > 0) 334 { 335 { 335 distance = s1; 336 distance = s1; 336 return true; 337 return true; 337 } 338 } 338 } 339 } 339 } 340 } 340 341 341 if (nside==1) return false; 342 if (nside==1) return false; 342 343 343 // 344 // 344 // Well, try the second hit 345 // Well, try the second hit 345 // 346 // 346 hit = p + s2*v; 347 hit = p + s2*v; 347 348 348 if (PointOnCone( hit, normSign, p, v, normal 349 if (PointOnCone( hit, normSign, p, v, normal )) 349 { 350 { 350 // 351 // 351 // Good intersection! What about the norma 352 // Good intersection! What about the normal? 352 // 353 // 353 if (normSign*v.dot(normal) > 0) 354 if (normSign*v.dot(normal) > 0) 354 { 355 { 355 G4double pr = p.perp(); 356 G4double pr = p.perp(); 356 if (pr < DBL_MIN) pr = DBL_MIN; 357 if (pr < DBL_MIN) pr = DBL_MIN; 357 G4ThreeVector pNormal( rNorm*p.x()/pr, r 358 G4ThreeVector pNormal( rNorm*p.x()/pr, rNorm*p.y()/pr, zNorm ); 358 if (normSign*v.dot(pNormal) > 0) 359 if (normSign*v.dot(pNormal) > 0) 359 { 360 { 360 G4double distOutside2; 361 G4double distOutside2; 361 distFromSurface = -normSign*DistanceAw 362 distFromSurface = -normSign*DistanceAway( p, false, distOutside2 ); 362 if (distOutside2 < surfTolerance*surfT 363 if (distOutside2 < surfTolerance*surfTolerance) 363 { 364 { 364 if (distFromSurface > -surfTolerance 365 if (distFromSurface > -surfTolerance) 365 { 366 { 366 distance = s2; 367 distance = s2; 367 return true; 368 return true; 368 } 369 } 369 } 370 } 370 } 371 } 371 else 372 else 372 distFromSurface = s2; 373 distFromSurface = s2; 373 374 374 if (s2 > 0) 375 if (s2 > 0) 375 { 376 { 376 distance = s2; 377 distance = s2; 377 return true; 378 return true; 378 } 379 } 379 } 380 } 380 } 381 } 381 382 382 // 383 // 383 // Better luck next time 384 // Better luck next time 384 // 385 // 385 return false; 386 return false; 386 } 387 } 387 388 388 // Distance 389 // Distance 389 // 390 // 390 G4double G4PolyconeSide::Distance( const G4Thr 391 G4double G4PolyconeSide::Distance( const G4ThreeVector& p, G4bool outgoing ) 391 { 392 { 392 G4double normSign = outgoing ? -1 : +1; 393 G4double normSign = outgoing ? -1 : +1; 393 G4double distFrom, distOut2; 394 G4double distFrom, distOut2; 394 395 395 // 396 // 396 // We have two tries for each hemisphere. Tr 397 // We have two tries for each hemisphere. Try the closest first. 397 // 398 // 398 distFrom = normSign*DistanceAway( p, false, 399 distFrom = normSign*DistanceAway( p, false, distOut2 ); 399 if (distFrom > -0.5*kCarTolerance ) 400 if (distFrom > -0.5*kCarTolerance ) 400 { 401 { 401 // 402 // 402 // Good answer 403 // Good answer 403 // 404 // 404 if (distOut2 > 0) 405 if (distOut2 > 0) 405 return std::sqrt( distFrom*distFrom + di 406 return std::sqrt( distFrom*distFrom + distOut2 ); 406 else 407 else 407 return std::fabs(distFrom); 408 return std::fabs(distFrom); 408 } 409 } 409 410 410 // 411 // 411 // Try second side. 412 // Try second side. 412 // 413 // 413 distFrom = normSign*DistanceAway( p, true, 414 distFrom = normSign*DistanceAway( p, true, distOut2 ); 414 if (distFrom > -0.5*kCarTolerance) 415 if (distFrom > -0.5*kCarTolerance) 415 { 416 { 416 417 417 if (distOut2 > 0) 418 if (distOut2 > 0) 418 return std::sqrt( distFrom*distFrom + di 419 return std::sqrt( distFrom*distFrom + distOut2 ); 419 else 420 else 420 return std::fabs(distFrom); 421 return std::fabs(distFrom); 421 } 422 } 422 423 423 return kInfinity; 424 return kInfinity; 424 } 425 } 425 426 426 // Inside 427 // Inside 427 // 428 // 428 EInside G4PolyconeSide::Inside( const G4ThreeV 429 EInside G4PolyconeSide::Inside( const G4ThreeVector& p, 429 G4double 430 G4double tolerance, 430 G4double 431 G4double* bestDistance ) 431 { 432 { 432 G4double distFrom, distOut2, dist2; 433 G4double distFrom, distOut2, dist2; 433 G4double edgeRZnorm; 434 G4double edgeRZnorm; 434 435 435 distFrom = DistanceAway( p, distOut2, &edge 436 distFrom = DistanceAway( p, distOut2, &edgeRZnorm ); 436 dist2 = distFrom*distFrom + distOut2; 437 dist2 = distFrom*distFrom + distOut2; 437 438 438 *bestDistance = std::sqrt( dist2); 439 *bestDistance = std::sqrt( dist2); 439 440 440 // Okay then, inside or out? 441 // Okay then, inside or out? 441 // 442 // 442 if ( (std::fabs(edgeRZnorm) < tolerance) 443 if ( (std::fabs(edgeRZnorm) < tolerance) 443 && (distOut2< tolerance*tolerance) ) 444 && (distOut2< tolerance*tolerance) ) 444 return kSurface; 445 return kSurface; 445 else if (edgeRZnorm < 0) 446 else if (edgeRZnorm < 0) 446 return kInside; 447 return kInside; 447 else 448 else 448 return kOutside; 449 return kOutside; 449 } 450 } 450 451 451 // Normal 452 // Normal 452 // 453 // 453 G4ThreeVector G4PolyconeSide::Normal( const G4 454 G4ThreeVector G4PolyconeSide::Normal( const G4ThreeVector& p, 454 G4 455 G4double* bestDistance ) 455 { 456 { 456 if (p == G4ThreeVector(0.,0.,0.)) { return 457 if (p == G4ThreeVector(0.,0.,0.)) { return p; } 457 458 458 G4double dFrom, dOut2; 459 G4double dFrom, dOut2; 459 460 460 dFrom = DistanceAway( p, false, dOut2 ); 461 dFrom = DistanceAway( p, false, dOut2 ); 461 462 462 *bestDistance = std::sqrt( dFrom*dFrom + dOu 463 *bestDistance = std::sqrt( dFrom*dFrom + dOut2 ); 463 464 464 G4double rds = p.perp(); 465 G4double rds = p.perp(); 465 if (rds!=0.) { return {rNorm*p.x()/rds,rNorm << 466 if (rds!=0.) { return G4ThreeVector(rNorm*p.x()/rds,rNorm*p.y()/rds,zNorm); } 466 return G4ThreeVector( 0.,0., zNorm ).unit(); 467 return G4ThreeVector( 0.,0., zNorm ).unit(); 467 } 468 } 468 469 469 // Extent 470 // Extent 470 // 471 // 471 G4double G4PolyconeSide::Extent( const G4Three 472 G4double G4PolyconeSide::Extent( const G4ThreeVector axis ) 472 { 473 { 473 if (axis.perp2() < DBL_MIN) 474 if (axis.perp2() < DBL_MIN) 474 { 475 { 475 // 476 // 476 // Special case 477 // Special case 477 // 478 // 478 return axis.z() < 0 ? -cone->ZLo() : cone- 479 return axis.z() < 0 ? -cone->ZLo() : cone->ZHi(); 479 } 480 } 480 481 481 // 482 // 482 // Is the axis pointing inside our phi gap? 483 // Is the axis pointing inside our phi gap? 483 // 484 // 484 if (phiIsOpen) 485 if (phiIsOpen) 485 { 486 { 486 G4double phi = GetPhi(axis); 487 G4double phi = GetPhi(axis); 487 while( phi < startPhi ) // Loop checkin 488 while( phi < startPhi ) // Loop checking, 13.08.2015, G.Cosmo 488 phi += twopi; 489 phi += twopi; 489 490 490 if (phi > deltaPhi+startPhi) 491 if (phi > deltaPhi+startPhi) 491 { 492 { 492 // 493 // 493 // Yeah, looks so. Make four three vecto 494 // Yeah, looks so. Make four three vectors defining the phi 494 // opening 495 // opening 495 // 496 // 496 G4double cosP = std::cos(startPhi), sinP 497 G4double cosP = std::cos(startPhi), sinP = std::sin(startPhi); 497 G4ThreeVector a( r[0]*cosP, r[0]*sinP, z 498 G4ThreeVector a( r[0]*cosP, r[0]*sinP, z[0] ); 498 G4ThreeVector b( r[1]*cosP, r[1]*sinP, z 499 G4ThreeVector b( r[1]*cosP, r[1]*sinP, z[1] ); 499 cosP = std::cos(startPhi+deltaPhi); sinP 500 cosP = std::cos(startPhi+deltaPhi); sinP = std::sin(startPhi+deltaPhi); 500 G4ThreeVector c( r[0]*cosP, r[0]*sinP, z 501 G4ThreeVector c( r[0]*cosP, r[0]*sinP, z[0] ); 501 G4ThreeVector d( r[1]*cosP, r[1]*sinP, z 502 G4ThreeVector d( r[1]*cosP, r[1]*sinP, z[1] ); 502 503 503 G4double ad = axis.dot(a), 504 G4double ad = axis.dot(a), 504 bd = axis.dot(b), 505 bd = axis.dot(b), 505 cd = axis.dot(c), 506 cd = axis.dot(c), 506 dd = axis.dot(d); 507 dd = axis.dot(d); 507 508 508 if (bd > ad) ad = bd; 509 if (bd > ad) ad = bd; 509 if (cd > ad) ad = cd; 510 if (cd > ad) ad = cd; 510 if (dd > ad) ad = dd; 511 if (dd > ad) ad = dd; 511 512 512 return ad; 513 return ad; 513 } 514 } 514 } 515 } 515 516 516 // 517 // 517 // Check either end 518 // Check either end 518 // 519 // 519 G4double aPerp = axis.perp(); 520 G4double aPerp = axis.perp(); 520 521 521 G4double a = aPerp*r[0] + axis.z()*z[0]; 522 G4double a = aPerp*r[0] + axis.z()*z[0]; 522 G4double b = aPerp*r[1] + axis.z()*z[1]; 523 G4double b = aPerp*r[1] + axis.z()*z[1]; 523 524 524 if (b > a) a = b; 525 if (b > a) a = b; 525 526 526 return a; 527 return a; 527 } 528 } 528 529 529 // CalculateExtent 530 // CalculateExtent 530 // 531 // 531 // See notes in G4VCSGface 532 // See notes in G4VCSGface 532 // 533 // 533 void G4PolyconeSide::CalculateExtent( const EA 534 void G4PolyconeSide::CalculateExtent( const EAxis axis, 534 const G4 535 const G4VoxelLimits& voxelLimit, 535 const G4 536 const G4AffineTransform& transform, 536 G4 537 G4SolidExtentList& extentList ) 537 { 538 { 538 G4ClippablePolygon polygon; 539 G4ClippablePolygon polygon; 539 540 540 // 541 // 541 // Here we will approximate (ala G4Cons) and 542 // Here we will approximate (ala G4Cons) and divide our conical section 542 // into segments, like G4Polyhedra. When doi 543 // into segments, like G4Polyhedra. When doing so, the radius 543 // is extented far enough such that the segm 544 // is extented far enough such that the segments always lie 544 // just outside the surface of the conical s 545 // just outside the surface of the conical section we are 545 // approximating. 546 // approximating. 546 // 547 // 547 548 548 // 549 // 549 // Choose phi size of our segment(s) based o 550 // Choose phi size of our segment(s) based on constants as 550 // defined in meshdefs.hh 551 // defined in meshdefs.hh 551 // 552 // 552 G4int numPhi = (G4int)(deltaPhi/kMeshAngleDe 553 G4int numPhi = (G4int)(deltaPhi/kMeshAngleDefault) + 1; 553 if (numPhi < kMinMeshSections) 554 if (numPhi < kMinMeshSections) 554 numPhi = kMinMeshSections; 555 numPhi = kMinMeshSections; 555 else if (numPhi > kMaxMeshSections) 556 else if (numPhi > kMaxMeshSections) 556 numPhi = kMaxMeshSections; 557 numPhi = kMaxMeshSections; 557 558 558 G4double sigPhi = deltaPhi/numPhi; 559 G4double sigPhi = deltaPhi/numPhi; 559 560 560 // 561 // 561 // Determine radius factor to keep segments 562 // Determine radius factor to keep segments outside 562 // 563 // 563 G4double rFudge = 1.0/std::cos(0.5*sigPhi); 564 G4double rFudge = 1.0/std::cos(0.5*sigPhi); 564 565 565 // 566 // 566 // Decide which radius to use on each end of 567 // Decide which radius to use on each end of the side, 567 // and whether a transition mesh is required 568 // and whether a transition mesh is required 568 // 569 // 569 // {r0,z0} - Beginning of this side 570 // {r0,z0} - Beginning of this side 570 // {r1,z1} - Ending of this side 571 // {r1,z1} - Ending of this side 571 // {r2,z0} - Beginning of transition piece 572 // {r2,z0} - Beginning of transition piece connecting previous 572 // side (and ends at beginning of 573 // side (and ends at beginning of this side) 573 // 574 // 574 // So, order is 2 --> 0 --> 1. 575 // So, order is 2 --> 0 --> 1. 575 // ------- 576 // ------- 576 // 577 // 577 // r2 < 0 indicates that no transition piece 578 // r2 < 0 indicates that no transition piece is required 578 // 579 // 579 G4double r0, r1, r2, z0, z1; 580 G4double r0, r1, r2, z0, z1; 580 581 581 r2 = -1; // By default: no transition piece 582 r2 = -1; // By default: no transition piece 582 583 583 if (rNorm < -DBL_MIN) 584 if (rNorm < -DBL_MIN) 584 { 585 { 585 // 586 // 586 // This side faces *inward*, and so our me 587 // This side faces *inward*, and so our mesh has 587 // the same radius 588 // the same radius 588 // 589 // 589 r1 = r[1]; 590 r1 = r[1]; 590 z1 = z[1]; 591 z1 = z[1]; 591 z0 = z[0]; 592 z0 = z[0]; 592 r0 = r[0]; 593 r0 = r[0]; 593 594 594 r2 = -1; 595 r2 = -1; 595 596 596 if (prevZS > DBL_MIN) 597 if (prevZS > DBL_MIN) 597 { 598 { 598 // 599 // 599 // The previous side is facing outwards 600 // The previous side is facing outwards 600 // 601 // 601 if ( prevRS*zS - prevZS*rS > 0 ) 602 if ( prevRS*zS - prevZS*rS > 0 ) 602 { 603 { 603 // 604 // 604 // Transition was convex: build transi 605 // Transition was convex: build transition piece 605 // 606 // 606 if (r[0] > DBL_MIN) r2 = r[0]*rFudge; 607 if (r[0] > DBL_MIN) r2 = r[0]*rFudge; 607 } 608 } 608 else 609 else 609 { 610 { 610 // 611 // 611 // Transition was concave: short this 612 // Transition was concave: short this side 612 // 613 // 613 FindLineIntersect( z0, r0, zS, rS, 614 FindLineIntersect( z0, r0, zS, rS, 614 z0, r0*rFudge, prev 615 z0, r0*rFudge, prevZS, prevRS*rFudge, z0, r0 ); 615 } 616 } 616 } 617 } 617 618 618 if ( nextZS > DBL_MIN && (rS*nextZS - zS*n 619 if ( nextZS > DBL_MIN && (rS*nextZS - zS*nextRS < 0) ) 619 { 620 { 620 // 621 // 621 // The next side is facing outwards, for 622 // The next side is facing outwards, forming a 622 // concave transition: short this side 623 // concave transition: short this side 623 // 624 // 624 FindLineIntersect( z1, r1, zS, rS, 625 FindLineIntersect( z1, r1, zS, rS, 625 z1, r1*rFudge, nextZS 626 z1, r1*rFudge, nextZS, nextRS*rFudge, z1, r1 ); 626 } 627 } 627 } 628 } 628 else if (rNorm > DBL_MIN) 629 else if (rNorm > DBL_MIN) 629 { 630 { 630 // 631 // 631 // This side faces *outward* and is given 632 // This side faces *outward* and is given a boost to 632 // it radius 633 // it radius 633 // 634 // 634 r0 = r[0]*rFudge; 635 r0 = r[0]*rFudge; 635 z0 = z[0]; 636 z0 = z[0]; 636 r1 = r[1]*rFudge; 637 r1 = r[1]*rFudge; 637 z1 = z[1]; 638 z1 = z[1]; 638 639 639 if (prevZS < -DBL_MIN) 640 if (prevZS < -DBL_MIN) 640 { 641 { 641 // 642 // 642 // The previous side is facing inwards 643 // The previous side is facing inwards 643 // 644 // 644 if ( prevRS*zS - prevZS*rS > 0 ) 645 if ( prevRS*zS - prevZS*rS > 0 ) 645 { 646 { 646 // 647 // 647 // Transition was convex: build transi 648 // Transition was convex: build transition piece 648 // 649 // 649 if (r[0] > DBL_MIN) r2 = r[0]; 650 if (r[0] > DBL_MIN) r2 = r[0]; 650 } 651 } 651 else 652 else 652 { 653 { 653 // 654 // 654 // Transition was concave: short this 655 // Transition was concave: short this side 655 // 656 // 656 FindLineIntersect( z0, r0, zS, rS*rFud 657 FindLineIntersect( z0, r0, zS, rS*rFudge, 657 z0, r[0], prevZS, p 658 z0, r[0], prevZS, prevRS, z0, r0 ); 658 } 659 } 659 } 660 } 660 661 661 if ( nextZS < -DBL_MIN && (rS*nextZS - zS* 662 if ( nextZS < -DBL_MIN && (rS*nextZS - zS*nextRS < 0) ) 662 { 663 { 663 // 664 // 664 // The next side is facing inwards, form 665 // The next side is facing inwards, forming a 665 // concave transition: short this side 666 // concave transition: short this side 666 // 667 // 667 FindLineIntersect( z1, r1, zS, rS*rFudge 668 FindLineIntersect( z1, r1, zS, rS*rFudge, 668 z1, r[1], nextZS, nex 669 z1, r[1], nextZS, nextRS, z1, r1 ); 669 } 670 } 670 } 671 } 671 else 672 else 672 { 673 { 673 // 674 // 674 // This side is perpendicular to the z axi 675 // This side is perpendicular to the z axis (is a disk) 675 // 676 // 676 // Whether or not r0 needs a rFudge factor 677 // Whether or not r0 needs a rFudge factor depends 677 // on the normal of the previous edge. Sim 678 // on the normal of the previous edge. Similar with r1 678 // and the next edge. No transition piece 679 // and the next edge. No transition piece is required. 679 // 680 // 680 r0 = r[0]; 681 r0 = r[0]; 681 r1 = r[1]; 682 r1 = r[1]; 682 z0 = z[0]; 683 z0 = z[0]; 683 z1 = z[1]; 684 z1 = z[1]; 684 685 685 if (prevZS > DBL_MIN) r0 *= rFudge; 686 if (prevZS > DBL_MIN) r0 *= rFudge; 686 if (nextZS > DBL_MIN) r1 *= rFudge; 687 if (nextZS > DBL_MIN) r1 *= rFudge; 687 } 688 } 688 689 689 // 690 // 690 // Loop 691 // Loop 691 // 692 // 692 G4double phi = startPhi, 693 G4double phi = startPhi, 693 cosPhi = std::cos(phi), 694 cosPhi = std::cos(phi), 694 sinPhi = std::sin(phi); 695 sinPhi = std::sin(phi); 695 696 696 G4ThreeVector v0( r0*cosPhi, r0*sinPhi, z0 ) 697 G4ThreeVector v0( r0*cosPhi, r0*sinPhi, z0 ), 697 v1( r1*cosPhi, r1*sinPhi, 698 v1( r1*cosPhi, r1*sinPhi, z1 ), 698 v2, w0, w1, w2; 699 v2, w0, w1, w2; 699 transform.ApplyPointTransform( v0 ); 700 transform.ApplyPointTransform( v0 ); 700 transform.ApplyPointTransform( v1 ); 701 transform.ApplyPointTransform( v1 ); 701 702 702 if (r2 >= 0) 703 if (r2 >= 0) 703 { 704 { 704 v2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, 705 v2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, z0 ); 705 transform.ApplyPointTransform( v2 ); 706 transform.ApplyPointTransform( v2 ); 706 } 707 } 707 708 708 do // Loop checking, 13.08.2015, G.Cosmo 709 do // Loop checking, 13.08.2015, G.Cosmo 709 { 710 { 710 phi += sigPhi; 711 phi += sigPhi; 711 if (numPhi == 1) phi = startPhi+deltaPhi; 712 if (numPhi == 1) phi = startPhi+deltaPhi; // Try to avoid roundoff 712 cosPhi = std::cos(phi), 713 cosPhi = std::cos(phi), 713 sinPhi = std::sin(phi); 714 sinPhi = std::sin(phi); 714 715 715 w0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, 716 w0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, z0 ); 716 w1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, 717 w1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, z1 ); 717 transform.ApplyPointTransform( w0 ); 718 transform.ApplyPointTransform( w0 ); 718 transform.ApplyPointTransform( w1 ); 719 transform.ApplyPointTransform( w1 ); 719 720 720 G4ThreeVector deltaV = r0 > r1 ? w0-v0 : w 721 G4ThreeVector deltaV = r0 > r1 ? w0-v0 : w1-v1; 721 722 722 // 723 // 723 // Build polygon, taking special care to k 724 // Build polygon, taking special care to keep the vertices 724 // in order 725 // in order 725 // 726 // 726 polygon.ClearAllVertices(); 727 polygon.ClearAllVertices(); 727 728 728 polygon.AddVertexInOrder( v0 ); 729 polygon.AddVertexInOrder( v0 ); 729 polygon.AddVertexInOrder( v1 ); 730 polygon.AddVertexInOrder( v1 ); 730 polygon.AddVertexInOrder( w1 ); 731 polygon.AddVertexInOrder( w1 ); 731 polygon.AddVertexInOrder( w0 ); 732 polygon.AddVertexInOrder( w0 ); 732 733 733 // 734 // 734 // Get extent 735 // Get extent 735 // 736 // 736 if (polygon.PartialClip( voxelLimit, axis 737 if (polygon.PartialClip( voxelLimit, axis )) 737 { 738 { 738 // 739 // 739 // Get dot product of normal with target 740 // Get dot product of normal with target axis 740 // 741 // 741 polygon.SetNormal( deltaV.cross(v1-v0).u 742 polygon.SetNormal( deltaV.cross(v1-v0).unit() ); 742 743 743 extentList.AddSurface( polygon ); 744 extentList.AddSurface( polygon ); 744 } 745 } 745 746 746 if (r2 >= 0) 747 if (r2 >= 0) 747 { 748 { 748 // 749 // 749 // Repeat, for transition piece 750 // Repeat, for transition piece 750 // 751 // 751 w2 = G4ThreeVector( r2*cosPhi, r2*sinPhi 752 w2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, z0 ); 752 transform.ApplyPointTransform( w2 ); 753 transform.ApplyPointTransform( w2 ); 753 754 754 polygon.ClearAllVertices(); 755 polygon.ClearAllVertices(); 755 756 756 polygon.AddVertexInOrder( v2 ); 757 polygon.AddVertexInOrder( v2 ); 757 polygon.AddVertexInOrder( v0 ); 758 polygon.AddVertexInOrder( v0 ); 758 polygon.AddVertexInOrder( w0 ); 759 polygon.AddVertexInOrder( w0 ); 759 polygon.AddVertexInOrder( w2 ); 760 polygon.AddVertexInOrder( w2 ); 760 761 761 if (polygon.PartialClip( voxelLimit, axi 762 if (polygon.PartialClip( voxelLimit, axis )) 762 { 763 { 763 polygon.SetNormal( deltaV.cross(v0-v2) 764 polygon.SetNormal( deltaV.cross(v0-v2).unit() ); 764 765 765 extentList.AddSurface( polygon ); 766 extentList.AddSurface( polygon ); 766 } 767 } 767 768 768 v2 = w2; 769 v2 = w2; 769 } 770 } 770 771 771 // 772 // 772 // Next vertex 773 // Next vertex 773 // 774 // 774 v0 = w0; 775 v0 = w0; 775 v1 = w1; 776 v1 = w1; 776 } while( --numPhi > 0 ); 777 } while( --numPhi > 0 ); 777 778 778 // 779 // 779 // We are almost done. But, it is important 780 // We are almost done. But, it is important that we leave no 780 // gaps in the surface of our solid. By usin 781 // gaps in the surface of our solid. By using rFudge, however, 781 // we've done exactly that, if we have a phi 782 // we've done exactly that, if we have a phi segment. 782 // Add two additional faces if necessary 783 // Add two additional faces if necessary 783 // 784 // 784 if (phiIsOpen && rNorm > DBL_MIN) 785 if (phiIsOpen && rNorm > DBL_MIN) 785 { 786 { 786 cosPhi = std::cos(startPhi); 787 cosPhi = std::cos(startPhi); 787 sinPhi = std::sin(startPhi); 788 sinPhi = std::sin(startPhi); 788 789 789 G4ThreeVector a0( r[0]*cosPhi, r[0]*sinPhi 790 G4ThreeVector a0( r[0]*cosPhi, r[0]*sinPhi, z[0] ), 790 a1( r[1]*cosPhi, r[1]*sinPhi 791 a1( r[1]*cosPhi, r[1]*sinPhi, z[1] ), 791 b0( r0*cosPhi, r0*sinPhi, z[ 792 b0( r0*cosPhi, r0*sinPhi, z[0] ), 792 b1( r1*cosPhi, r1*sinPhi, z[ 793 b1( r1*cosPhi, r1*sinPhi, z[1] ); 793 794 794 transform.ApplyPointTransform( a0 ); 795 transform.ApplyPointTransform( a0 ); 795 transform.ApplyPointTransform( a1 ); 796 transform.ApplyPointTransform( a1 ); 796 transform.ApplyPointTransform( b0 ); 797 transform.ApplyPointTransform( b0 ); 797 transform.ApplyPointTransform( b1 ); 798 transform.ApplyPointTransform( b1 ); 798 799 799 polygon.ClearAllVertices(); 800 polygon.ClearAllVertices(); 800 801 801 polygon.AddVertexInOrder( a0 ); 802 polygon.AddVertexInOrder( a0 ); 802 polygon.AddVertexInOrder( a1 ); 803 polygon.AddVertexInOrder( a1 ); 803 polygon.AddVertexInOrder( b0 ); 804 polygon.AddVertexInOrder( b0 ); 804 polygon.AddVertexInOrder( b1 ); 805 polygon.AddVertexInOrder( b1 ); 805 806 806 if (polygon.PartialClip( voxelLimit , axis 807 if (polygon.PartialClip( voxelLimit , axis)) 807 { 808 { 808 G4ThreeVector normal( sinPhi, -cosPhi, 0 809 G4ThreeVector normal( sinPhi, -cosPhi, 0 ); 809 polygon.SetNormal( transform.TransformAx 810 polygon.SetNormal( transform.TransformAxis( normal ) ); 810 811 811 extentList.AddSurface( polygon ); 812 extentList.AddSurface( polygon ); 812 } 813 } 813 814 814 cosPhi = std::cos(startPhi+deltaPhi); 815 cosPhi = std::cos(startPhi+deltaPhi); 815 sinPhi = std::sin(startPhi+deltaPhi); 816 sinPhi = std::sin(startPhi+deltaPhi); 816 817 817 a0 = G4ThreeVector( r[0]*cosPhi, r[0]*sinP 818 a0 = G4ThreeVector( r[0]*cosPhi, r[0]*sinPhi, z[0] ), 818 a1 = G4ThreeVector( r[1]*cosPhi, r[1]*sinP 819 a1 = G4ThreeVector( r[1]*cosPhi, r[1]*sinPhi, z[1] ), 819 b0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, 820 b0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, z[0] ), 820 b1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, 821 b1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, z[1] ); 821 transform.ApplyPointTransform( a0 ); 822 transform.ApplyPointTransform( a0 ); 822 transform.ApplyPointTransform( a1 ); 823 transform.ApplyPointTransform( a1 ); 823 transform.ApplyPointTransform( b0 ); 824 transform.ApplyPointTransform( b0 ); 824 transform.ApplyPointTransform( b1 ); 825 transform.ApplyPointTransform( b1 ); 825 826 826 polygon.ClearAllVertices(); 827 polygon.ClearAllVertices(); 827 828 828 polygon.AddVertexInOrder( a0 ); 829 polygon.AddVertexInOrder( a0 ); 829 polygon.AddVertexInOrder( a1 ); 830 polygon.AddVertexInOrder( a1 ); 830 polygon.AddVertexInOrder( b0 ); 831 polygon.AddVertexInOrder( b0 ); 831 polygon.AddVertexInOrder( b1 ); 832 polygon.AddVertexInOrder( b1 ); 832 833 833 if (polygon.PartialClip( voxelLimit, axis 834 if (polygon.PartialClip( voxelLimit, axis )) 834 { 835 { 835 G4ThreeVector normal( -sinPhi, cosPhi, 0 836 G4ThreeVector normal( -sinPhi, cosPhi, 0 ); 836 polygon.SetNormal( transform.TransformAx 837 polygon.SetNormal( transform.TransformAxis( normal ) ); 837 838 838 extentList.AddSurface( polygon ); 839 extentList.AddSurface( polygon ); 839 } 840 } 840 } 841 } 841 842 842 return; 843 return; 843 } 844 } 844 845 845 // GetPhi 846 // GetPhi 846 // 847 // 847 // Calculate Phi for a given 3-vector (point), 848 // Calculate Phi for a given 3-vector (point), if not already cached for the 848 // same point, in the attempt to avoid consecu 849 // same point, in the attempt to avoid consecutive computation of the same 849 // quantity 850 // quantity 850 // 851 // 851 G4double G4PolyconeSide::GetPhi( const G4Three 852 G4double G4PolyconeSide::GetPhi( const G4ThreeVector& p ) 852 { 853 { 853 G4double val=0.; 854 G4double val=0.; 854 G4ThreeVector vphi(G4MT_pcphix, G4MT_pcphiy, 855 G4ThreeVector vphi(G4MT_pcphix, G4MT_pcphiy, G4MT_pcphiz); 855 856 856 if (vphi != p) 857 if (vphi != p) 857 { 858 { 858 val = p.phi(); 859 val = p.phi(); 859 G4MT_pcphix = p.x(); G4MT_pcphiy = p.y(); 860 G4MT_pcphix = p.x(); G4MT_pcphiy = p.y(); G4MT_pcphiz = p.z(); 860 G4MT_pcphik = val; 861 G4MT_pcphik = val; 861 } 862 } 862 else 863 else 863 { 864 { 864 val = G4MT_pcphik; 865 val = G4MT_pcphik; 865 } 866 } 866 return val; 867 return val; 867 } 868 } 868 869 869 // DistanceAway 870 // DistanceAway 870 // 871 // 871 // Calculate distance of a point from our coni 872 // Calculate distance of a point from our conical surface, including the effect 872 // of any phi segmentation 873 // of any phi segmentation 873 // 874 // 874 // Arguments: 875 // Arguments: 875 // p - (in) Point to check 876 // p - (in) Point to check 876 // opposite - (in) If true, check opposi 877 // opposite - (in) If true, check opposite hemisphere (see below) 877 // distOutside - (out) Additional distance 878 // distOutside - (out) Additional distance outside the edges of the surface 878 // edgeRZnorm - (out) if negative, point i 879 // edgeRZnorm - (out) if negative, point is inside 879 // 880 // 880 // return value = distance from the conical p 881 // return value = distance from the conical plane, if extrapolated beyond edges, 881 // signed by whether the point 882 // signed by whether the point is in inside or outside the shape 882 // 883 // 883 // Notes: 884 // Notes: 884 // * There are two answers, depending on whic 885 // * There are two answers, depending on which hemisphere is considered. 885 // 886 // 886 G4double G4PolyconeSide::DistanceAway( const G 887 G4double G4PolyconeSide::DistanceAway( const G4ThreeVector& p, 887 G 888 G4bool opposite, 888 G 889 G4double& distOutside2, 889 G 890 G4double* edgeRZnorm ) 890 { 891 { 891 // 892 // 892 // Convert our point to r and z 893 // Convert our point to r and z 893 // 894 // 894 G4double rx = p.perp(), zx = p.z(); 895 G4double rx = p.perp(), zx = p.z(); 895 896 896 // 897 // 897 // Change sign of r if opposite says we shou 898 // Change sign of r if opposite says we should 898 // 899 // 899 if (opposite) rx = -rx; 900 if (opposite) rx = -rx; 900 901 901 // 902 // 902 // Calculate return value 903 // Calculate return value 903 // 904 // 904 G4double deltaR = rx - r[0], deltaZ = zx - 905 G4double deltaR = rx - r[0], deltaZ = zx - z[0]; 905 G4double answer = deltaR*rNorm + deltaZ*zNor 906 G4double answer = deltaR*rNorm + deltaZ*zNorm; 906 907 907 // 908 // 908 // Are we off the surface in r,z space? 909 // Are we off the surface in r,z space? 909 // 910 // 910 G4double q = deltaR*rS + deltaZ*zS; 911 G4double q = deltaR*rS + deltaZ*zS; 911 if (q < 0) 912 if (q < 0) 912 { 913 { 913 distOutside2 = q*q; 914 distOutside2 = q*q; 914 if (edgeRZnorm != nullptr) 915 if (edgeRZnorm != nullptr) 915 *edgeRZnorm = deltaR*rNormEdge[0] + delt 916 *edgeRZnorm = deltaR*rNormEdge[0] + deltaZ*zNormEdge[0]; 916 } 917 } 917 else if (q > length) 918 else if (q > length) 918 { 919 { 919 distOutside2 = sqr( q-length ); 920 distOutside2 = sqr( q-length ); 920 if (edgeRZnorm != nullptr) 921 if (edgeRZnorm != nullptr) 921 { 922 { 922 deltaR = rx - r[1]; 923 deltaR = rx - r[1]; 923 deltaZ = zx - z[1]; 924 deltaZ = zx - z[1]; 924 *edgeRZnorm = deltaR*rNormEdge[1] + delt 925 *edgeRZnorm = deltaR*rNormEdge[1] + deltaZ*zNormEdge[1]; 925 } 926 } 926 } 927 } 927 else 928 else 928 { 929 { 929 distOutside2 = 0.; 930 distOutside2 = 0.; 930 if (edgeRZnorm != nullptr) *edgeRZnorm = a 931 if (edgeRZnorm != nullptr) *edgeRZnorm = answer; 931 } 932 } 932 933 933 if (phiIsOpen) 934 if (phiIsOpen) 934 { 935 { 935 // 936 // 936 // Finally, check phi 937 // Finally, check phi 937 // 938 // 938 G4double phi = GetPhi(p); 939 G4double phi = GetPhi(p); 939 while( phi < startPhi ) // Loop checkin 940 while( phi < startPhi ) // Loop checking, 13.08.2015, G.Cosmo 940 phi += twopi; 941 phi += twopi; 941 942 942 if (phi > startPhi+deltaPhi) 943 if (phi > startPhi+deltaPhi) 943 { 944 { 944 // 945 // 945 // Oops. Are we closer to the start phi 946 // Oops. Are we closer to the start phi or end phi? 946 // 947 // 947 G4double d1 = phi-startPhi-deltaPhi; 948 G4double d1 = phi-startPhi-deltaPhi; 948 while( phi > startPhi ) // Loop check 949 while( phi > startPhi ) // Loop checking, 13.08.2015, G.Cosmo 949 phi -= twopi; 950 phi -= twopi; 950 G4double d2 = startPhi-phi; 951 G4double d2 = startPhi-phi; 951 952 952 if (d2 < d1) d1 = d2; 953 if (d2 < d1) d1 = d2; 953 954 954 // 955 // 955 // Add result to our distance 956 // Add result to our distance 956 // 957 // 957 G4double dist = d1*rx; 958 G4double dist = d1*rx; 958 959 959 distOutside2 += dist*dist; 960 distOutside2 += dist*dist; 960 if (edgeRZnorm != nullptr) 961 if (edgeRZnorm != nullptr) 961 { 962 { 962 *edgeRZnorm = std::max(std::fabs(*edge 963 *edgeRZnorm = std::max(std::fabs(*edgeRZnorm),std::fabs(dist)); 963 } 964 } 964 } 965 } 965 } 966 } 966 967 967 return answer; 968 return answer; 968 } 969 } 969 970 970 // DistanceAway 971 // DistanceAway 971 // 972 // 972 // Special version of DistanceAway for Inside. 973 // Special version of DistanceAway for Inside. 973 // Opposite parameter is not used, instead use 974 // Opposite parameter is not used, instead use sign of rx for choosing the side 974 // 975 // 975 G4double G4PolyconeSide::DistanceAway( const G 976 G4double G4PolyconeSide::DistanceAway( const G4ThreeVector& p, 976 G 977 G4double& distOutside2, 977 G 978 G4double* edgeRZnorm ) 978 { 979 { 979 // 980 // 980 // Convert our point to r and z 981 // Convert our point to r and z 981 // 982 // 982 G4double rx = p.perp(), zx = p.z(); 983 G4double rx = p.perp(), zx = p.z(); 983 984 984 // 985 // 985 // Change sign of r if we should 986 // Change sign of r if we should 986 // 987 // 987 G4int part = 1; 988 G4int part = 1; 988 if (rx < 0) part = -1; 989 if (rx < 0) part = -1; 989 990 990 // 991 // 991 // Calculate return value 992 // Calculate return value 992 // 993 // 993 G4double deltaR = rx - r[0]*part, deltaZ = z 994 G4double deltaR = rx - r[0]*part, deltaZ = zx - z[0]; 994 G4double answer = deltaR*rNorm*part + deltaZ 995 G4double answer = deltaR*rNorm*part + deltaZ*zNorm; 995 996 996 // 997 // 997 // Are we off the surface in r,z space? 998 // Are we off the surface in r,z space? 998 // 999 // 999 G4double q = deltaR*rS*part + deltaZ*zS; 1000 G4double q = deltaR*rS*part + deltaZ*zS; 1000 if (q < 0) 1001 if (q < 0) 1001 { 1002 { 1002 distOutside2 = q*q; 1003 distOutside2 = q*q; 1003 if (edgeRZnorm != nullptr) 1004 if (edgeRZnorm != nullptr) 1004 { 1005 { 1005 *edgeRZnorm = deltaR*rNormEdge[0]*part 1006 *edgeRZnorm = deltaR*rNormEdge[0]*part + deltaZ*zNormEdge[0]; 1006 } 1007 } 1007 } 1008 } 1008 else if (q > length) 1009 else if (q > length) 1009 { 1010 { 1010 distOutside2 = sqr( q-length ); 1011 distOutside2 = sqr( q-length ); 1011 if (edgeRZnorm != nullptr) 1012 if (edgeRZnorm != nullptr) 1012 { 1013 { 1013 deltaR = rx - r[1]*part; 1014 deltaR = rx - r[1]*part; 1014 deltaZ = zx - z[1]; 1015 deltaZ = zx - z[1]; 1015 *edgeRZnorm = deltaR*rNormEdge[1]*part 1016 *edgeRZnorm = deltaR*rNormEdge[1]*part + deltaZ*zNormEdge[1]; 1016 } 1017 } 1017 } 1018 } 1018 else 1019 else 1019 { 1020 { 1020 distOutside2 = 0.; 1021 distOutside2 = 0.; 1021 if (edgeRZnorm != nullptr) *edgeRZnorm = 1022 if (edgeRZnorm != nullptr) *edgeRZnorm = answer; 1022 } 1023 } 1023 1024 1024 if (phiIsOpen) 1025 if (phiIsOpen) 1025 { 1026 { 1026 // 1027 // 1027 // Finally, check phi 1028 // Finally, check phi 1028 // 1029 // 1029 G4double phi = GetPhi(p); 1030 G4double phi = GetPhi(p); 1030 while( phi < startPhi ) // Loop checki 1031 while( phi < startPhi ) // Loop checking, 13.08.2015, G.Cosmo 1031 phi += twopi; 1032 phi += twopi; 1032 1033 1033 if (phi > startPhi+deltaPhi) 1034 if (phi > startPhi+deltaPhi) 1034 { 1035 { 1035 // 1036 // 1036 // Oops. Are we closer to the start phi 1037 // Oops. Are we closer to the start phi or end phi? 1037 // 1038 // 1038 G4double d1 = phi-startPhi-deltaPhi; 1039 G4double d1 = phi-startPhi-deltaPhi; 1039 while( phi > startPhi ) // Loop chec 1040 while( phi > startPhi ) // Loop checking, 13.08.2015, G.Cosmo 1040 phi -= twopi; 1041 phi -= twopi; 1041 G4double d2 = startPhi-phi; 1042 G4double d2 = startPhi-phi; 1042 1043 1043 if (d2 < d1) d1 = d2; 1044 if (d2 < d1) d1 = d2; 1044 1045 1045 // 1046 // 1046 // Add result to our distance 1047 // Add result to our distance 1047 // 1048 // 1048 G4double dist = d1*rx*part; 1049 G4double dist = d1*rx*part; 1049 1050 1050 distOutside2 += dist*dist; 1051 distOutside2 += dist*dist; 1051 if (edgeRZnorm != nullptr) 1052 if (edgeRZnorm != nullptr) 1052 { 1053 { 1053 *edgeRZnorm = std::max(std::fabs(*edg 1054 *edgeRZnorm = std::max(std::fabs(*edgeRZnorm),std::fabs(dist)); 1054 } 1055 } 1055 } 1056 } 1056 } 1057 } 1057 1058 1058 return answer; 1059 return answer; 1059 } 1060 } 1060 1061 1061 // PointOnCone 1062 // PointOnCone 1062 // 1063 // 1063 // Decide if a point is on a cone and return 1064 // Decide if a point is on a cone and return normal if it is 1064 // 1065 // 1065 G4bool G4PolyconeSide::PointOnCone( const G4T 1066 G4bool G4PolyconeSide::PointOnCone( const G4ThreeVector& hit, 1066 G4d 1067 G4double normSign, 1067 const G4T 1068 const G4ThreeVector& p, 1068 const G4T 1069 const G4ThreeVector& v, 1069 G4T 1070 G4ThreeVector& normal ) 1070 { 1071 { 1071 G4double rx = hit.perp(); 1072 G4double rx = hit.perp(); 1072 // 1073 // 1073 // Check radial/z extent, as appropriate 1074 // Check radial/z extent, as appropriate 1074 // 1075 // 1075 if (!cone->HitOn( rx, hit.z() )) return fal 1076 if (!cone->HitOn( rx, hit.z() )) return false; 1076 1077 1077 if (phiIsOpen) 1078 if (phiIsOpen) 1078 { 1079 { 1079 G4double phiTolerant = 2.0*kCarTolerance/ 1080 G4double phiTolerant = 2.0*kCarTolerance/(rx+kCarTolerance); 1080 // 1081 // 1081 // Check phi segment. Here we have to be 1082 // Check phi segment. Here we have to be careful 1082 // to use the standard method consistent 1083 // to use the standard method consistent with 1083 // PolyPhiFace. See PolyPhiFace::InsideEd 1084 // PolyPhiFace. See PolyPhiFace::InsideEdgesExact 1084 // 1085 // 1085 G4double phi = GetPhi(hit); 1086 G4double phi = GetPhi(hit); 1086 while( phi < startPhi-phiTolerant ) // 1087 while( phi < startPhi-phiTolerant ) // Loop checking, 13.08.2015, G.Cosmo 1087 phi += twopi; 1088 phi += twopi; 1088 1089 1089 if (phi > startPhi+deltaPhi+phiTolerant) 1090 if (phi > startPhi+deltaPhi+phiTolerant) return false; 1090 1091 1091 if (phi > startPhi+deltaPhi-phiTolerant) 1092 if (phi > startPhi+deltaPhi-phiTolerant) 1092 { 1093 { 1093 // 1094 // 1094 // Exact treatment 1095 // Exact treatment 1095 // 1096 // 1096 G4ThreeVector qx = p + v; 1097 G4ThreeVector qx = p + v; 1097 G4ThreeVector qa = qx - corners[2], 1098 G4ThreeVector qa = qx - corners[2], 1098 qb = qx - corners[3]; 1099 qb = qx - corners[3]; 1099 G4ThreeVector qacb = qa.cross(qb); 1100 G4ThreeVector qacb = qa.cross(qb); 1100 1101 1101 if (normSign*qacb.dot(v) < 0) return fa 1102 if (normSign*qacb.dot(v) < 0) return false; 1102 } 1103 } 1103 else if (phi < phiTolerant) 1104 else if (phi < phiTolerant) 1104 { 1105 { 1105 G4ThreeVector qx = p + v; 1106 G4ThreeVector qx = p + v; 1106 G4ThreeVector qa = qx - corners[1], 1107 G4ThreeVector qa = qx - corners[1], 1107 qb = qx - corners[0]; 1108 qb = qx - corners[0]; 1108 G4ThreeVector qacb = qa.cross(qb); 1109 G4ThreeVector qacb = qa.cross(qb); 1109 1110 1110 if (normSign*qacb.dot(v) < 0) return fa 1111 if (normSign*qacb.dot(v) < 0) return false; 1111 } 1112 } 1112 } 1113 } 1113 1114 1114 // 1115 // 1115 // We have a good hit! Calculate normal 1116 // We have a good hit! Calculate normal 1116 // 1117 // 1117 if (rx < DBL_MIN) 1118 if (rx < DBL_MIN) 1118 normal = G4ThreeVector( 0, 0, zNorm < 0 ? 1119 normal = G4ThreeVector( 0, 0, zNorm < 0 ? -1 : 1 ); 1119 else 1120 else 1120 normal = G4ThreeVector( rNorm*hit.x()/rx, 1121 normal = G4ThreeVector( rNorm*hit.x()/rx, rNorm*hit.y()/rx, zNorm ); 1121 return true; 1122 return true; 1122 } 1123 } 1123 1124 1124 // FindLineIntersect 1125 // FindLineIntersect 1125 // 1126 // 1126 // Decide the point at which two 2-dimensiona 1127 // Decide the point at which two 2-dimensional lines intersect 1127 // 1128 // 1128 // Equation of line: x = x1 + s*tx1 1129 // Equation of line: x = x1 + s*tx1 1129 // y = y1 + s*ty1 1130 // y = y1 + s*ty1 1130 // 1131 // 1131 // It is assumed that the lines are *not* par 1132 // It is assumed that the lines are *not* parallel 1132 // 1133 // 1133 void G4PolyconeSide::FindLineIntersect( G4dou 1134 void G4PolyconeSide::FindLineIntersect( G4double x1, G4double y1, 1134 G4dou 1135 G4double tx1, G4double ty1, 1135 G4dou 1136 G4double x2, G4double y2, 1136 G4dou 1137 G4double tx2, G4double ty2, 1137 G4dou 1138 G4double& x, G4double& y ) 1138 { 1139 { 1139 // 1140 // 1140 // The solution is a simple linear equation 1141 // The solution is a simple linear equation 1141 // 1142 // 1142 G4double deter = tx1*ty2 - tx2*ty1; 1143 G4double deter = tx1*ty2 - tx2*ty1; 1143 1144 1144 G4double s1 = ((x2-x1)*ty2 - tx2*(y2-y1))/d 1145 G4double s1 = ((x2-x1)*ty2 - tx2*(y2-y1))/deter; 1145 G4double s2 = ((x2-x1)*ty1 - tx1*(y2-y1))/d 1146 G4double s2 = ((x2-x1)*ty1 - tx1*(y2-y1))/deter; 1146 1147 1147 // 1148 // 1148 // We want the answer to not depend on whic 1149 // We want the answer to not depend on which order the 1149 // lines were specified. Take average. 1150 // lines were specified. Take average. 1150 // 1151 // 1151 x = 0.5*( x1+s1*tx1 + x2+s2*tx2 ); 1152 x = 0.5*( x1+s1*tx1 + x2+s2*tx2 ); 1152 y = 0.5*( y1+s1*ty1 + y2+s2*ty2 ); 1153 y = 0.5*( y1+s1*ty1 + y2+s2*ty2 ); 1153 } 1154 } 1154 1155 1155 // Calculate surface area for GetPointOnSurfa 1156 // Calculate surface area for GetPointOnSurface() 1156 // 1157 // 1157 G4double G4PolyconeSide::SurfaceArea() 1158 G4double G4PolyconeSide::SurfaceArea() 1158 { 1159 { 1159 if(fSurfaceArea==0.) 1160 if(fSurfaceArea==0.) 1160 { 1161 { 1161 fSurfaceArea = (r[0]+r[1])* std::sqrt(sqr 1162 fSurfaceArea = (r[0]+r[1])* std::sqrt(sqr(r[0]-r[1])+sqr(z[0]-z[1])); 1162 fSurfaceArea *= 0.5*(deltaPhi); 1163 fSurfaceArea *= 0.5*(deltaPhi); 1163 } 1164 } 1164 return fSurfaceArea; 1165 return fSurfaceArea; 1165 } 1166 } 1166 1167 1167 // GetPointOnFace 1168 // GetPointOnFace 1168 // 1169 // 1169 G4ThreeVector G4PolyconeSide::GetPointOnFace( 1170 G4ThreeVector G4PolyconeSide::GetPointOnFace() 1170 { 1171 { 1171 G4double x,y,zz; 1172 G4double x,y,zz; 1172 G4double rr,phi,dz,dr; 1173 G4double rr,phi,dz,dr; 1173 dr=r[1]-r[0];dz=z[1]-z[0]; 1174 dr=r[1]-r[0];dz=z[1]-z[0]; 1174 phi=startPhi+deltaPhi*G4UniformRand(); 1175 phi=startPhi+deltaPhi*G4UniformRand(); 1175 rr=r[0]+dr*G4UniformRand(); 1176 rr=r[0]+dr*G4UniformRand(); 1176 1177 1177 x=rr*std::cos(phi); 1178 x=rr*std::cos(phi); 1178 y=rr*std::sin(phi); 1179 y=rr*std::sin(phi); 1179 1180 1180 // PolyconeSide has a Ring Form 1181 // PolyconeSide has a Ring Form 1181 // 1182 // 1182 if (dz==0.) 1183 if (dz==0.) 1183 { 1184 { 1184 zz=z[0]; 1185 zz=z[0]; 1185 } 1186 } 1186 else 1187 else 1187 { 1188 { 1188 if(dr==0.) // PolyconeSide has a Tube Fo 1189 if(dr==0.) // PolyconeSide has a Tube Form 1189 { 1190 { 1190 zz = z[0]+dz*G4UniformRand(); 1191 zz = z[0]+dz*G4UniformRand(); 1191 } 1192 } 1192 else 1193 else 1193 { 1194 { 1194 zz = z[0]+(rr-r[0])*dz/dr; 1195 zz = z[0]+(rr-r[0])*dz/dr; 1195 } 1196 } 1196 } 1197 } 1197 1198 1198 return {x,y,zz}; << 1199 return G4ThreeVector(x,y,zz); 1199 } 1200 } 1200 1201