Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4Qt3DViewer.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// John Allison 17th June 2019
27
28#if defined (G4VIS_BUILD_QT3D_DRIVER) || defined (G4VIS_USE_QT3D)
29
30#include "G4Qt3DViewer.hh"
31
32#include "G4Qt3DSceneHandler.hh"
33#include "G4Qt3DUtils.hh"
34
35#include "G4Scene.hh"
36#include "G4UImanager.hh"
37#include "G4UIQt.hh"
38#include "G4SystemOfUnits.hh"
39
40G4Qt3DViewer::G4Qt3DViewer
41(G4Qt3DSceneHandler& sceneHandler, const G4String& name)
42: G4VViewer(sceneHandler, sceneHandler.IncrementViewCount(), name)
43, fQt3DSceneHandler(sceneHandler)
44, fKeyPressed(false)
45, fMousePressed(false)
46, fMousePressedX(0.)
47, fMousePressedY(0.)
48{
49 setObjectName(fName.c_str());
50
51 fVP.SetAutoRefresh(true);
52 fDefaultVP.SetAutoRefresh(true);
53
54 // Background is white (not figured out how to change it) so...
55 fVP.SetDefaultColour(G4Colour::Black());
56 fDefaultVP.SetDefaultColour(G4Colour::Black());
57
58 auto UI = G4UImanager::GetUIpointer();
59 auto uiQt = dynamic_cast<G4UIQt*>(UI->GetG4UIWindow());
60 if (!uiQt) {
61 fViewId = -1; // This flags an error.
62 G4cerr << "G4Qt3DViewer::G4Qt3DViewer requires G4UIQt"
63 << G4endl;
64 return;
65 }
66 fUIWidget = QWidget::createWindowContainer(this);
67 uiQt->AddTabWidget(fUIWidget,QString(fName));
68
69 setRootEntity(fQt3DSceneHandler.fpQt3DScene);
70}
71
72G4Qt3DViewer::~G4Qt3DViewer()
73{}
74
75void G4Qt3DViewer::SetView()
76{
77 // Get radius of scene, etc.
78 // Note that this procedure properly takes into account zoom, dolly and pan.
79 const G4Point3D targetPoint
80 = fSceneHandler.GetScene()->GetStandardTargetPoint()
81 + fVP.GetCurrentTargetPoint ();
82 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
83 if(radius<=0.) radius = 1.;
84 const G4double cameraDistance = fVP.GetCameraDistance (radius);
85 const G4Point3D cameraPosition =
86 targetPoint + cameraDistance * fVP.GetViewpointDirection().unit();
87 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius);
88 const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius);
89 const GLdouble right = fVP.GetFrontHalfHeight (pnear, radius);
90 const GLdouble left = -right;
91 const GLdouble top = fVP.GetFrontHalfHeight (pnear, radius);
92 const GLdouble bottom = -top;
93
94 camera()->setObjectName((fName + " camera").c_str());
95 camera()->setViewCenter(G4Qt3DUtils::ConvertToQVector3D(targetPoint));
96 camera()->setPosition(G4Qt3DUtils::ConvertToQVector3D(cameraPosition));
97 camera()->setUpVector(G4Qt3DUtils::ConvertToQVector3D(fVP.GetUpVector()));
98
99// auto lightEntity = new Qt3DCore::QEntity(fQt3DSceneHandler.fpQt3DScene);
100// auto directionalLight = new Qt3DRender::QDirectionalLight(lightEntity);
101//// directionalLight->setColor("white");
102//// directionalLight->setIntensity(1.);
103// directionalLight->setWorldDirection(G4Qt3DUtils::ConvertToQVector3D(fVP.GetActualLightpointDirection()));
104// lightEntity->addComponent(directionalLight);
105
106 const auto& size = fUIWidget->size();
107 G4double w = size.width();
108 G4double h = size.height();
109#ifdef G4QT3DDEBUG
110 // Curiously w,h are wrong first time - 640,480 instead of (my Mac) 991,452.
111 G4cout << "W,H: " << w << ',' << h << G4endl;
112#endif
113 const G4double aspectRatio = w/h;
114 if (fVP.GetFieldHalfAngle() == 0.) {
115 camera()->lens()->setOrthographicProjection
116 (left*aspectRatio,right*aspectRatio,bottom,top,pnear,pfar);
117 } else {
118 camera()->lens()->setPerspectiveProjection
119 (2.*fVP.GetFieldHalfAngle()/deg,aspectRatio,pnear,pfar);
120 }
121}
122
123void G4Qt3DViewer::ClearView()
124{}
125
126void G4Qt3DViewer::DrawView()
127{
128 // First, a view should decide when to re-visit the G4 kernel.
129 // Sometimes it might not be necessary, e.g., if the scene is stored
130 // in a graphical database (e.g., OpenGL's display lists) and only
131 // the viewing angle has changed. But graphics systems without a
132 // graphical database will always need to visit the G4 kernel.
133
134 // The fNeedKernelVisit flag might have been set by the user in
135 // /vis/viewer/rebuild, but if not, make decision and set flag only
136 // if necessary...
137 if (!fNeedKernelVisit) KernelVisitDecision();
138 G4bool kernelVisitWasNeeded = fNeedKernelVisit; // Keep (ProcessView resets).
139 fLastVP = fVP;
140
141 ProcessView (); // Clears store and processes scene only if necessary.
142
143 if (kernelVisitWasNeeded) {
144 // We might need to do something if the kernel was visited.
145 } else {
146 }
147
148 // ...before finally...
149 FinishView (); // Flush streams and/or swap buffers.
150}
151
152void G4Qt3DViewer::ShowView()
153{
154 show();
155}
156
157void G4Qt3DViewer::FinishView()
158{
159 show();
160}
161
162void G4Qt3DViewer::SwitchToVisSubThread()
163{
164// fUIWidget->moveToThread(QThread::currentThread());
165// moveToThread(QThread::currentThread());
166// fQt3DSceneHandler.fpQt3DScene->moveToThread(QThread::currentThread());
167// fQt3DSceneHandler.fpTransientObjects->moveToThread(QThread::currentThread());
168#ifdef G4QT3DDEBUG
169// G4cout
170// << "G4Qt3DViewer::SwitchToVisSubThread: (void*)fQt3DSceneHandler.fpQt3DScene: "
171// << (void*)fQt3DSceneHandler.fpQt3DScene
172// << G4endl;
173#endif
174}
175
176void G4Qt3DViewer::SwitchToMasterThread()
177{
178// fUIWidget->moveToThread(QThread::currentThread());
179// moveToThread(QThread::currentThread());
180// fQt3DSceneHandler.fpQt3DScene->moveToThread(QThread::currentThread());
181// fQt3DSceneHandler.fpTransientObjects->moveToThread(QThread::currentThread());
182#ifdef G4QT3DDEBUG
183// G4cout
184// << "G4Qt3DViewer::SwitchToMasterThread: (void*)fQt3DSceneHandler.fpQt3DScene: "
185// << (void*)fQt3DSceneHandler.fpQt3DScene
186// << G4endl;
187#endif
188
189#ifdef G4MULTITHREADED
191 // I have not figured out how to draw during a run. In fact, even attempting
192 // to fill nodes gives the error "Cannot create children for a parent that
193 // is in a different thread." So instead draw events from kept events.
194 //
195 // Setting fNeedKernelVisit=true causes scene deletion and a complete rebuild,
196 // including trajectories, hits, etc. from kept events.
197 //
198 // Clearly this is a limitation because even if you run 1000 events you only
199 // get those kept (default 100), and even worse, if end-if-event-action is
200 // "refresh", you only get one event (the last I think).
201 //
202 // Also, strictly, there is no need to rebuid run-duration models (detector),
203 // but a complete rebuild is the easiest way (already imeplemented).
204 fNeedKernelVisit = true;
205 DrawView(); // Draw trajectories, etc., from kept events
206 }
207#endif
208}
209
210void G4Qt3DViewer::KernelVisitDecision () {
211
212 // If there's a significant difference with the last view parameters
213 // of either the scene handler or this viewer, trigger a rebuild.
214
215 if (CompareForKernelVisit(fLastVP)) {
216 NeedKernelVisit (); // Sets fNeedKernelVisit.
217 }
218}
219
220G4bool G4Qt3DViewer::CompareForKernelVisit(G4ViewParameters& lastVP)
221{
222 // Typical comparison. Taken from OpenGL.
223 if (
224 (lastVP.GetDrawingStyle () != fVP.GetDrawingStyle ()) ||
225 (lastVP.GetNumberOfCloudPoints() != fVP.GetNumberOfCloudPoints()) ||
226 (lastVP.IsAuxEdgeVisible () != fVP.IsAuxEdgeVisible ()) ||
227 (lastVP.IsCulling () != fVP.IsCulling ()) ||
228 (lastVP.IsCullingInvisible () != fVP.IsCullingInvisible ()) ||
229 (lastVP.IsDensityCulling () != fVP.IsDensityCulling ()) ||
230 (lastVP.IsCullingCovered () != fVP.IsCullingCovered ()) ||
231 (lastVP.GetCBDAlgorithmNumber() !=
232 fVP.GetCBDAlgorithmNumber()) ||
233 (lastVP.IsSection () != fVP.IsSection ()) ||
234 (lastVP.IsCutaway () != fVP.IsCutaway ()) ||
235 (lastVP.IsExplode () != fVP.IsExplode ()) ||
236 (lastVP.GetNoOfSides () != fVP.GetNoOfSides ()) ||
237 (lastVP.GetGlobalMarkerScale() != fVP.GetGlobalMarkerScale()) ||
238 (lastVP.GetGlobalLineWidthScale() != fVP.GetGlobalLineWidthScale()) ||
239 (lastVP.IsMarkerNotHidden () != fVP.IsMarkerNotHidden ()) ||
240 (lastVP.GetDefaultVisAttributes()->GetColour() !=
241 fVP.GetDefaultVisAttributes()->GetColour()) ||
243 fVP.GetDefaultTextVisAttributes()->GetColour()) ||
244 (lastVP.GetBackgroundColour ()!= fVP.GetBackgroundColour ())||
245 (lastVP.IsPicking () != fVP.IsPicking ()) ||
246 (lastVP.GetVisAttributesModifiers() !=
247 fVP.GetVisAttributesModifiers())
248 ) {
249 return true;
250 }
251
252 if (lastVP.IsDensityCulling () &&
253 (lastVP.GetVisibleDensity () != fVP.GetVisibleDensity ()))
254 return true;
255
256 if (lastVP.GetCBDAlgorithmNumber() > 0) {
257 if (lastVP.GetCBDParameters().size() != fVP.GetCBDParameters().size()) return true;
258 else if (lastVP.GetCBDParameters() != fVP.GetCBDParameters()) return true;
259 }
260
261 if (lastVP.IsExplode () &&
262 (lastVP.GetExplodeFactor () != fVP.GetExplodeFactor ()))
263 return true;
264
265 return false;
266}
267
268void G4Qt3DViewer::keyPressEvent(QKeyEvent* ev)
269{
270 fKeyPressed = true;
271 fKey = ev->key();
272}
273
274void G4Qt3DViewer::keyReleaseEvent(QKeyEvent* /*ev*/)
275{
276 fKeyPressed = false;
277}
278
279void G4Qt3DViewer::mouseDoubleClickEvent(QMouseEvent* /*ev*/) {}
280
281void G4Qt3DViewer::mouseMoveEvent(QMouseEvent* ev)
282{
283 // I think we only want these if a mouse button is pressed.
284 // But they come even when not pressed (on my MacBook Pro trackpad).
285 // Documentation says:
286 /* Mouse move events will occur only when a mouse button is pressed down,
287 unless mouse tracking has been enabled with QWidget::setMouseTracking().*/
288 // But this is a window not a widget.
289 // As a workaround we maintain a flag changed by mousePress/ReleaseEvent.
290
291 G4double x = ev->x();
292 G4double y = ev->y();
293 G4double dx = x-fMousePressedX;
294 G4double dy = y-fMousePressedY;
295 fMousePressedX = x;
296 fMousePressedY = y;
297
298 if (fMousePressed) {
299
300 if (fKeyPressed && fKey == Qt::Key_Shift) { // Translation (pan)
301
302 const G4double sceneRadius = fQt3DSceneHandler.fpScene->GetExtent().GetExtentRadius();
303 const G4double scale = 300; // Roughly pixels per window, empirically chosen
304 const G4double dxScene = dx*sceneRadius/scale;
305 const G4double dyScene = dy*sceneRadius/scale;
306 fVP.IncrementPan(-dxScene,dyScene);
307
308 } else { // Rotation
309
310 // Simple ad-hoc algorithms
311 const G4Vector3D& x_prime = fVP.GetViewpointDirection().cross(fVP.GetUpVector());
312 const G4Vector3D& y_prime = x_prime.cross(fVP.GetViewpointDirection());
313 const G4double scale = 200; // Roughly pixels per window, empirically chosen
314 G4Vector3D newViewpointDirection = fVP.GetViewpointDirection();
315 newViewpointDirection += dx*x_prime/scale;
316 newViewpointDirection += dy*y_prime/scale;
317 fVP.SetViewpointDirection(newViewpointDirection.unit());
318
319 if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) {
320 G4Vector3D newUpVector = fVP.GetUpVector();
321 newUpVector += dx*x_prime/scale;
322 newUpVector += dy*y_prime/scale;
323 fVP.SetUpVector(newUpVector.unit());
324 }
325 }
326 }
327
328 SetView();
329 DrawView();
330}
331
332void G4Qt3DViewer::mousePressEvent(QMouseEvent* ev)
333{
334 fMousePressed = true;
335 fMousePressedX = ev->x();
336 fMousePressedY = ev->y();
337}
338
339void G4Qt3DViewer::mouseReleaseEvent(QMouseEvent* /*ev*/)
340{
341 fMousePressed = false;
342}
343
344void G4Qt3DViewer::wheelEvent(QWheelEvent* ev)
345{
346 // Take note of up-down motion only
347 const G4double angleY = ev->angleDelta().y();
348
349 if (fVP.GetFieldHalfAngle() == 0.) { // Orthographic projection
350 const G4double scale = 500; // Empirically chosen
351 fVP.MultiplyZoomFactor(1.+angleY/scale);
352 } else { // Perspective projection
353 const G4double scale = fVP.GetFieldHalfAngle()/(10.*deg); // Empirical
354 fVP.SetDolly(fVP.GetDolly()+angleY/scale);
355 }
356
357 SetView();
358 DrawView();
359}
360
361#endif // #if defined (G4VIS_BUILD_QT3D_DRIVER) || defined (G4VIS_USE_QT3D)
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
static G4bool GetColour(const G4String &key, G4Colour &result)
Definition: G4Colour.cc:162
static G4Colour Black()
Definition: G4Colour.hh:157
static G4UImanager * GetUIpointer()
Definition: G4UImanager.cc:77
const std::vector< G4ModelingParameters::VisAttributesModifier > & GetVisAttributesModifiers() const
G4int GetNoOfSides() const
G4double GetExplodeFactor() const
G4int GetNumberOfCloudPoints() const
G4bool IsMarkerNotHidden() const
G4double GetGlobalLineWidthScale() const
G4bool IsCutaway() const
const G4Colour & GetBackgroundColour() const
G4bool IsSection() const
G4bool IsPicking() const
G4bool IsCulling() const
const G4VisAttributes * GetDefaultTextVisAttributes() const
G4bool IsExplode() const
const std::vector< G4double > & GetCBDParameters() const
G4int GetCBDAlgorithmNumber() const
G4double GetGlobalMarkerScale() const
G4bool IsCullingInvisible() const
const G4VisAttributes * GetDefaultVisAttributes() const
G4bool IsDensityCulling() const
G4double GetVisibleDensity() const
G4bool IsCullingCovered() const
DrawingStyle GetDrawingStyle() const
G4bool IsAuxEdgeVisible() const
const G4Colour & GetColour() const
BasicVector3D< T > cross(const BasicVector3D< T > &v) const
BasicVector3D< T > unit() const
const char * name(G4int ptype)
G4bool IsMultithreadedApplication()
Definition: G4Threading.cc:130