| Summary: | visualization viewer creation with c++ coding | ||
|---|---|---|---|
| Product: | Geant4 | Reporter: | Bartlomiej Rachwal <bartlomiej.rachwal> |
| Component: | visualization | Assignee: | Laurent Garnier <laurent.garnier> |
| Status: | RESOLVED FIXED | ||
| Severity: | normal | CC: | bartlomiej.rachwal, Ben.Morgan, John.Allison, laurent.garnier |
| Priority: | P4 | ||
| Version: | 10.4 | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Attachments: |
problem exercise based on B1 g4 example
Creating simple Qt viewer based on B1 g4 example and UIQt class B1 example with independent viewer implementation |
||
|
Description
Bartlomiej Rachwal
2018-08-14 14:37:32 CEST
The key issue here is how to write correctly the c++ code for the one line of the geant4 .mac for creating the viewer: "/vis/open OGLSQt" --> c++ code ?? Can anybody help me, please? Created attachment 506 [details]
Creating simple Qt viewer based on B1 g4 example and UIQt class
The main issue is how to rewrite the UI command:
UImanager->ApplyCommand("/vis/open OGLSQt");
with plain c++ code. I didn't manage with attempts that are commented out in a given example.
Hi Bartlomiej
First, I'd like to know a little more about your use case. Why, for instance, is the existing Qt UI and viewer not appropriate for your needs? Have you a more general application in mind? Or perhaps an existing one? Could you not simply extend the existing Qt UI?
Secondly, if you proceed, I'd like to say right from the beginning that there is a design to be respected. Each graphics system/type has a "factory" (derived from G4VGraphicsSystem). There are two levels of processing - the scene handler, which takes all objects/models in the scene and turns them into suitable primitives in 3D, and a viewer, which renders to the screen from a particular viewpoint, or to a file or whatever. The factory knows how to create a scene handler and viewer. There may be any number of "factories", any number of scene handlers for any given graphics system and any number of viewers for any given scene handler.
Here is an example of a "factory":
class G4OpenGLStoredQt: public G4OpenGLQt {
public:
G4OpenGLStoredQt ();
G4VSceneHandler* CreateSceneHandler (const G4String& name = "");
G4VViewer* CreateViewer (G4VSceneHandler&, const G4String& name = "");
};
The vis manager (or one of its messengers) invokes these functions via the virtual function mechanism when the user asks "/vis/sceneHandler/create" or "/vis.viewer/create". The vis manager keeps a list of all scenes, scene handlers and viewers. We have not envisaged that the user would call these functions him/herself, but I guess you could look at the messengers for the above commands and reproduce the code in there somehow, but it would frustrate the design whereby the vis manager keeps control, knows whats going on and makes extensive checks.
We have attempted to document all this in the Toolkit Developers Guide/Extending Toolkit Functionality/Visualisation.
I'll now go back and look at your comments in a little more detail.
John
Hi Bartlomiej
I've had a quick look at the code in your attachments. It really does look as though you have made great attempts to respect the design and keep the vis manager informed. That's great. A big effort - well done. Phew!
[DEBUG]:: SceneHandler name OGLSQt
[DEBUG]:: viewer name viewer-0 (OpenGLStoredX)
This is curious. It looks like your scene handler pointers and viewer pointers do not match.
What messages do you get if you up the verbosity:
G4VisManager* visManager = new G4VisExecutive("Confirmations");
or "/vis/verbose Confirmations"?
Looking at the code below it seems you are missing something like
G4VViewer* pViewer = pSystem->CreateViewer();
visManager->SetCurrentViewer(pViewer);
I will await some feedback from you.
Cheers and good luck
John
Code snippet from main of "B1 2":
// A graphics system has been found
G4VGraphicsSystem* pSystem = gsl [iGS];
visManager->SetCurrentGraphicsSystem(pSystem);
//Create scene handler.
// visManager->CreateSceneHandler ("OGLSQt");
G4VSceneHandler* pSceneHandler = pSystem ->CreateSceneHandler("OGLSQt");
visManager->SetCurrentSceneHandler(pSceneHandler);
// Attach scene.
UImanager->ApplyCommand ("/vis/scene/create");
if (visManager -> GetCurrentScene ()) {
UImanager->ApplyCommand ("/vis/sceneHandler/attach");
}
//////////////////////////////////////////////////////////////////////////////////////
auto session = new B1UIQt(argc, argv, mw);
UImanager->ApplyCommand("/vis/open OGLSQt");
// visManager->CreateViewer("test","600");
auto viewer = visManager->GetCurrentViewer();
Dear John,
Thank you for detailed introduction. You are right that I'm creating more general application with the geant4 as
the simulation engine. In addition, I'm developing GUI in Qt, hence having all the machinery of the visulalization
already implemented in geant4 and interfaced with Qt I thought to simply take what I need - the OGLSQt.
However, I've faced to the issue I've described.
I thought that having the pgraphic system registered in the visManager, calling the
visManager->CreateViewer("MyViewer","600");
would do all the job, but it desn't.
In fact, I was trying what you seggested, creating and registering the viewer explicitly, using the
G4VGraphicsSystem method, like:
G4VViewer* pViewer = pSystem->CreateViewer(*pSceneHandler, "MyViewer");
visManager->SetCurrentViewer(pViewer);
Unfortunately, the scene handler doesn't see it:
G4VisManager::SetCurrentViewer: viewer now MyViewer
ERROR: G4VisManager::IsValidView (): the current scene handler
"OGLSQt" has no viewers. Do /vis/viewer/create.
Afterwards, I've tried with:
pSceneHandler->AddViewerToList(pViewer);
pSceneHandler->SetCurrentViewer(pViewer);
but this alse doesn't help :(
It seems that above reagistraion methods doesn't work?
Thank you for helping,
Bartek
Hi Bartek
OK. Great. Having thought about it a bit more, I think my approach would be to write a complete graphics system - factory, scene handler and viewer - that differed from OGLSQt only in that the viewer embeds itself in your UI rather than G4UIQt. You might be able avoid changing the scene handler at all. Then you can use all the the vis system commands in a .mac file or coded with ApplyCommand.
So register your factory
G4VisManager* visManager = new G4VisExecutive;
visManager -> RegisterGraphicsSystem(new MyOpenGLStoredQt);
where
G4VSceneHandler* MyOpenGLStoredQt::CreateSceneHandler
(const G4String& name) {
G4VSceneHandler* pScene = new G4OpenGLStoredQtSceneHandler (*this, name);
return pScene;
}
G4VViewer* G4OpenGLStoredQt::CreateViewer
(G4VSceneHandler& scene, const G4String& name) {
G4VViewer* pView = 0;
pView = new MyOpenGLStoredQtViewer
((G4OpenGLStoredSceneHandler&) scene, name);
...
MyOpenGLStoredQtViewer would be identical to G4OpenGLStoredQtViewer except it inherits MyOpenGLQtViewer, in which
#include "G4UIQt.hh"
is replaced by
#include "MyUIQt.hh"
I'm not familiar with Qt enough to know exactly how the viewer gets embedded in the UI. It sounds like you have already figured that out. Laurent may be able to help.
I'm away today but will look in again on Sunday.
John
Sorry. That should be
G4VSceneHandler* MyOpenGLStoredQt::CreateSceneHandler
(const G4String& name) {
G4VSceneHandler* pScene = new G4OpenGLStoredQtSceneHandler (*this, name);
return pScene;
}
G4VViewer* MyOpenGLStoredQt::CreateViewer
(G4VSceneHandler& scene, const G4String& name) {
G4VViewer* pView = 0;
pView = new MyOpenGLStoredQtViewer
((G4OpenGLStoredSceneHandler&) scene, name);
...
Hi John,
Indeed this would be very suitable solution! Thank for this suggestion.
Trying yo implement this idea, I'm also experiencing some difficulties, which are related to the Geant4 compilation flags.
Since my new factory inherits from Geant4 interface, like:
------------
class MyOpenGLQtViewer: public QObject, virtual public G4OpenGLViewer
------------
the corresponding modules should be included in G4 compilation (we have many guards in the code depending on the flags).
I've set in the cmake comfiguration (among others):
------------
-DG4VIS_USE=ON
-DGEANT4_USE_QT=ON
-DGEANT4_USE_OPENGL=ON
-DGEANT4_USE_OPENGLQT=ON
------------
Should this be enough to compile the code which has the guard called:
G4VIS_BUILD_OPENGL_DRIVER ??
I'm worrying about this since I'm getting the following compilation error:
---------------
In file included from /usr/worspace/g4examples/B1/src/B1OpenGLQtViewer.cc:36:0:
/mnt/hgfs/Centos7G4-win/g4examples/B1/include/B1OpenGLQtViewer.hh:81:72: error: expected class-name before ‘{’ token
class B1OpenGLQtViewer: public QObject, virtual public G4OpenGLViewer {
---------------
which suggests that the G4OpenGLViewer was not compiled :( This is really weird, since the factory works well for the 'normal' viewers, like '/vis/open OGLSQt'
By making a simple test with try of creating the object (even with wrong constructor arguments list), I see:
------------
/usr/worspace/g4examples/B1/exampleB1.cc:62:19: error: ‘G4OpenGLViewer’ does not name a type; did you mean ‘QOpenGLShader’?
auto test = new G4OpenGLViewer{};
^~~~~~~~~~~~~~
QOpenGLShader
------------
So the file G4OpenGLViewer.hh exist and it is included, for sure, the G4OpenGLViewer definition is missing. Is that mean that the guard: G4VIS_BUILD_OPENGL_DRIVER hasn't been set during the Geant4 compilation?
Cheers,
Bartek
Hi Bartek
Mmmm. The CMake system should set the C-pre-processor flag G4VIS_BUILD_OPENGL_DRIVER if you pass -DGEANT4_USE_QT=ON to cmake. I have to say I've never tested this alone (I'll get back to you on this). I usually have -DGEANT4_USE_OPENGL_X11=ON as well, and that certainly does the trick. Looking at the Installation Guide/Building and Installing/Geant4 Build Options/Standard Options, GEANT4_USE_OPENGL as such does not exist, and cmake should tell you so towards the end.
One other point: I would make yours a stored viewer. Miss out the intermediate B1OpenGLQtViewer:
class B1OpenGLStoredQtViewer: public QObject, virtual public G4OpenGLStoredViewer {
and I think there's no need for virtual inheritance (I might be wrong).
John
With -DGEANT4_USE_QT=ON alone I get many, many warnings about shadowed variables but it compiles OK and it certainly looks as though the C-pre-processor flag G4VIS_BUILD_OPENGL_DRIVER is set. Created attachment 510 [details]
B1 example with independent viewer implementation
Hi Bartek
Wow! Congratualtions. Looks like you have succeeded.
I tried building your example (B1 3) but cmake gives me some errors (see below). I'm not an expert here so I can't think how to fix this.
Anyway, it looks good. I propose we close this bug report but please feel free to contact use, either directly or via the User Forum. Hope that's OK.
Good luck
John
CMake Error at CMakeLists.txt:34 (find_package):
By not providing "FindQt5.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "Qt5", but
CMake did not find one.
Could not find a package configuration file provided by "Qt5" with any of
the following names:
Qt5Config.cmake
qt5-config.cmake
Add the installation prefix of "Qt5" to CMAKE_PREFIX_PATH or set "Qt5_DIR"
to a directory containing one of the above files. If "Qt5" provides a
separate development package or SDK, be sure it has been installed.
Hi John, Indeed, I think that the attached version looks complete. Thank you for all the suggestions! Unfortunately, I cannot test it since I'm still experiencing troubles with compile definition, it seems that the definitions related to G4VIS_BUILD_OPENGL_DRIVER are not available for me (eg. when trying to create an object of G4OpenGLStoredViewer). This caused that I cannot develop independent/new viewer factory. I started new thread in module dedicated to cmake: https://bugzilla-geant4.kek.jp/show_bug.cgi?id=2091 Thank you again, bartek The issues with the definitions are down to the old GNumake way of building vis drivers which compiled everything, using preprocessor symbols to exclude certain features. It's easy to fix this, but, it would mean obsoleting the old GNUmake system and would require a clear definition of the public/private interface/classes of the OpenGL driver(s). |