Geant4 Cross Reference |
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 27 // Frederick Jones TRIUMF 07 January 2018 28 29 #include "G4OpenInventorQtExaminerViewer.hh" 30 31 #include "ui_OIQtListsDialog.h" 32 33 #include "saveViewPt.h" 34 #include "pickext.h" 35 #include "pickref.h" 36 #include "wireframe.h" 37 38 #include <algorithm> // For using sort on a vector 39 40 #include "G4ios.hh" 41 #include "G4UImanager.hh" 42 #include "G4UIQt.hh" 43 44 #include <Inventor/Qt/SoQt.h> 45 #include <Inventor/Qt/SoQtCursor.h> 46 #include <Inventor/events/SoKeyboardEvent.h> 47 #include <Inventor/events/SoMouseButtonEvent.h> 48 #include <Inventor/events/SoLocation2Event.h> 49 #include <Inventor/nodes/SoSeparator.h> 50 #include <Inventor/nodes/SoOrthographicCamera.h> 51 #include <Inventor/nodes/SoPerspectiveCamera.h> 52 53 // FWJ moved to header file 54 //#include <Inventor/nodes/SoEventCallback.h> 55 #include <Inventor/nodes/SoLineSet.h> 56 #include <Inventor/nodes/SoMaterial.h> 57 #include <Inventor/errors/SoDebugError.h> 58 #include <Inventor/SoPickedPoint.h> 59 #include <Inventor/actions/SoWriteAction.h> 60 #include <Inventor/projectors/SbPlaneProjector.h> 61 62 #include <Inventor/sensors/SoTimerSensor.h> // Animation 63 #include <Inventor/sensors/SoNodeSensor.h> // Detect start of run 64 65 #include "Geant4_SoPolyhedron.h" 66 #include "G4TrajectoryPoint.hh" 67 #include "G4AttHolder.hh" 68 #include "G4AttCheck.hh" 69 #if 0x060000 <= QT_VERSION 70 #include "G4StateManager.hh" 71 #endif 72 73 #include <Inventor/nodes/SoCallback.h> 74 #include <Inventor/nodes/SoSwitch.h> 75 #include <Inventor/nodes/SoScale.h> 76 #include <Inventor/nodes/SoTranslation.h> 77 #include <Inventor/actions/SoSearchAction.h> 78 #include <Inventor/actions/SoGetBoundingBoxAction.h> 79 80 #include <Inventor/nodes/SoCoordinate3.h> 81 // For rendering distance during animation: 82 #include <Inventor/nodes/SoText2.h> 83 #include <Inventor/nodes/SoFont.h> 84 #include <Inventor/nodes/SoPointSet.h> 85 #include <Inventor/nodes/SoDrawStyle.h> 86 #include <Inventor/nodes/SoBaseColor.h> 87 88 // For searching for nodes within kits: 89 #include <Inventor/nodekits/SoBaseKit.h> 90 91 #include <QMenuBar> 92 #include <QPushButton> 93 #include <QRadioButton> 94 #include <QToolButton> 95 #include <QListWidget> 96 #include <QListWidgetItem> 97 #include <QInputDialog> 98 #include <QMessageBox> 99 #include <QFileDialog> 100 #include <QStyle> 101 #include <QCommonStyle> 102 //#include <QMainWindow> 103 104 #ifndef G4GMAKE 105 #include "moc_G4OpenInventorQtExaminerViewer.cpp" 106 #endif 107 108 #define G4warn G4cout 109 110 #if QT_VERSION < 0x060000 111 G4OpenInventorQtExaminerViewer* G4OpenInventorQtExaminerViewer::viewer = 0; 112 #endif 113 114 #define MIN_SPEED 2.1 // Lower number means faster 115 #define START_STEP 0.3 116 #define SPEED_INDICATOR_STEP 0.045 117 #define MAX_SPEED_INDICATOR 0.81 118 // Number of steps 90 degree rotation around an element is split into 119 #define ROT_CNT 6 120 121 122 // Constructor 123 G4OpenInventorQtExaminerViewer:: 124 G4OpenInventorQtExaminerViewer(QWidget* parent, const char* name, SbBool embed, 125 SoQtFullViewer::BuildFlag flag, 126 SoQtViewer::Type type) 127 : SoQtExaminerViewer(parent, name, embed, flag, type), 128 #if 0x060000 <= QT_VERSION 129 fName(name), 130 #endif 131 externalQtApp(0), processSoEventCount(0) 132 { 133 // FWJ DEBUG 134 // G4cout << "G4OpenInventorQtExaminerViewer CONSTRUCTOR CALLED" << G4endl; 135 // G4cout << "G4OpenInventorQtExaminerViewer parent=" << parent << G4endl; 136 137 // FWJ THIS DOESN'T WORK APPARENTLY NO MAINWINDOW 138 // QMenuBar* menubar = ((QMainWindow*)parent)->menuBar(); 139 140 #if QT_VERSION < 0x060000 141 fName = new QString(name); 142 viewer = this; 143 #endif 144 construct(TRUE); 145 } 146 147 // Destructor 148 G4OpenInventorQtExaminerViewer::~G4OpenInventorQtExaminerViewer() 149 { 150 // if (superimposition != NULL) { 151 // removeSuperimposition(superimposition); 152 // superimposition->unref(); 153 // superimposition = NULL; 154 // } 155 // if (animateSensor->isScheduled()) 156 // animateSensor->unschedule(); 157 // delete animateSensor; 158 // delete sceneChangeSensor; 159 // delete[] curViewPtName; 160 // delete searcher; 161 162 #if QT_VERSION < 0x060000 163 viewer = 0; 164 #else 165 delete hookBeamOn; 166 #endif 167 } 168 169 170 void G4OpenInventorQtExaminerViewer::construct(const SbBool) 171 { 172 setFeedbackSize(40); 173 174 hookBeamOn = new HookEventProcState(this); 175 newEvents = false; 176 177 buildWidget(getParentWidget()); 178 179 fileName = "bookmarkFile"; // Default viewpoint file name 180 viewPtIdx = -1; // index of the most recent viewpoint in viewPtList vector 181 182 animateSensor = new SoTimerSensor(animateSensorCB, this); 183 animateSensorRotation = new SoTimerSensor(animateSensorRotationCB, this); 184 animateBtwPtsPeriod = MIN_SPEED; 185 186 currentState = GENERAL; 187 myCam = new SoPerspectiveCamera; 188 MAX_VP_IDX = 3; 189 MAX_VP_NAME = 35; // Max length of a viewpoint name, padded with spaces 190 #if QT_VERSION < 0x060000 191 curViewPtName = new char[MAX_VP_NAME + 1]; 192 #else 193 curViewPtName.clear(); 194 #endif 195 left_right = up_down = 0; // For movements around the beam during animation 196 speedStep = START_STEP; // For smoother animation speed increase/decrease 197 rotUpVec = false; // Used during scene element rotations 198 step = 1; //By default 199 // Used for moving along the beam with the 200 // mouse instead of rotating the view 201 lshiftdown = rshiftdown = false; 202 // Used for rotating the view with the camera 203 // staying in place 204 lctrldown = rctrldown = false; 205 // Used to send abbreviated output to the console when 206 abbrOutputFlag = false; 207 pickRefPathFlag = false; 208 prevColorField = NULL; 209 // warningFlag = false; // We come from the warning dialog 210 // myElementList = NULL; 211 // FWJ default path look-ahead 212 pathLookahead = 5; 213 214 newSceneGraph = NULL; 215 zcoordSetFlag = false; 216 217 //////////////////////////SUPERIMPOSED SCENE////////////////////////// 218 searcher = NULL; 219 // Used in animation; progressively scaled for gradual speed change 220 maxSpeed = 0.0f; 221 222 static const char * superimposed[] = { 223 "#Inventor V2.1 ascii", "", 224 "Separator ", 225 "{", 226 " MaterialBinding ", 227 " {", 228 " value OVERALL", 229 " }", 230 " OrthographicCamera ", 231 " {", 232 " height 1", 233 " nearDistance 0", 234 " farDistance 1", 235 " }", 236 " DEF soxt->callback Callback { }", 237 " Separator ", 238 " {", 239 " DEF soxt->translation Translation ", 240 " {", 241 " translation 0 0 0", 242 " }", 243 " DEF soxt->scale Scale ", 244 " {", 245 " scaleFactor 1 1 1", 246 " }", 247 " DEF soxt->geometry Coordinate3 ", 248 " {", 249 " point ", 250 " [", 251 " -0.81 -0.04 0, -0.81 0 0,", 252 " -0.81 0.04 0, 0 -0.04 0,", 253 " 0 0 0, 0 0.04 0,", 254 " 0.81 -0.04 0, 0.81 0 0,", 255 " 0.81 0.04 0,", 256 " 0 0.02 0,", // idx 9 257 " 0.81 0.02 0, 0.81 -0.02 0,", 258 " 0 -0.02 0,", 259 " 0 0.01 0,", // idx 13 260 " 0.4 0.01 0, 0.4 -0.01 0,", 261 " 0 -0.01 0", 262 " ]", 263 " }", 264 // current speed indicator (outline) 265 " DEF soxt->animSpeedOutlineSwitch Switch ", 266 " {", 267 " whichChild -3", 268 " Material ", 269 " {", 270 " emissiveColor 0 0 0", 271 " }", 272 " IndexedFaceSet ", 273 " {", 274 " coordIndex ", 275 " [", 276 " 12, 11, 10, 9, -1", 277 " ]", 278 " }", 279 " }", 280 // the coordinate system 281 " DEF soxt->axisSwitch Switch ", 282 " {", 283 " whichChild -3", 284 " BaseColor ", 285 " {", 286 " rgb 1 1 1", 287 " }", 288 " IndexedLineSet ", 289 " {", 290 " coordIndex ", 291 " [", 292 " 0, 2, -1,", 293 " 3, 5, -1,", 294 " 6, 8, -1,", 295 " 1, 7, -1", 296 " ]", 297 " }", 298 " }", 299 // current speed indicator 300 " DEF soxt->animSpeedSwitch Switch ", 301 " {", 302 " whichChild -3", 303 " Material ", 304 " {", 305 " emissiveColor 0 1 0", 306 " }", 307 " IndexedFaceSet ", 308 " {", 309 " coordIndex ", 310 " [", 311 " 16, 15, 14, 13, -1", 312 " ]", 313 " }", 314 " }", 315 " }", 316 // For displaying either z position (during animation) or current viewpoint name 317 " DEF soxt->curInfoSwitch Switch ", 318 " {", 319 " whichChild -3", 320 " DEF soxt->curInfoTrans Translation ", 321 " {", 322 " translation 0 0 0 ", 323 // " translation 10 20 30 ", 324 " }", 325 " DEF soxt->curInfoFont Font ", 326 " {", 327 " name defaultFont:Bold", 328 " size 16", 329 " }", 330 " DEF soxt->curInfoText Text2 ", 331 " {", 332 " string Hello", 333 " }", 334 " }", 335 // Need to use different fields for mouseover 336 // because newlines are ignored when the scene is rendered 337 " Separator ", 338 " {", 339 " DEF soxt->mouseOverTransLogName Translation ", 340 " {", 341 " translation 0 0 0 ", 342 " }", 343 " DEF soxt->mouseOverFontLogName Font ", 344 " {", 345 " name defaultFont:Bold", 346 " size 16", 347 " }", 348 " DEF soxt->mouseOverTextLogName Text2 { } ", 349 " }", 350 " Separator ", 351 " {", 352 " DEF soxt->mouseOverTransSolid Translation ", 353 " {", 354 " translation 0 0 0 ", 355 " }", 356 " DEF soxt->mouseOverFontSolid Font ", 357 " {", 358 " name defaultFont:Bold", 359 " size 16", 360 " }", 361 " DEF soxt->mouseOverTextSolid Text2 { } ", 362 " }", 363 " Separator ", 364 " {", 365 " DEF soxt->mouseOverTransMaterial Translation ", 366 " {", 367 " translation 0 0 0 ", 368 " }", 369 " DEF soxt->mouseOverFontMaterial Font ", 370 " {", 371 " name defaultFont:Bold", 372 " size 16", 373 " }", 374 " DEF soxt->mouseOverTextMaterial Text2 { } ", 375 " }", 376 " Separator ", 377 " {", 378 " DEF soxt->mouseOverTransZPos Translation ", 379 " {", 380 " translation 0 0 0 ", 381 " }", 382 " DEF soxt->mouseOverFontZPos Font ", 383 " {", 384 " name defaultFont:Bold", 385 " size 16", 386 " }", 387 " DEF soxt->mouseOverTextZPos Text2 { } ", 388 " }", 389 "}", NULL 390 }; 391 392 int i, bufsize; 393 for (i = bufsize = 0; superimposed[i]; i++) 394 bufsize += strlen(superimposed[i]) + 1; 395 char * buf = new char[bufsize + 1]; 396 for (i = bufsize = 0; superimposed[i]; i++) { 397 strcpy(buf + bufsize, superimposed[i]); 398 bufsize += strlen(superimposed[i]); 399 buf[bufsize] = '\n'; 400 bufsize++; 401 } 402 SoInput * input = new SoInput; 403 input->setBuffer(buf, bufsize); 404 SbBool ok = SoDB::read(input, superimposition); 405 (void)ok; // FWJ added to avoid compiler warning 406 assert(ok); 407 delete input; 408 delete[] buf; 409 superimposition->ref(); 410 411 sscale = (SoScale *) getSuperimpositionNode(superimposition, "soxt->scale"); 412 stranslation = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->translation"); 413 sgeometry = (SoCoordinate3 *) getSuperimpositionNode(superimposition, "soxt->geometry"); 414 axisSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->axisSwitch"); 415 animSpeedOutlineSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->animSpeedOutlineSwitch"); 416 animSpeedSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->animSpeedSwitch"); 417 curInfoSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->curInfoSwitch"); 418 curInfoTrans = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->curInfoTrans"); 419 curInfoFont = (SoFont *) getSuperimpositionNode(superimposition, "soxt->curInfoFont"); 420 curInfoText = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->curInfoText"); 421 mouseOverTransLogName = (SoTranslation*)getSuperimpositionNode(superimposition, "soxt->mouseOverTransLogName"); 422 mouseOverFontLogName = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontLogName"); 423 mouseOverTextLogName = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextLogName"); 424 mouseOverTransSolid = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->mouseOverTransSolid"); 425 mouseOverFontSolid = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontSolid"); 426 mouseOverTextSolid = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextSolid"); 427 mouseOverTransMaterial = (SoTranslation*)getSuperimpositionNode(superimposition, "soxt->mouseOverTransMaterial"); 428 mouseOverFontMaterial = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontMaterial"); 429 mouseOverTextMaterial = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextMaterial"); 430 mouseOverTransZPos = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->mouseOverTransZPos"); 431 mouseOverFontZPos = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontZPos"); 432 mouseOverTextZPos = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextZPos"); 433 434 SoCallback * cb = (SoCallback *) getSuperimpositionNode(superimposition, "soxt->callback"); 435 cb->setCallback(superimpositionCB, this); 436 437 addSuperimposition(superimposition); 438 setSuperimpositionEnabled(superimposition, FALSE); 439 axisSwitch->whichChild.setValue(SO_SWITCH_NONE); 440 animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); 441 animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); 442 443 /////////////////////\SUPERIMPOSED SCENE/////////////////////////////////// 444 445 } 446 447 448 // Adds a menu bar and menu items to the viewer. 449 void G4OpenInventorQtExaminerViewer::buildWidget(QWidget* parent) 450 { 451 if (!parent) 452 SoDebugError::post("G4OpenInventorQtExaminerViewer::buildWidget", 453 "Error: Parent is null."); 454 455 // Common font for (almost) all widgets 456 font = new QFont; 457 font->setPointSize(12); 458 // This font setting does not propagate to added child widgets - Why? 459 parent->setFont(*font); 460 // This propagates everywhere but would affect UIQt! 461 // QApplication::setFont(*font); 462 463 // MENU BAR 464 465 #if QT_VERSION < 0x060000 466 menubar = new QMenuBar(getRenderAreaWidget()); 467 #else 468 menubar = new QMenuBar(); 469 menubar->setNativeMenuBar(false); 470 addAppPushButton(menubar); 471 #endif 472 // FWJ DEBUG 473 // G4cout << "G4OpenInventorQtExaminerViewer: GOT A menubar=" << 474 // menubar << G4endl; 475 476 filemenu = new QMenu("File"); 477 menubar->addMenu(filemenu); 478 479 FileOpenBookmark = new QAction("Open Bookmark File", this); 480 FileOpenBookmark->setFont(*font); 481 connect(FileOpenBookmark, SIGNAL(triggered()), this, 482 SLOT(FileOpenBookmarkCB())); 483 filemenu->addAction(FileOpenBookmark); 484 485 FileNewBookmark = new QAction("New Bookmark File", this); 486 FileNewBookmark->setFont(*font); 487 connect(FileNewBookmark, SIGNAL(triggered()), this, 488 SLOT(FileNewBookmarkCB())); 489 filemenu->addAction(FileNewBookmark); 490 491 FileLoadRefPath = new QAction("Load Reference Path", this); 492 FileLoadRefPath->setFont(*font); 493 connect(FileLoadRefPath, SIGNAL(triggered()), this, 494 SLOT(FileLoadRefPathCB())); 495 filemenu->addAction(FileLoadRefPath); 496 497 FileSaveRefPath = new QAction("Save Reference Path", this); 498 FileSaveRefPath->setFont(*font); 499 connect(FileSaveRefPath, SIGNAL(triggered()), this, 500 SLOT(FileSaveRefPathCB())); 501 filemenu->addAction(FileSaveRefPath); 502 503 FileLoadSceneGraph = new QAction("Load scene graph", this); 504 FileLoadSceneGraph->setFont(*font); 505 connect(FileLoadSceneGraph, SIGNAL(triggered()), this, 506 SLOT(FileLoadSceneGraphCB())); 507 filemenu->addAction(FileLoadSceneGraph); 508 509 FileSaveSceneGraph = new QAction("Save scene graph", this); 510 FileSaveSceneGraph->setFont(*font); 511 connect(FileSaveSceneGraph, SIGNAL(triggered()), this, 512 SLOT(FileSaveSceneGraphCB())); 513 filemenu->addAction(FileSaveSceneGraph); 514 515 // Rest of File menu is done in G4OpenInventorQtViewer 516 517 toolsmenu = new QMenu("Tools"); 518 menubar->addMenu(toolsmenu); 519 520 ToolsAnimateRefParticle = new QAction("Fly on Ref Path", this); 521 ToolsAnimateRefParticle->setFont(*font); 522 connect(ToolsAnimateRefParticle, SIGNAL(triggered()), this, 523 SLOT(ToolsAnimateRefParticleCB())); 524 toolsmenu->addAction(ToolsAnimateRefParticle); 525 526 ToolsRefPathStart = new QAction("Go to start of Ref Path", this); 527 ToolsRefPathStart->setFont(*font); 528 connect(ToolsRefPathStart, SIGNAL(triggered()), this, 529 SLOT(ToolsRefPathStartCB())); 530 toolsmenu->addAction(ToolsRefPathStart); 531 532 ToolsRefPathInvert = new QAction("Invert Ref Path", this); 533 ToolsRefPathInvert->setFont(*font); 534 connect(ToolsRefPathInvert, SIGNAL(triggered()), this, 535 SLOT(ToolsRefPathInvertCB())); 536 toolsmenu->addAction(ToolsRefPathInvert); 537 538 etcmenu = new QMenu("Etc"); 539 menubar->addMenu(etcmenu); 540 541 // All Etc menu items are done in G4OpenInventorQtViewer 542 543 helpmenu = new QMenu("Help"); 544 menubar->addMenu(helpmenu); 545 546 HelpControls = new QAction("Controls", this); 547 HelpControls->setFont(*font); 548 connect(HelpControls, SIGNAL(triggered()), this, SLOT(HelpControlsCB())); 549 helpmenu->addAction(HelpControls); 550 551 #if QT_VERSION < 0x060000 552 menubar->show(); 553 #endif 554 555 // SoQtExaminerViewer::buildWidget(parent); 556 557 // APP VIEWER BUTTONS have their own box on upper left 558 // The built in viewer button list is PRIVATE 559 560 saveViewPtButton = new QPushButton; 561 saveViewPtButton->setIcon(QPixmap((const char **)saveViewPt_xpm)); 562 saveViewPtButton->setIconSize(QSize(24,24)); 563 saveViewPtButton->setToolTip("Bookmark this view"); 564 connect(saveViewPtButton, SIGNAL(clicked()), this, 565 SLOT(SaveViewPtCB())); 566 addAppPushButton(saveViewPtButton); 567 568 nextViewPtButton = new QPushButton; 569 nextViewPtButton->setIconSize(QSize(24,24)); 570 QCommonStyle style; 571 nextViewPtButton->setIcon(style.standardIcon(QStyle::SP_ArrowRight)); 572 nextViewPtButton->setToolTip("Next bookmark"); 573 connect(nextViewPtButton, SIGNAL(clicked()), this, 574 SLOT(NextViewPtCB())); 575 addAppPushButton(nextViewPtButton); 576 577 prevViewPtButton = new QPushButton; 578 prevViewPtButton->setIconSize(QSize(24,24)); 579 prevViewPtButton->setIcon(style.standardIcon(QStyle::SP_ArrowLeft)); 580 prevViewPtButton->setToolTip("Previous bookmark"); 581 connect(prevViewPtButton, SIGNAL(clicked()), this, 582 SLOT(PrevViewPtCB())); 583 addAppPushButton(prevViewPtButton); 584 585 abbrOutputButton = new QPushButton; 586 abbrOutputButton->setCheckable(true); 587 abbrOutputButton->setIconSize(QSize(24,24)); 588 abbrOutputButton->setIcon(QPixmap((const char **)pickext_xpm)); 589 abbrOutputButton->setToolTip("Extended picking & readout"); 590 connect(abbrOutputButton, SIGNAL(toggled(bool)), this, 591 SLOT(AbbrOutputCB(bool))); 592 addAppPushButton(abbrOutputButton); 593 594 pickRefPathButton = new QPushButton; 595 pickRefPathButton->setIconSize(QSize(24,24)); 596 pickRefPathButton->setIcon(QPixmap((const char **)pickref_xpm)); 597 pickRefPathButton->setToolTip("Pick ref trajectory"); 598 connect(pickRefPathButton, SIGNAL(clicked()), this, 599 SLOT(PickRefPathCB())); 600 addAppPushButton(pickRefPathButton); 601 602 switchWireFrameButton = new QPushButton; 603 switchWireFrameButton->setCheckable(true); 604 switchWireFrameButton->setIconSize(QSize(24,24)); 605 switchWireFrameButton->setIcon(QPixmap((const char **)wireframe_xpm)); 606 switchWireFrameButton->setToolTip("Switch wireframe/solid"); 607 connect(switchWireFrameButton, SIGNAL(toggled(bool)), this, 608 SLOT(SwitchWireFrameCB(bool))); 609 addAppPushButton(switchWireFrameButton); 610 611 switchAxesButton = new QPushButton; 612 switchAxesButton->setCheckable(true); 613 switchAxesButton->setText(QString("A")); 614 switchAxesButton->setToolTip("Axes on/off"); 615 connect(switchAxesButton, SIGNAL(toggled(bool)), this, 616 SLOT(SwitchAxesCB(bool))); 617 addAppPushButton(switchAxesButton); 618 619 detachButton = new QPushButton; 620 detachButton->setIconSize(QSize(24,24)); 621 detachButton->setIcon(style.standardIcon(QStyle::SP_CommandLink)); 622 detachButton->setToolTip("Detach viewer window"); 623 connect(detachButton, SIGNAL(clicked()), this, 624 SLOT(DetachCB())); 625 // Used for UIQt only so check and add later 626 // addAppPushButton(detachButton); 627 628 // HELP WINDOW 629 630 helpmsgbox = new QMessageBox(getParentWidget()); 631 helpmsgbox->setWindowTitle("OIQt Controls"); 632 helpmsgbox->setFont(*font); 633 QString messagetxt = 634 "\nVIEWING mode (Hand cursor):\n\n\ 635 Left-button + pointer move: rotate\n\ 636 Shift+Left-button + pointer move: pan\n\ 637 Middle-button + pointer move: pan\n\ 638 Ctrl+Shift+Left-button + pointer move: zoom\n\ 639 Mouse wheel: zoom\n\ 640 Right-button: popup menu\n\n\ 641 PICKING mode (Arrow cursor):\n\n\ 642 Click on a volume: geometry readout\n\ 643 Click on a trajectory: particle & trajectory readout\n\ 644 Ctrl + click on a volume: see daughters.\n\ 645 Shift + click on a volume: see mother.\n\n\ 646 EXTENDED PICKING mode (Arrow+ viewer button):\n\n\ 647 Hover the mouse over a volume or trajectory for\n\ 648 overlayed readout.\n\n\ 649 ELEMENT NAVIGATION (requires Reference Path):\n\n\ 650 Click on element in list: centers view on element\n\ 651 Arrow keys: rotate in 90 degree steps around element \n\ 652 Shift + Right Arrow: move to next element\n\ 653 Shift + Left Arrow: move to previous element\n\n\ 654 FLY mode (requires Reference Path):\n\n\ 655 Page Up: Increase speed\n\ 656 Page Down: Decrease speed (& reverse if wanted)\n\ 657 Up Arrow: raise camera above path\n\ 658 Down Arror: lower camera below path\n\ 659 Escape: Exit fly mode"; 660 helpmsgbox->setText(messagetxt); 661 helpmsgbox->setModal(false); 662 // helpmsgbox->setWindowModality(Qt::NonModal); 663 664 // AUXILIARY LISTS WINDOW 665 666 // Bypass the namespace in order to make a persistent object 667 AuxWindowDialog = new Ui_Dialog; 668 AuxWindow = new QDialog(parent); 669 AuxWindowDialog->setupUi(AuxWindow); 670 671 // SIGNALS 672 connect(AuxWindowDialog->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), 673 this, SLOT(LoadBookmarkCB(QListWidgetItem*))); 674 connect(AuxWindowDialog->listWidget1, SIGNAL(itemClicked(QListWidgetItem*)), 675 this, SLOT(LookAtSceneElementCB(QListWidgetItem*))); 676 connect(AuxWindowDialog->pushButton_2, SIGNAL(clicked()), 677 this, SLOT(DeleteBookmarkCB())); 678 connect(AuxWindowDialog->pushButton_3, SIGNAL(clicked()), 679 this, SLOT(RenameBookmarkCB())); 680 connect(AuxWindowDialog->pushButton, SIGNAL(clicked()), 681 this, SLOT(SortBookmarksCB())); 682 683 // FWJ Better to do this after viewer window is realized 684 // AuxWindow->show(); 685 // AuxWindow->raise(); 686 // AuxWindow->activateWindow(); 687 } 688 689 690 #if QT_VERSION < 0x060000 691 // Called right after buttons and widgets get realized. 692 // It sets the viewpoint last accessed. 693 void G4OpenInventorQtExaminerViewer::afterRealizeHook() 694 { 695 SoQtExaminerViewer::afterRealizeHook(); 696 #else 697 void G4OpenInventorQtExaminerViewer::setupSceneGraph() 698 { 699 #endif 700 // Default height is used when selecting and viewing scene elements 701 // FWJ Added defaultHeight for Ortho camera 702 SoCamera *cam = getCamera(); 703 if (cam) { 704 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { 705 defaultHeightAngle = 706 ((SoPerspectiveCamera *) cam)->heightAngle.getValue(); 707 toggleCameraType(); 708 defaultHeight = 709 ((SoOrthographicCamera *) cam)->height.getValue(); 710 toggleCameraType(); 711 } else { 712 defaultHeight = 713 ((SoOrthographicCamera *) cam)->height.getValue(); 714 toggleCameraType(); 715 cam = getCamera(); 716 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) 717 defaultHeightAngle = 718 ((SoPerspectiveCamera *) cam)->heightAngle.getValue(); 719 toggleCameraType(); 720 } 721 } 722 723 // Open the default bookmark file 724 fileIn.open(fileName.c_str()); 725 if (!fileIn.fail()) { 726 if (!loadViewPts()) { 727 QMessageBox msgbox; 728 msgbox.setFont(*font); 729 QString messagetxt = "Error reading bookmark file "; 730 messagetxt.append(QString(fileName.c_str())); 731 msgbox.setText(messagetxt); 732 msgbox.exec(); 733 } else { 734 // Opens a file without erasing it 735 fileOut.open(fileName.c_str(), std::ios::in); 736 fileOut.seekp(0, std::ios::end); // For appending new data to the end 737 // FWJ DEBUG 738 // G4cout << "afterRealizeHook: opened EXISTING bookmark file" 739 // << G4endl; 740 if (viewPtList.size()) { 741 // FWJ disabled auto-selection of first viewpoint. 742 // Initial view should be user-controllable & not forced 743 // setViewPt(); 744 addViewPoints(); 745 } 746 } 747 fileIn.close(); 748 } else { 749 // Creates a new default bookmark file 750 fileOut.open(fileName.c_str()); 751 // FWJ DEBUG 752 // G4cout << "afterRealizeHook: Opened a NEW bookmark file" << G4endl; 753 } 754 755 fileIn.clear(); 756 757 SoSeparator* root = (SoSeparator*) (getSceneManager()->getSceneGraph()); 758 if (root == NULL) 759 SoDebugError::post("G4OpenInventorQtExaminerViewer::afterRealizeHook", "Root is null."); 760 else { 761 root->addChild(myCam); // For position/orientation calculation during animation 762 } 763 764 #if 0x060000 <= QT_VERSION 765 if(root!=nullptr) { 766 #endif 767 sceneChangeSensor = new SoNodeSensor; 768 sceneChangeSensor->setFunction(sceneChangeCB); 769 sceneChangeSensor->attach(root); 770 sceneChangeSensor->setData(this); 771 772 ///////////////////////////// MOUSEOVER & PICK ///////////////////// 773 774 // Monitor mouseover events for displaying the name of scene elements 775 // An SoEventCallback is needed instead of using the default processSoEvent 776 // because that last one does not provide us with an SoPath to the object 777 // that was picked 778 SoEventCallback *moCB = new SoEventCallback; 779 moCB->addEventCallback( 780 SoLocation2Event::getClassTypeId(), 781 mouseoverCB, static_cast<void *>(this)); 782 root->addChild(moCB); 783 784 // Override the default picking mechanism present in G4OpenInventorViewer 785 // because we want abbreviated output when picking a trajectory 786 SoEventCallback *pickCB = new SoEventCallback; 787 pickCB->addEventCallback( 788 SoMouseButtonEvent::getClassTypeId(), 789 pickingCB, static_cast<void *>(this)); 790 root->addChild(pickCB); 791 #if 0x060000 <= QT_VERSION 792 } 793 #endif 794 795 ///////////////////////////// MOUSEOVER & PICK ///////////////////// 796 797 #if QT_VERSION < 0x060000 798 AuxWindow->show(); 799 AuxWindow->raise(); 800 AuxWindow->activateWindow(); 801 802 auto UI = G4UImanager::GetUIpointer(); 803 uiQt = dynamic_cast<G4UIQt*>(UI->GetG4UIWindow()); 804 // This explicitly sets the TabWidget as parent before addTab(): 805 if (uiQt) { 806 viewerParent = getParentWidget(); 807 viewerParent2 = viewerParent->parentWidget(); 808 uiQt->AddTabWidget(getParentWidget(), *fName); 809 uiQtTabIndex = uiQt->GetViewerTabWidget()->currentIndex(); 810 // attached = TRUE; 811 addAppPushButton(detachButton); 812 } 813 #else 814 //G.Barrand: map the AuxWindow "at need", it is done in the SaveViewPtCB. 815 // Having one appearing for each viewer creation is cumbersome. 816 // Also, if "closing" the AuxWindow with the mouse, we have no 817 // way to map it again. Moreover, if done here, on macOS at sartup, 818 // it inactivates the Apple menu bar. An idea: since there is one 819 // AuxWindow per viewer, why not having them as tabs in the UI 820 // tab widget? It will go toward a more compact GUI. 821 #endif 822 } 823 824 #if 0x060000 <= QT_VERSION 825 void G4OpenInventorQtExaminerViewer::addInTab() { 826 auto UI = G4UImanager::GetUIpointer(); 827 uiQt = dynamic_cast<G4UIQt*>(UI->GetG4UIWindow()); 828 if(uiQt) { 829 uiQt->AddTabWidget(getParentWidget(),fName); 830 addAppPushButton(detachButton); 831 } 832 } 833 #endif 834 835 // This method locates a named node in the superimposed or original scene. 836 // FWJ RENAME THIS 837 SoNode* 838 G4OpenInventorQtExaminerViewer::getSuperimpositionNode(SoNode* root, 839 const char* name) 840 { 841 if (!searcher) 842 searcher = new SoSearchAction; 843 searcher->reset(); 844 searcher->setName(SbName(name)); 845 searcher->setInterest(SoSearchAction::FIRST); 846 searcher->setSearchingAll(TRUE); 847 searcher->apply(root); 848 assert(searcher->getPath()); 849 return searcher->getPath()->getTail(); 850 } 851 852 853 // FWJ don't know why userdata is called "closure" 854 // It contains the this pointer! 855 void G4OpenInventorQtExaminerViewer::superimpositionCB(void * closure, 856 SoAction * action) 857 { 858 if (closure) 859 ((G4OpenInventorQtExaminerViewer*)closure)->superimpositionEvent(action); 860 } 861 862 863 // Renders and positions speed indicator and longitudinal 864 // distance/viewpoint name on the drawing canvas 865 void G4OpenInventorQtExaminerViewer::superimpositionEvent(SoAction * action) 866 { 867 868 if (!action->isOfType(SoGLRenderAction::getClassTypeId())) 869 return; 870 SbViewportRegion vpRegion = 871 ((SoGLRenderAction*)action)->getViewportRegion(); 872 SbVec2s viewportSize = vpRegion.getViewportSizePixels(); 873 874 // Aspect is WIDTH/HEIGHT 875 float aspect = float(viewportSize[0]) / float(viewportSize[1]); 876 877 // FWJ DEBUG 878 // G4cout << "SPEVENT X0 Y0 DX DY aspect: " << vpRegion.getViewportOrigin()[0] << 879 // " " << vpRegion.getViewportOrigin()[1] << 880 // " " << viewportSize[0] << 881 // " " << viewportSize()[1] << 882 // " " << aspect << G4endl; 883 884 // Translation and scale factor for animation speed indicator... 885 886 float factorx = 1.0f / float(viewportSize[1]) * 220.0f; 887 float factory = factorx; 888 889 if (aspect > 1.0f) { 890 stranslation->translation.setValue(SbVec3f(0.0f, -0.4f, 0.0f)); 891 } else { 892 stranslation->translation.setValue(SbVec3f(0.0f, -0.4f / aspect, 0.0f)); 893 factorx /= aspect; 894 factory /= aspect; 895 } 896 if (viewportSize[0] > 500) 897 factorx *= 500.0f / 400.0f; 898 else 899 factorx *= float(viewportSize[0]) / 400.0f; 900 901 sscale->scaleFactor.setValue(SbVec3f(factorx, factory, 1.0f)); 902 903 // TEXT OVERLAY... 904 905 // FWJ Simplified and rewrote the following section to ease problems 906 // with the overlayed text after a viewer window resize. 907 // Result is now readable but needs further refinement of the scaling. 908 909 float xInfo, yInfo, xLogName, yLogName, xSolid, ySolid, 910 xMaterial, yMaterial, xZPos, yZPos; 911 912 // Base point for navigation distance or viewpoint name 913 // Origin is at center of render area. 914 xInfo = -.475; 915 yInfo = .475; 916 // Menu bar height in same coordinates: 917 float mbgap = 0.03; 918 if (aspect > 1.) xInfo = xInfo*aspect; 919 if (aspect < 1.) yInfo = yInfo/aspect; 920 yInfo = yInfo - mbgap*aspect; 921 922 // Following are relative to above base point 923 xLogName = 0.0; 924 yLogName = -.88 + mbgap*aspect; 925 xSolid = 0.0; 926 ySolid = -.91 + mbgap*aspect; 927 xMaterial = 0.0; 928 yMaterial = -.94 + mbgap*aspect; 929 xZPos = 0.0; 930 yZPos = -.97 + mbgap*aspect; 931 932 // Top line 933 curInfoTrans->translation.setValue(SbVec3f(xInfo, yInfo, 0.0)); 934 935 // Bottom lines 936 mouseOverTransLogName->translation.setValue(SbVec3f(xLogName, yLogName, 0.0)); 937 mouseOverTransSolid->translation.setValue(SbVec3f(xSolid, ySolid, 0.0)); 938 mouseOverTransMaterial->translation.setValue(SbVec3f(xMaterial, yMaterial, 0.0)); 939 mouseOverTransZPos->translation.setValue(SbVec3f(xZPos, yZPos, 0.0)); 940 941 if (currentState == VIEWPOINT) { // Displaying viewpoint name 942 curInfoFont->size.setValue(15); 943 curInfoFont->name.setValue("defaultFont:Italic"); 944 #if QT_VERSION < 0x060000 945 curInfoText->string.setValue(SbString(curViewPtName)); 946 #else 947 curInfoText->string.setValue(SbString(curViewPtName.c_str())); 948 #endif 949 } 950 else if(currentState == GENERAL) { // Displaying longitudinal distance 951 curInfoFont->size.setValue(16); 952 curInfoFont->name.setValue("defaultFont:Bold"); 953 curInfoText->string.setValue(SbString("")); 954 } 955 else { 956 if (refParticleIdx < (int) refParticleTrajectory.size() - 1) { 957 curInfoFont->size.setValue(16); 958 curInfoFont->name.setValue("defaultFont:Bold"); 959 char zPos[20]; 960 // FWJ need a better format here 961 snprintf(zPos, sizeof zPos, "%-7.2f [m]", refZPositions[refParticleIdx] / 1000); 962 curInfoText->string.setValue(SbString(zPos)); 963 } 964 } 965 } 966 967 968 // Loads view point data from a file into a vector. 969 970 bool G4OpenInventorQtExaminerViewer::loadViewPts() 971 { 972 bool error = false; 973 viewPtData tmp; 974 std::string token; 975 SbVec3f axis; 976 SbRotation orient; 977 float x{0.0}, y{0.0}, z{0.0}, angle{0.0}; 978 979 // Gets the last view point accessed, stored in the first line of the data file. 980 fileIn >> token; 981 parseString<int>(viewPtIdx, token, error); 982 getline(fileIn, token); // Remove "\n" 983 // Converts data from string type into necessary types 984 while (getline(fileIn, token)) { 985 986 std::size_t end = token.find_last_not_of(' '); // Remove padded spaces 987 token = token.substr(0, end + 1); 988 989 #if QT_VERSION < 0x060000 990 char *vpName = new char[token.size() + 1]; 991 strcpy(vpName, token.c_str()); 992 tmp.viewPtName = vpName; 993 #else 994 tmp.viewPtName = token; 995 #endif 996 fileIn >> token; 997 998 parseString<float>(x, token, error); 999 fileIn >> token; 1000 parseString<float>(y, token, error); 1001 fileIn >> token; 1002 parseString<float>(z, token, error); 1003 fileIn >> token; 1004 tmp.position = axis.setValue(x, y, z); 1005 1006 parseString<float>(x, token, error); 1007 fileIn >> token; 1008 parseString<float>(y, token, error); 1009 fileIn >> token; 1010 parseString<float>(z, token, error); 1011 fileIn >> token; 1012 parseString<float>(angle, token, error); 1013 fileIn >> token; 1014 orient.setValue(axis.setValue(x, y, z), angle); 1015 tmp.orientation = orient.getValue(); 1016 1017 int camType{0}; 1018 parseString<int>(camType, token, error); 1019 fileIn >> token; 1020 tmp.camType = (CameraType) camType; 1021 1022 parseString<float>(tmp.height, token, error); 1023 fileIn >> token; 1024 parseString<float>(tmp.focalDistance, token, error); 1025 fileIn >> token; 1026 parseString<float>(tmp.nearDistance, token, error); 1027 fileIn >> token; 1028 parseString<float>(tmp.farDistance, token, error); 1029 fileIn >> token; 1030 parseString<int>(tmp.viewportMapping, token, error); 1031 fileIn >> token; 1032 parseString<float>(tmp.aspectRatio, token, error); 1033 1034 getline(fileIn, token); // To remove "\n" characters 1035 getline(fileIn, token); 1036 1037 if (error) { 1038 #if QT_VERSION < 0x060000 1039 viewPtIdx = 0; 1040 #else 1041 viewPtIdx = -1; 1042 #endif 1043 viewPtList.clear(); 1044 return false; 1045 } 1046 viewPtList.push_back(tmp); 1047 } 1048 1049 return true; 1050 } 1051 1052 1053 // Rotates camera 90 degrees around a scene element. 1054 // Rotation is animated for smoothness. 1055 void G4OpenInventorQtExaminerViewer::rotateCamera() 1056 { 1057 SoCamera *cam = getCamera(); 1058 1059 SbRotation rot(rotAxis, M_PI / (2 * ROT_CNT)); 1060 rot.multVec(camDir, camDir); 1061 rot.multVec(camUpVec, camUpVec); 1062 1063 SbVec3f camPosNew = prevPt - (camDir*distance); 1064 cam->position = camPosNew; 1065 cam->pointAt(prevPt, camUpVec); 1066 cam->focalDistance = (prevPt - camPosNew).length(); 1067 1068 rotCnt--; 1069 1070 if (animateSensorRotation->isScheduled()) { 1071 animateSensorRotation->unschedule(); 1072 } 1073 1074 animateSensorRotation->setBaseTime(SbTime::getTimeOfDay()); 1075 animateSensorRotation->setInterval(SbTime(0.02)); 1076 animateSensorRotation->schedule(); 1077 1078 } 1079 1080 1081 // Slides camera along the beamline. 1082 void G4OpenInventorQtExaminerViewer::moveCamera(float dist, bool lookdown) 1083 { 1084 1085 SoCamera *cam = getCamera(); 1086 SbVec3f p1, p2; // The particle moves from p1 to p2 1087 SbVec3f particleDir; // Direction vector from p1 to p2 1088 SbVec3f camPosNew{0.0f, 0.0f, 0.0f}; // New position of the camera 1089 1090 if(refParticleTrajectory.size() == 0) { 1091 //refParticleTrajectory hasn't been set yet 1092 if(dist) 1093 distance = dist; 1094 else 1095 distance = (cam->position.getValue() - center).length(); 1096 1097 cam->position.setValue(center + offsetFromCenter*distance); 1098 cam->focalDistance = (cam->position.getValue() - center).length(); 1099 cam->pointAt(center, upVector); 1100 } 1101 else { 1102 1103 // If we move forward past the last trajectory point, 1104 // go back to the beginning 1105 if (refParticleIdx >= (int) refParticleTrajectory.size() - 1) { 1106 prevPt = refParticleTrajectory[refParticleIdx - step]; 1107 dist = (prevPt - cam->position.getValue()).length(); 1108 refParticleIdx = 0; 1109 } 1110 // If we move backward past the beginning, 1111 // go to the last trajectory point 1112 if (refParticleIdx < 0) { 1113 prevPt = refParticleTrajectory[refParticleIdx + step]; 1114 dist = (prevPt - cam->position.getValue()).length(); 1115 refParticleIdx = (int) refParticleTrajectory.size() - 2; 1116 } 1117 1118 // Set start and end points 1119 p1 = refParticleTrajectory[refParticleIdx]; 1120 p2 = refParticleTrajectory[refParticleIdx + step]; 1121 1122 // Get the direction from p1 to p2 1123 particleDir = p2 - p1; 1124 particleDir.normalize(); 1125 1126 if(prevParticleDir == SbVec3f(0,0,0)) { 1127 // First time entering BEAMLINE mode, look at 1128 // the element from the front, with camera upright 1129 if(lookdown) 1130 camDir = SbVec3f(0,0,1); 1131 else 1132 camDir = SbVec3f(1,0,0); 1133 camUpVec = SbVec3f(0,1,0); 1134 1135 // In case the start of the goes in a 1136 // direction other than +z, rotate the camera accordingly 1137 SbRotation rot(SbVec3f(0,0,1), particleDir); 1138 rot.multVec(camDir, camDir); 1139 rot.multVec(camUpVec, camUpVec); 1140 1141 } 1142 else if(particleDir != prevParticleDir) { 1143 // The beamline has changed direction 1144 1145 SbRotation rot(prevParticleDir, particleDir); 1146 rot.multVec(camDir, camDir); 1147 rot.multVec(camUpVec, camUpVec); 1148 1149 } 1150 1151 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { 1152 if (!dist) 1153 distance = (prevPt - cam->position.getValue()).length(); 1154 else 1155 distance = dist; 1156 } 1157 1158 // FWJ distance not relevant -- use focalDistance 1159 // if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 1160 // if (!dist) 1161 // distance = (prevPt - cam->position.getValue()).length(); 1162 // else 1163 // distance = dist; 1164 // } 1165 1166 1167 float x,y,z; 1168 prevPt.getValue(x,y,z); 1169 1170 1171 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { 1172 camPosNew = p2 - (camDir*distance); 1173 } 1174 if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 1175 // FWJ maintain focal distance 1176 camPosNew = p2 - (camDir*cam->focalDistance.getValue()); 1177 // camPosNew = p2 - (camDir); 1178 } 1179 1180 cam->position = camPosNew; 1181 cam->pointAt(p2, camUpVec); 1182 cam->focalDistance = (p2 - camPosNew).length(); 1183 1184 p2.getValue(x,y,z); 1185 camPosNew.getValue(x,y,z); 1186 1187 prevParticleDir = particleDir; 1188 prevPt = p1; // For accurate distance calculation 1189 1190 } 1191 1192 } 1193 1194 1195 void G4OpenInventorQtExaminerViewer::pickingCB(void *aThis, 1196 SoEventCallback *eventCB) 1197 { 1198 SoHandleEventAction* action = eventCB->getAction(); 1199 const SoPickedPoint *pp = action->getPickedPoint(); 1200 G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*)aThis; 1201 1202 if(pp != NULL) { 1203 1204 SoPath* path = pp->getPath(); 1205 SoNode* node = ((SoFullPath*)path)->getTail(); 1206 1207 if(node->getTypeId() == SoLineSet::getClassTypeId()) { 1208 1209 if(This->pickRefPathFlag) { 1210 This->pickRefPathFlag = false; 1211 if(This->viewingBeforePickRef != This->isViewing()) 1212 This->setViewing(This->viewingBeforePickRef); 1213 else 1214 This->setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT)); 1215 1216 // The trajectory is a set of lines stored in a LineSet 1217 SoLineSet * trajectory = (SoLineSet *)node; 1218 // FWJ DEBUG 1219 // G4cout << "FOUND trajectory LineSet" << trajectory << G4endl; 1220 1221 // The set of all trajectories is stored in a Seperator group node 1222 // one level above the LineSet that was picked. The nodes under that 1223 // seperator are as follows (in this order): Material, LightModel, 1224 // ResetTransform, MatrixTransform, Coordinate3, DrawStyle, LineSet 1225 SoSeparator * grpNode = 1226 (SoSeparator*)(((SoFullPath*)path)->getNodeFromTail(1)); 1227 1228 // The node that contains the coordinates for the trajectory is a 1229 // Coordinate3 node which occurs before the LineSet node. We iterate 1230 // back through the nodes in the group until we find the Coordinate3 node 1231 int nodeIndex = grpNode->findChild(trajectory); 1232 SoNode * tmpNode; 1233 // FWJ needs initialization 1234 SoCoordinate3 * coords = 0; 1235 // SoCoordinate3 * coords; 1236 // We allow only 100 iterations, in case the node isn't found 1237 // (should take only a few iterations) 1238 for(int i = 0; i < 100; ++i) { 1239 --nodeIndex; 1240 1241 tmpNode = grpNode->getChild(nodeIndex); 1242 if(tmpNode->getTypeId() == SoCoordinate3::getClassTypeId()) { 1243 //node found 1244 coords = (SoCoordinate3 *)tmpNode; 1245 break; 1246 } 1247 } 1248 1249 if(coords == NULL) { 1250 G4warn << "Could not find the coordinates node" 1251 " for the picked trajectory." << G4endl; 1252 G4warn << " Reference trajectory not set" << G4endl; 1253 return; 1254 } 1255 // FWJ DEBUG 1256 // G4cout << "FOUND SoCoordinate3 node " << coords << G4endl; 1257 1258 1259 if ((This->lshiftdown) || (This->rshiftdown)) 1260 This->setReferencePath(trajectory, coords, true); //APPENDING 1261 else 1262 This->setReferencePath(trajectory, coords, false); 1263 1264 return; 1265 1266 } 1267 else if(This->abbrOutputFlag) { 1268 1269 G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node); 1270 if(attHolder && attHolder->GetAttDefs().size()) { 1271 1272 std::string strTrajPoint = "G4TrajectoryPoint:"; 1273 std::ostringstream oss; 1274 for (std::size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) { 1275 G4cout << G4AttCheck(attHolder->GetAttValues()[i], 1276 attHolder->GetAttDefs()[i]); 1277 oss << G4AttCheck(attHolder->GetAttValues()[i], 1278 attHolder->GetAttDefs()[i]); 1279 if(oss.str().find(strTrajPoint) != std::string::npos) { 1280 1281 // Last attribute displayed was a trajectory point. Since we 1282 // want abbreviated output, display the last one and exit 1283 // (unless we're already at the last (and only) trajectory point) 1284 if(i != attHolder->GetAttDefs().size()-1) { 1285 G4cout << G4AttCheck( 1286 attHolder->GetAttValues()[attHolder->GetAttDefs().size()-1], 1287 attHolder->GetAttDefs()[attHolder->GetAttDefs().size()-1]); 1288 } 1289 break; 1290 } 1291 } 1292 } else { 1293 G4String name((char*)node->getName().getString()); 1294 G4String cls((char*)node->getTypeId().getName().getString()); 1295 G4warn << "SoNode : " << node 1296 << " SoType : " << cls 1297 << " name : " << name 1298 << G4endl; 1299 G4warn << "No attributes attached." << G4endl; 1300 } 1301 1302 return; 1303 } 1304 else{ 1305 //Go to default behavior 1306 } 1307 } 1308 else { 1309 //Go to default behavior 1310 } 1311 1312 // Default behavior in G4OpenInventorViewer::SelectionCB 1313 G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node); 1314 if(attHolder && attHolder->GetAttDefs().size()) { 1315 for (std::size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) { 1316 G4cout << G4AttCheck(attHolder->GetAttValues()[i], 1317 attHolder->GetAttDefs()[i]); 1318 } 1319 } else { 1320 G4String name((char*)node->getName().getString()); 1321 G4String cls((char*)node->getTypeId().getName().getString()); 1322 G4warn << "SoNode : " << node 1323 << " SoType : " << cls 1324 << " name : " << name 1325 << G4endl; 1326 G4warn << "No attributes attached." << G4endl; 1327 } 1328 1329 //Suppress other event handlers 1330 eventCB->setHandled(); 1331 } 1332 } 1333 1334 1335 void G4OpenInventorQtExaminerViewer::mouseoverCB(void *aThis, SoEventCallback *eventCB) 1336 { 1337 SoHandleEventAction* action = eventCB->getAction(); 1338 const SoPickedPoint* pp = action->getPickedPoint(); 1339 G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*)aThis; 1340 1341 if(!This->abbrOutputFlag) 1342 return; 1343 1344 if(pp != NULL) { 1345 1346 const SbViewportRegion & viewportRegion = action->getViewportRegion(); 1347 1348 std::string sLogName; 1349 float x,y,z; 1350 std::stringstream ssZPos; 1351 std::stringstream ssSolids; 1352 std::stringstream ssMaterials; 1353 SoPath * path = pp->getPath(); 1354 SoNode* node = ((SoFullPath*)path)->getTail(); 1355 1356 if(node->getTypeId() == Geant4_SoPolyhedron::getClassTypeId()) { 1357 1358 sLogName = "Logical Volume: "; 1359 sLogName += ((Geant4_SoPolyhedron *)node)->getName().getString(); 1360 1361 SoGetBoundingBoxAction bAction(viewportRegion); 1362 bAction.apply((SoFullPath*)path); 1363 SbBox3f bBox = bAction.getBoundingBox(); 1364 SbVec3f centr = bBox.getCenter(); 1365 centr.getValue(x,y,z); 1366 ssZPos << "Pos: " << x << " " << y << " " << z; 1367 1368 G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node); 1369 if(attHolder && attHolder->GetAttDefs().size()) { 1370 1371 std::vector<const std::map<G4String,G4AttDef>*> vecDefs = 1372 attHolder->GetAttDefs(); 1373 std::vector<const std::vector<G4AttValue>*> vecVals = 1374 attHolder->GetAttValues(); 1375 for (std::size_t i = 0; i < vecDefs.size(); ++i) { 1376 const std::vector<G4AttValue> * vals = vecVals[i]; 1377 1378 std::vector<G4AttValue>::const_iterator iValue; 1379 1380 for (iValue = vals->begin(); iValue != vals->end(); ++iValue) { 1381 const G4String& valueName = iValue->GetName(); 1382 const G4String& value = iValue->GetValue(); 1383 1384 if(valueName == "Solid") { 1385 if(ssSolids.str() == "") 1386 ssSolids << "Solid Name: " << value; 1387 else 1388 ssSolids << ", " << value; 1389 } 1390 1391 if(valueName == "Material") { 1392 if(ssMaterials.str() == "") 1393 ssMaterials << "Material Name: " << value; 1394 else 1395 ssMaterials << ", " << value; 1396 } 1397 } 1398 } 1399 } 1400 } 1401 // FWJ Mouseover for trajectories 1402 else if(node->getTypeId() == SoLineSet::getClassTypeId()) { 1403 // G4cout << "Trajectory!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << G4endl; 1404 G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node); 1405 if(attHolder && attHolder->GetAttDefs().size()) { 1406 std::string strTrajPoint = "G4TrajectoryPoint:"; 1407 std::ostringstream oss; 1408 G4String t1, t1Ch, t2, t3, t4; 1409 for (std::size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) { 1410 // G4cout << "Getting index " << i << " from attHolder" << G4endl; 1411 // No, returns a vector! 1412 // G4AttValue* attValue = attHolder->GetAttValues()[i]; 1413 const std::vector<G4AttValue>* vals = attHolder->GetAttValues()[i]; 1414 std::vector<G4AttValue>::const_iterator iValue; 1415 for (iValue = vals->begin(); iValue != vals->end(); ++iValue) { 1416 const G4String& valueName = iValue->GetName(); 1417 const G4String& value = iValue->GetValue(); 1418 // G4cout << " valueName = " << valueName << G4endl; 1419 // G4cout << " value = " << value << G4endl; 1420 // LINE 1 1421 if (valueName == "PN") t1 = value; 1422 if (valueName == "Ch") { 1423 if (atof(value.c_str()) > 0) 1424 t1Ch = " +"; 1425 else 1426 t1Ch = " "; 1427 t1Ch += value; 1428 } 1429 if (valueName == "PDG") { 1430 t1 += " "; 1431 t1 += value; 1432 t1 += t1Ch; 1433 This->mouseOverTextLogName->string.setValue(t1); 1434 } 1435 // G4cout << " t1 = " << t1 << G4endl; 1436 // LINE 2 1437 if (valueName == "EventID") t2 = "Evt " + value; 1438 if (valueName == "ID") t2 += " Trk " + value; 1439 if (valueName == "PID") { 1440 t2 += " Prt " + value; 1441 This->mouseOverTextSolid->string.setValue(t2); 1442 } 1443 // LINE 3 1444 if (valueName == "IKE") t3 = "KE " + value; 1445 if (valueName == "IMom") { 1446 // Remove units 1447 std::size_t ipos = value.rfind(" "); 1448 G4String value1 = value; 1449 value1.erase(ipos); 1450 t3 += " P (" + value1 + ")"; 1451 } 1452 if (valueName == "IMag") { 1453 t3 += " " + value + "/c"; 1454 // t3 += " " + value; 1455 This->mouseOverTextMaterial->string.setValue(t3); 1456 } 1457 // LINE 4 1458 if (valueName == "NTP") { 1459 std::ostringstream t4oss; 1460 t4oss << "TrjPts " << value; 1461 t4oss << " Pos " << pp->getPoint()[0] << " " << pp->getPoint()[1] << 1462 " " << pp->getPoint()[2]; 1463 This->mouseOverTextZPos->string.setValue(SbString(t4oss.str().c_str())); 1464 } 1465 } 1466 // G4cout << " NOW CALLING G4AttCheck" << G4endl; 1467 // G4cout << G4AttCheck(attHolder->GetAttValues()[i], 1468 // attHolder->GetAttDefs()[i]); 1469 // oss << G4AttCheck(attHolder->GetAttValues()[i], 1470 // attHolder->GetAttDefs()[i]); 1471 // if(oss.str().find(strTrajPoint) != std::string::npos) { 1472 // // Last attribute displayed was a trajectory point. Since we 1473 // // want abbreviated output, display the last one and exit 1474 // // (unless we're already at the last (and only) trajectory point) 1475 // if(i != attHolder->GetAttDefs().size()-1) { 1476 // G4cout << G4AttCheck( 1477 // attHolder->GetAttValues()[attHolder->GetAttDefs().size()-1], 1478 // attHolder->GetAttDefs()[attHolder->GetAttDefs().size()-1]); 1479 // } 1480 // break; 1481 // } 1482 } 1483 } 1484 This->setSuperimpositionEnabled(This->superimposition, TRUE); 1485 This->scheduleRedraw(); 1486 eventCB->setHandled(); 1487 return; 1488 } 1489 1490 bool redraw = false; 1491 if(std::string(This->mouseOverTextLogName->string.getValues(0)->getString()) != sLogName) { 1492 This->mouseOverTextLogName->string.setValue(SbString(sLogName.c_str())); 1493 redraw = true; 1494 } 1495 if(std::string(This->mouseOverTextSolid->string.getValues(0)->getString()) != ssSolids.str()) { 1496 This->mouseOverTextSolid->string.setValue(SbString(ssSolids.str().c_str())); 1497 redraw = true; 1498 } 1499 if(std::string(This->mouseOverTextMaterial->string.getValues(0)->getString()) != ssMaterials.str()) { 1500 This->mouseOverTextMaterial->string.setValue(SbString(ssMaterials.str().c_str())); 1501 redraw = true; 1502 } 1503 if(std::string(This->mouseOverTextZPos->string.getValues(0)->getString()) != ssZPos.str()) { 1504 This->mouseOverTextZPos->string.setValue(SbString(ssZPos.str().c_str())); 1505 redraw = true; 1506 } 1507 1508 if(redraw) { 1509 This->setSuperimpositionEnabled(This->superimposition, TRUE); 1510 This->scheduleRedraw(); 1511 } 1512 1513 eventCB->setHandled(); 1514 } 1515 else { 1516 if(std::string(This->mouseOverTextLogName->string.getValues(0)->getString()) != "") { 1517 This->mouseOverTextLogName->string.setValue(SbString("")); 1518 This->scheduleRedraw(); 1519 } 1520 if(std::string(This->mouseOverTextSolid->string.getValues(0)->getString()) != "") { 1521 This->mouseOverTextSolid->string.setValue(SbString("")); 1522 This->scheduleRedraw(); 1523 } 1524 if(std::string(This->mouseOverTextMaterial->string.getValues(0)->getString()) != "") { 1525 This->mouseOverTextMaterial->string.setValue(SbString("")); 1526 This->scheduleRedraw(); 1527 } 1528 if(std::string(This->mouseOverTextZPos->string.getValues(0)->getString()) != "") { 1529 This->mouseOverTextZPos->string.setValue(SbString("")); 1530 This->scheduleRedraw(); 1531 } 1532 } 1533 } 1534 1535 1536 // Called by hitting PageUp during animation. 1537 void G4OpenInventorQtExaminerViewer::incSpeed() { 1538 if (std::ceil(animateBtwPtsPeriod * 100) >= 4) { 1539 if (speedStep > 0.08) 1540 speedStep -= 0.02; 1541 else 1542 speedStep = 0.02; 1543 animateBtwPtsPeriod -= speedStep; 1544 } else 1545 animateBtwPtsPeriod = 0.0; 1546 1547 if (currentState != PAUSED_ANIMATION) { 1548 int lastIdx = (int) refParticleTrajectory.size() - 1; 1549 if (refParticleIdx < lastIdx && !animateSensor->isScheduled()) 1550 animateRefParticle(); 1551 } 1552 } 1553 1554 // Called by hitting PageDown during animation. 1555 void G4OpenInventorQtExaminerViewer::decSpeed() { 1556 animateBtwPtsPeriod += speedStep; 1557 if (animateBtwPtsPeriod < MIN_SPEED) { 1558 if (std::floor(animateBtwPtsPeriod * 100) == 12) { // Errors in double representation 1559 speedStep = 0.08; 1560 } else if (animateBtwPtsPeriod > 0.12) 1561 speedStep += 0.02; 1562 } else { 1563 animateBtwPtsPeriod = MIN_SPEED; 1564 speedStep = START_STEP; 1565 maxSpeed = 0.0f; 1566 if (animateSensor->isScheduled()) 1567 animateSensor->unschedule(); 1568 } 1569 } 1570 1571 1572 // Based on the user's interaction the speed indicator bar needs to be adjusted 1573 1574 void G4OpenInventorQtExaminerViewer::updateSpeedIndicator(void) 1575 { 1576 assert(this->sgeometry != NULL); 1577 1578 SbVec3f * points = this->sgeometry->point.startEditing(); 1579 1580 if (points[10][0] == 0.0f) 1581 this->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_ALL); 1582 if (points[14][0] == 0.0f) 1583 this->animSpeedSwitch->whichChild.setValue(SO_SWITCH_ALL); 1584 points[10][0] = this->maxSpeed; 1585 points[11][0] = this->maxSpeed; 1586 points[14][0] = this->maxSpeed; 1587 points[15][0] = this->maxSpeed; 1588 this->sgeometry->point.finishEditing(); 1589 1590 if (this->maxSpeed == 0.0f) { 1591 this->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); 1592 this->animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); 1593 } 1594 } 1595 1596 1597 void G4OpenInventorQtExaminerViewer::actualRedraw(void) { 1598 switch (currentState) { 1599 case ANIMATION: 1600 case REVERSED_ANIMATION: 1601 case PAUSED_ANIMATION: 1602 updateSpeedIndicator(); 1603 SoQtExaminerViewer::actualRedraw(); 1604 break; 1605 default: 1606 SoQtExaminerViewer::actualRedraw(); 1607 break; 1608 } 1609 } 1610 1611 1612 void G4OpenInventorQtExaminerViewer::setReferencePath(SoLineSet *lineset, 1613 SoCoordinate3 *coords, bool append) 1614 { 1615 // TODO: Color the reference path 1616 // Disable the color stuff for now: changes all trajectories 1617 // FWJ See G4OpenInventorXtExaminerViewer.cc for test code 1618 1619 // The trajectory is composed of all the polyline segments in the 1620 // multiple value field (SoMFInt32) numVertices. 1621 // For each of the numVertices.getNum()* polyline segments, 1622 // retrieve the points from the SoCoordinate3 node 1623 1624 SbVec3f refParticlePt; 1625 1626 if(!append) 1627 refParticleTrajectory.clear(); 1628 1629 for(int i = 0; i < lineset->numVertices.getNum(); ++i) { 1630 for(int j = 0; j < lineset->numVertices[i]; ++j) { 1631 refParticlePt = coords->point[j]; 1632 refParticleTrajectory.push_back(refParticlePt); 1633 } 1634 } 1635 // Remove points that are too close to each other 1636 evenOutRefParticlePts(); 1637 setReferencePathZPos(); 1638 getSceneElements(); 1639 sortElements(); 1640 } 1641 1642 1643 void G4OpenInventorQtExaminerViewer::setReferencePathZPos() 1644 { 1645 refZPositions.clear(); 1646 refZPositions.push_back(0); 1647 float dist; 1648 for(unsigned int i=0; i < refParticleTrajectory.size() - 1; ++i) { 1649 dist = (refParticleTrajectory[i] - 1650 refParticleTrajectory[i + 1]).length(); 1651 refZPositions.push_back(refZPositions[i] + dist); 1652 } 1653 } 1654 1655 1656 void G4OpenInventorQtExaminerViewer::findAndSetRefPath() 1657 { 1658 SoSearchAction action; 1659 action.setType(SoLineSet::getClassTypeId(),false); 1660 action.setInterest(SoSearchAction::ALL); 1661 action.apply(getSceneGraph()); 1662 1663 SoPathList &pathList = action.getPaths(); 1664 1665 if(pathList.getLength() != 0) { 1666 1667 SoCoordinate3 * coords = NULL; 1668 std::vector<SoCoordinate3 *> coordvec; 1669 std::vector<SoLineSet *> linevec; 1670 1671 bool refPathFound = false; 1672 for(int i = 0; i < pathList.getLength(); ++i) { 1673 SoFullPath *path = (SoFullPath *)pathList[i]; 1674 1675 G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(path->getTail()); 1676 if(attHolder != nullptr) 1677 { 1678 for (std::size_t j = 0; j < attHolder->GetAttDefs().size(); ++j) { 1679 std::ostringstream oss; 1680 oss << G4AttCheck(attHolder->GetAttValues()[j], 1681 attHolder->GetAttDefs()[j]); 1682 1683 std::string findStr = "Type of trajectory (Type): "; 1684 std::string compareValue = "REFERENCE"; 1685 std::size_t idx = oss.str().find(findStr); 1686 1687 if(idx != std::string::npos) { 1688 if(oss.str().substr(idx + findStr.size(), 1689 compareValue.size()) == compareValue) { 1690 coords = getCoordsNode(path); 1691 if(coords != NULL) { 1692 refPathFound = true; 1693 coordvec.push_back(coords); 1694 linevec.push_back((SoLineSet *)path->getTail()); 1695 } 1696 break; 1697 } 1698 } 1699 1700 findStr = "Track ID (ID): "; 1701 idx = oss.str().find(findStr); 1702 if(idx != std::string::npos) { 1703 //index all primary tracks 1704 std::string tmpstr = oss.str().substr(idx + findStr.size(),1); 1705 std::istringstream buffer(tmpstr); 1706 int num; 1707 buffer >> num; 1708 if(num == 1) { 1709 1710 // Check if next character is a number, 1711 // in which case we don't have Track ID 1 1712 // FWJ attempt to fix Coverity issue. 1713 char nextChar = oss.str().at(idx+findStr.size()+1); 1714 // const char * nextChar = 1715 // oss.str().substr(idx + findStr.size() + 1,1).c_str(); 1716 if(std::isdigit(nextChar)) 1717 break; //Not a primary track, continue with next track 1718 1719 coords = getCoordsNode(path); 1720 if(coords != NULL) { 1721 coordvec.push_back(coords); 1722 linevec.push_back((SoLineSet *)path->getTail()); 1723 break; //Found coords node, continue with next track 1724 } 1725 } 1726 else 1727 break; //Not a primary track, continue with next track 1728 } 1729 else{ 1730 //Not a Track ID attribute, fall through 1731 } 1732 } 1733 } 1734 1735 if(refPathFound) 1736 break; 1737 } 1738 1739 if(coordvec.empty()) 1740 return; //No track with a Coordinate3 node found 1741 1742 if(refPathFound) { 1743 //set ref path to last traj, coord in the vecs 1744 setReferencePath(linevec.back(), coordvec.back()); 1745 return; 1746 } 1747 //else 1748 1749 int longestIdx = 0; 1750 float longestLength = 0.0; 1751 // For all paths 1752 for(unsigned int i=0;i < linevec.size(); ++i) { 1753 1754 //First generate a vector with all the points in this lineset 1755 std::vector<SbVec3f> trajectory; 1756 // For all lines in the i path 1757 for(int j=0; j < linevec[i]->numVertices.getNum(); ++j) { 1758 // For all points in line j 1759 for(int k=0; k < linevec[i]->numVertices[j]; ++k) { 1760 trajectory.push_back(coordvec[i]->point[k]); 1761 } 1762 } 1763 1764 // Then calculate the total length 1765 float tmpLength=0.0; 1766 for(unsigned int j=0; j < trajectory.size() - 1; ++j) { 1767 tmpLength += (trajectory[j] - trajectory[j + 1]).length(); 1768 } 1769 1770 if(tmpLength > longestLength) { 1771 longestIdx = i; 1772 longestLength = tmpLength; 1773 } 1774 } 1775 1776 // Set the longest path as the reference path 1777 setReferencePath(linevec[longestIdx], coordvec[longestIdx]); 1778 } 1779 } 1780 1781 1782 SoCoordinate3 * G4OpenInventorQtExaminerViewer::getCoordsNode(SoFullPath *path) 1783 { 1784 SoLineSet *trajectory = (SoLineSet *)path->getTail(); 1785 SoSeparator * grpNode = (SoSeparator*)(((SoFullPath*)path)->getNodeFromTail(1)); 1786 int nodeIndex = grpNode->findChild(trajectory); 1787 SoNode * tmpNode; 1788 1789 // We allow only 100 iterations, in case the node isn't found 1790 // (should take only a few iterations) 1791 for (int i = 0; i < 100; ++i) { 1792 --nodeIndex; 1793 1794 tmpNode = grpNode->getChild(nodeIndex); 1795 if(tmpNode->getTypeId() == SoCoordinate3::getClassTypeId()) { 1796 //node found 1797 return (SoCoordinate3 *)tmpNode; 1798 } 1799 } 1800 return NULL; //coords node not found 1801 } 1802 1803 1804 // Displays scene elements on the right side of listsDialog. 1805 // else: scene graph is searched for Geant4_SoPolyhedron type nodes 1806 void G4OpenInventorQtExaminerViewer::getSceneElements() 1807 { 1808 std::string field, eltName; 1809 1810 std::map<std::string, int> duplicates; 1811 std::map<std::string, int> sceneElts; 1812 SoSearchAction search; 1813 Geant4_SoPolyhedron *node; 1814 SoGroup *root = (SoGroup *)getSceneManager()->getSceneGraph(); 1815 1816 SoBaseKit::setSearchingChildren(TRUE); 1817 1818 search.reset(); 1819 search.setSearchingAll(TRUE); 1820 search.setInterest(SoSearchAction::ALL); 1821 search.setType(Geant4_SoPolyhedron::getClassTypeId(), 0); 1822 1823 // FWJ DEBUG 1824 // G4cout << "Searching for elements....." << G4endl; 1825 search.apply(root); 1826 1827 SoPathList &pl = search.getPaths(); 1828 1829 1830 // First find which names occur more than once so we can append a counter to them 1831 for (int i = 0; i < pl.getLength(); i++) { 1832 SoFullPath *path = (SoFullPath *)pl[i]; 1833 node = (Geant4_SoPolyhedron *)path->getTail(); 1834 eltName = node->getName(); 1835 // G4cout << " FOUND " << i << " " << eltName << G4endl; 1836 if(duplicates.count(eltName)) 1837 duplicates[eltName]++; 1838 else 1839 duplicates[eltName] = 1; 1840 } 1841 1842 for(int i = 0; i < pl.getLength(); i++) { 1843 float x,y,z; 1844 std::stringstream ssCount; 1845 SoFullPath *path = (SoFullPath *)pl[i]; 1846 node = (Geant4_SoPolyhedron *)path->getTail(); 1847 eltName = node->getName(); 1848 field = eltName; 1849 if(duplicates[eltName] == 1) 1850 ssCount << "";//duplicates[field] 1851 else { 1852 if(sceneElts.count(eltName)) 1853 sceneElts[eltName]++; 1854 else 1855 sceneElts[eltName] = 1; 1856 1857 ssCount << sceneElts[eltName]; 1858 field += "_"; 1859 } 1860 1861 field += ssCount.str(); 1862 1863 SoGetBoundingBoxAction bAction(getViewportRegion()); 1864 bAction.apply(path); 1865 SbBox3f bBox = bAction.getBoundingBox(); 1866 1867 SbVec3f centr = bBox.getCenter(); 1868 centr.getValue(x,y,z); 1869 1870 path->ref(); 1871 sceneElement el = { field, path, centr, 0.0 }; 1872 sceneElements.push_back(el); 1873 } 1874 } 1875 1876 1877 float G4OpenInventorQtExaminerViewer::sqrlen(const SbVec3f &a) 1878 { 1879 float x,y,z; 1880 a.getValue(x,y,z); 1881 return x*x + y*y + z*z; 1882 } 1883 1884 1885 void G4OpenInventorQtExaminerViewer::distanceToTrajectory(const SbVec3f &q, 1886 float &dist, 1887 SbVec3f &closestPoint, 1888 int &index) 1889 { 1890 // a : Previous point on trajectory 1891 // b : Next point on trajectory 1892 // q : the point in space 1893 // dab, daq, dbq: distance between a & b, a & q, b & q 1894 // 1895 // Theory: A point p on a line ab is defined as: 1896 // 1897 // p(t) = a+t?(b?a) 1898 // 1899 // note: All are vectors except the parameter t 1900 // 1901 // When t is between 0 and 1 the point p is situated between a and b on ab. 1902 // The point p is defined in terms of the parameter t, subsequently so does 1903 // the distance from the query point q to the point p. To find the minimum 1904 // of that distance we differentiate it and set equal to zero: 1905 // 1906 // diff(Norm(p(t)- q)) = 0 1907 // 1908 // note: diff means taking the derivative with regard to t 1909 // 1910 // The resulting t is given in the code below. The square of the distance 1911 // between p and q is given by: 1912 // 1913 // d^2 = (Norm(p(t)-q))^2 1914 // 1915 // The expression found is given in the code below (current_dist) 1916 // 1917 // Ref: http://programmizm.sourceforge.net/blog/2012/ 1918 // distance-from-a-point-to-a-polyline 1919 // 1920 // --PLG 1921 1922 const std::size_t count = refParticleTrajectory.size(); 1923 assert(count>0); 1924 1925 SbVec3f b = refParticleTrajectory[0]; 1926 SbVec3f dbq = b - q; 1927 float sqrDist = sqrlen(dbq); 1928 closestPoint = b; 1929 index = 0; 1930 for (std::size_t i = 1; i < count; ++i) { 1931 const SbVec3f a = b; 1932 const SbVec3f daq = dbq; 1933 b = refParticleTrajectory[i]; 1934 dbq = b - q; 1935 const SbVec3f dab = a - b; 1936 1937 float dab_x, dab_y, dab_z; 1938 dab.getValue(dab_x,dab_y,dab_z); 1939 float daq_x, daq_y, daq_z; 1940 daq.getValue(daq_x, daq_y, daq_z); 1941 float dbq_x, dbq_y, dbq_z; 1942 dbq.getValue(dbq_x, dbq_y, dbq_z); 1943 1944 const float inv_sqrlen = 1./sqrlen(dab); 1945 const float t = (dab_x*daq_x + dab_y*daq_y + dab_z*daq_z)*inv_sqrlen; 1946 1947 if (t<0.) { 1948 // The trajectory point occurs before point a 1949 // Go to the next point 1950 continue; 1951 } 1952 float current_dist; 1953 if (t<=1.) { 1954 // The trajectory point occurs between a and b. 1955 // Compute the distance to that point 1956 current_dist = daq_x*daq_x + daq_y*daq_y + daq_z*daq_z 1957 - t*(daq_x*dab_x + daq_y*dab_y + daq_z*dab_z) 1958 + t*t*(dab_x*dab_x + dab_y*dab_y + dab_z*dab_z); 1959 } 1960 else { //t>1. 1961 // The trajectory point occurs after b. 1962 // Get the distance to point b 1963 current_dist = sqrlen(dbq); 1964 } 1965 1966 if (current_dist < sqrDist) { 1967 sqrDist = current_dist; 1968 closestPoint = a + t*(b-a); 1969 index = (int) i; 1970 } 1971 } 1972 1973 dist = std::sqrt(sqrDist); 1974 } 1975 1976 1977 void G4OpenInventorQtExaminerViewer::sortElements() 1978 { 1979 if(refParticleTrajectory.empty()) 1980 return; 1981 1982 float * trajLength = new float[refParticleTrajectory.size()]; 1983 typedef std::map<elementForSorting, sceneElement> sortedMap; 1984 sortedMap sorted; 1985 1986 // For every point on the reference trajectory, compute 1987 // the total length from the start 1988 SbVec3f prevPoint; 1989 std::vector<SbVec3f>::iterator itRef = refParticleTrajectory.begin(); 1990 int trajIndex = 0; 1991 prevPoint = *itRef; 1992 trajLength[trajIndex] = 0.0; 1993 ++itRef; 1994 ++trajIndex; 1995 for(; itRef != refParticleTrajectory.end(); ++itRef, ++trajIndex) { 1996 trajLength[trajIndex] = trajLength[trajIndex-1] + (*itRef - prevPoint).length(); 1997 prevPoint = *itRef; 1998 } 1999 2000 // Compute the smallest distance between the element 2001 // and the reference trajectory (find the closest point), 2002 // then map the element to the trajectory length of that 2003 // point (calculated above) 2004 SoGetBoundingBoxAction bAction(getViewportRegion()); 2005 SbVec3f elementCoord; 2006 std::vector<sceneElement>::iterator itEl; 2007 int elementIndex; 2008 elementForSorting el; 2009 for(itEl = sceneElements.begin(), elementIndex = 0; 2010 itEl != sceneElements.end(); ++itEl, ++elementIndex) { 2011 bAction.apply(itEl->path); 2012 2013 // FWJ sceneElement already has a center 2014 elementCoord = itEl->center; 2015 // ... and this sometimes returns an empty box! 2016 // elementCoord = bAction.getBoundingBox().getCenter(); 2017 // if (bAction.getBoundingBox().isEmpty()) { 2018 // G4cout << "sortElements: Box is empty!" << G4endl; 2019 // G4cout << " element name=" << itEl->name << G4endl; 2020 // } 2021 2022 int index; 2023 distanceToTrajectory(elementCoord, el.smallestDistance, el.closestPoint, index); 2024 itEl->closestPointZCoord = el.closestPointZCoord = trajLength[index]; 2025 el.distanceToBeamlineStart = (itEl->center - refParticleTrajectory[0]).length(); 2026 2027 // This map of the scene elements (or their coordinates rather) 2028 // is automatically sorted by trajectory length (Z coord), then 2029 // by the distance between the element and the point in case the Z coord 2030 // is the same as another element. This is done by using as a key 2031 // an element structure which implements the operator for weak ordering 2032 sorted.insert(std::make_pair(el,*itEl)); 2033 } 2034 2035 // store the sorted elements into the vector field 2036 sceneElements.clear(); 2037 2038 sortedMap::iterator itSorted = sorted.begin(); 2039 for(; itSorted != sorted.end(); itSorted++) 2040 sceneElements.push_back(itSorted->second); 2041 2042 zcoordSetFlag = true; 2043 2044 createElementsList(); 2045 2046 delete[] trajLength; 2047 } 2048 2049 2050 void G4OpenInventorQtExaminerViewer::createElementsList() 2051 { 2052 // FWJ DEBUG 2053 // G4cout << "Populating ELEMENT LIST..." << G4endl; 2054 2055 AuxWindowDialog->listWidget1->clear(); 2056 // int size = sceneElements.size(); 2057 2058 std::vector<sceneElement>::const_iterator it; 2059 std::stringstream ss; 2060 2061 for(it=sceneElements.begin(); it!=sceneElements.end(); ++it) { 2062 ss << it->name; 2063 if(zcoordSetFlag) 2064 ss << " [" << it->closestPointZCoord << "]"; 2065 2066 new QListWidgetItem(ss.str().c_str(), AuxWindowDialog->listWidget1); 2067 ss.str(""); 2068 } 2069 } 2070 2071 2072 // Called when user clicks a scene element in listsDialog. 2073 // Zooms onto that element. 2074 void 2075 G4OpenInventorQtExaminerViewer::LookAtSceneElementCB(QListWidgetItem* item) 2076 { 2077 // FWJ DEBUG 2078 // G4cout << "AuxWindow: listWidget1 select element CALLBACK" << G4endl; 2079 2080 SoCamera * cam = getCamera(); 2081 2082 if (SoQtExaminerViewer::isAnimating()) 2083 stopAnimating(); 2084 2085 if (currentState == ANIMATION || currentState == REVERSED_ANIMATION 2086 || currentState == PAUSED_ANIMATION ) { 2087 if (animateSensor->isScheduled()) 2088 animateSensor->unschedule(); 2089 setSuperimpositionEnabled(superimposition, FALSE); 2090 maxSpeed = 0.0f; 2091 scheduleRedraw(); 2092 restoreCamera(); 2093 currentState = prevState; 2094 } else if (currentState == VIEWPOINT) 2095 setSuperimpositionEnabled(superimposition, FALSE); 2096 2097 std::string elementField = qPrintable(item->text()); 2098 2099 std::size_t idx = elementField.find_last_of("["); 2100 if(idx == std::string::npos) 2101 idx = elementField.size(); //if "[" not found for whatever reason (list not sorted) 2102 else 2103 idx--; // To get rid of the space that is between the name and '[' 2104 2105 bool error = false; 2106 SoFullPath *path; 2107 SoSearchAction search; 2108 SoNode *root = getSceneManager()->getSceneGraph(); 2109 int counter = 0; 2110 std::size_t idxUnderscore = elementField.find_last_of("_"); 2111 2112 parseString<int>(counter, 2113 elementField.substr(idxUnderscore + 1, idx), error); 2114 2115 SoBaseKit::setSearchingChildren(TRUE); 2116 search.reset(); 2117 search.setSearchingAll(TRUE); 2118 2119 // G4cout << " Starting search for elementField " << elementField 2120 // << G4endl; 2121 2122 if(error) { // No counter is present => element name was not modified 2123 curEltName = elementField.substr(0, idx); 2124 search.setName(curEltName.c_str()); 2125 search.apply(root); 2126 2127 path = (SoFullPath *)search.getPath(); 2128 } 2129 else { 2130 curEltName = elementField.substr(0, idxUnderscore); 2131 search.setInterest(SoSearchAction::ALL); 2132 search.setName(curEltName.c_str()); 2133 search.apply(root); 2134 2135 SoPathList &pl = search.getPaths(); 2136 path = (SoFullPath *)pl[counter - 1]; // Since counter starts at 1, not 0 2137 } 2138 2139 G4ThreeVector global; 2140 2141 // FWJ FLIP THIS 2142 if ((idx > 0) && (path)) { 2143 2144 if(!refParticleTrajectory.empty()) { 2145 2146 SoGetBoundingBoxAction bAction(getViewportRegion()); 2147 bAction.apply(path); 2148 SbBox3f bBox = bAction.getBoundingBox(); 2149 SbVec3f elementCoord = bBox.getCenter(); 2150 2151 refParticleIdx = 0; 2152 SbVec3f p; 2153 2154 float absLengthNow, absLengthMin; 2155 int maxIdx = (int) refParticleTrajectory.size() - 2; 2156 int targetIdx = 0; 2157 SbVec3f dir; 2158 2159 p = refParticleTrajectory[refParticleIdx]; 2160 absLengthMin = (p - elementCoord).length(); 2161 refParticleIdx++; 2162 2163 // Find a ref. particle's point closest to element's global coords 2164 while (refParticleIdx < maxIdx) { 2165 p = refParticleTrajectory[refParticleIdx]; 2166 absLengthNow = (p - elementCoord).length(); 2167 2168 if (absLengthNow < absLengthMin) { 2169 absLengthMin = absLengthNow; 2170 targetIdx = refParticleIdx; 2171 } 2172 refParticleIdx++; 2173 } 2174 2175 if (currentState != BEAMLINE) { // Set up default zoom 2176 SbVec3f p1, pN; 2177 currentState = BEAMLINE; 2178 prevParticleDir = SbVec3f(0,0,0); //so that moveCamera() knows sets default parameters 2179 2180 p1 = prevPt = refParticleTrajectory[0]; 2181 pN = refParticleTrajectory[refParticleTrajectory.size() - 1]; 2182 distance = (pN - p1).length() / 10; 2183 2184 // FWJ Rather than switching to a default height, it is more flexible 2185 // to keep the same height(magnification) while moving the camera. 2186 // if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 2187 // ((SoOrthographicCamera *) cam)->height.setValue(defaultHeight); 2188 // // FWJ Restore the default height instead of hard-wired value 2189 // // ((SoOrthographicCamera *) cam)->height.setValue(10000.0f); 2190 // } 2191 // else if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) 2192 2193 // FWJ required to avoid extreme perspective after camera move: 2194 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) 2195 ((SoPerspectiveCamera*)cam)->heightAngle.setValue(defaultHeightAngle); 2196 2197 } else { 2198 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) 2199 distance = (prevPt - cam->position.getValue()).length(); 2200 } 2201 refParticleIdx = targetIdx; 2202 2203 ////////////////////////////////////////////////////////////// 2204 setSuperimpositionEnabled(superimposition, TRUE); 2205 axisSwitch->whichChild.setValue(SO_SWITCH_NONE); 2206 animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); 2207 animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); 2208 scheduleRedraw(); 2209 ////////////////////////////////////////////////////////////// 2210 2211 moveCamera(distance); 2212 2213 } 2214 2215 else { 2216 offsetFromCenter.setValue(0, 0, 1); 2217 distance = 50;// small number since using viewAll() for default zoom 2218 upVector.setValue(0, 1, 0); 2219 moveCamera(distance); 2220 cam->viewAll(path, getViewportRegion()); 2221 } 2222 } 2223 2224 } 2225 2226 2227 void G4OpenInventorQtExaminerViewer::FileLoadRefPathCB() 2228 { 2229 // G4cout << "File: Load Ref Path CALLBACK" << G4endl; 2230 2231 QFileDialog filedialog(getParentWidget(), tr("Load Reference Path")); 2232 filedialog.setFileMode(QFileDialog::AnyFile); 2233 filedialog.setFont(*font); 2234 if (!filedialog.exec()) return; 2235 QStringList filenameinlist = filedialog.selectedFiles(); 2236 QString filenamein = filenameinlist[0]; 2237 2238 std::ifstream ifs(qPrintable(filenamein)); 2239 if(ifs.is_open()) { 2240 refParticleTrajectory.clear(); 2241 float x,y,z; 2242 while(ifs >> x >> y >> z) { 2243 refParticleTrajectory.push_back(SbVec3f(x,y,z)); 2244 } 2245 ifs.close(); 2246 } else { 2247 QMessageBox msgbox; 2248 msgbox.setFont(*font); 2249 QString messagetxt = "Reference Path file not found: "; 2250 messagetxt.append(filenamein); 2251 msgbox.setText(messagetxt); 2252 msgbox.exec(); 2253 return; 2254 } 2255 if (refParticleTrajectory.size() < 2) { 2256 QMessageBox msgbox; 2257 msgbox.setFont(*font); 2258 QString messagetxt = "Invalid Reference Path"; 2259 msgbox.setText(messagetxt); 2260 msgbox.exec(); 2261 return; 2262 } 2263 // Following setReferencePath() ... 2264 evenOutRefParticlePts(); 2265 setReferencePathZPos(); 2266 getSceneElements(); 2267 sortElements(); 2268 } 2269 2270 2271 void G4OpenInventorQtExaminerViewer::FileSaveRefPathCB() 2272 { 2273 // G4cout << "File: Save Ref Path CALLBACK" << G4endl; 2274 2275 QFileDialog filedialog(getParentWidget(), tr("Save Reference Path")); 2276 filedialog.setFileMode(QFileDialog::AnyFile); 2277 // To enable confirmation of overwriting 2278 filedialog.setAcceptMode(QFileDialog::AcceptSave); 2279 filedialog.setFont(*font); 2280 if (!filedialog.exec()) return; 2281 QStringList filenameinlist = filedialog.selectedFiles(); 2282 QString filenamein = filenameinlist[0]; 2283 2284 std::ofstream ofs(qPrintable(filenamein)); 2285 if (ofs.is_open()) { 2286 float x,y,z; 2287 for (unsigned int i=0; i < refParticleTrajectory.size(); ++i) { 2288 refParticleTrajectory[i].getValue(x,y,z); 2289 ofs << x << " " << y << " " << z << "\n"; 2290 } 2291 ofs.close(); 2292 } else { 2293 QMessageBox msgbox; 2294 msgbox.setFont(*font); 2295 QString messagetxt = "Error opening file "; 2296 messagetxt.append(filenamein); 2297 msgbox.setText(messagetxt); 2298 msgbox.exec(); 2299 } 2300 2301 } 2302 2303 void G4OpenInventorQtExaminerViewer::evenOutRefParticlePts() 2304 { 2305 if(refParticleTrajectory.empty()) 2306 return; 2307 2308 SbVec3f p1, p2, p3, dirNow, dirNxt, dir, p2_tmp, p_start, p_corner, p_nxt; 2309 float avgDistBtwPts = 0; 2310 float totalDistBtwPts = 0; 2311 std::vector<SbVec3f> newRefParticleTrajectory; 2312 SbVec3f refPoint; 2313 std::size_t size = refParticleTrajectory.size() - 1; 2314 int numOfPts = 0; 2315 for (std::size_t i = 0; i < size; ++i) { 2316 p1 = refParticleTrajectory[i]; 2317 p2 = refParticleTrajectory[i + 1]; 2318 if (p1 == p2) 2319 continue; 2320 numOfPts++; 2321 totalDistBtwPts += (p2 - p1).length(); 2322 } 2323 // Nothing useful to do (and fix Coverity) 2324 if (numOfPts <= 2) return; 2325 2326 avgDistBtwPts = totalDistBtwPts / numOfPts; 2327 float minDistAllowed = 0.75 * avgDistBtwPts; 2328 // float maxDistAllowed = 1.25 * avgDistBtwPts; // Pts tend to be close not far 2329 2330 float x, y, z; 2331 std::size_t i = 0, j = 0; 2332 while (i < size) { 2333 p1 = refParticleTrajectory[i]; 2334 p2 = refParticleTrajectory[i + 1]; 2335 2336 refPoint = p1; 2337 p1.getValue(x, y, z); 2338 2339 newRefParticleTrajectory.push_back(refPoint); 2340 2341 j = i; 2342 while ((p2 - p1).length() < minDistAllowed && j < (size - 1)) { 2343 j++; 2344 2345 p1 = refParticleTrajectory[j]; 2346 p2 = refParticleTrajectory[j + 1]; 2347 } 2348 if (j != i) 2349 i = j + 1; 2350 else 2351 i++; 2352 } 2353 2354 refParticleTrajectory.clear(); 2355 refParticleTrajectory = newRefParticleTrajectory; 2356 } 2357 2358 2359 void G4OpenInventorQtExaminerViewer::saveCurCamera() 2360 { 2361 SoCamera *cam = getCamera(); 2362 camB4Animation.viewportMapping = cam->viewportMapping.getValue(); 2363 camB4Animation.position = cam->position.getValue(); 2364 camB4Animation.orientation = cam->orientation.getValue(); 2365 camB4Animation.aspectRatio = cam->aspectRatio.getValue(); 2366 camB4Animation.nearDistance = cam->nearDistance.getValue(); 2367 camB4Animation.farDistance = cam->farDistance.getValue(); 2368 camB4Animation.focalDistance = cam->focalDistance.getValue(); 2369 2370 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { 2371 camB4Animation.height = 2372 ((SoPerspectiveCamera *) cam)->heightAngle.getValue(); 2373 camB4Animation.camType = PERSPECTIVE; 2374 } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 2375 camB4Animation.height = 2376 ((SoOrthographicCamera *) cam)->height.getValue(); 2377 camB4Animation.camType = ORTHOGRAPHIC; 2378 } 2379 } 2380 2381 2382 void G4OpenInventorQtExaminerViewer::restoreCamera() 2383 { 2384 SoCamera *cam = getCamera(); 2385 2386 cam->viewportMapping = camB4Animation.viewportMapping; 2387 cam->position = camB4Animation.position; 2388 cam->orientation = camB4Animation.orientation; 2389 cam->aspectRatio = camB4Animation.aspectRatio; 2390 cam->nearDistance = camB4Animation.nearDistance; 2391 cam->farDistance = camB4Animation.farDistance; 2392 cam->focalDistance = camB4Animation.focalDistance; 2393 2394 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { 2395 if (camB4Animation.camType == ORTHOGRAPHIC) { 2396 toggleCameraType(); 2397 cam = getCamera(); 2398 ((SoOrthographicCamera *) cam)->height.setValue( 2399 camB4Animation.height); 2400 } else 2401 ((SoPerspectiveCamera *) cam)->heightAngle.setValue( 2402 camB4Animation.height); 2403 } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 2404 if (camB4Animation.camType == PERSPECTIVE) { 2405 toggleCameraType(); 2406 cam = getCamera(); 2407 ((SoPerspectiveCamera *) cam)->heightAngle.setValue( 2408 camB4Animation.height); 2409 } else 2410 ((SoOrthographicCamera *) cam)->height.setValue( 2411 camB4Animation.height); 2412 } 2413 } 2414 2415 2416 void G4OpenInventorQtExaminerViewer::animateSensorRotationCB(void *data, 2417 SoSensor *sensor) 2418 { 2419 SbTime curTime = SbTime::getTimeOfDay(); 2420 G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*) data; 2421 2422 SoTimerSensor* s = (SoTimerSensor*) sensor; 2423 2424 float t = float((curTime - s->getBaseTime()).getValue()) 2425 / This->animateBtwPtsPeriod; 2426 2427 if ((t > 1.0f) || (t + s->getInterval().getValue() > 1.0f)) 2428 t = 1.0f; 2429 SbBool end = (t == 1.0f); 2430 2431 if (end) { 2432 This->animateSensorRotation->unschedule(); 2433 if(This->rotCnt) { 2434 // rotations left 2435 This->rotateCamera(); 2436 } 2437 else { 2438 // rotation over 2439 This->currentState = This->prevState; 2440 return; 2441 } 2442 } 2443 2444 } 2445 2446 2447 // Called repeatedly during reference particle animation 2448 2449 void G4OpenInventorQtExaminerViewer::animateSensorCB(void *data, 2450 SoSensor *sensor) 2451 { 2452 SbTime curTime = SbTime::getTimeOfDay(); 2453 G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*) data; 2454 SoCamera *cam = This->getCamera(); 2455 SoTimerSensor* s = (SoTimerSensor*) sensor; 2456 2457 float t = float((curTime - s->getBaseTime()).getValue()) 2458 / This->animateBtwPtsPeriod; 2459 2460 if ((t > 1.0f) || (t + s->getInterval().getValue() > 1.0f)) 2461 t = 1.0f; 2462 SbBool end = (t == 1.0f); 2463 2464 cam->orientation = SbRotation::slerp(This->camStartOrient, This->camEndOrient, t); 2465 cam->position = This->camStartPos + (This->camEndPos - This->camStartPos) * t; 2466 2467 if (end) { 2468 This->animateSensor->unschedule(); 2469 2470 if (This->currentState == ANIMATION) { 2471 if (This->refParticleIdx < (int) (This->refParticleTrajectory.size() - 1)) 2472 This->animateRefParticle(); 2473 else { 2474 This->animateBtwPtsPeriod = MIN_SPEED; 2475 This->speedStep = START_STEP; 2476 } 2477 } 2478 if (This->currentState == REVERSED_ANIMATION) { 2479 if (This->refParticleIdx >= 1) 2480 This->animateRefParticle(); 2481 else { 2482 This->animateBtwPtsPeriod = MIN_SPEED; 2483 This->speedStep = START_STEP; 2484 } 2485 } 2486 } 2487 } 2488 2489 2490 void G4OpenInventorQtExaminerViewer::setStartingPtForAnimation() 2491 { 2492 if (SoQtExaminerViewer::isAnimating()) 2493 stopAnimating(); 2494 2495 SbRotation rot; 2496 SbVec3f p1{0.0, 0.0, 0.0}, p2{0.0, 0.0, 0.0}, p2_tmp, camUpV, camD, camD_tmp, leftRightAxis; 2497 float x1, y1, z1, x2, y2, z2; 2498 2499 if (currentState == ANIMATION) { 2500 p1 = refParticleTrajectory[refParticleIdx]; 2501 p2 = refParticleTrajectory[++(refParticleIdx)]; 2502 } else if (currentState == REVERSED_ANIMATION) { 2503 p2 = refParticleTrajectory[refParticleIdx]; 2504 p1 = refParticleTrajectory[--(refParticleIdx)]; 2505 } else if (currentState == PAUSED_ANIMATION) { 2506 if (refParticleIdx < (int) refParticleTrajectory.size()) { 2507 p1 = refParticleTrajectory[refParticleIdx]; 2508 p2 = refParticleTrajectory[refParticleIdx + 1]; 2509 } else { 2510 p1 = refParticleTrajectory[refParticleIdx - 1]; 2511 p2 = refParticleTrajectory[refParticleIdx]; 2512 } 2513 } 2514 p1.getValue(x1, y1, z1); 2515 p2.getValue(x2, y2, z2); 2516 2517 camD = p2 - p1; 2518 camD.normalize(); 2519 2520 p2_tmp.setValue(x2, y1, z2); 2521 camD_tmp = p2_tmp - p1; 2522 camD_tmp.normalize(); 2523 2524 camUpV.setValue(0, 1, 0); 2525 rot.setValue(camD_tmp, camD); 2526 rot.multVec(camUpV, camUpV); 2527 2528 leftRightAxis = camD.cross(camUpV); 2529 2530 myCam->position = p1; 2531 myCam->pointAt(p2, camUpV); 2532 2533 // Update camera position 2534 p1 = p1 + (up_down * camUpV) + (left_right * leftRightAxis); 2535 myCam->position = p1; 2536 // FWJ Try look-ahead here 2537 int idx = refParticleIdx + pathLookahead; 2538 idx = std::min(idx, (int)refParticleTrajectory.size() - 1); 2539 myCam->pointAt(refParticleTrajectory[idx], camUpV); 2540 // myCam->pointAt(refParticleTrajectory[idx], camUpVec); 2541 myCam->focalDistance = 0.1f; 2542 } 2543 2544 2545 void G4OpenInventorQtExaminerViewer::gotoRefPathStart() 2546 { 2547 G4OpenInventorQtExaminerViewer::ToolsRefPathStartCB(); 2548 } 2549 2550 2551 void G4OpenInventorQtExaminerViewer::ToolsRefPathStartCB() 2552 { 2553 if (!refParticleTrajectory.size()) { 2554 QMessageBox msgbox; 2555 msgbox.setFont(*font); 2556 QString messagetxt = "No current reference path"; 2557 msgbox.setText(messagetxt); 2558 msgbox.exec(); 2559 return; 2560 } 2561 2562 if (currentState == ROTATING) 2563 return; 2564 if (currentState == ANIMATION || currentState == REVERSED_ANIMATION 2565 || currentState == PAUSED_ANIMATION) { 2566 if (animateSensor->isScheduled()) 2567 animateSensor->unschedule(); 2568 setSuperimpositionEnabled(superimposition, FALSE); 2569 maxSpeed = 0.0f; 2570 scheduleRedraw(); 2571 } else { 2572 saveCurCamera(); 2573 prevState = currentState; 2574 prevRefIdx = refParticleIdx; 2575 } 2576 2577 if (SoQtExaminerViewer::isAnimating()) 2578 stopAnimating(); 2579 2580 up_down = 0; 2581 left_right = 0; 2582 step = 1; 2583 2584 refParticleIdx = 0; 2585 currentState = BEAMLINE; 2586 setSuperimpositionEnabled(superimposition, TRUE); 2587 axisSwitch->whichChild.setValue(SO_SWITCH_NONE); 2588 animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); 2589 animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); 2590 scheduleRedraw(); 2591 2592 // FWJ Disabled: this is set in moveCamera() 2593 // Zoom in 2594 // SoCamera *cam = getCamera(); 2595 // cam->focalDistance = 0.1f; 2596 2597 prevParticleDir = SbVec3f(0,0,0); 2598 2599 //Default zoom 2600 SbVec3f p1 = refParticleTrajectory[0]; 2601 SbVec3f pN = refParticleTrajectory[refParticleTrajectory.size() - 1]; 2602 distance = (pN - p1).length() / 10; 2603 2604 moveCamera(distance, true); 2605 } 2606 2607 2608 void G4OpenInventorQtExaminerViewer::ToolsRefPathInvertCB() 2609 { 2610 invertRefPath(); 2611 } 2612 2613 2614 void G4OpenInventorQtExaminerViewer::invertRefPath() 2615 { 2616 std::reverse(refParticleTrajectory.begin(), 2617 refParticleTrajectory.end()); 2618 setReferencePathZPos(); 2619 sortElements(); 2620 } 2621 2622 2623 void G4OpenInventorQtExaminerViewer::animateRefParticle() 2624 { 2625 SoCamera *cam = getCamera(); 2626 2627 camStartPos = cam->position.getValue(); 2628 camStartOrient = cam->orientation.getValue(); 2629 2630 if (currentState != BEAMLINE) 2631 setStartingPtForAnimation(); 2632 2633 camEndPos = myCam->position.getValue(); 2634 camEndOrient = myCam->orientation.getValue(); 2635 2636 if (animateSensor->isScheduled()) 2637 animateSensor->unschedule(); 2638 2639 animateSensor->setBaseTime(SbTime::getTimeOfDay()); 2640 animateSensor->setInterval(SbTime(0.02)); 2641 2642 animateSensor->schedule(); 2643 } 2644 2645 2646 #if QT_VERSION < 0x060000 2647 void G4OpenInventorQtExaminerViewer::addEscapeCallback(void (*callback)()) 2648 { 2649 escapeCallback = callback; 2650 } 2651 #endif 2652 2653 void G4OpenInventorQtExaminerViewer::sceneChangeCB(void* userData, SoSensor*) 2654 { 2655 // FWJ DEBUG 2656 // G4cout << "SCENE CHANGE callback" << G4endl; 2657 // NOTE: could/should be disabled during animation 2658 2659 G4OpenInventorQtExaminerViewer* This = 2660 (G4OpenInventorQtExaminerViewer*)userData; 2661 if(This->newEvents) { 2662 This->findAndSetRefPath(); 2663 This->newEvents = false; 2664 } 2665 } 2666 2667 2668 //////////////////////////////////// BOOKMARKS /////////////////////////// 2669 2670 // Adds bookmarks to listsDialog. 2671 2672 void G4OpenInventorQtExaminerViewer::addViewPoints() 2673 { 2674 std::size_t size = viewPtList.size(); 2675 if (!size) return; 2676 2677 for (std::size_t i = 0; i < size; ++i) { 2678 #if QT_VERSION < 0x060000 2679 new QListWidgetItem(viewPtList[i].viewPtName, 2680 AuxWindowDialog->listWidget); 2681 #else 2682 new QListWidgetItem(viewPtList[i].viewPtName.c_str(), 2683 AuxWindowDialog->listWidget); 2684 #endif 2685 } 2686 } 2687 2688 2689 // Converts a string type word into a float type. 2690 2691 template<class T> 2692 void G4OpenInventorQtExaminerViewer::parseString(T &t, const std::string &s, 2693 bool &error) 2694 { 2695 std::istringstream str(s); 2696 if ((str >> t).fail()) 2697 error = true; 2698 } 2699 2700 2701 void 2702 G4OpenInventorQtExaminerViewer::FileOpenBookmarkCB() 2703 { 2704 // FWJ DEBUG 2705 // G4cout << "File: Open Bookmark File CALLBACK" << G4endl; 2706 QFileDialog filedialog(getParentWidget(), tr("Open bookmark file")); 2707 filedialog.setFileMode(QFileDialog::ExistingFile); 2708 filedialog.setFont(*font); 2709 if (!filedialog.exec()) return; 2710 QStringList filenameinlist = filedialog.selectedFiles(); 2711 QString filenamein = filenameinlist[0]; 2712 2713 fileIn.close(); 2714 fileIn.open(qPrintable(filenamein)); 2715 if (fileIn.fail()) { 2716 QMessageBox msgbox; 2717 msgbox.setFont(*font); 2718 QString messagetxt = "Error opening file: "; 2719 messagetxt.append(filenamein); 2720 msgbox.setText(messagetxt); 2721 msgbox.exec(); 2722 // G4cout << "ERROR opening file " << filename << G4endl; 2723 fileIn.clear(); 2724 return; 2725 } 2726 // Opens a file without erasing it 2727 cleanUpAfterPrevFile(); 2728 2729 if (!loadViewPts()) { 2730 QMessageBox msgbox; 2731 msgbox.setFont(*font); 2732 QString messagetxt = "Error reading bookmark file: "; 2733 messagetxt.append(filenamein); 2734 msgbox.setText(messagetxt); 2735 msgbox.exec(); 2736 // G4cout << "ERROR reading bookmark file " << filename << G4endl; 2737 fileIn.clear(); 2738 return; 2739 } 2740 2741 fileName = qPrintable(filenamein); 2742 fileOut.open(fileName.c_str(), std::ios::in); 2743 fileOut.seekp(0, std::ios::end); 2744 2745 addViewPoints(); 2746 2747 // LATER: display filename in lists window 2748 2749 fileIn.close(); 2750 fileIn.clear(); 2751 } 2752 2753 // Called before loading a new viewpoint file. 2754 // Resets member fields to default values. 2755 2756 void G4OpenInventorQtExaminerViewer::cleanUpAfterPrevFile() 2757 { 2758 viewPtIdx = -1; 2759 viewPtList.clear(); 2760 // setSuperimpositionEnabled(superimposition, FALSE); 2761 // scheduleRedraw(); 2762 currentState = GENERAL; 2763 if (fileOut.is_open()) fileOut.close(); 2764 2765 AuxWindowDialog->listWidget->clear(); 2766 AuxWindowDialog->lineEdit->setText(QString("")); 2767 } 2768 2769 2770 void 2771 G4OpenInventorQtExaminerViewer::FileNewBookmarkCB() 2772 { 2773 // G4cout << "File: Open New Bookmark File CALLBACK" << G4endl; 2774 QFileDialog filedialog(getParentWidget(), tr("Open new bookmark file")); 2775 filedialog.setFileMode(QFileDialog::AnyFile); 2776 // To enable confirmation of overwriting 2777 filedialog.setAcceptMode(QFileDialog::AcceptSave); 2778 // But change the "Save" button text 2779 filedialog.setLabelText(QFileDialog::Accept, QString("New")); 2780 filedialog.setFont(*font); 2781 if (!filedialog.exec()) return; 2782 QStringList filenameinlist = filedialog.selectedFiles(); 2783 QString filenamein = filenameinlist[0]; 2784 2785 cleanUpAfterPrevFile(); 2786 fileName = qPrintable(filenamein); 2787 fileOut.open(fileName.c_str()); 2788 if (fileOut.fail()) { 2789 QMessageBox msgbox; 2790 msgbox.setFont(*font); 2791 QString messagetxt = "Error opening new bookmark file: "; 2792 messagetxt.append(filenamein); 2793 msgbox.setText(messagetxt); 2794 msgbox.exec(); 2795 // G4cout << "ERROR opening new bookmark file " << filename << G4endl; 2796 } 2797 } 2798 2799 2800 void 2801 G4OpenInventorQtExaminerViewer::ToolsAnimateRefParticleCB() 2802 { 2803 // G4cout << "Tools: Animate Ref Particle CALLBACK" << G4endl; 2804 if (!refParticleTrajectory.size()) { 2805 returnToAnim = true; 2806 G4warn << "No Reference Trajectory" << G4endl; 2807 return; 2808 } 2809 2810 /////////////////////////////////////////////////////////////// 2811 setSuperimpositionEnabled(superimposition, TRUE); 2812 maxSpeed = SPEED_INDICATOR_STEP; 2813 axisSwitch->whichChild.setValue(SO_SWITCH_ALL); 2814 animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_ALL); 2815 animSpeedSwitch->whichChild.setValue(SO_SWITCH_ALL); 2816 scheduleRedraw(); 2817 /////////////////////////////////////////////////////////////// 2818 2819 SoCamera *cam = getCamera(); 2820 // SbVec3f camDirOld, camDirNew, camDirNew_tmp, camUpVec, P0, P1, P1_tmp; 2821 2822 if (currentState == ANIMATION || currentState == REVERSED_ANIMATION 2823 || currentState == ROTATING) 2824 return; 2825 2826 if (currentState != PAUSED_ANIMATION) { 2827 2828 saveCurCamera(); 2829 prevState = currentState; 2830 prevRefIdx = refParticleIdx; 2831 2832 if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 2833 toggleCameraType(); 2834 cam = getCamera(); 2835 } 2836 2837 refParticleIdx = 0; // Set the camera to the starting point of the animation 2838 animateBtwPtsPeriod = MIN_SPEED; 2839 speedStep = START_STEP; 2840 left_right = up_down = 0; 2841 2842 cam->focalDistance = 0.1f; 2843 ((SoPerspectiveCamera *) cam)->heightAngle = 0.50f; 2844 } 2845 2846 currentState = ANIMATION; 2847 setStartingPtForAnimation(); 2848 2849 cam->position = (myCam)->position.getValue(); 2850 cam->orientation = (myCam)->orientation.getValue(); 2851 animateRefParticle(); // Animate the camera 2852 } 2853 2854 2855 void 2856 G4OpenInventorQtExaminerViewer::SaveViewPtCB() 2857 { 2858 // G4cout << "AppButton: Save Viewpoint CALLBACK" << G4endl; 2859 // First get viewpoint name ... 2860 // EMULATING getViewPtNameCB ... 2861 // bool ok; 2862 // Note QString() returns an empty string 2863 #if 0x060000 <= QT_VERSION 2864 //G.Barrand: map the AuxWindow here. Then it is mapped "at need" 2865 // and not systematically when creating a new viewer. 2866 // Moreover, if "closing" the AuxWindow with the mouse, 2867 // it permits to map it back. 2868 AuxWindow->show(); 2869 AuxWindow->raise(); 2870 AuxWindow->activateWindow(); 2871 #endif 2872 2873 // NONE OF THE FOLLOWING CHANGES THE FONT: FORGET IT FOR NOW 2874 QInputDialog* inputdialog = new QInputDialog(getParentWidget()); 2875 inputdialog->setFont(*font); 2876 inputdialog->setWindowTitle(tr("Enter a name for the bookmark")); 2877 inputdialog->setLabelText("Bookmark name"); 2878 // inputdialog->setTextEchoMode(QLineEdit::Normal); 2879 inputdialog->adjustSize(); 2880 QString namein; 2881 if (inputdialog->exec() == QDialog::Accepted) 2882 namein=inputdialog->textValue().trimmed(); 2883 else 2884 return; 2885 if (namein.isEmpty()) return; 2886 2887 // This easier approach failed: unable to set font size 2888 // QString namein = 2889 // QInputDialog::getText(getParentWidget(), 2890 // tr("Enter a name for the bookmark"), 2891 // tr("Bookmark name"), QLineEdit::Normal, 2892 // QString(), &ok); 2893 2894 namein.truncate(MAX_VP_NAME); 2895 2896 char* name = strdup(qPrintable(namein)); 2897 2898 // FWJ DEBUG 2899 // G4cout << "QString is " << qPrintable(namein) << G4endl; 2900 // G4cout << "char[] is " << name << G4endl; 2901 2902 for (int i = 0; i < (int)viewPtList.size(); i++) { 2903 #if QT_VERSION < 0x060000 2904 if (!strcmp(name, viewPtList[i].viewPtName)) { 2905 #else 2906 if (!strcmp(name, viewPtList[i].viewPtName.c_str())) { 2907 #endif 2908 QMessageBox msgbox; 2909 msgbox.setText("Bookmark name is already in use"); 2910 msgbox.exec(); 2911 free(name); 2912 return; 2913 } 2914 } 2915 2916 if (viewPtIdx == -1) viewPtIdx = 0; 2917 saveViewPt(name); 2918 2919 saveViewPtItem = new QListWidgetItem(namein, 2920 AuxWindowDialog->listWidget); 2921 AuxWindowDialog->listWidget->setCurrentItem(saveViewPtItem); 2922 AuxWindowDialog->lineEdit->setText(namein); 2923 free(name); 2924 } 2925 2926 2927 // Saves current camera parameters to a viewpoint file. 2928 2929 void G4OpenInventorQtExaminerViewer::saveViewPt(char *name) 2930 { 2931 SbVec3f axis; 2932 viewPtData tmp; 2933 float x, y, z, angle; 2934 SoCamera* camera = getCamera(); 2935 2936 // NOTE: Xt VSN increments this at end of procedure 2937 // viewPtIdx++; 2938 2939 // FWJ DEBUG 2940 // G4cout << "saveViewPt: saving bookmark " << viewPtIdx << " " << name 2941 // << G4endl; 2942 2943 if (viewPtList.size() == 0) { 2944 writeViewPtIdx(); 2945 } 2946 2947 #if QT_VERSION < 0x060000 2948 tmp.viewPtName = name; 2949 #else 2950 tmp.viewPtName = std::string(name); 2951 #endif 2952 tmp.viewportMapping = camera->viewportMapping.getValue(); 2953 tmp.position = camera->position.getValue(); 2954 tmp.orientation = camera->orientation.getValue(); 2955 tmp.aspectRatio = camera->aspectRatio.getValue(); 2956 tmp.nearDistance = camera->nearDistance.getValue(); 2957 tmp.farDistance = camera->farDistance.getValue(); 2958 tmp.focalDistance = camera->focalDistance.getValue(); 2959 2960 // Save camera height (changed by zooming) 2961 if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) { 2962 tmp.height = ((SoPerspectiveCamera *) camera)->heightAngle.getValue(); 2963 tmp.camType = PERSPECTIVE; 2964 } else if (camera->isOfType(SoOrthographicCamera::getClassTypeId())) { 2965 tmp.height = ((SoOrthographicCamera *) camera)->height.getValue(); 2966 tmp.camType = ORTHOGRAPHIC; 2967 } else { 2968 SoDebugError::post("G4OpenInventorQtExaminerViewer::saveViewPtCB", 2969 "Only Perspective and Orthographic cameras are supported."); 2970 return; 2971 } 2972 2973 viewPtList.push_back(tmp); 2974 2975 // Now save the view point to a .txt file 2976 // FWJ DEBUG 2977 // G4cout << "saveViewPt: writing to Bookmark file " << fileName << G4endl; 2978 2979 std::string vpName = name; 2980 2981 while ((int) vpName.size() <= MAX_VP_NAME) 2982 vpName += " "; 2983 2984 fileOut << vpName << std::endl; 2985 tmp.position.getValue(x, y, z); 2986 fileOut << x << " " << y << " " << z << std::endl; 2987 2988 // Reusing x, y and z for storing the axis 2989 tmp.orientation.getValue(axis, angle); 2990 axis.getValue(x, y, z); 2991 fileOut << x << " " << y << " " << z << " " << angle << std::endl; 2992 2993 fileOut << tmp.camType << " " << tmp.height << std::endl; 2994 fileOut << tmp.focalDistance << " "; 2995 fileOut << tmp.nearDistance << " "; 2996 fileOut << tmp.farDistance << std::endl; 2997 fileOut << tmp.viewportMapping << " "; 2998 fileOut << tmp.aspectRatio << "\n" << std::endl; 2999 fileOut.flush(); 3000 3001 viewPtIdx++; 3002 3003 // FWJ DEBUG 3004 // G4cout << "saveViewPt: finished writing to file" << G4endl << 3005 // " Next viewPtIdx is " << viewPtIdx << G4endl; 3006 } 3007 3008 3009 // Updates the viewPtIdx in a viewpoint file. 3010 3011 void G4OpenInventorQtExaminerViewer::writeViewPtIdx() 3012 { 3013 std::string idxStr; 3014 std::stringstream out; 3015 3016 out << viewPtIdx; 3017 idxStr = out.str(); 3018 fileOut.seekp(0, std::ios::beg); 3019 3020 while ((int) idxStr.length() < MAX_VP_IDX) { 3021 idxStr += " "; 3022 } 3023 3024 // FWJ DEBUG 3025 // G4cout << "writeViewPtIdx: " << viewPtIdx << G4endl; 3026 fileOut << idxStr << "\n"; 3027 fileOut.flush(); 3028 fileOut.seekp(0, std::ios::end); 3029 } 3030 3031 3032 // Receives the name of the bookmark clicked and searches for it in viewPtList. 3033 3034 void G4OpenInventorQtExaminerViewer::LoadBookmarkCB(QListWidgetItem* item) 3035 { 3036 // FWJ DEBUG 3037 // G4cout << "AuxWindow: listWidget LoadBookmark CALLBACK" << G4endl; 3038 3039 for (int i = 0; i < (int)viewPtList.size(); i++) { 3040 #if QT_VERSION < 0x060000 3041 if (!strcmp(viewPtList[i].viewPtName, qPrintable(item->text()))) { 3042 #else 3043 if (!strcmp(viewPtList[i].viewPtName.c_str(), qPrintable(item->text()))) { 3044 #endif 3045 viewPtIdx = i; 3046 break; 3047 } 3048 } 3049 // G4cout << " FOUND viewPtIdx " << viewPtIdx << G4endl; 3050 3051 writeViewPtIdx(); 3052 setViewPt(); 3053 AuxWindowDialog->lineEdit->setText(item->text()); 3054 } 3055 3056 3057 // Sets the viewpoint based on camera data that viewPtIdx is pointing to. 3058 3059 void G4OpenInventorQtExaminerViewer::setViewPt() 3060 { 3061 if (currentState == ANIMATION || currentState == REVERSED_ANIMATION 3062 || currentState == ROTATING) { 3063 if (animateSensor->isScheduled()) animateSensor->unschedule(); 3064 setSuperimpositionEnabled(superimposition, FALSE); 3065 maxSpeed = 0.0f; 3066 scheduleRedraw(); 3067 } 3068 3069 SoCamera * camera = getCamera(); 3070 if (camera == NULL) { 3071 G4warn << "setViewPt: Camera is null. Unable to set the viewpoint." << 3072 G4endl; 3073 // String dialogName = (char *) "Missing Camera Node"; 3074 // std::string msg = "Camera is null. Unable to set the viewpoint."; 3075 // warningMsgDialog(msg, dialogName, NULL); 3076 return; 3077 } 3078 3079 if (!viewPtList.size()) { 3080 G4warn << "setViewPt: There are no viewpoints to load." << G4endl; 3081 // String dialogName = (char *) "Missing Viewpoints"; 3082 // std::string msg = "There are no viewpoints to load."; 3083 // warningMsgDialog(msg, dialogName, NULL); 3084 return; 3085 } 3086 3087 if (SoQtExaminerViewer::isAnimating()) stopAnimating(); 3088 3089 if (currentState != VIEWPOINT) { 3090 currentState = VIEWPOINT; 3091 ////////////////////////////////////////////////////////////// 3092 setSuperimpositionEnabled(superimposition, TRUE); 3093 axisSwitch->whichChild.setValue(SO_SWITCH_NONE); 3094 animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); 3095 animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); 3096 scheduleRedraw(); 3097 /////////////////////////////////////////////////////////////// 3098 } 3099 3100 #if QT_VERSION < 0x060000 3101 #else 3102 if((viewPtIdx<0)||(viewPtIdx>=int(viewPtList.size()))) { 3103 G4warn << "setViewPt: inconsitent viewPtIdx " << viewPtIdx << ", viewPtList.size() " << viewPtList.size() << G4endl; 3104 return; 3105 } 3106 #endif 3107 3108 curViewPtName = viewPtList[viewPtIdx].viewPtName; 3109 camera->viewportMapping = viewPtList[viewPtIdx].viewportMapping; 3110 camera->position = viewPtList[viewPtIdx].position; 3111 camera->orientation = viewPtList[viewPtIdx].orientation; 3112 camera->aspectRatio = viewPtList[viewPtIdx].aspectRatio; 3113 camera->nearDistance = viewPtList[viewPtIdx].nearDistance; 3114 camera->farDistance = viewPtList[viewPtIdx].farDistance; 3115 camera->focalDistance = viewPtList[viewPtIdx].focalDistance; 3116 3117 // Restore camera height (changed by zooming) 3118 if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) { 3119 if (viewPtList[viewPtIdx].camType == ORTHOGRAPHIC) { 3120 toggleCameraType(); 3121 camera = getCamera(); 3122 ((SoOrthographicCamera *) camera)->height.setValue( 3123 viewPtList[viewPtIdx].height); 3124 } else 3125 ((SoPerspectiveCamera *) camera)->heightAngle.setValue( 3126 viewPtList[viewPtIdx].height); 3127 } else if (camera->isOfType(SoOrthographicCamera::getClassTypeId())) { 3128 if (viewPtList[viewPtIdx].camType == PERSPECTIVE) { 3129 toggleCameraType(); 3130 camera = getCamera(); 3131 ((SoPerspectiveCamera *) camera)->heightAngle.setValue( 3132 viewPtList[viewPtIdx].height); 3133 } else 3134 ((SoOrthographicCamera *) camera)->height.setValue( 3135 viewPtList[viewPtIdx].height); 3136 } else { 3137 SoDebugError::post("G4OpenInventorQtExaminerViewer::setViewPt", 3138 "Only Perspective and Orthographic cameras are supported."); 3139 return; 3140 } 3141 3142 } 3143 3144 3145 void G4OpenInventorQtExaminerViewer::NextViewPtCB() 3146 { 3147 // FWJ DEBUG 3148 // G4cout << "App Button: nextViewPt CALLBACK" << G4endl; 3149 3150 if (!viewPtList.size()) return; 3151 if (viewPtIdx >= (int)viewPtList.size() - 1) 3152 viewPtIdx = 0; 3153 #if 0x060000 <= QT_VERSION 3154 else if (viewPtIdx<0) 3155 viewPtIdx = 0; 3156 #endif 3157 else 3158 viewPtIdx++; 3159 3160 writeViewPtIdx(); 3161 setViewPt(); 3162 #if QT_VERSION < 0x060000 3163 char* viewptname = viewPtList[viewPtIdx].viewPtName; 3164 AuxWindowDialog->lineEdit->setText(QString(viewptname)); 3165 #else 3166 AuxWindowDialog->lineEdit->setText(QString(viewPtList[viewPtIdx].viewPtName.c_str())); 3167 #endif 3168 } 3169 3170 void G4OpenInventorQtExaminerViewer::PrevViewPtCB() 3171 { 3172 // FWJ DEBUG 3173 // G4cout << "App Button: prevViewPt CALLBACK" << G4endl; 3174 3175 if (!viewPtList.size()) return; 3176 #if QT_VERSION < 0x060000 3177 if (viewPtIdx == 0) 3178 #else 3179 if (viewPtIdx <= 0) 3180 #endif 3181 viewPtIdx = (int) viewPtList.size() - 1; 3182 else 3183 viewPtIdx--; 3184 3185 writeViewPtIdx(); 3186 setViewPt(); 3187 #if QT_VERSION < 0x060000 3188 char* viewptname = viewPtList[viewPtIdx].viewPtName; 3189 AuxWindowDialog->lineEdit->setText(QString(viewptname)); 3190 #else 3191 AuxWindowDialog->lineEdit->setText(QString(viewPtList[viewPtIdx].viewPtName.c_str())); 3192 #endif 3193 } 3194 3195 3196 void G4OpenInventorQtExaminerViewer::AbbrOutputCB(bool checked) 3197 { 3198 // FWJ DEBUG 3199 // G4cout << "App Button: abbrOutput CALLBACK" << G4endl; 3200 3201 abbrOutputFlag = checked; 3202 } 3203 3204 3205 void G4OpenInventorQtExaminerViewer::PickRefPathCB() 3206 { 3207 // FWJ DEBUG 3208 // G4cout << "App Button: pickRefPath CALLBACK" << G4endl; 3209 3210 // Save viewing state and go to picking mode 3211 viewingBeforePickRef = isViewing(); 3212 if(isViewing()) 3213 setViewing(false); 3214 setComponentCursor(SoQtCursor(SoQtCursor::CROSSHAIR)); 3215 pickRefPathFlag = true; 3216 } 3217 3218 3219 void G4OpenInventorQtExaminerViewer::SwitchWireFrameCB(bool checked) 3220 { 3221 // FWJ DEBUG 3222 // G4cout << "App Button: switchWireFrame CALLBACK" << G4endl; 3223 3224 // if (switchWireFrameButton->isDown()) { 3225 if (checked) { 3226 setDrawStyle(SoQtViewer::STILL, SoQtViewer::VIEW_LINE); 3227 setDrawStyle(SoQtViewer::INTERACTIVE, SoQtViewer::VIEW_LINE); 3228 } else { 3229 setDrawStyle(SoQtViewer::STILL, SoQtViewer::VIEW_AS_IS); 3230 setDrawStyle(SoQtViewer::INTERACTIVE, 3231 SoQtViewer::VIEW_SAME_AS_STILL); 3232 } 3233 } 3234 3235 3236 void G4OpenInventorQtExaminerViewer::SwitchAxesCB(bool checked) 3237 { 3238 // FWJ DEBUG 3239 // G4cout << "App Button: switchAxes CALLBACK" << G4endl; 3240 setFeedbackVisibility(checked); 3241 // if (checked) { 3242 // setFeedbackVisibility(TRUE); 3243 // } else { 3244 // setFeedbackVisibility(FALSE); 3245 // } 3246 } 3247 3248 3249 void G4OpenInventorQtExaminerViewer::DetachCB() 3250 { 3251 #if QT_VERSION < 0x060000 3252 // FWJ DEBUG 3253 // G4cout << "App Button: detach CALLBACK" << G4endl; 3254 uiQt->GetViewerTabWidget()->removeTab(uiQtTabIndex); 3255 viewerParent->setParent(viewerParent2); 3256 removeAppPushButton(detachButton); 3257 show(); 3258 #else 3259 //G.Barrand: have the viewer in a detached window. 3260 // We have the title window reflecting from where 3261 // it comes from, then "Detached <viewer name>". 3262 // Ask to destroy the detached viewer in case 3263 // of closing the window with the mouse; if not 3264 // we have a dandling hidden viewer without a way 3265 // to map it again. 3266 G4int index = -1; 3267 {int tabn = uiQt->GetViewerTabWidget()->count(); 3268 for (G4int c = 0; c < tabn; ++c) { 3269 if (uiQt->GetViewerTabWidget()->tabText(c)==fName) { 3270 index = c; 3271 } 3272 }} 3273 if(index==(-1)) return; 3274 removeAppPushButton(detachButton); 3275 uiQt->GetViewerTabWidget()->removeTab(index); 3276 {short w,h; 3277 getSize().getValue(w,h); 3278 QWidget* dialog = new QDialog(); 3279 dialog->setWindowTitle(QString("Detached "+fName)); 3280 dialog->setAttribute(Qt::WA_DeleteOnClose); 3281 {QHBoxLayout* layout = new QHBoxLayout(); 3282 layout->setContentsMargins(0,0,0,0); 3283 layout->setSpacing(0); 3284 layout->addWidget(getParentWidget()); 3285 dialog->setLayout(layout);} 3286 dialog->resize(w,h); 3287 getParentWidget()->show(); 3288 dialog->show(); 3289 } 3290 #endif 3291 } 3292 3293 3294 void G4OpenInventorQtExaminerViewer::DeleteBookmarkCB() 3295 { 3296 // FWJ DEBUG 3297 // G4cout << "Delete Button: DeleteBookmark CALLBACK" << G4endl; 3298 3299 // Maybe nothing selected yet 3300 QListWidgetItem* listitem = AuxWindowDialog->listWidget->currentItem(); 3301 if (!listitem) return; 3302 if (!(listitem->isSelected())) return; 3303 3304 QString vpnamein = listitem->text(); 3305 3306 char* vpName = strdup(qPrintable(vpnamein)); 3307 // G4cout << "DELETING bookmark " << vpName << G4endl; 3308 3309 deleteViewPt(vpName); 3310 delete listitem; 3311 free(vpName); 3312 } 3313 3314 // Deletes current viewpoint the user is looking at. 3315 // Updates the input file and bookmarks as well. 3316 3317 void G4OpenInventorQtExaminerViewer::deleteViewPt(char *vpName) 3318 { 3319 std::string line; 3320 std::size_t end; 3321 fileIn.open(fileName.c_str()); 3322 std::ofstream out("temporaryFile.txt"); 3323 3324 #if QT_VERSION < 0x060000 3325 if (!vpName) 3326 vpName = viewPtList[viewPtIdx].viewPtName; 3327 #endif 3328 3329 getline(fileIn, line); // Printing the viewpoint idx 3330 out << line << "\n"; 3331 3332 while (getline(fileIn, line)) { 3333 end = line.find_last_not_of(' '); 3334 line = line.substr(0, end + 1); 3335 if (!strcmp(line.c_str(), vpName)) { // Equal 3336 while (line.size()) { 3337 getline(fileIn, line); 3338 } 3339 3340 while (getline(fileIn, line)) 3341 out << line << "\n"; 3342 } else { 3343 while (line.size()) { 3344 out << line << "\n"; 3345 getline(fileIn, line); 3346 } 3347 out << "\n"; 3348 } 3349 } 3350 3351 std::size_t idx = 0; // Remove viewpoint from the vector 3352 std::size_t size = viewPtList.size(); 3353 while (idx < size) { 3354 #if QT_VERSION < 0x060000 3355 if (!strcmp(viewPtList[idx].viewPtName, vpName)) { 3356 #else 3357 if (!strcmp(viewPtList[idx].viewPtName.c_str(), vpName)) { 3358 #endif 3359 viewPtList.erase(viewPtList.begin() + idx); 3360 break; 3361 } 3362 idx++; 3363 } 3364 3365 out.close(); 3366 fileOut.close(); 3367 fileIn.clear(); 3368 fileIn.close(); 3369 3370 // FWJ check return status: error popups needed here 3371 int istat = remove(fileName.c_str()); 3372 if (istat == -1) { 3373 QMessageBox msgbox; 3374 msgbox.setFont(*font); 3375 QString messagetxt = "Error removing bookmarks file"; 3376 // messagetxt.append(filenamein); 3377 msgbox.setText(messagetxt); 3378 msgbox.exec(); 3379 // G4cout << "Error removing bookmarks file" << G4endl; 3380 } 3381 istat = rename("temporaryFile.txt", fileName.c_str()); 3382 if (istat == -1) { 3383 QMessageBox msgbox; 3384 msgbox.setFont(*font); 3385 QString messagetxt = "Error renaming bookmarks file"; 3386 // messagetxt.append(filenamein); 3387 msgbox.setText(messagetxt); 3388 msgbox.exec(); 3389 // G4cout << "Error renaming bookmarks file" << G4endl; 3390 } 3391 fileOut.open(fileName.c_str(), std::ios::in); 3392 fileOut.seekp(0, std::ios::end); 3393 3394 if (!viewPtList.size()) { // viewPtList is empty 3395 #if QT_VERSION < 0x060000 3396 curViewPtName = (char *) empty.c_str(); 3397 #else 3398 curViewPtName.clear(); 3399 #endif 3400 scheduleRedraw(); 3401 } else { 3402 if (viewPtIdx >= (int) viewPtList.size()) 3403 viewPtIdx--; 3404 writeViewPtIdx(); 3405 setViewPt(); 3406 } 3407 } 3408 3409 3410 void G4OpenInventorQtExaminerViewer::RenameBookmarkCB() 3411 { 3412 // FWJ DEBUG 3413 // G4cout << "Rename Button: RenameBookmark CALLBACK" << G4endl; 3414 // Maybe nothing selected yet 3415 QListWidgetItem* listitem = AuxWindowDialog->listWidget->currentItem(); 3416 if (!listitem) return; 3417 if (!(listitem->isSelected())) return; 3418 3419 QString vpnamein = listitem->text(); 3420 3421 QInputDialog* inputdialog = new QInputDialog(getParentWidget()); 3422 inputdialog->setFont(*font); 3423 inputdialog->setWindowTitle(tr("Enter")); 3424 inputdialog->setLabelText("New bookmark name"); 3425 inputdialog->adjustSize(); 3426 QString newnamein; 3427 if (inputdialog->exec() == QDialog::Accepted) 3428 newnamein=inputdialog->textValue().trimmed(); 3429 else 3430 return; 3431 if (newnamein.isEmpty()) return; 3432 3433 char* newname = strdup(qPrintable(newnamein)); 3434 3435 std::size_t size = viewPtList.size(); 3436 for (std::size_t i = 0; i < size; ++i) { 3437 #if QT_VERSION < 0x060000 3438 if (!strcmp(newname, viewPtList[i].viewPtName)) { 3439 #else 3440 if (!strcmp(newname, viewPtList[i].viewPtName.c_str())) { 3441 #endif 3442 QMessageBox msgbox; 3443 msgbox.setFont(*font); 3444 msgbox.setText("Bookmark name is already in use"); 3445 msgbox.exec(); 3446 } 3447 } 3448 3449 // G4cout << "RENAMING to " << newname << G4endl; 3450 renameViewPt(newname); 3451 listitem->setText(QString(newname)); 3452 AuxWindowDialog->lineEdit->setText(newname); 3453 // if (currentState == VIEWPOINT) 3454 // scheduleRedraw(); 3455 3456 free(newname); 3457 } 3458 3459 // Renames currently selected viewpoint. 3460 3461 void G4OpenInventorQtExaminerViewer::renameViewPt(char *vpName) 3462 { 3463 std::size_t idx = 0, end, pos; 3464 std::size_t size = viewPtList.size(); 3465 std::string line, newName; 3466 fileIn.open(fileName.c_str()); 3467 3468 newName = vpName; 3469 while ((int) newName.size() < MAX_VP_NAME) 3470 newName += " "; 3471 3472 getline(fileIn, line); 3473 pos = fileIn.tellg(); 3474 while (getline(fileIn, line)) { 3475 end = line.find_last_not_of(' '); 3476 line = line.substr(0, end + 1); 3477 #if QT_VERSION < 0x060000 3478 if (!strcmp(line.c_str(), curViewPtName)) { 3479 #else 3480 if (!strcmp(line.c_str(), curViewPtName.c_str())) { 3481 #endif 3482 fileOut.seekp(pos); 3483 fileOut << newName; 3484 fileOut.seekp(0, std::ios::end); // Set the file pointer to the end of the file 3485 break; 3486 } 3487 while (line.size()) 3488 getline(fileIn, line); 3489 pos = fileIn.tellg(); 3490 } 3491 3492 fileIn.close(); 3493 fileIn.clear(); 3494 3495 while (idx < size) { 3496 #if QT_VERSION < 0x060000 3497 if (!strcmp(viewPtList[idx].viewPtName, curViewPtName)) { 3498 strcpy(viewPtList[idx].viewPtName, vpName); 3499 #else 3500 if (!strcmp(viewPtList[idx].viewPtName.c_str(), curViewPtName.c_str())) { 3501 viewPtList[idx].viewPtName = std::string(vpName); 3502 #endif 3503 break; 3504 } 3505 idx++; 3506 } 3507 } 3508 3509 3510 void G4OpenInventorQtExaminerViewer::SortBookmarksCB() 3511 { 3512 // FWJ NOTE: Xt version of this does not work (does nothing) 3513 3514 // G4cout << "Sort Button: SortBookmarks CALLBACK" << G4endl; 3515 3516 // FWJ List for sorting 3517 // The dialog list and bookmark file will be rewritten. 3518 // Simpler to populate this list from the data structure. 3519 3520 std::vector<std::string> charList; 3521 3522 if (viewPtList.size() < 2) return; 3523 3524 // Get current entries from the list 3525 3526 for (int i = 0; i < (int)viewPtList.size(); i++) { 3527 3528 charList.push_back(viewPtList[i].viewPtName); 3529 // G4cout << " Pushed " << i << " " << charList[i] << G4endl; 3530 } 3531 3532 std::sort(charList.begin(), charList.end()); 3533 3534 // FWJ POPULATE the new dialog list 3535 // G4cout << " Populating Bookmark listWidget..." << G4endl; 3536 AuxWindowDialog->listWidget->clear(); 3537 3538 for (int i = 0; i < (int)viewPtList.size(); i++) { 3539 // viewPtIdx has to be changed to account for a different order in viewPtList 3540 #if QT_VERSION < 0x060000 3541 if (!strcmp(charList[i].c_str(), curViewPtName)) 3542 #else 3543 if (!strcmp(charList[i].c_str(), curViewPtName.c_str())) 3544 #endif 3545 viewPtIdx = i; 3546 new QListWidgetItem(charList[i].c_str(), AuxWindowDialog->listWidget); 3547 3548 } 3549 3550 sortViewPts(charList); 3551 3552 } 3553 3554 // Rewrites entire viewpoint file with sorted viewpoints. 3555 3556 void G4OpenInventorQtExaminerViewer::sortViewPts(std::vector<std::string> sortedViewPts) 3557 { 3558 SbVec3f axis; 3559 float x, y, z, angle; 3560 std::size_t sortIdx = 0, unsortIdx = 0; 3561 3562 if (fileOut.is_open()) 3563 fileOut.close(); 3564 3565 fileOut.open(fileName.c_str()); // Erase current viewpoint file 3566 3567 writeViewPtIdx(); 3568 3569 std::size_t size = sortedViewPts.size(); 3570 while (sortIdx < size) { 3571 while (strcmp(sortedViewPts[sortIdx].c_str(), 3572 #if QT_VERSION < 0x060000 3573 viewPtList[unsortIdx].viewPtName)) 3574 #else 3575 viewPtList[unsortIdx].viewPtName.c_str())) 3576 #endif 3577 unsortIdx++; 3578 3579 std::string vpName = viewPtList[unsortIdx].viewPtName; 3580 3581 while ((int) vpName.size() < MAX_VP_NAME) 3582 vpName += " "; 3583 fileOut << vpName << std::endl; 3584 viewPtList[unsortIdx].position.getValue(x, y, z); 3585 fileOut << x << " " << y << " " << z << std::endl; 3586 3587 // Reusing x, y and z for storing the axis 3588 viewPtList[unsortIdx].orientation.getValue(axis, angle); 3589 axis.getValue(x, y, z); 3590 fileOut << x << " " << y << " " << z << " " << angle << std::endl; 3591 3592 fileOut << viewPtList[unsortIdx].camType << " " 3593 << viewPtList[unsortIdx].height << std::endl; 3594 fileOut << viewPtList[unsortIdx].focalDistance << " "; 3595 3596 fileOut << viewPtList[unsortIdx].nearDistance << " "; 3597 3598 fileOut << viewPtList[unsortIdx].farDistance << std::endl; 3599 3600 fileOut << viewPtList[unsortIdx].viewportMapping << " "; 3601 fileOut << viewPtList[unsortIdx].aspectRatio << "\n" << std::endl; 3602 fileOut.flush(); 3603 3604 unsortIdx = 0; 3605 sortIdx++; 3606 } 3607 } 3608 3609 // Needed to implement mouse wheel zoom direction change. 3610 // Does not work with MacOS trackpad: use Coin3d default handler. 3611 // Emulating private method SoGuiFullViewerP::zoom() 3612 #ifndef __APPLE__ 3613 void 3614 G4OpenInventorQtExaminerViewer::zoom(const float diffvalue) 3615 { 3616 float multiplicator = float(std::exp(diffvalue)); 3617 SoCamera *cam = getCamera(); 3618 3619 if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { 3620 const float oldfocaldist = cam->focalDistance.getValue(); 3621 const float newfocaldist = oldfocaldist * multiplicator; 3622 3623 SbVec3f direction; 3624 cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); 3625 3626 const SbVec3f oldpos = cam->position.getValue(); 3627 const SbVec3f newpos = oldpos + (newfocaldist - oldfocaldist) * -direction; 3628 cam->position = newpos; 3629 cam->focalDistance = newfocaldist; 3630 } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { 3631 SoOrthographicCamera * oc = (SoOrthographicCamera *)cam; 3632 oc->height = oc->height.getValue() * multiplicator; 3633 } 3634 } 3635 #endif 3636 3637 // Handling mouse and keyboard events 3638 3639 SbBool 3640 G4OpenInventorQtExaminerViewer::processSoEvent(const SoEvent* const ev) 3641 { 3642 3643 // FWJ DEBUG 3644 // G4cout << "processSoEvent ############" << ++processSoEventCount << G4endl; 3645 3646 SoCamera *cam = getCamera(); 3647 const SoType type(ev->getTypeId()); 3648 3649 // Needed to implement mouse wheel zoom direction change. 3650 // Does not work with MacOS trackpad: use Coin3d default handler. 3651 #ifndef __APPLE__ 3652 if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { 3653 SoMouseButtonEvent * me = (SoMouseButtonEvent *) ev; 3654 3655 // if (currentState == ANIMATION || currentState == REVERSED_ANIMATION 3656 // || currentState == PAUSED_ANIMATION) { 3657 3658 switch (me->getButton()) { 3659 3660 case SoMouseButtonEvent::BUTTON4: // Scroll wheel up 3661 if (me->getState() == SoButtonEvent::DOWN) { 3662 // G4cout << "SCROLL WHEEL UP" << G4endl; 3663 zoom(-0.1f); 3664 return TRUE; 3665 } 3666 break; 3667 3668 case SoMouseButtonEvent::BUTTON5: // Scroll wheel down 3669 if (me->getState() == SoButtonEvent::DOWN) { 3670 // G4cout << "SCROLL WHEEL DOWN" << G4endl; 3671 zoom(0.1f); 3672 return TRUE; 3673 } 3674 break; 3675 3676 default: 3677 break; 3678 } 3679 // } 3680 if (currentState == GENERAL) { 3681 3682 } 3683 } 3684 #endif 3685 3686 if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { 3687 SoKeyboardEvent* ke = (SoKeyboardEvent*)ev; 3688 3689 if (SoKeyboardEvent::isKeyPressEvent(ev, ke->getKey())) { 3690 switch (ke->getKey()) { 3691 case SoKeyboardEvent::E: 3692 if (externalQtApp) { 3693 // G4cout << "E KEY PRESSED" << G4endl; 3694 return TRUE; 3695 } else { 3696 G4cout << 3697 "E KEY PRESSED, EXITING OIQT VIEWER SECONDARY LOOP" << 3698 G4endl; 3699 SoQt::exitMainLoop(); 3700 // escapeCallback(); 3701 return TRUE; 3702 } 3703 case SoKeyboardEvent::LEFT_SHIFT: 3704 this->lshiftdown = true; 3705 return TRUE; 3706 case SoKeyboardEvent::RIGHT_SHIFT: 3707 this->rshiftdown = true; 3708 return TRUE; 3709 case SoKeyboardEvent::LEFT_CONTROL: 3710 this->lctrldown = true; 3711 return TRUE; 3712 case SoKeyboardEvent::RIGHT_CONTROL: 3713 this->rctrldown = true; 3714 return TRUE; 3715 case SoKeyboardEvent::SPACE: 3716 if (currentState == ANIMATION 3717 || currentState == REVERSED_ANIMATION) { 3718 beforePausing = currentState; 3719 currentState = PAUSED_ANIMATION; 3720 if (animateSensor->isScheduled()) 3721 animateSensor->unschedule(); 3722 return TRUE; 3723 } else if (currentState == PAUSED_ANIMATION) { 3724 if (maxSpeed) { 3725 if ((beforePausing == ANIMATION 3726 && refParticleIdx 3727 < (int) refParticleTrajectory.size() - 1) 3728 || (beforePausing == REVERSED_ANIMATION 3729 && refParticleIdx > 0)) { 3730 currentState = beforePausing; 3731 animateRefParticle(); 3732 } 3733 } 3734 return TRUE; 3735 } 3736 break; 3737 case SoKeyboardEvent::ESCAPE: 3738 if (currentState == ANIMATION 3739 || currentState == REVERSED_ANIMATION 3740 || currentState == PAUSED_ANIMATION) { 3741 3742 if (animateSensor->isScheduled()) 3743 animateSensor->unschedule(); 3744 currentState = prevState; 3745 refParticleIdx = prevRefIdx; 3746 setSuperimpositionEnabled(superimposition, FALSE); 3747 maxSpeed = 0.0f; 3748 step = 1; 3749 3750 scheduleRedraw(); 3751 if (currentState == VIEWPOINT) { 3752 setSuperimpositionEnabled(superimposition, TRUE); 3753 axisSwitch->whichChild.setValue(SO_SWITCH_NONE); 3754 animSpeedOutlineSwitch->whichChild.setValue( 3755 SO_SWITCH_NONE); 3756 animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); 3757 3758 scheduleRedraw(); 3759 } 3760 restoreCamera(); 3761 return TRUE; 3762 } 3763 break; 3764 case SoKeyboardEvent::DELETE: 3765 if (viewPtList.size() 3766 && (currentState != ANIMATION 3767 && currentState != REVERSED_ANIMATION 3768 && currentState != PAUSED_ANIMATION)) { 3769 // FWJ IMPLEMENT LATER 3770 // String dialogName = (char *) "Delete Viewpoint"; 3771 // std::string msg = "Are you sure you want to delete current viewpoint?"; 3772 // warningMsgDialog(msg, dialogName, deleteViewPtCB); 3773 return TRUE; 3774 } 3775 break; 3776 case SoKeyboardEvent::LEFT_ARROW: 3777 switch (currentState) { 3778 case BEAMLINE: 3779 if ((this->lshiftdown) || (this->rshiftdown)) { 3780 refParticleIdx -= step; 3781 moveCamera(); 3782 } 3783 else if ((this->lctrldown) || (this->rctrldown)) { 3784 if (SoQtExaminerViewer::isAnimating()) 3785 stopAnimating(); 3786 prevState = currentState; 3787 currentState = ROTATING; 3788 animateBtwPtsPeriod = 0.08f; 3789 3790 SbVec3f tmp = camDir; 3791 tmp.negate(); 3792 rotAxis = tmp; 3793 3794 rotCnt = ROT_CNT; 3795 moveCamera(); // To make sure camera is perpendicular to the beamline 3796 rotateCamera(); 3797 } 3798 else { 3799 if (SoQtExaminerViewer::isAnimating()) 3800 stopAnimating(); 3801 prevState = currentState; 3802 currentState = ROTATING; 3803 animateBtwPtsPeriod = 0.08f; 3804 3805 SbVec3f tmp = camUpVec; 3806 tmp.negate(); 3807 rotAxis = tmp; 3808 3809 rotCnt = ROT_CNT; 3810 moveCamera(); // To make sure camera is perpendicular to the beamline 3811 rotateCamera(); 3812 3813 } 3814 return TRUE; 3815 3816 case ANIMATION: 3817 case REVERSED_ANIMATION: 3818 left_right -= 1.5f; 3819 return TRUE; 3820 case PAUSED_ANIMATION: 3821 left_right -= 1.5f; 3822 setStartingPtForAnimation(); 3823 cam->position = myCam->position; 3824 return TRUE; 3825 case GENERAL: 3826 case VIEWPOINT: 3827 if ((!this->lshiftdown) && (!this->rshiftdown)) { 3828 // Using this allows us to look around without 3829 // changing the camera parameters (camDir, camUpVec) 3830 this->bottomWheelMotion( 3831 this->getBottomWheelValue() + 0.1f); 3832 3833 return TRUE; 3834 } 3835 break; 3836 case ROTATING: 3837 // For this state, let the keyboard event 3838 // be handled by superclass 3839 break; 3840 default: 3841 SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", 3842 "Unhandled viewer state"); 3843 break; 3844 } 3845 break; 3846 3847 case SoKeyboardEvent::RIGHT_ARROW: 3848 switch(currentState) { 3849 case BEAMLINE: 3850 if ((this->lshiftdown) || (this->rshiftdown)) { 3851 refParticleIdx += step; 3852 moveCamera(); 3853 } 3854 else if ((this->lctrldown) || (this->rctrldown)) { 3855 if (SoQtExaminerViewer::isAnimating()) 3856 stopAnimating(); 3857 prevState = currentState; 3858 currentState = ROTATING; 3859 animateBtwPtsPeriod = 0.08f; 3860 3861 rotAxis = camDir; 3862 3863 rotCnt = ROT_CNT; 3864 moveCamera(); // To make sure camera is perpendicular to the beamline 3865 rotateCamera(); 3866 } 3867 else{ 3868 if (SoQtExaminerViewer::isAnimating()) 3869 stopAnimating(); 3870 prevState = currentState; 3871 currentState = ROTATING; 3872 animateBtwPtsPeriod = 0.08f; 3873 3874 rotAxis = camUpVec; 3875 3876 rotCnt = ROT_CNT; 3877 moveCamera(); // To make sure camera is perpendicular to the beamline 3878 rotateCamera(); 3879 } 3880 return TRUE; 3881 3882 case ANIMATION: 3883 case REVERSED_ANIMATION: 3884 left_right += 1.5f; 3885 return TRUE; 3886 case PAUSED_ANIMATION: 3887 left_right += 1.5f; 3888 setStartingPtForAnimation(); 3889 cam->position = myCam->position; 3890 return TRUE; 3891 case GENERAL: 3892 case VIEWPOINT: 3893 if ((!this->lshiftdown) && (!this->rshiftdown)) { 3894 // Using this allows us to look around without 3895 // changing the camera parameters (camDir, camUpVec) 3896 this->bottomWheelMotion( 3897 this->getBottomWheelValue() - 0.1f); 3898 return TRUE; 3899 } 3900 break; 3901 case ROTATING: 3902 // For this state, let the keyboard event 3903 // be handled by superclass 3904 break; 3905 default: 3906 SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", 3907 "Unhandled viewer state"); 3908 break; 3909 } 3910 break; 3911 3912 case SoKeyboardEvent::DOWN_ARROW: 3913 switch(currentState) { 3914 case BEAMLINE: 3915 3916 if ((this->lshiftdown) || (this->rshiftdown)) { 3917 refParticleIdx -= step; 3918 moveCamera(); 3919 } 3920 else{ 3921 if (SoQtExaminerViewer::isAnimating()) 3922 stopAnimating(); 3923 prevState = currentState; 3924 currentState = ROTATING; 3925 animateBtwPtsPeriod = 0.08f; 3926 3927 rotAxis = camDir.cross(camUpVec); 3928 3929 rotCnt = ROT_CNT; 3930 moveCamera(); // To make sure camera is perpendicular to the beamline 3931 rotateCamera(); 3932 3933 } 3934 return TRUE; 3935 3936 case ANIMATION: 3937 case REVERSED_ANIMATION: 3938 up_down -= 1.5f; 3939 return TRUE; 3940 case PAUSED_ANIMATION: 3941 up_down -= 1.5f; 3942 setStartingPtForAnimation(); 3943 cam->position = myCam->position; 3944 return TRUE; 3945 case GENERAL: 3946 case VIEWPOINT: 3947 // Using this allows us to look around without 3948 // changing the camera parameters (camDir, camUpVec) 3949 if ((!this->lshiftdown) && (!this->rshiftdown)) { 3950 this->leftWheelMotion(this->getLeftWheelValue() - 0.1f); 3951 return TRUE; 3952 } 3953 break; 3954 case ROTATING: 3955 // For this state, let the keyboard event 3956 // be handled by superclass 3957 break; 3958 default: 3959 SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", 3960 "Unhandled viewer state"); 3961 break; 3962 } 3963 break; 3964 3965 case SoKeyboardEvent::UP_ARROW: 3966 switch(currentState) { 3967 case BEAMLINE: 3968 if ((this->lshiftdown) || (this->rshiftdown)) { 3969 refParticleIdx -= step; 3970 moveCamera(); 3971 } 3972 else{ 3973 if (SoQtExaminerViewer::isAnimating()) 3974 stopAnimating(); 3975 prevState = currentState; 3976 currentState = ROTATING; 3977 animateBtwPtsPeriod = 0.08f; 3978 3979 rotAxis = camUpVec.cross(camDir); 3980 3981 rotCnt = ROT_CNT; 3982 moveCamera(); 3983 3984 rotateCamera(); 3985 3986 3987 } 3988 return TRUE; 3989 case ANIMATION: 3990 case REVERSED_ANIMATION: 3991 up_down += 1.5f; 3992 return TRUE; 3993 case PAUSED_ANIMATION: 3994 up_down += 1.5f; 3995 setStartingPtForAnimation(); 3996 cam->position = myCam->position; 3997 return TRUE; 3998 case GENERAL: 3999 case VIEWPOINT: 4000 // Using this allows us to look around without 4001 // changing the camera parameters (camDir, camUpVec) 4002 if ((!this->lshiftdown) && (!this->rshiftdown)) { 4003 this->leftWheelMotion(this->getLeftWheelValue() + 0.1f); 4004 return TRUE; 4005 } 4006 break; 4007 case ROTATING: 4008 // For this state, let the keyboard event 4009 // be handled by superclass 4010 break; 4011 default: 4012 SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", 4013 "Unhandled viewer state"); 4014 break; 4015 } 4016 break; 4017 4018 case SoKeyboardEvent::PAGE_UP: 4019 switch(currentState) { 4020 case BEAMLINE: 4021 if (step < (int) refParticleTrajectory.size() / 5) // Magic number 4022 step++; 4023 return TRUE; 4024 case ANIMATION: 4025 incSpeed(); 4026 maxSpeed += SPEED_INDICATOR_STEP; 4027 if (maxSpeed > 0.8) 4028 maxSpeed = MAX_SPEED_INDICATOR; 4029 scheduleRedraw(); 4030 4031 return TRUE; 4032 case REVERSED_ANIMATION: 4033 if(!animateSensor->isScheduled()) { 4034 currentState = ANIMATION; 4035 if (refParticleIdx 4036 < (int) refParticleTrajectory.size() - 1) { 4037 refParticleIdx++; 4038 maxSpeed = SPEED_INDICATOR_STEP; 4039 scheduleRedraw(); 4040 animateRefParticle(); 4041 } 4042 } 4043 else{ 4044 maxSpeed += SPEED_INDICATOR_STEP; 4045 decSpeed(); 4046 scheduleRedraw(); 4047 } 4048 return TRUE; 4049 case PAUSED_ANIMATION: 4050 maxSpeed += SPEED_INDICATOR_STEP; 4051 if (maxSpeed > 0.8) 4052 maxSpeed = MAX_SPEED_INDICATOR; 4053 4054 if (beforePausing == ANIMATION) { 4055 incSpeed(); 4056 } else { 4057 decSpeed(); 4058 if (animateBtwPtsPeriod >= MIN_SPEED) 4059 beforePausing = ANIMATION; 4060 } 4061 4062 scheduleRedraw(); 4063 return TRUE; 4064 default: //fall through 4065 break; 4066 } 4067 break; 4068 4069 case SoKeyboardEvent::PAGE_DOWN: 4070 switch(currentState) { 4071 case BEAMLINE: 4072 if (step > 1) 4073 step--; 4074 return TRUE; 4075 case ANIMATION: 4076 if(!animateSensor->isScheduled()) { 4077 currentState = REVERSED_ANIMATION; 4078 if (refParticleIdx > 1) { 4079 refParticleIdx--; 4080 maxSpeed = -SPEED_INDICATOR_STEP; 4081 scheduleRedraw(); 4082 animateRefParticle(); 4083 } 4084 } 4085 else{ 4086 maxSpeed -= SPEED_INDICATOR_STEP; 4087 decSpeed(); 4088 scheduleRedraw(); 4089 } 4090 return TRUE; 4091 case REVERSED_ANIMATION: 4092 incSpeed(); 4093 maxSpeed -= SPEED_INDICATOR_STEP; 4094 if (maxSpeed < -0.8) 4095 maxSpeed = -MAX_SPEED_INDICATOR; 4096 scheduleRedraw(); 4097 return TRUE; 4098 case PAUSED_ANIMATION: 4099 maxSpeed -= SPEED_INDICATOR_STEP; 4100 if (maxSpeed < -0.8) 4101 maxSpeed = -MAX_SPEED_INDICATOR; 4102 if (beforePausing == REVERSED_ANIMATION) { 4103 incSpeed(); 4104 } else { 4105 decSpeed(); 4106 if (animateBtwPtsPeriod >= MIN_SPEED) 4107 beforePausing = REVERSED_ANIMATION; 4108 } 4109 scheduleRedraw(); 4110 return TRUE; 4111 default: 4112 //fall through 4113 break; 4114 } 4115 break; 4116 4117 // FROM XT VIEWER 4118 // case SoKeyboardEvent::E: 4119 // this->escapeCallback(this->examinerObject); 4120 // break; 4121 4122 default: 4123 break; // To get rid of compiler warnings 4124 } 4125 } 4126 if (SoKeyboardEvent::isKeyReleaseEvent(ev, ke->getKey())) { 4127 switch (ke->getKey()) { 4128 case SoKeyboardEvent::LEFT_SHIFT: 4129 this->lshiftdown = false; 4130 return TRUE; 4131 case SoKeyboardEvent::RIGHT_SHIFT: 4132 this->rshiftdown = false; 4133 return TRUE; 4134 case SoKeyboardEvent::LEFT_CONTROL: 4135 this->lctrldown = false; 4136 return TRUE; 4137 case SoKeyboardEvent::RIGHT_CONTROL: 4138 this->rctrldown = false; 4139 return TRUE; 4140 default: 4141 break; 4142 } 4143 } 4144 } 4145 4146 // Pass the event on to the viewer 4147 // Need some checks here as in Xt viewer? 4148 4149 if (currentState == ANIMATION || currentState == REVERSED_ANIMATION 4150 || currentState == ROTATING) 4151 return FALSE; 4152 else 4153 return SoQtExaminerViewer::processSoEvent(ev); 4154 } 4155 4156 4157 // REMAINDER OF MENU BAR FUNCTIONS... 4158 4159 4160 void G4OpenInventorQtExaminerViewer::FileLoadSceneGraphCB() 4161 { 4162 // G4cout << "File: Load scene graph CALLBACK" << G4endl; 4163 4164 QFileDialog filedialog(getParentWidget(), tr("Load Scene Graph")); 4165 filedialog.setFileMode(QFileDialog::AnyFile); 4166 filedialog.setFont(*font); 4167 if (!filedialog.exec()) return; 4168 QStringList filenameinlist = filedialog.selectedFiles(); 4169 QString filenamein = filenameinlist[0]; 4170 4171 SoInput sceneInput; 4172 4173 if (sceneInput.openFile(qPrintable(filenamein))) { 4174 // Read the whole file into the database 4175 newSceneGraph = SoDB::readAll(&sceneInput); 4176 if (newSceneGraph == NULL) { 4177 QMessageBox msgbox; 4178 msgbox.setFont(*font); 4179 QString messagetxt = "Error reading scene graph file "; 4180 messagetxt.append(filenamein); 4181 msgbox.setText(messagetxt); 4182 msgbox.exec(); 4183 sceneInput.closeFile(); 4184 return; 4185 } 4186 } else { 4187 QMessageBox msgbox; 4188 msgbox.setFont(*font); 4189 QString messagetxt = "Error opening scene graph file "; 4190 messagetxt.append(filenamein); 4191 msgbox.setText(messagetxt); 4192 msgbox.exec(); 4193 return; 4194 } 4195 4196 SoSeparator* root = (SoSeparator*)getSceneGraph(); 4197 root->unref(); 4198 newSceneGraph->ref(); 4199 setSceneGraph(newSceneGraph); 4200 } 4201 4202 void G4OpenInventorQtExaminerViewer::FileSaveSceneGraphCB() 4203 { 4204 // G4cout << "File: Save scene graph CALLBACK" << G4endl; 4205 4206 QFileDialog filedialog(getParentWidget(), tr("Save scene graph")); 4207 filedialog.setFileMode(QFileDialog::AnyFile); 4208 // To enable confirmation of overwriting 4209 filedialog.setAcceptMode(QFileDialog::AcceptSave); 4210 filedialog.setFont(*font); 4211 if (!filedialog.exec()) return; 4212 QStringList filenameinlist = filedialog.selectedFiles(); 4213 QString filenamein = filenameinlist[0]; 4214 4215 SoWriteAction writeAction; 4216 SoSeparator* root = (SoSeparator*)getSceneGraph(); 4217 4218 SoOutput* out = writeAction.getOutput(); 4219 4220 if (out->openFile(qPrintable(filenamein))) { 4221 out->setBinary(FALSE); 4222 writeAction.apply(root); 4223 out->closeFile(); 4224 } else { 4225 QMessageBox msgbox; 4226 msgbox.setFont(*font); 4227 QString messagetxt = "Error opening file "; 4228 messagetxt.append(filenamein); 4229 msgbox.setText(messagetxt); 4230 msgbox.exec(); 4231 } 4232 } 4233 4234 4235 void G4OpenInventorQtExaminerViewer::HelpControlsCB() 4236 { 4237 // G4cout << "Help: Help Controls CALLBACK" << G4endl; 4238 helpmsgbox->show(); 4239 } 4240 4241 4242 HookEventProcState::HookEventProcState(G4OpenInventorQtExaminerViewer* vwr) 4243 { 4244 viewer = vwr; 4245 } 4246 4247 HookEventProcState::~HookEventProcState() 4248 {;} 4249 4250 G4bool HookEventProcState::Notify(G4ApplicationState requestedState) 4251 { 4252 #if QT_VERSION < 0x060000 4253 if (requestedState == G4State_EventProc) viewer->newEvents = true; 4254 #else 4255 #ifdef G4MULTITHREADED 4256 //G.Barrand: on the master thread, we are not notified of end of events, 4257 // we raise the newEvents flag on the end of run. 4258 G4StateManager* stateManager = G4StateManager::GetStateManager(); 4259 G4ApplicationState previousState = stateManager->GetPreviousState(); 4260 //if (previousState == G4State_Idle && requestedState == G4State_GeomClosed) //BeginOfRun 4261 //if (previousState == G4State_GeomClosed && requestedState == G4State_EventProc) //BeginOfEvent 4262 //if (previousState == G4State_EventProc && requestedState == G4State_GeomClosed) //EndOfEvent 4263 if (previousState == G4State_GeomClosed && requestedState == G4State_Idle) { //EndOfRun 4264 viewer->newEvents = true; 4265 } 4266 #else 4267 if (requestedState == G4State_EventProc) viewer->newEvents = true; 4268 #endif 4269 #endif 4270 return true; 4271 } 4272