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