Import Geant4 11.2.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2023-06-30 09:09:57 +02:00
parent aef78ca386
commit dd1f179cda
3780 changed files with 212808 additions and 142780 deletions
@@ -1,51 +0,0 @@
# -------------------------------------------------------------
# GNUmakefile for visualization library. John Allison, 5/7/95.
name := G4vis_management
ifndef G4INSTALL
G4INSTALL = ../../..
endif
# For debug mode
# CPPFLAGS += -DG4DEBUG_VIS_MANAGEMENT
GLOBLIBS = libG4modeling.lib libG4tools.lib
GLOBLIBS += libG4run.lib libG4event.lib
GLOBLIBS += libG4tracking.lib libG4processes.lib libG4digits_hits.lib
GLOBLIBS += libG4track.lib libG4particles.lib libG4geometry.lib
GLOBLIBS += libG4materials.lib libG4graphics_reps.lib
GLOBLIBS += libG4intercoms.lib libG4global.lib
include $(G4INSTALL)/config/architecture.gmk
include $(G4INSTALL)/config/G4VIS_BUILD.gmk
CPPFLAGS += -I$(G4BASE)/visualization/management/include
CPPFLAGS += -I$(G4BASE)/visualization/modeling/include
CPPFLAGS += -I$(G4BASE)/externals/g4tools/include
CPPFLAGS += -I$(G4BASE)/graphics_reps/include
CPPFLAGS += -I$(G4BASE)/global/management/include
CPPFLAGS += -I$(G4BASE)/global/HEPGeometry/include
CPPFLAGS += -I$(G4BASE)/global/HEPRandom/include
CPPFLAGS += -I$(G4BASE)/global/HEPNumerics/include
CPPFLAGS += -I$(G4BASE)/geometry/solids/CSG/include
CPPFLAGS += -I$(G4BASE)/geometry/solids/specific/include
CPPFLAGS += -I$(G4BASE)/geometry/solids/Boolean/include
CPPFLAGS += -I$(G4BASE)/geometry/management/include
CPPFLAGS += -I$(G4BASE)/geometry/volumes/include
CPPFLAGS += -I$(G4BASE)/geometry/navigation/include
CPPFLAGS += -I$(G4BASE)/geometry/magneticfield/include
CPPFLAGS += -I$(G4BASE)/intercoms/include
CPPFLAGS += -I$(G4BASE)/tracking/include
CPPFLAGS += -I$(G4BASE)/digits_hits/hits/include
CPPFLAGS += -I$(G4BASE)/particles/management/include
CPPFLAGS += -I$(G4BASE)/materials/include
CPPFLAGS += -I$(G4BASE)/run/include
CPPFLAGS += -I$(G4BASE)/tasking/include
CPPFLAGS += -I$(G4BASE)/event/include
CPPFLAGS += -I$(G4BASE)/track/include
CPPFLAGS += -I$(G4BASE)/processes/management/include
CPPFLAGS += -I$(G4BASE)/digits_hits/utils/include
CPPFLAGS += -I$(G4BASE)/digits_hits/digits/include
include $(G4INSTALL)/config/common.gmk
+188
View File
@@ -6,6 +6,194 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2023-06-16 John Allison (visman-V11-01-15)
- G4VisExecutive.icc:
- Temporary fix to divert OGL to TSG for Qt6.
## 2023-06-06 John Allison (visman-V11-01-14)
- G4VisCommandsTouchable; Introduce /vis/touchable/twinkle.
## 2023-06-01 John Allison (visman-V11-01-13)
- Rework issue of implicit type conversion.
- Improve layout in G4VViewer::SceneTreeScene::FindOrInsertModel.
- (No code changes.)
## 2023-05-29 Guy Barrand (visman-v11-01-12)
- G4VisExecutive.icc: declare TOOLSSG_[X11,XT,WINDOWS,QT]_ZB drivers.
## 2023-05-23 Gabriele Cosmo (visman-V11-01-11)
- Fixed compilation warning for implicit type conversion on macOS/XCode>=14.1.
## 2023-05-09 John Allison (visman-V11-01-10)
- Coworks: greps-V11-01-04 and interfaces-V11-01-15.
- New scene tree: Implement expand and collapse of touchables.
- Expand only to depth 2 - thereafter sub-trees are collapsed.
- When the scene tree is expanded or collapsed it is remembered in
the viewer-side scene tree and may be propagated to other viewers.
- G4VViewer.hh/cc:
- Augment SceneTreeScene::FindOrInsertTouchable to handle depth of descent.
## 2023-05-02 John Allison (visman-V11-01-09)
- Coworks: modeling-V11-01-04.
- These two tags implement "generic cutaways"...finally...after 20 years!!!
- It relies on the Boolean Processor (graphics_reps/src/BooleanProcessor.src),
which handles the Boolean operations on polyhedral (G4Polyhedron)
representations of solids. It is well known that this has its
limitations, and the mistake, in the past, has been to ask too much of it.
The most demanding task is cutaways, which attempts to mimic the effect
of OpenGL clipping planes by using Boolean intersections and/or
subtraction of a "cutaway solid". This cutaway solid can itself be the
Boolean combination of up to 3 simple solids (boxes) to deal with up to
3 "cutaway planes". It then goes forward in the G4PhysicalVolumeModel to a
further Boolean operation on the volumes (touchables) of the detector
geometry, which themselves might also be Boolean solids.
- The most demanding case is the union of the result of 3 cutaway planes.
The key breakthrough in this tag is to make a subtractor of the
intersection of the *inverted* cutaways instead of an intersector of the
union of normal cutaways. ("Inverted cutaway" means
cutting away a*x+b*y+c*z+d>0, "normal" means a*x+b*y+c*z+d<0.) Although
logically equivalent, the former is much less demanding because the
shape of an intersection is invariably much simpler that the shape of
a union - at least that's how it seems to be for the case of 3 boxes.
- This work was triggered by an initial attempt by a Geant4 user,
Pooria Heidary. Demanding tests showed that there needed to be careful
checking of the validity of the results of the Boolean operations -
Evgueni Tcherniaev has made a big contribution there. Pooria will
hardly recognise the code compared to that submitted in the GitHub pull
request after these tests and other checks have been added. Hopefully
this update is now well tested and robust.
- It means that clips, sections and cutaways will now be available to *all*
viewers.
- G4VSceneHandler.cc:
- RequestPrimitives: Improve test for invalid Boolean solid.
- Algorithm by Evgueni Tcherniaev.
- CreateSectionSolid and CreateCutawaySolid: Improve algorithms.
- Algorithms suggested by Evgueni Tcherniaev.
## 2023-04-30 John Allison (visman-V11-01-08)
- G4VSceneHandler:
- Bug fix: Protect material pointer used to name G4Mesh item.
- If null, use name of container.
- In particular, avoids crash for a G4Mesh is a parallel world.
## 2023-04-28 John Allison (visman-V11-01-07)
- G4VViewer::SceneTreeScene::FindOrInsertTouchable:
- Coverity fix - protect pPVModel pointer.
## 2023-04-25 John Allison (visman-V11-01-06)
- G4VisCommandsTouchableSet.cc:
- /vis/touchable/set/visibility:
- Add one-time warning about circumstances in which the command may
appear not to work.
## 2023-04-23 John Allison (visman-V11-01-05)
- Correct Special Mesh Rendering Option default.
- G4ViewParameters.cc:
- Initialise fSpecialMeshRenderingOption(meshAsDefault).
- G4VisCommandsViewerSet.cc:
- /vis/viewer/set/specialMeshRenderingOption:
- SetDefaultValue("default");
## 2023-04-14 John Allison (visman-V11-01-04)
- Co-working: greps-V11-01-03, interfaces-V11-01-11, opengl-V11-01-06,
openinventor-V11-01-04, vis_toolssg-V11-01-05.
- New Scene Tree Phase 2 - first implementation of a no-frills GUI-side
interactive scene tree.
- Works with touchables - a touchable is a physical volume as rolled out
by the geometry hierarchy.
- You can change the visibility of a touchable.
- Colour, transparency, etc., will be implemented in a future MR.
- Providing you are using a scene-tree-enabled interactive session (only
the Qt GUI at present), it works with any graphics driver...except OpenGL.
- OpenGL for the time being uses its existing interactive scene tree.
- You can prepare a view with a graphical driver, such as
TSG, OI or Vtk, and transfer it to Ray Tracer, TOOLSSG_OFFSCREEN, etc.,
simply with `/vis/open RayTracer`, etc.
- G4VVisCommand:
- Add static G4SceneTreeItem fExistingSceneTree.
- Used for "remembering" scene tree of previous viewer.
- G4VisCommandsSceneHandler:
- If there is an existing viewer, store scene tree.
- G4VisCommandsViewer:
- If there is an existing viewer, store scene tree.
- Copy existing scene tree to the new viewer.
- /vis/viewer/select: Call UpdateGUISceneTree to ensure the scene tree
of the newly selected viewer is in sync.
- G4VViewer:
- Improve G4VViewer::SceneTreeScene::FindOrInsertTouchable.
- Simplify ghost-touchable transition.
- Protect vis attributes pointer.
- Add "utility" function UpdateGUISceneTree.
- Calls GUI->UpdateSceneTree if session is interactive:
```
void G4VViewer::UpdateGUISceneTree()
{
G4UImanager* UI = G4UImanager::GetUIpointer();
auto uiWindow = dynamic_cast<G4VInteractiveSession*>(UI->GetG4UIWindow());
if (uiWindow) uiWindow->UpdateSceneTree(fSceneTree);
}
```
- sources.cmake:
- Add G4interfaces to geant4_module_link_libraries.
## 2023-04-07 Stewart Boogert (visman-v11-01-03)
- Default special mesh rendering for viewers which can render all objects
## 2023-04-07 John Allison (visman-V11-01-02)
- Co-works with: greps-V11-01-02.
- Improve vis-side scene tree creation and maintenance.
- G4VViewer::SceneTreeScene:
- Simplify - remove unnecessary overrides.
- Fix bugs in scene tree building and add some features.
- Add "tags" that will become the identifier in the GUI tree.
- G4VSceneHandler::ProcessScene:
- Simplify scene tree processing.
- G4VVisCommand::RefreshIfRequired:
- Call viewer->UpdateGUISceneTree() after refreshing.
- This ensures the GUI-side scene tree and vis-side scene tree
are in sync.
## 2023-03-28 John Allison (visman-V11-01-01)
- Co-works with: greps-V11-01-01, interfaces-V11-01-10, modeling-V11-01-02.
- Introduce scene tree in G4VViewer.
- The scene tree is a tree of G4SceneTreeItem objects (see graphics-reps).
- Its root is a data member fSceneTree of all viewers by virtue of
G4VViewer inheritance,
- G4SceneTreeItem is an aggregate of data members that represent
properties of objects in the scene (G4Scene). Its data members are
low-level types - G4String, G4VisAttributes and G4AttDef/Value - so
that it can be used across categories, avoiding coupling.
- The root item has children that represent the models (G4VModel
sub-classes) in the scene.
- For a G4PhysicalVolumeModel (detector components), its children and
children's children, etc., imitate the geometry hierarchy of that
model. These descendants are called "touchables".
- There may be more than one G4PhysicalVolumeModel, depending how
the user creates his/her scene.
- The scene tree is reviewed, and updated if necessary, at every pass
of G4VSceneHandler::ProcessScene. This is called a "kernel visit".
- A kernel visit is triggered by some vis commands (e.g.,
/vis/viewer/rebuild) and by a viewer if it deems necessary. For
example, a kernel visit may not be required for a rotation, zoom, etc.,
but required for a change from surface to wireframe.
- The idea is that the scene tree can be passed to a GUI, the GUI can
create a tree widget, and interactions with it raise UI commands such as
/vis/scene/activateModel, /vis/set/touchable and /vis/touchable/set/...
The viewer decides if this requires a kernel visit, otherwise it
must update fSceneTree itself (utilities are provided -
G4VViewer::TouchableSetVisibility/Colour).
- G4VViewer:
- Add scene tree and related functionality.
- G4VSceneHandler::ProcessScene:
- Add code to build scene tree.
## 2022-12-31 John Allison (visman-V11-01-00)
- Clean up G4VUserVisAction:
- The central pure virtual Draw() method is not intended to be called
directly - see longer explanation in G4VUserVisAction.hh - so make
it protected (more hygienic).
- Improve comments in G4VUserVisAction.hh.
## 2022-11-25 Gabriele Cosmo (visman-V11-00-31)
- Fixed compilation warning for implicit type conversions on macOS/XCode 14.1.
@@ -354,11 +354,11 @@ protected:
public:
PseudoSceneFor3DRectMeshPositions
(G4PhysicalVolumeModel* pvModel // input
, G4int depth // input...the following are outputs by reference
, const G4Mesh* pMesh // input...the following are outputs by reference
, std::multimap<const G4Material*,const G4ThreeVector>& positionByMaterial
, std::map<const G4Material*,NameAndVisAtts>& nameAndVisAttsByMaterial)
: fpPVModel(pvModel)
, fDepth(depth)
, fpMesh(pMesh)
, fPositionByMaterial(positionByMaterial)
, fNameAndVisAttsByMaterial(nameAndVisAttsByMaterial)
{}
@@ -369,7 +369,7 @@ protected:
// Do nothing if uninteresting solids found, e.g., the container if not marked invisible.
}
G4PhysicalVolumeModel* fpPVModel;
G4int fDepth;
const G4Mesh* fpMesh;
std::multimap<const G4Material*,const G4ThreeVector>& fPositionByMaterial;
std::map<const G4Material*,NameAndVisAtts>& fNameAndVisAttsByMaterial;
};
@@ -378,11 +378,11 @@ protected:
public:
PseudoSceneForTetVertices
(G4PhysicalVolumeModel* pvModel // input
, G4int depth // input...the following are outputs by reference
, const G4Mesh* pMesh // input...the following are outputs by reference
, std::multimap<const G4Material*,std::vector<G4ThreeVector>>& verticesByMaterial
, std::map<const G4Material*,NameAndVisAtts>& nameAndVisAttsByMaterial)
: fpPVModel(pvModel)
, fDepth(depth)
, fpMesh(pMesh)
, fVerticesByMaterial(verticesByMaterial)
, fNameAndVisAttsByMaterial(nameAndVisAttsByMaterial)
{}
@@ -393,7 +393,7 @@ protected:
// Do nothing if uninteresting solids found, e.g., the container if not marked invisible.
}
G4PhysicalVolumeModel* fpPVModel;
G4int fDepth;
const G4Mesh* fpMesh;
std::multimap<const G4Material*,std::vector<G4ThreeVector>>& fVerticesByMaterial;
std::map<const G4Material*,NameAndVisAtts>& fNameAndVisAttsByMaterial;
};
@@ -24,45 +24,50 @@
// ********************************************************************
//
//
//
//
// Class Description:
//
// G4VUserVisAction is added to the scene by the command
// /vis/scene/add/userAction, which instantiates a G4CallbackModel to
// add to the RunDurationModels. Thus the pure virtual Draw() method
// G4VUserVisAction is brought into effect by the command
// /vis/scene/add/userAction. The vis manager instantiates a
// G4CallbackModel when the vis action is registered, and adds
// it to the scene. The pure virtual Draw() method
// is invoked whenever the viewer needs to "visit the kernel", e.g.,
// to remake its graphical database, if any, or simply to refresh the
// screen. operator() is defined to satisfy the template
// screen. It is not intended to be called directly. It is called
// via the operator() which is defined to satisfy the template
// G4CallbackModel<G4VUserVisAction>.
//
// See the User Guide for Application Developers, Section 8.8.7 and 8.8.8.
// A concrete Draw() method would normally make use of the Draw() methods
// of the vis manager, e.g:
// G4VVisManager* pVisManager = G4VVisManager::GetConcreteInstance();
// if (pVisManager) {
// pVisManager->Draw(G4Box("box",2*cm,2*cm,2*cm),
// G4VisAttributes(G4Colour(1,1,0)));
// ...
// but it can also use pointers fpSceneHandler and pMP that give it
// direct access to the current scene handler and modeling parameters
// for more advanced use.
//
// See the User Guide for Application Developers.
#ifndef G4VUSERVISACTION_HH
#define G4VUSERVISACTION_HH
#include "G4Transform3D.hh"
class G4VGraphicsScene;
class G4ModelingParameters;
class G4VUserVisAction
{
public: // With description
G4VUserVisAction()
: fpSceneHandler(nullptr)
, fpMP(nullptr)
{}
G4VUserVisAction(): fpSceneHandler(nullptr), fpMP(nullptr) {}
virtual ~G4VUserVisAction() {}
virtual void Draw() = 0;
void operator()(G4VGraphicsScene& scene, const G4ModelingParameters* pMP) {
fpSceneHandler = &scene;
fpMP = pMP;
Draw();
}
protected:
virtual void Draw() = 0;
G4VGraphicsScene* fpSceneHandler;
const G4ModelingParameters* fpMP;
};
@@ -37,8 +37,14 @@
#include "globals.hh"
#include "G4SceneTreeItem.hh"
#include "G4ViewParameters.hh"
#include "G4PhysicalVolumeModel.hh"
#include "G4PseudoScene.hh"
#include <vector>
#include <list>
class G4VSceneHandler;
@@ -131,6 +137,57 @@ public: // With description
virtual void SwitchToMasterThread ();
#endif
//////////////////////////////////////////////////////////////
// Stuff for scene tree.
/**
- The scene tree is a tree of G4SceneTreeItem objects (see graphics-reps).
- Its root is a data member fSceneTree of all viewers by virtue of
G4VViewer inheritance,
- G4SceneTreeItem is an aggregate of data members that represent
properties of objects in the scene (G4Scene). Its data members are
low-level types - G4String, G4VisAttributes and G4AttDef/Value - so
that it can be used across categories, avoiding coupling.
- The root item has children that represent the models (G4VModel
sub-classes) in the scene.
- For a G4PhysicalVolumeModel (detector components), its children and
children's children, etc., imitate the geometry hierarchy of that
model. These descendants are called "touchables".
- There may be more than one G4PhysicalVolumeModel, depending how
the user creates his/her scene.
- The scene tree is reviewed, and updated if necessary, at every pass
of G4VSceneHandler::ProcessScene. This is called a "kernel visit".
- A kernel visit is triggered by some vis commands (e.g.,
/vis/viewer/rebuild) and by a viewer if it deems necessary. For
example, a kernel visit may not be required for a rotation, zoom, etc.,
but required for a change from surface to wireframe.
- The idea is that the scene tree can be passed to a GUI, the GUI can
create a tree widget, and interactions with it raise UI commands such as
/vis/scene/activateModel, /vis/set/touchable and /vis/touchable/set/...
The viewer decides if this requires a kernel visit, otherwise it
must update fSceneTree itself (utilities are provided -
G4VViewer::TouchableSetVisibility/Colour).
*/
class SceneTreeScene: public G4PseudoScene {
// G4PhysicalVolumeModel sends touchables to this scene
public:
SceneTreeScene() = default;
~SceneTreeScene() = default;
void SetViewer(G4VViewer* pViewer) {fpViewer = pViewer;}
void SetModel(G4VModel* pModel);
private:
void ProcessVolume(const G4VSolid& solid) override;
std::list<G4SceneTreeItem>::iterator FindOrInsertModel
(const G4String& modelType,const G4String& modelID);
std::list<G4SceneTreeItem>::iterator FindOrInsertTouchable
(const G4String& modelID, G4SceneTreeItem& mother,
G4int depth, const G4String& partialPathString, const G4String& fullPathString);
G4VViewer* fpViewer = nullptr;
G4VModel* fpModel = nullptr;
};
SceneTreeScene& AccessSceneTreeScene() {return fSceneTreeScene;}
G4SceneTreeItem& AccessSceneTree() {return fSceneTree;}
void UpdateGUISceneTree(); // A utility
//////////////////////////////////////////////////////////////
// Access functions.
const G4String& GetName () const;
@@ -221,6 +278,8 @@ protected:
G4ViewParameters fDefaultVP; // Default view parameters.
G4double fKernelVisitElapsedTimeSeconds = 999.; // Default to a large number
// Note: fKernelVisitElapsedTimeSeconds is measured in ProcessView().
SceneTreeScene fSceneTreeScene; // G4PhysicalVolumeModel sends touchables to this scene
G4SceneTreeItem fSceneTree;
//////////////////////////////////////////////////////////////
// Other parameters.
@@ -39,6 +39,8 @@
#include "G4VMarker.hh"
#include "G4ModelingParameters.hh"
#include "G4PhysicalVolumesSearchScene.hh"
#include "G4SceneTreeItem.hh"
#include <vector>
class G4UIcommand;
@@ -165,6 +167,7 @@ protected:
// handler.
static G4bool fThereWasAViewer; // True if there was a viewer
static G4ViewParameters fExistingVP; // Its view parameters
static G4SceneTreeItem fExistingSceneTree; // Its scene tree
};
#endif
@@ -101,7 +101,7 @@ public: // With description
enum CutawayMode {
cutawayUnion, // Union (addition) of result of each cutaway plane.
cutawayIntersection // Intersection (multiplication) " .
cutawayIntersection // Intersection (multiplication).
};
enum RotationStyle {
@@ -110,6 +110,7 @@ public: // With description
};
enum SMROption { // Special Mesh Rendering Option
meshAsDefault,
meshAsDots,
meshAsSurfaces
};
@@ -53,6 +53,7 @@ private:
G4UIcommand* fpCommandFindPath;
G4UIcmdWithoutParameter* fpCommandLocalAxes;
G4UIcmdWithABool* fpCommandShowExtent;
G4UIcmdWithoutParameter* fpCommandTwinkle;
G4UIcmdWithABool* fpCommandVolumeForField;
};
@@ -93,18 +93,34 @@
#include "G4ToolsSGX11GLES.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_X11_ZB
#include "G4ToolsSGX11ZB.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_WINDOWS_GLES
#include "G4ToolsSGWindowsGLES.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_WINDOWS_ZB
#include "G4ToolsSGWindowsZB.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_XT_GLES
#include "G4ToolsSGXtGLES.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_XT_ZB
#include "G4ToolsSGXtZB.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_QT_GLES
#include "G4ToolsSGQtGLES.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_TOOLSSG_QT_ZB
#include "G4ToolsSGQtZB.hh" // no_geant4_module_check
#endif
#ifdef G4VIS_USE_VTK
#include "G4Vtk.hh" // no_geant4_module_check
#endif
@@ -113,6 +129,10 @@
#include "G4VtkQt.hh" // no_geant4_module_check
#endif
#if defined (G4VIS_USE_OPENGLQT) || (G4VIS_USE_TOOLSSG_QT_GLES)
#include <QtGlobal>
#endif
// The inline keyword prevents the compiler making an external
// reference even though they cannot actually be inlined since they
// are virtual functions. This prevents a "multiple definition" error
@@ -148,6 +168,7 @@ G4VisExecutive::RegisterGraphicsSystems () {
// super-abbreviated names and fallback names where approproiate.
#ifdef G4VIS_USE_OPENGLQT
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
G4VGraphicsSystem* ogliqt = new G4OpenGLImmediateQt;
G4VGraphicsSystem* oglsqt = new G4OpenGLStoredQt;
RegisterGraphicsSystem(ogliqt);
@@ -156,6 +177,7 @@ G4VisExecutive::RegisterGraphicsSystems () {
oglsqt->AddNickname("OGL");
oglsqt->AddNickname("OGLS");
#endif
#endif
#ifdef G4VIS_USE_OPENGLXM
G4VGraphicsSystem* oglixm = new G4OpenGLImmediateXm;
@@ -252,6 +274,12 @@ G4VisExecutive::RegisterGraphicsSystems () {
#endif
#endif
#ifdef G4VIS_USE_TOOLSSG_X11_ZB
G4VGraphicsSystem* tsg_x11_zb = new G4ToolsSGX11ZB;
RegisterGraphicsSystem(tsg_x11_zb);
tsg_x11_zb->AddNickname("TSGX11ZB");
#endif
#ifdef G4VIS_USE_TOOLSSG_XT_GLES
G4VGraphicsSystem* tsg_xt_gles = new G4ToolsSGXtGLES;
RegisterGraphicsSystem(tsg_xt_gles);
@@ -261,19 +289,40 @@ G4VisExecutive::RegisterGraphicsSystems () {
#endif
#endif
#ifdef G4VIS_USE_TOOLSSG_XT_ZB
G4VGraphicsSystem* tsg_xt_zb = new G4ToolsSGXtZB;
RegisterGraphicsSystem(tsg_xt_zb);
tsg_xt_zb->AddNickname("TSGXtZB");
#endif
#ifdef G4VIS_USE_TOOLSSG_QT_GLES
G4VGraphicsSystem* tsg_qt_gles = new G4ToolsSGQtGLES;
RegisterGraphicsSystem(tsg_qt_gles);
tsg_qt_gles->AddNickname("TSGQt");
#endif
#ifdef G4VIS_USE_TOOLSSG_QT_ZB
G4VGraphicsSystem* tsg_qt_zb = new G4ToolsSGQtZB;
RegisterGraphicsSystem(tsg_qt_zb);
tsg_qt_zb->AddNickname("TSGQtZB");
#endif
#ifdef G4VIS_USE_TOOLSSG_WINDOWS_GLES
G4VGraphicsSystem* tsg_windows_gles = new G4ToolsSGWindowsGLES;
RegisterGraphicsSystem(tsg_windows_gles);
#endif
#ifdef G4VIS_USE_TOOLSSG_WINDOWS_ZB
G4VGraphicsSystem* tsg_windows_zb = new G4ToolsSGWindowsZB;
RegisterGraphicsSystem(tsg_windows_zb);
#endif
#ifdef G4VIS_USE_TOOLSSG_QT_GLES
tsg_qt_gles->AddNickname("TSG");
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
G4cout << " Qt6: Asking ToolsSG to stand in for OpenGL" << G4endl;
tsg_qt_gles->AddNickname("OGL");
# endif
#elif defined(G4VIS_USE_TOOLSSG_XT_GLES)
tsg_xt_gles->AddNickname("TSG");
#elif defined(G4VIS_USE_TOOLSSG_X11_GLES)
@@ -96,7 +96,8 @@ geant4_module_link_libraries(G4vis_management
G4run
G4navigation
G4digits
G4heprandom)
G4heprandom
G4UIcore)
if(GEANT4_BUILD_MULTITHREADED)
geant4_module_link_libraries(G4vis_management PRIVATE G4volumes)
@@ -68,6 +68,7 @@
#include "G4DisplacedSolid.hh"
#include "G4UnionSolid.hh"
#include "G4IntersectionSolid.hh"
#include "G4SubtractionSolid.hh"
#include "G4LogicalVolume.hh"
#include "G4PhysicalVolumeModel.hh"
#include "G4ModelingParameters.hh"
@@ -88,6 +89,7 @@
#include "G4Transform3D.hh"
#include "G4AttHolder.hh"
#include "G4AttDef.hh"
#include "G4SceneTreeItem.hh"
#include "G4VVisCommand.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
@@ -526,29 +528,58 @@ void G4VSceneHandler::RequestPrimitives (const G4VSolid& solid)
{
// Sometimes solids that have no substance get requested. They may
// be part of the geometry tree but have been "spirited away", for
// example by a Boolean subtraction in wich the original volume
// is entirely inside the subtractor.
// example by a Boolean subtraction in which the original volume
// is entirely inside the subtractor or an intersection in which
// the original volume is entirely outside the intersector.
// The problem is that the Boolean Processor still returns a
// polyhedron in these cases (IMHO it should not), so the
// workaround is to return before the damage is done.
// Algorithm by Evgueni Tcherniaev
auto pSolid = &solid;
auto pBooleanSolid = dynamic_cast<const G4BooleanSolid*>(pSolid);
if (pBooleanSolid) {
G4ThreeVector bmin, bmax;
pBooleanSolid->BoundingLimits(bmin, bmax);
G4bool isGood = false;
for (G4int i=0; i<100000; ++i) {
G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand();
G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand();
G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand();
if (pBooleanSolid->Inside(G4ThreeVector(x,y,z)) == kInside) {
isGood = true;
break;
if (dynamic_cast<const G4SubtractionSolid*>(pBooleanSolid)) {
auto ptrB = pBooleanSolid->GetConstituentSolid(1);
for (G4int i=0; i<10; ++i) {
G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand();
G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand();
G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand();
if (ptrB->Inside(G4ThreeVector(x,y,bmin.z())) != kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(x,y,bmax.z())) != kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(x,bmin.y(),z)) != kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(x,bmax.y(),z)) != kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(bmin.x(),y,z)) != kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(bmax.x(),y,z)) != kInside) { isGood = true; break; }
}
} else if (dynamic_cast<const G4IntersectionSolid*>(pBooleanSolid)) {
auto ptrB = pBooleanSolid->GetConstituentSolid(1);
for (G4int i=0; i<10; ++i) {
G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand();
G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand();
G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand();
if (ptrB->Inside(G4ThreeVector(x,y,bmin.z())) == kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(x,y,bmax.z())) == kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(x,bmin.y(),z)) == kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(x,bmax.y(),z)) == kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(bmin.x(),y,z)) == kInside) { isGood = true; break; }
if (ptrB->Inside(G4ThreeVector(bmax.x(),y,z)) == kInside) { isGood = true; break; }
}
}
if (!isGood)
{
for (G4int i=0; i<10000; ++i) {
G4double x = bmin.x() + (bmax.x() - bmin.x())*G4QuickRand();
G4double y = bmin.y() + (bmax.y() - bmin.y())*G4QuickRand();
G4double z = bmin.z() + (bmax.z() - bmin.z())*G4QuickRand();
if (pBooleanSolid->Inside(G4ThreeVector(x,y,z)) == kInside) { isGood = true; break; }
}
}
if (!isGood) return;
}
const G4ViewParameters::DrawingStyle style = GetDrawingStyle(fpVisAttribs);
const G4ViewParameters& vp = fpViewer->GetViewParameters();
@@ -684,6 +715,9 @@ void G4VSceneHandler::ProcessScene()
G4cout << "Traversing scene data..." << G4endl;
}
// Reset visibility of all objects to false - visible objects will then set to true
fpViewer->AccessSceneTree().ResetVisibility();
BeginModeling();
// Create modeling parameters from view parameters...
@@ -695,10 +729,24 @@ void G4VSceneHandler::ProcessScene()
{
fpModel = runDurationModelList[i].fpModel;
fpModel->SetModelingParameters(pMP);
fpModel->DescribeYourselfTo(*this);
// To see the extents of each model represented as wireframe boxes,
// uncomment the next line and DrawExtent in namespace above
// DrawExtent(fpModel);
// Describe to the current scene handler
fpModel->DescribeYourselfTo(*this);
// To see the extents of each model represented as wireframe boxes,
// uncomment the next line and DrawExtent in namespace above.
// DrawExtent(fpModel);
// Enter models in the scene tree, and for PV models, describe
// the model to the scene tree, i.e., enter all the touchables.
auto& sceneTreeScene = fpViewer->AccessSceneTreeScene();
sceneTreeScene.SetViewer(fpViewer);
sceneTreeScene.SetModel(fpModel);
if (dynamic_cast<G4PhysicalVolumeModel*>(fpModel)) {
fpModel->DescribeYourselfTo(sceneTreeScene);
}
// Reset modeling parameters pointer
fpModel->SetModelingParameters(0);
}
}
@@ -729,6 +777,8 @@ void G4VSceneHandler::ProcessScene()
if(runManager)
{
const G4Run* run = runManager->GetCurrentRun();
// Draw a null event in order to pick up models for the scene tree even before a run
if (run == nullptr) DrawEvent(0);
const std::vector<const G4Event*>* events =
run ? run->GetEventVector() : 0;
std::size_t nKeptEvents = 0;
@@ -797,9 +847,18 @@ void G4VSceneHandler::DrawEvent(const G4Event* event)
pMP->SetEvent(event);
for (std::size_t i = 0; i < nModels; ++i) {
if (EOEModelList[i].fActive) {
fpModel = EOEModelList[i].fpModel;
fpModel -> SetModelingParameters(pMP);
fpModel -> DescribeYourselfTo (*this);
fpModel = EOEModelList[i].fpModel;
fpModel -> SetModelingParameters(pMP);
// Describe to the current scene handler
fpModel -> DescribeYourselfTo (*this);
// Enter models in the scene tree
auto& sceneTreeScene = fpViewer->AccessSceneTreeScene();
sceneTreeScene.SetViewer(fpViewer);
sceneTreeScene.SetModel(fpModel);
// Reset modeling parameters pointer
fpModel -> SetModelingParameters(0);
}
}
@@ -819,9 +878,18 @@ void G4VSceneHandler::DrawEndOfRunModels()
for (std::size_t i = 0; i < nModels; ++i) {
if (EORModelList[i].fActive) {
fpModel = EORModelList[i].fpModel;
fpModel -> SetModelingParameters(pMP);
fpModel -> SetModelingParameters(pMP);
// Describe to the current scene handler
fpModel -> DescribeYourselfTo (*this);
fpModel -> SetModelingParameters(0);
// Enter models in the scene tree
auto& sceneTreeScene = fpViewer->AccessSceneTreeScene();
sceneTreeScene.SetViewer(fpViewer);
sceneTreeScene.SetModel(fpModel);
// Reset modeling parameters pointer
fpModel -> SetModelingParameters(0);
}
}
fpModel = 0;
@@ -887,6 +955,13 @@ G4ModelingParameters* G4VSceneHandler::CreateModelingParameters ()
pModelingParams->SetExplodeCentre(vp.GetExplodeCentre());
pModelingParams->SetSectionSolid(CreateSectionSolid());
if (vp.GetCutawayMode() == G4ViewParameters::cutawayUnion) {
pModelingParams->SetCutawayMode(G4ModelingParameters::cutawayUnion);
} else if (vp.GetCutawayMode() == G4ViewParameters::cutawayIntersection) {
pModelingParams->SetCutawayMode(G4ModelingParameters::cutawayIntersection);
}
pModelingParams->SetCutawaySolid(CreateCutawaySolid());
// The polyhedron objects are deleted in the modeling parameters destructor.
@@ -909,27 +984,14 @@ G4DisplacedSolid* G4VSceneHandler::CreateSectionSolid()
G4double safe = radius + fpScene->GetExtent().GetExtentCentre().mag();
G4VSolid* sectionBox =
new G4Box("_sectioner", safe, safe, 1.e-5 * radius); // Thin in z-plane...
const G4Normal3D originalNormal(0,0,1); // ...so this is original normal.
const G4Plane3D& sp = vp.GetSectionPlane ();
const G4double& a = sp.a();
const G4double& b = sp.b();
const G4double& c = sp.c();
const G4double& d = sp.d();
const G4Normal3D newNormal(a,b,c);
G4Transform3D requiredTransform;
// Rotate
if (newNormal != originalNormal) {
const G4double& angle = std::acos(newNormal.dot(originalNormal));
const G4Vector3D& axis = originalNormal.cross(newNormal);
requiredTransform = G4Rotate3D(angle, axis);
}
// Translate
requiredTransform = requiredTransform * G4TranslateZ3D(-d);
G4ThreeVector normal = sp.normal();
G4Transform3D requiredTransform = G4Translate3D(normal*(-sp.d())) *
G4Rotate3D(G4ThreeVector(0,0,1), G4ThreeVector(0,1,0), normal, normal.orthogonal());
sectioner = new G4DisplacedSolid
("_displaced_sectioning_box", sectionBox, requiredTransform);
("_displaced_sectioning_box", sectionBox, requiredTransform);
}
return sectioner;
@@ -937,69 +999,82 @@ G4DisplacedSolid* G4VSceneHandler::CreateSectionSolid()
G4DisplacedSolid* G4VSceneHandler::CreateCutawaySolid()
{
const G4ViewParameters& vp = fpViewer->GetViewParameters();
if (vp.IsCutaway()) {
const auto& vp = fpViewer->GetViewParameters();
const auto& nPlanes = vp.GetCutawayPlanes().size();
std::vector<G4DisplacedSolid*> cutaway_solids;
if (nPlanes == 0) return nullptr;
G4double radius = fpScene->GetExtent().GetExtentRadius();
G4double safe = radius + fpScene->GetExtent().GetExtentCentre().mag();
G4VSolid* cutawayBox =
new G4Box("_cutaway_box", safe, safe, safe); // world box...
std::vector<G4DisplacedSolid*> cutaway_solids;
for (int plane_no = 0; plane_no < int(vp.GetCutawayPlanes().size()); plane_no++){
G4double radius = fpScene->GetExtent().GetExtentRadius();
G4double safe = radius + fpScene->GetExtent().GetExtentCentre().mag();
auto cutawayBox = new G4Box("_cutaway_box", safe, safe, safe);
const G4Normal3D originalNormal(0,0,1); // ...so this is original normal.
// if (vp.GetCutawayMode() == G4ViewParameters::cutawayUnion) we need a subtractor that is
// the intersection of displaced cutaway boxes, displaced so that a subtraction keeps the
// positive values a*x+b*y+c*z+d>0, so we have to invert the normal. This may appear
// "back to front". The parameter "cutawayUnion" means "the union of volumes
// that remain *after* cutaway", because we base the concept on OpenGL cutaway planes and make
// a "union" of what remains by superimposing up to 3 passes - see G4OpenGLViewer::SetView
// and G4OpenGLImmediate/StoredViewer::ProcessView. So we have to create a subtractor
// that is the intersection of inverted cutaway planes.
const G4Plane3D& sp = vp.GetCutawayPlanes()[plane_no]; //];
const G4double& a = sp.a();
const G4double& b = sp.b();
const G4double& c = sp.c();
const G4double& d = sp.d();
const G4Normal3D newNormal(-a,-b,-c); // Convention: keep a*x+b*y+c*z+d>=0
// Not easy to see why the above gives the right convention, but it has been
// arrived at by trial and error to agree with the OpenGL implementation
// of clipping planes.
// Conversely, if (vp.GetCutawayMode() == G4ViewParameters::cutawayIntersection) we have to
// create an intersector that is the intersector of intersected non-inverted cutaway planes.
G4Transform3D requiredTransform; // Null transform
// Calculate the rotation
// If newNormal is (0,0,1), no need to do anything
// Treat (0,0,-1) as a special case, since cannot define axis in this case
if (newNormal == G4Normal3D(0,0,-1)) {
requiredTransform = G4Rotate3D(pi,G4Vector3D(1,0,0));
} else if (newNormal != originalNormal) {
const G4double& angle = std::acos(newNormal.dot(originalNormal));
const G4Vector3D& axis = originalNormal.cross(newNormal);
requiredTransform = G4Rotate3D(angle, axis);
}
// Translation
requiredTransform = requiredTransform * G4TranslateZ3D(d + safe);
cutaway_solids.push_back
(new G4DisplacedSolid("_displaced_cutaway_box", cutawayBox, requiredTransform));
}
if (cutaway_solids.size() == 1){
return (G4DisplacedSolid*) cutaway_solids[0];
} else if (vp.GetCutawayMode() == G4ViewParameters::cutawayUnion) {
G4UnionSolid* union2 =
new G4UnionSolid("_union_2", cutaway_solids[0], cutaway_solids[1]);
if (cutaway_solids.size() == 2)
return (G4DisplacedSolid*)union2;
else
return (G4DisplacedSolid*)
new G4UnionSolid("_union_3", union2, cutaway_solids[2]);
} else if (vp.GetCutawayMode() == G4ViewParameters::cutawayIntersection){
G4IntersectionSolid* intersection2 =
new G4IntersectionSolid("_intersection_2", cutaway_solids[0], cutaway_solids[1]);
if (cutaway_solids.size() == 2)
return (G4DisplacedSolid*)intersection2;
else
return (G4DisplacedSolid*)
new G4IntersectionSolid("_intersection_3", intersection2, cutaway_solids[2]);
for (size_t plane_no = 0; plane_no < nPlanes; plane_no++)
{
const G4Plane3D& sp = vp.GetCutawayPlanes()[plane_no];
G4Transform3D requiredTransform;
G4ThreeVector normal;
switch (vp.GetCutawayMode()) {
case G4ViewParameters::cutawayUnion:
normal = -sp.normal(); // Invert normal - we want a subtractor
requiredTransform = G4Translate3D(normal*(safe + sp.d())) *
G4Rotate3D(G4ThreeVector(0,0,1), G4ThreeVector(0,1,0), normal, normal.orthogonal());
break;
case G4ViewParameters::cutawayIntersection:
normal = sp.normal();
requiredTransform = G4Translate3D(normal*(safe - sp.d())) *
G4Rotate3D(G4ThreeVector(0,0,1), G4ThreeVector(0,1,0), normal, normal.orthogonal());
break;
}
cutaway_solids.push_back
(new G4DisplacedSolid("_displaced_cutaway_box", cutawayBox, requiredTransform));
}
return 0;
if (nPlanes == 1) return (G4DisplacedSolid*) cutaway_solids[0];
G4IntersectionSolid *union2 = nullptr, *union3 = nullptr;
G4IntersectionSolid *intersection2 = nullptr, *intersection3 = nullptr;
switch (vp.GetCutawayMode()) {
case G4ViewParameters::cutawayUnion:
// Here we make a subtractor of intersections of inverted cutaway planes.
union2 = new G4IntersectionSolid("_union_2", cutaway_solids[0], cutaway_solids[1]);
if (nPlanes == 2) return (G4DisplacedSolid*)union2;
else if (nPlanes == 3) {
union3 = new G4IntersectionSolid("_union_3", union2, cutaway_solids[2]);
return (G4DisplacedSolid*)union3;
}
break;
case G4ViewParameters::cutawayIntersection:
// And here we make an intersector of intersections of non-inverted cutaway planes.
intersection2
= new G4IntersectionSolid("_intersection_2", cutaway_solids[0], cutaway_solids[1]);
if (nPlanes == 2) return (G4DisplacedSolid*)intersection2;
else if (nPlanes == 3) {
intersection3
= new G4IntersectionSolid("_intersection_3", intersection2, cutaway_solids[2]);
return (G4DisplacedSolid*)intersection3;
}
break;
}
G4Exception("G4VSceneHandler::CreateCutawaySolid", "visman107", JustWarning,
"Not programmed for more than 3 cutaway planes");
return nullptr;
}
void G4VSceneHandler::LoadAtts(const G4Visible& visible, G4AttHolder* holder)
@@ -1220,10 +1295,10 @@ std::ostream& operator << (std::ostream& os, const G4VSceneHandler& sh) {
}
void G4VSceneHandler::PseudoSceneFor3DRectMeshPositions::AddSolid(const G4Box&) {
if (fpPVModel->GetCurrentDepth() == fDepth) { // Leaf-level cells only
if (fpPVModel->GetCurrentDepth() == fpMesh->GetMeshDepth()) { // Leaf-level cells only
const auto& material = fpPVModel->GetCurrentLV()->GetMaterial();
const auto& name = material->GetName();
const auto* pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes();
const auto& name = material? material->GetName(): fpMesh->GetContainerVolume()->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.
@@ -1236,13 +1311,13 @@ void G4VSceneHandler::PseudoSceneFor3DRectMeshPositions::AddSolid(const G4Box&)
}
void G4VSceneHandler::PseudoSceneForTetVertices::AddSolid(const G4VSolid& solid) {
if (fpPVModel->GetCurrentDepth() == fDepth) { // Leaf-level cells only
if (fpPVModel->GetCurrentDepth() == fpMesh->GetMeshDepth()) { // 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& tet = dynamic_cast<const G4Tet&>(solid);
const auto& material = fpPVModel->GetCurrentLV()->GetMaterial();
const auto& name = material->GetName();
const auto* pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes();
const auto& name = material? material->GetName(): fpMesh->GetContainerVolume()->GetName();
const auto& pVisAtts = fpPVModel->GetCurrentLV()->GetVisAttributes();
// Transform into world coordinates if necessary
if (fpCurrentObjectTransformation->xx() == 1. &&
fpCurrentObjectTransformation->yy() == 1. &&
@@ -1278,6 +1353,8 @@ void G4VSceneHandler::StandardSpecialMeshRendering(const G4Mesh& mesh)
case G4Mesh::rectangle: [[fallthrough]];
case G4Mesh::nested3DRectangular:
switch (fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()) {
case G4ViewParameters::meshAsDefault:
[[fallthrough]];
case G4ViewParameters::meshAsDots:
Draw3DRectMeshAsDots(mesh); // Rectangular 3-deep mesh as dots
implemented = true;
@@ -1290,6 +1367,8 @@ void G4VSceneHandler::StandardSpecialMeshRendering(const G4Mesh& mesh)
break;
case G4Mesh::tetrahedron:
switch (fpViewer->GetViewParameters().GetSpecialMeshRenderingOption()) {
case G4ViewParameters::meshAsDefault:
[[fallthrough]];
case G4ViewParameters::meshAsDots:
DrawTetMeshAsDots(mesh); // Tetrahedron mesh as dots
implemented = true;
@@ -1378,7 +1457,7 @@ void G4VSceneHandler::Draw3DRectMeshAsDots(const G4Mesh& mesh)
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate the pseudo scene
PseudoSceneFor3DRectMeshPositions pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),positionByMaterial,nameAndVisAttsByMaterial);
(&tmpPVModel,&mesh,positionByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of positions by material.
@@ -1522,7 +1601,7 @@ void G4VSceneHandler::Draw3DRectMeshAsSurfaces(const G4Mesh& mesh)
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate the pseudo scene
PseudoSceneFor3DRectMeshPositions pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),positionByMaterial,nameAndVisAttsByMaterial);
(&tmpPVModel,&mesh,positionByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of positions by material.
@@ -1666,7 +1745,7 @@ void G4VSceneHandler::DrawTetMeshAsDots(const G4Mesh& mesh)
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate a pseudo scene
PseudoSceneForTetVertices pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),verticesByMaterial,nameAndVisAttsByMaterial);
(&tmpPVModel,&mesh,verticesByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of vertices by material.
@@ -1804,7 +1883,7 @@ void G4VSceneHandler::DrawTetMeshAsSurfaces(const G4Mesh& mesh)
std::map<const G4Material*,G4VSceneHandler::NameAndVisAtts> nameAndVisAttsByMaterial;
// Instantiate a pseudo scene
PseudoSceneForTetVertices pseudoScene
(&tmpPVModel,mesh.GetMeshDepth(),verticesByMaterial,nameAndVisAttsByMaterial);
(&tmpPVModel,&mesh,verticesByMaterial,nameAndVisAttsByMaterial);
// Make private descent into the parameterisation
tmpPVModel.DescribeYourselfTo(pseudoScene);
// Now we have a map of vertices by material.
@@ -44,6 +44,8 @@
#include "G4VPhysicalVolume.hh"
#include "G4Transform3D.hh"
#include "G4UImanager.hh"
#include "G4UIsession.hh"
#include "G4VInteractiveSession.hh"
G4VViewer::G4VViewer (G4VSceneHandler& sceneHandler,
G4int id, const G4String& name):
@@ -65,6 +67,8 @@ fNeedKernelVisit (true)
fVP = G4VisManager::GetInstance()->GetDefaultViewParameters();
fDefaultVP = fVP;
fSceneTree.SetType(G4SceneTreeItem::root);
}
G4VViewer::~G4VViewer () {
@@ -118,6 +122,7 @@ void G4VViewer::ProcessView ()
fNeedKernelVisit = false;
fSceneHandler.ClearStore ();
fSceneHandler.ProcessScene ();
UpdateGUISceneTree();
timer.Stop();
fKernelVisitElapsedTimeSeconds = timer.GetRealElapsed();
}
@@ -139,7 +144,7 @@ void G4VViewer::SetTouchable
if (iterator == pvStore->cend()) {
G4ExceptionDescription ed;
ed << "Volume no longer in physical volume store.";
G4Exception("G4VViewer::SetTouchable", "visman0501", JustWarning, ed);
G4Exception("G4VViewer::SetTouchable", "visman0401", JustWarning, ed);
} else {
oss
<< ' ' << pvNodeId.GetPhysicalVolume()->GetName()
@@ -153,7 +158,7 @@ void G4VViewer::TouchableSetVisibility
(const std::vector<G4PhysicalVolumeModel::G4PhysicalVolumeNodeID>& fullPath,
G4bool visibiity)
{
// Changes the Vis Attribute Modifiers WITHOUT triggering a rebuild.
// Changes the Vis Attribute Modifiers and scene tree WITHOUT triggering a rebuild.
// The following is equivalent to
// G4UImanager::GetUIpointer()->ApplyCommand("/vis/touchable/set/visibility ...");
@@ -172,13 +177,26 @@ void G4VViewer::TouchableSetVisibility
// G4ModelingParameters::VASVisibility (VAS = Vis Attribute Signifier)
// signifies that it is the visibility that should be picked out
// and merged with the touchable's normal vis attributes.
// Find scene tree item and set visibility
// The scene tree works with strings
G4String fullPathString = G4PhysicalVolumeModel::GetPVNamePathString(fullPath);
std::list<G4SceneTreeItem>::iterator foundIter;
if (fSceneTree.FindTouchableFromRoot(fullPathString,foundIter)) {
foundIter->AccessVisAttributes().SetVisibility(visibiity);
UpdateGUISceneTree();
} else {
G4ExceptionDescription ed;
ed << "Touchable \"" << fullPath << "\" not found";
G4Exception("G4VViewer::TouchableSetVisibility", "visman0402", JustWarning, ed);
}
}
void G4VViewer::TouchableSetColour
(const std::vector<G4PhysicalVolumeModel::G4PhysicalVolumeNodeID>& fullPath,
const G4Colour& colour)
{
// Changes the Vis Attribute Modifiers WITHOUT triggering a rebuild.
// Changes the Vis Attribute Modifiers and scene tree WITHOUT triggering a rebuild.
// The following is equivalent to
// G4UImanager::GetUIpointer()->ApplyCommand("/vis/touchable/set/colour ...");
@@ -197,6 +215,201 @@ void G4VViewer::TouchableSetColour
// G4ModelingParameters::VASColour (VAS = Vis Attribute Signifier)
// signifies that it is the colour that should be picked out
// and merged with the touchable's normal vis attributes.
// Find scene tree item and set colour
// The scene tree works with strings
G4String fullPathString = G4PhysicalVolumeModel::GetPVNamePathString(fullPath);
std::list<G4SceneTreeItem>::iterator foundIter;
if (fSceneTree.FindTouchableFromRoot(fullPathString,foundIter)) {
foundIter->AccessVisAttributes().SetColour(colour);
UpdateGUISceneTree();
} else {
G4ExceptionDescription ed;
ed << "Touchable \"" << fullPath << "\" not found";
G4Exception("G4VViewer::TouchableSetColour", "visman0403", JustWarning, ed);
}
}
void G4VViewer::UpdateGUISceneTree()
{
G4UImanager* UI = G4UImanager::GetUIpointer();
auto uiWindow = dynamic_cast<G4VInteractiveSession*>(UI->GetG4UIWindow());
if (uiWindow) uiWindow->UpdateSceneTree(fSceneTree);
}
void G4VViewer::SceneTreeScene::SetModel(G4VModel* pModel)
{
fpModel = pModel;
auto& modelType = fpModel->GetType();
auto& modelID = fpModel->GetGlobalDescription();
FindOrInsertModel(modelType,modelID);
}
std::list<G4SceneTreeItem>::iterator G4VViewer::SceneTreeScene::FindOrInsertModel
(const G4String& modelType,const G4String& modelID)
{
G4SceneTreeItem::Type type = G4SceneTreeItem::unidentified;
if (dynamic_cast<G4PhysicalVolumeModel*>(fpModel)) {
type = G4SceneTreeItem::pvmodel;
} else {
type = G4SceneTreeItem::model;
}
auto& rootItem = fpViewer->fSceneTree;
rootItem.SetDescription(fpViewer->GetName());
// Find appropriate model
auto& modelItems = rootItem.AccessChildren();
auto modelIter = modelItems.begin();
auto pvModelIter = modelItems.end();
for (; modelIter != modelItems.end(); ++modelIter) {
if (modelIter->GetType() == G4SceneTreeItem::pvmodel) {
pvModelIter = modelIter; // Last PV model
}
if (modelIter->GetModelDescription() == modelID) break;
}
if (modelIter == modelItems.end()) {
// Model not seen before
G4SceneTreeItem modelItem(type);
modelItem.SetDescription("model");
modelItem.SetModelType(modelType);
modelItem.SetModelDescription(modelID);
if (pvModelIter != modelItems.end() && // There was pre-existing PV Model...
type == G4SceneTreeItem::pvmodel) { // ...and the new model is also PV...
modelIter = rootItem.InsertChild(++pvModelIter,modelItem); // ...insert after, else...
} else {
modelIter = rootItem.InsertChild(modelIter,modelItem); // ...insert at end
}
} else {
// Existing model - mark visible == active
modelIter->AccessVisAttributes().SetVisibility(true);
}
return modelIter;
}
std::list<G4SceneTreeItem>::iterator G4VViewer::SceneTreeScene::FindOrInsertTouchable
(const G4String& modelID, G4SceneTreeItem& mother,
G4int depth, const G4String& partialPathString, const G4String& fullPathString)
{
auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
if (pPVModel == nullptr) {
G4ExceptionDescription ed;
ed << fpModel->GetType() << ": not a Physical VolumeModel";
G4Exception("G4VViewer::SceneTreeScene::FindOrInsertTouchable", "visman0404", FatalException, ed);
}
auto& children = mother.AccessChildren();
auto childIter = children.begin();
for (; childIter != children.end(); ++childIter) {
if (childIter->GetPVPath() == partialPathString) break;
}
if (childIter != children.end()) {
// Item already exists
if (childIter->GetType() == G4SceneTreeItem::ghost) {
// Previously it was a ghost - but maybe this time it's real
if (partialPathString == fullPathString) {
// Partial path string refers to the actual volume so it's a touchable
childIter->SetType(G4SceneTreeItem::touchable);
// Populate with information
childIter->SetDescription(fpModel->GetCurrentTag());
childIter->SetModelType(fpModel->GetType());
childIter->SetModelDescription(modelID);
childIter->SetPVPath(partialPathString);
if (fpVisAttributes) childIter->SetVisAttributes(*fpVisAttributes);
if (pPVModel) childIter->SetAttDefs(pPVModel->GetAttDefs());
if (pPVModel) childIter->SetAttValues(pPVModel->CreateCurrentAttValues());
} // Partial path string refers to an ancester - do nothing
} else {
// Already a pre-existing full touchable
if (partialPathString == fullPathString) {
// Partial path string refers to the actual volume
// Replace vis attributes (if any) - they might have changed
if (fpVisAttributes) childIter->SetVisAttributes(*fpVisAttributes);
} // Partial path string refers to an ancester - do nothing
}
} else {
// Item does not yet exist
if (partialPathString == fullPathString) {
// Partial path string refers to the actual volume
// Insert new touchable item
G4SceneTreeItem touchable(G4SceneTreeItem::touchable);
touchable.SetExpanded(depth > 2? false: true);
touchable.SetDescription(fpModel->GetCurrentTag());
touchable.SetModelType(fpModel->GetType());
touchable.SetModelDescription(modelID);
touchable.SetPVPath(partialPathString);
if (fpVisAttributes) touchable.SetVisAttributes(*fpVisAttributes);
if (pPVModel) touchable.SetAttDefs(pPVModel->GetAttDefs());
if (pPVModel) touchable.SetAttValues(pPVModel->CreateCurrentAttValues());
childIter = mother.InsertChild(childIter,touchable);
} else {
// Partial path string refers to an ancester - it's what we call a "ghost"
G4SceneTreeItem ghost(G4SceneTreeItem::ghost);
ghost.SetExpanded(depth > 2? false: true);
// Create a tag from the partial path
std::istringstream iss(partialPathString);
G4String name, copyNo;
while (iss >> name >> copyNo);
std::ostringstream oss;
oss << name << ':' << copyNo;
ghost.SetDescription(oss.str());
ghost.SetModelType(fpModel->GetType());
ghost.SetModelDescription(modelID);
ghost.SetPVPath(partialPathString);
ghost.AccessVisAttributes().SetVisibility(false);
childIter = mother.InsertChild(childIter,ghost);
}
}
return childIter;
}
void G4VViewer::SceneTreeScene::ProcessVolume(const G4VSolid&)
{
auto& modelType = fpModel->GetType();
auto& modelID = fpModel->GetGlobalDescription();
auto modelIter = FindOrInsertModel(modelType,modelID);
auto pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
if (pPVModel) { // G4PhysicalVolumeModel
std::ostringstream oss; oss << pPVModel->GetFullPVPath();
G4String fullPathString(oss.str()); // Has a leading space - OK
// Navigate scene tree and find or insert touchables one by one
const auto& nodeIDs = pPVModel->GetFullPVPath(); // std::vector<G4PhysicalVolumeNodeID>
// Work down the path - "name id", then "name id name id", etc.
G4String partialPathString;
auto currentIter = modelIter;
G4int depth = 0;
for (const auto& nodeID: nodeIDs) {
std::ostringstream oss1; oss1 << nodeID;
partialPathString += ' ' + oss1.str(); // Has a leading space - OK
currentIter = FindOrInsertTouchable
(modelID, *currentIter, ++depth, partialPathString, fullPathString);
}
} else {
// Orphan solid - what to do? Push an empty scene tree item????????????????????????
}
}
std::vector <G4ThreeVector> G4VViewer::ComputeFlyThrough(G4Vector3D* /*aVect*/)
@@ -55,6 +55,7 @@ G4VisExtent G4VVisCommand::fCurrentExten
std::vector<G4PhysicalVolumesSearchScene::Findings> G4VVisCommand::fCurrrentPVFindingsForField;
G4bool G4VVisCommand::fThereWasAViewer = false;
G4ViewParameters G4VVisCommand::fExistingVP;
G4SceneTreeItem G4VVisCommand::fExistingSceneTree;
G4VVisCommand::G4VVisCommand () {}
@@ -339,7 +340,6 @@ void G4VVisCommand::InterpolateToNewView
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)
@@ -379,16 +379,11 @@ void G4VVisCommand::Twinkle
// 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 twinkles is reasonable to get a human's attention
for (G4int i = 0; i < 5; i++) {
viewVector.push_back(loVP);
viewVector.push_back(hiVP);
}
// Just 5 interpolation points for a reasonable twinkle rate
InterpolateViews(currentViewer,viewVector,5);
}
@@ -104,7 +104,7 @@ G4ViewParameters::G4ViewParameters ():
fDisplayLightFrontGreen(1.),
fDisplayLightFrontBlue(0.),
fSpecialMeshRendering(false),
fSpecialMeshRenderingOption(meshAsDots)
fSpecialMeshRenderingOption(meshAsDefault)
{
// Pick up default no of sides from G4Polyhedron.
// Note that this parameter is variously called:
@@ -896,6 +896,8 @@ std::ostream& operator <<
(std::ostream& os, G4ViewParameters::SMROption option)
{
switch (option) {
case G4ViewParameters::meshAsDefault:
os << "default"; break;
case G4ViewParameters::meshAsDots:
os << "dots"; break;
case G4ViewParameters::meshAsSurfaces:
@@ -324,10 +324,12 @@ void G4VisCommandSceneHandlerCreate::SetNewValue (G4UIcommand* command,
}
}
// If there is an existing viewer, store its view parameters
// If there is an existing viewer, store its view parameters and scene tree
if (fpVisManager->GetCurrentViewer()) {
fThereWasAViewer = true;
fExistingVP = fpVisManager->GetCurrentViewer()->GetViewParameters();
auto viewer = fpVisManager->GetCurrentViewer();
fExistingVP = viewer->GetViewParameters();
fExistingSceneTree = viewer->AccessSceneTree();
}
// Set current graphics system in preparation for
@@ -120,6 +120,11 @@ G4VisCommandsTouchable::G4VisCommandsTouchable()
fpCommandShowExtent->SetParameterName("draw", omitable = true);
fpCommandShowExtent->SetDefaultValue(false);
fpCommandTwinkle = new G4UIcmdWithoutParameter("/vis/touchable/twinkle",this);
fpCommandTwinkle->SetGuidance("Cause touchable to twinkle.");
// Pick up additional guidance from /vis/viewer/centreAndZoomInOn
CopyGuidanceFrom(fpCommandCentreAndZoomInOn,fpCommandTwinkle,1);
fpCommandVolumeForField = new G4UIcmdWithABool("/vis/touchable/volumeForField",this);
fpCommandVolumeForField->SetGuidance("Set volume for field.");
fpCommandVolumeForField->SetGuidance("If parameter == true, also draw.");
@@ -131,6 +136,7 @@ G4VisCommandsTouchable::G4VisCommandsTouchable()
G4VisCommandsTouchable::~G4VisCommandsTouchable() {
delete fpCommandVolumeForField;
delete fpCommandTwinkle;
delete fpCommandShowExtent;
delete fpCommandLocalAxes;
delete fpCommandFindPath;
@@ -255,7 +261,6 @@ void G4VisCommandsTouchable::SetNewValue
} else {
G4warn << "Touchable not found." << G4endl;
}
return;
} else if (command == fpCommandDraw) {
@@ -263,7 +268,7 @@ void G4VisCommandsTouchable::SetNewValue
G4PhysicalVolumeModel::TouchableProperties properties =
G4TouchableUtils::FindTouchableProperties(fCurrentTouchableProperties.fTouchablePath);
if (properties.fpTouchablePV) {
// To handle paramaterisations we have to set the copy number
// To handle parameterisations we have to set the copy number
properties.fpTouchablePV->SetCopyNo(properties.fCopyNo);
G4PhysicalVolumeModel* pvModel = new G4PhysicalVolumeModel
(properties.fpTouchablePV,
@@ -310,7 +315,7 @@ void G4VisCommandsTouchable::SetNewValue
G4PhysicalVolumeModel::TouchableProperties properties =
G4TouchableUtils::FindTouchableProperties(fCurrentTouchableProperties.fTouchablePath);
if (properties.fpTouchablePV) {
// To handle paramaterisations we have to set the copy number
// To handle parameterisations we have to set the copy number
properties.fpTouchablePV->SetCopyNo(properties.fCopyNo);
G4PhysicalVolumeModel tempPVModel
(properties.fpTouchablePV,
@@ -398,19 +403,27 @@ void G4VisCommandsTouchable::SetNewValue
if (copyNo >= 0) G4warn << ':' << copyNo;
G4warn << " not found" << G4endl;
}
return;
} else if (command == fpCommandLocalAxes) {
const auto& transform = fCurrentTouchableProperties.fTouchableGlobalTransform;
const auto& extent = fCurrentTouchableProperties.fpTouchablePV->GetLogicalVolume()->GetSolid()->GetExtent();
const G4double lengthMax = extent.GetExtentRadius()/2.;
const G4double intLog10LengthMax = std::floor(std::log10(lengthMax));
G4double length = std::pow(10,intLog10LengthMax);
if (5.*length < lengthMax) length *= 5.;
else if (2.*length < lengthMax) length *= 2.;
G4AxesModel axesModel(0.,0.,0.,length,transform);
axesModel.SetGlobalTag("LocalAxesModel");
axesModel.DescribeYourselfTo(*fpVisManager->GetCurrentSceneHandler());
G4PhysicalVolumeModel::TouchableProperties properties =
G4TouchableUtils::FindTouchableProperties(fCurrentTouchableProperties.fTouchablePath);
if (properties.fpTouchablePV) {
const auto& transform = fCurrentTouchableProperties.fTouchableGlobalTransform;
const auto& extent = fCurrentTouchableProperties.fpTouchablePV->GetLogicalVolume()->GetSolid()->GetExtent();
const G4double lengthMax = extent.GetExtentRadius()/2.;
const G4double intLog10LengthMax = std::floor(std::log10(lengthMax));
G4double length = std::pow(10,intLog10LengthMax);
if (5.*length < lengthMax) length *= 5.;
else if (2.*length < lengthMax) length *= 2.;
G4AxesModel axesModel(0.,0.,0.,length,transform);
axesModel.SetGlobalTag("LocalAxesModel");
axesModel.DescribeYourselfTo(*fpVisManager->GetCurrentSceneHandler());
} else {
G4warn << "Touchable not found." << G4endl;
}
return;
} else if (command == fpCommandShowExtent) {
@@ -427,6 +440,24 @@ void G4VisCommandsTouchable::SetNewValue
}
return;
} else if (command == fpCommandTwinkle) {
G4PhysicalVolumeModel::TouchableProperties properties =
G4TouchableUtils::FindTouchableProperties(fCurrentTouchableProperties.fTouchablePath);
if (properties.fpTouchablePV) {
std::vector<std::vector<G4PhysicalVolumeModel::G4PhysicalVolumeNodeID>> touchables;
touchables.push_back(properties.fTouchableFullPVPath);
auto keepVisVerbose = fpVisManager->GetVerbosity();
fpVisManager->SetVerboseLevel(G4VisManager::errors);
auto keepVP = currentViewer->GetViewParameters();
Twinkle(currentViewer,currentViewer->GetViewParameters(),touchables);
SetViewParameters(currentViewer, keepVP);
fpVisManager->SetVerboseLevel(keepVisVerbose);
} else {
G4warn << "Touchable not found." << G4endl;
}
return;
} else if (command == fpCommandVolumeForField) {
G4PhysicalVolumeModel::TouchableProperties properties =
@@ -309,6 +309,20 @@ void G4VisCommandsTouchableSet::SetNewValue
(workingVisAtts,
G4ModelingParameters::VASVisibility,
fCurrentTouchableProperties.fTouchablePath));
if (verbosity >= G4VisManager::warnings) {
static G4bool first = true;
if (first) {
first = false;
G4warn << "WARNING: If \"/vis/touchable/set/visibility\" does not appear to"
"\n work, check that opacity (4th component of colour) is non-zero." << G4endl;
G4warn << "ALSO: The volume must be in a requested physical volume tree,"
"\n not in the \"base path\". E.g., if"
"\n /vis/drawVolume volume-name"
"\n there is no way to make a parent of volume-name visible except by"
"\n explicitly adding the parent:"
"\n /vis/scene/add/volume parent-name" << G4endl;
}
}
}
else {
@@ -1067,6 +1067,7 @@ void G4VisCommandViewerCreate::SetNewValue (G4UIcommand* command, G4String newVa
if (existingViewer) {
// ...bring view parameters up to date...
fExistingVP = existingViewer->GetViewParameters();
fExistingSceneTree = existingViewer->AccessSceneTree();
}
}
@@ -1090,13 +1091,16 @@ void G4VisCommandViewerCreate::SetNewValue (G4UIcommand* command, G4String newVa
fExistingVP.SetXGeometryString(vp.GetXGeometryString());
vp = fExistingVP;
newViewer->SetViewParameters(vp);
newViewer->AccessSceneTree() = fExistingSceneTree;
}
if (verbosity >= G4VisManager::confirmations) {
G4cout << "New viewer \"" << newName << "\" created." << G4endl;
}
// Keep for next time...
fThereWasAViewer = true;
fExistingVP = fpVisManager->GetCurrentViewer()->GetViewParameters();
auto viewer = fpVisManager->GetCurrentViewer();
fExistingVP = viewer->GetViewParameters();
fExistingSceneTree = viewer->AccessSceneTree();
} else {
G4ExceptionDescription ed;
if (newViewer) {
@@ -2168,6 +2172,9 @@ void G4VisCommandViewerSelect::SetNewValue (G4UIcommand*, G4String newValue) {
fpVisManager -> SetCurrentViewer (viewer);
RefreshIfRequired(viewer);
// Update GUI scene tree (make sure it's in sync)
viewer->UpdateGUISceneTree();
}
////////////// /vis/viewer/update ///////////////////////////////////////
@@ -388,10 +388,10 @@ fViewpointVector (G4ThreeVector(0.,0.,1.))
fpCommandSpecialMeshRenderingOption = new G4UIcmdWithAString
("/vis/viewer/set/specialMeshRenderingOption",this);
fpCommandSpecialMeshRenderingOption->SetGuidance
("Set special mesh rendering option - \"dots\" or \"surfaces\".");
("Set special mesh rendering option - \"default\", \"dots\" or \"surfaces\".");
fpCommandSpecialMeshRenderingOption->SetParameterName ("option",omitable = true);
fpCommandSpecialMeshRenderingOption->SetCandidates("dots surfaces");
fpCommandSpecialMeshRenderingOption->SetDefaultValue("dots");
fpCommandSpecialMeshRenderingOption->SetCandidates("default dots surfaces");
fpCommandSpecialMeshRenderingOption->SetDefaultValue("default");
fpCommandSpecialMeshVolumes = new G4UIcommand
("/vis/viewer/set/specialMeshVolumes",this);
@@ -1274,8 +1274,11 @@ void G4VisCommandsViewerSet::SetNewValue
}
else if (command == fpCommandSpecialMeshRenderingOption) {
G4ViewParameters::SMROption option = G4ViewParameters::meshAsDots;
if (newValue == "surfaces") {
G4ViewParameters::SMROption option = G4ViewParameters::meshAsDefault;
if (newValue == "dots") {
option = G4ViewParameters::meshAsDots;
}
else if(newValue == "surfaces") {
option = G4ViewParameters::meshAsSurfaces;
}
vp.SetSpecialMeshRenderingOption(option);