Geant4 Cross Reference |
1 // 1 2 // ******************************************* 3 // * License and Disclaimer 4 // * 5 // * The Geant4 software is copyright of th 6 // * the Geant4 Collaboration. It is provided 7 // * conditions of the Geant4 Software License 8 // * LICENSE and available at http://cern.ch/ 9 // * include a list of copyright holders. 10 // * 11 // * Neither the authors of this software syst 12 // * institutes,nor the agencies providing fin 13 // * work make any representation or warran 14 // * regarding this software system or assum 15 // * use. Please see the license in the file 16 // * for the full disclaimer and the limitatio 17 // * 18 // * This code implementation is the result 19 // * technical work of the GEANT4 collaboratio 20 // * By using, copying, modifying or distri 21 // * any work based on the software) you ag 22 // * use in resulting scientific publicati 23 // * acceptance of all terms of the Geant4 Sof 24 // ******************************************* 25 // 26 // Implementation of G4UPolyhedra wrapper clas 27 // 28 // 31.10.13 G.Cosmo, CERN 29 // ------------------------------------------- 30 31 #include "G4Polyhedra.hh" 32 #include "G4UPolyhedra.hh" 33 34 #if ( defined(G4GEOM_USE_USOLIDS) || defined(G 35 36 #include "G4GeomTools.hh" 37 #include "G4GeometryTolerance.hh" 38 #include "G4AffineTransform.hh" 39 #include "G4VPVParameterisation.hh" 40 #include "G4BoundingEnvelope.hh" 41 42 using namespace CLHEP; 43 44 ////////////////////////////////////////////// 45 // 46 // Constructor (GEANT3 style parameters) 47 // 48 // GEANT3 PGON radii are specified in the dist 49 // 50 G4UPolyhedra::G4UPolyhedra(const G4String& nam 51 G4double phiS 52 G4double phiT 53 G4int numSide 54 G4int numZPla 55 const G4double zPla 56 const G4double rInn 57 const G4double rOut 58 : Base_t(name, phiStart, phiTotal, numSide, 59 numZPlanes, zPlane, rInner, rOuter) 60 { 61 fGenericPgon = false; 62 SetOriginalParameters(); 63 wrStart = phiStart; 64 while (wrStart < 0) 65 { 66 wrStart += twopi; 67 } 68 wrDelta = phiTotal; 69 if (wrDelta <= 0. || wrDelta >= twopi*(1-DBL 70 { 71 wrDelta = twopi; 72 } 73 wrNumSide = numSide; 74 G4double convertRad = 1./std::cos(0.5*wrDelt 75 rzcorners.resize(0); 76 for (G4int i=0; i<numZPlanes; ++i) 77 { 78 G4double z = zPlane[i]; 79 G4double r = rOuter[i]*convertRad; 80 rzcorners.emplace_back(r,z); 81 } 82 for (G4int i=numZPlanes-1; i>=0; --i) 83 { 84 G4double z = zPlane[i]; 85 G4double r = rInner[i]*convertRad; 86 rzcorners.emplace_back(r,z); 87 } 88 std::vector<G4int> iout; 89 G4GeomTools::RemoveRedundantVertices(rzcorne 90 } 91 92 93 ////////////////////////////////////////////// 94 // 95 // Constructor (generic parameters) 96 // 97 G4UPolyhedra::G4UPolyhedra(const G4String& nam 98 G4double phiS 99 G4double phiT 100 G4int numS 101 G4int numR 102 const G4double r[], 103 const G4double z[] 104 : Base_t(name, phiStart, phiTotal, numSide, 105 { 106 fGenericPgon = true; 107 SetOriginalParameters(); 108 wrStart = phiStart; 109 while (wrStart < 0.) 110 { 111 wrStart += twopi; 112 } 113 wrDelta = phiTotal; 114 if (wrDelta <= 0. || wrDelta >= twopi*(1-DBL 115 { 116 wrDelta = twopi; 117 } 118 wrNumSide = numSide; 119 rzcorners.resize(0); 120 for (G4int i=0; i<numRZ; ++i) 121 { 122 rzcorners.emplace_back(r[i],z[i]); 123 } 124 std::vector<G4int> iout; 125 G4GeomTools::RemoveRedundantVertices(rzcorne 126 } 127 128 129 ////////////////////////////////////////////// 130 // 131 // Fake default constructor - sets only member 132 // for usage restri 133 // 134 G4UPolyhedra::G4UPolyhedra( __void__& a ) 135 : Base_t(a) 136 { 137 } 138 139 140 ////////////////////////////////////////////// 141 // 142 // Destructor 143 // 144 G4UPolyhedra::~G4UPolyhedra() = default; 145 146 147 ////////////////////////////////////////////// 148 // 149 // Copy constructor 150 // 151 G4UPolyhedra::G4UPolyhedra( const G4UPolyhedra 152 : Base_t( source ) 153 { 154 fGenericPgon = source.fGenericPgon; 155 fOriginalParameters = source.fOriginalParame 156 wrStart = source.wrStart; 157 wrDelta = source.wrDelta; 158 wrNumSide = source.wrNumSide; 159 rzcorners = source.rzcorners; 160 } 161 162 163 ////////////////////////////////////////////// 164 // 165 // Assignment operator 166 // 167 G4UPolyhedra& G4UPolyhedra::operator=( const G 168 { 169 if (this == &source) return *this; 170 171 Base_t::operator=( source ); 172 fGenericPgon = source.fGenericPgon; 173 fOriginalParameters = source.fOriginalParame 174 wrStart = source.wrStart; 175 wrDelta = source.wrDelta; 176 wrNumSide = source.wrNumSide; 177 rzcorners = source.rzcorners; 178 179 return *this; 180 } 181 182 183 ////////////////////////////////////////////// 184 // 185 // Accessors & modifiers 186 // 187 G4int G4UPolyhedra::GetNumSide() const 188 { 189 return wrNumSide; 190 } 191 G4double G4UPolyhedra::GetStartPhi() const 192 { 193 return wrStart; 194 } 195 G4double G4UPolyhedra::GetEndPhi() const 196 { 197 return (wrStart + wrDelta); 198 } 199 G4double G4UPolyhedra::GetSinStartPhi() const 200 { 201 G4double phi = GetStartPhi(); 202 return std::sin(phi); 203 } 204 G4double G4UPolyhedra::GetCosStartPhi() const 205 { 206 G4double phi = GetStartPhi(); 207 return std::cos(phi); 208 } 209 G4double G4UPolyhedra::GetSinEndPhi() const 210 { 211 G4double phi = GetEndPhi(); 212 return std::sin(phi); 213 } 214 G4double G4UPolyhedra::GetCosEndPhi() const 215 { 216 G4double phi = GetEndPhi(); 217 return std::cos(phi); 218 } 219 G4bool G4UPolyhedra::IsOpen() const 220 { 221 return (wrDelta < twopi); 222 } 223 G4bool G4UPolyhedra::IsGeneric() const 224 { 225 return fGenericPgon; 226 } 227 G4int G4UPolyhedra::GetNumRZCorner() const 228 { 229 return rzcorners.size(); 230 } 231 G4PolyhedraSideRZ G4UPolyhedra::GetCorner(G4in 232 { 233 G4TwoVector rz = rzcorners.at(index); 234 G4PolyhedraSideRZ psiderz = { rz.x(), rz.y() 235 236 return psiderz; 237 } 238 G4PolyhedraHistorical* G4UPolyhedra::GetOrigin 239 { 240 return new G4PolyhedraHistorical(fOriginalPa 241 } 242 void G4UPolyhedra::SetOriginalParameters() 243 { 244 G4double startPhi = GetPhiStart(); 245 G4double deltaPhi = GetPhiDelta(); 246 G4int numPlanes = GetZSegmentCount() + 1; 247 G4int numSides = GetSideCount(); 248 249 fOriginalParameters.Start_angle = startPhi 250 fOriginalParameters.Opening_angle = deltaPhi 251 fOriginalParameters.Num_z_planes = numPlane 252 fOriginalParameters.numSide = numSides 253 254 delete [] fOriginalParameters.Z_values; 255 delete [] fOriginalParameters.Rmin; 256 delete [] fOriginalParameters.Rmax; 257 fOriginalParameters.Z_values = new G4double[ 258 fOriginalParameters.Rmin = new G4double[numP 259 fOriginalParameters.Rmax = new G4double[numP 260 261 G4double convertRad = fGenericPgon 262 ? 1.0 : std::cos(0.5*del 263 for (G4int i=0; i<numPlanes; ++i) 264 { 265 fOriginalParameters.Z_values[i] = GetZPlan 266 fOriginalParameters.Rmax[i] = GetRMax( 267 fOriginalParameters.Rmin[i] = GetRMin( 268 } 269 } 270 void G4UPolyhedra::SetOriginalParameters(G4Pol 271 { 272 fOriginalParameters = *pars; 273 fRebuildPolyhedron = true; 274 Reset(); 275 } 276 277 G4bool G4UPolyhedra::Reset() 278 { 279 if (fGenericPgon) 280 { 281 std::ostringstream message; 282 message << "Solid " << GetName() << " buil 283 << G4endl << "Not applicable to th 284 G4Exception("G4UPolyhedra::Reset()", "Geom 285 JustWarning, message, "Paramet 286 return true; // error code set 287 } 288 289 // 290 // Rebuild polyhedra based on original param 291 // 292 wrStart = fOriginalParameters.Start_angle; 293 while (wrStart < 0.) 294 { 295 wrStart += twopi; 296 } 297 wrDelta = fOriginalParameters.Opening_angle; 298 if (wrDelta <= 0. || wrDelta >= twopi*(1-DBL 299 { 300 wrDelta = twopi; 301 } 302 wrNumSide = fOriginalParameters.numSide; 303 rzcorners.resize(0); 304 for (G4int i=0; i<fOriginalParameters.Num_z_ 305 { 306 G4double z = fOriginalParameters.Z_values[ 307 G4double r = fOriginalParameters.Rmax[i]; 308 rzcorners.emplace_back(r,z); 309 } 310 for (G4int i=fOriginalParameters.Num_z_plane 311 { 312 G4double z = fOriginalParameters.Z_values[ 313 G4double r = fOriginalParameters.Rmin[i]; 314 rzcorners.emplace_back(r,z); 315 } 316 std::vector<G4int> iout; 317 G4GeomTools::RemoveRedundantVertices(rzcorne 318 319 return false; // error code unset 320 } 321 322 323 ////////////////////////////////////////////// 324 // 325 // Dispatch to parameterisation for replicatio 326 // computation & modification. 327 // 328 void G4UPolyhedra::ComputeDimensions(G4VPVPara 329 const G4i 330 const G4V 331 { 332 p->ComputeDimensions(*(G4Polyhedra*)this,n,p 333 } 334 335 336 ////////////////////////////////////////////// 337 // 338 // Make a clone of the object 339 340 G4VSolid* G4UPolyhedra::Clone() const 341 { 342 return new G4UPolyhedra(*this); 343 } 344 345 346 ////////////////////////////////////////////// 347 // 348 // Get bounding box 349 350 void G4UPolyhedra::BoundingLimits(G4ThreeVecto 351 G4ThreeVecto 352 { 353 static G4bool checkBBox = true; 354 static G4bool checkPhi = true; 355 356 G4double rmin = kInfinity, rmax = -kInfinity 357 G4double zmin = kInfinity, zmax = -kInfinity 358 for (G4int i=0; i<GetNumRZCorner(); ++i) 359 { 360 G4PolyhedraSideRZ corner = GetCorner(i); 361 if (corner.r < rmin) rmin = corner.r; 362 if (corner.r > rmax) rmax = corner.r; 363 if (corner.z < zmin) zmin = corner.z; 364 if (corner.z > zmax) zmax = corner.z; 365 } 366 367 G4double sphi = GetStartPhi(); 368 G4double ephi = GetEndPhi(); 369 G4double dphi = IsOpen() ? ephi-sphi : tw 370 G4int ksteps = GetNumSide(); 371 G4double astep = dphi/ksteps; 372 G4double sinStep = std::sin(astep); 373 G4double cosStep = std::cos(astep); 374 375 G4double sinCur = GetSinStartPhi(); 376 G4double cosCur = GetCosStartPhi(); 377 if (!IsOpen()) rmin = 0.; 378 G4double xmin = rmin*cosCur, xmax = xmin; 379 G4double ymin = rmin*sinCur, ymax = ymin; 380 for (G4int k=0; k<ksteps+1; ++k) 381 { 382 G4double x = rmax*cosCur; 383 if (x < xmin) xmin = x; 384 if (x > xmax) xmax = x; 385 G4double y = rmax*sinCur; 386 if (y < ymin) ymin = y; 387 if (y > ymax) ymax = y; 388 if (rmin > 0.) 389 { 390 G4double xx = rmin*cosCur; 391 if (xx < xmin) xmin = xx; 392 if (xx > xmax) xmax = xx; 393 G4double yy = rmin*sinCur; 394 if (yy < ymin) ymin = yy; 395 if (yy > ymax) ymax = yy; 396 } 397 G4double sinTmp = sinCur; 398 sinCur = sinCur*cosStep + cosCur*sinStep; 399 cosCur = cosCur*cosStep - sinTmp*sinStep; 400 } 401 pMin.set(xmin,ymin,zmin); 402 pMax.set(xmax,ymax,zmax); 403 404 // Check correctness of the bounding box 405 // 406 if (pMin.x() >= pMax.x() || pMin.y() >= pMax 407 { 408 std::ostringstream message; 409 message << "Bad bounding box (min >= max) 410 << GetName() << " !" 411 << "\npMin = " << pMin 412 << "\npMax = " << pMax; 413 G4Exception("G4UPolyhedra::BoundingLimits( 414 JustWarning, message); 415 StreamInfo(G4cout); 416 } 417 418 // Check consistency of bounding boxes 419 // 420 if (checkBBox) 421 { 422 U3Vector vmin, vmax; 423 Extent(vmin,vmax); 424 if (std::abs(pMin.x()-vmin.x()) > kCarTole 425 std::abs(pMin.y()-vmin.y()) > kCarTole 426 std::abs(pMin.z()-vmin.z()) > kCarTole 427 std::abs(pMax.x()-vmax.x()) > kCarTole 428 std::abs(pMax.y()-vmax.y()) > kCarTole 429 std::abs(pMax.z()-vmax.z()) > kCarTole 430 { 431 std::ostringstream message; 432 message << "Inconsistency in bounding bo 433 << GetName() << " !" 434 << "\nBBox min: wrapper = " << p 435 << "\nBBox max: wrapper = " << p 436 G4Exception("G4UPolyhedra::BoundingLimit 437 JustWarning, message); 438 checkBBox = false; 439 } 440 } 441 442 // Check consistency of angles 443 // 444 if (checkPhi) 445 { 446 if (GetStartPhi() != GetPhiStart() || 447 GetEndPhi() != GetPhiEnd() || 448 GetNumSide() != GetSideCount() || 449 IsOpen() != (Base_t::GetPhiDelta( 450 { 451 std::ostringstream message; 452 message << "Inconsistency in Phi angles 453 << GetName() << " !" 454 << "\nPhi start : wrapper = " < 455 << " solid = " << GetPhiStar 456 << "\nPhi end : wrapper = " < 457 << " solid = " << GetPhiEnd( 458 << "\nPhi # sides: wrapper = " < 459 << " solid = " << GetSideCou 460 << "\nPhi is open: wrapper = " < 461 << " solid = " 462 << ((Base_t::GetPhiDelta() < two 463 G4Exception("G4UPolyhedra::BoundingLimit 464 JustWarning, message); 465 checkPhi = false; 466 } 467 } 468 } 469 470 ////////////////////////////////////////////// 471 // 472 // Calculate extent under transform and specif 473 474 G4bool 475 G4UPolyhedra::CalculateExtent(const EAxis pAxi 476 const G4VoxelLim 477 const G4AffineTr 478 G4double& 479 { 480 G4ThreeVector bmin, bmax; 481 G4bool exist; 482 483 // Check bounding box (bbox) 484 // 485 BoundingLimits(bmin,bmax); 486 G4BoundingEnvelope bbox(bmin,bmax); 487 #ifdef G4BBOX_EXTENT 488 if (true) return bbox.CalculateExtent(pAxis, 489 #endif 490 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVox 491 { 492 return exist = pMin < pMax; 493 } 494 495 // To find the extent, RZ contour of the pol 496 // in triangles. The extent is calculated as 497 // all sub-polycones formed by rotation of t 498 // 499 G4TwoVectorList contourRZ; 500 G4TwoVectorList triangles; 501 std::vector<G4int> iout; 502 G4double eminlim = pVoxelLimit.GetMinExtent( 503 G4double emaxlim = pVoxelLimit.GetMaxExtent( 504 505 // get RZ contour, ensure anticlockwise orde 506 for (G4int i=0; i<GetNumRZCorner(); ++i) 507 { 508 G4PolyhedraSideRZ corner = GetCorner(i); 509 contourRZ.emplace_back(corner.r,corner.z); 510 } 511 G4GeomTools::RemoveRedundantVertices(contour 512 G4double area = G4GeomTools::PolygonArea(con 513 if (area < 0.) std::reverse(contourRZ.begin( 514 515 // triangulate RZ countour 516 if (!G4GeomTools::TriangulatePolygon(contour 517 { 518 std::ostringstream message; 519 message << "Triangulation of RZ contour ha 520 << GetName() << " !" 521 << "\nExtent has been calculated u 522 G4Exception("G4UPolyhedra::CalculateExtent 523 "GeomMgt1002",JustWarning,mess 524 return bbox.CalculateExtent(pAxis,pVoxelLi 525 } 526 527 // set trigonometric values 528 G4double sphi = GetStartPhi(); 529 G4double ephi = GetEndPhi(); 530 G4double dphi = IsOpen() ? ephi-sphi : t 531 G4int ksteps = GetNumSide(); 532 G4double astep = dphi/ksteps; 533 G4double sinStep = std::sin(astep); 534 G4double cosStep = std::cos(astep); 535 G4double sinStart = GetSinStartPhi(); 536 G4double cosStart = GetCosStartPhi(); 537 538 // allocate vector lists 539 std::vector<const G4ThreeVectorList *> polyg 540 polygons.resize(ksteps+1); 541 for (G4int k=0; k<ksteps+1; ++k) 542 { 543 polygons[k] = new G4ThreeVectorList(3); 544 } 545 546 // main loop along triangles 547 pMin = kInfinity; 548 pMax = -kInfinity; 549 G4int ntria = triangles.size()/3; 550 for (G4int i=0; i<ntria; ++i) 551 { 552 G4double sinCur = sinStart; 553 G4double cosCur = cosStart; 554 G4int i3 = i*3; 555 for (G4int k=0; k<ksteps+1; ++k) // rotate 556 { 557 auto ptr = const_cast<G4ThreeVectorList* 558 auto iter = ptr->begin(); 559 iter->set(triangles[i3+0].x()*cosCur, 560 triangles[i3+0].x()*sinCur, 561 triangles[i3+0].y()); 562 iter++; 563 iter->set(triangles[i3+1].x()*cosCur, 564 triangles[i3+1].x()*sinCur, 565 triangles[i3+1].y()); 566 iter++; 567 iter->set(triangles[i3+2].x()*cosCur, 568 triangles[i3+2].x()*sinCur, 569 triangles[i3+2].y()); 570 571 G4double sinTmp = sinCur; 572 sinCur = sinCur*cosStep + cosCur*sinStep 573 cosCur = cosCur*cosStep - sinTmp*sinStep 574 } 575 576 // set sub-envelope and adjust extent 577 G4double emin,emax; 578 G4BoundingEnvelope benv(polygons); 579 if (!benv.CalculateExtent(pAxis,pVoxelLimi 580 if (emin < pMin) pMin = emin; 581 if (emax > pMax) pMax = emax; 582 if (eminlim > pMin && emaxlim < pMax) brea 583 } 584 // free memory 585 for (G4int k=0; k<ksteps+1; ++k) { delete po 586 return (pMin < pMax); 587 } 588 589 590 ////////////////////////////////////////////// 591 // 592 // CreatePolyhedron 593 // 594 G4Polyhedron* G4UPolyhedra::CreatePolyhedron() 595 { 596 return new G4PolyhedronPgon(wrStart, wrDelta 597 } 598 599 #endif // G4GEOM_USE_USOLIDS 600