Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // John Allison 17th June 2019 26 // John Allison 17th June 2019 27 27 >> 28 #if defined (G4VIS_BUILD_QT3D_DRIVER) || defined (G4VIS_USE_QT3D) >> 29 28 #include "G4Qt3DViewer.hh" 30 #include "G4Qt3DViewer.hh" 29 31 30 #include "G4Qt3DSceneHandler.hh" 32 #include "G4Qt3DSceneHandler.hh" 31 #include "G4Qt3DUtils.hh" 33 #include "G4Qt3DUtils.hh" 32 34 33 #include "G4Scene.hh" 35 #include "G4Scene.hh" 34 #include "G4UImanager.hh" 36 #include "G4UImanager.hh" 35 #include "G4UIQt.hh" 37 #include "G4UIQt.hh" 36 #include "G4SystemOfUnits.hh" 38 #include "G4SystemOfUnits.hh" 37 39 38 #define G4warn G4cout << 39 << 40 G4Qt3DViewer::G4Qt3DViewer 40 G4Qt3DViewer::G4Qt3DViewer 41 (G4Qt3DSceneHandler& sceneHandler, const G4Str 41 (G4Qt3DSceneHandler& sceneHandler, const G4String& name) 42 : G4VViewer(sceneHandler, sceneHandler.Increme 42 : G4VViewer(sceneHandler, sceneHandler.IncrementViewCount(), name) 43 , fQt3DSceneHandler(sceneHandler) 43 , fQt3DSceneHandler(sceneHandler) 44 , fKeyPressed(false) 44 , fKeyPressed(false) 45 , fMousePressed(false) 45 , fMousePressed(false) 46 , fMousePressedX(0.) 46 , fMousePressedX(0.) 47 , fMousePressedY(0.) 47 , fMousePressedY(0.) 48 {} 48 {} 49 49 50 void G4Qt3DViewer::Initialise() 50 void G4Qt3DViewer::Initialise() 51 { 51 { 52 setObjectName(fName.c_str()); 52 setObjectName(fName.c_str()); 53 53 54 fVP.SetAutoRefresh(true); 54 fVP.SetAutoRefresh(true); 55 fDefaultVP.SetAutoRefresh(true); 55 fDefaultVP.SetAutoRefresh(true); 56 56 >> 57 // Background is white (not figured out how to change it) so... >> 58 fVP.SetDefaultColour(G4Colour::Black()); >> 59 fDefaultVP.SetDefaultColour(G4Colour::Black()); >> 60 57 auto UI = G4UImanager::GetUIpointer(); 61 auto UI = G4UImanager::GetUIpointer(); 58 auto uiQt = dynamic_cast<G4UIQt*>(UI->GetG4U 62 auto uiQt = dynamic_cast<G4UIQt*>(UI->GetG4UIWindow()); 59 if (!uiQt) { 63 if (!uiQt) { 60 fViewId = -1; // This flags an error. 64 fViewId = -1; // This flags an error. 61 G4warn << "G4Qt3DViewer::G4Qt3DViewer requ << 65 G4cerr << "G4Qt3DViewer::G4Qt3DViewer requires G4UIQt" 62 << G4endl; 66 << G4endl; 63 return; 67 return; 64 } 68 } 65 fUIWidget = QWidget::createWindowContainer(t 69 fUIWidget = QWidget::createWindowContainer(this); 66 uiQt->AddTabWidget(fUIWidget,QString(fName)) 70 uiQt->AddTabWidget(fUIWidget,QString(fName)); 67 71 68 setRootEntity(fQt3DSceneHandler.fpQt3DScene) 72 setRootEntity(fQt3DSceneHandler.fpQt3DScene); 69 } 73 } 70 74 71 G4Qt3DViewer::~G4Qt3DViewer() 75 G4Qt3DViewer::~G4Qt3DViewer() 72 { << 76 {} 73 setRootEntity(nullptr); << 74 } << 75 << 76 void G4Qt3DViewer::resizeEvent(QResizeEvent*) << 77 SetView(); << 78 } << 79 77 80 void G4Qt3DViewer::SetView() 78 void G4Qt3DViewer::SetView() 81 { 79 { 82 // Background colour << 83 defaultFrameGraph()->setClearColor(G4Qt3DUti << 84 << 85 // Get radius of scene, etc. 80 // Get radius of scene, etc. 86 // Note that this procedure properly takes i 81 // Note that this procedure properly takes into account zoom, dolly and pan. 87 const G4Point3D targetPoint 82 const G4Point3D targetPoint 88 = fSceneHandler.GetScene()->GetStandardTar 83 = fSceneHandler.GetScene()->GetStandardTargetPoint() 89 + fVP.GetCurrentTargetPoint (); 84 + fVP.GetCurrentTargetPoint (); 90 G4double radius = fSceneHandler.GetScene()-> 85 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius(); 91 if(radius<=0.) radius = 1.; 86 if(radius<=0.) radius = 1.; 92 const G4double cameraDistance = fVP.GetCamer 87 const G4double cameraDistance = fVP.GetCameraDistance (radius); 93 const G4Point3D cameraPosition = 88 const G4Point3D cameraPosition = 94 targetPoint + cameraDistance * fVP.GetView 89 targetPoint + cameraDistance * fVP.GetViewpointDirection().unit(); 95 const GLdouble pnear = fVP.GetNearDistance 90 const GLdouble pnear = fVP.GetNearDistance (cameraDistance, radius); 96 const GLdouble pfar = fVP.GetFarDistance 91 const GLdouble pfar = fVP.GetFarDistance (cameraDistance, pnear, radius); 97 const GLdouble right = fVP.GetFrontHalfHeig 92 const GLdouble right = fVP.GetFrontHalfHeight (pnear, radius); 98 const GLdouble left = -right; 93 const GLdouble left = -right; 99 const GLdouble top = fVP.GetFrontHalfHeig 94 const GLdouble top = fVP.GetFrontHalfHeight (pnear, radius); 100 const GLdouble bottom = -top; 95 const GLdouble bottom = -top; 101 96 102 camera()->setObjectName((fName + " camera"). 97 camera()->setObjectName((fName + " camera").c_str()); 103 camera()->setViewCenter(G4Qt3DUtils::Convert 98 camera()->setViewCenter(G4Qt3DUtils::ConvertToQVector3D(targetPoint)); 104 camera()->setPosition(G4Qt3DUtils::ConvertTo 99 camera()->setPosition(G4Qt3DUtils::ConvertToQVector3D(cameraPosition)); 105 camera()->setUpVector(G4Qt3DUtils::ConvertTo 100 camera()->setUpVector(G4Qt3DUtils::ConvertToQVector3D(fVP.GetUpVector())); 106 101 107 // auto lightEntity = new Qt3DCore::QEntity(f 102 // auto lightEntity = new Qt3DCore::QEntity(fQt3DSceneHandler.fpQt3DScene); 108 // auto directionalLight = new Qt3DRender::QD 103 // auto directionalLight = new Qt3DRender::QDirectionalLight(lightEntity); 109 //// directionalLight->setColor("white"); 104 //// directionalLight->setColor("white"); 110 //// directionalLight->setIntensity(1.); 105 //// directionalLight->setIntensity(1.); 111 // directionalLight->setWorldDirection(G4Qt3D 106 // directionalLight->setWorldDirection(G4Qt3DUtils::ConvertToQVector3D(fVP.GetActualLightpointDirection())); 112 // lightEntity->addComponent(directionalLight 107 // lightEntity->addComponent(directionalLight); 113 108 114 const auto& size = fUIWidget->size(); 109 const auto& size = fUIWidget->size(); 115 G4double w = size.width(); 110 G4double w = size.width(); 116 G4double h = size.height(); 111 G4double h = size.height(); 117 #ifdef G4QT3DDEBUG 112 #ifdef G4QT3DDEBUG 118 // Curiously w,h are wrong first time - 640, 113 // Curiously w,h are wrong first time - 640,480 instead of (my Mac) 991,452. 119 G4cout << "W,H: " << w << ',' << h << G4endl 114 G4cout << "W,H: " << w << ',' << h << G4endl; 120 #endif 115 #endif 121 const G4double aspectRatio = w/h; 116 const G4double aspectRatio = w/h; 122 if (fVP.GetFieldHalfAngle() == 0.) { 117 if (fVP.GetFieldHalfAngle() == 0.) { 123 camera()->lens()->setOrthographicProjectio 118 camera()->lens()->setOrthographicProjection 124 (left*aspectRatio,right*aspectRatio,bottom 119 (left*aspectRatio,right*aspectRatio,bottom,top,pnear,pfar); 125 } else { 120 } else { 126 camera()->lens()->setPerspectiveProjection 121 camera()->lens()->setPerspectiveProjection 127 (2.*fVP.GetFieldHalfAngle()/deg,aspectRati 122 (2.*fVP.GetFieldHalfAngle()/deg,aspectRatio,pnear,pfar); 128 } 123 } 129 } 124 } 130 125 131 void G4Qt3DViewer::ClearView() 126 void G4Qt3DViewer::ClearView() 132 {} 127 {} 133 128 134 void G4Qt3DViewer::DrawView() 129 void G4Qt3DViewer::DrawView() 135 { 130 { 136 // First, a view should decide when to re-vi 131 // First, a view should decide when to re-visit the G4 kernel. 137 // Sometimes it might not be necessary, e.g. 132 // Sometimes it might not be necessary, e.g., if the scene is stored 138 // in a graphical database (e.g., OpenGL's d 133 // in a graphical database (e.g., OpenGL's display lists) and only 139 // the viewing angle has changed. But graph 134 // the viewing angle has changed. But graphics systems without a 140 // graphical database will always need to vi 135 // graphical database will always need to visit the G4 kernel. 141 136 142 // The fNeedKernelVisit flag might have been 137 // The fNeedKernelVisit flag might have been set by the user in 143 // /vis/viewer/rebuild, but if not, make dec 138 // /vis/viewer/rebuild, but if not, make decision and set flag only 144 // if necessary... 139 // if necessary... 145 if (!fNeedKernelVisit) KernelVisitDecision() 140 if (!fNeedKernelVisit) KernelVisitDecision(); 146 G4bool kernelVisitWasNeeded = fNeedKernelVis 141 G4bool kernelVisitWasNeeded = fNeedKernelVisit; // Keep (ProcessView resets). 147 fLastVP = fVP; 142 fLastVP = fVP; 148 143 149 ProcessView (); // Clears store and process 144 ProcessView (); // Clears store and processes scene only if necessary. 150 145 151 if (kernelVisitWasNeeded) { 146 if (kernelVisitWasNeeded) { 152 // We might need to do something if the ke 147 // We might need to do something if the kernel was visited. 153 } else { 148 } else { 154 } 149 } 155 150 156 // ...before finally... 151 // ...before finally... 157 FinishView (); // Flush streams and/or 152 FinishView (); // Flush streams and/or swap buffers. 158 } 153 } 159 154 160 void G4Qt3DViewer::ShowView() 155 void G4Qt3DViewer::ShowView() 161 { 156 { 162 #if QT_VERSION < 0x060000 << 157 show(); 163 // show() may only be called from master thr << 164 if (G4Threading::IsMasterThread()) { << 165 show(); << 166 } << 167 // The way Qt seems to work, we don't seem t << 168 // we'll leave it in - it seems not to have << 169 #endif << 170 } 158 } 171 159 172 void G4Qt3DViewer::FinishView() 160 void G4Qt3DViewer::FinishView() 173 { 161 { 174 #if QT_VERSION < 0x060000 << 162 show(); 175 if (G4Threading::IsMasterThread()) { << 176 show(); << 177 } << 178 #endif << 179 } << 180 << 181 // Note: the order of calling of MovingToVisSu << 182 // is undefined. The order of calling is << 183 // DoneWithMasterThread << 184 // MovingToVisSubThread ) or ( SwitchToVisSu << 185 // SwitchToVisSubThread ) ( MovingToVisSu << 186 // DoneWithVisSubThread << 187 // MovingToMasterThread << 188 // SwitchToMasterThread << 189 // So regarding the move/switch to the vis sub << 190 // If the viewer wishes to accept drawing from << 191 // But at this point we are still on the maste << 192 // not known. So it has to wait - a conditiona << 193 // and the provision of a pointer to the QThre << 194 // sub-thread has to wait until the QObjects h << 195 << 196 namespace { << 197 QThread* masterQThread = nullptr; << 198 QThread* visSubThreadQThread = nullptr; << 199 << 200 G4Mutex visSubThreadMutex = G4MUTEX_INITIALI << 201 G4Condition waitForVisSubThreadInitialized = << 202 G4bool visSubThreadEstablished = false; << 203 G4bool qObjectsSwitched = false; << 204 } << 205 << 206 void G4Qt3DViewer::MovingToVisSubThread() << 207 // Still on master thread but vis thread has b << 208 { << 209 // Make note of master QThread << 210 masterQThread = QThread::currentThread(); << 211 << 212 // Wait until SwitchToVisSubThread has found << 213 { << 214 G4AutoLock lock(&visSubThreadMutex); << 215 G4CONDITIONWAITLAMBDA(&waitForVisSubThreadIn << 216 } << 217 << 218 // Move relevant stuff to vis sub-thread QTh << 219 auto p1 = fQt3DSceneHandler.fpQt3DScene->par << 220 if(p1) { << 221 auto p2 = p1->parent(); << 222 if(p2) { << 223 p2->moveToThread(visSubThreadQThread); << 224 } else { << 225 p1->moveToThread(visSubThreadQThread); << 226 } << 227 } << 228 << 229 // Inform sub-thread << 230 G4AutoLock lock(&visSubThreadMutex); << 231 qObjectsSwitched = true; << 232 lock.unlock(); << 233 G4CONDITIONBROADCAST(&waitForVisSubThreadIni << 234 } 163 } 235 164 236 void G4Qt3DViewer::SwitchToVisSubThread() 165 void G4Qt3DViewer::SwitchToVisSubThread() 237 // On vis sub-thread before any drawing << 238 { << 239 // Make note of vis-subthread QThread for Mo << 240 visSubThreadQThread = QThread::currentThread << 241 << 242 // Let MovingToVisSubThread know we have the << 243 { << 244 G4AutoLock lock(&visSubThreadMutex); << 245 visSubThreadEstablished = true; << 246 G4CONDITIONBROADCAST(&waitForVisSubThreadIni << 247 } << 248 << 249 // Wait until MovingToVisSubThread has moved << 250 { << 251 G4AutoLock lock(&visSubThreadMutex); << 252 G4CONDITIONWAITLAMBDA(&waitForVisSubThreadIn << 253 } << 254 } << 255 << 256 void G4Qt3DViewer::MovingToMasterThread() << 257 // On vis sub-thread just before exit << 258 { 166 { 259 // Move relevant stuff to master QThread. << 167 // fUIWidget->moveToThread(QThread::currentThread()); 260 auto p1 = fQt3DSceneHandler.fpQt3DScene->par << 168 // moveToThread(QThread::currentThread()); 261 if(p1) { << 169 // fQt3DSceneHandler.fpQt3DScene->moveToThread(QThread::currentThread()); 262 auto p2 = p1->parent(); << 170 // fQt3DSceneHandler.fpTransientObjects->moveToThread(QThread::currentThread()); 263 if(p2) { << 171 #ifdef G4QT3DDEBUG 264 p2->moveToThread(masterQThread); << 172 // G4cout 265 } else { << 173 // << "G4Qt3DViewer::SwitchToVisSubThread: (void*)fQt3DSceneHandler.fpQt3DScene: " 266 p1->moveToThread(masterQThread); << 174 // << (void*)fQt3DSceneHandler.fpQt3DScene 267 } << 175 // << G4endl; 268 } << 176 #endif 269 << 270 // Reset << 271 visSubThreadQThread = nullptr; << 272 qObjectsSwitched = false; << 273 } 177 } 274 178 275 void G4Qt3DViewer::SwitchToMasterThread() 179 void G4Qt3DViewer::SwitchToMasterThread() 276 // On master thread after vis sub-thread has t << 277 { 180 { 278 visSubThreadEstablished = false; << 181 // fUIWidget->moveToThread(QThread::currentThread()); >> 182 // moveToThread(QThread::currentThread()); >> 183 // fQt3DSceneHandler.fpQt3DScene->moveToThread(QThread::currentThread()); >> 184 // fQt3DSceneHandler.fpTransientObjects->moveToThread(QThread::currentThread()); >> 185 #ifdef G4QT3DDEBUG >> 186 // G4cout >> 187 // << "G4Qt3DViewer::SwitchToMasterThread: (void*)fQt3DSceneHandler.fpQt3DScene: " >> 188 // << (void*)fQt3DSceneHandler.fpQt3DScene >> 189 // << G4endl; >> 190 #endif >> 191 >> 192 #ifdef G4MULTITHREADED >> 193 if (G4Threading::IsMultithreadedApplication()) { >> 194 // I have not figured out how to draw during a run. In fact, even attempting >> 195 // to fill nodes gives the error "Cannot create children for a parent that >> 196 // is in a different thread." So instead draw events from kept events. >> 197 // >> 198 // Setting fNeedKernelVisit=true causes scene deletion and a complete rebuild, >> 199 // including trajectories, hits, etc. from kept events. >> 200 // >> 201 // Clearly this is a limitation because even if you run 1000 events you only >> 202 // get those kept (default 100), and even worse, if end-if-event-action is >> 203 // "refresh", you only get one event (the last I think). >> 204 // >> 205 // Also, strictly, there is no need to rebuid run-duration models (detector), >> 206 // but a complete rebuild is the easiest way (already imeplemented). >> 207 fNeedKernelVisit = true; >> 208 DrawView(); // Draw trajectories, etc., from kept events >> 209 } >> 210 #endif 279 } 211 } 280 212 281 void G4Qt3DViewer::KernelVisitDecision () { 213 void G4Qt3DViewer::KernelVisitDecision () { 282 214 283 // If there's a significant difference with 215 // If there's a significant difference with the last view parameters 284 // of either the scene handler or this viewe 216 // of either the scene handler or this viewer, trigger a rebuild. 285 217 286 if (CompareForKernelVisit(fLastVP)) { 218 if (CompareForKernelVisit(fLastVP)) { 287 NeedKernelVisit (); // Sets fNeedKernelVi 219 NeedKernelVisit (); // Sets fNeedKernelVisit. 288 } 220 } 289 } 221 } 290 222 291 G4bool G4Qt3DViewer::CompareForKernelVisit(G4V << 223 G4bool G4Qt3DViewer::CompareForKernelVisit(G4ViewParameters& lastVP) 292 { 224 { 293 // Typical comparison. Taken from OpenInven << 225 // Typical comparison. Taken from OpenGL. 294 if ( 226 if ( 295 (vp.GetDrawingStyle () != fVP.GetDrawi << 227 (lastVP.GetDrawingStyle () != fVP.GetDrawingStyle ()) || 296 (vp.GetNumberOfCloudPoints() != fVP.GetN << 228 (lastVP.GetNumberOfCloudPoints() != fVP.GetNumberOfCloudPoints()) || 297 (vp.IsAuxEdgeVisible () != fVP.IsAuxEdg << 229 (lastVP.IsAuxEdgeVisible () != fVP.IsAuxEdgeVisible ()) || 298 (vp.IsCulling () != fVP.IsCullin << 230 (lastVP.IsCulling () != fVP.IsCulling ()) || 299 (vp.IsCullingInvisible () != fVP.IsCullin << 231 (lastVP.IsCullingInvisible () != fVP.IsCullingInvisible ()) || 300 (vp.IsDensityCulling () != fVP.IsDensit << 232 (lastVP.IsDensityCulling () != fVP.IsDensityCulling ()) || 301 (vp.IsCullingCovered () != fVP.IsCullin << 233 (lastVP.IsCullingCovered () != fVP.IsCullingCovered ()) || 302 (vp.GetCBDAlgorithmNumber() != << 234 (lastVP.GetCBDAlgorithmNumber() != 303 fVP.GetCBDAlgorithmNumber()) << 235 fVP.GetCBDAlgorithmNumber()) || 304 (vp.IsSection () != fVP.IsSectio << 236 (lastVP.IsSection () != fVP.IsSection ()) || 305 (vp.IsCutaway () != fVP.IsCutawa << 237 (lastVP.IsCutaway () != fVP.IsCutaway ()) || 306 // This assumes use of generic clipping ( << 238 (lastVP.IsExplode () != fVP.IsExplode ()) || 307 // DCUT, cutaway). If a decision is made << 239 (lastVP.GetNoOfSides () != fVP.GetNoOfSides ()) || 308 // this will need changing. See G4OpenGL << 240 (lastVP.GetGlobalMarkerScale() != fVP.GetGlobalMarkerScale()) || 309 // G4OpenGLStoredViewer.cc::CompareForKer << 241 (lastVP.GetGlobalLineWidthScale() != fVP.GetGlobalLineWidthScale()) || 310 // G4OpenGLStoredSceneHander::CreateSecti << 242 (lastVP.IsMarkerNotHidden () != fVP.IsMarkerNotHidden ()) || 311 (vp.IsExplode () != fVP.IsExplod << 243 (lastVP.GetDefaultVisAttributes()->GetColour() != 312 (vp.GetNoOfSides () != fVP.GetNoOfS << 244 fVP.GetDefaultVisAttributes()->GetColour()) || 313 (vp.GetGlobalMarkerScale() != fVP.GetG << 245 (lastVP.GetDefaultTextVisAttributes()->GetColour() != 314 (vp.GetGlobalLineWidthScale() != fVP.GetG << 246 fVP.GetDefaultTextVisAttributes()->GetColour()) || 315 (vp.IsMarkerNotHidden () != fVP.IsMarker << 247 (lastVP.GetBackgroundColour ()!= fVP.GetBackgroundColour ())|| 316 (vp.GetDefaultVisAttributes()->GetColour( << 248 (lastVP.IsPicking () != fVP.IsPicking ()) || 317 fVP.GetDefaultVisAttributes()->GetColour << 249 (lastVP.GetVisAttributesModifiers() != 318 (vp.GetDefaultTextVisAttributes()->GetCol << 250 fVP.GetVisAttributesModifiers()) 319 fVP.GetDefaultTextVisAttributes()->GetCo << 251 ) { 320 (vp.GetBackgroundColour ()!= fVP.GetBackg << 321 (vp.IsPicking () != fVP.IsPickin << 322 // Scaling for Open Inventor is done by t << 323 // needs a kernel visit. (In this respec << 324 // OpenGL drivers, where it's done in Set << 325 (vp.GetScaleFactor () != fVP.GetScale << 326 (vp.GetVisAttributesModifiers() != << 327 fVP.GetVisAttributesModifiers()) << 328 (vp.IsSpecialMeshRendering() != << 329 fVP.IsSpecialMeshRendering()) << 330 (vp.GetSpecialMeshRenderingOption() != << 331 fVP.GetSpecialMeshRenderingOption()) << 332 ) << 333 return true; << 334 << 335 if (vp.IsDensityCulling () && << 336 (vp.GetVisibleDensity () != fVP.GetVisib << 337 return true; 252 return true; 338 << 339 if (vp.GetCBDAlgorithmNumber() > 0) { << 340 if (vp.GetCBDParameters().size() != fVP.Ge << 341 else if (vp.GetCBDParameters() != fVP.GetC << 342 } 253 } 343 254 344 if (vp.IsSection () && << 255 if (lastVP.IsDensityCulling () && 345 (vp.GetSectionPlane () != fVP.GetSection << 256 (lastVP.GetVisibleDensity () != fVP.GetVisibleDensity ())) 346 return true; 257 return true; 347 258 348 if (vp.IsCutaway ()) { << 259 if (lastVP.GetCBDAlgorithmNumber() > 0) { 349 if (vp.GetCutawayMode() != fVP.GetCutawayM << 260 if (lastVP.GetCBDParameters().size() != fVP.GetCBDParameters().size()) return true; 350 if (vp.GetCutawayPlanes ().size () != << 261 else if (lastVP.GetCBDParameters() != fVP.GetCBDParameters()) return true; 351 fVP.GetCutawayPlanes ().size ()) retur << 352 for (size_t i = 0; i < vp.GetCutawayPlanes << 353 if (vp.GetCutawayPlanes()[i] != fVP.GetCut << 354 return true; << 355 } 262 } 356 263 357 if (vp.IsExplode () && << 264 if (lastVP.IsExplode () && 358 (vp.GetExplodeFactor () != fVP.GetExplod << 265 (lastVP.GetExplodeFactor () != fVP.GetExplodeFactor ())) 359 return true; << 360 << 361 if (vp.IsSpecialMeshRendering() && << 362 (vp.GetSpecialMeshVolumes() != fVP.GetSp << 363 return true; 266 return true; 364 267 365 return false; 268 return false; 366 } 269 } 367 270 368 void G4Qt3DViewer::keyPressEvent(QKeyEvent* ev 271 void G4Qt3DViewer::keyPressEvent(QKeyEvent* ev) 369 { 272 { 370 fKeyPressed = true; 273 fKeyPressed = true; 371 fKey = ev->key(); 274 fKey = ev->key(); 372 } 275 } 373 276 374 void G4Qt3DViewer::keyReleaseEvent(QKeyEvent* 277 void G4Qt3DViewer::keyReleaseEvent(QKeyEvent* /*ev*/) 375 { 278 { 376 fKeyPressed = false; 279 fKeyPressed = false; 377 } 280 } 378 281 379 void G4Qt3DViewer::mouseDoubleClickEvent(QMous 282 void G4Qt3DViewer::mouseDoubleClickEvent(QMouseEvent* /*ev*/) {} 380 283 381 void G4Qt3DViewer::mouseMoveEvent(QMouseEvent* 284 void G4Qt3DViewer::mouseMoveEvent(QMouseEvent* ev) 382 { 285 { 383 // I think we only want these if a mouse but 286 // I think we only want these if a mouse button is pressed. 384 // But they come even when not pressed (on m 287 // But they come even when not pressed (on my MacBook Pro trackpad). 385 // Documentation says: 288 // Documentation says: 386 /* Mouse move events will occur only when a 289 /* Mouse move events will occur only when a mouse button is pressed down, 387 unless mouse tracking has been enabled with 290 unless mouse tracking has been enabled with QWidget::setMouseTracking().*/ 388 // But this is a window not a widget. 291 // But this is a window not a widget. 389 // As a workaround we maintain a flag change 292 // As a workaround we maintain a flag changed by mousePress/ReleaseEvent. 390 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) << 293 391 G4double x = ev->x(); 294 G4double x = ev->x(); 392 G4double y = ev->y(); 295 G4double y = ev->y(); 393 #else << 394 G4double x = ev->position().x(); << 395 G4double y = ev->position().y(); << 396 #endif << 397 G4double dx = x-fMousePressedX; 296 G4double dx = x-fMousePressedX; 398 G4double dy = y-fMousePressedY; 297 G4double dy = y-fMousePressedY; 399 fMousePressedX = x; 298 fMousePressedX = x; 400 fMousePressedY = y; 299 fMousePressedY = y; 401 300 402 if (fMousePressed) { 301 if (fMousePressed) { 403 302 404 if (fKeyPressed && fKey == Qt::Key_Shift) 303 if (fKeyPressed && fKey == Qt::Key_Shift) { // Translation (pan) 405 304 406 const G4double sceneRadius = fQt3DSceneH 305 const G4double sceneRadius = fQt3DSceneHandler.fpScene->GetExtent().GetExtentRadius(); 407 const G4double scale = 300; // Roughly 306 const G4double scale = 300; // Roughly pixels per window, empirically chosen 408 const G4double dxScene = dx*sceneRadius/ 307 const G4double dxScene = dx*sceneRadius/scale; 409 const G4double dyScene = dy*sceneRadius/ 308 const G4double dyScene = dy*sceneRadius/scale; 410 fVP.IncrementPan(-dxScene,dyScene); 309 fVP.IncrementPan(-dxScene,dyScene); 411 310 412 } else { // Rotation 311 } else { // Rotation 413 312 414 // Simple ad-hoc algorithms 313 // Simple ad-hoc algorithms 415 const G4Vector3D& x_prime = fVP.GetViewp 314 const G4Vector3D& x_prime = fVP.GetViewpointDirection().cross(fVP.GetUpVector()); 416 const G4Vector3D& y_prime = x_prime.cros 315 const G4Vector3D& y_prime = x_prime.cross(fVP.GetViewpointDirection()); 417 const G4double scale = 200; // Roughly 316 const G4double scale = 200; // Roughly pixels per window, empirically chosen 418 G4Vector3D newViewpointDirection = fVP.G 317 G4Vector3D newViewpointDirection = fVP.GetViewpointDirection(); 419 newViewpointDirection += dx*x_prime/scal 318 newViewpointDirection += dx*x_prime/scale; 420 newViewpointDirection += dy*y_prime/scal 319 newViewpointDirection += dy*y_prime/scale; 421 fVP.SetViewpointDirection(newViewpointDi 320 fVP.SetViewpointDirection(newViewpointDirection.unit()); 422 321 423 if (fVP.GetRotationStyle() == G4ViewPara 322 if (fVP.GetRotationStyle() == G4ViewParameters::freeRotation) { 424 G4Vector3D newUpVector = fVP.GetUpVect 323 G4Vector3D newUpVector = fVP.GetUpVector(); 425 newUpVector += dx*x_prime/scale; 324 newUpVector += dx*x_prime/scale; 426 newUpVector += dy*y_prime/scale; 325 newUpVector += dy*y_prime/scale; 427 fVP.SetUpVector(newUpVector.unit()); 326 fVP.SetUpVector(newUpVector.unit()); 428 } 327 } 429 } 328 } 430 } 329 } 431 330 432 SetView(); 331 SetView(); 433 DrawView(); 332 DrawView(); 434 } 333 } 435 334 436 void G4Qt3DViewer::mousePressEvent(QMouseEvent 335 void G4Qt3DViewer::mousePressEvent(QMouseEvent* ev) 437 { 336 { 438 fMousePressed = true; 337 fMousePressed = true; 439 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) << 440 fMousePressedX = ev->x(); 338 fMousePressedX = ev->x(); 441 fMousePressedY = ev->y(); 339 fMousePressedY = ev->y(); 442 #else << 443 fMousePressedX = ev->position().x(); << 444 fMousePressedY = ev->position().y(); << 445 #endif << 446 } 340 } 447 341 448 void G4Qt3DViewer::mouseReleaseEvent(QMouseEve 342 void G4Qt3DViewer::mouseReleaseEvent(QMouseEvent* /*ev*/) 449 { 343 { 450 fMousePressed = false; 344 fMousePressed = false; 451 } 345 } 452 346 453 void G4Qt3DViewer::wheelEvent(QWheelEvent* ev) 347 void G4Qt3DViewer::wheelEvent(QWheelEvent* ev) 454 { 348 { 455 // Take note of up-down motion only 349 // Take note of up-down motion only 456 const G4double angleY = ev->angleDelta().y() 350 const G4double angleY = ev->angleDelta().y(); 457 351 458 if (fVP.GetFieldHalfAngle() == 0.) { // Ort 352 if (fVP.GetFieldHalfAngle() == 0.) { // Orthographic projection 459 const G4double scale = 500; // Empiricall 353 const G4double scale = 500; // Empirically chosen 460 fVP.MultiplyZoomFactor(1.+angleY/scale); 354 fVP.MultiplyZoomFactor(1.+angleY/scale); 461 } else { // Per 355 } else { // Perspective projection 462 const G4double delta = fSceneHandler.GetEx << 356 const G4double scale = fVP.GetFieldHalfAngle()/(10.*deg); // Empirical 463 fVP.SetDolly(fVP.GetDolly()+angleY*delta); << 357 fVP.SetDolly(fVP.GetDolly()+angleY/scale); 464 } 358 } 465 359 466 SetView(); 360 SetView(); 467 DrawView(); 361 DrawView(); 468 } 362 } >> 363 >> 364 #endif // #if defined (G4VIS_BUILD_QT3D_DRIVER) || defined (G4VIS_USE_QT3D) 469 365