// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // Frederick Jones TRIUMF 07 January 2018 #include "G4OpenInventorQtExaminerViewer.hh" #include "ui_OIQtListsDialog.h" #include "saveViewPt.h" #include "pickext.h" #include "pickref.h" #include "wireframe.h" #include // For using sort on a vector #include "G4ios.hh" #include "G4UImanager.hh" #include "G4UIQt.hh" #include #include #include #include #include #include #include #include // FWJ moved to header file //#include #include #include #include #include #include #include #include // Animation #include // Detect start of run #include "Geant4_SoPolyhedron.h" #include "G4TrajectoryPoint.hh" #include "G4AttHolder.hh" #include "G4AttCheck.hh" #include #include #include #include #include #include #include // For rendering distance during animation: #include #include #include #include #include // For searching for nodes within kits: #include #include #include #include #include #include #include #include #include #include #include #include //#include #ifndef G4GMAKE #include "moc_G4OpenInventorQtExaminerViewer.cpp" #endif G4OpenInventorQtExaminerViewer* G4OpenInventorQtExaminerViewer::viewer = 0; #define MIN_SPEED 2.1 // Lower number means faster #define START_STEP 0.3 #define SPEED_INDICATOR_STEP 0.045 #define MAX_SPEED_INDICATOR 0.81 // Number of steps 90 degree rotation around an element is split into #define ROT_CNT 6 // Constructor G4OpenInventorQtExaminerViewer:: G4OpenInventorQtExaminerViewer(QWidget* parent, const char* name, SbBool embed, SoQtFullViewer::BuildFlag flag, SoQtViewer::Type type) : SoQtExaminerViewer(parent, name, embed, flag, type), externalQtApp(0), processSoEventCount(0) { // FWJ DEBUG // G4cout << "G4OpenInventorQtExaminerViewer CONSTRUCTOR CALLED" << G4endl; // G4cout << "G4OpenInventorQtExaminerViewer parent=" << parent << G4endl; // FWJ THIS DOESN'T WORK APPARENTLY NO MAINWINDOW // QMenuBar* menubar = ((QMainWindow*)parent)->menuBar(); fName = new QString(name); viewer = this; construct(TRUE); } // Destructor G4OpenInventorQtExaminerViewer::~G4OpenInventorQtExaminerViewer() { // if (superimposition != NULL) { // removeSuperimposition(superimposition); // superimposition->unref(); // superimposition = NULL; // } // if (animateSensor->isScheduled()) // animateSensor->unschedule(); // delete animateSensor; // delete sceneChangeSensor; // delete[] curViewPtName; // delete searcher; viewer = 0; } void G4OpenInventorQtExaminerViewer::construct(const SbBool) { setFeedbackSize(40); hookBeamOn = new HookEventProcState(this); newEvents = false; buildWidget(getParentWidget()); fileName = "bookmarkFile"; // Default viewpoint file name viewPtIdx = -1; // index of the most recent viewpoint in viewPtList vector animateSensor = new SoTimerSensor(animateSensorCB, this); animateSensorRotation = new SoTimerSensor(animateSensorRotationCB, this); animateBtwPtsPeriod = MIN_SPEED; currentState = GENERAL; myCam = new SoPerspectiveCamera; MAX_VP_IDX = 3; MAX_VP_NAME = 35; // Max length of a viewpoint name, padded with spaces curViewPtName = new char[MAX_VP_NAME + 1]; left_right = up_down = 0; // For movements around the beam during animation speedStep = START_STEP; // For smoother animation speed increase/decrease rotUpVec = false; // Used during scene element rotations step = 1; //By default // Used for moving along the beam with the // mouse instead of rotating the view lshiftdown = rshiftdown = false; // Used for rotating the view with the camera // staying in place lctrldown = rctrldown = false; // Used to send abbreviated output to the console when abbrOutputFlag = false; pickRefPathFlag = false; prevColorField = NULL; // warningFlag = false; // We come from the warning dialog // myElementList = NULL; // FWJ default path look-ahead pathLookahead = 5; newSceneGraph = NULL; zcoordSetFlag = false; //////////////////////////SUPERIMPOSED SCENE////////////////////////// searcher = NULL; // Used in animation; progressively scaled for gradual speed change maxSpeed = 0.0f; static const char * superimposed[] = { "#Inventor V2.1 ascii", "", "Separator ", "{", " MaterialBinding ", " {", " value OVERALL", " }", " OrthographicCamera ", " {", " height 1", " nearDistance 0", " farDistance 1", " }", " DEF soxt->callback Callback { }", " Separator ", " {", " DEF soxt->translation Translation ", " {", " translation 0 0 0", " }", " DEF soxt->scale Scale ", " {", " scaleFactor 1 1 1", " }", " DEF soxt->geometry Coordinate3 ", " {", " point ", " [", " -0.81 -0.04 0, -0.81 0 0,", " -0.81 0.04 0, 0 -0.04 0,", " 0 0 0, 0 0.04 0,", " 0.81 -0.04 0, 0.81 0 0,", " 0.81 0.04 0,", " 0 0.02 0,", // idx 9 " 0.81 0.02 0, 0.81 -0.02 0,", " 0 -0.02 0,", " 0 0.01 0,", // idx 13 " 0.4 0.01 0, 0.4 -0.01 0,", " 0 -0.01 0", " ]", " }", // current speed indicator (outline) " DEF soxt->animSpeedOutlineSwitch Switch ", " {", " whichChild -3", " Material ", " {", " emissiveColor 0 0 0", " }", " IndexedFaceSet ", " {", " coordIndex ", " [", " 12, 11, 10, 9, -1", " ]", " }", " }", // the coordinate system " DEF soxt->axisSwitch Switch ", " {", " whichChild -3", " BaseColor ", " {", " rgb 1 1 1", " }", " IndexedLineSet ", " {", " coordIndex ", " [", " 0, 2, -1,", " 3, 5, -1,", " 6, 8, -1,", " 1, 7, -1", " ]", " }", " }", // current speed indicator " DEF soxt->animSpeedSwitch Switch ", " {", " whichChild -3", " Material ", " {", " emissiveColor 0 1 0", " }", " IndexedFaceSet ", " {", " coordIndex ", " [", " 16, 15, 14, 13, -1", " ]", " }", " }", " }", // For displaying either z position (during animation) or current viewpoint name " DEF soxt->curInfoSwitch Switch ", " {", " whichChild -3", " DEF soxt->curInfoTrans Translation ", " {", " translation 0 0 0 ", // " translation 10 20 30 ", " }", " DEF soxt->curInfoFont Font ", " {", " name defaultFont:Bold", " size 16", " }", " DEF soxt->curInfoText Text2 ", " {", " string Hello", " }", " }", // Need to use different fields for mouseover // because newlines are ignored when the scene is rendered " Separator ", " {", " DEF soxt->mouseOverTransLogName Translation ", " {", " translation 0 0 0 ", " }", " DEF soxt->mouseOverFontLogName Font ", " {", " name defaultFont:Bold", " size 16", " }", " DEF soxt->mouseOverTextLogName Text2 { } ", " }", " Separator ", " {", " DEF soxt->mouseOverTransSolid Translation ", " {", " translation 0 0 0 ", " }", " DEF soxt->mouseOverFontSolid Font ", " {", " name defaultFont:Bold", " size 16", " }", " DEF soxt->mouseOverTextSolid Text2 { } ", " }", " Separator ", " {", " DEF soxt->mouseOverTransMaterial Translation ", " {", " translation 0 0 0 ", " }", " DEF soxt->mouseOverFontMaterial Font ", " {", " name defaultFont:Bold", " size 16", " }", " DEF soxt->mouseOverTextMaterial Text2 { } ", " }", " Separator ", " {", " DEF soxt->mouseOverTransZPos Translation ", " {", " translation 0 0 0 ", " }", " DEF soxt->mouseOverFontZPos Font ", " {", " name defaultFont:Bold", " size 16", " }", " DEF soxt->mouseOverTextZPos Text2 { } ", " }", "}", NULL }; int i, bufsize; for (i = bufsize = 0; superimposed[i]; i++) bufsize += strlen(superimposed[i]) + 1; char * buf = new char[bufsize + 1]; for (i = bufsize = 0; superimposed[i]; i++) { strcpy(buf + bufsize, superimposed[i]); bufsize += strlen(superimposed[i]); buf[bufsize] = '\n'; bufsize++; } SoInput * input = new SoInput; input->setBuffer(buf, bufsize); SbBool ok = SoDB::read(input, superimposition); (void)ok; // FWJ added to avoid compiler warning assert(ok); delete input; delete[] buf; superimposition->ref(); sscale = (SoScale *) getSuperimpositionNode(superimposition, "soxt->scale"); stranslation = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->translation"); sgeometry = (SoCoordinate3 *) getSuperimpositionNode(superimposition, "soxt->geometry"); axisSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->axisSwitch"); animSpeedOutlineSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->animSpeedOutlineSwitch"); animSpeedSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->animSpeedSwitch"); curInfoSwitch = (SoSwitch *) getSuperimpositionNode(superimposition, "soxt->curInfoSwitch"); curInfoTrans = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->curInfoTrans"); curInfoFont = (SoFont *) getSuperimpositionNode(superimposition, "soxt->curInfoFont"); curInfoText = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->curInfoText"); mouseOverTransLogName = (SoTranslation*)getSuperimpositionNode(superimposition, "soxt->mouseOverTransLogName"); mouseOverFontLogName = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontLogName"); mouseOverTextLogName = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextLogName"); mouseOverTransSolid = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->mouseOverTransSolid"); mouseOverFontSolid = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontSolid"); mouseOverTextSolid = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextSolid"); mouseOverTransMaterial = (SoTranslation*)getSuperimpositionNode(superimposition, "soxt->mouseOverTransMaterial"); mouseOverFontMaterial = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontMaterial"); mouseOverTextMaterial = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextMaterial"); mouseOverTransZPos = (SoTranslation *) getSuperimpositionNode(superimposition, "soxt->mouseOverTransZPos"); mouseOverFontZPos = (SoFont *) getSuperimpositionNode(superimposition, "soxt->mouseOverFontZPos"); mouseOverTextZPos = (SoText2 *) getSuperimpositionNode(superimposition, "soxt->mouseOverTextZPos"); SoCallback * cb = (SoCallback *) getSuperimpositionNode(superimposition, "soxt->callback"); cb->setCallback(superimpositionCB, this); addSuperimposition(superimposition); setSuperimpositionEnabled(superimposition, FALSE); axisSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); /////////////////////\SUPERIMPOSED SCENE/////////////////////////////////// } // Adds a menu bar and menu items to the viewer. void G4OpenInventorQtExaminerViewer::buildWidget(QWidget* parent) { if (!parent) SoDebugError::post("G4OpenInventorQtExaminerViewer::buildWidget", "Error: Parent is null."); // Common font for (almost) all widgets font = new QFont; font->setPointSize(12); // This font setting does not propagate to added child widgets - Why? parent->setFont(*font); // This propagates everywhere but would affect UIQt! // QApplication::setFont(*font); // MENU BAR menubar = new QMenuBar(getRenderAreaWidget()); // FWJ DEBUG // G4cout << "G4OpenInventorQtExaminerViewer: GOT A menubar=" << // menubar << G4endl; filemenu = new QMenu("File"); menubar->addMenu(filemenu); FileOpenBookmark = new QAction("Open Bookmark File", this); FileOpenBookmark->setFont(*font); connect(FileOpenBookmark, SIGNAL(triggered()), this, SLOT(FileOpenBookmarkCB())); filemenu->addAction(FileOpenBookmark); FileNewBookmark = new QAction("New Bookmark File", this); FileNewBookmark->setFont(*font); connect(FileNewBookmark, SIGNAL(triggered()), this, SLOT(FileNewBookmarkCB())); filemenu->addAction(FileNewBookmark); FileLoadRefPath = new QAction("Load Reference Path", this); FileLoadRefPath->setFont(*font); connect(FileLoadRefPath, SIGNAL(triggered()), this, SLOT(FileLoadRefPathCB())); filemenu->addAction(FileLoadRefPath); FileSaveRefPath = new QAction("Save Reference Path", this); FileSaveRefPath->setFont(*font); connect(FileSaveRefPath, SIGNAL(triggered()), this, SLOT(FileSaveRefPathCB())); filemenu->addAction(FileSaveRefPath); FileLoadSceneGraph = new QAction("Load scene graph", this); FileLoadSceneGraph->setFont(*font); connect(FileLoadSceneGraph, SIGNAL(triggered()), this, SLOT(FileLoadSceneGraphCB())); filemenu->addAction(FileLoadSceneGraph); FileSaveSceneGraph = new QAction("Save scene graph", this); FileSaveSceneGraph->setFont(*font); connect(FileSaveSceneGraph, SIGNAL(triggered()), this, SLOT(FileSaveSceneGraphCB())); filemenu->addAction(FileSaveSceneGraph); // Rest of File menu is done in G4OpenInventorQtViewer toolsmenu = new QMenu("Tools"); menubar->addMenu(toolsmenu); ToolsAnimateRefParticle = new QAction("Fly on Ref Path", this); ToolsAnimateRefParticle->setFont(*font); connect(ToolsAnimateRefParticle, SIGNAL(triggered()), this, SLOT(ToolsAnimateRefParticleCB())); toolsmenu->addAction(ToolsAnimateRefParticle); ToolsRefPathStart = new QAction("Go to start of Ref Path", this); ToolsRefPathStart->setFont(*font); connect(ToolsRefPathStart, SIGNAL(triggered()), this, SLOT(ToolsRefPathStartCB())); toolsmenu->addAction(ToolsRefPathStart); ToolsRefPathInvert = new QAction("Invert Ref Path", this); ToolsRefPathInvert->setFont(*font); connect(ToolsRefPathInvert, SIGNAL(triggered()), this, SLOT(ToolsRefPathInvertCB())); toolsmenu->addAction(ToolsRefPathInvert); etcmenu = new QMenu("Etc"); menubar->addMenu(etcmenu); // All Etc menu items are done in G4OpenInventorQtViewer helpmenu = new QMenu("Help"); menubar->addMenu(helpmenu); HelpControls = new QAction("Controls", this); HelpControls->setFont(*font); connect(HelpControls, SIGNAL(triggered()), this, SLOT(HelpControlsCB())); helpmenu->addAction(HelpControls); menubar->show(); // SoQtExaminerViewer::buildWidget(parent); // APP VIEWER BUTTONS have their own box on upper left // The built in viewer button list is PRIVATE saveViewPtButton = new QPushButton; saveViewPtButton->setIcon(QPixmap((const char **)saveViewPt_xpm)); saveViewPtButton->setIconSize(QSize(24,24)); saveViewPtButton->setToolTip("Bookmark this view"); connect(saveViewPtButton, SIGNAL(clicked()), this, SLOT(SaveViewPtCB())); addAppPushButton(saveViewPtButton); nextViewPtButton = new QPushButton; nextViewPtButton->setIconSize(QSize(24,24)); QCommonStyle style; nextViewPtButton->setIcon(style.standardIcon(QStyle::SP_ArrowRight)); nextViewPtButton->setToolTip("Next bookmark"); connect(nextViewPtButton, SIGNAL(clicked()), this, SLOT(NextViewPtCB())); addAppPushButton(nextViewPtButton); prevViewPtButton = new QPushButton; prevViewPtButton->setIconSize(QSize(24,24)); prevViewPtButton->setIcon(style.standardIcon(QStyle::SP_ArrowLeft)); prevViewPtButton->setToolTip("Previous bookmark"); connect(prevViewPtButton, SIGNAL(clicked()), this, SLOT(PrevViewPtCB())); addAppPushButton(prevViewPtButton); abbrOutputButton = new QPushButton; abbrOutputButton->setCheckable(true); abbrOutputButton->setIconSize(QSize(24,24)); abbrOutputButton->setIcon(QPixmap((const char **)pickext_xpm)); abbrOutputButton->setToolTip("Extended picking & readout"); connect(abbrOutputButton, SIGNAL(toggled(bool)), this, SLOT(AbbrOutputCB(bool))); addAppPushButton(abbrOutputButton); pickRefPathButton = new QPushButton; pickRefPathButton->setIconSize(QSize(24,24)); pickRefPathButton->setIcon(QPixmap((const char **)pickref_xpm)); pickRefPathButton->setToolTip("Pick ref trajectory"); connect(pickRefPathButton, SIGNAL(clicked()), this, SLOT(PickRefPathCB())); addAppPushButton(pickRefPathButton); switchWireFrameButton = new QPushButton; switchWireFrameButton->setCheckable(true); switchWireFrameButton->setIconSize(QSize(24,24)); switchWireFrameButton->setIcon(QPixmap((const char **)wireframe_xpm)); switchWireFrameButton->setToolTip("Switch wireframe/solid"); connect(switchWireFrameButton, SIGNAL(toggled(bool)), this, SLOT(SwitchWireFrameCB(bool))); addAppPushButton(switchWireFrameButton); switchAxesButton = new QPushButton; switchAxesButton->setCheckable(true); switchAxesButton->setText(QString("A")); switchAxesButton->setToolTip("Axes on/off"); connect(switchAxesButton, SIGNAL(toggled(bool)), this, SLOT(SwitchAxesCB(bool))); addAppPushButton(switchAxesButton); detachButton = new QPushButton; detachButton->setIconSize(QSize(24,24)); detachButton->setIcon(style.standardIcon(QStyle::SP_CommandLink)); detachButton->setToolTip("Detach viewer window"); connect(detachButton, SIGNAL(clicked()), this, SLOT(DetachCB())); // Used for UIQt only so check and add later // addAppPushButton(detachButton); // HELP WINDOW helpmsgbox = new QMessageBox(getParentWidget()); helpmsgbox->setWindowTitle("OIQt Controls"); helpmsgbox->setFont(*font); QString messagetxt = "\nVIEWING mode (Hand cursor):\n\n\ Left-button + pointer move: rotate\n\ Shift+Left-button + pointer move: pan\n\ Middle-button + pointer move: pan\n\ Ctrl+Shift+Left-button + pointer move: zoom\n\ Mouse wheel: zoom\n\ Right-button: popup menu\n\n\ PICKING mode (Arrow cursor):\n\n\ Click on a volume: geometry readout\n\ Click on a trajectory: particle & trajectory readout\n\ Ctrl + click on a volume: see daughters.\n\ Shift + click on a volume: see mother.\n\n\ EXTENDED PICKING mode (Arrow+ viewer button):\n\n\ Hover the mouse over a volume or trajectory for\n\ overlayed readout.\n\n\ ELEMENT NAVIGATION (requires Reference Path):\n\n\ Click on element in list: centers view on element\n\ Arrow keys: rotate in 90 degree steps around element \n\ Shift + Right Arrow: move to next element\n\ Shift + Left Arrow: move to previous element\n\n\ FLY mode (requires Reference Path):\n\n\ Page Up: Increase speed\n\ Page Down: Decrease speed (& reverse if wanted)\n\ Up Arrow: raise camera above path\n\ Down Arror: lower camera below path\n\ Escape: Exit fly mode"; helpmsgbox->setText(messagetxt); helpmsgbox->setModal(false); // helpmsgbox->setWindowModality(Qt::NonModal); // AUXILIARY LISTS WINDOW // Bypass the namespace in order to make a persistent object AuxWindowDialog = new Ui_Dialog; AuxWindow = new QDialog(parent); AuxWindowDialog->setupUi(AuxWindow); // SIGNALS connect(AuxWindowDialog->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(LoadBookmarkCB(QListWidgetItem*))); connect(AuxWindowDialog->listWidget1, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(LookAtSceneElementCB(QListWidgetItem*))); connect(AuxWindowDialog->pushButton_2, SIGNAL(clicked()), this, SLOT(DeleteBookmarkCB())); connect(AuxWindowDialog->pushButton_3, SIGNAL(clicked()), this, SLOT(RenameBookmarkCB())); connect(AuxWindowDialog->pushButton, SIGNAL(clicked()), this, SLOT(SortBookmarksCB())); // FWJ Better to do this after viewer window is realized // AuxWindow->show(); // AuxWindow->raise(); // AuxWindow->activateWindow(); } // Called right after buttons and widgets get realized. // It sets the viewpoint last accessed. void G4OpenInventorQtExaminerViewer::afterRealizeHook() { SoQtExaminerViewer::afterRealizeHook(); // Default height is used when selecting and viewing scene elements // FWJ Added defaultHeight for Ortho camera SoCamera *cam = getCamera(); if (cam) { if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { defaultHeightAngle = ((SoPerspectiveCamera *) cam)->heightAngle.getValue(); toggleCameraType(); defaultHeight = ((SoOrthographicCamera *) cam)->height.getValue(); toggleCameraType(); } else { defaultHeight = ((SoOrthographicCamera *) cam)->height.getValue(); toggleCameraType(); cam = getCamera(); if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) defaultHeightAngle = ((SoPerspectiveCamera *) cam)->heightAngle.getValue(); toggleCameraType(); } } // Open the default bookmark file fileIn.open(fileName.c_str()); if (!fileIn.fail()) { if (!loadViewPts()) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error reading bookmark file "; messagetxt.append(QString(fileName.c_str())); msgbox.setText(messagetxt); msgbox.exec(); } else { // Opens a file without erasing it fileOut.open(fileName.c_str(), std::ios::in); fileOut.seekp(0, std::ios::end); // For appending new data to the end // FWJ DEBUG // G4cout << "afterRealizeHook: opened EXISTING bookmark file" // << G4endl; if (viewPtList.size()) { // FWJ disabled auto-selection of first viewpoint. // Initial view should be user-controllable & not forced // setViewPt(); addViewPoints(); } } fileIn.close(); } else { // Creates a new default bookmark file fileOut.open(fileName.c_str()); // FWJ DEBUG // G4cout << "afterRealizeHook: Opened a NEW bookmark file" << G4endl; } fileIn.clear(); SoSeparator* root = (SoSeparator*) (getSceneManager()->getSceneGraph()); if (root == NULL) SoDebugError::post("G4OpenInventorQtExaminerViewer::afterRealizeHook", "Root is null."); else { root->addChild(myCam); // For position/orientation calculation during animation } sceneChangeSensor = new SoNodeSensor; sceneChangeSensor->setFunction(sceneChangeCB); sceneChangeSensor->attach(root); sceneChangeSensor->setData(this); ///////////////////////////// MOUSEOVER & PICK ///////////////////// // Monitor mouseover events for displaying the name of scene elements // An SoEventCallback is needed instead of using the default processSoEvent // because that last one does not provide us with an SoPath to the object // that was picked SoEventCallback *moCB = new SoEventCallback; moCB->addEventCallback( SoLocation2Event::getClassTypeId(), mouseoverCB, static_cast(this)); root->addChild(moCB); // Override the default picking mechanism present in G4OpenInventorViewer // because we want abbreviated output when picking a trajectory SoEventCallback *pickCB = new SoEventCallback; pickCB->addEventCallback( SoMouseButtonEvent::getClassTypeId(), pickingCB, static_cast(this)); root->addChild(pickCB); ///////////////////////////// MOUSEOVER & PICK ///////////////////// AuxWindow->show(); AuxWindow->raise(); AuxWindow->activateWindow(); auto UI = G4UImanager::GetUIpointer(); uiQt = dynamic_cast(UI->GetG4UIWindow()); // This explicitly sets the TabWidget as parent before addTab(): if (uiQt) { viewerParent = getParentWidget(); viewerParent2 = viewerParent->parentWidget(); uiQt->AddTabWidget(getParentWidget(), *fName); uiQtTabIndex = uiQt->GetViewerTabWidget()->currentIndex(); // attached = TRUE; addAppPushButton(detachButton); } } // This method locates a named node in the superimposed or original scene. // FWJ RENAME THIS SoNode* G4OpenInventorQtExaminerViewer::getSuperimpositionNode(SoNode* root, const char* name) { if (!searcher) searcher = new SoSearchAction; searcher->reset(); searcher->setName(SbName(name)); searcher->setInterest(SoSearchAction::FIRST); searcher->setSearchingAll(TRUE); searcher->apply(root); assert(searcher->getPath()); return searcher->getPath()->getTail(); } // FWJ don't know why userdata is called "closure" // It contains the this pointer! void G4OpenInventorQtExaminerViewer::superimpositionCB(void * closure, SoAction * action) { if (closure) ((G4OpenInventorQtExaminerViewer*)closure)->superimpositionEvent(action); } // Renders and positions speed indicator and longitudinal // distance/viewpoint name on the drawing canvas void G4OpenInventorQtExaminerViewer::superimpositionEvent(SoAction * action) { if (!action->isOfType(SoGLRenderAction::getClassTypeId())) return; SbViewportRegion vpRegion = ((SoGLRenderAction*)action)->getViewportRegion(); SbVec2s viewportSize = vpRegion.getViewportSizePixels(); // Aspect is WIDTH/HEIGHT float aspect = float(viewportSize[0]) / float(viewportSize[1]); // FWJ DEBUG // G4cout << "SPEVENT X0 Y0 DX DY aspect: " << vpRegion.getViewportOrigin()[0] << // " " << vpRegion.getViewportOrigin()[1] << // " " << viewportSize[0] << // " " << viewportSize()[1] << // " " << aspect << G4endl; // Translation and scale factor for animation speed indicator... float factorx = 1.0f / float(viewportSize[1]) * 220.0f; float factory = factorx; if (aspect > 1.0f) { stranslation->translation.setValue(SbVec3f(0.0f, -0.4f, 0.0f)); } else { stranslation->translation.setValue(SbVec3f(0.0f, -0.4f / aspect, 0.0f)); factorx /= aspect; factory /= aspect; } if (viewportSize[0] > 500) factorx *= 500.0f / 400.0f; else factorx *= float(viewportSize[0]) / 400.0f; sscale->scaleFactor.setValue(SbVec3f(factorx, factory, 1.0f)); // TEXT OVERLAY... // FWJ Simplified and rewrote the following section to ease problems // with the overlayed text after a viewer window resize. // Result is now readable but needs further refinement of the scaling. float xInfo, yInfo, xLogName, yLogName, xSolid, ySolid, xMaterial, yMaterial, xZPos, yZPos; // Base point for navigation distance or viewpoint name // Origin is at center of render area. xInfo = -.475; yInfo = .475; // Menu bar height in same coordinates: float mbgap = 0.03; if (aspect > 1.) xInfo = xInfo*aspect; if (aspect < 1.) yInfo = yInfo/aspect; yInfo = yInfo - mbgap*aspect; // Following are relative to above base point xLogName = 0.0; yLogName = -.88 + mbgap*aspect; xSolid = 0.0; ySolid = -.91 + mbgap*aspect; xMaterial = 0.0; yMaterial = -.94 + mbgap*aspect; xZPos = 0.0; yZPos = -.97 + mbgap*aspect; // Top line curInfoTrans->translation.setValue(SbVec3f(xInfo, yInfo, 0.0)); // Bottom lines mouseOverTransLogName->translation.setValue(SbVec3f(xLogName, yLogName, 0.0)); mouseOverTransSolid->translation.setValue(SbVec3f(xSolid, ySolid, 0.0)); mouseOverTransMaterial->translation.setValue(SbVec3f(xMaterial, yMaterial, 0.0)); mouseOverTransZPos->translation.setValue(SbVec3f(xZPos, yZPos, 0.0)); if (currentState == VIEWPOINT) { // Displaying viewpoint name curInfoFont->size.setValue(15); curInfoFont->name.setValue("defaultFont:Italic"); curInfoText->string.setValue(SbString(curViewPtName)); } else if(currentState == GENERAL) { // Displaying longitudinal distance curInfoFont->size.setValue(16); curInfoFont->name.setValue("defaultFont:Bold"); curInfoText->string.setValue(SbString("")); } else { if (refParticleIdx < (int) refParticleTrajectory.size() - 1) { curInfoFont->size.setValue(16); curInfoFont->name.setValue("defaultFont:Bold"); char zPos[20]; // FWJ need a better format here sprintf(zPos, "%-7.2f [m]", refZPositions[refParticleIdx] / 1000); // sprintf(zPos, "%7.2f [m]", refZPositions[refParticleIdx] / 1000); curInfoText->string.setValue(SbString(zPos)); } } } // Loads view point data from a file into a vector. bool G4OpenInventorQtExaminerViewer::loadViewPts() { bool error = false; viewPtData tmp; std::string token; SbVec3f axis; SbRotation orient; float x, y, z, angle; // Gets the last view point accessed, stored in the first line of the data file. fileIn >> token; parseString(viewPtIdx, token, error); getline(fileIn, token); // Remove "\n" // Converts data from string type into necessary types while (getline(fileIn, token)) { int end = token.find_last_not_of(' '); // Remove padded spaces token = token.substr(0, end + 1); char *vpName = new char[token.size() + 1]; strcpy(vpName, token.c_str()); tmp.viewPtName = vpName; fileIn >> token; parseString(x, token, error); fileIn >> token; parseString(y, token, error); fileIn >> token; parseString(z, token, error); fileIn >> token; tmp.position = axis.setValue(x, y, z); parseString(x, token, error); fileIn >> token; parseString(y, token, error); fileIn >> token; parseString(z, token, error); fileIn >> token; parseString(angle, token, error); fileIn >> token; orient.setValue(axis.setValue(x, y, z), angle); tmp.orientation = orient.getValue(); int camType; parseString(camType, token, error); fileIn >> token; tmp.camType = (CameraType) camType; parseString(tmp.height, token, error); fileIn >> token; parseString(tmp.focalDistance, token, error); fileIn >> token; parseString(tmp.nearDistance, token, error); fileIn >> token; parseString(tmp.farDistance, token, error); fileIn >> token; parseString(tmp.viewportMapping, token, error); fileIn >> token; parseString(tmp.aspectRatio, token, error); getline(fileIn, token); // To remove "\n" characters getline(fileIn, token); if (error) { viewPtIdx = 0; viewPtList.clear(); return false; } viewPtList.push_back(tmp); } return true; } // Rotates camera 90 degrees around a scene element. // Rotation is animated for smoothness. void G4OpenInventorQtExaminerViewer::rotateCamera() { SoCamera *cam = getCamera(); SbRotation rot(rotAxis, M_PI / (2 * ROT_CNT)); rot.multVec(camDir, camDir); rot.multVec(camUpVec, camUpVec); SbVec3f camPosNew = prevPt - (camDir*distance); cam->position = camPosNew; cam->pointAt(prevPt, camUpVec); cam->focalDistance = (prevPt - camPosNew).length(); rotCnt--; if (animateSensorRotation->isScheduled()) { animateSensorRotation->unschedule(); } animateSensorRotation->setBaseTime(SbTime::getTimeOfDay()); animateSensorRotation->setInterval(SbTime(0.02)); animateSensorRotation->schedule(); } // Slides camera along the beamline. void G4OpenInventorQtExaminerViewer::moveCamera(float dist, bool lookdown) { SoCamera *cam = getCamera(); SbVec3f p1, p2; // The particle moves from p1 to p2 SbVec3f particleDir; // Direction vector from p1 to p2 SbVec3f camPosNew; // New position of the camera if(refParticleTrajectory.size() == 0) { //refParticleTrajectory hasn't been set yet if(dist) distance = dist; else distance = (cam->position.getValue() - center).length(); cam->position.setValue(center + offsetFromCenter*distance); cam->focalDistance = (cam->position.getValue() - center).length(); cam->pointAt(center, upVector); } else { // If we move forward past the last trajectory point, // go back to the beginning if (refParticleIdx >= (int) refParticleTrajectory.size() - 1) { prevPt = refParticleTrajectory[refParticleIdx - step]; dist = (prevPt - cam->position.getValue()).length(); refParticleIdx = 0; } // If we move backward past the beginning, // go to the last trajectory point if (refParticleIdx < 0) { prevPt = refParticleTrajectory[refParticleIdx + step]; dist = (prevPt - cam->position.getValue()).length(); refParticleIdx = refParticleTrajectory.size() - 2; } // Set start and end points p1 = refParticleTrajectory[refParticleIdx]; p2 = refParticleTrajectory[refParticleIdx + step]; // Get the direction from p1 to p2 particleDir = p2 - p1; particleDir.normalize(); if(prevParticleDir == SbVec3f(0,0,0)) { // First time entering BEAMLINE mode, look at // the element from the front, with camera upright if(lookdown) camDir = SbVec3f(0,0,1); else camDir = SbVec3f(1,0,0); camUpVec = SbVec3f(0,1,0); // In case the start of the goes in a // direction other than +z, rotate the camera accordingly SbRotation rot(SbVec3f(0,0,1), particleDir); rot.multVec(camDir, camDir); rot.multVec(camUpVec, camUpVec); } else if(particleDir != prevParticleDir) { // The beamline has changed direction SbRotation rot(prevParticleDir, particleDir); rot.multVec(camDir, camDir); rot.multVec(camUpVec, camUpVec); } if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { if (!dist) distance = (prevPt - cam->position.getValue()).length(); else distance = dist; } // FWJ distance not relevant -- use focalDistance // if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { // if (!dist) // distance = (prevPt - cam->position.getValue()).length(); // else // distance = dist; // } float x,y,z; prevPt.getValue(x,y,z); if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { camPosNew = p2 - (camDir*distance); } if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { // FWJ maintain focal distance camPosNew = p2 - (camDir*cam->focalDistance.getValue()); // camPosNew = p2 - (camDir); } cam->position = camPosNew; cam->pointAt(p2, camUpVec); cam->focalDistance = (p2 - camPosNew).length(); p2.getValue(x,y,z); camPosNew.getValue(x,y,z); prevParticleDir = particleDir; prevPt = p1; // For accurate distance calculation } } void G4OpenInventorQtExaminerViewer::pickingCB(void *aThis, SoEventCallback *eventCB) { SoHandleEventAction* action = eventCB->getAction(); const SoPickedPoint *pp = action->getPickedPoint(); G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*)aThis; if(pp != NULL) { SoPath* path = pp->getPath(); SoNode* node = ((SoFullPath*)path)->getTail(); if(node->getTypeId() == SoLineSet::getClassTypeId()) { if(This->pickRefPathFlag) { This->pickRefPathFlag = false; if(This->viewingBeforePickRef != This->isViewing()) This->setViewing(This->viewingBeforePickRef); else This->setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT)); // The trajectory is a set of lines stored in a LineSet SoLineSet * trajectory = (SoLineSet *)node; // FWJ DEBUG // G4cout << "FOUND trajectory LineSet" << trajectory << G4endl; // The set of all trajectories is stored in a Seperator group node // one level above the LineSet that was picked. The nodes under that // seperator are as follows (in this order): Material, LightModel, // ResetTransform, MatrixTransform, Coordinate3, DrawStyle, LineSet SoSeparator * grpNode = (SoSeparator*)(((SoFullPath*)path)->getNodeFromTail(1)); // The node that contains the coordinates for the trajectory is a // Coordinate3 node which occurs before the LineSet node. We iterate // back through the nodes in the group until we find the Coordinate3 node int nodeIndex = grpNode->findChild(trajectory); SoNode * tmpNode; // FWJ needs initialization SoCoordinate3 * coords = 0; // SoCoordinate3 * coords; // We allow only 100 iterations, in case the node isn't found // (should take only a few iterations) for(int i = 0; i < 100; ++i) { --nodeIndex; tmpNode = grpNode->getChild(nodeIndex); if(tmpNode->getTypeId() == SoCoordinate3::getClassTypeId()) { //node found coords = (SoCoordinate3 *)tmpNode; break; } } if(coords == NULL) { G4cout << "Could not find the coordinates node" " for the picked trajectory." << G4endl; G4cout << " Reference trajectory not set" << G4endl; return; } // FWJ DEBUG // G4cout << "FOUND SoCoordinate3 node " << coords << G4endl; if ((This->lshiftdown) || (This->rshiftdown)) This->setReferencePath(trajectory, coords, true); //APPENDING else This->setReferencePath(trajectory, coords, false); return; } else if(This->abbrOutputFlag) { G4AttHolder* attHolder = dynamic_cast(node); if(attHolder && attHolder->GetAttDefs().size()) { std::string strTrajPoint = "G4TrajectoryPoint:"; std::ostringstream oss; for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) { G4cout << G4AttCheck(attHolder->GetAttValues()[i], attHolder->GetAttDefs()[i]); oss << G4AttCheck(attHolder->GetAttValues()[i], attHolder->GetAttDefs()[i]); if(oss.str().find(strTrajPoint) != std::string::npos) { // Last attribute displayed was a trajectory point. Since we // want abbreviated output, display the last one and exit // (unless we're already at the last (and only) trajectory point) if(i != attHolder->GetAttDefs().size()-1) { G4cout << G4AttCheck( attHolder->GetAttValues()[attHolder->GetAttDefs().size()-1], attHolder->GetAttDefs()[attHolder->GetAttDefs().size()-1]); } break; } } } else { G4String name((char*)node->getName().getString()); G4String cls((char*)node->getTypeId().getName().getString()); G4cout << "SoNode : " << node << " SoType : " << cls << " name : " << name << G4endl; G4cout << "No attributes attached." << G4endl; } return; } else{ //Go to default behavior } } else { //Go to default behavior } // Default behavior in G4OpenInventorViewer::SelectionCB G4AttHolder* attHolder = dynamic_cast(node); if(attHolder && attHolder->GetAttDefs().size()) { for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) { G4cout << G4AttCheck(attHolder->GetAttValues()[i], attHolder->GetAttDefs()[i]); } } else { G4String name((char*)node->getName().getString()); G4String cls((char*)node->getTypeId().getName().getString()); G4cout << "SoNode : " << node << " SoType : " << cls << " name : " << name << G4endl; G4cout << "No attributes attached." << G4endl; } //Suppress other event handlers eventCB->setHandled(); } } void G4OpenInventorQtExaminerViewer::mouseoverCB(void *aThis, SoEventCallback *eventCB) { SoHandleEventAction* action = eventCB->getAction(); const SoPickedPoint* pp = action->getPickedPoint(); G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*)aThis; if(!This->abbrOutputFlag) return; if(pp != NULL) { const SbViewportRegion & viewportRegion = action->getViewportRegion(); std::string sLogName; float x,y,z; std::stringstream ssZPos; std::stringstream ssSolids; std::stringstream ssMaterials; SoPath * path = pp->getPath(); SoNode* node = ((SoFullPath*)path)->getTail(); if(node->getTypeId() == Geant4_SoPolyhedron::getClassTypeId()) { sLogName = "Logical Volume: "; sLogName += ((Geant4_SoPolyhedron *)node)->getName().getString(); SoGetBoundingBoxAction bAction(viewportRegion); bAction.apply((SoFullPath*)path); SbBox3f bBox = bAction.getBoundingBox(); SbVec3f centr = bBox.getCenter(); centr.getValue(x,y,z); ssZPos << "Pos: " << x << " " << y << " " << z; G4AttHolder* attHolder = dynamic_cast(node); if(attHolder && attHolder->GetAttDefs().size()) { std::vector*> vecDefs = attHolder->GetAttDefs(); std::vector*> vecVals = attHolder->GetAttValues(); for (size_t i = 0; i < vecDefs.size(); ++i) { const std::vector * vals = vecVals[i]; std::vector::const_iterator iValue; for (iValue = vals->begin(); iValue != vals->end(); ++iValue) { const G4String& valueName = iValue->GetName(); const G4String& value = iValue->GetValue(); if(valueName == "Solid") { if(ssSolids.str() == "") ssSolids << "Solid Name: " << value; else ssSolids << ", " << value; } if(valueName == "Material") { if(ssMaterials.str() == "") ssMaterials << "Material Name: " << value; else ssMaterials << ", " << value; } } } } } // FWJ Mouseover for trajectories else if(node->getTypeId() == SoLineSet::getClassTypeId()) { // G4cout << "Trajectory!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << G4endl; G4AttHolder* attHolder = dynamic_cast(node); if(attHolder && attHolder->GetAttDefs().size()) { std::string strTrajPoint = "G4TrajectoryPoint:"; std::ostringstream oss; G4String t1, t1Ch, t2, t3, t4; for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) { // G4cout << "Getting index " << i << " from attHolder" << G4endl; // No, returns a vector! // G4AttValue* attValue = attHolder->GetAttValues()[i]; const std::vector* vals = attHolder->GetAttValues()[i]; std::vector::const_iterator iValue; for (iValue = vals->begin(); iValue != vals->end(); ++iValue) { const G4String& valueName = iValue->GetName(); const G4String& value = iValue->GetValue(); // G4cout << " valueName = " << valueName << G4endl; // G4cout << " value = " << value << G4endl; // LINE 1 if (valueName == "PN") t1 = value; if (valueName == "Ch") { if (atof(value.c_str()) > 0) t1Ch = " +"; else t1Ch = " "; t1Ch += value; } if (valueName == "PDG") { t1 += " "; t1 += value; t1 += t1Ch; This->mouseOverTextLogName->string.setValue(t1); } // G4cout << " t1 = " << t1 << G4endl; // LINE 2 if (valueName == "EventID") t2 = "Evt " + value; if (valueName == "ID") t2 += " Trk " + value; if (valueName == "PID") { t2 += " Prt " + value; This->mouseOverTextSolid->string.setValue(t2); } // LINE 3 if (valueName == "IKE") t3 = "KE " + value; if (valueName == "IMom") { // Remove units unsigned ipos = value.rfind(" "); G4String value1 = value; value1.erase(ipos); t3 += " P (" + value1 + ")"; } if (valueName == "IMag") { t3 += " " + value + "/c"; // t3 += " " + value; This->mouseOverTextMaterial->string.setValue(t3); } // LINE 4 if (valueName == "NTP") { std::ostringstream t4oss; t4oss << "TrjPts " << value; t4oss << " Pos " << pp->getPoint()[0] << " " << pp->getPoint()[1] << " " << pp->getPoint()[2]; This->mouseOverTextZPos->string.setValue(SbString(t4oss.str().c_str())); } } // G4cout << " NOW CALLING G4AttCheck" << G4endl; // G4cout << G4AttCheck(attHolder->GetAttValues()[i], // attHolder->GetAttDefs()[i]); // oss << G4AttCheck(attHolder->GetAttValues()[i], // attHolder->GetAttDefs()[i]); // if(oss.str().find(strTrajPoint) != std::string::npos) { // // Last attribute displayed was a trajectory point. Since we // // want abbreviated output, display the last one and exit // // (unless we're already at the last (and only) trajectory point) // if(i != attHolder->GetAttDefs().size()-1) { // G4cout << G4AttCheck( // attHolder->GetAttValues()[attHolder->GetAttDefs().size()-1], // attHolder->GetAttDefs()[attHolder->GetAttDefs().size()-1]); // } // break; // } } } This->setSuperimpositionEnabled(This->superimposition, TRUE); This->scheduleRedraw(); eventCB->setHandled(); return; } bool redraw = false; if(std::string(This->mouseOverTextLogName->string.getValues(0)->getString()) != sLogName) { This->mouseOverTextLogName->string.setValue(SbString(sLogName.c_str())); redraw = true; } if(std::string(This->mouseOverTextSolid->string.getValues(0)->getString()) != ssSolids.str()) { This->mouseOverTextSolid->string.setValue(SbString(ssSolids.str().c_str())); redraw = true; } if(std::string(This->mouseOverTextMaterial->string.getValues(0)->getString()) != ssMaterials.str()) { This->mouseOverTextMaterial->string.setValue(SbString(ssMaterials.str().c_str())); redraw = true; } if(std::string(This->mouseOverTextZPos->string.getValues(0)->getString()) != ssZPos.str()) { This->mouseOverTextZPos->string.setValue(SbString(ssZPos.str().c_str())); redraw = true; } if(redraw) { This->setSuperimpositionEnabled(This->superimposition, TRUE); This->scheduleRedraw(); } eventCB->setHandled(); } else { if(std::string(This->mouseOverTextLogName->string.getValues(0)->getString()) != "") { This->mouseOverTextLogName->string.setValue(SbString("")); This->scheduleRedraw(); } if(std::string(This->mouseOverTextSolid->string.getValues(0)->getString()) != "") { This->mouseOverTextSolid->string.setValue(SbString("")); This->scheduleRedraw(); } if(std::string(This->mouseOverTextMaterial->string.getValues(0)->getString()) != "") { This->mouseOverTextMaterial->string.setValue(SbString("")); This->scheduleRedraw(); } if(std::string(This->mouseOverTextZPos->string.getValues(0)->getString()) != "") { This->mouseOverTextZPos->string.setValue(SbString("")); This->scheduleRedraw(); } } } // Called by hitting PageUp during animation. void G4OpenInventorQtExaminerViewer::incSpeed() { if (std::ceil(animateBtwPtsPeriod * 100) >= 4) { if (speedStep > 0.08) speedStep -= 0.02; else speedStep = 0.02; animateBtwPtsPeriod -= speedStep; } else animateBtwPtsPeriod = 0.0; if (currentState != PAUSED_ANIMATION) { int lastIdx = refParticleTrajectory.size() - 1; if (refParticleIdx < lastIdx && !animateSensor->isScheduled()) animateRefParticle(); } } // Called by hitting PageDown during animation. void G4OpenInventorQtExaminerViewer::decSpeed() { animateBtwPtsPeriod += speedStep; if (animateBtwPtsPeriod < MIN_SPEED) { if (std::floor(animateBtwPtsPeriod * 100) == 12) { // Errors in double representation speedStep = 0.08; } else if (animateBtwPtsPeriod > 0.12) speedStep += 0.02; } else { animateBtwPtsPeriod = MIN_SPEED; speedStep = START_STEP; maxSpeed = 0.0f; if (animateSensor->isScheduled()) animateSensor->unschedule(); } } // Based on the user's interaction the speed indicator bar needs to be adjusted void G4OpenInventorQtExaminerViewer::updateSpeedIndicator(void) { assert(this->sgeometry != NULL); SbVec3f * points = this->sgeometry->point.startEditing(); if (points[10][0] == 0.0f) this->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_ALL); if (points[14][0] == 0.0f) this->animSpeedSwitch->whichChild.setValue(SO_SWITCH_ALL); points[10][0] = this->maxSpeed; points[11][0] = this->maxSpeed; points[14][0] = this->maxSpeed; points[15][0] = this->maxSpeed; this->sgeometry->point.finishEditing(); if (this->maxSpeed == 0.0f) { this->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); this->animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); } } void G4OpenInventorQtExaminerViewer::actualRedraw(void) { switch (currentState) { case ANIMATION: case REVERSED_ANIMATION: case PAUSED_ANIMATION: updateSpeedIndicator(); SoQtExaminerViewer::actualRedraw(); break; default: SoQtExaminerViewer::actualRedraw(); break; } } void G4OpenInventorQtExaminerViewer::setReferencePath(SoLineSet *lineset, SoCoordinate3 *coords, bool append) { // TODO: Color the reference path // Disable the color stuff for now: changes all trajectories // FWJ See G4OpenInventorXtExaminerViewer.cc for test code // The trajectory is composed of all the polyline segments in the // multiple value field (SoMFInt32) numVertices. // For each of the numVertices.getNum()* polyline segments, // retrieve the points from the SoCoordinate3 node SbVec3f refParticlePt; if(!append) refParticleTrajectory.clear(); for(int i = 0; i < lineset->numVertices.getNum(); ++i) { for(int j = 0; j < lineset->numVertices[i]; ++j) { refParticlePt = coords->point[j]; refParticleTrajectory.push_back(refParticlePt); } } // Remove points that are too close to each other evenOutRefParticlePts(); setReferencePathZPos(); getSceneElements(); sortElements(); } void G4OpenInventorQtExaminerViewer::setReferencePathZPos() { refZPositions.clear(); refZPositions.push_back(0); float dist; for(unsigned int i=0; i < refParticleTrajectory.size() - 1; ++i) { dist = (refParticleTrajectory[i] - refParticleTrajectory[i + 1]).length(); refZPositions.push_back(refZPositions[i] + dist); } } void G4OpenInventorQtExaminerViewer::findAndSetRefPath() { SoSearchAction action; action.setType(SoLineSet::getClassTypeId(),false); action.setInterest(SoSearchAction::ALL); action.apply(getSceneGraph()); SoPathList &pathList = action.getPaths(); if(pathList.getLength() != 0) { SoCoordinate3 * coords = NULL; std::vector coordvec; std::vector linevec; bool refPathFound = false; for(int i = 0; i < pathList.getLength(); ++i) { SoFullPath *path = (SoFullPath *)pathList[i]; G4AttHolder* attHolder = dynamic_cast(path->getTail()); for (size_t j = 0; j < attHolder->GetAttDefs().size(); ++j) { std::ostringstream oss; oss << G4AttCheck(attHolder->GetAttValues()[j], attHolder->GetAttDefs()[j]); std::string findStr = "Type of trajectory (Type): "; std::string compareValue = "REFERENCE"; size_t idx = oss.str().find(findStr); if(idx != std::string::npos) { if(oss.str().substr(idx + findStr.size(), compareValue.size()) == compareValue) { coords = getCoordsNode(path); if(coords != NULL) { refPathFound = true; coordvec.push_back(coords); linevec.push_back((SoLineSet *)path->getTail()); } break; } } findStr = "Track ID (ID): "; idx = oss.str().find(findStr); if(idx != std::string::npos) { //index all primary tracks std::string tmpstr = oss.str().substr(idx + findStr.size(),1); std::istringstream buffer(tmpstr); int num; buffer >> num; if(num == 1) { // Check if next character is a number, // in which case we don't have Track ID 1 // FWJ attempt to fix Coverity issue. char nextChar = oss.str().at(idx+findStr.size()+1); // const char * nextChar = // oss.str().substr(idx + findStr.size() + 1,1).c_str(); if(std::isdigit(nextChar)) break; //Not a primary track, continue with next track coords = getCoordsNode(path); if(coords != NULL) { coordvec.push_back(coords); linevec.push_back((SoLineSet *)path->getTail()); break; //Found coords node, continue with next track } } else break; //Not a primary track, continue with next track } else{ //Not a Track ID attribute, fall through } } if(refPathFound) break; } if(coordvec.empty()) return; //No track with a Coordinate3 node found if(refPathFound) { //set ref path to last traj, coord in the vecs setReferencePath(linevec.back(), coordvec.back()); return; } //else int longestIdx = 0; float longestLength = 0.0; // For all paths for(unsigned int i=0;i < linevec.size(); ++i) { //First generate a vector with all the points in this lineset std::vector trajectory; // For all lines in the i path for(int j=0; j < linevec[i]->numVertices.getNum(); ++j) { // For all points in line j for(int k=0; k < linevec[i]->numVertices[j]; ++k) { trajectory.push_back(coordvec[i]->point[k]); } } // Then calculate the total length float tmpLength=0.0; for(unsigned int j=0; j < trajectory.size() - 1; ++j) { tmpLength += (trajectory[j] - trajectory[j + 1]).length(); } if(tmpLength > longestLength) { longestIdx = i; longestLength = tmpLength; } } // Set the longest path as the reference path setReferencePath(linevec[longestIdx], coordvec[longestIdx]); } } SoCoordinate3 * G4OpenInventorQtExaminerViewer::getCoordsNode(SoFullPath *path) { SoLineSet *trajectory = (SoLineSet *)path->getTail(); SoSeparator * grpNode = (SoSeparator*)(((SoFullPath*)path)->getNodeFromTail(1)); int nodeIndex = grpNode->findChild(trajectory); SoNode * tmpNode; // We allow only 100 iterations, in case the node isn't found // (should take only a few iterations) for (int i = 0; i < 100; ++i) { --nodeIndex; tmpNode = grpNode->getChild(nodeIndex); if(tmpNode->getTypeId() == SoCoordinate3::getClassTypeId()) { //node found return (SoCoordinate3 *)tmpNode; } } return NULL; //coords node not found } // Displays scene elements on the right side of listsDialog. // else: scene graph is searched for Geant4_SoPolyhedron type nodes void G4OpenInventorQtExaminerViewer::getSceneElements() { std::string field, eltName; std::map duplicates; std::map sceneElts; SoSearchAction search; Geant4_SoPolyhedron *node; SoGroup *root = (SoGroup *)getSceneManager()->getSceneGraph(); SoBaseKit::setSearchingChildren(TRUE); search.reset(); search.setSearchingAll(TRUE); search.setInterest(SoSearchAction::ALL); search.setType(Geant4_SoPolyhedron::getClassTypeId(), 0); // FWJ DEBUG // G4cout << "Searching for elements....." << G4endl; search.apply(root); SoPathList &pl = search.getPaths(); // First find which names occur more than once so we can append a counter to them for (int i = 0; i < pl.getLength(); i++) { SoFullPath *path = (SoFullPath *)pl[i]; node = (Geant4_SoPolyhedron *)path->getTail(); eltName = node->getName(); // G4cout << " FOUND " << i << " " << eltName << G4endl; if(duplicates.count(eltName)) duplicates[eltName]++; else duplicates[eltName] = 1; } for(int i = 0; i < pl.getLength(); i++) { float x,y,z; std::stringstream ssCount; SoFullPath *path = (SoFullPath *)pl[i]; node = (Geant4_SoPolyhedron *)path->getTail(); eltName = node->getName(); field = eltName; if(duplicates[eltName] == 1) ssCount << "";//duplicates[field] else { if(sceneElts.count(eltName)) sceneElts[eltName]++; else sceneElts[eltName] = 1; ssCount << sceneElts[eltName]; field += "_"; } field += ssCount.str(); SoGetBoundingBoxAction bAction(getViewportRegion()); bAction.apply(path); SbBox3f bBox = bAction.getBoundingBox(); SbVec3f centr = bBox.getCenter(); centr.getValue(x,y,z); path->ref(); sceneElement el = { field, path, centr, 0.0 }; sceneElements.push_back(el); } } float G4OpenInventorQtExaminerViewer::sqrlen(const SbVec3f &a) { float x,y,z; a.getValue(x,y,z); return x*x + y*y + z*z; } void G4OpenInventorQtExaminerViewer::distanceToTrajectory(const SbVec3f &q, float &dist, SbVec3f &closestPoint, int &index) { // a : Previous point on trajectory // b : Next point on trajectory // q : the point in space // dab, daq, dbq: distance between a & b, a & q, b & q // // Theory: A point p on a line ab is defined as: // // p(t) = a+t?(b?a) // // note: All are vectors except the parameter t // // When t is between 0 and 1 the point p is situated between a and b on ab. // The point p is defined in terms of the parameter t, subsequently so does // the distance from the query point q to the point p. To find the minimum // of that distance we differentiate it and set equal to zero: // // diff(Norm(p(t)- q)) = 0 // // note: diff means taking the derivative with regard to t // // The resulting t is given in the code below. The square of the distance // between p and q is given by: // // d^2 = (Norm(p(t)-q))^2 // // The expression found is given in the code below (current_dist) // // Ref: http://programmizm.sourceforge.net/blog/2012/ // distance-from-a-point-to-a-polyline // // --PLG const size_t count = refParticleTrajectory.size(); assert(count>0); SbVec3f b = refParticleTrajectory[0]; SbVec3f dbq = b - q; float sqrDist = sqrlen(dbq); closestPoint = b; index = 0; for (size_t i = 1; i < count; ++i) { const SbVec3f a = b; const SbVec3f daq = dbq; b = refParticleTrajectory[i]; dbq = b - q; const SbVec3f dab = a - b; float dab_x, dab_y, dab_z; dab.getValue(dab_x,dab_y,dab_z); float daq_x, daq_y, daq_z; daq.getValue(daq_x, daq_y, daq_z); float dbq_x, dbq_y, dbq_z; dbq.getValue(dbq_x, dbq_y, dbq_z); const float inv_sqrlen = 1./sqrlen(dab); const float t = (dab_x*daq_x + dab_y*daq_y + dab_z*daq_z)*inv_sqrlen; if (t<0.) { // The trajectory point occurs before point a // Go to the next point continue; } float current_dist; if (t<=1.) { // The trajectory point occurs between a and b. // Compute the distance to that point current_dist = daq_x*daq_x + daq_y*daq_y + daq_z*daq_z - t*(daq_x*dab_x + daq_y*dab_y + daq_z*dab_z) + t*t*(dab_x*dab_x + dab_y*dab_y + dab_z*dab_z); } else { //t>1. // The trajectory point occurs after b. // Get the distance to point b current_dist = sqrlen(dbq); } if (current_dist < sqrDist) { sqrDist = current_dist; closestPoint = a + t*(b-a); index = i; } } dist = std::sqrt(sqrDist); } void G4OpenInventorQtExaminerViewer::sortElements() { if(refParticleTrajectory.empty()) return; float * trajLength = new float[refParticleTrajectory.size()]; typedef std::map sortedMap; sortedMap sorted; // For every point on the reference trajectory, compute // the total length from the start SbVec3f prevPoint; std::vector::iterator itRef = refParticleTrajectory.begin(); int trajIndex = 0; prevPoint = *itRef; trajLength[trajIndex] = 0.0; ++itRef; ++trajIndex; for(; itRef != refParticleTrajectory.end(); ++itRef, ++trajIndex) { trajLength[trajIndex] = trajLength[trajIndex-1] + (*itRef - prevPoint).length(); prevPoint = *itRef; } // Compute the smallest distance between the element // and the reference trajectory (find the closest point), // then map the element to the trajectory length of that // point (calculated above) SoGetBoundingBoxAction bAction(getViewportRegion()); SbVec3f elementCoord; std::vector::iterator itEl; int elementIndex; elementForSorting el; for(itEl = sceneElements.begin(), elementIndex = 0; itEl != sceneElements.end(); ++itEl, ++elementIndex) { bAction.apply(itEl->path); // FWJ sceneElement already has a center elementCoord = itEl->center; // ... and this sometimes returns an empty box! // elementCoord = bAction.getBoundingBox().getCenter(); // if (bAction.getBoundingBox().isEmpty()) { // G4cout << "sortElements: Box is empty!" << G4endl; // G4cout << " element name=" << itEl->name << G4endl; // } int index; distanceToTrajectory(elementCoord, el.smallestDistance, el.closestPoint, index); itEl->closestPointZCoord = el.closestPointZCoord = trajLength[index]; el.distanceToBeamlineStart = (itEl->center - refParticleTrajectory[0]).length(); // This map of the scene elements (or their coordinates rather) // is automatically sorted by trajectory length (Z coord), then // by the distance between the element and the point in case the Z coord // is the same as another element. This is done by using as a key // an element structure which implements the operator for weak ordering sorted.insert(std::make_pair(el,*itEl)); } // store the sorted elements into the vector field sceneElements.clear(); sortedMap::iterator itSorted = sorted.begin(); for(; itSorted != sorted.end(); itSorted++) sceneElements.push_back(itSorted->second); zcoordSetFlag = true; createElementsList(); delete[] trajLength; } void G4OpenInventorQtExaminerViewer::createElementsList() { // FWJ DEBUG // G4cout << "Populating ELEMENT LIST..." << G4endl; AuxWindowDialog->listWidget1->clear(); // int size = sceneElements.size(); std::vector::const_iterator it; std::stringstream ss; for(it=sceneElements.begin(); it!=sceneElements.end(); ++it) { ss << it->name; if(zcoordSetFlag) ss << " [" << it->closestPointZCoord << "]"; new QListWidgetItem(ss.str().c_str(), AuxWindowDialog->listWidget1); ss.str(""); } } // Called when user clicks a scene element in listsDialog. // Zooms onto that element. void G4OpenInventorQtExaminerViewer::LookAtSceneElementCB(QListWidgetItem* item) { char* value; std::string elementField; // FWJ DEBUG // G4cout << "AuxWindow: listWidget1 select element CALLBACK" << G4endl; SoCamera * cam = getCamera(); if (SoQtExaminerViewer::isAnimating()) stopAnimating(); value = strdup(qPrintable(item->text())); // G4cout << "LOOKING FOR BOOKMARK " << value << G4endl; if (currentState == ANIMATION || currentState == REVERSED_ANIMATION || currentState == PAUSED_ANIMATION ) { if (animateSensor->isScheduled()) animateSensor->unschedule(); setSuperimpositionEnabled(superimposition, FALSE); maxSpeed = 0.0f; scheduleRedraw(); restoreCamera(); currentState = prevState; } else if (currentState == VIEWPOINT) setSuperimpositionEnabled(superimposition, FALSE); elementField = value; int idx = elementField.find_last_of("["); if(idx == -1) idx = elementField.size(); //if "[" not found for whatever reason (list not sorted) else idx--; // To get rid of the space that is between the name and '[' bool error = false; SoFullPath *path; SoSearchAction search; SoNode *root = getSceneManager()->getSceneGraph(); int counter, idxUnderscore = elementField.find_last_of("_"); parseString(counter, elementField.substr(idxUnderscore + 1, idx), error); SoBaseKit::setSearchingChildren(TRUE); search.reset(); search.setSearchingAll(TRUE); // G4cout << " Starting search for elementField " << elementField // << G4endl; if(error) { // No counter is present => element name was not modified curEltName = elementField.substr(0, idx); search.setName(curEltName.c_str()); search.apply(root); path = (SoFullPath *)search.getPath(); } else { curEltName = elementField.substr(0, idxUnderscore); search.setInterest(SoSearchAction::ALL); search.setName(curEltName.c_str()); search.apply(root); SoPathList &pl = search.getPaths(); path = (SoFullPath *)pl[counter - 1]; // Since counter starts at 1, not 0 } G4ThreeVector global; // FWJ FLIP THIS if ((idx > 0) && (path)) { if(!refParticleTrajectory.empty()) { SoGetBoundingBoxAction bAction(getViewportRegion()); bAction.apply(path); SbBox3f bBox = bAction.getBoundingBox(); SbVec3f elementCoord = bBox.getCenter(); refParticleIdx = 0; SbVec3f p; float absLengthNow, absLengthMin; int maxIdx = refParticleTrajectory.size() - 2; int targetIdx = 0; SbVec3f dir; p = refParticleTrajectory[refParticleIdx]; absLengthMin = (p - elementCoord).length(); refParticleIdx++; // Find a ref. particle's point closest to element's global coords while (refParticleIdx < maxIdx) { p = refParticleTrajectory[refParticleIdx]; absLengthNow = (p - elementCoord).length(); if (absLengthNow < absLengthMin) { absLengthMin = absLengthNow; targetIdx = refParticleIdx; } refParticleIdx++; } if (currentState != BEAMLINE) { // Set up default zoom SbVec3f p1, pN; currentState = BEAMLINE; prevParticleDir = SbVec3f(0,0,0); //so that moveCamera() knows sets default parameters p1 = prevPt = refParticleTrajectory[0]; pN = refParticleTrajectory[refParticleTrajectory.size() - 1]; distance = (pN - p1).length() / 10; // FWJ Rather than switching to a default height, it is more flexible // to keep the same height(magnification) while moving the camera. // if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { // ((SoOrthographicCamera *) cam)->height.setValue(defaultHeight); // // FWJ Restore the default height instead of hard-wired value // // ((SoOrthographicCamera *) cam)->height.setValue(10000.0f); // } // else if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) // FWJ required to avoid extreme perspective after camera move: if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) ((SoPerspectiveCamera*)cam)->heightAngle.setValue(defaultHeightAngle); } else { if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) distance = (prevPt - cam->position.getValue()).length(); } refParticleIdx = targetIdx; ////////////////////////////////////////////////////////////// setSuperimpositionEnabled(superimposition, TRUE); axisSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); scheduleRedraw(); ////////////////////////////////////////////////////////////// moveCamera(distance); } else { offsetFromCenter.setValue(0, 0, 1); distance = 50;// small number since using viewAll() for default zoom upVector.setValue(0, 1, 0); moveCamera(distance); cam->viewAll(path, getViewportRegion()); } } } void G4OpenInventorQtExaminerViewer::FileLoadRefPathCB() { // G4cout << "File: Load Ref Path CALLBACK" << G4endl; QFileDialog filedialog(getParentWidget(), tr("Load Reference Path")); filedialog.setFileMode(QFileDialog::AnyFile); filedialog.setFont(*font); if (!filedialog.exec()) return; QStringList filenameinlist = filedialog.selectedFiles(); QString filenamein = filenameinlist[0]; // G4cout << "Input file name is " << qPrintable(filenamein) << G4endl; char* filename = new char[filenamein.size()+1]; filename = strdup(qPrintable(filenamein)); // G4cout << "char[] file name is " << filename << G4endl; std::ifstream ifs(filename); if(ifs.is_open()) { refParticleTrajectory.clear(); float x,y,z; while(ifs >> x >> y >> z) { refParticleTrajectory.push_back(SbVec3f(x,y,z)); } ifs.close(); } else { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Reference Path file not found: "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); return; } if (refParticleTrajectory.size() < 2) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Invalid Reference Path"; msgbox.setText(messagetxt); msgbox.exec(); return; } // Following setReferencePath() ... evenOutRefParticlePts(); setReferencePathZPos(); getSceneElements(); sortElements(); } void G4OpenInventorQtExaminerViewer::FileSaveRefPathCB() { // G4cout << "File: Save Ref Path CALLBACK" << G4endl; QFileDialog filedialog(getParentWidget(), tr("Save Reference Path")); filedialog.setFileMode(QFileDialog::AnyFile); // To enable confirmation of overwriting filedialog.setAcceptMode(QFileDialog::AcceptSave); filedialog.setFont(*font); if (!filedialog.exec()) return; QStringList filenameinlist = filedialog.selectedFiles(); QString filenamein = filenameinlist[0]; // G4cout << "Input file name is " << qPrintable(filenamein) << G4endl; char* filename = new char[filenamein.size()+1]; filename = strdup(qPrintable(filenamein)); // G4cout << "char[] file name is " << filename << G4endl; std::ofstream ofs(filename); if (ofs.is_open()) { float x,y,z; for (unsigned int i=0; i < refParticleTrajectory.size(); ++i) { refParticleTrajectory[i].getValue(x,y,z); ofs << x << " " << y << " " << z << "\n"; } ofs.close(); } else { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error opening file "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); } } void G4OpenInventorQtExaminerViewer::evenOutRefParticlePts() { if(refParticleTrajectory.empty()) return; SbVec3f p1, p2, p3, dirNow, dirNxt, dir, p2_tmp, p_start, p_corner, p_nxt; float avgDistBtwPts = 0; float totalDistBtwPts = 0; std::vector newRefParticleTrajectory; SbVec3f refPoint; int size = refParticleTrajectory.size() - 1; int numOfPts = 0; for (int i = 0; i < size; i++) { p1 = refParticleTrajectory[i]; p2 = refParticleTrajectory[i + 1]; if (p1 == p2) continue; numOfPts++; totalDistBtwPts += (p2 - p1).length(); } // Nothing useful to do (and fix Coverity) if (numOfPts <= 2) return; avgDistBtwPts = totalDistBtwPts / numOfPts; float minDistAllowed = 0.75 * avgDistBtwPts; // float maxDistAllowed = 1.25 * avgDistBtwPts; // Pts tend to be close not far float x, y, z; int i = 0, j = 0; while (i < size) { p1 = refParticleTrajectory[i]; p2 = refParticleTrajectory[i + 1]; refPoint = p1; p1.getValue(x, y, z); newRefParticleTrajectory.push_back(refPoint); j = i; while ((p2 - p1).length() < minDistAllowed && j < (size - 1)) { j++; p1 = refParticleTrajectory[j]; p2 = refParticleTrajectory[j + 1]; } if (j != i) i = j + 1; else i++; } refParticleTrajectory.clear(); refParticleTrajectory = newRefParticleTrajectory; } void G4OpenInventorQtExaminerViewer::saveCurCamera() { SoCamera *cam = getCamera(); camB4Animation.viewportMapping = cam->viewportMapping.getValue(); camB4Animation.position = cam->position.getValue(); camB4Animation.orientation = cam->orientation.getValue(); camB4Animation.aspectRatio = cam->aspectRatio.getValue(); camB4Animation.nearDistance = cam->nearDistance.getValue(); camB4Animation.farDistance = cam->farDistance.getValue(); camB4Animation.focalDistance = cam->focalDistance.getValue(); if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { camB4Animation.height = ((SoPerspectiveCamera *) cam)->heightAngle.getValue(); camB4Animation.camType = PERSPECTIVE; } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { camB4Animation.height = ((SoOrthographicCamera *) cam)->height.getValue(); camB4Animation.camType = ORTHOGRAPHIC; } } void G4OpenInventorQtExaminerViewer::restoreCamera() { SoCamera *cam = getCamera(); cam->viewportMapping = camB4Animation.viewportMapping; cam->position = camB4Animation.position; cam->orientation = camB4Animation.orientation; cam->aspectRatio = camB4Animation.aspectRatio; cam->nearDistance = camB4Animation.nearDistance; cam->farDistance = camB4Animation.farDistance; cam->focalDistance = camB4Animation.focalDistance; if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { if (camB4Animation.camType == ORTHOGRAPHIC) { toggleCameraType(); cam = getCamera(); ((SoOrthographicCamera *) cam)->height.setValue( camB4Animation.height); } else ((SoPerspectiveCamera *) cam)->heightAngle.setValue( camB4Animation.height); } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { if (camB4Animation.camType == PERSPECTIVE) { toggleCameraType(); cam = getCamera(); ((SoPerspectiveCamera *) cam)->heightAngle.setValue( camB4Animation.height); } else ((SoOrthographicCamera *) cam)->height.setValue( camB4Animation.height); } } void G4OpenInventorQtExaminerViewer::animateSensorRotationCB(void *data, SoSensor *sensor) { SbTime curTime = SbTime::getTimeOfDay(); G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*) data; SoTimerSensor* s = (SoTimerSensor*) sensor; float t = float((curTime - s->getBaseTime()).getValue()) / This->animateBtwPtsPeriod; if ((t > 1.0f) || (t + s->getInterval().getValue() > 1.0f)) t = 1.0f; SbBool end = (t == 1.0f); if (end) { This->animateSensorRotation->unschedule(); if(This->rotCnt) { // rotations left This->rotateCamera(); } else { // rotation over This->currentState = This->prevState; return; } } } // Called repeatedly during reference particle animation void G4OpenInventorQtExaminerViewer::animateSensorCB(void *data, SoSensor *sensor) { SbTime curTime = SbTime::getTimeOfDay(); G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*) data; SoCamera *cam = This->getCamera(); SoTimerSensor* s = (SoTimerSensor*) sensor; float t = float((curTime - s->getBaseTime()).getValue()) / This->animateBtwPtsPeriod; if ((t > 1.0f) || (t + s->getInterval().getValue() > 1.0f)) t = 1.0f; SbBool end = (t == 1.0f); cam->orientation = SbRotation::slerp(This->camStartOrient, This->camEndOrient, t); cam->position = This->camStartPos + (This->camEndPos - This->camStartPos) * t; if (end) { This->animateSensor->unschedule(); if (This->currentState == ANIMATION) { if (This->refParticleIdx < (int) (This->refParticleTrajectory.size() - 1)) This->animateRefParticle(); else { This->animateBtwPtsPeriod = MIN_SPEED; This->speedStep = START_STEP; } } if (This->currentState == REVERSED_ANIMATION) { if (This->refParticleIdx >= 1) This->animateRefParticle(); else { This->animateBtwPtsPeriod = MIN_SPEED; This->speedStep = START_STEP; } } } } void G4OpenInventorQtExaminerViewer::setStartingPtForAnimation() { if (SoQtExaminerViewer::isAnimating()) stopAnimating(); SbRotation rot; SbVec3f p1, p2, p2_tmp, camUpV, camD, camD_tmp, leftRightAxis; float x1, y1, z1, x2, y2, z2; if (currentState == ANIMATION) { p1 = refParticleTrajectory[refParticleIdx]; p2 = refParticleTrajectory[++(refParticleIdx)]; } else if (currentState == REVERSED_ANIMATION) { p2 = refParticleTrajectory[refParticleIdx]; p1 = refParticleTrajectory[--(refParticleIdx)]; } else if (currentState == PAUSED_ANIMATION) { if (refParticleIdx < (int) refParticleTrajectory.size()) { p1 = refParticleTrajectory[refParticleIdx]; p2 = refParticleTrajectory[refParticleIdx + 1]; } else { p1 = refParticleTrajectory[refParticleIdx - 1]; p2 = refParticleTrajectory[refParticleIdx]; } } p1.getValue(x1, y1, z1); p2.getValue(x2, y2, z2); camD = p2 - p1; camD.normalize(); p2_tmp.setValue(x2, y1, z2); camD_tmp = p2_tmp - p1; camD_tmp.normalize(); camUpV.setValue(0, 1, 0); rot.setValue(camD_tmp, camD); rot.multVec(camUpV, camUpV); leftRightAxis = camD.cross(camUpV); myCam->position = p1; myCam->pointAt(p2, camUpV); // Update camera position p1 = p1 + (up_down * camUpV) + (left_right * leftRightAxis); myCam->position = p1; // FWJ Try look-ahead here int idx = refParticleIdx + pathLookahead; idx = std::min(idx, (int)refParticleTrajectory.size() - 1); myCam->pointAt(refParticleTrajectory[idx], camUpV); // myCam->pointAt(refParticleTrajectory[idx], camUpVec); myCam->focalDistance = 0.1f; } void G4OpenInventorQtExaminerViewer::gotoRefPathStart() { G4OpenInventorQtExaminerViewer::ToolsRefPathStartCB(); } void G4OpenInventorQtExaminerViewer::ToolsRefPathStartCB() { if (!refParticleTrajectory.size()) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "No current reference path"; msgbox.setText(messagetxt); msgbox.exec(); return; } if (currentState == ROTATING) return; if (currentState == ANIMATION || currentState == REVERSED_ANIMATION || currentState == PAUSED_ANIMATION) { if (animateSensor->isScheduled()) animateSensor->unschedule(); setSuperimpositionEnabled(superimposition, FALSE); maxSpeed = 0.0f; scheduleRedraw(); } else { saveCurCamera(); prevState = currentState; prevRefIdx = refParticleIdx; } if (SoQtExaminerViewer::isAnimating()) stopAnimating(); up_down = 0; left_right = 0; step = 1; refParticleIdx = 0; currentState = BEAMLINE; setSuperimpositionEnabled(superimposition, TRUE); axisSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); scheduleRedraw(); // FWJ Disabled: this is set in moveCamera() // Zoom in // SoCamera *cam = getCamera(); // cam->focalDistance = 0.1f; prevParticleDir = SbVec3f(0,0,0); //Default zoom SbVec3f p1 = refParticleTrajectory[0]; SbVec3f pN = refParticleTrajectory[refParticleTrajectory.size() - 1]; distance = (pN - p1).length() / 10; moveCamera(distance, true); } void G4OpenInventorQtExaminerViewer::ToolsRefPathInvertCB() { invertRefPath(); } void G4OpenInventorQtExaminerViewer::invertRefPath() { std::reverse(refParticleTrajectory.begin(), refParticleTrajectory.end()); setReferencePathZPos(); sortElements(); } void G4OpenInventorQtExaminerViewer::animateRefParticle() { SoCamera *cam = getCamera(); camStartPos = cam->position.getValue(); camStartOrient = cam->orientation.getValue(); if (currentState != BEAMLINE) setStartingPtForAnimation(); camEndPos = myCam->position.getValue(); camEndOrient = myCam->orientation.getValue(); if (animateSensor->isScheduled()) animateSensor->unschedule(); animateSensor->setBaseTime(SbTime::getTimeOfDay()); animateSensor->setInterval(SbTime(0.02)); animateSensor->schedule(); } void G4OpenInventorQtExaminerViewer::addEscapeCallback(void (*callback)()) { escapeCallback = callback; } void G4OpenInventorQtExaminerViewer::sceneChangeCB(void* userData, SoSensor*) { // FWJ DEBUG // G4cout << "SCENE CHANGE callback" << G4endl; // NOTE: could/should be disabled during animation G4OpenInventorQtExaminerViewer* This = (G4OpenInventorQtExaminerViewer*)userData; if(This->newEvents) { This->findAndSetRefPath(); This->newEvents = false; } } //////////////////////////////////// BOOKMARKS /////////////////////////// // Adds bookmarks to listsDialog. void G4OpenInventorQtExaminerViewer::addViewPoints() { int size = viewPtList.size(); if (!size) return; for (int i = 0; i < size; i++) { new QListWidgetItem(viewPtList[i].viewPtName, AuxWindowDialog->listWidget); } } // Converts a string type word into a float type. template void G4OpenInventorQtExaminerViewer::parseString(T &t, const std::string &s, bool &error) { std::istringstream str(s); if ((str >> t).fail()) error = true; } void G4OpenInventorQtExaminerViewer::FileOpenBookmarkCB() { // FWJ DEBUG // G4cout << "File: Open Bookmark File CALLBACK" << G4endl; QFileDialog filedialog(getParentWidget(), tr("Open bookmark file")); filedialog.setFileMode(QFileDialog::ExistingFile); filedialog.setFont(*font); if (!filedialog.exec()) return; QStringList filenameinlist = filedialog.selectedFiles(); QString filenamein = filenameinlist[0]; char* filename = new char[filenamein.size()+1]; filename = strdup(qPrintable(filenamein)); // G4cout << "char[] file name is " << filename << G4endl; fileIn.close(); fileIn.open(filename); if (fileIn.fail()) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error opening file: "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); // G4cout << "ERROR opening file " << filename << G4endl; fileIn.clear(); return; } // Opens a file without erasing it cleanUpAfterPrevFile(); if (!loadViewPts()) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error reading bookmark file: "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); // G4cout << "ERROR reading bookmark file " << filename << G4endl; fileIn.clear(); return; } fileName = filename; fileOut.open(fileName.c_str(), std::ios::in); fileOut.seekp(0, std::ios::end); addViewPoints(); // LATER: display filename in lists window fileIn.close(); fileIn.clear(); } // Called before loading a new viewpoint file. // Resets member fields to default values. void G4OpenInventorQtExaminerViewer::cleanUpAfterPrevFile() { viewPtIdx = -1; viewPtList.clear(); // setSuperimpositionEnabled(superimposition, FALSE); // scheduleRedraw(); currentState = GENERAL; if (fileOut.is_open()) fileOut.close(); AuxWindowDialog->listWidget->clear(); AuxWindowDialog->lineEdit->setText(QString("")); } void G4OpenInventorQtExaminerViewer::FileNewBookmarkCB() { // G4cout << "File: Open New Bookmark File CALLBACK" << G4endl; QFileDialog filedialog(getParentWidget(), tr("Open new bookmark file")); filedialog.setFileMode(QFileDialog::AnyFile); // To enable confirmation of overwriting filedialog.setAcceptMode(QFileDialog::AcceptSave); // But change the "Save" button text filedialog.setLabelText(QFileDialog::Accept, QString("New")); filedialog.setFont(*font); if (!filedialog.exec()) return; QStringList filenameinlist = filedialog.selectedFiles(); QString filenamein = filenameinlist[0]; // G4cout << "Input file name is " << qPrintable(filenamein) << G4endl; char* filename = new char[filenamein.size()+1]; filename = strdup(qPrintable(filenamein)); // G4cout << "char[] file name is " << filename << G4endl; cleanUpAfterPrevFile(); fileName = filename; fileOut.open(fileName.c_str()); if (fileOut.fail()) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error opening new bookmark file: "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); // G4cout << "ERROR opening new bookmark file " << filename << G4endl; } } void G4OpenInventorQtExaminerViewer::ToolsAnimateRefParticleCB() { // G4cout << "Tools: Animate Ref Particle CALLBACK" << G4endl; if (!refParticleTrajectory.size()) { returnToAnim = true; G4cout << "No Reference Trajectory" << G4endl; return; } /////////////////////////////////////////////////////////////// setSuperimpositionEnabled(superimposition, TRUE); maxSpeed = SPEED_INDICATOR_STEP; axisSwitch->whichChild.setValue(SO_SWITCH_ALL); animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_ALL); animSpeedSwitch->whichChild.setValue(SO_SWITCH_ALL); scheduleRedraw(); /////////////////////////////////////////////////////////////// SoCamera *cam = getCamera(); // SbVec3f camDirOld, camDirNew, camDirNew_tmp, camUpVec, P0, P1, P1_tmp; if (currentState == ANIMATION || currentState == REVERSED_ANIMATION || currentState == ROTATING) return; if (currentState != PAUSED_ANIMATION) { saveCurCamera(); prevState = currentState; prevRefIdx = refParticleIdx; if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { toggleCameraType(); cam = getCamera(); } refParticleIdx = 0; // Set the camera to the starting point of the animation animateBtwPtsPeriod = MIN_SPEED; speedStep = START_STEP; left_right = up_down = 0; cam->focalDistance = 0.1f; ((SoPerspectiveCamera *) cam)->heightAngle = 0.50f; } currentState = ANIMATION; setStartingPtForAnimation(); cam->position = (myCam)->position.getValue(); cam->orientation = (myCam)->orientation.getValue(); animateRefParticle(); // Animate the camera } void G4OpenInventorQtExaminerViewer::SaveViewPtCB() { // G4cout << "AppButton: Save Viewpoint CALLBACK" << G4endl; // First get viewpoint name ... // EMULATING getViewPtNameCB ... // bool ok; // Note QString() returns an empty string // NONE OF THE FOLLOWING CHANGES THE FONT: FORGET IT FOR NOW QInputDialog* inputdialog = new QInputDialog(getParentWidget()); inputdialog->setFont(*font); inputdialog->setWindowTitle(tr("Enter a name for the bookmark")); inputdialog->setLabelText("Bookmark name"); // inputdialog->setTextEchoMode(QLineEdit::Normal); inputdialog->adjustSize(); QString namein; if (inputdialog->exec() == QDialog::Accepted) namein=inputdialog->textValue().trimmed(); else return; if (namein.isEmpty()) return; // This easier approach failed: unable to set font size // QString namein = // QInputDialog::getText(getParentWidget(), // tr("Enter a name for the bookmark"), // tr("Bookmark name"), QLineEdit::Normal, // QString(), &ok); const int nVPName = MAX_VP_NAME + 1; char* name = new char[nVPName]; // strncpy(name, strName.c_str(), nVPName); namein.truncate(MAX_VP_NAME); QByteArray ba = namein.toLocal8Bit(); name = strdup(ba.constData()); // name = strdup(qPrintable(namein)) // FWJ DEBUG // G4cout << "QString is " << qPrintable(namein) << G4endl; // G4cout << "char[] is " << name << G4endl; for (int i = 0; i < (int)viewPtList.size(); i++) { if (!strcmp(name, viewPtList[i].viewPtName)) { QMessageBox msgbox; msgbox.setText("Bookmark name is already in use"); msgbox.exec(); return; } } if (viewPtIdx == -1) viewPtIdx = 0; saveViewPt(name); saveViewPtItem = new QListWidgetItem(namein, AuxWindowDialog->listWidget); AuxWindowDialog->listWidget->setCurrentItem(saveViewPtItem); AuxWindowDialog->lineEdit->setText(namein); } // Saves current camera parameters to a viewpoint file. void G4OpenInventorQtExaminerViewer::saveViewPt(char *name) { SbVec3f axis; viewPtData tmp; float x, y, z, angle; SoCamera* camera = getCamera(); // NOTE: Xt VSN increments this at end of procedure // viewPtIdx++; // FWJ DEBUG // G4cout << "saveViewPt: saving bookmark " << viewPtIdx << " " << name // << G4endl; if (viewPtList.size() == 0) { writeViewPtIdx(); } tmp.viewPtName = name; tmp.viewportMapping = camera->viewportMapping.getValue(); tmp.position = camera->position.getValue(); tmp.orientation = camera->orientation.getValue(); tmp.aspectRatio = camera->aspectRatio.getValue(); tmp.nearDistance = camera->nearDistance.getValue(); tmp.farDistance = camera->farDistance.getValue(); tmp.focalDistance = camera->focalDistance.getValue(); // Save camera height (changed by zooming) if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) { tmp.height = ((SoPerspectiveCamera *) camera)->heightAngle.getValue(); tmp.camType = PERSPECTIVE; } else if (camera->isOfType(SoOrthographicCamera::getClassTypeId())) { tmp.height = ((SoOrthographicCamera *) camera)->height.getValue(); tmp.camType = ORTHOGRAPHIC; } else { SoDebugError::post("G4OpenInventorQtExaminerViewer::saveViewPtCB", "Only Perspective and Orthographic cameras are supported."); return; } viewPtList.push_back(tmp); // Now save the view point to a .txt file // FWJ DEBUG // G4cout << "saveViewPt: writing to Bookmark file " << fileName << G4endl; std::string vpName = name; while ((int) vpName.size() <= MAX_VP_NAME) vpName += " "; fileOut << vpName << std::endl; tmp.position.getValue(x, y, z); fileOut << x << " " << y << " " << z << std::endl; // Reusing x, y and z for storing the axis tmp.orientation.getValue(axis, angle); axis.getValue(x, y, z); fileOut << x << " " << y << " " << z << " " << angle << std::endl; fileOut << tmp.camType << " " << tmp.height << std::endl; fileOut << tmp.focalDistance << " "; fileOut << tmp.nearDistance << " "; fileOut << tmp.farDistance << std::endl; fileOut << tmp.viewportMapping << " "; fileOut << tmp.aspectRatio << "\n" << std::endl; fileOut.flush(); viewPtIdx++; // FWJ DEBUG // G4cout << "saveViewPt: finished writing to file" << G4endl << // " Next viewPtIdx is " << viewPtIdx << G4endl; } // Updates the viewPtIdx in a viewpoint file. void G4OpenInventorQtExaminerViewer::writeViewPtIdx() { std::string idxStr; std::stringstream out; out << viewPtIdx; idxStr = out.str(); fileOut.seekp(0, std::ios::beg); while ((int) idxStr.length() < MAX_VP_IDX) { idxStr += " "; } // FWJ DEBUG // G4cout << "writeViewPtIdx: " << viewPtIdx << G4endl; fileOut << idxStr << "\n"; fileOut.flush(); fileOut.seekp(0, std::ios::end); } // Receives the name of the bookmark clicked and searches for it in viewPtList. void G4OpenInventorQtExaminerViewer::LoadBookmarkCB(QListWidgetItem* item) { // FWJ DEBUG // G4cout << "AuxWindow: listWidget LoadBookmark CALLBACK" << G4endl; const int nVPName = MAX_VP_NAME + 1; char* vpName = new char[nVPName]; vpName = strdup(qPrintable(item->text())); // G4cout << "LOOKING FOR BOOKMARK " << vpName << G4endl; for (int i = 0; i < (int)viewPtList.size(); i++) { if (!strcmp(viewPtList[i].viewPtName, vpName)) { viewPtIdx = i; break; } } // G4cout << " FOUND viewPtIdx " << viewPtIdx << G4endl; writeViewPtIdx(); setViewPt(); AuxWindowDialog->lineEdit->setText(item->text()); } // Sets the viewpoint based on camera data that viewPtIdx is pointing to. void G4OpenInventorQtExaminerViewer::setViewPt() { if (currentState == ANIMATION || currentState == REVERSED_ANIMATION || currentState == ROTATING) { if (animateSensor->isScheduled()) animateSensor->unschedule(); setSuperimpositionEnabled(superimposition, FALSE); maxSpeed = 0.0f; scheduleRedraw(); } SoCamera * camera = getCamera(); if (camera == NULL) { G4cout << "setViewPt: Camera is null. Unable to set the viewpoint." << G4endl; // String dialogName = (char *) "Missing Camera Node"; // std::string msg = "Camera is null. Unable to set the viewpoint."; // warningMsgDialog(msg, dialogName, NULL); return; } if (!viewPtList.size()) { G4cout << "setViewPt: There are no viewpoints to load." << G4endl; // String dialogName = (char *) "Missing Viewpoints"; // std::string msg = "There are no viewpoints to load."; // warningMsgDialog(msg, dialogName, NULL); return; } if (SoQtExaminerViewer::isAnimating()) stopAnimating(); if (currentState != VIEWPOINT) { currentState = VIEWPOINT; ////////////////////////////////////////////////////////////// setSuperimpositionEnabled(superimposition, TRUE); axisSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); scheduleRedraw(); /////////////////////////////////////////////////////////////// } curViewPtName = viewPtList[viewPtIdx].viewPtName; camera->viewportMapping = viewPtList[viewPtIdx].viewportMapping; camera->position = viewPtList[viewPtIdx].position; camera->orientation = viewPtList[viewPtIdx].orientation; camera->aspectRatio = viewPtList[viewPtIdx].aspectRatio; camera->nearDistance = viewPtList[viewPtIdx].nearDistance; camera->farDistance = viewPtList[viewPtIdx].farDistance; camera->focalDistance = viewPtList[viewPtIdx].focalDistance; // Restore camera height (changed by zooming) if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) { if (viewPtList[viewPtIdx].camType == ORTHOGRAPHIC) { toggleCameraType(); camera = getCamera(); ((SoOrthographicCamera *) camera)->height.setValue( viewPtList[viewPtIdx].height); } else ((SoPerspectiveCamera *) camera)->heightAngle.setValue( viewPtList[viewPtIdx].height); } else if (camera->isOfType(SoOrthographicCamera::getClassTypeId())) { if (viewPtList[viewPtIdx].camType == PERSPECTIVE) { toggleCameraType(); camera = getCamera(); ((SoPerspectiveCamera *) camera)->heightAngle.setValue( viewPtList[viewPtIdx].height); } else ((SoOrthographicCamera *) camera)->height.setValue( viewPtList[viewPtIdx].height); } else { SoDebugError::post("G4OpenInventorQtExaminerViewer::setViewPt", "Only Perspective and Orthographic cameras are supported."); return; } } void G4OpenInventorQtExaminerViewer::NextViewPtCB() { // FWJ DEBUG // G4cout << "App Button: nextViewPt CALLBACK" << G4endl; if (!viewPtList.size()) return; if (viewPtIdx >= (int)viewPtList.size() - 1) viewPtIdx = 0; else viewPtIdx++; writeViewPtIdx(); setViewPt(); char* viewptname = viewPtList[viewPtIdx].viewPtName; AuxWindowDialog->lineEdit->setText(QString(viewptname)); } void G4OpenInventorQtExaminerViewer::PrevViewPtCB() { // FWJ DEBUG // G4cout << "App Button: prevViewPt CALLBACK" << G4endl; if (!viewPtList.size()) return; if (viewPtIdx == 0) viewPtIdx = viewPtList.size() - 1; else viewPtIdx--; writeViewPtIdx(); setViewPt(); char* viewptname = viewPtList[viewPtIdx].viewPtName; AuxWindowDialog->lineEdit->setText(QString(viewptname)); } void G4OpenInventorQtExaminerViewer::AbbrOutputCB(bool checked) { // FWJ DEBUG // G4cout << "App Button: abbrOutput CALLBACK" << G4endl; abbrOutputFlag = checked; } void G4OpenInventorQtExaminerViewer::PickRefPathCB() { // FWJ DEBUG // G4cout << "App Button: pickRefPath CALLBACK" << G4endl; // Save viewing state and go to picking mode viewingBeforePickRef = isViewing(); if(isViewing()) setViewing(false); setComponentCursor(SoQtCursor(SoQtCursor::CROSSHAIR)); pickRefPathFlag = true; } void G4OpenInventorQtExaminerViewer::SwitchWireFrameCB(bool checked) { // FWJ DEBUG // G4cout << "App Button: switchWireFrame CALLBACK" << G4endl; // if (switchWireFrameButton->isDown()) { if (checked) { setDrawStyle(SoQtViewer::STILL, SoQtViewer::VIEW_LINE); setDrawStyle(SoQtViewer::INTERACTIVE, SoQtViewer::VIEW_LINE); } else { setDrawStyle(SoQtViewer::STILL, SoQtViewer::VIEW_AS_IS); setDrawStyle(SoQtViewer::INTERACTIVE, SoQtViewer::VIEW_SAME_AS_STILL); } } void G4OpenInventorQtExaminerViewer::SwitchAxesCB(bool checked) { // FWJ DEBUG // G4cout << "App Button: switchAxes CALLBACK" << G4endl; setFeedbackVisibility(checked); // if (checked) { // setFeedbackVisibility(TRUE); // } else { // setFeedbackVisibility(FALSE); // } } void G4OpenInventorQtExaminerViewer::DetachCB() { // FWJ DEBUG // G4cout << "App Button: detach CALLBACK" << G4endl; uiQt->GetViewerTabWidget()->removeTab(uiQtTabIndex); viewerParent->setParent(viewerParent2); removeAppPushButton(detachButton); show(); } void G4OpenInventorQtExaminerViewer::DeleteBookmarkCB() { // FWJ DEBUG // G4cout << "Delete Button: DeleteBookmark CALLBACK" << G4endl; // Maybe nothing selected yet QListWidgetItem* listitem = AuxWindowDialog->listWidget->currentItem(); if (!listitem) return; if (!(listitem->isSelected())) return; QString vpnamein = listitem->text(); const int nVPName = MAX_VP_NAME + 1; char* vpName = new char[nVPName]; vpName = strdup(qPrintable(vpnamein)); // G4cout << "DELETING bookmark " << vpName << G4endl; deleteViewPt(vpName); delete listitem; } // Deletes current viewpoint the user is looking at. // Updates the input file and bookmarks as well. void G4OpenInventorQtExaminerViewer::deleteViewPt(char *vpName) { std::string line; int end; fileIn.open(fileName.c_str()); std::ofstream out("temporaryFile.txt"); if (!vpName) vpName = viewPtList[viewPtIdx].viewPtName; getline(fileIn, line); // Printing the viewpoint idx out << line << "\n"; while (getline(fileIn, line)) { end = line.find_last_not_of(' '); line = line.substr(0, end + 1); if (!strcmp(line.c_str(), vpName)) { // Equal while (line.size()) { getline(fileIn, line); } while (getline(fileIn, line)) out << line << "\n"; } else { while (line.size()) { out << line << "\n"; getline(fileIn, line); } out << "\n"; } } int idx = 0; // Remove viewpoint from the vector int size = viewPtList.size(); while (idx < size) { if (!strcmp(viewPtList[idx].viewPtName, vpName)) { viewPtList.erase(viewPtList.begin() + idx); break; } idx++; } out.close(); fileOut.close(); fileIn.clear(); fileIn.close(); // FWJ check return status: error popups needed here int istat = remove(fileName.c_str()); if (istat == -1) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error removing bookmarks file"; // messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); // G4cout << "Error removing bookmarks file" << G4endl; } istat = rename("temporaryFile.txt", fileName.c_str()); if (istat == -1) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error renaming bookmarks file"; // messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); // G4cout << "Error renaming bookmarks file" << G4endl; } fileOut.open(fileName.c_str(), std::ios::in); fileOut.seekp(0, std::ios::end); if (!viewPtList.size()) { // viewPtList is empty curViewPtName = (char *) ""; scheduleRedraw(); } else { if (viewPtIdx >= (int) viewPtList.size()) viewPtIdx--; writeViewPtIdx(); setViewPt(); } } void G4OpenInventorQtExaminerViewer::RenameBookmarkCB() { // FWJ DEBUG // G4cout << "Rename Button: RenameBookmark CALLBACK" << G4endl; // Maybe nothing selected yet QListWidgetItem* listitem = AuxWindowDialog->listWidget->currentItem(); if (!listitem) return; if (!(listitem->isSelected())) return; QString vpnamein = listitem->text(); const int nVPName = MAX_VP_NAME + 1; // char* vpName = new char[nVPName]; // vpName = strdup(qPrintable(vpnamein)); // G4cout << "RENAMING bookmark " << vpName << G4endl; QInputDialog* inputdialog = new QInputDialog(getParentWidget()); inputdialog->setFont(*font); inputdialog->setWindowTitle(tr("Enter")); inputdialog->setLabelText("New bookmark name"); inputdialog->adjustSize(); QString newnamein; if (inputdialog->exec() == QDialog::Accepted) newnamein=inputdialog->textValue().trimmed(); else return; if (newnamein.isEmpty()) return; char* newname = new char[nVPName]; newname = strdup(qPrintable(newnamein)); int size = viewPtList.size(); for (int i = 0; i < size; i++) { if (!strcmp(newname, viewPtList[i].viewPtName)) { QMessageBox msgbox; msgbox.setFont(*font); msgbox.setText("Bookmark name is already in use"); msgbox.exec(); } } // G4cout << "RENAMING to " << newname << G4endl; renameViewPt(newname); listitem->setText(QString(newname)); AuxWindowDialog->lineEdit->setText(newname); // if (currentState == VIEWPOINT) // scheduleRedraw(); delete[] newname; } // Renames currently selected viewpoint. void G4OpenInventorQtExaminerViewer::renameViewPt(char *vpName) { int idx = 0, end, pos; int size = viewPtList.size(); std::string line, newName; fileIn.open(fileName.c_str()); newName = vpName; while ((int) newName.size() < MAX_VP_NAME) newName += " "; getline(fileIn, line); pos = fileIn.tellg(); while (getline(fileIn, line)) { end = line.find_last_not_of(' '); line = line.substr(0, end + 1); if (!strcmp(line.c_str(), curViewPtName)) { fileOut.seekp(pos); fileOut << newName; fileOut.seekp(0, std::ios::end); // Set the file pointer to the end of the file break; } while (line.size()) getline(fileIn, line); pos = fileIn.tellg(); } fileIn.close(); fileIn.clear(); while (idx < size) { if (!strcmp(viewPtList[idx].viewPtName, curViewPtName)) { strcpy(viewPtList[idx].viewPtName, vpName); break; } idx++; } } void G4OpenInventorQtExaminerViewer::SortBookmarksCB() { // FWJ NOTE: Xt version of this does not work (does nothing) // G4cout << "Sort Button: SortBookmarks CALLBACK" << G4endl; // FWJ List for sorting // The dialog list and bookmark file will be rewritten. // Simpler to populate this list from the data structure. std::vector charList; if (viewPtList.size() < 2) return; // Get current entries from the list for (int i = 0; i < (int)viewPtList.size(); i++) { charList.push_back(viewPtList[i].viewPtName); // G4cout << " Pushed " << i << " " << charList[i] << G4endl; } std::sort(charList.begin(), charList.end()); // FWJ POPULATE the new dialog list // G4cout << " Populating Bookmark listWidget..." << G4endl; AuxWindowDialog->listWidget->clear(); for (int i = 0; i < (int)viewPtList.size(); i++) { // viewPtIdx has to be changed to account for a different order in viewPtList if (!strcmp(charList[i].c_str(), curViewPtName)) viewPtIdx = i; new QListWidgetItem(charList[i].c_str(), AuxWindowDialog->listWidget); } sortViewPts(charList); } // Rewrites entire viewpoint file with sorted viewpoints. void G4OpenInventorQtExaminerViewer::sortViewPts(std::vector sortedViewPts) { SbVec3f axis; float x, y, z, angle; int sortIdx = 0, unsortIdx = 0; if (fileOut.is_open()) fileOut.close(); fileOut.open(fileName.c_str()); // Erase current viewpoint file writeViewPtIdx(); int size = sortedViewPts.size(); while (sortIdx < size) { while (strcmp(sortedViewPts[sortIdx].c_str(), viewPtList[unsortIdx].viewPtName)) unsortIdx++; std::string vpName = viewPtList[unsortIdx].viewPtName; while ((int) vpName.size() < MAX_VP_NAME) vpName += " "; fileOut << vpName << std::endl; viewPtList[unsortIdx].position.getValue(x, y, z); fileOut << x << " " << y << " " << z << std::endl; // Reusing x, y and z for storing the axis viewPtList[unsortIdx].orientation.getValue(axis, angle); axis.getValue(x, y, z); fileOut << x << " " << y << " " << z << " " << angle << std::endl; fileOut << viewPtList[unsortIdx].camType << " " << viewPtList[unsortIdx].height << std::endl; fileOut << viewPtList[unsortIdx].focalDistance << " "; fileOut << viewPtList[unsortIdx].nearDistance << " "; fileOut << viewPtList[unsortIdx].farDistance << std::endl; fileOut << viewPtList[unsortIdx].viewportMapping << " "; fileOut << viewPtList[unsortIdx].aspectRatio << "\n" << std::endl; fileOut.flush(); unsortIdx = 0; sortIdx++; } } // Emulating private method SoGuiFullViewerP::zoom() void G4OpenInventorQtExaminerViewer::zoom(const float diffvalue) { float multiplicator = float(std::exp(diffvalue)); SoCamera *cam = getCamera(); if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { const float oldfocaldist = cam->focalDistance.getValue(); const float newfocaldist = oldfocaldist * multiplicator; SbVec3f direction; cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); const SbVec3f oldpos = cam->position.getValue(); const SbVec3f newpos = oldpos + (newfocaldist - oldfocaldist) * -direction; cam->position = newpos; cam->focalDistance = newfocaldist; } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { SoOrthographicCamera * oc = (SoOrthographicCamera *)cam; oc->height = oc->height.getValue() * multiplicator; } } // Handling mouse and keyboard events SbBool G4OpenInventorQtExaminerViewer::processSoEvent(const SoEvent* const ev) { // FWJ DEBUG // G4cout << "processSoEvent ############" << ++processSoEventCount << G4endl; SoCamera *cam = getCamera(); const SoType type(ev->getTypeId()); if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { SoMouseButtonEvent * me = (SoMouseButtonEvent *) ev; // if (currentState == ANIMATION || currentState == REVERSED_ANIMATION // || currentState == PAUSED_ANIMATION) { switch (me->getButton()) { case SoMouseButtonEvent::BUTTON4: // Scroll wheel up if (me->getState() == SoButtonEvent::DOWN) { // G4cout << "SCROLL WHEEL UP" << G4endl; zoom(-0.1f); return TRUE; } break; case SoMouseButtonEvent::BUTTON5: // Scroll wheel down if (me->getState() == SoButtonEvent::DOWN) { // G4cout << "SCROLL WHEEL DOWN" << G4endl; zoom(0.1f); return TRUE; } break; default: break; } // } if (currentState == GENERAL) { } } if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { SoKeyboardEvent* ke = (SoKeyboardEvent*)ev; if (SoKeyboardEvent::isKeyPressEvent(ev, ke->getKey())) { switch (ke->getKey()) { case SoKeyboardEvent::E: if (externalQtApp) { // G4cout << "E KEY PRESSED" << G4endl; return TRUE; } else { G4cout << "E KEY PRESSED, EXITING OIQT VIEWER SECONDARY LOOP" << G4endl; SoQt::exitMainLoop(); // escapeCallback(); return TRUE; } case SoKeyboardEvent::LEFT_SHIFT: this->lshiftdown = true; return TRUE; case SoKeyboardEvent::RIGHT_SHIFT: this->rshiftdown = true; return TRUE; case SoKeyboardEvent::LEFT_CONTROL: this->lctrldown = true; return TRUE; case SoKeyboardEvent::RIGHT_CONTROL: this->rctrldown = true; return TRUE; case SoKeyboardEvent::SPACE: if (currentState == ANIMATION || currentState == REVERSED_ANIMATION) { beforePausing = currentState; currentState = PAUSED_ANIMATION; if (animateSensor->isScheduled()) animateSensor->unschedule(); return TRUE; } else if (currentState == PAUSED_ANIMATION) { if (maxSpeed) { if ((beforePausing == ANIMATION && refParticleIdx < (int) refParticleTrajectory.size() - 1) || (beforePausing == REVERSED_ANIMATION && refParticleIdx > 0)) { currentState = beforePausing; animateRefParticle(); } } return TRUE; } break; case SoKeyboardEvent::ESCAPE: if (currentState == ANIMATION || currentState == REVERSED_ANIMATION || currentState == PAUSED_ANIMATION) { if (animateSensor->isScheduled()) animateSensor->unschedule(); currentState = prevState; refParticleIdx = prevRefIdx; setSuperimpositionEnabled(superimposition, FALSE); maxSpeed = 0.0f; step = 1; scheduleRedraw(); if (currentState == VIEWPOINT) { setSuperimpositionEnabled(superimposition, TRUE); axisSwitch->whichChild.setValue(SO_SWITCH_NONE); animSpeedOutlineSwitch->whichChild.setValue( SO_SWITCH_NONE); animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE); scheduleRedraw(); } restoreCamera(); return TRUE; } break; case SoKeyboardEvent::DELETE: if (viewPtList.size() && (currentState != ANIMATION && currentState != REVERSED_ANIMATION && currentState != PAUSED_ANIMATION)) { // FWJ IMPLEMENT LATER // String dialogName = (char *) "Delete Viewpoint"; // std::string msg = "Are you sure you want to delete current viewpoint?"; // warningMsgDialog(msg, dialogName, deleteViewPtCB); return TRUE; } break; case SoKeyboardEvent::LEFT_ARROW: switch (currentState) { case BEAMLINE: if ((this->lshiftdown) || (this->rshiftdown)) { refParticleIdx -= step; moveCamera(); } else if ((this->lctrldown) || (this->rctrldown)) { if (SoQtExaminerViewer::isAnimating()) stopAnimating(); prevState = currentState; currentState = ROTATING; animateBtwPtsPeriod = 0.08f; SbVec3f tmp = camDir; tmp.negate(); rotAxis = tmp; rotCnt = ROT_CNT; moveCamera(); // To make sure camera is perpendicular to the beamline rotateCamera(); } else { if (SoQtExaminerViewer::isAnimating()) stopAnimating(); prevState = currentState; currentState = ROTATING; animateBtwPtsPeriod = 0.08f; SbVec3f tmp = camUpVec; tmp.negate(); rotAxis = tmp; rotCnt = ROT_CNT; moveCamera(); // To make sure camera is perpendicular to the beamline rotateCamera(); } return TRUE; case ANIMATION: case REVERSED_ANIMATION: left_right -= 1.5f; return TRUE; case PAUSED_ANIMATION: left_right -= 1.5f; setStartingPtForAnimation(); cam->position = myCam->position; return TRUE; case GENERAL: case VIEWPOINT: if ((!this->lshiftdown) && (!this->rshiftdown)) { // Using this allows us to look around without // changing the camera parameters (camDir, camUpVec) this->bottomWheelMotion( this->getBottomWheelValue() + 0.1f); return TRUE; } break; case ROTATING: // For this state, let the keyboard event // be handled by superclass break; default: SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", "Unhandled viewer state"); break; } break; case SoKeyboardEvent::RIGHT_ARROW: switch(currentState) { case BEAMLINE: if ((this->lshiftdown) || (this->rshiftdown)) { refParticleIdx += step; moveCamera(); } else if ((this->lctrldown) || (this->rctrldown)) { if (SoQtExaminerViewer::isAnimating()) stopAnimating(); prevState = currentState; currentState = ROTATING; animateBtwPtsPeriod = 0.08f; rotAxis = camDir; rotCnt = ROT_CNT; moveCamera(); // To make sure camera is perpendicular to the beamline rotateCamera(); } else{ if (SoQtExaminerViewer::isAnimating()) stopAnimating(); prevState = currentState; currentState = ROTATING; animateBtwPtsPeriod = 0.08f; rotAxis = camUpVec; rotCnt = ROT_CNT; moveCamera(); // To make sure camera is perpendicular to the beamline rotateCamera(); } return TRUE; case ANIMATION: case REVERSED_ANIMATION: left_right += 1.5f; return TRUE; case PAUSED_ANIMATION: left_right += 1.5f; setStartingPtForAnimation(); cam->position = myCam->position; return TRUE; case GENERAL: case VIEWPOINT: if ((!this->lshiftdown) && (!this->rshiftdown)) { // Using this allows us to look around without // changing the camera parameters (camDir, camUpVec) this->bottomWheelMotion( this->getBottomWheelValue() - 0.1f); return TRUE; } break; case ROTATING: // For this state, let the keyboard event // be handled by superclass break; default: SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", "Unhandled viewer state"); break; } break; case SoKeyboardEvent::DOWN_ARROW: switch(currentState) { case BEAMLINE: if ((this->lshiftdown) || (this->rshiftdown)) { refParticleIdx -= step; moveCamera(); } else{ if (SoQtExaminerViewer::isAnimating()) stopAnimating(); prevState = currentState; currentState = ROTATING; animateBtwPtsPeriod = 0.08f; rotAxis = camDir.cross(camUpVec); rotCnt = ROT_CNT; moveCamera(); // To make sure camera is perpendicular to the beamline rotateCamera(); } return TRUE; case ANIMATION: case REVERSED_ANIMATION: up_down -= 1.5f; return TRUE; case PAUSED_ANIMATION: up_down -= 1.5f; setStartingPtForAnimation(); cam->position = myCam->position; return TRUE; case GENERAL: case VIEWPOINT: // Using this allows us to look around without // changing the camera parameters (camDir, camUpVec) if ((!this->lshiftdown) && (!this->rshiftdown)) { this->leftWheelMotion(this->getLeftWheelValue() - 0.1f); return TRUE; } break; case ROTATING: // For this state, let the keyboard event // be handled by superclass break; default: SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", "Unhandled viewer state"); break; } break; case SoKeyboardEvent::UP_ARROW: switch(currentState) { case BEAMLINE: if ((this->lshiftdown) || (this->rshiftdown)) { refParticleIdx -= step; moveCamera(); } else{ if (SoQtExaminerViewer::isAnimating()) stopAnimating(); prevState = currentState; currentState = ROTATING; animateBtwPtsPeriod = 0.08f; rotAxis = camUpVec.cross(camDir); rotCnt = ROT_CNT; moveCamera(); rotateCamera(); } return TRUE; case ANIMATION: case REVERSED_ANIMATION: up_down += 1.5f; return TRUE; case PAUSED_ANIMATION: up_down += 1.5f; setStartingPtForAnimation(); cam->position = myCam->position; return TRUE; case GENERAL: case VIEWPOINT: // Using this allows us to look around without // changing the camera parameters (camDir, camUpVec) if ((!this->lshiftdown) && (!this->rshiftdown)) { this->leftWheelMotion(this->getLeftWheelValue() + 0.1f); return TRUE; } break; case ROTATING: // For this state, let the keyboard event // be handled by superclass break; default: SoDebugError::post("G4OpenInventorQtExaminerViewer::processSoEvent", "Unhandled viewer state"); break; } break; case SoKeyboardEvent::PAGE_UP: switch(currentState) { case BEAMLINE: if (step < (int) refParticleTrajectory.size() / 5) // Magic number step++; return TRUE; case ANIMATION: incSpeed(); maxSpeed += SPEED_INDICATOR_STEP; if (maxSpeed > 0.8) maxSpeed = MAX_SPEED_INDICATOR; scheduleRedraw(); return TRUE; case REVERSED_ANIMATION: if(!animateSensor->isScheduled()) { currentState = ANIMATION; if (refParticleIdx < (int) refParticleTrajectory.size() - 1) { refParticleIdx++; maxSpeed = SPEED_INDICATOR_STEP; scheduleRedraw(); animateRefParticle(); } } else{ maxSpeed += SPEED_INDICATOR_STEP; decSpeed(); scheduleRedraw(); } return TRUE; case PAUSED_ANIMATION: maxSpeed += SPEED_INDICATOR_STEP; if (maxSpeed > 0.8) maxSpeed = MAX_SPEED_INDICATOR; if (beforePausing == ANIMATION) { incSpeed(); } else { decSpeed(); if (animateBtwPtsPeriod >= MIN_SPEED) beforePausing = ANIMATION; } scheduleRedraw(); return TRUE; default: //fall through break; } break; case SoKeyboardEvent::PAGE_DOWN: switch(currentState) { case BEAMLINE: if (step > 1) step--; return TRUE; case ANIMATION: if(!animateSensor->isScheduled()) { currentState = REVERSED_ANIMATION; if (refParticleIdx > 1) { refParticleIdx--; maxSpeed = -SPEED_INDICATOR_STEP; scheduleRedraw(); animateRefParticle(); } } else{ maxSpeed -= SPEED_INDICATOR_STEP; decSpeed(); scheduleRedraw(); } return TRUE; case REVERSED_ANIMATION: incSpeed(); maxSpeed -= SPEED_INDICATOR_STEP; if (maxSpeed < -0.8) maxSpeed = -MAX_SPEED_INDICATOR; scheduleRedraw(); return TRUE; case PAUSED_ANIMATION: maxSpeed -= SPEED_INDICATOR_STEP; if (maxSpeed < -0.8) maxSpeed = -MAX_SPEED_INDICATOR; if (beforePausing == REVERSED_ANIMATION) { incSpeed(); } else { decSpeed(); if (animateBtwPtsPeriod >= MIN_SPEED) beforePausing = REVERSED_ANIMATION; } scheduleRedraw(); return TRUE; default: //fall through break; } break; // FROM XT VIEWER // case SoKeyboardEvent::E: // this->escapeCallback(this->examinerObject); // break; default: break; // To get rid of compiler warnings } } if (SoKeyboardEvent::isKeyReleaseEvent(ev, ke->getKey())) { switch (ke->getKey()) { case SoKeyboardEvent::LEFT_SHIFT: this->lshiftdown = false; return TRUE; case SoKeyboardEvent::RIGHT_SHIFT: this->rshiftdown = false; return TRUE; case SoKeyboardEvent::LEFT_CONTROL: this->lctrldown = false; return TRUE; case SoKeyboardEvent::RIGHT_CONTROL: this->rctrldown = false; return TRUE; default: break; } } } // Pass the event on to the viewer // Need some checks here as in Xt viewer? if (currentState == ANIMATION || currentState == REVERSED_ANIMATION || currentState == ROTATING) return FALSE; else return SoQtExaminerViewer::processSoEvent(ev); } // REMAINDER OF MENU BAR FUNCTIONS... void G4OpenInventorQtExaminerViewer::FileLoadSceneGraphCB() { // G4cout << "File: Load scene graph CALLBACK" << G4endl; QFileDialog filedialog(getParentWidget(), tr("Load Scene Graph")); filedialog.setFileMode(QFileDialog::AnyFile); filedialog.setFont(*font); if (!filedialog.exec()) return; QStringList filenameinlist = filedialog.selectedFiles(); QString filenamein = filenameinlist[0]; // G4cout << "Entered file name is " << qPrintable(filenamein) << G4endl; char* filename = new char[filenamein.size()+1]; filename = strdup(qPrintable(filenamein)); // G4cout << "char[] file name is " << filename << G4endl; SoInput sceneInput; if (sceneInput.openFile(filename)) { // Read the whole file into the database newSceneGraph = SoDB::readAll(&sceneInput); if (newSceneGraph == NULL) { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error reading scene graph file "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); sceneInput.closeFile(); return; } } else { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error opening scene graph file "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); return; } SoSeparator* root = (SoSeparator*)getSceneGraph(); root->unref(); newSceneGraph->ref(); setSceneGraph(newSceneGraph); } void G4OpenInventorQtExaminerViewer::FileSaveSceneGraphCB() { // G4cout << "File: Save scene graph CALLBACK" << G4endl; QFileDialog filedialog(getParentWidget(), tr("Save scene graph")); filedialog.setFileMode(QFileDialog::AnyFile); // To enable confirmation of overwriting filedialog.setAcceptMode(QFileDialog::AcceptSave); filedialog.setFont(*font); if (!filedialog.exec()) return; QStringList filenameinlist = filedialog.selectedFiles(); QString filenamein = filenameinlist[0]; // G4cout << "Entered file name is " << qPrintable(filenamein) << G4endl; char* filename = new char[filenamein.size()+1]; filename = strdup(qPrintable(filenamein)); // G4cout << "char[] file name is " << filename << G4endl; SoWriteAction writeAction; SoSeparator* root = (SoSeparator*)getSceneGraph(); SoOutput* out = writeAction.getOutput(); if (out->openFile(filename)) { out->setBinary(FALSE); writeAction.apply(root); out->closeFile(); } else { QMessageBox msgbox; msgbox.setFont(*font); QString messagetxt = "Error opening file "; messagetxt.append(filenamein); msgbox.setText(messagetxt); msgbox.exec(); } } void G4OpenInventorQtExaminerViewer::HelpControlsCB() { // G4cout << "Help: Help Controls CALLBACK" << G4endl; helpmsgbox->show(); } HookEventProcState::HookEventProcState(G4OpenInventorQtExaminerViewer* vwr) { viewer = vwr; } HookEventProcState::~HookEventProcState() {;} G4bool HookEventProcState::Notify(G4ApplicationState requestedState) { if (requestedState == G4State_EventProc) viewer->newEvents = true; return true; }