Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // 27 // 28 // 29 // John Allison 19th July 1996 30 // Abstract interface class for graphics scenes. 31 32 #include "G4VSceneHandler.hh" 33 34 #include "G4ios.hh" 35 #include <sstream> 36 37 #include "G4VisManager.hh" 38 #include "G4VGraphicsSystem.hh" 39 #include "G4VViewer.hh" 40 #include "G4VSolid.hh" 41 #include "G4RotationMatrix.hh" 42 #include "G4ThreeVector.hh" 43 #include "G4VPhysicalVolume.hh" 44 #include "G4Material.hh" 45 #include "G4Polyline.hh" 46 #include "G4Text.hh" 47 #include "G4Circle.hh" 48 #include "G4Square.hh" 49 #include "G4Polymarker.hh" 50 #include "G4Polyhedron.hh" 51 #include "G4Visible.hh" 52 #include "G4VisAttributes.hh" 53 #include "G4VModel.hh" 54 #include "G4TrajectoriesModel.hh" 55 #include "G4Box.hh" 56 #include "G4Cons.hh" 57 #include "G4Orb.hh" 58 #include "G4Para.hh" 59 #include "G4Sphere.hh" 60 #include "G4Torus.hh" 61 #include "G4Trap.hh" 62 #include "G4Trd.hh" 63 #include "G4Tubs.hh" 64 #include "G4Ellipsoid.hh" 65 #include "G4Polycone.hh" 66 #include "G4Polyhedra.hh" 67 #include "G4Tet.hh" 68 #include "G4DisplacedSolid.hh" 69 #include "G4UnionSolid.hh" 70 #include "G4IntersectionSolid.hh" 71 #include "G4SubtractionSolid.hh" 72 #include "G4LogicalVolume.hh" 73 #include "G4PhysicalVolumeModel.hh" 74 #include "G4ModelingParameters.hh" 75 #include "G4VTrajectory.hh" 76 #include "G4VTrajectoryPoint.hh" 77 #include "G4HitsModel.hh" 78 #include "G4VHit.hh" 79 #include "G4VDigi.hh" 80 #include "G4ScoringManager.hh" 81 #include "G4VScoringMesh.hh" 82 #include "G4Mesh.hh" 83 #include "G4DefaultLinearColorMap.hh" 84 #include "G4QuickRand.hh" 85 #include "G4StateManager.hh" 86 #include "G4RunManager.hh" 87 #include "G4RunManagerFactory.hh" 88 #include "G4Run.hh" 89 #include "G4Transform3D.hh" 90 #include "G4AttHolder.hh" 91 #include "G4AttDef.hh" 92 #include "G4SceneTreeItem.hh" 93 #include "G4VVisCommand.hh" 94 #include "G4PhysicalConstants.hh" 95 #include "G4SystemOfUnits.hh" 96 97 #define G4warn G4cout 98 99 G4VSceneHandler::G4VSceneHandler (G4VGraphicsSystem& system, G4int id, const G4String& name): 100 fSystem (system), 101 fSceneHandlerId (id), 102 fViewCount (0), 103 fpViewer (0), 104 fpScene (0), 105 fMarkForClearingTransientStore (true), // Ready for first 106 // ClearTransientStoreIfMarked(), 107 // e.g., at end of run (see 108 // G4VisManager.cc). 109 fReadyForTransients (true), // Only false while processing scene. 110 fProcessingSolid (false), 111 fProcessing2D (false), 112 fpModel (0), 113 fNestingDepth (0), 114 fpVisAttribs (0) 115 { 116 G4VisManager* pVMan = G4VisManager::GetInstance (); 117 fpScene = pVMan -> GetCurrentScene (); 118 if (name == "") { 119 std::ostringstream ost; 120 ost << fSystem.GetName () << '-' << fSceneHandlerId; 121 fName = ost.str(); 122 } 123 else { 124 fName = name; 125 } 126 fTransientsDrawnThisEvent = pVMan->GetTransientsDrawnThisEvent(); 127 fTransientsDrawnThisRun = pVMan->GetTransientsDrawnThisRun(); 128 } 129 130 G4VSceneHandler::~G4VSceneHandler () { 131 G4VViewer* last; 132 while( ! fViewerList.empty() ) { 133 last = fViewerList.back(); 134 fViewerList.pop_back(); 135 delete last; 136 } 137 } 138 139 const G4VisExtent& G4VSceneHandler::GetExtent() const 140 { 141 if (fpScene) { 142 return fpScene->GetExtent(); 143 } else { 144 static const G4VisExtent defaultExtent = G4VisExtent(); 145 return defaultExtent; 146 } 147 } 148 149 void G4VSceneHandler::PreAddSolid (const G4Transform3D& objectTransformation, 150 const G4VisAttributes& visAttribs) { 151 fObjectTransformation = objectTransformation; 152 fpVisAttribs = &visAttribs; 153 fProcessingSolid = true; 154 } 155 156 void G4VSceneHandler::PostAddSolid () { 157 fpVisAttribs = 0; 158 fProcessingSolid = false; 159 if (fReadyForTransients) { 160 fTransientsDrawnThisEvent = true; 161 fTransientsDrawnThisRun = true; 162 } 163 } 164 165 void G4VSceneHandler::BeginPrimitives 166 (const G4Transform3D& objectTransformation) { 167 //static G4int count = 0; 168 //G4cout << "G4VSceneHandler::BeginPrimitives: " << count++ << G4endl; 169 fNestingDepth++; 170 if (fNestingDepth > 1) 171 G4Exception 172 ("G4VSceneHandler::BeginPrimitives", 173 "visman0101", FatalException, 174 "Nesting detected. It is illegal to nest Begin/EndPrimitives."); 175 fObjectTransformation = objectTransformation; 176 } 177 178 void G4VSceneHandler::EndPrimitives () { 179 if (fNestingDepth <= 0) 180 G4Exception("G4VSceneHandler::EndPrimitives", 181 "visman0102", FatalException, "Nesting error."); 182 fNestingDepth--; 183 if (fReadyForTransients) { 184 fTransientsDrawnThisEvent = true; 185 fTransientsDrawnThisRun = true; 186 } 187 } 188 189 void G4VSceneHandler::BeginPrimitives2D 190 (const G4Transform3D& objectTransformation) { 191 fNestingDepth++; 192 if (fNestingDepth > 1) 193 G4Exception 194 ("G4VSceneHandler::BeginPrimitives2D", 195 "visman0103", FatalException, 196 "Nesting detected. It is illegal to nest Begin/EndPrimitives."); 197 fObjectTransformation = objectTransformation; 198 fProcessing2D = true; 199 } 200 201 void G4VSceneHandler::EndPrimitives2D () { 202 if (fNestingDepth <= 0) 203 G4Exception("G4VSceneHandler::EndPrimitives2D", 204 "visman0104", FatalException, "Nesting error."); 205 fNestingDepth--; 206 if (fReadyForTransients) { 207 fTransientsDrawnThisEvent = true; 208 fTransientsDrawnThisRun = true; 209 } 210 fProcessing2D = false; 211 } 212 213 void G4VSceneHandler::BeginModeling () { 214 } 215 216 void G4VSceneHandler::EndModeling () 217 { 218 fpModel = 0; 219 } 220 221 void G4VSceneHandler::ClearStore () {} 222 223 void G4VSceneHandler::ClearTransientStore () {} 224 225 template <class T> void G4VSceneHandler::AddSolidT 226 (const T& solid) 227 { 228 // Get and check applicable vis attributes. 229 fpVisAttribs = fpViewer->GetApplicableVisAttributes(fpVisAttribs); 230 RequestPrimitives (solid); 231 } 232 233 template <class T> void G4VSceneHandler::AddSolidWithAuxiliaryEdges 234 (const T& solid) 235 { 236 // Get and check applicable vis attributes. 237 fpVisAttribs = fpViewer->GetApplicableVisAttributes(fpVisAttribs); 238 // Draw with auxiliary edges unless otherwise specified. 239 if (!fpVisAttribs->IsForceAuxEdgeVisible()) { 240 // Create a vis atts object for the modified vis atts. 241 // It is static so that we may return a reliable pointer to it. 242 static G4VisAttributes visAttsWithAuxEdges; 243 // Initialise it with the current vis atts and reset the pointer. 244 visAttsWithAuxEdges = *fpVisAttribs; 245 // Force auxiliary edges visible. 246 visAttsWithAuxEdges.SetForceAuxEdgeVisible(); 247 fpVisAttribs = &visAttsWithAuxEdges; 248 } 249 RequestPrimitives (solid); 250 } 251 252 void G4VSceneHandler::AddSolid (const G4Box& box) { 253 AddSolidT (box); 254 // If your graphics system is sophisticated enough to handle a 255 // particular solid shape as a primitive, in your derived class write a 256 // function to override this. 257 // Your function might look like this... 258 // void G4MySceneHandler::AddSolid (const G4Box& box) { 259 // Get and check applicable vis attributes. 260 // fpVisAttribs = fpViewer->GetApplicableVisAttributes(fpVisAttribs); 261 // Do not draw if not visible. 262 // if (fpVisAttribs->IsVisible()) { 263 // Get parameters of appropriate object, e.g.: 264 // G4double dx = box.GetXHalfLength (); 265 // G4double dy = box.GetYHalfLength (); 266 // G4double dz = box.GetZHalfLength (); 267 // ... 268 // and Draw or Store in your display List. 269 } 270 271 void G4VSceneHandler::AddSolid (const G4Cons& cons) { 272 AddSolidT (cons); 273 } 274 275 void G4VSceneHandler::AddSolid (const G4Orb& orb) { 276 AddSolidWithAuxiliaryEdges (orb); 277 } 278 279 void G4VSceneHandler::AddSolid (const G4Para& para) { 280 AddSolidT (para); 281 } 282 283 void G4VSceneHandler::AddSolid (const G4Sphere& sphere) { 284 AddSolidWithAuxiliaryEdges (sphere); 285 } 286 287 void G4VSceneHandler::AddSolid (const G4Torus& torus) { 288 AddSolidWithAuxiliaryEdges (torus); 289 } 290 291 void G4VSceneHandler::AddSolid (const G4Trap& trap) { 292 AddSolidT (trap); 293 } 294 295 void G4VSceneHandler::AddSolid (const G4Trd& trd) { 296 AddSolidT (trd); 297 } 298 299 void G4VSceneHandler::AddSolid (const G4Tubs& tubs) { 300 AddSolidT (tubs); 301 } 302 303 void G4VSceneHandler::AddSolid (const G4Ellipsoid& ellipsoid) { 304 AddSolidWithAuxiliaryEdges (ellipsoid); 305 } 306 307 void G4VSceneHandler::AddSolid (const G4Polycone& polycone) { 308 AddSolidT (polycone); 309 } 310 311 void G4VSceneHandler::AddSolid (const G4Polyhedra& polyhedra) { 312 AddSolidT (polyhedra); 313 } 314 315 void G4VSceneHandler::AddSolid (const G4TessellatedSolid& tess) { 316 AddSolidT (tess); 317 } 318 319 void G4VSceneHandler::AddSolid (const G4VSolid& solid) { 320 AddSolidT (solid); 321 } 322 323 void G4VSceneHandler::AddCompound (const G4VTrajectory& traj) { 324 G4TrajectoriesModel* trajectoriesModel = 325 dynamic_cast<G4TrajectoriesModel*>(fpModel); 326 if (trajectoriesModel) 327 traj.DrawTrajectory(); 328 else { 329 G4Exception 330 ("G4VSceneHandler::AddCompound(const G4VTrajectory&)", 331 "visman0105", FatalException, "Not a G4TrajectoriesModel."); 332 } 333 } 334 335 void G4VSceneHandler::AddCompound (const G4VHit& hit) { 336 // Cast away const because Draw is non-const!!!! 337 const_cast<G4VHit&>(hit).Draw(); 338 } 339 340 void G4VSceneHandler::AddCompound (const G4VDigi& digi) { 341 // Cast away const because Draw is non-const!!!! 342 const_cast<G4VDigi&>(digi).Draw(); 343 } 344 345 void G4VSceneHandler::AddCompound (const G4THitsMap<G4double>& hits) { 346 using MeshScoreMap = G4VScoringMesh::MeshScoreMap; 347 //G4cout << "AddCompound: hits: " << &hits << G4endl; 348 G4bool scoreMapHits = false; 349 G4ScoringManager* scoringManager = G4ScoringManager::GetScoringManagerIfExist(); 350 if (scoringManager) { 351 std::size_t nMeshes = scoringManager->GetNumberOfMesh(); 352 for (std::size_t iMesh = 0; iMesh < nMeshes; ++iMesh) { 353 G4VScoringMesh* mesh = scoringManager->GetMesh((G4int)iMesh); 354 if (mesh && mesh->IsActive()) { 355 MeshScoreMap scoreMap = mesh->GetScoreMap(); 356 const G4String& mapNam = const_cast<G4THitsMap<G4double>&>(hits).GetName(); 357 for(MeshScoreMap::const_iterator i = scoreMap.cbegin(); 358 i != scoreMap.cend(); ++i) { 359 const G4String& scoreMapName = i->first; 360 if (scoreMapName == mapNam) { 361 G4DefaultLinearColorMap colorMap("G4VSceneHandlerColorMap"); 362 scoreMapHits = true; 363 mesh->DrawMesh(scoreMapName, &colorMap); 364 } 365 } 366 } 367 } 368 } 369 if (scoreMapHits) { 370 static G4bool first = true; 371 if (first) { 372 first = false; 373 G4cout << 374 "Scoring map drawn with default parameters." 375 "\n To get gMocren file for gMocren browser:" 376 "\n /vis/open gMocrenFile" 377 "\n /vis/viewer/flush" 378 "\n Many other options available with /score/draw... commands." 379 "\n You might want to \"/vis/viewer/set/autoRefresh false\"." 380 << G4endl; 381 } 382 } else { // Not score map hits. Just call DrawAllHits. 383 // Cast away const because DrawAllHits is non-const!!!! 384 const_cast<G4THitsMap<G4double>&>(hits).DrawAllHits(); 385 } 386 } 387 388 void G4VSceneHandler::AddCompound (const G4THitsMap<G4StatDouble>& hits) { 389 using MeshScoreMap = G4VScoringMesh::MeshScoreMap; 390 //G4cout << "AddCompound: hits: " << &hits << G4endl; 391 G4bool scoreMapHits = false; 392 G4ScoringManager* scoringManager = G4ScoringManager::GetScoringManagerIfExist(); 393 if (scoringManager) { 394 std::size_t nMeshes = scoringManager->GetNumberOfMesh(); 395 for (std::size_t iMesh = 0; iMesh < nMeshes; ++iMesh) { 396 G4VScoringMesh* mesh = scoringManager->GetMesh((G4int)iMesh); 397 if (mesh && mesh->IsActive()) { 398 MeshScoreMap scoreMap = mesh->GetScoreMap(); 399 for(MeshScoreMap::const_iterator i = scoreMap.cbegin(); 400 i != scoreMap.cend(); ++i) { 401 const G4String& scoreMapName = i->first; 402 const G4THitsMap<G4StatDouble>* foundHits = i->second; 403 if (foundHits == &hits) { 404 G4DefaultLinearColorMap colorMap("G4VSceneHandlerColorMap"); 405 scoreMapHits = true; 406 mesh->DrawMesh(scoreMapName, &colorMap); 407 } 408 } 409 } 410 } 411 } 412 if (scoreMapHits) { 413 static G4bool first = true; 414 if (first) { 415 first = false; 416 G4cout << 417 "Scoring map drawn with default parameters." 418 "\n To get gMocren file for gMocren browser:" 419 "\n /vis/open gMocrenFile" 420 "\n /vis/viewer/flush" 421 "\n Many other options available with /score/draw... commands." 422 "\n You might want to \"/vis/viewer/set/autoRefresh false\"." 423 << G4endl; 424 } 425 } else { // Not score map hits. Just call DrawAllHits. 426 // Cast away const because DrawAllHits is non-const!!!! 427 const_cast<G4THitsMap<G4StatDouble>&>(hits).DrawAllHits(); 428 } 429 } 430 431 void G4VSceneHandler::AddCompound(const G4Mesh& mesh) 432 { 433 G4warn << 434 "There has been an attempt to draw a mesh with option \"" 435 << fpViewer->GetViewParameters().GetSpecialMeshRenderingOption() 436 << "\":\n" << mesh 437 << "but it is not of a recognised type or is not implemented" 438 "\nby the current graphics driver. Instead we draw its" 439 "\ncontainer \"" << mesh.GetContainerVolume()->GetName() << "\"." 440 << G4endl; 441 const auto& pv = mesh.GetContainerVolume(); 442 const auto& lv = pv->GetLogicalVolume(); 443 const auto& solid = lv->GetSolid(); 444 const auto& transform = mesh.GetTransform(); 445 // Make sure container is visible 446 G4VisAttributes tmpVisAtts; // Visible, white, not forced. 447 const auto& saveVisAtts = lv->GetVisAttributes(); 448 if (saveVisAtts) { 449 tmpVisAtts = *saveVisAtts; 450 tmpVisAtts.SetVisibility(true); 451 auto colour = saveVisAtts->GetColour(); 452 colour.SetAlpha(1.); 453 tmpVisAtts.SetColour(colour); 454 } 455 // Draw container 456 PreAddSolid(transform,tmpVisAtts); 457 solid->DescribeYourselfTo(*this); 458 PostAddSolid(); 459 // Restore vis attributes 460 lv->SetVisAttributes(saveVisAtts); 461 } 462 463 void G4VSceneHandler::AddViewerToList (G4VViewer* pViewer) { 464 fViewerList.push_back (pViewer); 465 } 466 467 void G4VSceneHandler::AddPrimitive (const G4Polymarker& polymarker) { 468 switch (polymarker.GetMarkerType()) { 469 default: 470 case G4Polymarker::dots: 471 { 472 G4Circle dot (polymarker); 473 dot.SetWorldSize (0.); 474 dot.SetScreenSize (0.1); // Very small circle. 475 for (std::size_t iPoint = 0; iPoint < polymarker.size (); ++iPoint) { 476 dot.SetPosition (polymarker[iPoint]); 477 AddPrimitive (dot); 478 } 479 } 480 break; 481 case G4Polymarker::circles: 482 { 483 G4Circle circle (polymarker); // Default circle 484 for (std::size_t iPoint = 0; iPoint < polymarker.size (); ++iPoint) { 485 circle.SetPosition (polymarker[iPoint]); 486 AddPrimitive (circle); 487 } 488 } 489 break; 490 case G4Polymarker::squares: 491 { 492 G4Square square (polymarker); // Default square 493 for (std::size_t iPoint = 0; iPoint < polymarker.size (); ++iPoint) { 494 square.SetPosition (polymarker[iPoint]); 495 AddPrimitive (square); 496 } 497 } 498 break; 499 } 500 } 501 502 void G4VSceneHandler::RemoveViewerFromList (G4VViewer* pViewer) { 503 fViewerList.remove(pViewer); // Does nothing if already removed 504 // And reset current viewer 505 auto visManager = G4VisManager::GetInstance(); 506 visManager->SetCurrentViewer(nullptr); 507 } 508 509 510 void G4VSceneHandler::AddPrimitive (const G4Plotter&) { 511 G4warn << "WARNING: Plotter not implemented for " << fSystem.GetName() << G4endl; 512 G4warn << " Open a plotter-aware graphics system or remove plotter with" << G4endl; 513 G4warn << " /vis/scene/removeModel Plotter" << G4endl; 514 } 515 516 void G4VSceneHandler::SetScene (G4Scene* pScene) { 517 fpScene = pScene; 518 // Notify all viewers that a kernel visit is required. 519 G4ViewerListIterator i; 520 for (i = fViewerList.begin(); i != fViewerList.end(); i++) { 521 (*i) -> SetNeedKernelVisit (true); 522 } 523 } 524 525 void G4VSceneHandler::RequestPrimitives (const G4VSolid& solid) 526 { 527 // Sometimes solids that have no substance get requested. They may 528 // be part of the geometry tree but have been "spirited away", for 529 // example by a Boolean subtraction in which the original volume 530 // is entirely inside the subtractor or an intersection in which 531 // the original volume is entirely outside the intersector. 532 // The problem is that the Boolean Processor still returns a 533 // polyhedron in these cases (IMHO it should not), so the 534 // workaround is to return before the damage is done. 535 // Algorithm by Evgueni Tcherniaev 536 auto pSolid = &solid; 537 auto pBooleanSolid = dynamic_cast<const G4BooleanSolid*>(pSolid); 538 if (pBooleanSolid) { 539 G4ThreeVector bmin, bmax; 540 pBooleanSolid->BoundingLimits(bmin, bmax); 541 G4bool isGood = false; 542 if (dynamic_cast<const G4SubtractionSolid*>(pBooleanSolid)) { 543 auto ptrB = pBooleanSolid->GetConstituentSolid(1); 544 for (G4int i=0; i<10; ++i) { 545 G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand(); 546 G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand(); 547 G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand(); 548 if (ptrB->Inside(G4ThreeVector(x,y,bmin.z())) != kInside) { isGood = true; break; } 549 if (ptrB->Inside(G4ThreeVector(x,y,bmax.z())) != kInside) { isGood = true; break; } 550 if (ptrB->Inside(G4ThreeVector(x,bmin.y(),z)) != kInside) { isGood = true; break; } 551 if (ptrB->Inside(G4ThreeVector(x,bmax.y(),z)) != kInside) { isGood = true; break; } 552 if (ptrB->Inside(G4ThreeVector(bmin.x(),y,z)) != kInside) { isGood = true; break; } 553 if (ptrB->Inside(G4ThreeVector(bmax.x(),y,z)) != kInside) { isGood = true; break; } 554 } 555 } else if (dynamic_cast<const G4IntersectionSolid*>(pBooleanSolid)) { 556 auto ptrB = pBooleanSolid->GetConstituentSolid(1); 557 for (G4int i=0; i<10; ++i) { 558 G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand(); 559 G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand(); 560 G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand(); 561 if (ptrB->Inside(G4ThreeVector(x,y,bmin.z())) == kInside) { isGood = true; break; } 562 if (ptrB->Inside(G4ThreeVector(x,y,bmax.z())) == kInside) { isGood = true; break; } 563 if (ptrB->Inside(G4ThreeVector(x,bmin.y(),z)) == kInside) { isGood = true; break; } 564 if (ptrB->Inside(G4ThreeVector(x,bmax.y(),z)) == kInside) { isGood = true; break; } 565 if (ptrB->Inside(G4ThreeVector(bmin.x(),y,z)) == kInside) { isGood = true; break; } 566 if (ptrB->Inside(G4ThreeVector(bmax.x(),y,z)) == kInside) { isGood = true; break; } 567 } 568 } 569 if (!isGood) 570 { 571 for (G4int i=0; i<10000; ++i) { 572 G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand(); 573 G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand(); 574 G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand(); 575 if (pBooleanSolid->Inside(G4ThreeVector(x,y,z)) == kInside) { isGood = true; break; } 576 } 577 } 578 if (!isGood) return; 579 } 580 581 const G4ViewParameters::DrawingStyle style = GetDrawingStyle(fpVisAttribs); 582 const G4ViewParameters& vp = fpViewer->GetViewParameters(); 583 584 switch (style) { 585 default: 586 case G4ViewParameters::wireframe: 587 case G4ViewParameters::hlr: 588 case G4ViewParameters::hsr: 589 case G4ViewParameters::hlhsr: 590 { 591 // Use polyhedral representation 592 G4Polyhedron::SetNumberOfRotationSteps (GetNoOfSides (fpVisAttribs)); 593 G4Polyhedron* pPolyhedron = solid.GetPolyhedron (); 594 G4Polyhedron::ResetNumberOfRotationSteps (); 595 if (pPolyhedron) { 596 pPolyhedron -> SetVisAttributes (fpVisAttribs); 597 BeginPrimitives (fObjectTransformation); 598 AddPrimitive (*pPolyhedron); 599 EndPrimitives (); 600 break; 601 } else { // Print warnings and drop through to cloud 602 G4VisManager::Verbosity verbosity = G4VisManager::GetVerbosity(); 603 auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 604 if (pPVModel) { 605 auto problematicVolume = pPVModel->GetCurrentPV(); 606 if (fProblematicVolumes.find(problematicVolume) == fProblematicVolumes.end()) { 607 fProblematicVolumes[problematicVolume] = "Null polyhedron"; 608 if (verbosity >= G4VisManager::errors) { 609 G4warn << 610 "ERROR: G4VSceneHandler::RequestPrimitives" 611 "\n Polyhedron not available for " << solid.GetName (); 612 G4warn << "\n Touchable path: " << pPVModel->GetFullPVPath(); 613 static G4bool explanation = false; 614 if (!explanation) { 615 explanation = true; 616 G4warn << 617 "\n This means it cannot be visualized in the usual way on most systems." 618 "\n 1) The solid may not have implemented the CreatePolyhedron method." 619 "\n 2) For Boolean solids, the BooleanProcessor, which attempts to create" 620 "\n the resultant polyhedron, may have failed." 621 "\n Try RayTracer. It uses Geant4's tracking algorithms instead."; 622 } 623 } 624 G4warn << "\n Drawing solid with cloud of points."; 625 G4warn << G4endl; 626 } 627 } 628 } 629 } 630 [[fallthrough]]; 631 632 case G4ViewParameters::cloud: 633 { 634 // Form solid out of cloud of dots on surface of solid 635 G4Polymarker dots; 636 // Note: OpenGL has a fast implementation of polymarker so it's better 637 // to build a polymarker rather than add a succession of circles. 638 // And anyway, in Qt, in the latter case each circle would be a scene-tree 639 // entry, something we would want to avoid. 640 dots.SetVisAttributes(fpVisAttribs); 641 dots.SetMarkerType(G4Polymarker::dots); 642 dots.SetSize(G4VMarker::screen,1.); 643 G4int numberOfCloudPoints = GetNumberOfCloudPoints(fpVisAttribs); 644 if (numberOfCloudPoints <= 0) numberOfCloudPoints = vp.GetNumberOfCloudPoints(); 645 for (G4int i = 0; i < numberOfCloudPoints; ++i) { 646 G4ThreeVector p = solid.GetPointOnSurface(); 647 dots.push_back(p); 648 } 649 BeginPrimitives (fObjectTransformation); 650 AddPrimitive(dots); 651 EndPrimitives (); 652 break; 653 } 654 } 655 } 656 657 //namespace { 658 // void DrawExtent(const G4VModel* pModel) 659 // { 660 // // Show extent boxes - debug only, OGLSX only (OGLSQt problem?) 661 // if (pModel->GetExtent() != G4VisExtent::GetNullExtent()) { 662 // const auto& extent = pModel->GetExtent(); 663 // const auto& centre = extent.GetExtentCenter(); 664 // const auto& position = G4Translate3D(centre); 665 // const auto& dx = (extent.GetXmax()-extent.GetXmin())/2.; 666 // const auto& dy = (extent.GetYmax()-extent.GetYmin())/2.; 667 // const auto& dz = (extent.GetZmax()-extent.GetZmin())/2.; 668 // auto visAtts = G4VisAttributes(); 669 // visAtts.SetForceWireframe(); 670 // G4Box extentBox("Extent",dx,dy,dz); 671 // G4VisManager::GetInstance()->Draw(extentBox,visAtts,position); 672 // } 673 // } 674 //} 675 676 void G4VSceneHandler::ProcessScene() 677 { 678 // Assumes graphics database store has already been cleared if 679 // relevant for the particular scene handler. 680 681 if(!fpScene) 682 return; 683 684 if(fpScene->GetExtent() == G4VisExtent::GetNullExtent()) 685 { 686 G4Exception("G4VSceneHandler::ProcessScene", "visman0106", JustWarning, 687 "The scene has no extent."); 688 } 689 690 G4VisManager* visManager = G4VisManager::GetInstance(); 691 692 if(!visManager->GetConcreteInstance()) 693 return; 694 695 G4VisManager::Verbosity verbosity = visManager->GetVerbosity(); 696 697 fReadyForTransients = false; 698 699 // Reset fMarkForClearingTransientStore. (Leaving 700 // fMarkForClearingTransientStore true causes problems with 701 // recomputing transients below.) Restore it again at end... 702 G4bool tmpMarkForClearingTransientStore = fMarkForClearingTransientStore; 703 fMarkForClearingTransientStore = false; 704 705 // Traverse geometry tree and send drawing primitives to window(s). 706 707 const std::vector<G4Scene::Model>& runDurationModelList = 708 fpScene->GetRunDurationModelList(); 709 710 if(runDurationModelList.size()) { 711 if(verbosity >= G4VisManager::confirmations) { 712 G4cout << "Traversing scene data..." << G4endl; 713 static G4int first = true; 714 if (first) { 715 first = false; 716 G4cout << 717 "(This could happen more than once - in fact, up to three times" 718 "\nper rebuild, for opaque, transparent and non-hidden markers.)" 719 << G4endl; 720 } 721 } 722 723 // Reset visibility of all objects to false - visible objects will then set to true 724 fpViewer->AccessSceneTree().ResetVisibility(); 725 726 BeginModeling(); 727 728 // Create modeling parameters from view parameters... 729 G4ModelingParameters* pMP = CreateModelingParameters(); 730 731 for(std::size_t i = 0; i < runDurationModelList.size(); ++i) { 732 if(runDurationModelList[i].fActive) { 733 fpModel = runDurationModelList[i].fpModel; 734 fpModel->SetModelingParameters(pMP); 735 736 // Describe to the current scene handler 737 fpModel->DescribeYourselfTo(*this); 738 739 // To see the extents of each model represented as wireframe boxes, 740 // uncomment the next line and DrawExtent in namespace above. 741 // DrawExtent(fpModel); 742 743 // Enter models in the scene tree. Then for PV models, describe 744 // the model to the scene tree, i.e., enter all the touchables. 745 fpViewer->InsertModelInSceneTree(fpModel); 746 auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 747 if (pPVModel) { 748 G4VViewer::SceneTreeScene sceneTreeScene(fpViewer, pPVModel); 749 fpModel->DescribeYourselfTo(sceneTreeScene); 750 } 751 752 // Reset modeling parameters pointer 753 fpModel->SetModelingParameters(0); 754 } 755 } 756 757 fpModel = 0; 758 delete pMP; 759 760 EndModeling(); 761 } 762 763 // Some printing 764 if(verbosity >= G4VisManager::confirmations) { 765 for (const auto& model: runDurationModelList) { 766 if (model.fActive) { 767 auto pvModel = dynamic_cast<G4PhysicalVolumeModel*>(model.fpModel); 768 if (pvModel) { 769 G4int nTouchables = 0; 770 G4cout << "Numbers of touchables by depth in model \"" 771 << pvModel->GetGlobalDescription() << "\":"; 772 for (const auto& dn : pvModel->GetNumberOfTouchables()) { 773 G4cout << "\n Depth " << dn.first << ": " << dn.second; 774 nTouchables += dn.second; 775 } 776 G4cout << "\n Total number of touchables: " << nTouchables << G4endl; 777 } 778 } 779 } 780 781 if (fProblematicVolumes.size() > 0) { 782 G4cout << "Problematic volumes:"; 783 for (const auto& prob: fProblematicVolumes) { 784 G4cout << "\n " << prob.first->GetName() << " (" << prob.second << ')'; 785 } 786 G4cout << G4endl; 787 } 788 } 789 790 fReadyForTransients = true; 791 792 // Refresh event from end-of-event model list. 793 // Allow only in Idle or GeomClosed state... 794 G4StateManager* stateManager = G4StateManager::GetStateManager(); 795 G4ApplicationState state = stateManager->GetCurrentState(); 796 if(state == G4State_Idle || state == G4State_GeomClosed) 797 { 798 visManager->SetEventRefreshing(true); 799 800 if(visManager->GetRequestedEvent()) 801 { 802 DrawEvent(visManager->GetRequestedEvent()); 803 } 804 else 805 { 806 G4RunManager* runManager = G4RunManagerFactory::GetMasterRunManager(); 807 if(runManager) 808 { 809 const G4Run* run = runManager->GetCurrentRun(); 810 // Draw a null event in order to pick up models for the scene tree even before a run 811 if (run == nullptr) DrawEvent(0); 812 const std::vector<const G4Event*>* events = 813 run ? run->GetEventVector() : 0; 814 std::size_t nKeptEvents = 0; 815 if(events) 816 nKeptEvents = events->size(); 817 if(nKeptEvents) 818 { 819 if(fpScene->GetRefreshAtEndOfEvent()) 820 { 821 if(verbosity >= G4VisManager::confirmations) 822 { 823 G4cout << "Refreshing event..." << G4endl; 824 } 825 const G4Event* event = 0; 826 if(events && events->size()) 827 event = events->back(); 828 if(event) 829 DrawEvent(event); 830 } 831 else 832 { // Accumulating events. 833 834 if(verbosity >= G4VisManager::confirmations) 835 { 836 G4cout << "Refreshing events in run..." << G4endl; 837 } 838 for(const auto& event : *events) 839 { 840 if(event) 841 DrawEvent(event); 842 } 843 844 if(!fpScene->GetRefreshAtEndOfRun()) 845 { 846 if(verbosity >= G4VisManager::warnings) 847 { 848 G4warn << "WARNING: Cannot refresh events accumulated over more" 849 "\n than one runs. Refreshed just the last run." 850 << G4endl; 851 } 852 } 853 } 854 } 855 } 856 } 857 visManager->SetEventRefreshing(false); 858 } 859 860 // Refresh end-of-run model list. 861 // Allow only in Idle or GeomClosed state... 862 if(state == G4State_Idle || state == G4State_GeomClosed) 863 { 864 DrawEndOfRunModels(); 865 } 866 867 fMarkForClearingTransientStore = tmpMarkForClearingTransientStore; 868 } 869 870 void G4VSceneHandler::DrawEvent(const G4Event* event) 871 { 872 if(!fpViewer->ReadyToDraw()) return; 873 const std::vector<G4Scene::Model>& EOEModelList = 874 fpScene -> GetEndOfEventModelList (); 875 std::size_t nModels = EOEModelList.size(); 876 if (nModels) { 877 G4ModelingParameters* pMP = CreateModelingParameters(); 878 pMP->SetEvent(event); 879 for (std::size_t i = 0; i < nModels; ++i) { 880 if (EOEModelList[i].fActive) { 881 fpModel = EOEModelList[i].fpModel; 882 fpModel -> SetModelingParameters(pMP); 883 884 // Describe to the current scene handler 885 fpModel -> DescribeYourselfTo (*this); 886 887 // Enter models in the scene tree 888 fpViewer->InsertModelInSceneTree(fpModel); 889 890 // Reset modeling parameters pointer 891 fpModel -> SetModelingParameters(0); 892 } 893 } 894 fpModel = 0; 895 delete pMP; 896 } 897 } 898 899 void G4VSceneHandler::DrawEndOfRunModels() 900 { 901 if(!fpViewer->ReadyToDraw()) return; 902 const std::vector<G4Scene::Model>& EORModelList = 903 fpScene -> GetEndOfRunModelList (); 904 std::size_t nModels = EORModelList.size(); 905 if (nModels) { 906 G4ModelingParameters* pMP = CreateModelingParameters(); 907 pMP->SetEvent(0); 908 for (std::size_t i = 0; i < nModels; ++i) { 909 if (EORModelList[i].fActive) { 910 fpModel = EORModelList[i].fpModel; 911 fpModel -> SetModelingParameters(pMP); 912 913 // Describe to the current scene handler 914 fpModel -> DescribeYourselfTo (*this); 915 916 // Enter models in the scene tree 917 fpViewer->InsertModelInSceneTree(fpModel); 918 919 // Reset modeling parameters pointer 920 fpModel -> SetModelingParameters(0); 921 } 922 } 923 fpModel = 0; 924 delete pMP; 925 } 926 } 927 928 G4ModelingParameters* G4VSceneHandler::CreateModelingParameters () 929 { 930 // Create modeling parameters from View Parameters... 931 if (!fpViewer) return NULL; 932 933 const G4ViewParameters& vp = fpViewer -> GetViewParameters (); 934 935 // Convert drawing styles... 936 G4ModelingParameters::DrawingStyle modelDrawingStyle = 937 G4ModelingParameters::wf; 938 switch (vp.GetDrawingStyle ()) { 939 default: 940 case G4ViewParameters::wireframe: 941 modelDrawingStyle = G4ModelingParameters::wf; 942 break; 943 case G4ViewParameters::hlr: 944 modelDrawingStyle = G4ModelingParameters::hlr; 945 break; 946 case G4ViewParameters::hsr: 947 modelDrawingStyle = G4ModelingParameters::hsr; 948 break; 949 case G4ViewParameters::hlhsr: 950 modelDrawingStyle = G4ModelingParameters::hlhsr; 951 break; 952 case G4ViewParameters::cloud: 953 modelDrawingStyle = G4ModelingParameters::cloud; 954 break; 955 } 956 957 // Decide if covered daughters are really to be culled... 958 G4bool reallyCullCovered = 959 vp.IsCullingCovered() // Culling daughters depends also on... 960 && !vp.IsSection () // Sections (DCUT) not requested. 961 && !vp.IsCutaway () // Cutaways not requested. 962 ; 963 964 G4ModelingParameters* pModelingParams = new G4ModelingParameters 965 (vp.GetDefaultVisAttributes (), 966 modelDrawingStyle, 967 vp.IsCulling (), 968 vp.IsCullingInvisible (), 969 vp.IsDensityCulling (), 970 vp.GetVisibleDensity (), 971 reallyCullCovered, 972 vp.GetNoOfSides () 973 ); 974 975 pModelingParams->SetNumberOfCloudPoints(vp.GetNumberOfCloudPoints()); 976 pModelingParams->SetWarning 977 (G4VisManager::GetVerbosity() >= G4VisManager::warnings); 978 979 pModelingParams->SetCBDAlgorithmNumber(vp.GetCBDAlgorithmNumber()); 980 pModelingParams->SetCBDParameters(vp.GetCBDParameters()); 981 982 pModelingParams->SetExplodeFactor(vp.GetExplodeFactor()); 983 pModelingParams->SetExplodeCentre(vp.GetExplodeCentre()); 984 985 pModelingParams->SetSectionSolid(CreateSectionSolid()); 986 987 if (vp.GetCutawayMode() == G4ViewParameters::cutawayUnion) { 988 pModelingParams->SetCutawayMode(G4ModelingParameters::cutawayUnion); 989 } else if (vp.GetCutawayMode() == G4ViewParameters::cutawayIntersection) { 990 pModelingParams->SetCutawayMode(G4ModelingParameters::cutawayIntersection); 991 } 992 993 pModelingParams->SetCutawaySolid(CreateCutawaySolid()); 994 // The polyhedron objects are deleted in the modeling parameters destructor. 995 996 pModelingParams->SetVisAttributesModifiers(vp.GetVisAttributesModifiers()); 997 998 pModelingParams->SetSpecialMeshRendering(vp.IsSpecialMeshRendering()); 999 pModelingParams->SetSpecialMeshVolumes(vp.GetSpecialMeshVolumes()); 1000 1001 return pModelingParams; 1002 } 1003 1004 G4DisplacedSolid* G4VSceneHandler::CreateSectionSolid() 1005 { 1006 G4DisplacedSolid* sectioner = 0; 1007 1008 const G4ViewParameters& vp = fpViewer->GetViewParameters(); 1009 if (vp.IsSection () ) { 1010 1011 G4double radius = fpScene->GetExtent().GetExtentRadius(); 1012 G4double safe = radius + fpScene->GetExtent().GetExtentCentre().mag(); 1013 G4VSolid* sectionBox = 1014 new G4Box("_sectioner", safe, safe, 1.e-5 * radius); // Thin in z-plane... 1015 1016 const G4Plane3D& sp = vp.GetSectionPlane (); 1017 G4ThreeVector normal = sp.normal(); 1018 G4Transform3D requiredTransform = G4Translate3D(normal*(-sp.d())) * 1019 G4Rotate3D(G4ThreeVector(0,0,1), G4ThreeVector(0,1,0), normal, normal.orthogonal()); 1020 1021 sectioner = new G4DisplacedSolid 1022 ("_displaced_sectioning_box", sectionBox, requiredTransform); 1023 } 1024 1025 return sectioner; 1026 } 1027 1028 G4DisplacedSolid* G4VSceneHandler::CreateCutawaySolid() 1029 { 1030 const auto& vp = fpViewer->GetViewParameters(); 1031 const auto& nPlanes = vp.GetCutawayPlanes().size(); 1032 1033 if (nPlanes == 0) return nullptr; 1034 1035 std::vector<G4DisplacedSolid*> cutaway_solids; 1036 1037 G4double radius = fpScene->GetExtent().GetExtentRadius(); 1038 G4double safe = radius + fpScene->GetExtent().GetExtentCentre().mag(); 1039 auto cutawayBox = new G4Box("_cutaway_box", safe, safe, safe); 1040 1041 // if (vp.GetCutawayMode() == G4ViewParameters::cutawayUnion) we need a subtractor that is 1042 // the intersection of displaced cutaway boxes, displaced so that a subtraction keeps the 1043 // positive values a*x+b*y+c*z+d>0, so we have to invert the normal. This may appear 1044 // "back to front". The parameter "cutawayUnion" means "the union of volumes 1045 // that remain *after* cutaway", because we base the concept on OpenGL cutaway planes and make 1046 // a "union" of what remains by superimposing up to 3 passes - see G4OpenGLViewer::SetView 1047 // and G4OpenGLImmediate/StoredViewer::ProcessView. So we have to create a subtractor 1048 // that is the intersection of inverted cutaway planes. 1049 1050 // Conversely, if (vp.GetCutawayMode() == G4ViewParameters::cutawayIntersection) we have to 1051 // create an intersector that is the intersector of intersected non-inverted cutaway planes. 1052 1053 for (size_t plane_no = 0; plane_no < nPlanes; plane_no++) 1054 { 1055 const G4Plane3D& sp = vp.GetCutawayPlanes()[plane_no]; 1056 G4Transform3D requiredTransform; 1057 G4ThreeVector normal; 1058 switch (vp.GetCutawayMode()) { 1059 case G4ViewParameters::cutawayUnion: 1060 normal = -sp.normal(); // Invert normal - we want a subtractor 1061 requiredTransform = G4Translate3D(normal*(safe + sp.d())) * 1062 G4Rotate3D(G4ThreeVector(0,0,1), G4ThreeVector(0,1,0), normal, normal.orthogonal()); 1063 break; 1064 case G4ViewParameters::cutawayIntersection: 1065 normal = sp.normal(); 1066 requiredTransform = G4Translate3D(normal*(safe - sp.d())) * 1067 G4Rotate3D(G4ThreeVector(0,0,1), G4ThreeVector(0,1,0), normal, normal.orthogonal()); 1068 break; 1069 } 1070 cutaway_solids.push_back 1071 (new G4DisplacedSolid("_displaced_cutaway_box", cutawayBox, requiredTransform)); 1072 } 1073 1074 if (nPlanes == 1) return (G4DisplacedSolid*) cutaway_solids[0]; 1075 1076 G4IntersectionSolid *union2 = nullptr, *union3 = nullptr; 1077 G4IntersectionSolid *intersection2 = nullptr, *intersection3 = nullptr; 1078 switch (vp.GetCutawayMode()) { 1079 1080 case G4ViewParameters::cutawayUnion: 1081 // Here we make a subtractor of intersections of inverted cutaway planes. 1082 union2 = new G4IntersectionSolid("_union_2", cutaway_solids[0], cutaway_solids[1]); 1083 if (nPlanes == 2) return (G4DisplacedSolid*)union2; 1084 else if (nPlanes == 3) { 1085 union3 = new G4IntersectionSolid("_union_3", union2, cutaway_solids[2]); 1086 return (G4DisplacedSolid*)union3; 1087 } 1088 break; 1089 1090 case G4ViewParameters::cutawayIntersection: 1091 // And here we make an intersector of intersections of non-inverted cutaway planes. 1092 intersection2 1093 = new G4IntersectionSolid("_intersection_2", cutaway_solids[0], cutaway_solids[1]); 1094 if (nPlanes == 2) return (G4DisplacedSolid*)intersection2; 1095 else if (nPlanes == 3) { 1096 intersection3 1097 = new G4IntersectionSolid("_intersection_3", intersection2, cutaway_solids[2]); 1098 return (G4DisplacedSolid*)intersection3; 1099 } 1100 break; 1101 } 1102 1103 G4Exception("G4VSceneHandler::CreateCutawaySolid", "visman0107", JustWarning, 1104 "Not programmed for more than 3 cutaway planes"); 1105 return nullptr; 1106 } 1107 1108 void G4VSceneHandler::LoadAtts(const G4Visible& visible, G4AttHolder* holder) 1109 { 1110 // Load G4Atts from G4VisAttributes, if any... 1111 const G4VisAttributes* va = visible.GetVisAttributes(); 1112 if (va) { 1113 const std::map<G4String,G4AttDef>* vaDefs = 1114 va->GetAttDefs(); 1115 if (vaDefs) { 1116 holder->AddAtts(visible.GetVisAttributes()->CreateAttValues(), vaDefs); 1117 } 1118 } 1119 1120 G4PhysicalVolumeModel* pPVModel = 1121 dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 1122 if (pPVModel) { 1123 // Load G4Atts from G4PhysicalVolumeModel... 1124 const std::map<G4String,G4AttDef>* pvDefs = pPVModel->GetAttDefs(); 1125 if (pvDefs) { 1126 holder->AddAtts(pPVModel->CreateCurrentAttValues(), pvDefs); 1127 } 1128 } 1129 1130 G4TrajectoriesModel* trajModel = dynamic_cast<G4TrajectoriesModel*>(fpModel); 1131 if (trajModel) { 1132 // Load G4Atts from trajectory model... 1133 const std::map<G4String,G4AttDef>* trajModelDefs = trajModel->GetAttDefs(); 1134 if (trajModelDefs) { 1135 holder->AddAtts(trajModel->CreateCurrentAttValues(), trajModelDefs); 1136 } 1137 // Load G4Atts from trajectory... 1138 const G4VTrajectory* traj = trajModel->GetCurrentTrajectory(); 1139 if (traj) { 1140 const std::map<G4String,G4AttDef>* trajDefs = traj->GetAttDefs(); 1141 if (trajDefs) { 1142 holder->AddAtts(traj->CreateAttValues(), trajDefs); 1143 } 1144 G4int nPoints = traj->GetPointEntries(); 1145 for (G4int i = 0; i < nPoints; ++i) { 1146 G4VTrajectoryPoint* trajPoint = traj->GetPoint(i); 1147 if (trajPoint) { 1148 const std::map<G4String,G4AttDef>* pointDefs = trajPoint->GetAttDefs(); 1149 if (pointDefs) { 1150 holder->AddAtts(trajPoint->CreateAttValues(), pointDefs); 1151 } 1152 } 1153 } 1154 } 1155 } 1156 1157 G4HitsModel* hitsModel = dynamic_cast<G4HitsModel*>(fpModel); 1158 if (hitsModel) { 1159 // Load G4Atts from hit... 1160 const G4VHit* hit = hitsModel->GetCurrentHit(); 1161 const std::map<G4String,G4AttDef>* hitsDefs = hit->GetAttDefs(); 1162 if (hitsDefs) { 1163 holder->AddAtts(hit->CreateAttValues(), hitsDefs); 1164 } 1165 } 1166 } 1167 1168 const G4Colour& G4VSceneHandler::GetColour () { 1169 fpVisAttribs = fpViewer->GetApplicableVisAttributes(fpVisAttribs); 1170 const G4Colour& colour = fpVisAttribs -> GetColour (); 1171 return colour; 1172 } 1173 1174 const G4Colour& G4VSceneHandler::GetColour (const G4Visible& visible) { 1175 auto pVA = visible.GetVisAttributes(); 1176 if (!pVA) pVA = fpViewer->GetViewParameters().GetDefaultVisAttributes(); 1177 return pVA->GetColour(); 1178 } 1179 1180 const G4Colour& G4VSceneHandler::GetTextColour (const G4Text& text) { 1181 auto pVA = text.GetVisAttributes(); 1182 if (!pVA) pVA = fpViewer->GetViewParameters().GetDefaultTextVisAttributes(); 1183 return pVA->GetColour(); 1184 } 1185 1186 G4double G4VSceneHandler::GetLineWidth(const G4VisAttributes* pVisAttribs) 1187 { 1188 G4double lineWidth = pVisAttribs->GetLineWidth(); 1189 if (lineWidth < 1.) lineWidth = 1.; 1190 lineWidth *= fpViewer -> GetViewParameters().GetGlobalLineWidthScale(); 1191 if (lineWidth < 1.) lineWidth = 1.; 1192 return lineWidth; 1193 } 1194 1195 G4ViewParameters::DrawingStyle G4VSceneHandler::GetDrawingStyle 1196 (const G4VisAttributes* pVisAttribs) { 1197 // Drawing style is normally determined by the view parameters, but 1198 // it can be overriddden by the ForceDrawingStyle flag in the vis 1199 // attributes. 1200 const G4ViewParameters& vp = fpViewer->GetViewParameters(); 1201 const G4ViewParameters::DrawingStyle viewerStyle = vp.GetDrawingStyle(); 1202 G4ViewParameters::DrawingStyle resultantStyle = viewerStyle; 1203 if (pVisAttribs -> IsForceDrawingStyle ()) { 1204 G4VisAttributes::ForcedDrawingStyle forcedStyle = 1205 pVisAttribs -> GetForcedDrawingStyle (); 1206 // This is complicated because if hidden line and surface removal 1207 // has been requested we wish to preserve this sometimes. 1208 switch (forcedStyle) { 1209 case (G4VisAttributes::solid): 1210 switch (viewerStyle) { 1211 case (G4ViewParameters::hlr): 1212 resultantStyle = G4ViewParameters::hlhsr; 1213 break; 1214 case (G4ViewParameters::wireframe): 1215 resultantStyle = G4ViewParameters::hsr; 1216 break; 1217 case (G4ViewParameters::cloud): 1218 resultantStyle = G4ViewParameters::hsr; 1219 break; 1220 case (G4ViewParameters::hlhsr): 1221 case (G4ViewParameters::hsr): 1222 break; 1223 } 1224 break; 1225 case (G4VisAttributes::cloud): 1226 resultantStyle = G4ViewParameters::cloud; 1227 break; 1228 case (G4VisAttributes::wireframe): 1229 default: 1230 // But if forced style is wireframe, do it, because one of its 1231 // main uses is in displaying the consituent solids of a Boolean 1232 // solid and their surfaces overlap with the resulting Booean 1233 // solid, making a mess if hlr is specified. 1234 resultantStyle = G4ViewParameters::wireframe; 1235 break; 1236 } 1237 } 1238 return resultantStyle; 1239 } 1240 1241 G4int G4VSceneHandler::GetNumberOfCloudPoints 1242 (const G4VisAttributes* pVisAttribs) const { 1243 // Returns no of cloud points from current view parameters, unless the user 1244 // has forced through the vis attributes, thereby over-riding the 1245 // current view parameter. 1246 G4int numberOfCloudPoints = fpViewer->GetViewParameters().GetNumberOfCloudPoints(); 1247 if (pVisAttribs -> IsForceDrawingStyle() && 1248 pVisAttribs -> GetForcedDrawingStyle() == G4VisAttributes::cloud && 1249 pVisAttribs -> GetForcedNumberOfCloudPoints() > 0) { 1250 numberOfCloudPoints = pVisAttribs -> GetForcedNumberOfCloudPoints(); 1251 } 1252 return numberOfCloudPoints; 1253 } 1254 1255 G4bool G4VSceneHandler::GetAuxEdgeVisible (const G4VisAttributes* pVisAttribs) { 1256 G4bool isAuxEdgeVisible = fpViewer->GetViewParameters().IsAuxEdgeVisible (); 1257 if (pVisAttribs -> IsForceAuxEdgeVisible()) { 1258 isAuxEdgeVisible = pVisAttribs->IsForcedAuxEdgeVisible(); 1259 } 1260 return isAuxEdgeVisible; 1261 } 1262 1263 G4double G4VSceneHandler::GetMarkerSize 1264 (const G4VMarker& marker, 1265 G4VSceneHandler::MarkerSizeType& markerSizeType) 1266 { 1267 G4bool userSpecified = marker.GetWorldSize() || marker.GetScreenSize(); 1268 const G4VMarker& defaultMarker = 1269 fpViewer -> GetViewParameters().GetDefaultMarker(); 1270 G4double size = userSpecified ? 1271 marker.GetWorldSize() : defaultMarker.GetWorldSize(); 1272 if (size) { 1273 // Draw in world coordinates. 1274 markerSizeType = world; 1275 } 1276 else { 1277 size = userSpecified ? 1278 marker.GetScreenSize() : defaultMarker.GetScreenSize(); 1279 // Draw in screen coordinates. 1280 markerSizeType = screen; 1281 } 1282 size *= fpViewer -> GetViewParameters().GetGlobalMarkerScale(); 1283 if (markerSizeType == screen && size < 1.) size = 1.; 1284 return size; 1285 } 1286 1287 G4int G4VSceneHandler::GetNoOfSides(const G4VisAttributes* pVisAttribs) 1288 { 1289 // No. of sides (lines segments per circle) is normally determined 1290 // by the view parameters, but it can be overriddden by the 1291 // ForceLineSegmentsPerCircle in the vis attributes. 1292 G4int lineSegmentsPerCircle = fpViewer->GetViewParameters().GetNoOfSides(); 1293 if (pVisAttribs) { 1294 if (pVisAttribs->IsForceLineSegmentsPerCircle()) 1295 lineSegmentsPerCircle = pVisAttribs->GetForcedLineSegmentsPerCircle(); 1296 if (lineSegmentsPerCircle < pVisAttribs->GetMinLineSegmentsPerCircle()) { 1297 lineSegmentsPerCircle = pVisAttribs->GetMinLineSegmentsPerCircle(); 1298 G4warn << 1299 "G4VSceneHandler::GetNoOfSides: attempt to set the" 1300 "\nnumber of line segments per circle < " << lineSegmentsPerCircle 1301 << "; forced to " << pVisAttribs->GetMinLineSegmentsPerCircle() << G4endl; 1302 } 1303 } 1304 return lineSegmentsPerCircle; 1305 } 1306 1307 std::ostream& operator << (std::ostream& os, const G4VSceneHandler& sh) { 1308 1309 os << "Scene handler " << sh.fName << " has " 1310 << sh.fViewerList.size () << " viewer(s):"; 1311 for (std::size_t i = 0; i < sh.fViewerList.size (); ++i) { 1312 os << "\n " << *(sh.fViewerList [i]); 1313 } 1314 1315 if (sh.fpScene) { 1316 os << "\n " << *sh.fpScene; 1317 } 1318 else { 1319 os << "\n This scene handler currently has no scene."; 1320 } 1321 1322 return os; 1323 } 1324 1325 void G4VSceneHandler::PseudoSceneFor3DRectMeshPositions::AddSolid(const G4Box&) { 1326 if (fpPVModel->GetCurrentDepth() == fpMesh->GetMeshDepth()) { // Leaf-level cells only 1327 const auto& material = fpPVModel->GetCurrentLV()->GetMaterial(); 1328 const auto& name = material? material->GetName(): fpMesh->GetContainerVolume()->GetName(); 1329 const auto& pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes(); 1330 // Get position in world coordinates 1331 // As a parameterisation the box is transformed by the current transformation 1332 // and its centre, originally by definition at (0,0,0), is now translated. 1333 const G4ThreeVector& position = fpCurrentObjectTransformation->getTranslation(); 1334 fPositionByMaterial.insert(std::make_pair(material,position)); 1335 if (fNameAndVisAttsByMaterial.find(material) == fNameAndVisAttsByMaterial.end()) 1336 // Store name and vis attributes of first encounter with this material 1337 fNameAndVisAttsByMaterial[material] = NameAndVisAtts(name,*pVisAtts); 1338 } 1339 } 1340 1341 void G4VSceneHandler::PseudoSceneForTetVertices::AddSolid(const G4VSolid& solid) { 1342 if (fpPVModel->GetCurrentDepth() == fpMesh->GetMeshDepth()) { // Leaf-level cells only 1343 // Need to know it's a tet !!!! or implement G4VSceneHandler::AddSolid (const G4Tet&) !!!! 1344 try { 1345 const auto& tet = dynamic_cast<const G4Tet&>(solid); 1346 const auto& material = fpPVModel->GetCurrentLV()->GetMaterial(); 1347 const auto& name = material? material->GetName(): fpMesh->GetContainerVolume()->GetName(); 1348 const auto& pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes(); 1349 // Transform into world coordinates if necessary 1350 if (fpCurrentObjectTransformation->xx() == 1. && 1351 fpCurrentObjectTransformation->yy() == 1. && 1352 fpCurrentObjectTransformation->zz() == 1.) { // No transformation necessary 1353 const auto& vertices = tet.GetVertices(); 1354 fVerticesByMaterial.insert(std::make_pair(material,vertices)); 1355 } else { 1356 auto vertices = tet.GetVertices(); 1357 for (auto&& vertex: vertices) { 1358 vertex = G4Point3D(vertex).transform(*fpCurrentObjectTransformation); 1359 } 1360 fVerticesByMaterial.insert(std::make_pair(material,vertices)); 1361 } 1362 if (fNameAndVisAttsByMaterial.find(material) == fNameAndVisAttsByMaterial.end()) 1363 // Store name and vis attributes of first encounter with this material 1364 fNameAndVisAttsByMaterial[material] = NameAndVisAtts(name,*pVisAtts); 1365 } 1366 catch (const std::bad_cast&) { 1367 G4ExceptionDescription ed; 1368 ed << "Called for a mesh that is not a tetrahedron mesh: " << solid.GetName(); 1369 G4Exception("PseudoSceneForTetVertices","visman0108",JustWarning,ed); 1370 } 1371 } 1372 } 1373 1374 void G4VSceneHandler::StandardSpecialMeshRendering(const G4Mesh& mesh) 1375 // Standard way of special mesh rendering. 1376 // MySceneHandler::AddCompound(const G4Mesh& mesh) may use this if 1377 // appropriate or implement its own special mesh rendereing. 1378 { 1379 G4bool implemented = false; 1380 switch (mesh.GetMeshType()) { 1381 case G4Mesh::rectangle: [[fallthrough]]; 1382 case G4Mesh::nested3DRectangular: 1383 switch (fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()) { 1384 case G4ViewParameters::meshAsDefault: 1385 [[fallthrough]]; 1386 case G4ViewParameters::meshAsDots: 1387 Draw3DRectMeshAsDots(mesh); // Rectangular 3-deep mesh as dots 1388 implemented = true; 1389 break; 1390 case G4ViewParameters::meshAsSurfaces: 1391 Draw3DRectMeshAsSurfaces(mesh); // Rectangular 3-deep mesh as surfaces 1392 implemented = true; 1393 break; 1394 } 1395 break; 1396 case G4Mesh::tetrahedron: 1397 switch (fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()) { 1398 case G4ViewParameters::meshAsDefault: 1399 [[fallthrough]]; 1400 case G4ViewParameters::meshAsDots: 1401 DrawTetMeshAsDots(mesh); // Tetrahedron mesh as dots 1402 implemented = true; 1403 break; 1404 case G4ViewParameters::meshAsSurfaces: 1405 DrawTetMeshAsSurfaces(mesh); // Tetrahedron mesh as surfaces 1406 implemented = true; 1407 break; 1408 } 1409 break; 1410 case G4Mesh::cylinder: [[fallthrough]]; 1411 case G4Mesh::sphere: [[fallthrough]]; 1412 case G4Mesh::invalid: break; 1413 } 1414 if (implemented) { 1415 // Draw container if not marked invisible... 1416 auto container = mesh.GetContainerVolume(); 1417 auto containerLogical = container->GetLogicalVolume(); 1418 auto containerVisAtts = containerLogical->GetVisAttributes(); 1419 if (containerVisAtts == nullptr || containerVisAtts->IsVisible()) { 1420 auto solid = containerLogical->GetSolid(); 1421 auto polyhedron = solid->GetPolyhedron(); 1422 // Always draw as wireframe 1423 G4VisAttributes tmpVisAtts; 1424 if (containerVisAtts != nullptr) tmpVisAtts = *containerVisAtts; 1425 tmpVisAtts.SetForceWireframe(); 1426 polyhedron->SetVisAttributes(tmpVisAtts); 1427 BeginPrimitives(mesh.GetTransform()); 1428 AddPrimitive(*polyhedron); 1429 EndPrimitives(); 1430 } 1431 } else { 1432 // Invoke base class function 1433 G4VSceneHandler::AddCompound(mesh); 1434 } 1435 return; 1436 } 1437 1438 void G4VSceneHandler::Draw3DRectMeshAsDots(const G4Mesh& mesh) 1439 // For a rectangular 3-D mesh, draw as coloured dots by colour and material, 1440 // one dot randomly placed in each visible mesh cell. 1441 { 1442 // Check 1443 if (mesh.GetMeshType() != G4Mesh::rectangle && 1444 mesh.GetMeshType() != G4Mesh::nested3DRectangular) { 1445 G4ExceptionDescription ed; 1446 ed << "Called with a mesh that is not rectangular:" << mesh; 1447 G4Exception("G4VSceneHandler::Draw3DRectMeshAsDots","visman0108",JustWarning,ed); 1448 return; 1449 } 1450 1451 static G4bool firstPrint = true; 1452 const auto& verbosity = G4VisManager::GetVerbosity(); 1453 G4bool print = firstPrint && verbosity >= G4VisManager::errors; 1454 if (print) { 1455 G4cout 1456 << "Special case drawing of 3D rectangular G4VNestedParameterisation as dots:" 1457 << '\n' << mesh 1458 << G4endl; 1459 } 1460 1461 const auto& container = mesh.GetContainerVolume(); 1462 1463 // This map is static so that once filled it stays filled. 1464 static std::map<G4String,std::map<const G4Material*,G4Polymarker>> dotsByMaterialAndMesh; 1465 auto& dotsByMaterial = dotsByMaterialAndMesh[mesh.GetContainerVolume()->GetName()]; 1466 1467 // Fill map if not already filled 1468 if (dotsByMaterial.empty()) { 1469 1470 // Get positions and material one cell at a time (using PseudoSceneFor3DRectMeshPositions). 1471 // The pseudo scene allows a "private" descent into the parameterisation. 1472 // Instantiate a temporary G4PhysicalVolumeModel 1473 G4ModelingParameters tmpMP; 1474 tmpMP.SetCulling(true); // This avoids drawing transparent... 1475 tmpMP.SetCullingInvisible(true); // ... or invisble volumes. 1476 const G4bool useFullExtent = true; // To avoid calculating the extent 1477 G4PhysicalVolumeModel tmpPVModel 1478 (container, 1479 G4PhysicalVolumeModel::UNLIMITED, 1480 G4Transform3D(), // so that positions are in local coordinates 1481 &tmpMP, 1482 useFullExtent); 1483 // Accumulate information in temporary maps by material 1484 std::multimap<const G4Material*,const G4ThreeVector> positionByMaterial; 1485 std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial; 1486 // Instantiate the pseudo scene 1487 PseudoSceneFor3DRectMeshPositions pseudoScene 1488 (&tmpPVModel,&mesh,positionByMaterial,nameAndVisAttsByMaterial); 1489 // Make private descent into the parameterisation 1490 tmpPVModel.DescribeYourselfTo(pseudoScene); 1491 // Now we have a map of positions by material. 1492 // Also a map of name and colour by material. 1493 1494 const auto& prms = mesh.GetThreeDRectParameters(); 1495 const auto& halfX = prms.fHalfX; 1496 const auto& halfY = prms.fHalfY; 1497 const auto& halfZ = prms.fHalfZ; 1498 1499 // Fill the permanent (static) map of dots by material 1500 G4int nDotsTotal = 0; 1501 for (const auto& entry: nameAndVisAttsByMaterial) { 1502 G4int nDots = 0; 1503 const auto& material = entry.first; 1504 const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material]; 1505 const auto& name = nameAndVisAtts.fName; 1506 const auto& visAtts = nameAndVisAtts.fVisAtts; 1507 G4Polymarker dots; 1508 dots.SetInfo(name); 1509 dots.SetVisAttributes(visAtts); 1510 dots.SetMarkerType(G4Polymarker::dots); 1511 dots.SetSize(G4VMarker::screen,1.); 1512 // Enter empty polymarker into the map 1513 dotsByMaterial[material] = dots; 1514 // Now fill it in situ 1515 auto& dotsInMap = dotsByMaterial[material]; 1516 const auto& range = positionByMaterial.equal_range(material); 1517 for (auto posByMat = range.first; posByMat != range.second; ++posByMat) { 1518 dotsInMap.push_back(GetPointInBox(posByMat->second, halfX, halfY, halfZ)); 1519 ++nDots; 1520 } 1521 1522 if (print) { 1523 G4cout 1524 << std::setw(30) << std::left << name.substr(0,30) << std::right 1525 << ": " << std::setw(7) << nDots << " dots" 1526 << ": colour " << std::fixed << std::setprecision(2) 1527 << visAtts.GetColour() << std::defaultfloat 1528 << G4endl; 1529 } 1530 1531 nDotsTotal += nDots; 1532 } 1533 1534 if (print) { 1535 G4cout << "Total number of dots: " << nDotsTotal << G4endl; 1536 } 1537 } 1538 1539 // Some subsequent expressions apply only to G4PhysicalVolumeModel 1540 auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 1541 1542 G4String parameterisationName; 1543 if (pPVModel) { 1544 parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName(); 1545 } 1546 1547 // Draw the dots by material 1548 // Ensure they are "hidden", i.e., use the z-buffer as non-marker primitives do 1549 auto keepVP = fpViewer->GetViewParameters(); 1550 auto vp = fpViewer->GetViewParameters(); 1551 vp.SetMarkerHidden(); 1552 fpViewer->SetViewParameters(vp); 1553 // Now we transform to world coordinates 1554 BeginPrimitives (mesh.GetTransform()); 1555 for (const auto& entry: dotsByMaterial) { 1556 const auto& dots = entry.second; 1557 // The current "leaf" node in the PVPath is the parameterisation. Here it has 1558 // been converted into polymarkers by material. So...temporarily...change 1559 // its name to that of the material (whose name has been stored in Info) 1560 // so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has 1561 // an appropriate name and its visibility and colour may be changed. 1562 if (pPVModel) { 1563 const auto& fullPVPath = pPVModel->GetFullPVPath(); 1564 auto leafPV = fullPVPath.back().GetPhysicalVolume(); 1565 leafPV->SetName(dots.GetInfo()); 1566 } 1567 // Add dots to the scene 1568 AddPrimitive(dots); 1569 } 1570 EndPrimitives (); 1571 // Restore view parameters 1572 fpViewer->SetViewParameters(keepVP); 1573 // Restore parameterisation name 1574 if (pPVModel) { 1575 pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName); 1576 } 1577 1578 firstPrint = false; 1579 return; 1580 } 1581 1582 void G4VSceneHandler::Draw3DRectMeshAsSurfaces(const G4Mesh& mesh) 1583 // For a rectangular 3-D mesh, draw as surfaces by colour and material 1584 // with inner shared faces removed. 1585 { 1586 // Check 1587 if (mesh.GetMeshType() != G4Mesh::rectangle && 1588 mesh.GetMeshType() != G4Mesh::nested3DRectangular) { 1589 G4ExceptionDescription ed; 1590 ed << "Called with a mesh that is not rectangular:" << mesh; 1591 G4Exception("G4VSceneHandler::Draw3DRectMeshAsSurfaces","visman0108",JustWarning,ed); 1592 return; 1593 } 1594 1595 static G4bool firstPrint = true; 1596 const auto& verbosity = G4VisManager::GetVerbosity(); 1597 G4bool print = firstPrint && verbosity >= G4VisManager::errors; 1598 if (print) { 1599 G4cout 1600 << "Special case drawing of 3D rectangular G4VNestedParameterisation as surfaces:" 1601 << '\n' << mesh 1602 << G4endl; 1603 } 1604 1605 const auto& container = mesh.GetContainerVolume(); 1606 1607 // This map is static so that once filled it stays filled. 1608 static std::map<G4String,std::map<const G4Material*,G4Polyhedron>> boxesByMaterialAndMesh; 1609 auto& boxesByMaterial = boxesByMaterialAndMesh[mesh.GetContainerVolume()->GetName()]; 1610 1611 // Fill map if not already filled 1612 if (boxesByMaterial.empty()) { 1613 1614 // Get positions and material one cell at a time (using PseudoSceneFor3DRectMeshPositions). 1615 // The pseudo scene allows a "private" descent into the parameterisation. 1616 // Instantiate a temporary G4PhysicalVolumeModel 1617 G4ModelingParameters tmpMP; 1618 tmpMP.SetCulling(true); // This avoids drawing transparent... 1619 tmpMP.SetCullingInvisible(true); // ... or invisble volumes. 1620 const G4bool useFullExtent = true; // To avoid calculating the extent 1621 G4PhysicalVolumeModel tmpPVModel 1622 (container, 1623 G4PhysicalVolumeModel::UNLIMITED, 1624 G4Transform3D(), // so that positions are in local coordinates 1625 &tmpMP, 1626 useFullExtent); 1627 // Accumulate information in temporary maps by material 1628 std::multimap<const G4Material*,const G4ThreeVector> positionByMaterial; 1629 std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial; 1630 // Instantiate the pseudo scene 1631 PseudoSceneFor3DRectMeshPositions pseudoScene 1632 (&tmpPVModel,&mesh,positionByMaterial,nameAndVisAttsByMaterial); 1633 // Make private descent into the parameterisation 1634 tmpPVModel.DescribeYourselfTo(pseudoScene); 1635 // Now we have a map of positions by material. 1636 // Also a map of name and colour by material. 1637 1638 const auto& prms = mesh.GetThreeDRectParameters(); 1639 const auto& sizeX = 2.*prms.fHalfX; 1640 const auto& sizeY = 2.*prms.fHalfY; 1641 const auto& sizeZ = 2.*prms.fHalfZ; 1642 1643 // Fill the permanent (static) map of boxes by material 1644 G4int nBoxesTotal = 0, nFacetsTotal = 0; 1645 for (const auto& entry: nameAndVisAttsByMaterial) { 1646 G4int nBoxes = 0; 1647 const auto& material = entry.first; 1648 const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material]; 1649 const auto& name = nameAndVisAtts.fName; 1650 const auto& visAtts = nameAndVisAtts.fVisAtts; 1651 // Transfer positions into a vector ready for creating polyhedral surface 1652 std::vector<G4ThreeVector> positionsForPolyhedron; 1653 const auto& range = positionByMaterial.equal_range(material); 1654 for (auto posByMat = range.first; posByMat != range.second; ++posByMat) { 1655 const auto& position = posByMat->second; 1656 positionsForPolyhedron.push_back(position); 1657 ++nBoxes; 1658 } 1659 // The polyhedron will be in local coordinates 1660 // Add an empty place-holder to the map and get a reference to it 1661 auto& polyhedron = boxesByMaterial[material]; 1662 // Replace with the desired polyhedron (uses efficient "move assignment") 1663 polyhedron = G4PolyhedronBoxMesh(sizeX,sizeY,sizeZ,positionsForPolyhedron); 1664 polyhedron.SetVisAttributes(visAtts); 1665 polyhedron.SetInfo(name); 1666 1667 if (print) { 1668 G4cout 1669 << std::setw(30) << std::left << name.substr(0,30) << std::right 1670 << ": " << std::setw(7) << nBoxes << " boxes" 1671 << " (" << std::setw(7) << 6*nBoxes << " faces)" 1672 << ": reduced to " << std::setw(7) << polyhedron.GetNoFacets() << " facets (" 1673 << std::setw(2) << std::fixed << std::setprecision(2) << 100*polyhedron.GetNoFacets()/(6*nBoxes) 1674 << "%): colour " << std::fixed << std::setprecision(2) 1675 << visAtts.GetColour() << std::defaultfloat 1676 << G4endl; 1677 } 1678 1679 nBoxesTotal += nBoxes; 1680 nFacetsTotal += polyhedron.GetNoFacets(); 1681 } 1682 1683 if (print) { 1684 G4cout << "Total number of boxes: " << nBoxesTotal << " (" << 6*nBoxesTotal << " faces)" 1685 << ": reduced to " << nFacetsTotal << " facets (" 1686 << std::setw(2) << std::fixed << std::setprecision(2) << 100*nFacetsTotal/(6*nBoxesTotal) << "%)" 1687 << G4endl; 1688 } 1689 } 1690 1691 // Some subsequent expressions apply only to G4PhysicalVolumeModel 1692 auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 1693 1694 G4String parameterisationName; 1695 if (pPVModel) { 1696 parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName(); 1697 } 1698 1699 // Draw the boxes by material 1700 // Now we transform to world coordinates 1701 BeginPrimitives (mesh.GetTransform()); 1702 for (const auto& entry: boxesByMaterial) { 1703 const auto& poly = entry.second; 1704 // The current "leaf" node in the PVPath is the parameterisation. Here it has 1705 // been converted into polyhedra by material. So...temporarily...change 1706 // its name to that of the material (whose name has been stored in Info) 1707 // so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has 1708 // an appropriate name and its visibility and colour may be changed. 1709 if (pPVModel) { 1710 const auto& fullPVPath = pPVModel->GetFullPVPath(); 1711 auto leafPV = fullPVPath.back().GetPhysicalVolume(); 1712 leafPV->SetName(poly.GetInfo()); 1713 } 1714 AddPrimitive(poly); 1715 } 1716 EndPrimitives (); 1717 // Restore parameterisation name 1718 if (pPVModel) { 1719 pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName); 1720 } 1721 1722 firstPrint = false; 1723 return; 1724 } 1725 1726 void G4VSceneHandler::DrawTetMeshAsDots(const G4Mesh& mesh) 1727 // For a tetrahedron mesh, draw as coloured dots by colour and material, 1728 // one dot randomly placed in each visible mesh cell. 1729 { 1730 // Check 1731 if (mesh.GetMeshType() != G4Mesh::tetrahedron) { 1732 G4ExceptionDescription ed; 1733 ed << "Called with mesh that is not a tetrahedron mesh:" << mesh; 1734 G4Exception("G4VSceneHandler::DrawTetMeshAsDots","visman0108",JustWarning,ed); 1735 return; 1736 } 1737 1738 static G4bool firstPrint = true; 1739 const auto& verbosity = G4VisManager::GetVerbosity(); 1740 G4bool print = firstPrint && verbosity >= G4VisManager::errors; 1741 1742 if (print) { 1743 G4cout 1744 << "Special case drawing of tetrahedron mesh as dots" 1745 << '\n' << mesh 1746 << G4endl; 1747 } 1748 1749 const auto& container = mesh.GetContainerVolume(); 1750 1751 // This map is static so that once filled it stays filled. 1752 static std::map<G4String,std::map<const G4Material*,G4Polymarker>> dotsByMaterialAndMesh; 1753 auto& dotsByMaterial = dotsByMaterialAndMesh[mesh.GetContainerVolume()->GetName()]; 1754 1755 // Fill map if not already filled 1756 if (dotsByMaterial.empty()) { 1757 1758 // Get vertices and colour one cell at a time (using PseudoSceneForTetVertices). 1759 // The pseudo scene allows a "private" descent into the parameterisation. 1760 // Instantiate a temporary G4PhysicalVolumeModel 1761 G4ModelingParameters tmpMP; 1762 tmpMP.SetCulling(true); // This avoids drawing transparent... 1763 tmpMP.SetCullingInvisible(true); // ... or invisble volumes. 1764 const G4bool useFullExtent = true; // To avoid calculating the extent 1765 G4PhysicalVolumeModel tmpPVModel 1766 (container, 1767 G4PhysicalVolumeModel::UNLIMITED, 1768 G4Transform3D(), // so that positions are in local coordinates 1769 &tmpMP, 1770 useFullExtent); 1771 // Accumulate information in temporary maps by material 1772 std::multimap<const G4Material*,std::vector<G4ThreeVector>> verticesByMaterial; 1773 std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial; 1774 // Instantiate a pseudo scene 1775 PseudoSceneForTetVertices pseudoScene 1776 (&tmpPVModel,&mesh,verticesByMaterial,nameAndVisAttsByMaterial); 1777 // Make private descent into the parameterisation 1778 tmpPVModel.DescribeYourselfTo(pseudoScene); 1779 // Now we have a map of vertices by material. 1780 // Also a map of name and colour by material. 1781 1782 // Fill the permanent (static) map of dots by material 1783 G4int nDotsTotal = 0; 1784 for (const auto& entry: nameAndVisAttsByMaterial) { 1785 G4int nDots = 0; 1786 const auto& material = entry.first; 1787 const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material]; 1788 const auto& name = nameAndVisAtts.fName; 1789 const auto& visAtts = nameAndVisAtts.fVisAtts; 1790 G4Polymarker dots; 1791 dots.SetVisAttributes(visAtts); 1792 dots.SetMarkerType(G4Polymarker::dots); 1793 dots.SetSize(G4VMarker::screen,1.); 1794 dots.SetInfo(name); 1795 // Enter empty polymarker into the map 1796 dotsByMaterial[material] = dots; 1797 // Now fill it in situ 1798 auto& dotsInMap = dotsByMaterial[material]; 1799 const auto& range = verticesByMaterial.equal_range(material); 1800 for (auto vByMat = range.first; vByMat != range.second; ++vByMat) { 1801 dotsInMap.push_back(GetPointInTet(vByMat->second)); 1802 ++nDots; 1803 } 1804 1805 if (print) { 1806 G4cout 1807 << std::setw(30) << std::left << name.substr(0,30) << std::right 1808 << ": " << std::setw(7) << nDots << " dots" 1809 << ": colour " << std::fixed << std::setprecision(2) 1810 << visAtts.GetColour() << std::defaultfloat 1811 << G4endl; 1812 } 1813 1814 nDotsTotal += nDots; 1815 } 1816 1817 if (print) { 1818 G4cout << "Total number of dots: " << nDotsTotal << G4endl; 1819 } 1820 } 1821 1822 // Some subsequent expressions apply only to G4PhysicalVolumeModel 1823 auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 1824 1825 G4String parameterisationName; 1826 if (pPVModel) { 1827 parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName(); 1828 } 1829 1830 // Draw the dots by material 1831 // Ensure they are "hidden", i.e., use the z-buffer as non-marker primitives do 1832 auto keepVP = fpViewer->GetViewParameters(); 1833 auto vp = fpViewer->GetViewParameters(); 1834 vp.SetMarkerHidden(); 1835 fpViewer->SetViewParameters(vp); 1836 1837 // Now we transform to world coordinates 1838 BeginPrimitives (mesh.GetTransform()); 1839 for (const auto& entry: dotsByMaterial) { 1840 const auto& dots = entry.second; 1841 // The current "leaf" node in the PVPath is the parameterisation. Here it has 1842 // been converted into polymarkers by material. So...temporarily...change 1843 // its name to that of the material (whose name has been stored in Info) 1844 // so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has 1845 // an appropriate name and its visibility and colour may be changed. 1846 if (pPVModel) { 1847 const auto& fullPVPath = pPVModel->GetFullPVPath(); 1848 auto leafPV = fullPVPath.back().GetPhysicalVolume(); 1849 leafPV->SetName(dots.GetInfo()); 1850 } 1851 AddPrimitive(dots); 1852 } 1853 EndPrimitives (); 1854 1855 // Restore view parameters 1856 fpViewer->SetViewParameters(keepVP); 1857 // Restore parameterisation name 1858 if (pPVModel) { 1859 pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName); 1860 } 1861 1862 firstPrint = false; 1863 return; 1864 } 1865 1866 void G4VSceneHandler::DrawTetMeshAsSurfaces(const G4Mesh& mesh) 1867 // For a tetrahedron mesh, draw as surfaces by colour and material 1868 // with inner shared faces removed. 1869 { 1870 // Check 1871 if (mesh.GetMeshType() != G4Mesh::tetrahedron) { 1872 G4ExceptionDescription ed; 1873 ed << "Called with mesh that is not a tetrahedron mesh:" << mesh; 1874 G4Exception("G4VSceneHandler::DrawTetMeshAsSurfaces","visman0108",JustWarning,ed); 1875 return; 1876 } 1877 1878 static G4bool firstPrint = true; 1879 const auto& verbosity = G4VisManager::GetVerbosity(); 1880 G4bool print = firstPrint && verbosity >= G4VisManager::errors; 1881 1882 if (print) { 1883 G4cout 1884 << "Special case drawing of tetrahedron mesh as surfaces" 1885 << '\n' << mesh 1886 << G4endl; 1887 } 1888 1889 // This map is static so that once filled it stays filled. 1890 static std::map<G4String,std::map<const G4Material*,G4Polyhedron>> surfacesByMaterialAndMesh; 1891 auto& surfacesByMaterial = surfacesByMaterialAndMesh[mesh.GetContainerVolume()->GetName()]; 1892 1893 // Fill map if not already filled 1894 if (surfacesByMaterial.empty()) { 1895 1896 // Get vertices and colour one cell at a time (using PseudoSceneForTetVertices). 1897 // The pseudo scene allows a "private" descent into the parameterisation. 1898 // Instantiate a temporary G4PhysicalVolumeModel 1899 G4ModelingParameters tmpMP; 1900 tmpMP.SetCulling(true); // This avoids drawing transparent... 1901 tmpMP.SetCullingInvisible(true); // ... or invisble volumes. 1902 const G4bool useFullExtent = true; // To avoid calculating the extent 1903 G4PhysicalVolumeModel tmpPVModel 1904 (mesh.GetContainerVolume(), 1905 G4PhysicalVolumeModel::UNLIMITED, 1906 G4Transform3D(), // so that positions are in local coordinates 1907 &tmpMP, 1908 useFullExtent); 1909 // Accumulate information in temporary maps by material 1910 std::multimap<const G4Material*,std::vector<G4ThreeVector>> verticesByMaterial; 1911 std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial; 1912 // Instantiate a pseudo scene 1913 PseudoSceneForTetVertices pseudoScene 1914 (&tmpPVModel,&mesh,verticesByMaterial,nameAndVisAttsByMaterial); 1915 // Make private descent into the parameterisation 1916 tmpPVModel.DescribeYourselfTo(pseudoScene); 1917 // Now we have a map of vertices by material. 1918 // Also a map of name and colour by material. 1919 1920 // Fill the permanent (static) map of surfaces by material 1921 G4int nTetsTotal = 0, nFacetsTotal = 0; 1922 for (const auto& entry: nameAndVisAttsByMaterial) { 1923 G4int nTets = 0; 1924 const auto& material = entry.first; 1925 const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material]; 1926 const auto& name = nameAndVisAtts.fName; 1927 const auto& visAtts = nameAndVisAtts.fVisAtts; 1928 // Transfer vertices into a vector ready for creating polyhedral surface 1929 std::vector<G4ThreeVector> verticesForPolyhedron; 1930 const auto& range = verticesByMaterial.equal_range(material); 1931 for (auto vByMat = range.first; vByMat != range.second; ++vByMat) { 1932 const std::vector<G4ThreeVector>& vertices = vByMat->second; 1933 for (const auto& vertex: vertices) 1934 verticesForPolyhedron.push_back(vertex); 1935 ++nTets; 1936 } 1937 // The polyhedron will be in local coordinates 1938 // Add an empty place-holder to the map and get a reference to it 1939 auto& polyhedron = surfacesByMaterial[material]; 1940 // Replace with the desired polyhedron (uses efficient "move assignment") 1941 polyhedron = G4PolyhedronTetMesh(verticesForPolyhedron); 1942 polyhedron.SetVisAttributes(visAtts); 1943 polyhedron.SetInfo(name); 1944 1945 if (print) { 1946 G4cout 1947 << std::setw(30) << std::left << name.substr(0,30) << std::right 1948 << ": " << std::setw(7) << nTets << " tetrahedra" 1949 << " (" << std::setw(7) << 4*nTets << " faces)" 1950 << ": reduced to " << std::setw(7) << polyhedron.GetNoFacets() << " facets (" 1951 << std::setw(2) << std::fixed << std::setprecision(2) << 100*polyhedron.GetNoFacets()/(4*nTets) 1952 << "%): colour " << std::fixed << std::setprecision(2) 1953 << visAtts.GetColour() << std::defaultfloat 1954 << G4endl; 1955 } 1956 1957 nTetsTotal += nTets; 1958 nFacetsTotal += polyhedron.GetNoFacets(); 1959 } 1960 1961 if (print) { 1962 G4cout << "Total number of tetrahedra: " << nTetsTotal << " (" << 4*nTetsTotal << " faces)" 1963 << ": reduced to " << nFacetsTotal << " facets (" 1964 << std::setw(2) << std::fixed << std::setprecision(2) << 100*nFacetsTotal/(4*nTetsTotal) << "%)" 1965 << G4endl; 1966 } 1967 } 1968 1969 // Some subsequent expressions apply only to G4PhysicalVolumeModel 1970 auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 1971 1972 G4String parameterisationName; 1973 if (pPVModel) { 1974 parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName(); 1975 } 1976 1977 // Draw the surfaces by material 1978 // Now we transform to world coordinates 1979 BeginPrimitives (mesh.GetTransform()); 1980 for (const auto& entry: surfacesByMaterial) { 1981 const auto& poly = entry.second; 1982 // The current "leaf" node in the PVPath is the parameterisation. Here it has 1983 // been converted into polyhedra by material. So...temporarily...change 1984 // its name to that of the material (whose name has been stored in Info) 1985 // so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has 1986 // an appropriate name and its visibility and colour may be changed. 1987 if (pPVModel) { 1988 const auto& fullPVPath = pPVModel->GetFullPVPath(); 1989 auto leafPV = fullPVPath.back().GetPhysicalVolume(); 1990 leafPV->SetName(poly.GetInfo()); 1991 } 1992 AddPrimitive(poly); 1993 } 1994 EndPrimitives (); 1995 1996 // Restore parameterisation name 1997 if (pPVModel) { 1998 pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName); 1999 } 2000 2001 firstPrint = false; 2002 return; 2003 } 2004 2005 G4ThreeVector 2006 G4VSceneHandler::GetPointInBox(const G4ThreeVector& pos, 2007 G4double halfX, 2008 G4double halfY, 2009 G4double halfZ) const 2010 { 2011 G4double x = pos.getX() + (2.*G4QuickRand() - 1.)*halfX; 2012 G4double y = pos.getY() + (2.*G4QuickRand() - 1.)*halfY; 2013 G4double z = pos.getZ() + (2.*G4QuickRand() - 1.)*halfZ; 2014 return G4ThreeVector(x, y, z); 2015 } 2016 2017 G4ThreeVector 2018 G4VSceneHandler::GetPointInTet(const std::vector<G4ThreeVector>& vertices) const 2019 { 2020 G4double p = G4QuickRand(); 2021 G4double q = G4QuickRand(); 2022 G4double r = G4QuickRand(); 2023 if (p + q > 1.) 2024 { 2025 p = 1. - p; 2026 q = 1. - q; 2027 } 2028 if (q + r > 1.) 2029 { 2030 G4double tmp = r; 2031 r = 1. - p - q; 2032 q = 1. - tmp; 2033 } 2034 else if (p + q + r > 1.) 2035 { 2036 G4double tmp = r; 2037 r = p + q + r - 1.; 2038 p = 1. - q - tmp; 2039 } 2040 G4double a = 1. - p - q - r; 2041 return vertices[0]*a + vertices[1]*p + vertices[2]*q + vertices[3]*r; 2042 } 2043