Import Geant4 11.1.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2022-07-01 10:44:02 +02:00
parent b3bf75a2a1
commit c07cea1fe0
2172 changed files with 183300 additions and 123938 deletions
@@ -32,8 +32,6 @@
#include <tools/forit>
#include <tools/tokenize>
#include <tools/xml/xml_style> //it uses expat.
G4PlotterManager& G4PlotterManager::GetInstance () {
static G4PlotterManager s_instance;
return s_instance;
@@ -145,7 +145,7 @@ G4bool G4Scene::AddWorldIfEmpty (G4bool warn) {
if (successful) {
if (warn) {
G4cout <<
"G4Scene::AddWorldIfEmpty: The scene was empty of run-duration models."
"G4Scene::AddWorldIfEmpty: The scene had no extent."
"\n \"world\" has been added.";
G4cout << G4endl;
}
@@ -196,6 +196,7 @@ G4bool G4Scene::AddEndOfEventModel (G4VModel* pModel, G4bool warn) {
return false;
}
fEndOfEventModelList.push_back (Model(pModel));
CalculateExtent ();
return true;
}
@@ -216,6 +217,7 @@ G4bool G4Scene::AddEndOfRunModel (G4VModel* pModel, G4bool warn) {
return false;
}
fEndOfRunModelList.push_back (pModel);
CalculateExtent ();
return true;
}
@@ -64,6 +64,7 @@
#include "G4Ellipsoid.hh"
#include "G4Polycone.hh"
#include "G4Polyhedra.hh"
#include "G4Tet.hh"
#include "G4DisplacedSolid.hh"
#include "G4LogicalVolume.hh"
#include "G4PhysicalVolumeModel.hh"
@@ -425,24 +426,28 @@ void G4VSceneHandler::AddCompound (const G4THitsMap<G4StatDouble>& hits) {
void G4VSceneHandler::AddCompound(const G4Mesh& mesh)
{
G4ExceptionDescription ed;
ed << "There has been an attempt to draw a mesh (a nested parameterisation),"
"\nbut it is not implemented by the current graphics driver. Here we simply"
"\ndraw the container, \"" << mesh.GetContainerVolume()->GetName() << "\".";
G4Exception("G4VSceneHandler::AddCompound(const G4Mesh&)",
"visman0107", JustWarning, ed);
G4cerr <<
"There has been an attempt to draw a mesh with option \""
<< fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()
<< "\":\n" << mesh
<< "but it is not of a recognised type or is not implemented"
"\nby the current graphics driver. Instead we draw its"
"\ncontainer \"" << mesh.GetContainerVolume()->GetName() << "\"."
<< G4endl;
const auto& pv = mesh.GetContainerVolume();
const auto& lv = pv->GetLogicalVolume();
const auto& solid = lv->GetSolid();
const auto& transform = mesh.GetTransform();
// Make sure container is visible
G4VisAttributes tmpVisAtts; // Visible, white, not forced.
const auto& saveVisAtts = lv->GetVisAttributes();
auto tmpVisAtts = *saveVisAtts;
tmpVisAtts.SetVisibility(true);
auto colour = saveVisAtts->GetColour();
colour.SetAlpha(1.);
tmpVisAtts.SetColour(colour);
if (saveVisAtts) {
tmpVisAtts = *saveVisAtts;
tmpVisAtts.SetVisibility(true);
auto colour = saveVisAtts->GetColour();
colour.SetAlpha(1.);
tmpVisAtts.SetColour(colour);
}
// Draw container
PreAddSolid(transform,tmpVisAtts);
solid->DescribeYourselfTo(*this);
@@ -1147,3 +1152,687 @@ std::ostream& operator << (std::ostream& os, const G4VSceneHandler& sh) {
return os;
}
void G4VSceneHandler::PseudoSceneFor3DRectMeshPositions::AddSolid(const G4Box&) {
if (fpPVModel->GetCurrentDepth() == fDepth) { // Leaf-level cells only
const auto& material = fpPVModel->GetCurrentLV()->GetMaterial();
const auto& name = material->GetName();
const auto* pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes();
// Get position in world coordinates
// As a parameterisation the box is transformed by the current transformation
// and its centre, originally by definition at (0,0,0), is now translated.
const G4ThreeVector& position = fpCurrentObjectTransformation->getTranslation();
fPositionByMaterial.insert(std::make_pair(material,position));
if (fNameAndVisAttsByMaterial.find(material) == fNameAndVisAttsByMaterial.end())
// Store name and vis attributes of first encounter with this material
fNameAndVisAttsByMaterial[material] = NameAndVisAtts(name,*pVisAtts);
}
}
void G4VSceneHandler::PseudoSceneForTetVertices::AddSolid(const G4VSolid& solid) {
if (fpPVModel->GetCurrentDepth() == fDepth) { // Leaf-level cells only
// Need to know it's a tet !!!! or implement G4VSceneHandler::AddSolid (const G4Tet&) !!!!
try {
const G4Tet& tet = dynamic_cast<const G4Tet&>(solid);
const auto& material = fpPVModel->GetCurrentLV()->GetMaterial();
const auto& name = material->GetName();
const auto* pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes();
// Transform into world coordinates if necessary
if (fpCurrentObjectTransformation->xx() == 1. &&
fpCurrentObjectTransformation->yy() == 1. &&
fpCurrentObjectTransformation->zz() == 1.) { // No transformation necessary
const auto& vertices = tet.GetVertices();
fVerticesByMaterial.insert(std::make_pair(material,vertices));
} else {
auto vertices = tet.GetVertices();
for (auto&& vertex: vertices) {
vertex = G4Point3D(vertex).transform(*fpCurrentObjectTransformation);
}
fVerticesByMaterial.insert(std::make_pair(material,vertices));
}
if (fNameAndVisAttsByMaterial.find(material) == fNameAndVisAttsByMaterial.end())
// Store name and vis attributes of first encounter with this material
fNameAndVisAttsByMaterial[material] = NameAndVisAtts(name,*pVisAtts);
}
catch (const std::bad_cast&) {
G4ExceptionDescription ed;
ed << "Called for a mesh that is not a tetrahedron mesh: " << solid.GetName();
G4Exception("PseudoSceneForTetVertices","visman0108",JustWarning,ed);
}
}
}
void G4VSceneHandler::StandardSpecialMeshRendering(const G4Mesh& mesh)
// Standard way of special mesh rendering.
// MySceneHandler::AddCompound(const G4Mesh& mesh) may use this if
// appropriate or implement its own special mesh rendereing.
{
G4bool implemented = false;
switch (mesh.GetMeshType()) {
case G4Mesh::rectangle: [[fallthrough]];
case G4Mesh::nested3DRectangular:
switch (fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()) {
case G4ViewParameters::meshAsDots:
Draw3DRectMeshAsDots(mesh); // Rectangular 3-deep mesh as dots
implemented = true;
break;
case G4ViewParameters::meshAsSurfaces:
Draw3DRectMeshAsSurfaces(mesh); // Rectangular 3-deep mesh as surfaces
implemented = true;
break;
}
break;
case G4Mesh::tetrahedron:
switch (fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()) {
case G4ViewParameters::meshAsDots:
DrawTetMeshAsDots(mesh); // Tetrahedron mesh as dots
implemented = true;
break;
case G4ViewParameters::meshAsSurfaces:
DrawTetMeshAsSurfaces(mesh); // Tetrahedron mesh as surfaces
implemented = true;
break;
}
break;
case G4Mesh::cylinder: [[fallthrough]];
case G4Mesh::sphere: [[fallthrough]];
case G4Mesh::invalid: break;
}
if (!implemented) {
G4VSceneHandler::AddCompound(mesh); // Base class function - just print warning
}
return;
}
void G4VSceneHandler::Draw3DRectMeshAsDots(const G4Mesh& mesh)
// For a rectangular 3-D mesh, draw as coloured dots by colour and material,
// one dot randomly placed in each visible mesh cell.
{
// Check
if (mesh.GetMeshType() != G4Mesh::rectangle &&
mesh.GetMeshType() != G4Mesh::nested3DRectangular) {
G4ExceptionDescription ed;
ed << "Called with a mesh that is not rectangular:" << mesh;
G4Exception("G4VSceneHandler::Draw3DRectMeshAsDots","visman0108",JustWarning,ed);
return;
}
static G4bool firstPrint = true;
const auto& verbosity = G4VisManager::GetVerbosity();
G4bool print = firstPrint && verbosity >= G4VisManager::errors;
if (print) {
G4cout
<< "Special case drawing of 3D rectangular G4VNestedParameterisation as dots:"
<< '\n' << mesh
<< G4endl;
}
const auto& container = mesh.GetContainerVolume();
// This map is static so that once filled it stays filled.
static std::map<G4String,std::map<const G4Material*,G4Polymarker>> dotsByMaterialAndMesh;
auto& dotsByMaterial = dotsByMaterialAndMesh[mesh.GetContainerVolume()->GetName()];
// Fill map if not already filled
if (dotsByMaterial.empty()) {
// Get positions and material one cell at a time (using PseudoSceneFor3DRectMeshPositions).
// The pseudo scene allows a "private" descent into the parameterisation.
// Instantiate a temporary G4PhysicalVolumeModel
G4ModelingParameters tmpMP;
tmpMP.SetCulling(true); // This avoids drawing transparent...
tmpMP.SetCullingInvisible(true); // ... or invisble volumes.
const G4bool useFullExtent = true; // To avoid calculating the extent
G4PhysicalVolumeModel tmpPVModel
(container,
G4PhysicalVolumeModel::UNLIMITED,
G4Transform3D(), // so that positions are in local coordinates
&tmpMP,
useFullExtent);
// Accumulate information in temporary maps by material
std::multimap<const G4Material*,const G4ThreeVector> positionByMaterial;
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate the pseudo scene
PseudoSceneFor3DRectMeshPositions pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),positionByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of positions by material.
// Also a map of name and colour by material.
const auto& prms = mesh.GetThreeDRectParameters();
const auto& halfX = prms.fHalfX;
const auto& halfY = prms.fHalfY;
const auto& halfZ = prms.fHalfZ;
// Fill the permanent (static) map of dots by material
G4int nDotsTotal = 0;
for (const auto& entry: nameAndVisAttsByMaterial) {
G4int nDots = 0;
const auto& material = entry.first;
const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material];
const auto& name = nameAndVisAtts.fName;
const auto& visAtts = nameAndVisAtts.fVisAtts;
G4Polymarker dots;
dots.SetInfo(name);
dots.SetVisAttributes(visAtts);
dots.SetMarkerType(G4Polymarker::dots);
dots.SetSize(G4VMarker::screen,1.);
// Enter empty polymarker into the map
dotsByMaterial[material] = dots;
// Now fill it in situ
auto& dotsInMap = dotsByMaterial[material];
const auto& range = positionByMaterial.equal_range(material);
for (auto posByMat = range.first; posByMat != range.second; ++posByMat) {
const G4double x = posByMat->second.getX() + (2.*G4UniformRand()-1.)*halfX;
const G4double y = posByMat->second.getY() + (2.*G4UniformRand()-1.)*halfY;
const G4double z = posByMat->second.getZ() + (2.*G4UniformRand()-1.)*halfZ;
dotsInMap.push_back(G4ThreeVector(x,y,z));
++nDots;
}
if (print) {
G4cout
<< std::setw(30) << std::left << name.substr(0,30) << std::right
<< ": " << std::setw(7) << nDots << " dots"
<< ": colour " << std::fixed << std::setprecision(2)
<< visAtts.GetColour() << std::defaultfloat
<< G4endl;
}
nDotsTotal += nDots;
}
if (print) {
G4cout << "Total number of dots: " << nDotsTotal << G4endl;
}
}
// Some subsequent expressions apply only to G4PhysicalVolumeModel
auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
G4String parameterisationName;
if (pPVModel) {
parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName();
}
// Draw the dots by material
// Ensure they are "hidden", i.e., use the z-buffer as non-marker primitives do
auto keepVP = fpViewer->GetViewParameters();
auto vp = fpViewer->GetViewParameters();
vp.SetMarkerHidden();
fpViewer->SetViewParameters(vp);
// Now we transform to world coordinates
BeginPrimitives (mesh.GetTransform());
for (const auto& entry: dotsByMaterial) {
const auto& dots = entry.second;
// The current "leaf" node in the PVPath is the parameterisation. Here it has
// been converted into polymarkers by material. So...temporarily...change
// its name to that of the material (whose name has been stored in Info)
// so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has
// an appropriate name and its visibility and colour may be changed.
if (pPVModel) {
const auto& fullPVPath = pPVModel->GetFullPVPath();
auto leafPV = fullPVPath.back().GetPhysicalVolume();
leafPV->SetName(dots.GetInfo());
}
// Add dots to the scene
AddPrimitive(dots);
}
EndPrimitives ();
// Restore view parameters
fpViewer->SetViewParameters(keepVP);
// Restore parameterisation name
if (pPVModel) {
pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName);
}
firstPrint = false;
return;
}
void G4VSceneHandler::Draw3DRectMeshAsSurfaces(const G4Mesh& mesh)
// For a rectangular 3-D mesh, draw as surfaces by colour and material
// with inner shared faces removed.
{
// Check
if (mesh.GetMeshType() != G4Mesh::rectangle &&
mesh.GetMeshType() != G4Mesh::nested3DRectangular) {
G4ExceptionDescription ed;
ed << "Called with a mesh that is not rectangular:" << mesh;
G4Exception("G4VSceneHandler::Draw3DRectMeshAsSurfaces","visman0108",JustWarning,ed);
return;
}
static G4bool firstPrint = true;
const auto& verbosity = G4VisManager::GetVerbosity();
G4bool print = firstPrint && verbosity >= G4VisManager::errors;
if (print) {
G4cout
<< "Special case drawing of 3D rectangular G4VNestedParameterisation as surfaces:"
<< '\n' << mesh
<< G4endl;
}
const auto& container = mesh.GetContainerVolume();
// This map is static so that once filled it stays filled.
static std::map<G4String,std::map<const G4Material*,G4Polyhedron>> boxesByMaterialAndMesh;
auto& boxesByMaterial = boxesByMaterialAndMesh[mesh.GetContainerVolume()->GetName()];
// Fill map if not already filled
if (boxesByMaterial.empty()) {
// Get positions and material one cell at a time (using PseudoSceneFor3DRectMeshPositions).
// The pseudo scene allows a "private" descent into the parameterisation.
// Instantiate a temporary G4PhysicalVolumeModel
G4ModelingParameters tmpMP;
tmpMP.SetCulling(true); // This avoids drawing transparent...
tmpMP.SetCullingInvisible(true); // ... or invisble volumes.
const G4bool useFullExtent = true; // To avoid calculating the extent
G4PhysicalVolumeModel tmpPVModel
(container,
G4PhysicalVolumeModel::UNLIMITED,
G4Transform3D(), // so that positions are in local coordinates
&tmpMP,
useFullExtent);
// Accumulate information in temporary maps by material
std::multimap<const G4Material*,const G4ThreeVector> positionByMaterial;
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate the pseudo scene
PseudoSceneFor3DRectMeshPositions pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),positionByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of positions by material.
// Also a map of name and colour by material.
const auto& prms = mesh.GetThreeDRectParameters();
const auto& sizeX = 2.*prms.fHalfX;
const auto& sizeY = 2.*prms.fHalfY;
const auto& sizeZ = 2.*prms.fHalfZ;
// Fill the permanent (static) map of boxes by material
G4int nBoxesTotal = 0, nFacetsTotal = 0;
for (const auto& entry: nameAndVisAttsByMaterial) {
G4int nBoxes = 0;
const auto& material = entry.first;
const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material];
const auto& name = nameAndVisAtts.fName;
const auto& visAtts = nameAndVisAtts.fVisAtts;
// Transfer positions into a vector ready for creating polyhedral surface
std::vector<G4ThreeVector> positionsForPolyhedron;
const auto& range = positionByMaterial.equal_range(material);
for (auto posByMat = range.first; posByMat != range.second; ++posByMat) {
const auto& position = posByMat->second;
positionsForPolyhedron.push_back(position);
++nBoxes;
}
// The polyhedron will be in local coordinates
// Add an empty place-holder to the map and get a reference to it
auto& polyhedron = boxesByMaterial[material];
// Replace with the desired polyhedron (uses efficient "move assignment")
polyhedron = G4PolyhedronBoxMesh(sizeX,sizeY,sizeZ,positionsForPolyhedron);
polyhedron.SetVisAttributes(visAtts);
polyhedron.SetInfo(name);
if (print) {
G4cout
<< std::setw(30) << std::left << name.substr(0,30) << std::right
<< ": " << std::setw(7) << nBoxes << " boxes"
<< " (" << std::setw(7) << 6*nBoxes << " faces)"
<< ": reduced to " << std::setw(7) << polyhedron.GetNoFacets() << " facets ("
<< std::setw(2) << std::fixed << std::setprecision(2) << 100*polyhedron.GetNoFacets()/(6*nBoxes)
<< "%): colour " << std::fixed << std::setprecision(2)
<< visAtts.GetColour() << std::defaultfloat
<< G4endl;
}
nBoxesTotal += nBoxes;
nFacetsTotal += polyhedron.GetNoFacets();
}
if (print) {
G4cout << "Total number of boxes: " << nBoxesTotal << " (" << 6*nBoxesTotal << " faces)"
<< ": reduced to " << nFacetsTotal << " facets ("
<< std::setw(2) << std::fixed << std::setprecision(2) << 100*nFacetsTotal/(6*nBoxesTotal) << "%)"
<< G4endl;
}
}
// Some subsequent expressions apply only to G4PhysicalVolumeModel
auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
G4String parameterisationName;
if (pPVModel) {
parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName();
}
// Draw the boxes by material
// Now we transform to world coordinates
BeginPrimitives (mesh.GetTransform());
for (const auto& entry: boxesByMaterial) {
const auto& poly = entry.second;
// The current "leaf" node in the PVPath is the parameterisation. Here it has
// been converted into polyhedra by material. So...temporarily...change
// its name to that of the material (whose name has been stored in Info)
// so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has
// an appropriate name and its visibility and colour may be changed.
if (pPVModel) {
const auto& fullPVPath = pPVModel->GetFullPVPath();
auto leafPV = fullPVPath.back().GetPhysicalVolume();
leafPV->SetName(poly.GetInfo());
}
AddPrimitive(poly);
}
EndPrimitives ();
// Restore parameterisation name
if (pPVModel) {
pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName);
}
firstPrint = false;
return;
}
void G4VSceneHandler::DrawTetMeshAsDots(const G4Mesh& mesh)
// For a tetrahedron mesh, draw as coloured dots by colour and material,
// one dot randomly placed in each visible mesh cell.
{
// Check
if (mesh.GetMeshType() != G4Mesh::tetrahedron) {
G4ExceptionDescription ed;
ed << "Called with mesh that is not a tetrahedron mesh:" << mesh;
G4Exception("G4VSceneHandler::DrawTetMeshAsDots","visman0108",JustWarning,ed);
return;
}
static G4bool firstPrint = true;
const auto& verbosity = G4VisManager::GetVerbosity();
G4bool print = firstPrint && verbosity >= G4VisManager::errors;
if (print) {
G4cout
<< "Special case drawing of tetrahedron mesh as dots"
<< '\n' << mesh
<< G4endl;
}
const auto& container = mesh.GetContainerVolume();
// This map is static so that once filled it stays filled.
static std::map<G4String,std::map<const G4Material*,G4Polymarker>> dotsByMaterialAndMesh;
auto& dotsByMaterial = dotsByMaterialAndMesh[mesh.GetContainerVolume()->GetName()];
// Fill map if not already filled
if (dotsByMaterial.empty()) {
// Get vertices and colour one cell at a time (using PseudoSceneForTetVertices).
// The pseudo scene allows a "private" descent into the parameterisation.
// Instantiate a temporary G4PhysicalVolumeModel
G4ModelingParameters tmpMP;
tmpMP.SetCulling(true); // This avoids drawing transparent...
tmpMP.SetCullingInvisible(true); // ... or invisble volumes.
const G4bool useFullExtent = true; // To avoid calculating the extent
G4PhysicalVolumeModel tmpPVModel
(container,
G4PhysicalVolumeModel::UNLIMITED,
G4Transform3D(), // so that positions are in local coordinates
&tmpMP,
useFullExtent);
// Accumulate information in temporary maps by material
std::multimap<const G4Material*,std::vector<G4ThreeVector>> verticesByMaterial;
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate a pseudo scene
PseudoSceneForTetVertices pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),verticesByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of vertices by material.
// Also a map of name and colour by material.
// Fill the permanent (static) map of dots by material
G4int nDotsTotal = 0;
for (const auto& entry: nameAndVisAttsByMaterial) {
G4int nDots = 0;
const auto& material = entry.first;
const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material];
const auto& name = nameAndVisAtts.fName;
const auto& visAtts = nameAndVisAtts.fVisAtts;
G4Polymarker dots;
dots.SetVisAttributes(visAtts);
dots.SetMarkerType(G4Polymarker::dots);
dots.SetSize(G4VMarker::screen,1.);
dots.SetInfo(name);
// Enter empty polymarker into the map
dotsByMaterial[material] = dots;
// Now fill it in situ
auto& dotsInMap = dotsByMaterial[material];
const auto& range = verticesByMaterial.equal_range(material);
for (auto vByMat = range.first; vByMat != range.second; ++vByMat) {
const std::vector<G4ThreeVector>& vertices = vByMat->second;
// Calculate extent/bounding box
G4double xmin, xmax, ymin, ymax, zmin, zmax;
xmin = ymin = zmin = DBL_MAX;
xmax = ymax = zmax = -DBL_MAX;
for (const auto& vertex: vertices) {
if (xmin > vertex.x()) xmin = vertex.x();
if (ymin > vertex.y()) ymin = vertex.y();
if (zmin > vertex.z()) zmin = vertex.z();
if (xmax < vertex.x()) xmax = vertex.x();
if (ymax < vertex.y()) ymax = vertex.y();
if (zmax < vertex.z()) zmax = vertex.z();
}
// Place dot at random in the extent/bounding box. Yes, I know this will
// be bigger than the tetrahedron, so sometimes the position will be outside
// the tetrahedron, but it will still give a reasonable visual representation.
// If you have a smart algorithm for generating a random point in a
// tetrahedron, please let us know.
const G4double x = xmin + G4UniformRand()*(xmax - xmin);
const G4double y = ymin + G4UniformRand()*(ymax - ymin);
const G4double z = zmin + G4UniformRand()*(zmax - zmin);
dotsInMap.push_back(G4ThreeVector(x,y,z));
++nDots;
}
if (print) {
G4cout
<< std::setw(30) << std::left << name.substr(0,30) << std::right
<< ": " << std::setw(7) << nDots << " dots"
<< ": colour " << std::fixed << std::setprecision(2)
<< visAtts.GetColour() << std::defaultfloat
<< G4endl;
}
nDotsTotal += nDots;
}
if (print) {
G4cout << "Total number of dots: " << nDotsTotal << G4endl;
}
}
// Some subsequent expressions apply only to G4PhysicalVolumeModel
auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
G4String parameterisationName;
if (pPVModel) {
parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName();
}
// Draw the dots by material
// Ensure they are "hidden", i.e., use the z-buffer as non-marker primitives do
auto keepVP = fpViewer->GetViewParameters();
auto vp = fpViewer->GetViewParameters();
vp.SetMarkerHidden();
fpViewer->SetViewParameters(vp);
// Now we transform to world coordinates
BeginPrimitives (mesh.GetTransform());
for (const auto& entry: dotsByMaterial) {
const auto& dots = entry.second;
// The current "leaf" node in the PVPath is the parameterisation. Here it has
// been converted into polymarkers by material. So...temporarily...change
// its name to that of the material (whose name has been stored in Info)
// so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has
// an appropriate name and its visibility and colour may be changed.
if (pPVModel) {
const auto& fullPVPath = pPVModel->GetFullPVPath();
auto leafPV = fullPVPath.back().GetPhysicalVolume();
leafPV->SetName(dots.GetInfo());
}
AddPrimitive(dots);
}
EndPrimitives ();
// Restore view parameters
fpViewer->SetViewParameters(keepVP);
// Restore parameterisation name
if (pPVModel) {
pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName);
}
firstPrint = false;
return;
}
void G4VSceneHandler::DrawTetMeshAsSurfaces(const G4Mesh& mesh)
// For a tetrahedron mesh, draw as surfaces by colour and material
// with inner shared faces removed.
{
// Check
if (mesh.GetMeshType() != G4Mesh::tetrahedron) {
G4ExceptionDescription ed;
ed << "Called with mesh that is not a tetrahedron mesh:" << mesh;
G4Exception("G4VSceneHandler::DrawTetMeshAsSurfaces","visman0108",JustWarning,ed);
return;
}
static G4bool firstPrint = true;
const auto& verbosity = G4VisManager::GetVerbosity();
G4bool print = firstPrint && verbosity >= G4VisManager::errors;
if (print) {
G4cout
<< "Special case drawing of tetrahedron mesh as surfaces"
<< '\n' << mesh
<< G4endl;
}
const auto& container = mesh.GetContainerVolume();
// This map is static so that once filled it stays filled.
static std::map<G4String,std::map<const G4Material*,G4Polyhedron>> surfacesByMaterialAndMesh;
auto& surfacesByMaterial = surfacesByMaterialAndMesh[mesh.GetContainerVolume()->GetName()];
// Fill map if not already filled
if (surfacesByMaterial.empty()) {
// Get vertices and colour one cell at a time (using PseudoSceneForTetVertices).
// The pseudo scene allows a "private" descent into the parameterisation.
// Instantiate a temporary G4PhysicalVolumeModel
G4ModelingParameters tmpMP;
tmpMP.SetCulling(true); // This avoids drawing transparent...
tmpMP.SetCullingInvisible(true); // ... or invisble volumes.
const G4bool useFullExtent = true; // To avoid calculating the extent
G4PhysicalVolumeModel tmpPVModel
(container,
G4PhysicalVolumeModel::UNLIMITED,
G4Transform3D(), // so that positions are in local coordinates
&tmpMP,
useFullExtent);
// Accumulate information in temporary maps by material
std::multimap<const G4Material*,std::vector<G4ThreeVector>> verticesByMaterial;
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate a pseudo scene
PseudoSceneForTetVertices pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),verticesByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of vertices by material.
// Also a map of name and colour by material.
// Fill the permanent (static) map of surfaces by material
G4int nTetsTotal = 0, nFacetsTotal = 0;
for (const auto& entry: nameAndVisAttsByMaterial) {
G4int nTets = 0;
const auto& material = entry.first;
const auto& nameAndVisAtts = nameAndVisAttsByMaterial[material];
const auto& name = nameAndVisAtts.fName;
const auto& visAtts = nameAndVisAtts.fVisAtts;
// Transfer vertices into a vector ready for creating polyhedral surface
std::vector<G4ThreeVector> verticesForPolyhedron;
const auto& range = verticesByMaterial.equal_range(material);
for (auto vByMat = range.first; vByMat != range.second; ++vByMat) {
const std::vector<G4ThreeVector>& vertices = vByMat->second;
for (const auto& vertex: vertices)
verticesForPolyhedron.push_back(vertex);
++nTets;
}
// The polyhedron will be in local coordinates
// Add an empty place-holder to the map and get a reference to it
auto& polyhedron = surfacesByMaterial[material];
// Replace with the desired polyhedron (uses efficient "move assignment")
polyhedron = G4PolyhedronTetMesh(verticesForPolyhedron);
polyhedron.SetVisAttributes(visAtts);
polyhedron.SetInfo(name);
if (print) {
G4cout
<< std::setw(30) << std::left << name.substr(0,30) << std::right
<< ": " << std::setw(7) << nTets << " tetrahedra"
<< " (" << std::setw(7) << 4*nTets << " faces)"
<< ": reduced to " << std::setw(7) << polyhedron.GetNoFacets() << " facets ("
<< std::setw(2) << std::fixed << std::setprecision(2) << 100*polyhedron.GetNoFacets()/(4*nTets)
<< "%): colour " << std::fixed << std::setprecision(2)
<< visAtts.GetColour() << std::defaultfloat
<< G4endl;
}
nTetsTotal += nTets;
nFacetsTotal += polyhedron.GetNoFacets();
}
if (print) {
G4cout << "Total number of tetrahedra: " << nTetsTotal << " (" << 4*nTetsTotal << " faces)"
<< ": reduced to " << nFacetsTotal << " facets ("
<< std::setw(2) << std::fixed << std::setprecision(2) << 100*nFacetsTotal/(4*nTetsTotal) << "%)"
<< G4endl;
}
}
// Some subsequent expressions apply only to G4PhysicalVolumeModel
auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
G4String parameterisationName;
if (pPVModel) {
parameterisationName = pPVModel->GetFullPVPath().back().GetPhysicalVolume()->GetName();
}
// Draw the surfaces by material
// Now we transform to world coordinates
BeginPrimitives (mesh.GetTransform());
for (const auto& entry: surfacesByMaterial) {
const auto& poly = entry.second;
// The current "leaf" node in the PVPath is the parameterisation. Here it has
// been converted into polyhedra by material. So...temporarily...change
// its name to that of the material (whose name has been stored in Info)
// so that its appearance in the scene tree of, e.g., G4OpenGLQtViewer, has
// an appropriate name and its visibility and colour may be changed.
if (pPVModel) {
const auto& fullPVPath = pPVModel->GetFullPVPath();
auto leafPV = fullPVPath.back().GetPhysicalVolume();
leafPV->SetName(poly.GetInfo());
}
AddPrimitive(poly);
}
EndPrimitives ();
// Restore parameterisation name
if (pPVModel) {
pPVModel->GetFullPVPath().back().GetPhysicalVolume()->SetName(parameterisationName);
}
firstPrint = false;
return;
}
@@ -31,6 +31,8 @@
#include "G4VViewer.hh"
#include "G4Timer.hh"
#include "G4ios.hh"
#include <sstream>
@@ -111,9 +113,13 @@ void G4VViewer::ProcessView ()
if (fNeedKernelVisit) {
// Reset flag. This must be done before ProcessScene to prevent
// recursive calls when recomputing transients...
G4Timer timer;
timer.Start();
fNeedKernelVisit = false;
fSceneHandler.ClearStore ();
fSceneHandler.ProcessScene ();
timer.Stop();
fKernelVisitElapsedTimeSeconds = timer.GetRealElapsed();
}
}
@@ -36,6 +36,9 @@
#include <sstream>
#include <cctype>
#include "G4PhysicalVolumeModel.hh"
#include "G4LogicalVolume.hh"
G4int G4VVisCommand::fCurrentArrow3DLineSegmentsPerCircle = 6;
G4Colour G4VVisCommand::fCurrentColour = G4Colour::White();
G4Colour G4VVisCommand::fCurrentTextColour = G4Colour::Blue();
@@ -49,7 +52,7 @@ G4PhysicalVolumeModel::TouchableProperties G4VVisCommand::fCurrentTouch
G4VisExtent G4VVisCommand::fCurrentExtentForField;
std::vector<G4PhysicalVolumesSearchScene::Findings> G4VVisCommand::fCurrrentPVFindingsForField;
G4bool G4VVisCommand::fThereWasAViewer = false;
G4ViewParameters G4VVisCommand::fVPExistingViewer;
G4ViewParameters G4VVisCommand::fExistingVP;
G4VVisCommand::G4VVisCommand () {}
@@ -323,7 +326,7 @@ void G4VVisCommand::InterpolateToNewView
viewVector.push_back(oldVP);
viewVector.push_back(newVP);
viewVector.push_back(newVP);
InterpolateViews
(currentViewer,
viewVector,
@@ -332,6 +335,62 @@ void G4VVisCommand::InterpolateToNewView
exportString);
}
void G4VVisCommand::Twinkle
// Twinkles the touchables in paths
// /vis/viewer/centreOn to see its effect
(G4VViewer* currentViewer,
const G4ViewParameters& baseVP,
const std::vector<std::vector<G4PhysicalVolumeModel::G4PhysicalVolumeNodeID>>& paths)
{
// Copy view parameters to temporary variables ready for adding VisAttributes Modifiers (VAMs)
auto loVP = baseVP; // For black and solid VAMs
auto hiVP = baseVP; // For white and solid VAMs
// Modify them with vis attribute modifiers (VAMs)
for (const auto& path: paths) {
const auto& touchable = path.back().GetPhysicalVolume();
auto loVisAtts
= *(currentViewer->GetApplicableVisAttributes
(touchable->GetLogicalVolume()->GetVisAttributes()));
auto hiVisAtts = loVisAtts;
loVisAtts.SetColour(G4Colour::Black());
loVisAtts.SetForceSolid();
hiVisAtts.SetColour(G4Colour::White());
hiVisAtts.SetForceSolid();
auto pvNameCopyNoPath
= G4PhysicalVolumeModel::GetPVNameCopyNoPath(path);
auto loVAMColour = G4ModelingParameters::VisAttributesModifier
(loVisAtts, G4ModelingParameters::VASColour, pvNameCopyNoPath);
loVP.AddVisAttributesModifier(loVAMColour);
auto loVAMStyle = G4ModelingParameters::VisAttributesModifier
(loVisAtts, G4ModelingParameters::VASForceSolid, pvNameCopyNoPath);
loVP.AddVisAttributesModifier(loVAMStyle);
auto hiVAMColour = G4ModelingParameters::VisAttributesModifier
(hiVisAtts, G4ModelingParameters::VASColour, pvNameCopyNoPath);
hiVP.AddVisAttributesModifier(hiVAMColour);
auto hiVAMStyle = G4ModelingParameters::VisAttributesModifier
(hiVisAtts, G4ModelingParameters::VASForceSolid, pvNameCopyNoPath);
hiVP.AddVisAttributesModifier(hiVAMStyle);
}
// Twinkle
std::vector<G4ViewParameters> viewVector;
viewVector.push_back(loVP);
viewVector.push_back(hiVP);
viewVector.push_back(loVP);
viewVector.push_back(hiVP);
viewVector.push_back(loVP);
viewVector.push_back(hiVP);
viewVector.push_back(loVP);
viewVector.push_back(hiVP);
viewVector.push_back(loVP);
viewVector.push_back(hiVP);
// Just 5 interpolation points for a reasonable twinkle rate
InterpolateViews(currentViewer,viewVector,5);
}
void G4VVisCommand::CopyGuidanceFrom
(const G4UIcommand* fromCmd, G4UIcommand* toCmd, G4int startLine)
{
@@ -371,17 +430,6 @@ void G4VVisCommand::DrawExtent(const G4VisExtent& extent)
}
}
void G4VVisCommand::CopyMostViewParameters
(G4ViewParameters& target, const G4ViewParameters& from)
{
// Copy view parameters except for autoRefresh and background...
auto targetAutoRefresh = target.IsAutoRefresh();
auto targetBackground = target.GetBackgroundColour();
target = from;
target.SetAutoRefresh(targetAutoRefresh);
target.SetBackgroundColour(targetBackground);
}
void G4VVisCommand::CopyCameraParameters
(G4ViewParameters& target, const G4ViewParameters& from)
{
@@ -101,7 +101,8 @@ G4ViewParameters::G4ViewParameters ():
fDisplayLightFrontRed(0.),
fDisplayLightFrontGreen(1.),
fDisplayLightFrontBlue(0.),
fSpecialMeshRendering(false)
fSpecialMeshRendering(false),
fSpecialMeshRenderingOption(meshAsDots)
{
// Pick up default no of sides from G4Polyhedron.
// Note that this parameter is variously called:
@@ -459,6 +460,9 @@ G4String G4ViewParameters::DrawingStyleCommands() const
oss << "false";
}
oss << "\n/vis/viewer/set/specialMeshRenderingOption "
<< fSpecialMeshRenderingOption;
oss << "\n/vis/viewer/set/specialMeshVolumes";
for (const auto& volume : fSpecialMeshVolumes) {
oss << ' ' << volume.GetName() << ' ' << volume.GetCopyNo();
@@ -868,20 +872,32 @@ void G4ViewParameters::PrintDifferences (const G4ViewParameters& v) const {
}
std::ostream& operator <<
(std::ostream& os, const G4ViewParameters::DrawingStyle& style)
(std::ostream& os, G4ViewParameters::DrawingStyle style)
{
switch (style) {
case G4ViewParameters::wireframe:
os << "wireframe"; break;
case G4ViewParameters::hlr:
os << "hlr - hidden lines removed"; break;
case G4ViewParameters::hsr:
os << "hsr - hidden surfaces removed"; break;
case G4ViewParameters::hlhsr:
os << "hlhsr - hidden line, hidden surface removed"; break;
case G4ViewParameters::cloud:
os << "cloud - draw volume as a cloud of dots"; break;
default: os << "unrecognised"; break;
case G4ViewParameters::wireframe:
os << "wireframe"; break;
case G4ViewParameters::hlr:
os << "hlr - hidden lines removed"; break;
case G4ViewParameters::hsr:
os << "hsr - hidden surfaces removed"; break;
case G4ViewParameters::hlhsr:
os << "hlhsr - hidden line, hidden surface removed"; break;
case G4ViewParameters::cloud:
os << "cloud - draw volume as a cloud of dots"; break;
default: os << "unrecognised"; break;
}
return os;
}
std::ostream& operator <<
(std::ostream& os, G4ViewParameters::SMROption option)
{
switch (option) {
case G4ViewParameters::meshAsDots:
os << "dots"; break;
case G4ViewParameters::meshAsSurfaces:
os << "surfaces"; break;
}
return os;
}
@@ -1063,19 +1079,19 @@ std::ostream& operator << (std::ostream& os, const G4ViewParameters& v) {
<< ' ' << v.fDisplayLightFrontGreen << ' ' << v.fDisplayLightFrontBlue;
}
os << "\n Special Mesh Rendering: ";
os << "\n Special Mesh Rendering";
if (v.fSpecialMeshRendering) {
os << "on: ";
os << " requested with option \"" << v.fSpecialMeshRenderingOption;
os << "\" for ";
if (v.fSpecialMeshVolumes.empty()) {
os << "all meshes";
os << "any mesh";
} else {
os << "selected meshes";
for (const auto& vol: v.fSpecialMeshVolumes) {
os << "\n " << vol.GetName() << ':' << vol.GetCopyNo();
}
}
} else os << "off";
} else os << ": off";
return os;
}
@@ -1121,7 +1137,8 @@ G4bool G4ViewParameters::operator != (const G4ViewParameters& v) const {
(fBackgroundColour != v.fBackgroundColour) ||
(fPicking != v.fPicking) ||
(fRotationStyle != v.fRotationStyle) ||
(fSpecialMeshRendering != v.fSpecialMeshRendering)
(fSpecialMeshRendering != v.fSpecialMeshRendering) ||
(fSpecialMeshRenderingOption != v.fSpecialMeshRenderingOption)
)
return true;
@@ -1189,29 +1206,36 @@ G4bool G4ViewParameters::operator != (const G4ViewParameters& v) const {
return false;
}
void G4ViewParameters::SetXGeometryString (const G4String& geomStringArg)
void G4ViewParameters::SetXGeometryString (const G4String& geomString)
{
G4int x = 0, y = 0;
unsigned int w = 0, h = 0;
G4String geomString = geomStringArg;
// Parse windowSizeHintString for backwards compatibility...
const G4String delimiters("xX+-");
G4String::size_type i = geomString.find_first_of(delimiters);
if (i == G4String::npos) { // Does not contain "xX+-". Assume single number
if (i == G4String::npos) {
// Does not contain "xX+-".
// Is it a single number?
std::istringstream iss(geomString);
G4int size;
iss >> size;
if (!iss) {
size = 600;
G4cout << "Unrecognised windowSizeHint string: \""
<< geomString
<< "\". Asuuming " << size << G4endl;
if (iss) {
// It is a number
fWindowSizeHintX = size;
fWindowSizeHintY = size;
}
// Accept other or all defaults (in G4ViewParameters constructor)
// Reconstruct a geometry string coherent with the above
char signX, signY;
if (fWindowLocationHintXNegative) signX = '-'; else signX ='+';
if (fWindowLocationHintYNegative) signY = '-'; else signY ='+';
std::ostringstream oss;
oss << size << 'x' << size;
geomString = oss.str();
oss << fWindowSizeHintX << 'x' << fWindowSizeHintY
<< signX << fWindowLocationHintX << signY << fWindowLocationHintY;
fXGeometryString = oss.str();
return;
}
// Assume it's a parseable X geometry string
G4int x = 0, y = 0;
unsigned int w = 0, h = 0;
fGeometryMask = ParseGeometry( geomString, &x, &y, &w, &h );
// Handle special case :
@@ -72,6 +72,31 @@ void G4VisCommandAbortReviewKeptEvents::SetNewValue (G4UIcommand*,
G4cout << "Type \"continue\" to complete the abort." << G4endl;
}
////////////// /vis/abortReviewPlots /////////////////////////////
G4VisCommandAbortReviewPlots::G4VisCommandAbortReviewPlots () {
G4bool omitable;
fpCommand = new G4UIcmdWithABool("/vis/abortReviewPlots", this);
fpCommand -> SetGuidance("Abort review of plots.");
fpCommand -> SetParameterName("abort", omitable=true);
fpCommand -> SetDefaultValue(true);
}
G4VisCommandAbortReviewPlots::~G4VisCommandAbortReviewPlots () {
delete fpCommand;
}
G4String G4VisCommandAbortReviewPlots::GetCurrentValue (G4UIcommand*) {
return G4String();
}
void G4VisCommandAbortReviewPlots::SetNewValue (G4UIcommand*,
G4String newValue) {
fpVisManager->SetAbortReviewPlots(G4UIcommand::ConvertToBool(newValue));
G4cout << "Type \"continue\" to complete the abort." << G4endl;
}
////////////// /vis/drawOnlyToBeKeptEvents /////////////////////////////
G4VisCommandDrawOnlyToBeKeptEvents::G4VisCommandDrawOnlyToBeKeptEvents ()
@@ -319,9 +344,9 @@ void G4VisCommandReviewKeptEvents::SetNewValue (G4UIcommand*, G4String newValue)
}
G4UImanager* UImanager = G4UImanager::GetUIpointer();
G4int keepVerbose = UImanager->GetVerboseLevel();
G4int keepControlVerbose = UImanager->GetVerboseLevel();
G4int newVerbose(0);
if (keepVerbose >= 2 || verbosity >= G4VisManager::confirmations)
if (keepControlVerbose >= 2 || verbosity >= G4VisManager::confirmations)
newVerbose = 2;
UImanager->SetVerboseLevel(newVerbose);
@@ -401,7 +426,129 @@ void G4VisCommandReviewKeptEvents::SetNewValue (G4UIcommand*, G4String newValue)
if (keepConcreteInstance) fpVisManager->Enable();
else fpVisManager->Disable();
UImanager->SetVerboseLevel(keepVerbose);
UImanager->SetVerboseLevel(keepControlVerbose);
}
////////////// /vis/reviewPlots ///////////////////////////////////////
G4VisCommandReviewPlots::G4VisCommandReviewPlots ()
{
fpCommand = new G4UIcmdWithoutParameter("/vis/reviewPlots", this);
fpCommand -> SetGuidance("Review plots.");
fpCommand -> SetGuidance
("Each plot is drawn, one by one, to the current viewer. After each"
"\nplot the session is paused. The user may issue any allowed command."
"\nThen enter \"cont[inue]\" to continue to the next plot."
"\nUseful commands might be:"
"\n \"/vis/tsg/export\" to get hard copy."
"\n \"/vis/abortReviewPlots\", then \"cont[inue]\", to abort.");
}
G4VisCommandReviewPlots::~G4VisCommandReviewPlots ()
{
delete fpCommand;
}
G4String G4VisCommandReviewPlots::GetCurrentValue (G4UIcommand*)
{
return "";
}
#include <tools/histo/h1d>
#include <tools/histo/h2d>
namespace {
template <typename HT> // tools::histo::h1d, etc
G4bool ReviewPlots(const G4String& plotType) { // h1, etc.
auto visManager = G4VisManager::GetInstance();
auto ui = G4UImanager::GetUIpointer();
auto session = ui->GetSession();
G4bool aborting = false;
auto keepControlVerbose = ui->GetVerboseLevel();
ui->SetVerboseLevel(0);
auto status = ui->ApplyCommand("/analysis/" + plotType + "/getVector");
ui->SetVerboseLevel(keepControlVerbose);
if(status==G4UIcommandStatus::fCommandSucceeded) {
G4String hexString = ui->GetCurrentValues(G4String("/analysis/" + plotType + "/getVector"));
if(hexString.size()) {
void* ptr;
std::istringstream is(hexString);
is >> ptr;
auto _v = (const std::vector<HT*>*)ptr;
auto _n = _v->size();
for (size_t i = 0; i < _n; ++i) {
// Draw then pause session...
std::ostringstream oss;
oss << "/vis/plot " << plotType << ' ' << i;
ui->ApplyCommand(oss.str());
session->PauseSessionStart("EndOfEvent");
if (visManager->GetAbortReviewPlots()) {
aborting = true;
break;
}
}
}
}
return aborting;
}
}
void G4VisCommandReviewPlots::SetNewValue (G4UIcommand*, G4String)
{
if (fpVisManager->GetReviewingPlots()) {
G4cout <<
"\"/vis/reviewPlots\" not allowed within an already started review."
"\n No action taken."
<< G4endl;
return;
}
auto verbosity = fpVisManager->GetVerbosity();
auto currentViewer = fpVisManager->GetCurrentViewer();
if (!currentViewer) {
if (verbosity >= G4VisManager::errors) {
G4cerr <<
"ERROR: No current viewer - \"/vis/viewer/list\" to see possibilities."
<< G4endl;
}
return;
}
if (currentViewer->GetName().find("TOOLSSG") == std::string::npos) {
G4cerr <<
"WARNING: Current viewer not able to draw plots."
"\n Try \"/vis/open TSG\", then \"/vis/reviewPlots\" again."
<< G4endl;
return;
}
G4Scene* pScene = fpVisManager->GetCurrentScene();
if (!pScene) {
if (verbosity >= G4VisManager::errors) {
G4cerr << "ERROR: No current scene. Please create one." << G4endl;
}
return;
}
auto ui = G4UImanager::GetUIpointer();
auto keepControlVerbose = ui->GetVerboseLevel();
ui->SetVerboseLevel(0);
auto keepVisVerbose = fpVisManager->GetVerbosity();
fpVisManager->SetVerboseLevel(G4VisManager::errors);
auto keepEnable = fpVisManager->IsEnabled();
fpVisManager->Enable();
fpVisManager->SetReviewingPlots(true);
if (ReviewPlots<tools::histo::h1d>("h1")) goto finish; // Aborting?
if (ReviewPlots<tools::histo::h2d>("h2")) goto finish; // Aborting?
finish:
fpVisManager->SetReviewingPlots(false);
if (!keepEnable) fpVisManager->Disable();
fpVisManager->SetVerboseLevel(keepVisVerbose);
ui->SetVerboseLevel(keepControlVerbose);
}
////////////// /vis/verbose ///////////////////////////////////////
@@ -342,17 +342,22 @@ G4VisCommandOpen::G4VisCommandOpen() {
G4bool omitable;
fpCommand = new G4UIcommand("/vis/open", this);
fpCommand->SetGuidance
("Creates a scene handler ready for drawing.");
("Creates a scene handler and viewer ready for drawing.");
fpCommand->SetGuidance
("The scene handler becomes current (the name is auto-generated).");
("The scene handler and viewer names are auto-generated.");
// Pick up guidance from /vis/viewer/create
const G4UIcommandTree* tree = G4UImanager::GetUIpointer()->GetTree();
const G4UIcommand* viewerCreateCmd = tree->FindPath("/vis/viewer/create");
CopyGuidanceFrom(viewerCreateCmd,fpCommand,2);
G4UIparameter* parameter;
parameter = new G4UIparameter("graphics-system-name", 's', omitable = false);
parameter = new G4UIparameter("graphics-system-name", 's', omitable = true);
parameter->SetCurrentAsDefault(true);
fpCommand->SetParameter(parameter);
parameter = new G4UIparameter("window-size-hint", 's', omitable = true);
parameter->SetGuidance
("integer (pixels) for square window placed by window manager or"
" X-Windows-type geometry string, e.g. 600x600-100+100");
parameter->SetDefaultValue("600");
parameter->SetDefaultValue("none");
fpCommand->SetParameter(parameter);
}
@@ -360,6 +365,19 @@ G4VisCommandOpen::~G4VisCommandOpen() {
delete fpCommand;
}
G4String G4VisCommandOpen::GetCurrentValue(G4UIcommand*)
{
G4String graphicsSystemName;
auto graphicsSystem = fpVisManager->GetCurrentGraphicsSystem();
if (graphicsSystem) {
graphicsSystemName = graphicsSystem->GetName ();
}
else {
graphicsSystemName = "none";
}
return graphicsSystemName;
}
void G4VisCommandOpen::SetNewValue (G4UIcommand* command, G4String newValue)
{
G4String systemName, windowSizeHint;
@@ -390,26 +408,80 @@ void G4VisCommandOpen::SetNewValue (G4UIcommand* command, G4String newValue)
finish:
if (errorCode) {
std::set<G4String> candidates;
for (const auto gs: fpVisManager -> GetAvailableGraphicsSystems()) {
// Just list nicknames, but exclude FALLBACK nicknames
for (const auto& nickname: gs->GetNicknames()) {
if (!G4StrUtil::contains(nickname, "FALLBACK")) {
candidates.insert(nickname);
}
}
}
G4ExceptionDescription ed;
ed << "Invoked command has failed - see above. Available graphics systems are (short names):\n ";
for (const auto& candidate: candidates) {
ed << ' ' << candidate;
};
ed << "Invoked command has failed - see above. Available graphics systems are:\n ";
fpVisManager->PrintAvailableGraphicsSystems(G4VisManager::warnings,ed);
command->CommandFailed(errorCode,ed);
}
UImanager->SetVerboseLevel(keepVerbose);
}
////////////// /vis/plot ///////////////////////////////////////
G4VisCommandPlot::G4VisCommandPlot ()
{
G4bool omitable;
G4UIparameter* parameter;
fpCommand = new G4UIcommand("/vis/plot", this);
fpCommand -> SetGuidance("Draws plots.");
parameter = new G4UIparameter ("type", 's', omitable = false);
parameter -> SetParameterCandidates("h1 h2");
fpCommand -> SetParameter (parameter);
parameter = new G4UIparameter ("id", 'i', omitable = false);
fpCommand -> SetParameter (parameter);
}
G4VisCommandPlot::~G4VisCommandPlot ()
{
delete fpCommand;
}
G4String G4VisCommandPlot::GetCurrentValue (G4UIcommand*)
{
return "";
}
void G4VisCommandPlot::SetNewValue (G4UIcommand*, G4String newValue)
{
auto currentViewer = fpVisManager->GetCurrentViewer();
if (currentViewer->GetName().find("TOOLSSG") == std::string::npos) {
G4cerr <<
"WARNING: Current viewer not able to draw plots."
"\n Try \"/vis/open TSG\", then \"/vis/plot " << newValue << "\" again."
<< G4endl;
return;
}
G4String type, id;
std::istringstream is (newValue);
is >> type >> id;
auto keepEnable = fpVisManager->IsEnabled();
auto ui = G4UImanager::GetUIpointer();
ui->ApplyCommand("/vis/enable");
ui->ApplyCommand("/vis/viewer/resetCameraParameters");
ui->ApplyCommand("/vis/scene/create");
ui->ApplyCommand("/vis/scene/endOfEventAction accumulate 0"); // Don't keep events
static G4int plotterID = 0;
std::ostringstream ossPlotter;
ossPlotter << "plotter-" << plotterID++;
const G4String& plotterName = ossPlotter.str();
ui->ApplyCommand("/vis/plotter/create " + plotterName);
ui->ApplyCommand("/vis/scene/add/plotter " + plotterName);
ui->ApplyCommand("/vis/plotter/add/" + type + ' ' + id + ' ' + plotterName);
ui->ApplyCommand("/vis/sceneHandler/attach");
if (!keepEnable) {
fpVisManager->Disable();
G4cerr <<
"WARNING: drawing was enabled for plotting but is now restored to disabled mode."
<< G4endl;
}
}
////////////// /vis/specify ///////////////////////////////////////
G4VisCommandSpecify::G4VisCommandSpecify() {
@@ -348,9 +348,9 @@ void G4VisCommandSceneAddAxes::SetNewValue (G4UIcommand*, G4String newValue) {
// Consult scene for arrow width...
G4double arrowWidth =
0.005 * fCurrentLineWidth * sceneExtent.GetExtentRadius();
// ...but limit it to length/50.
if (arrowWidth > length/50.) arrowWidth = length/50.;
0.05 * fCurrentLineWidth * sceneExtent.GetExtentRadius();
// ...but limit it to length/30.
if (arrowWidth > length/30.) arrowWidth = length/30.;
G4VModel* model = new G4AxesModel
(x0, y0, z0, length, arrowWidth, colourString, newValue,
@@ -3077,7 +3077,7 @@ G4VisCommandSceneAddVolume::G4VisCommandSceneAddVolume () {
parameter = new G4UIparameter ("depth-of-descent", 'i', omitable = true);
parameter -> SetGuidance
("Depth of descent of geometry hierarchy. Default = unlimited depth.");
parameter -> SetDefaultValue (G4Scene::UNLIMITED);
parameter -> SetDefaultValue (G4PhysicalVolumeModel::UNLIMITED);
fpCommand -> SetParameter (parameter);
parameter = new G4UIparameter ("clip-volume-type", 's', omitable = true);
parameter -> SetParameterCandidates("none box -box *box");
@@ -3259,12 +3259,11 @@ void G4VisCommandSceneAddVolume::SetNewValue (G4UIcommand*,
G4ModelingParameters mp; // Default - no culling.
G4PhysicalVolumeModel searchModel
(*iterWorld,
G4PhysicalVolumeModel::UNLIMITED,
requestedDepthOfDescent,
G4Transform3D(),
&mp,
useFullExtent);
G4PhysicalVolumesSearchScene searchScene
(&searchModel, name, copyNo, requestedDepthOfDescent);
G4PhysicalVolumesSearchScene searchScene(&searchModel, name, copyNo);
searchModel.DescribeYourselfTo (searchScene); // Initiate search.
for (const auto& findings: searchScene.GetFindings()) {
findingsVector.push_back(findings);
@@ -3357,14 +3356,16 @@ void G4VisCommandSceneAddPlotter::SetNewValue (G4UIcommand*, G4String newValue)
}
G4Plotter& _plotter = G4PlotterManager::GetInstance().GetPlotter(newValue);
G4VModel* model = new G4PlotterModel(_plotter);
G4VModel* model = new G4PlotterModel(_plotter,newValue);
const G4String& currentSceneName = pScene -> GetName ();
G4bool successful = pScene -> AddRunDurationModel (model, warn);
G4bool successful = pScene -> AddEndOfRunModel(model, warn);
if (successful) {
if (verbosity >= G4VisManager::confirmations) {
G4cout << "Arrow has been added to scene \"" << currentSceneName << "\"." << G4endl;
G4cout
<< "Plotter \"" << model->GetCurrentDescription()
<< "\" has been added to scene \"" << currentSceneName << "\"."
<< G4endl;
}
}
else G4VisCommandsSceneAddUnsuccessful(verbosity);
@@ -243,16 +243,6 @@ void G4VisCommandSceneHandlerCreate::SetNewValue (G4UIcommand* command,
}
if (!found) {
// Shouldn't happen, since graphicsSystem should be a candidate
// Use set to get alphabetical order
std::set<G4String> candidates;
for (const auto gs: fpVisManager -> GetAvailableGraphicsSystems()) {
// Just list nicknames, but exclude FALLBACK nicknames
for (const auto& nickname: gs->GetNicknames()) {
if (!G4StrUtil::contains(nickname, "FALLBACK")) {
candidates.insert(nickname);
}
}
}
G4ExceptionDescription ed;
ed <<
"ERROR: G4VisCommandSceneHandlerCreate::SetNewValue:"
@@ -260,9 +250,7 @@ void G4VisCommandSceneHandlerCreate::SetNewValue (G4UIcommand* command,
<< graphicsSystem
<< "\" requested."
<< "\n Candidates are:";
for (const auto& candidate: candidates) {
ed << ' ' << candidate;
};
fpVisManager->PrintAvailableGraphicsSystems(verbosity,ed);
command->CommandFailed(ed);
return;
}
@@ -337,7 +325,7 @@ void G4VisCommandSceneHandlerCreate::SetNewValue (G4UIcommand* command,
// If there is an existing viewer, store its view parameters
if (fpVisManager->GetCurrentViewer()) {
fThereWasAViewer = true;
fVPExistingViewer = fpVisManager->GetCurrentViewer()->GetViewParameters();
fExistingVP = fpVisManager->GetCurrentViewer()->GetViewParameters();
}
// Set current graphics system in preparation for
@@ -209,7 +209,8 @@ G4VisCommandSetLineWidth::G4VisCommandSetLineWidth ()
G4bool omitable;
fpCommand = new G4UIcmdWithADouble("/vis/set/lineWidth", this);
fpCommand->SetGuidance
("Defines line width for future \"/vis/scene/add/\" commands.");
("Defines line width for future \"/vis/scene/add/\" commands."
"\nSee \"/vis/viewer/set/lineWidth\" for more information.");
fpCommand->SetParameterName ("lineWidth", omitable = true);
fpCommand->SetDefaultValue (1.);
fpCommand->SetRange("lineWidth >= 1.");
@@ -231,11 +232,12 @@ void G4VisCommandSetLineWidth::SetNewValue (G4UIcommand*, G4String newValue)
fCurrentLineWidth = fpCommand->GetNewDoubleValue(newValue);
if (verbosity >= G4VisManager::confirmations) {
if (verbosity >= G4VisManager::warnings) {
G4cout <<
"Line width for future \"/vis/scene/add/\" commands has been set to "
<< fCurrentLineWidth
<< G4endl;
"Line width for *future* \"/vis/scene/add/\" commands has been set to "
<< fCurrentLineWidth <<
"\nSee \"/vis/viewer/set/lineWidth\" for more information."
<< G4endl;
}
}
@@ -59,10 +59,14 @@ G4VisCommandsTouchable::G4VisCommandsTouchable()
// Pick up additional guidance from /vis/viewer/centreAndZoomInOn
CopyGuidanceFrom(fpCommandCentreAndZoomInOn,fpCommandCentreOn,1);
fpCommandDraw = new G4UIcmdWithoutParameter("/vis/touchable/draw",this);
fpCommandDraw = new G4UIcmdWithABool("/vis/touchable/draw",this);
fpCommandDraw->SetGuidance("Draw touchable.");
fpCommandDraw->SetGuidance
("If parameter == true, also draw extent as a white wireframe box.");
// Pick up additional guidance from /vis/viewer/centreAndZoomInOn
CopyGuidanceFrom(fpCommandCentreAndZoomInOn,fpCommandDraw,1);
fpCommandDraw->SetParameterName("extent", omitable = true);
fpCommandDraw->SetDefaultValue(false);
fpCommandDump = new G4UIcmdWithoutParameter("/vis/touchable/dump",this);
fpCommandDump->SetGuidance("Dump touchable attributes.");
@@ -185,7 +189,10 @@ void G4VisCommandsTouchable::SetNewValue
}
if (command == fpCommandCentreOn || command == fpCommandCentreAndZoomInOn) {
// For twinkling...
std::vector<std::vector<G4PhysicalVolumeModel::G4PhysicalVolumeNodeID>> touchables;
G4PhysicalVolumeModel::TouchableProperties properties =
G4TouchableUtils::FindTouchableProperties(fCurrentTouchableProperties.fTouchablePath);
if (properties.fpTouchablePV) {
@@ -198,17 +205,18 @@ void G4VisCommandsTouchable::SetNewValue
nullptr, // Modelling parameters (not used)
true, // use full extent (prevents calculating own extent, which crashes)
properties.fTouchableBaseFullPVPath);
touchables.push_back(properties.fTouchableFullPVPath); // Only one in this case
// Use a temporary scene in order to find vis extent
G4Scene tempScene("Centre Scene");
G4bool successful = tempScene.AddRunDurationModel(&tempPVModel,warn);
if (successful) {
if (verbosity >= G4VisManager::confirmations) {
G4cout
<< "Touchable " << fCurrentTouchableProperties.fTouchablePath
<< ",\n has been added to temporary scene \"" << tempScene.GetName() << "\"."
<< G4endl;
}
if (!successful) return;
if (verbosity >= G4VisManager::parameters) {
G4cout
<< "Touchable " << fCurrentTouchableProperties.fTouchablePath
<< ",\n has been added to temporary scene \"" << tempScene.GetName() << "\"."
<< G4endl;
}
const G4VisExtent& newExtent = tempScene.GetExtent();
const G4ThreeVector& newTargetPoint = newExtent.GetExtentCentre();
G4ViewParameters saveVP = currentViewer->GetViewParameters();
@@ -222,8 +230,15 @@ void G4VisCommandsTouchable::SetNewValue
// Change the target point
const G4Point3D& standardTargetPoint = currentScene->GetStandardTargetPoint();
newVP.SetCurrentTargetPoint(newTargetPoint - standardTargetPoint);
// Interpolate
InterpolateToNewView(currentViewer, saveVP, newVP);
auto keepVerbose = fpVisManager->GetVerbosity();
fpVisManager->SetVerboseLevel(G4VisManager::errors);
if (newVP != saveVP) InterpolateToNewView(currentViewer, saveVP, newVP);
// ...and twinkle
Twinkle(currentViewer,newVP,touchables);
fpVisManager->SetVerboseLevel(keepVerbose);
if (verbosity >= G4VisManager::confirmations) {
G4cout
<< "Viewer \"" << currentViewer->GetName()
@@ -238,6 +253,7 @@ void G4VisCommandsTouchable::SetNewValue
} else {
G4cout << "Touchable not found." << G4endl;
}
return;
} else if (command == fpCommandDraw) {
@@ -267,10 +283,23 @@ void G4VisCommandsTouchable::SetNewValue
UImanager->SetVerboseLevel(keepVerbose);
if (successful) {
if (fpCommandDraw->GetNewBoolValue(newValue)) {
const auto& extent = pvModel->GetExtent();
const G4double halfX = (extent.GetXmax()-extent.GetXmin())/2.;
const G4double halfY = (extent.GetYmax()-extent.GetYmin())/2.;
const G4double halfZ = (extent.GetZmax()-extent.GetZmin())/2.;
G4Box extentBox("extent",halfX,halfY,halfZ);
G4VisAttributes extentVA;
extentVA.SetForceWireframe();
fpVisManager->Draw(extentBox,extentVA,G4Translate3D(extent.GetExtentCentre()));
}
if (verbosity >= G4VisManager::confirmations) {
G4cout << "\"" << properties.fpTouchablePV->GetName()
<< "\", copy no. " << properties.fCopyNo << " drawn"
<< G4endl;
<< "\", copy no. " << properties.fCopyNo << " drawn";
if (fpCommandDraw->GetNewBoolValue(newValue)) {
G4cout << " with extent box";
}
G4cout << '.' << G4endl;
}
} else {
G4VisCommandsSceneAddUnsuccessful(verbosity);
@@ -298,8 +327,9 @@ void G4VisCommandsTouchable::SetNewValue
std::vector<G4AttValue>* attValues = tempPVModel.CreateCurrentAttValues();
G4cout << G4AttCheck(attValues,attDefs);
delete attValues;
G4Polyhedron* polyhedron =
properties.fpTouchablePV->GetLogicalVolume()->GetSolid()->GetPolyhedron();
const auto lv = properties.fpTouchablePV->GetLogicalVolume();
const auto polyhedron = lv->GetSolid()->GetPolyhedron();
polyhedron->SetVisAttributes(lv->GetVisAttributes());
G4cout << "\nLocal polyhedron coordinates:\n" << *polyhedron;
const G4Transform3D& transform = tempPVModel.GetCurrentTransform();
polyhedron->Transform(transform);
@@ -234,8 +234,12 @@ void G4VisCommandViewerCentreOn::SetNewValue (G4UIcommand* command, G4String new
return;
}
// A vector of found paths so that we can highlight (twinkle) the found volume(s).
std::vector<std::vector<G4PhysicalVolumeModel::G4PhysicalVolumeNodeID>> foundPaths;
// Use a temporary scene in order to find vis extent
G4Scene tempScene("Centre Scene");
G4bool successfullyAdded = true;
for (const auto& findings: findingsVector) {
// To handle paramaterisations we have to set the copy number
findings.fpFoundPV->SetCopyNo(findings.fFoundPVCopyNo);
@@ -250,29 +254,33 @@ void G4VisCommandViewerCentreOn::SetNewValue (G4UIcommand* command, G4String new
true, // Use full extent
findings.fFoundBasePVPath);
// ...and add it to the scene.
G4bool successful = tempScene.AddRunDurationModel(tempPVModel,warn);
if (successful) {
if (verbosity >= G4VisManager::confirmations) {
G4cout << "\"" << findings.fpFoundPV->GetName()
<< "\", copy no. " << findings.fFoundPVCopyNo
<< ",\n found in searched volume \""
<< findings.fpSearchPV->GetName()
<< "\" at depth " << findings.fFoundDepth
<< ",\n base path: \"" << findings.fFoundBasePVPath
<< ",\n has been added to temporary scene \"" << tempScene.GetName() << "\"."
<< G4endl;
}
auto successful = tempScene.AddRunDurationModel(tempPVModel,warn);
if (!successful) {
successfullyAdded = false;
continue;
}
if (verbosity >= G4VisManager::parameters) {
G4cout << "\"" << findings.fpFoundPV->GetName()
<< "\", copy no. " << findings.fFoundPVCopyNo
<< ",\n found in searched volume \""
<< findings.fpSearchPV->GetName()
<< "\" at depth " << findings.fFoundDepth
<< ",\n base path: \"" << findings.fFoundBasePVPath
<< ",\n has been added to temporary scene \"" << tempScene.GetName() << "\"."
<< G4endl;
}
foundPaths.push_back(findings.fFoundFullPVPath);
}
// Delete temporary physical volume models
for (const auto& sceneModel: tempScene.GetRunDurationModelList()) {
delete sceneModel.fpModel;
}
if (!successfullyAdded) return;
// Relevant results
const G4VisExtent& newExtent = tempScene.GetExtent();
const G4ThreeVector& newTargetPoint = newExtent.GetExtentCentre();
G4Scene* currentScene = currentViewer->GetSceneHandler()->GetScene();
G4ViewParameters saveVP = currentViewer->GetViewParameters();
G4ViewParameters newVP = saveVP;
@@ -285,8 +293,17 @@ void G4VisCommandViewerCentreOn::SetNewValue (G4UIcommand* command, G4String new
// Change the target point
const G4Point3D& standardTargetPoint = currentScene->GetStandardTargetPoint();
newVP.SetCurrentTargetPoint(newTargetPoint - standardTargetPoint);
// Interpolate
InterpolateToNewView(currentViewer, saveVP, newVP);
// If this particular view is simple enough
if (currentViewer->GetKernelVisitElapsedTimeSeconds() < 0.1) {
// Interpolate
auto keepVerbose = fpVisManager->GetVerbosity();
fpVisManager->SetVerboseLevel(G4VisManager::errors);
if (newVP != saveVP) InterpolateToNewView(currentViewer, saveVP, newVP);
// ...and twinkle
Twinkle(currentViewer,newVP,foundPaths);
fpVisManager->SetVerboseLevel(keepVerbose);
}
if (verbosity >= G4VisManager::confirmations) {
G4cout
@@ -297,8 +314,8 @@ void G4VisCommandViewerCentreOn::SetNewValue (G4UIcommand* command, G4String new
}
G4cout << " on physical volume(s) \"" << pvName << '\"'
<< G4endl;
}
}
SetViewParameters(currentViewer, newVP);
}
@@ -890,13 +907,35 @@ G4VisCommandViewerCreate::G4VisCommandViewerCreate (): fId (0) {
G4bool omitable;
fpCommand = new G4UIcommand ("/vis/viewer/create", this);
fpCommand -> SetGuidance
("Creates a viewer for the specified scene handler.");
("Creates a viewer. If the scene handler name is specified, then a"
"\nviewer of that scene handler is created. Otherwise, a viewer"
"\nof the current scene handler is created.");
fpCommand -> SetGuidance
("Default scene handler is the current scene handler. Invents a name"
"\nif not supplied. (Note: the system adds information to the name"
"\nfor identification - only the characters up to the first blank are"
"\nused for removing, selecting, etc.) This scene handler and viewer"
"\nbecome current.");
("If the viewer name is not specified a name is generated from the name"
"\nof the scene handler and a serial number.");
fpCommand -> SetGuidance("The scene handler and viewer become current.");
fpCommand -> SetGuidance
("(Note: the system adds the graphics system name to the viewer name"
"\nfor identification, but for selecting, copying, etc., only characters"
"\nup to the first blank are used. For example, if the viewer name is"
"\n\"viewer-0 (G4OpenGLStoredQt)\", it may be referenced by \"viewer-0\","
"\nfor example in \"/vis/viewer/select viewer-0\".)");
fpCommand -> SetGuidance
("Window size and placement hints, e.g. 600x600-100+100 (in pixels):");
fpCommand -> SetGuidance
("- single number, e.g., \"600\": square window;");
fpCommand -> SetGuidance
("- two numbers, e.g., \"800x600\": rectangluar window;");
fpCommand -> SetGuidance
("- two numbers plus placement hint, e.g., \"600x600-100+100\" places window of size"
"\n 600x600 100 pixels left and 100 pixels down from top right corner.");
fpCommand -> SetGuidance
("- If not specified, the default is \"600\", i.e., 600 pixels square, placed"
"\n at the window manager's discretion...or picked up from the previous viewer.");
fpCommand -> SetGuidance
("- This is an X-Windows-type geometry string, see:"
"\n https://en.wikibooks.org/wiki/Guide_to_X11/Starting_Programs,"
"\n \"Specifying window geometry\".");
G4UIparameter* parameter;
parameter = new G4UIparameter ("scene-handler", 's', omitable = true);
parameter -> SetCurrentAsDefault (true);
@@ -905,10 +944,7 @@ G4VisCommandViewerCreate::G4VisCommandViewerCreate (): fId (0) {
parameter -> SetCurrentAsDefault (true);
fpCommand -> SetParameter (parameter);
parameter = new G4UIparameter ("window-size-hint", 's', omitable = true);
parameter->SetGuidance
("integer (pixels) for square window placed by window manager or"
" X-Windows-type geometry string, e.g. 600x600-100+100");
parameter->SetDefaultValue("600");
parameter -> SetDefaultValue("none");
fpCommand -> SetParameter (parameter);
}
@@ -936,17 +972,13 @@ G4String G4VisCommandViewerCreate::GetCurrentValue (G4UIcommand*) {
fpVisManager -> GetCurrentSceneHandler ();
if (currentSceneHandler) {
currentValue = currentSceneHandler -> GetName ();
}
else {
} else {
currentValue = "none";
}
currentValue += ' ';
currentValue += '"';
currentValue += NextName ();
currentValue += '"';
currentValue += " 600"; // Default number of pixels for window size hint.
return currentValue;
}
@@ -1032,36 +1064,43 @@ void G4VisCommandViewerCreate::SetNewValue (G4UIcommand* command, G4String newVa
}
}
// If there was an existing viewer, use its view parameters
if (fThereWasAViewer) {
// OK, we're going to use its view parameters below
} else {
// There wasn't one...but if there now is...
if (fpVisManager->GetCurrentViewer()) {
fThereWasAViewer = true;
fVPExistingViewer = fpVisManager->GetCurrentViewer()->GetViewParameters();
// ...and if it's still current...
auto existingViewer = fpVisManager->GetCurrentViewer();
if (existingViewer) {
// ...bring view parameters up to date...
fExistingVP = existingViewer->GetViewParameters();
}
}
// WindowSizeHint and XGeometryString are picked up from the vis
// manager in the G4VViewer constructor. In G4VisManager, after Viewer
// creation, we will store theses parameters in G4ViewParameters.
if (fThereWasAViewer && windowSizeHintString == "none") {
// The user did not specify a window size hint - get from existing VPs
windowSizeHintString = fExistingVP.GetXGeometryString();
}
fpVisManager -> CreateViewer (newName,windowSizeHintString);
// Now we have a new viewer
G4VViewer* newViewer = fpVisManager -> GetCurrentViewer ();
if (newViewer && newViewer -> GetName () == newName) {
if (fThereWasAViewer) {
G4ViewParameters vp = newViewer->GetViewParameters();
CopyMostViewParameters(vp, fVPExistingViewer);
fpVisManager->GetCurrentViewer()->SetViewParameters(vp);
// Copy view parameters from existing viewer, except for...
fExistingVP.SetAutoRefresh(vp.IsAutoRefresh());
fExistingVP.SetBackgroundColour(vp.GetBackgroundColour());
// ...including window hint paramaters that have been set already above...
fExistingVP.SetXGeometryString(vp.GetXGeometryString());
vp = fExistingVP;
newViewer->SetViewParameters(vp);
}
if (verbosity >= G4VisManager::confirmations) {
G4cout << "New viewer \"" << newName << "\" created." << G4endl;
}
}
else {
// Keep for next time...
fThereWasAViewer = true;
fExistingVP = fpVisManager->GetCurrentViewer()->GetViewParameters();
} else {
G4ExceptionDescription ed;
if (newViewer) {
ed << "ERROR: New viewer doesn\'t match!!! Curious!!";
@@ -1815,6 +1854,55 @@ void G4VisCommandViewerReset::SetNewValue (G4UIcommand*, G4String newValue) {
RefreshIfRequired(viewer);
}
////////////// /vis/viewer/resetCameraParameters ///////////////////////////////////////
G4VisCommandViewerResetCameraParameters::G4VisCommandViewerResetCameraParameters () {
G4bool omitable, currentAsDefault;
fpCommand = new G4UIcmdWithAString ("/vis/viewer/resetCameraParameters", this);
fpCommand -> SetGuidance ("Resets only the camera parameters.");
fpCommand -> SetGuidance
("By default, acts on current viewer. \"/vis/viewer/list\""
"\nto see possible viewers. Viewer becomes current.");
fpCommand -> SetParameterName ("viewer-name",
omitable = true,
currentAsDefault = true);
}
G4VisCommandViewerResetCameraParameters::~G4VisCommandViewerResetCameraParameters () {
delete fpCommand;
}
G4String G4VisCommandViewerResetCameraParameters::GetCurrentValue (G4UIcommand*) {
G4VViewer* viewer = fpVisManager -> GetCurrentViewer ();
if (viewer) {
return viewer -> GetName ();
}
else {
return "none";
}
}
void G4VisCommandViewerResetCameraParameters::SetNewValue (G4UIcommand*, G4String newValue) {
G4VisManager::Verbosity verbosity = fpVisManager->GetVerbosity();
G4String& resetName = newValue;
G4VViewer* viewer = fpVisManager -> GetViewer (resetName);
if (!viewer) {
if (verbosity >= G4VisManager::errors) {
G4cerr << "ERROR: Viewer \"" << resetName
<< "\" not found - \"/vis/viewer/list\" to see possibilities."
<< G4endl;
}
return;
}
G4ViewParameters newVP = viewer->GetViewParameters();
CopyCameraParameters(newVP,viewer->GetDefaultViewParameters());
viewer->SetViewParameters(newVP);
RefreshIfRequired(viewer);
}
////////////// /vis/viewer/save ///////////////////////////////////////
G4VisCommandViewerSave::G4VisCommandViewerSave () {
@@ -30,6 +30,7 @@
#include "G4VisCommandsViewerSet.hh"
#include "G4UIcommand.hh"
#include "G4UIcmdWithoutParameter.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithABool.hh"
#include "G4UIcmdWithAnInteger.hh"
@@ -282,6 +283,13 @@ fViewpointVector (G4ThreeVector(0.,0.,1.))
fpCommandLineSegments->SetParameterName("line-segments",omitable = true);
fpCommandLineSegments->SetDefaultValue(24);
fpCommandLineWidth = new G4UIcmdWithoutParameter
("/vis/viewer/set/lineWidth",this);
fpCommandLineWidth->SetGuidance
("Use \"/vis/viewer/set/globalLineWidthScale\" instead."
"\nFor trajectories use \"/vis/modeling/trajectories/*/default/setLineWidth\"."
"\nFor volumes use \"/vis/geometry/set/lineWidth\".");
fpCommandNumberOfCloudPoints = new G4UIcmdWithAnInteger
("/vis/viewer/set/numberOfCloudPoints",this);
fpCommandNumberOfCloudPoints->SetGuidance
@@ -371,10 +379,18 @@ fViewpointVector (G4ThreeVector(0.,0.,1.))
fpCommandSpecialMeshRendering = new G4UIcmdWithABool
("/vis/viewer/set/specialMeshRendering",this);
fpCommandSpecialMeshRendering -> SetGuidance
("Request special rendering of volumes (meshes) that use G4VNestedParameterisation.");
("Request special rendering of volumes (meshes) that use G4VParameterisation.");
fpCommandSpecialMeshRendering->SetParameterName("render",omitable = true);
fpCommandSpecialMeshRendering->SetDefaultValue(true);
fpCommandSpecialMeshRenderingOption = new G4UIcmdWithAString
("/vis/viewer/set/specialMeshRenderingOption",this);
fpCommandSpecialMeshRenderingOption->SetGuidance
("Set special mesh rendering option - \"dots\" or \"surfaces\".");
fpCommandSpecialMeshRenderingOption->SetParameterName ("option",omitable = true);
fpCommandSpecialMeshRenderingOption->SetCandidates("dots surfaces");
fpCommandSpecialMeshRenderingOption->SetDefaultValue("dots");
fpCommandSpecialMeshVolumes = new G4UIcommand
("/vis/viewer/set/specialMeshVolumes",this);
fpCommandSpecialMeshVolumes -> SetGuidance
@@ -630,12 +646,14 @@ G4VisCommandsViewerSet::~G4VisCommandsViewerSet() {
delete fpCommandTargetPoint;
delete fpCommandStyle;
delete fpCommandSpecialMeshVolumes;
delete fpCommandSpecialMeshRenderingOption;
delete fpCommandSpecialMeshRendering;
delete fpCommandSectionPlane;
delete fpCommandRotationStyle;
delete fpCommandProjection;
delete fpCommandPicking;
delete fpCommandNumberOfCloudPoints;
delete fpCommandLineWidth;
delete fpCommandLineSegments;
delete fpCommandLightsVector;
delete fpCommandLightsThetaPhi;
@@ -698,7 +716,11 @@ void G4VisCommandsViewerSet::SetNewValue
return;
}
// Copy view parameters except for autoRefresh and background...
CopyMostViewParameters(vp, fromViewer->GetViewParameters());
auto keepAutoRefresh = vp.IsAutoRefresh();
auto keepBackground = vp.GetBackgroundColour();
vp = fromViewer->GetViewParameters();
vp.SetAutoRefresh(keepAutoRefresh);
vp.SetBackgroundColour(keepBackground);
// Concatenate any private vis attributes modifiers...
const std::vector<G4ModelingParameters::VisAttributesModifier>*
privateVAMs = fromViewer->GetPrivateVisAttributesModifiers();
@@ -1076,6 +1098,13 @@ void G4VisCommandsViewerSet::SetNewValue
}
}
else if (command == fpCommandLineWidth) {
if (verbosity >= G4VisManager::errors) {
// A do-nothing command
G4cerr << command->GetGuidanceLine(0) << G4endl;
}
}
else if (command == fpCommandLineSegments) {
G4int nSides = G4UIcommand::ConvertToInt(newValue);
nSides = vp.SetNoOfSides(nSides);
@@ -1222,13 +1251,38 @@ void G4VisCommandsViewerSet::SetNewValue
else if (command == fpCommandSpecialMeshRendering) {
vp.SetSpecialMeshRendering(G4UIcommand::ConvertToBool(newValue));
if (verbosity >= G4VisManager::confirmations) {
G4cout << "Special mesh rendering ";
if (vp.IsSpecialMeshRendering()) G4cout << "requested.";
else G4cout << "inhibited.";
G4cout << "Special mesh rendering";
if (vp.IsSpecialMeshRendering()) {
G4cout << " requested. Current option is \""
<< vp.GetSpecialMeshRenderingOption() << "\" for ";
if (vp.GetSpecialMeshVolumes().empty()) {
G4cout << "any mesh.";
} else{
G4cout << "selected volumes:";
for (const auto& pvNameCopyNo: vp.GetSpecialMeshVolumes()) {
G4cout << "\n " << pvNameCopyNo.GetName();
if (pvNameCopyNo.GetCopyNo() >= 0) G4cout << ':' << pvNameCopyNo.GetCopyNo();
}
}
}
else G4cout << ": off.";
G4cout << G4endl;
}
}
else if (command == fpCommandSpecialMeshRenderingOption) {
G4ViewParameters::SMROption option = G4ViewParameters::meshAsDots;
if (newValue == "surfaces") {
option = G4ViewParameters::meshAsSurfaces;
}
vp.SetSpecialMeshRenderingOption(option);
if (verbosity >= G4VisManager::confirmations) {
G4cout << "Special mesh rendering option set to \""
<< vp.GetSpecialMeshRenderingOption() << "\"."
<< G4endl;
}
}
else if (command == fpCommandSpecialMeshVolumes) {
std::vector<G4ModelingParameters::PVNameCopyNo> requestedMeshes;
if (newValue.empty()) {
@@ -95,32 +95,34 @@ G4VisManager* G4VisManager::fpInstance = 0;
G4VisManager::Verbosity G4VisManager::fVerbosity = G4VisManager::warnings;
G4VisManager::G4VisManager (const G4String& verbosityString):
fVerbose (1),
fInitialised (false),
fpGraphicsSystem (0),
fpScene (0),
fpSceneHandler (0),
fpViewer (0),
fpStateDependent (0),
fEventRefreshing (false),
fTransientsDrawnThisRun (false),
fTransientsDrawnThisEvent (false),
fNoOfEventsDrawnThisRun (0),
fNKeepRequests (0),
fEventKeepingSuspended (false),
fDrawEventOnlyIfToBeKept (false),
fpRequestedEvent (0),
fReviewingKeptEvents (false),
fAbortReviewKeptEvents (false),
fIsDrawGroup (false),
fDrawGroupNestingDepth (0),
fIgnoreStateChanges (false)
G4VisManager::G4VisManager (const G4String& verbosityString)
: fVerbose (1)
, fInitialised (false)
, fpGraphicsSystem (0)
, fpScene (0)
, fpSceneHandler (0)
, fpViewer (0)
, fpStateDependent (0)
, fEventRefreshing (false)
, fTransientsDrawnThisRun (false)
, fTransientsDrawnThisEvent (false)
, fNoOfEventsDrawnThisRun (0)
, fNKeepRequests (0)
, fEventKeepingSuspended (false)
, fDrawEventOnlyIfToBeKept (false)
, fpRequestedEvent (0)
, fReviewingKeptEvents (false)
, fAbortReviewKeptEvents (false)
, fReviewingPlots (false)
, fAbortReviewPlots (false)
, fIsDrawGroup (false)
, fDrawGroupNestingDepth (0)
, fIgnoreStateChanges (false)
#ifdef G4MULTITHREADED
, fMaxEventQueueSize (100)
, fWaitOnEventQueueFull (true)
#endif
// All other objects use default constructors.
// All other objects use default constructors.
{
fpTrajDrawModelMgr = new G4VisModelManager<G4VTrajectoryModel>("/vis/modeling/trajectories");
fpTrajFilterMgr = new G4VisFilterManager<G4VTrajectory>("/vis/filtering/trajectories");
@@ -189,8 +191,9 @@ G4VisManager::G4VisManager (const G4String& verbosityString):
// ...
// Make top level command directory...
// Vis commands should *not* be broadcast to threads (2nd argument).
auto directory = new G4UIdirectory ("/vis/",false);
// vis commands should *not* be broadcast to workers
G4bool propagateToWorkers;
auto directory = new G4UIdirectory ("/vis/",propagateToWorkers=false);
directory -> SetGuidance ("Visualization commands.");
// Request commands in name order
directory -> Sort(); // Ordering propagates to sub-directories
@@ -600,6 +603,7 @@ void G4VisManager::RegisterMessengers () {
RegisterMessenger(new G4VisCommandViewerRebuild);
RegisterMessenger(new G4VisCommandViewerRefresh);
RegisterMessenger(new G4VisCommandViewerReset);
RegisterMessenger(new G4VisCommandViewerResetCameraParameters);
RegisterMessenger(new G4VisCommandViewerSave);
RegisterMessenger(new G4VisCommandViewerScale);
RegisterMessenger(new G4VisCommandViewerSelect);
@@ -623,6 +627,7 @@ void G4VisManager::RegisterMessengers () {
// (i.e., commands that invoke other commands) are instantiated here.
RegisterMessenger(new G4VisCommandAbortReviewKeptEvents);
RegisterMessenger(new G4VisCommandAbortReviewPlots);
RegisterMessenger(new G4VisCommandDrawOnlyToBeKeptEvents);
RegisterMessenger(new G4VisCommandDrawTree);
RegisterMessenger(new G4VisCommandDrawView);
@@ -631,7 +636,9 @@ void G4VisManager::RegisterMessengers () {
RegisterMessenger(new G4VisCommandEnable);
RegisterMessenger(new G4VisCommandList);
RegisterMessenger(new G4VisCommandOpen);
RegisterMessenger(new G4VisCommandPlot);
RegisterMessenger(new G4VisCommandReviewKeptEvents);
RegisterMessenger(new G4VisCommandReviewPlots);
RegisterMessenger(new G4VisCommandSpecify);
// List manager commands
@@ -659,6 +666,60 @@ void G4VisManager::RegisterMessengers () {
(fpDigiFilterMgr, fpDigiFilterMgr->Placement()));
}
#include <tools/histo/h1d>
#include <tools/histo/h2d>
namespace {
template <typename HT> // tools::histo::h1d, etc
G4bool PrintListOfHnPlots(const G4String& plotType) { // h1, etc.
auto ui = G4UImanager::GetUIpointer();
G4bool thereArePlots = false;
auto keepControlVerbose = ui->GetVerboseLevel();
ui->SetVerboseLevel(0);
auto status = ui->ApplyCommand("/analysis/" + plotType + "/getVector");
ui->SetVerboseLevel(keepControlVerbose);
if(status==G4UIcommandStatus::fCommandSucceeded) {
G4String hexString = ui->GetCurrentValues(G4String("/analysis/" + plotType + "/getVector"));
if(hexString.size()) {
void* ptr;
std::istringstream is(hexString);
is >> ptr;
auto _v = (const std::vector<HT*>*)ptr;
auto _n = _v->size();
if (_n > 0) {
thereArePlots = true;
G4String isare("are"),plural("s");
if (_n == 1) {isare = "is"; plural = "";}
G4cout <<
"There " << isare << ' ' << _n << ' ' << plotType << " histogram" << plural
<< G4endl;
if (_n <= 5) {
for (size_t i = 0; i < _n; ++i) {
const auto& _h = (*_v)[i];
G4cout
<< std::setw(3) << i
<< " with " << std::setw(6) << _h->entries() << " entries: "
<< _h->get_title() << G4endl;
}
}
}
}
}
return thereArePlots;
}
void PrintListOfPlots() {
G4bool thereArePlots = false;
if (PrintListOfHnPlots<tools::histo::h1d>("h1")) thereArePlots = true;
if (PrintListOfHnPlots<tools::histo::h2d>("h2")) thereArePlots = true;
if (thereArePlots) {
G4cout <<
"List them with \"/analysis/list\"."
"\nView them with \"/vis/plot\" or \"/vis/reviewPlots\"."
<< G4endl;
}
}
}
void G4VisManager::Enable() {
if (IsValidView ()) {
SetConcreteInstance(this);
@@ -669,11 +730,18 @@ void G4VisManager::Enable() {
G4int nKeptEvents = 0;
const G4Run* run = G4RunManager::GetRunManager()->GetCurrentRun();
if (run) nKeptEvents = run->GetEventVector()->size();
G4String isare("are"),plural("s");
if (nKeptEvents == 1) {isare = "is"; plural = "";}
G4cout <<
"There are " << nKeptEvents << " kept events."
"\n \"/vis/reviewKeptEvents\" to review them one by one."
"\n \"/vis/viewer/flush\" or \"/vis/viewer/rebuild\" to see them accumulated."
"There " << isare << ' ' << nKeptEvents << " kept event" << plural << '.'
<< G4endl;
if (nKeptEvents > 0) {
G4cout <<
" \"/vis/reviewKeptEvents\" to review one by one."
"\n To see accumulated, \"/vis/enable\", then \"/vis/viewer/flush\" or \"/vis/viewer/rebuild\"."
<< G4endl;
}
PrintListOfPlots();
}
}
else {
@@ -1293,14 +1361,26 @@ void G4VisManager::GeometryHasChanged () {
if (modelList.size () == 0) {
if (fVerbosity >= warnings) {
G4cout << "WARNING: No models left in this scene \""
G4cout << "WARNING: No run-duration models left in this scene \""
<< pScene -> GetName ()
<< "\"."
<< G4endl;
}
if (pWorld) {
if (fVerbosity >= warnings) {
G4cout << " Adding current world to \""
<< pScene -> GetName ()
<< "\"."
<< G4endl;
}
pScene->AddRunDurationModel(new G4PhysicalVolumeModel(pWorld),fVerbosity>=warnings);
// (The above includes a re-calculation of the extent.)
G4UImanager::GetUIpointer () ->
ApplyCommand (G4String("/vis/scene/notifyHandlers " + pScene->GetName()));
}
}
else {
pScene->CalculateExtent();
pScene->CalculateExtent(); // Recalculate extent
G4UImanager::GetUIpointer () ->
ApplyCommand (G4String("/vis/scene/notifyHandlers " + pScene->GetName()));
}
@@ -1620,31 +1700,32 @@ void G4VisManager::SetCurrentViewer (G4VViewer* pViewer) {
}
}
void G4VisManager::PrintAvailableGraphicsSystems (Verbosity verbosity) const
void G4VisManager::PrintAvailableGraphicsSystems
(Verbosity verbosity, std::ostream& out) const
{
G4cout << "Registered graphics systems are:\n";
out << "Registered graphics systems are:\n";
if (fAvailableGraphicsSystems.size ()) {
for (const auto& gs: fAvailableGraphicsSystems) {
const G4String& name = gs->GetName();
const std::vector<G4String>& nicknames = gs->GetNicknames();
if (verbosity <= warnings) {
// Brief output
G4cout << " " << name << " (";
out << " " << name << " (";
for (size_t i = 0; i < nicknames.size(); ++i) {
if (i != 0) {
G4cout << ", ";
out << ", ";
}
G4cout << nicknames[i];
out << nicknames[i];
}
G4cout << ')';
out << ')';
} else {
// Full output
G4cout << *gs;
out << *gs;
}
G4cout << G4endl;
out << G4endl;
}
} else {
G4cout << " NONE!!! None registered - yet! Mmmmm!" << G4endl;
out << " NONE!!! None registered - yet! Mmmmm!" << G4endl;
}
}
@@ -1984,12 +2065,6 @@ void G4VisManager::EndOfEvent ()
if (!GetConcreteInstance()) return;
// Don't call IsValidView unless there is a scene handler. This
// avoids WARNING message at end of event and run when the user has
// not instantiated a scene handler, e.g., in batch mode.
G4bool valid = fpSceneHandler && IsValidView();
if (!valid) return;
// G4cout << "G4VisManager::EndOfEvent: thread: "
// << G4Threading::G4GetThreadId() << G4endl;
@@ -1999,6 +2074,12 @@ void G4VisManager::EndOfEvent ()
// std::this_thread::sleep_for(std::chrono::seconds(5));
#endif
// Don't call IsValidView unless there is a scene handler. This
// avoids WARNING message at end of event and run when the user has
// not instantiated a scene handler, e.g., in batch mode.
G4bool valid = fpSceneHandler && IsValidView();
if (!valid) return;
G4RunManager* runManager = G4RunManagerFactory::GetMasterRunManager();
const G4Run* currentRun = runManager->GetCurrentRun();
@@ -2163,10 +2244,14 @@ void G4VisManager::EndOfEvent ()
if (fVerbosity >= warnings) {
G4cout <<
"WARNING: G4VisManager::EndOfEvent: Automatic event keeping suspended."
"\n The number of events exceeds the maximum, "
<< maxNumberOfKeptEvents <<
", that may be kept by\n the vis manager."
<< G4endl;
if (maxNumberOfKeptEvents > 0) {
G4cout <<
"\n The number of events exceeds the maximum, "
<< maxNumberOfKeptEvents <<
", that may be kept by\n the vis manager."
<< G4endl;
}
}
warned = true;
}
@@ -2181,7 +2266,6 @@ void G4VisManager::EndOfEvent ()
eventManager->KeepTheCurrentEvent();
fNKeepRequests++;
}
}
}
}
@@ -2243,7 +2327,7 @@ void G4VisManager::EndOfRun ()
G4int nKeptEvents = 0;
const std::vector<const G4Event*>* events = currentRun->GetEventVector();
if (events) nKeptEvents = events->size();
if (fVerbosity >= warnings) {
if (fVerbosity >= warnings && nKeptEvents > 0) {
G4cout << nKeptEvents;
if (nKeptEvents == 1) G4cout << " event has";
else G4cout << " events have";
@@ -2268,38 +2352,27 @@ void G4VisManager::EndOfRun ()
G4cout << G4endl;
}
G4cout <<
" \"/vis/reviewKeptEvents\" to review them one by one."
"\n \"/vis/enable\", then \"/vis/viewer/flush\" or \"/vis/viewer/rebuild\" to see them accumulated."
" \"/vis/reviewKeptEvents\" to review one by one."
"\n To see accumulated, \"/vis/enable\", then \"/vis/viewer/flush\" or \"/vis/viewer/rebuild\"."
<< G4endl;
}
// static G4bool warned = false;
// if (!valid && fVerbosity >= warnings && !warned) {
// G4cout <<
// " Only useful if before starting the run:"
// "\n a) trajectories are stored (\"/vis/scene/add/trajectories [smooth|rich]\"), or"
// "\n b) the Draw method of any hits or digis is implemented."
// "\n To view trajectories, hits or digis:"
// "\n open a viewer, draw a volume, \"/vis/scene/add/trajectories\""
// "\n \"/vis/scene/add/hits\" or \"/vis/scene/add/digitisations\""
// "\n and, possibly, \"/vis/viewer/flush\"."
// "\n To see all events: \"/vis/scene/endOfEventAction accumulate\"."
// "\n (You may need \"/vis/viewer/flush\" or even \"/vis/viewer/rebuild\".)"
// "\n To see events individually: \"/vis/reviewKeptEvents\"."
// << G4endl;
// warned = true;
// }
if (fVerbosity >= warnings) PrintListOfPlots();
if (fEventKeepingSuspended && fVerbosity >= warnings) {
G4cout <<
"WARNING: G4VisManager::EndOfRun: Automatic event keeping was suspended."
"\n The number of events in the run exceeded the maximum, "
<< fpScene->GetMaxNumberOfKeptEvents() <<
", that may be\n kept by the vis manager." <<
"\n The number of events kept by the vis manager can be changed with"
"\n \"/vis/scene/endOfEventAction accumulate <N>\", where N is the"
"\n maximum number you wish to allow. N < 0 means \"unlimited\"."
<< G4endl;
if (fpScene->GetMaxNumberOfKeptEvents() > 0) {
G4cout <<
"\n The number of events in the run exceeded the maximum, "
<< fpScene->GetMaxNumberOfKeptEvents() <<
", that may be\n kept by the vis manager." <<
"\n The number of events kept by the vis manager can be changed with"
"\n \"/vis/scene/endOfEventAction accumulate <N>\", where N is the"
"\n maximum number you wish to allow. N < 0 means \"unlimited\"."
<< G4endl;
}
}
// Don't call IsValidView unless there is a scene handler. This