Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/OpenInventor/src/G4OpenInventorXtExaminerViewer.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 // Open Inventor Xt Extended Viewer - 30 Oct 2012
 28 // Rastislav Ondrasek, Pierre-Luc Gagnon, Frederick Jones TRIUMF
 29 
 30 #include <stdio.h>
 31 #include <string.h>
 32 #include <string>
 33 #include <sstream>
 34 #include <cmath>
 35 #include <iostream>
 36 #include <iomanip>
 37 #include <cstdio>
 38 #include <algorithm> // For using sort on a vector
 39 #include <X11/keysym.h>
 40 
 41 #include <Xm/Xm.h>
 42 #include <Xm/Text.h>
 43 #include <Xm/List.h>
 44 #include <Xm/MessageB.h>
 45 #include <Xm/PushB.h>
 46 #include <Xm/ToggleB.h>
 47 #include <Xm/CascadeB.h>
 48 #include <Xm/ArrowBG.h>
 49 #include <Xm/Form.h>
 50 #include <Xm/RowColumn.h>
 51 #include <Xm/FileSB.h>
 52 #include <Xm/SelectioB.h>
 53 #include <Xm/Protocols.h>
 54 #include <Xm/SeparatoG.h>
 55 #include <Xm/DialogS.h>  
 56 #include <Xm/PanedW.h>
 57 #include <Xm/LabelG.h>
 58 #include <Xm/Scale.h>
 59 #include <Xm/DrawingA.h>
 60 
 61 #include <Inventor/Xt/SoXt.h>
 62 //#include <Inventor/Xt/SoXtInternal.h>
 63 #include <Inventor/Xt/SoXtCursor.h>
 64 #include <Inventor/events/SoKeyboardEvent.h>
 65 #include <Inventor/events/SoMouseButtonEvent.h>
 66 #include <Inventor/events/SoLocation2Event.h>
 67 #include <Inventor/nodes/SoSeparator.h>
 68 #include <Inventor/nodes/SoOrthographicCamera.h>
 69 #include <Inventor/nodes/SoPerspectiveCamera.h>
 70 // FWJ moved to header file
 71 //#include <Inventor/nodes/SoEventCallback.h>
 72 #include <Inventor/nodes/SoLineSet.h>
 73 #include <Inventor/nodes/SoMaterial.h>
 74 #include <Inventor/errors/SoDebugError.h>
 75 #include <Inventor/SoPickedPoint.h>
 76 #include <Inventor/actions/SoWriteAction.h>
 77 
 78 #include "G4OpenInventorXtExaminerViewer.hh"
 79 #include "wheelmouse.h"  // To use mouse scrolling in dialogs
 80 #include "SoXtInternal.h"
 81 #include <Inventor/sensors/SoTimerSensor.h>   // Animation
 82 #include <Inventor/sensors/SoNodeSensor.h>    // Detect start of run
 83 #include "saveViewPt.h"
 84 #include "pickext.h"
 85 #include "pickref.h"
 86 #include "wireframe.h"
 87 //#include "console.h"
 88 //#include "favorites.h"
 89 
 90 #include "Geant4_SoPolyhedron.h"
 91 //#include "G4RunManager.hh"
 92 //#include "G4Run.hh"
 93 #include "G4TrajectoryPoint.hh"
 94 #include "G4AttHolder.hh"
 95 #include "G4AttCheck.hh"
 96 
 97 #include <Inventor/nodes/SoCallback.h>
 98 #include <Inventor/nodes/SoSwitch.h>
 99 #include <Inventor/nodes/SoScale.h>
100 #include <Inventor/nodes/SoTranslation.h>
101 #include <Inventor/actions/SoSearchAction.h>
102 #include <Inventor/actions/SoGetBoundingBoxAction.h>
103 
104 #include <Inventor/nodes/SoCoordinate3.h>
105 // For rendering distance during animation:
106 #include <Inventor/nodes/SoText2.h>
107 #include <Inventor/nodes/SoFont.h>
108 #include <Inventor/nodes/SoPointSet.h>
109 #include <Inventor/nodes/SoDrawStyle.h>
110 #include <Inventor/nodes/SoBaseColor.h>
111 
112 // For searching for nodes within kits:
113 #include <Inventor/nodekits/SoBaseKit.h>
114 
115 // FWJ
116 #include <Inventor/SbVec3f.h>
117 
118 G4OpenInventorXtExaminerViewer* G4OpenInventorXtExaminerViewer::viewer = 0;
119 
120 static const char* thisClassName = "G4OpenInventorXtExaminerViewer";
121  
122 #define MIN_SPEED  2.1        // Lower number means faster
123 #define START_STEP 0.3
124 #define SPEED_INDICATOR_STEP 0.045
125 #define MAX_SPEED_INDICATOR  0.81
126 // Number of steps 90 degree rotation around an element is split into
127 #define ROT_CNT 6
128 
129 // Public constructor
130 G4OpenInventorXtExaminerViewer::G4OpenInventorXtExaminerViewer(Widget parent,
131                 const char *name, SbBool embed,
132     SoXtFullViewer::BuildFlag flag, SoXtViewer::Type type) :
133    SoXtExaminerViewer(parent, name, embed, flag, type, FALSE)
134 {
135 // Tell GLWidget not to build just yet
136    this->constructor(TRUE);
137 }
138 
139 // Protected constructor for classes deriving from this viewer.
140 G4OpenInventorXtExaminerViewer::G4OpenInventorXtExaminerViewer(Widget parent,
141                 const char *name, SbBool embed,
142                 SoXtFullViewer::BuildFlag flag, SoXtViewer::Type type,
143                 SbBool build) :
144    SoXtExaminerViewer(parent, name, embed, flag, type, FALSE)
145 {
146    this->constructor(build);
147 }
148 
149 // Called by all constructors to set up widgets and initialize member fields.
150 void G4OpenInventorXtExaminerViewer::constructor(const SbBool build)
151 {
152    setClassName(thisClassName);
153 
154    hookBeamOn = new HookEventProcState(this);
155    this->newEvents = false;
156 
157    fileName = ".bookmarkFile"; // Default viewpoint file name
158    viewPtIdx = -1; // index of the most recent viewpoint in viewPtList vector
159    animateSensor = new SoTimerSensor(
160                        G4OpenInventorXtExaminerViewer::animateSensorCB, this);
161    animateSensorRotation = new SoTimerSensor(
162                G4OpenInventorXtExaminerViewer::animateSensorRotationCB, this);
163    animateBtwPtsPeriod = MIN_SPEED;
164    currentState = GENERAL;
165    myCam = new SoPerspectiveCamera;
166    MAX_VP_IDX = 3;
167    MAX_VP_NAME = 35; // Max length of a viewpoint name, padded with spaces
168    rotCnt = ROT_CNT; // For 90 degree rotations
169    curViewPtName = new char[MAX_VP_NAME + 1];
170    left_right = up_down = 0; // For movements around the beam during animation
171    speedStep = START_STEP; // For smoother animation speed increase/decrease
172    rotUpVec = false; // Used during scene element rotations
173    step = 1;  //By default
174    // Used for moving along the beam with the
175    // mouse instead of rotating the view
176    lshiftdown = rshiftdown = false;
177    // Used for rotating the view with the camera
178    // staying in place
179    lctrldown = rctrldown = false;
180    // Used to send abbreviated output to the console when
181    abbrOutputFlag = false;
182    pickRefPathFlag = false;
183    prevColorField = NULL;
184    warningFlag = false; // We come from the warning dialog
185    viewer = this;
186    openFileDialog = newFileDialog = listsDialog = (Widget) NULL;
187    loadRefCoordsDialog = saveRefCoordsDialog = NULL;
188    loadSceneGraphDialog = saveSceneGraphDialog = NULL;
189    myElementList = NULL;
190    // FWJ default path look-ahead
191    pathLookahead = 5;
192 
193    newSceneGraph = NULL;
194    zcoordSetFlag = false;
195 
196    //////////////////////////SUPERIMPOSED SCENE//////////////////////////
197    searcher = NULL;
198    // Used in animation; progressively scaled for gradual speed change
199    maxSpeed = 0.0f;
200 
201    static const char * superimposed[] = {
202       "#Inventor V2.1 ascii", "",
203       "Separator ",
204       "{",
205       " MaterialBinding ",
206       " {",
207       "     value OVERALL",
208       " }",
209       "   OrthographicCamera ",
210       " {",
211       "     height 1",
212       "   nearDistance 0",
213       "     farDistance 1",
214       " }",
215       "   DEF soxt->callback Callback { }",
216       "   Separator ",
217       " {",
218       "     DEF soxt->translation Translation ",
219       "   {",
220       "         translation 0 0 0",
221       "     }",
222       "     DEF soxt->scale Scale ",
223       "   {",
224       "         scaleFactor 1 1 1",
225       "     }",
226       "   DEF soxt->geometry Coordinate3 ",
227       "   {",
228       "       point ",
229       "     [",
230       "         -0.81 -0.04 0,  -0.81 0   0,",
231       "           -0.81 0.04  0,  0     -0.04   0,",
232       "           0       0     0,  0       0.04  0,",
233       "           0.81  -0.04   0,  0.81    0       0,",
234       "           0.81    0.04  0,",
235       "           0       0.02  0,", // idx 9
236       "           0.81    0.02  0,  0.81  -0.02   0,",
237       "           0     -0.02   0,",
238       "           0       0.01  0,", // idx 13
239       "           0.4     0.01  0,  0.4   -0.01   0,",
240       "           0     -0.01   0",
241       "     ]",
242       "   }",
243       // current speed indicator (outline)
244       "     DEF soxt->animSpeedOutlineSwitch Switch ",
245       "   {",
246       "         whichChild -3",
247       "         Material ",
248       "     {",
249       "            emissiveColor 0 0 0",
250       "       }",
251       "         IndexedFaceSet ",
252       "     {",
253       "           coordIndex ",
254       "       [",
255       "               12, 11, 10, 9, -1",
256       "             ]",
257       "         }",
258       "      }",
259       // the coordinate system
260       "     DEF soxt->axisSwitch Switch ",
261       "   {",
262       "         whichChild -3",
263       "         BaseColor ",
264       "     {",
265       "             rgb 1 1 1",
266       "         }",
267       "         IndexedLineSet ",
268       "     {",
269       "           coordIndex ",
270       "       [",
271       "               0, 2, -1,",
272       "               3, 5, -1,",
273       "               6, 8, -1,",
274       "               1, 7, -1",
275       "             ]",
276       "         }",
277       "     }",
278       // current speed indicator
279       "     DEF soxt->animSpeedSwitch Switch ",
280       "   {",
281       "         whichChild -3",
282       "         Material ",
283       "     {",
284       "           emissiveColor 0 1 0",
285       "         }",
286       "     IndexedFaceSet ",
287       "     {",
288       "         coordIndex ",
289       "       [",
290       "               16, 15, 14, 13, -1",
291       "           ]",
292       "         }",
293       "     }",
294       "   }",
295       // For displaying either z position (during animation) or current viewpoint name
296       " DEF soxt->curInfoSwitch Switch ",
297       " {",
298       "   whichChild -3",
299       "     DEF soxt->curInfoTrans Translation ",
300       "   {",
301       "         translation 10 20 30    ",
302       "   }",
303       "     DEF soxt->curInfoFont Font ",
304       "   {",
305       "         name defaultFont:Bold",
306       "         size 16",
307       "     }",
308       "   DEF soxt->curInfoText Text2 ",
309       "   {",
310       "         string Hello",
311       "     }",
312       " }",
313       // Need to use different fields for mouseover
314       // because newlines are ignored when the scene is rendered
315       " Separator ",
316       " {",
317       "     DEF soxt->mouseOverTransLogName Translation ",
318       "   {",
319       "         translation 0 0 0    ",
320       "   }",
321       "     DEF soxt->mouseOverFontLogName Font ",
322       "   {",
323       "         name defaultFont:Bold",
324       "         size 16",
325       "     }",
326       "   DEF soxt->mouseOverTextLogName Text2 { } ",
327       " }",
328       " Separator ",
329       " {",
330       "     DEF soxt->mouseOverTransSolid Translation ",
331       "   {",
332       "         translation 0 0 0    ",
333       "   }",
334       "     DEF soxt->mouseOverFontSolid Font ",
335       "   {",
336       "         name defaultFont:Bold",
337       "         size 16",
338       "     }",
339       "   DEF soxt->mouseOverTextSolid Text2 { } ",
340       " }",
341       " Separator ",
342       " {",
343       "     DEF soxt->mouseOverTransMaterial Translation ",
344       "   {",
345       "         translation 0 0 0    ",
346       "   }",
347       "     DEF soxt->mouseOverFontMaterial Font ",
348       "   {",
349       "         name defaultFont:Bold",
350       "         size 16",
351       "     }",
352       "   DEF soxt->mouseOverTextMaterial Text2 { } ",
353       " }",
354       " Separator ",
355       " {",
356       "     DEF soxt->mouseOverTransZPos Translation ",
357       "   {",
358       "         translation 0 0 0    ",
359       "   }",
360       "     DEF soxt->mouseOverFontZPos Font ",
361       "   {",
362       "         name defaultFont:Bold",
363       "         size 16",
364       "     }",
365       "   DEF soxt->mouseOverTextZPos Text2 { } ",
366       " }",
367       "}", NULL
368    };
369 
370    int i, bufsize;
371    for (i = bufsize = 0; superimposed[i]; i++)
372       bufsize += strlen(superimposed[i]) + 1;
373    char * buf = new char[bufsize + 1];
374    for (i = bufsize = 0; superimposed[i]; i++) {
375       strcpy(buf + bufsize, superimposed[i]);
376       bufsize += strlen(superimposed[i]);
377       buf[bufsize] = '\n';
378       bufsize++;
379    }
380    SoInput * input = new SoInput;
381    input->setBuffer(buf, bufsize);
382    SbBool ok = SoDB::read(input, this->superimposition);
383    (void)ok;   // FWJ added to avoid compiler warning
384    assert(ok);
385    delete input;
386    delete[] buf;
387    this->superimposition->ref();
388 
389    this->sscale = (SoScale *) this->getSuperimpositionNode(
390                                  this->superimposition, "soxt->scale");
391    this->stranslation = (SoTranslation *) this->getSuperimpositionNode(
392                                  this->superimposition, "soxt->translation");
393    this->sgeometry = (SoCoordinate3 *) this->getSuperimpositionNode(
394                                  this->superimposition, "soxt->geometry");
395    this->axisSwitch = (SoSwitch *) this->getSuperimpositionNode(
396                                  this->superimposition, "soxt->axisSwitch");
397    this->animSpeedOutlineSwitch = (SoSwitch *) this->getSuperimpositionNode(
398                        this->superimposition, "soxt->animSpeedOutlineSwitch");
399    this->animSpeedSwitch = (SoSwitch *) this->getSuperimpositionNode(
400                        this->superimposition, "soxt->animSpeedSwitch");
401    this->curInfoSwitch = (SoSwitch *) this->getSuperimpositionNode(
402                              this->superimposition, "soxt->curInfoSwitch");
403    this->curInfoTrans = (SoTranslation *) this->getSuperimpositionNode(
404                              this->superimposition, "soxt->curInfoTrans");
405    this->curInfoFont = (SoFont *) this->getSuperimpositionNode(
406                              this->superimposition, "soxt->curInfoFont");
407    this->curInfoText = (SoText2 *) this->getSuperimpositionNode(
408                              this->superimposition, "soxt->curInfoText");
409    this->mouseOverTransLogName = (SoTranslation*)this->getSuperimpositionNode(
410                    this->superimposition, "soxt->mouseOverTransLogName");
411    this->mouseOverFontLogName = (SoFont *) this->getSuperimpositionNode(
412                    this->superimposition, "soxt->mouseOverFontLogName");
413    this->mouseOverTextLogName = (SoText2 *) this->getSuperimpositionNode(
414                    this->superimposition, "soxt->mouseOverTextLogName");
415    this->mouseOverTransSolid = (SoTranslation *) this->getSuperimpositionNode(
416                    this->superimposition, "soxt->mouseOverTransSolid");
417    this->mouseOverFontSolid = (SoFont *) this->getSuperimpositionNode(
418                    this->superimposition, "soxt->mouseOverFontSolid");
419    this->mouseOverTextSolid = (SoText2 *) this->getSuperimpositionNode(
420                    this->superimposition, "soxt->mouseOverTextSolid");
421    this->mouseOverTransMaterial = (SoTranslation*)this->getSuperimpositionNode(
422                    this->superimposition, "soxt->mouseOverTransMaterial");
423    this->mouseOverFontMaterial = (SoFont *) this->getSuperimpositionNode(
424                    this->superimposition, "soxt->mouseOverFontMaterial");
425    this->mouseOverTextMaterial = (SoText2 *) this->getSuperimpositionNode(
426                    this->superimposition, "soxt->mouseOverTextMaterial");
427    this->mouseOverTransZPos = (SoTranslation *) this->getSuperimpositionNode(
428                    this->superimposition, "soxt->mouseOverTransZPos");
429    this->mouseOverFontZPos = (SoFont *) this->getSuperimpositionNode(
430                    this->superimposition, "soxt->mouseOverFontZPos");
431    this->mouseOverTextZPos = (SoText2 *) this->getSuperimpositionNode(
432                    this->superimposition, "soxt->mouseOverTextZPos");
433 
434    SoCallback * cb = (SoCallback *) this->getSuperimpositionNode(
435                    this->superimposition, "soxt->callback");
436    cb->setCallback(superimpositionCB, this);
437 
438    this->addSuperimposition(this->superimposition);
439    this->setSuperimpositionEnabled(this->superimposition, FALSE);
440    axisSwitch->whichChild.setValue(SO_SWITCH_NONE);
441    animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE);
442    animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE);
443 
444    /////////////////////\SUPERIMPOSED SCENE///////////////////////////////////
445 
446    // Build everything else like the parent viewer does
447    if (build) {
448       Widget w = buildWidget(getParentWidget());
449       setBaseWidget(w);
450 
451       // Make this window a little bigger because of the extra buttons
452       // FWJ but it is already set to 600x600 by vis/open
453       //      setSize(SbVec2s(500, 550));
454    }
455 
456 }
457 
458 
459 // Static function that returns the pointer to G4OpenInventorXtExaminerViewer
460 // FWJ DISABLED
461 //G4OpenInventorXtExaminerViewer *G4OpenInventorXtExaminerViewer::getObject()
462 //{
463 //   if (!viewer)
464 //      new G4OpenInventorXtExaminerViewer();
465 //   return viewer;
466 //}
467 
468 
469 // This method locates a named node in the superimposed or original scene.
470 SoNode *
471 G4OpenInventorXtExaminerViewer::getSuperimpositionNode(SoNode *root,
472                                                      const char * name)
473 {
474    if (!this->searcher)
475       this->searcher = new SoSearchAction;
476    searcher->reset();
477    searcher->setName(SbName(name));
478    searcher->setInterest(SoSearchAction::FIRST);
479    searcher->setSearchingAll(TRUE);
480    searcher->apply(root);
481    assert(searcher->getPath());
482    return searcher->getPath()->getTail();
483 }
484 
485 
486 void G4OpenInventorXtExaminerViewer::superimpositionCB(void * closure,
487                                                      SoAction * action)
488 {
489    if (closure)
490       ((G4OpenInventorXtExaminerViewer*)closure)->superimpositionEvent(action);
491 }
492 
493 
494 // Renders and positions speed indicator and longitudinal
495 // distance/viewpoint name on the drawing canvas
496 void G4OpenInventorXtExaminerViewer::superimpositionEvent(SoAction * action)
497 {
498 
499    if (!action->isOfType(SoGLRenderAction::getClassTypeId()))
500       return;
501    SbViewportRegion vpRegion =
502       ((SoGLRenderAction *) action)->getViewportRegion();
503    SbVec2s viewportSize = vpRegion.getViewportSizePixels();
504 
505    float aspect = float(viewportSize[0]) / float(viewportSize[1]);
506    float factorx = 1.0f / float(viewportSize[1]) * 220.0f;
507    float factory = factorx;
508 
509    if (aspect > 1.0f) {
510       this->stranslation->translation.setValue(SbVec3f(0.0f, -0.4f, 0.0f));
511    } else {
512       this->stranslation->translation.setValue(
513                        SbVec3f(0.0f, -0.4f / aspect, 0.0f));
514       factorx /= aspect;
515       factory /= aspect;
516    }
517    if (viewportSize[0] > 500)
518       factorx *= 500.0f / 400.0f;
519    else
520       factorx *= float(viewportSize[0]) / 400.0f;
521    this->sscale->scaleFactor.setValue(SbVec3f(factorx, factory, 1.0f));
522 
523    float xInfo, yInfo, xMouseLogName, yMouseLogName, xMouseSolid, yMouseSolid,
524       xMouseMaterial, yMouseMaterial, xMouseZPos, yMouseZPos;
525    xInfo = -.45;
526    yInfo = .45;
527    xMouseLogName = 0.0;
528    yMouseLogName = -.75;
529    xMouseSolid = 0.0;
530    yMouseSolid = -.78;
531    xMouseMaterial = 0.0;
532    yMouseMaterial = -.81;
533    xMouseZPos = 0.0;
534    yMouseZPos = -.84;
535 
536    if (aspect > 1.0f) {
537       xInfo *= aspect;
538       xMouseSolid *= aspect;
539       xMouseMaterial *= aspect;
540       this->curInfoTrans->translation.setValue(SbVec3f(xInfo, yInfo, 0.0));
541       this->mouseOverTransLogName->translation.setValue(
542                         SbVec3f(xMouseLogName, yMouseLogName, 0.0));
543       this->mouseOverTransSolid->translation.setValue(
544                         SbVec3f(xMouseSolid, yMouseSolid, 0.0));
545       this->mouseOverTransMaterial->translation.setValue(
546                         SbVec3f(xMouseMaterial, yMouseMaterial, 0.0));
547       this->mouseOverTransZPos->translation.setValue(
548                         SbVec3f(xMouseZPos, yMouseZPos, 0.0));
549    } else {
550       yInfo /= aspect;
551       yMouseSolid /= aspect;
552       yMouseMaterial /= aspect;
553       this->curInfoTrans->translation.setValue(SbVec3f(xInfo, yInfo, 0.0));
554       this->mouseOverTransLogName->translation.setValue(
555                         SbVec3f(xMouseLogName, yMouseLogName, 0.0));
556       this->mouseOverTransSolid->translation.setValue(
557                         SbVec3f(xMouseSolid, yMouseSolid, 0.0));
558       this->mouseOverTransMaterial->translation.setValue(
559                         SbVec3f(xMouseMaterial, yMouseMaterial, 0.0));
560       this->mouseOverTransZPos->translation.setValue(
561                         SbVec3f(xMouseZPos, yMouseZPos, 0.0));
562    }
563 
564    if (currentState == VIEWPOINT) { // Displaying viewpoint name
565       this->curInfoFont->size.setValue(15);
566       this->curInfoFont->name.setValue("defaultFont:Italic");
567       this->curInfoText->string.setValue(SbString(curViewPtName));
568    }
569    else if(currentState == GENERAL) { // Displaying longitudinal distance
570       this->curInfoFont->size.setValue(16);
571       this->curInfoFont->name.setValue("defaultFont:Bold");
572       this->curInfoText->string.setValue(SbString(""));
573    }
574    else {
575       if (refParticleIdx < (int) refParticleTrajectory.size() - 1) {
576          this->curInfoFont->size.setValue(16);
577          this->curInfoFont->name.setValue("defaultFont:Bold");
578          char zPos[20];
579          snprintf(zPos, sizeof zPos, "%7.2f [m]", refZPositions[refParticleIdx] / 1000);
580          this->curInfoText->string.setValue(SbString(zPos));
581       }
582    }
583 }
584 
585 
586 G4OpenInventorXtExaminerViewer::~G4OpenInventorXtExaminerViewer()
587 {
588    if (superimposition != NULL) {
589       removeSuperimposition(superimposition);
590       superimposition->unref();
591       superimposition = NULL;
592    }
593    if (animateSensor->isScheduled())
594       animateSensor->unschedule();
595    delete animateSensor;
596    delete sceneChangeSensor;
597 
598    delete[] curViewPtName;
599    delete searcher;
600 
601    viewer = 0;
602 }
603 
604 
605 // Adds a menu bar and a few menu items to the viewer.
606 Widget G4OpenInventorXtExaminerViewer::buildWidget(Widget parent)
607 {
608    Widget shell;
609    Atom WM_DELETE_WINDOW;
610 
611    if (!parent)
612       SoDebugError::post("G4OpenInventorXtExaminerViewer::buildWidget", "Error: Parent is null.");
613 
614    Arg args[10];
615    XtSetArg(args[0], XmNtopAttachment, XmATTACH_FORM);
616    XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM);
617    XtSetArg(args[2], XmNrightAttachment, XmATTACH_FORM);
618    XtSetArg(args[3], XmNbottomAttachment, XmATTACH_FORM);
619    Widget form = XmCreateForm(parent, (char *) "Form", args, 4);
620    XtManageChild(form);
621 
622    shell = XtParent(form);
623    WM_DELETE_WINDOW = XInternAtom(XtDisplay(parent), "WM_DELETE_WINDOW",
624                                   False);
625    XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW,
626                            (XtCallbackProc)closeMainWindowCB, this);
627 
628    XtSetArg(args[0], XmNtopAttachment, XmATTACH_FORM);
629    XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM);
630    XtSetArg(args[2], XmNrightAttachment, XmATTACH_FORM);
631    menuBar = XmCreateMenuBar(form, (char *) "MenuBar", args, 3);
632    XtManageChild(menuBar);
633 
634    fileMenu = addMenu("File");
635    this->addButton(fileMenu, "Open Viewpoint File...", openViewPtFileCB);
636    addButton(fileMenu, "New Viewpoint File", newViewPtFileCB);
637    addButton(fileMenu, "Load Ref. Coords", loadRefCoordsDialogCB);
638    addButton(fileMenu, "Save Ref. Coords", saveRefCoordsDialogCB);
639    addButton(fileMenu, "Load Scene Graph", loadSceneGraphDialogCB);
640    addButton(fileMenu, "Save Scene Graph", saveSceneGraphDialogCB);
641    XtManageChild(
642           XmCreateSeparatorGadget(fileMenu, (char *) "Separator", NULL, 0));
643 
644    Widget menu = addMenu("Tools");
645    addButton(menu, "Animate Ref. Particle", animateRefParticleCB);
646    addButton(menu, "Go to start of Ref path", gotoRefPathStartCB);
647    addButton(menu, "Invert Ref path", invertRefPathCB);
648 
649    Widget viewerBase = SoXtFullViewer::buildWidget(form);
650 
651    XtSetArg(args[0], XmNtopAttachment, XmATTACH_WIDGET);
652    XtSetArg(args[1], XmNtopWidget, menuBar);
653    XtSetArg(args[2], XmNleftAttachment, XmATTACH_FORM);
654    XtSetArg(args[3], XmNrightAttachment, XmATTACH_FORM);
655    XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM);
656    XtSetValues(viewerBase, args, 5);
657 
658    return viewerBase;
659 }
660 
661 
662 // Adds a new menu to menuBar
663 Widget G4OpenInventorXtExaminerViewer::addMenu(std::string name)
664 {
665    Arg args[1];
666    Widget menu = XmCreatePulldownMenu(menuBar, (char *) name.c_str(), NULL, 0);
667 
668    XtSetArg(args[0], XmNsubMenuId, menu);
669    Widget w = XmCreateCascadeButton(menuBar, (char *) name.c_str(), args, 1);
670    XtManageChild(w);
671 
672    return menu;
673 }
674 
675 
676 // Adds a new button to menu
677 void G4OpenInventorXtExaminerViewer::addButton(Widget menu, std::string name,
678                                              XtCallbackProc cb)
679 {
680    Widget button = XmCreatePushButton(menu, (char *) name.c_str(), NULL, 0);
681    XtManageChild(button);
682    XtAddCallback(button, XmNactivateCallback, cb, this);
683 }
684 
685 
686 // Overloaded for saving of and browsing through viewpoints.
687 void G4OpenInventorXtExaminerViewer::createViewerButtons(Widget parent,
688                                                        SbPList * buttonlist)
689 {
690    int n;
691    Arg args[6];
692    Widget saveViewPtButton, abbrOutputButton, pickRefPathButton;
693    Widget switchWireFrameButton;
694 
695    // Create original buttons
696    SoXtExaminerViewer::createViewerButtons(parent, buttonlist);
697 
698    // Handle disappearing button caused by SoXtExaminerViewer::setCamera
699    Widget emptyButton = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
700                                                 parent, NULL);
701    buttonlist->append(emptyButton);
702 
703    // Left arrow that goes back one view point on click
704    n = 0;
705    XtSetArg(args[n], XmNtopPosition, 1);  n++;
706    XtSetArg(args[n], XmNbottomPosition, 2); n++;
707    XtSetArg(args[n], XmNleftPosition, 0); n++;
708    XtSetArg(args[n], XmNrightPosition, 1);  n++;
709    XtSetArg(args[n], XmNarrowDirection, XmARROW_LEFT);  n++;
710    XtSetArg(args[n], XmNsensitive, False);  n++;
711    prevViewPtButton = XmCreateArrowButtonGadget(parent, (char *) "ArrowL",
712                                                 args, n);
713    XtManageChild(prevViewPtButton);
714    XtAddCallback(prevViewPtButton, XmNactivateCallback,
715                  G4OpenInventorXtExaminerViewer::prevViewPtCB, this);
716    buttonlist->append(prevViewPtButton);
717 
718    // Right arrow that goes forward one view point on click
719    n = 0;
720    XtSetArg(args[n], XmNtopPosition, 1);  n++;
721    XtSetArg(args[n], XmNbottomPosition, 2); n++;
722    XtSetArg(args[n], XmNleftPosition, 0); n++;
723    XtSetArg(args[n], XmNrightPosition, 1);  n++;
724    XtSetArg(args[n], XmNarrowDirection, XmARROW_RIGHT); n++;
725    XtSetArg(args[n], XmNsensitive, False);  n++;
726    nextViewPtButton = XmCreateArrowButtonGadget(parent, (char *) "ArrowR",
727                                                 args, n);
728    XtManageChild(nextViewPtButton);
729    XtAddCallback(nextViewPtButton, XmNactivateCallback,
730                  G4OpenInventorXtExaminerViewer::nextViewPtCB, this);
731    buttonlist->append(nextViewPtButton);
732 
733    // Save button for storing current camera parameters
734    saveViewPtButton = XtVaCreateManagedWidget("Save", xmPushButtonWidgetClass,
735                                               parent, NULL);
736    XtAddCallback(saveViewPtButton, XmNactivateCallback,
737                  G4OpenInventorXtExaminerViewer::saveViewPtCB, this);
738    Pixmap saveVP, saveVP_ins;
739    saveVP = SoXtInternal::createPixmapFromXpm(saveViewPtButton,
740                                               saveViewPt_xpm);
741    saveVP_ins = SoXtInternal::createPixmapFromXpm(saveViewPtButton,
742                                                   saveViewPt_xpm, TRUE);
743    XtVaSetValues(saveViewPtButton, XmNlabelType, XmPIXMAP, XmNlabelPixmap,
744                  saveVP, XmNselectPixmap, saveVP, XmNlabelInsensitivePixmap,
745                  saveVP_ins, XmNselectInsensitivePixmap, saveVP_ins, NULL);
746    buttonlist->append(saveViewPtButton);
747 
748    // Toggle button to get abbreviated output
749    abbrOutputButton = XtVaCreateManagedWidget("Abbr",
750                                               xmToggleButtonWidgetClass, parent, XmNindicatorOn, False, NULL);
751    XtAddCallback(abbrOutputButton, XmNdisarmCallback, G4OpenInventorXtExaminerViewer::abbrOutputCB,
752                  this);
753    Pixmap pickextxpm, pickextxpm_ins;
754    pickextxpm = SoXtInternal::createPixmapFromXpm(abbrOutputButton,
755                                                   pickext_xpm);
756    pickextxpm_ins = SoXtInternal::createPixmapFromXpm(abbrOutputButton,
757                                                       pickext_xpm, TRUE);
758    XtVaSetValues(abbrOutputButton, XmNlabelType, XmPIXMAP, XmNlabelPixmap,
759                  pickextxpm, XmNselectPixmap, pickextxpm, XmNlabelInsensitivePixmap,
760                  pickextxpm_ins, XmNselectInsensitivePixmap, pickextxpm_ins, NULL);
761    //   Pixmap consolexpm, consolexpm_ins;
762    // consolexpm = SoXtInternal::createPixmapFromXpm(abbrOutputButton,
763    //                                                console_xpm);
764    // consolexpm_ins = SoXtInternal::createPixmapFromXpm(abbrOutputButton,
765    //                                                    console_xpm, TRUE);
766    // XtVaSetValues(abbrOutputButton, XmNlabelType, XmPIXMAP, XmNlabelPixmap,
767    //               consolexpm, XmNselectPixmap, consolexpm, XmNlabelInsensitivePixmap,
768    //               consolexpm_ins, XmNselectInsensitivePixmap, consolexpm_ins, NULL);
769    buttonlist->append(abbrOutputButton);
770 
771    // Button for selecting the beam that will act as reference path
772    pickRefPathButton = XtVaCreateManagedWidget("Refpath", xmPushButtonWidgetClass,
773                                                parent, NULL);
774    XtAddCallback(pickRefPathButton, XmNactivateCallback,
775                  G4OpenInventorXtExaminerViewer::pickRefPathCB, this);
776    Pixmap pickrefxpm, pickrefxpm_ins;
777    pickrefxpm = SoXtInternal::createPixmapFromXpm(pickRefPathButton,
778                                                     pickref_xpm);
779    pickrefxpm_ins = SoXtInternal::createPixmapFromXpm(pickRefPathButton,
780                                                         pickref_xpm, TRUE);
781    XtVaSetValues(pickRefPathButton, XmNlabelType, XmPIXMAP, XmNlabelPixmap,
782        pickrefxpm, XmNselectPixmap, pickrefxpm, XmNlabelInsensitivePixmap,
783        pickrefxpm_ins, XmNselectInsensitivePixmap, pickrefxpm_ins, NULL);
784 
785    buttonlist->append(pickRefPathButton);
786 
787    // Toggle button for switching in and out of wireframe mode
788    switchWireFrameButton = XtVaCreateManagedWidget("Wireframe",
789          xmToggleButtonWidgetClass, parent,  XmNindicatorOn, False, NULL);
790    XtAddCallback(switchWireFrameButton, XmNvalueChangedCallback,
791                  G4OpenInventorXtExaminerViewer::switchWireFrameCB, this);
792    Pixmap wireframe, wireframe_ins;
793    wireframe = SoXtInternal::createPixmapFromXpm(switchWireFrameButton,
794                                                  wireframe_xpm);
795    wireframe_ins = SoXtInternal::createPixmapFromXpm(switchWireFrameButton,
796                                                      wireframe_xpm, TRUE);
797    XtVaSetValues(switchWireFrameButton, XmNlabelType, XmPIXMAP, XmNlabelPixmap,
798               wireframe, XmNselectPixmap, wireframe, XmNlabelInsensitivePixmap,
799               wireframe_ins, XmNselectInsensitivePixmap, wireframe_ins, NULL);
800    buttonlist->append(switchWireFrameButton);
801 }
802 
803 
804 // Called right after buttons and widgets get realized.
805 // It sets the viewpoint last accessed.
806 void G4OpenInventorXtExaminerViewer::afterRealizeHook()
807 {
808    SoXtExaminerViewer::afterRealizeHook();
809 
810    // Default height is used when selecting and viewing scene elements
811    // FWJ Added defaultHeight for Ortho camera
812    SoCamera *cam = getCamera();
813    if (cam) {
814       if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
815          defaultHeightAngle =
816             ((SoPerspectiveCamera *) cam)->heightAngle.getValue();
817          toggleCameraType();
818          defaultHeight =
819             ((SoOrthographicCamera *) cam)->height.getValue();
820          toggleCameraType();
821       } else {
822          defaultHeight =
823             ((SoOrthographicCamera *) cam)->height.getValue();
824          toggleCameraType();
825          cam = getCamera();
826          if (cam->isOfType(SoPerspectiveCamera::getClassTypeId()))
827             defaultHeightAngle =
828                ((SoPerspectiveCamera *) cam)->heightAngle.getValue();
829          toggleCameraType();
830       }
831    }
832 
833    // Open the default bookmark file
834    fileIn.open(fileName.c_str());
835    if (!fileIn.fail()) {
836       if (!loadViewPts()) {
837          String dialogName = (char *) "Error Loading File";
838          std::string msg = "Wrong or corrupted input file.";
839          warningMsgDialog(msg, dialogName, NULL);
840       } else {
841          // Opens a file without erasing it
842          fileOut.open(fileName.c_str(), std::ios::in);
843          fileOut.seekp(0, std::ios::end); // For appending new data to the end
844          constructListsDialog(getParentWidget(), this, NULL); // Pop up listsDialog
845          if (viewPtList.size()) {
846             // FWJ disabled auto-selection of first viewpoint.
847             // Initial view should be user-controllable & not forced
848             //    setViewPt();
849             XtSetSensitive(nextViewPtButton, True);
850             XtSetSensitive(prevViewPtButton, True);
851          }
852       }
853       fileIn.close();
854    } else {
855       // Creates a new default bookmark file
856       fileOut.open(fileName.c_str());
857       constructListsDialog(getParentWidget(), this, NULL); // Pop up listsDialog
858    }
859 
860    fileIn.clear();
861 
862    SoSeparator *root = (SoSeparator *) (getSceneManager()->getSceneGraph());
863    if (root == NULL)
864       SoDebugError::post("G4OpenInventorXtExaminerViewer::afterRealizeHook", "Root is null.");
865    else {
866       root->addChild(myCam); // For position/orientation calculation during animation
867    }
868 
869    sceneChangeSensor = new SoNodeSensor;
870    sceneChangeSensor->setFunction(sceneChangeCB);
871    sceneChangeSensor->attach(root);
872    sceneChangeSensor->setData(this);
873 
874    // Monitor mouseover events for displaying the name of scene elements
875    // An SoEventCallback is needed instead of using the default processSoEvent
876    // because that last one does not provide us with an SoPath to the object
877    // that was picked
878    SoEventCallback *moCB = new SoEventCallback;
879    moCB->addEventCallback(
880                           SoLocation2Event::getClassTypeId(),
881                           mouseoverCB, static_cast<void *>(this));
882    root->addChild(moCB);
883 
884    // Override the default picking mechanism present in G4OpenInventorViewer
885    // because we want abbreviated output when picking a trajectory
886    SoEventCallback *pickCB = new SoEventCallback;
887    pickCB->addEventCallback(
888                             SoMouseButtonEvent::getClassTypeId(),
889                             pickingCB, static_cast<void *>(this));
890    root->addChild(pickCB);
891 
892 }
893 
894 
895 // Rotates camera 90 degrees around a scene element.
896 // Rotation is animated for smoothness.
897 void G4OpenInventorXtExaminerViewer::rotateCamera()
898 {
899    SoCamera *cam = getCamera();
900 
901    SbRotation rot(rotAxis, M_PI / (2 * ROT_CNT));
902    rot.multVec(camDir, camDir);
903    rot.multVec(camUpVec, camUpVec);
904 
905    SbVec3f camPosNew = prevPt - (camDir*distance);
906    cam->position = camPosNew;
907    cam->pointAt(prevPt, camUpVec);
908    cam->focalDistance = (prevPt - camPosNew).length();
909 
910    rotCnt--;
911 
912    if (animateSensorRotation->isScheduled()) {
913       animateSensorRotation->unschedule();
914    }
915 
916    animateSensorRotation->setBaseTime(SbTime::getTimeOfDay());
917    animateSensorRotation->setInterval(SbTime(0.02));
918    animateSensorRotation->schedule();
919 
920 }
921 
922 
923 // Slides camera along the beamline.
924 void G4OpenInventorXtExaminerViewer::moveCamera(float dist, bool lookdown)
925 {
926 
927    SoCamera *cam = getCamera();
928    SbVec3f p1(0), p2(0); // The particle moves from p1 to p2
929    SbVec3f particleDir;  // Direction vector from p1 to p2
930    SbVec3f camPosNew(0); // New position of the camera
931 
932    if(refParticleTrajectory.size() == 0) {
933       //refParticleTrajectory hasn't been set yet
934       if(dist)
935          distance = dist;
936       else
937          distance = (cam->position.getValue() - center).length();
938 
939       cam->position.setValue(center + offsetFromCenter*distance);
940       cam->focalDistance = (cam->position.getValue() - center).length();
941       cam->pointAt(center, upVector);
942    }
943    else{
944 
945       // If we move forward past the last trajectory point,
946       // go back to the beginning
947       if (refParticleIdx >= (int) refParticleTrajectory.size() - 1) {
948          prevPt = refParticleTrajectory[refParticleIdx - step];
949          dist = (prevPt - cam->position.getValue()).length();
950          refParticleIdx = 0;
951       }
952       // If we move backward past the beginning,
953       // go to the last trajectory point
954       if (refParticleIdx < 0) {
955          prevPt = refParticleTrajectory[refParticleIdx + step];
956          dist = (prevPt - cam->position.getValue()).length();
957          refParticleIdx = refParticleTrajectory.size() - 2;
958       }
959 
960       // Set start and end points
961       p1 = refParticleTrajectory[refParticleIdx];
962       p2 = refParticleTrajectory[refParticleIdx + step];
963 
964       // Get the direction from p1 to p2
965       particleDir = p2 - p1;
966       particleDir.normalize();
967 
968       if(prevParticleDir == SbVec3f(0,0,0)){
969          // First time entering BEAMLINE mode, look at
970          // the element from the front, with camera upright
971          if(lookdown)
972             camDir = SbVec3f(0,0,1);
973          else
974             camDir = SbVec3f(1,0,0);
975          camUpVec = SbVec3f(0,1,0);
976 
977          // In case the start of the goes in a
978          // direction other than +z, rotate the camera accordingly
979          SbRotation rot(SbVec3f(0,0,1), particleDir);
980          rot.multVec(camDir, camDir);
981          rot.multVec(camUpVec, camUpVec);
982 
983       }
984       else if(particleDir != prevParticleDir) {
985          // The beamline has changed direction
986 
987          SbRotation rot(prevParticleDir, particleDir);
988          rot.multVec(camDir, camDir);
989          rot.multVec(camUpVec, camUpVec);
990 
991       }
992 
993       if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
994          if (!dist)
995             distance = (prevPt - cam->position.getValue()).length();
996          else
997             distance = dist;
998       }
999 
1000       // FWJ distance not relevant -- use focalDistance
1001       // if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
1002       //    if (!dist)
1003       //       distance = (prevPt - cam->position.getValue()).length();
1004       //    else
1005       //       distance = dist;
1006       // }
1007 
1008 
1009       float x(0.),y(0.),z(0.);
1010       prevPt.getValue(x,y,z);
1011 
1012 
1013       if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
1014          camPosNew = p2 - (camDir*distance);
1015       }
1016       if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
1017          // FWJ maintain focal distance
1018          camPosNew = p2 - (camDir*cam->focalDistance.getValue());
1019          //         camPosNew = p2 - (camDir);
1020       }
1021 
1022       cam->position = camPosNew;
1023       cam->pointAt(p2, camUpVec);
1024       cam->focalDistance = (p2 - camPosNew).length();
1025 
1026       p2.getValue(x,y,z);
1027       camPosNew.getValue(x,y,z);
1028 
1029       prevParticleDir = particleDir;
1030       prevPt = p1; // For accurate distance calculation
1031 
1032    }
1033 
1034 }
1035 
1036 
1037 void G4OpenInventorXtExaminerViewer::pickingCB(void *aThis, 
1038                                                SoEventCallback *eventCB)
1039 {
1040    SoHandleEventAction* action = eventCB->getAction();
1041    const SoPickedPoint *pp = action->getPickedPoint();
1042    G4OpenInventorXtExaminerViewer* This = (G4OpenInventorXtExaminerViewer*)aThis;
1043 
1044    if(pp != NULL) {
1045 
1046       SoPath* path = pp->getPath();
1047       SoNode* node = ((SoFullPath*)path)->getTail();
1048 
1049       if(node->getTypeId() == SoLineSet::getClassTypeId()){
1050 
1051          if(This->pickRefPathFlag){
1052             This->pickRefPathFlag = false;
1053             if(This->viewingBeforePickRef != This->isViewing())
1054                This->setViewing(This->viewingBeforePickRef);
1055             else
1056                This->setComponentCursor(SoXtCursor(SoXtCursor::DEFAULT));
1057 
1058             // The trajectory is a set of lines stored in a LineSet
1059             SoLineSet * trajectory = (SoLineSet *)node;
1060 
1061        // The set of all trajectories is stored in a Seperator group node
1062        // one level above the LineSet that was picked. The nodes under that
1063        // seperator are as follows (in this order): Material, LightModel,
1064        // ResetTransform, MatrixTransform, Coordinate3, DrawStyle, LineSet
1065             SoSeparator * grpNode = 
1066                (SoSeparator*)(((SoFullPath*)path)->getNodeFromTail(1));
1067 
1068    // The node that contains the coordinates for the trajectory is a
1069    // Coordinate3 node which occurs before the LineSet node.  We iterate
1070    // back through the nodes in the group until we find the Coordinate3 node
1071             int nodeIndex = grpNode->findChild(trajectory);
1072             SoNode * tmpNode;
1073             // FWJ needs initialization
1074             SoCoordinate3 * coords = 0;
1075             //            SoCoordinate3 * coords;
1076             // We allow only 100 iterations, in case the node isn't found
1077             // (should take only a few iterations)
1078             for(int i = 0; i < 100; ++i) {
1079                --nodeIndex;
1080 
1081                tmpNode = grpNode->getChild(nodeIndex);
1082                if(tmpNode->getTypeId() == SoCoordinate3::getClassTypeId()){
1083                   //node found
1084                   coords = (SoCoordinate3 *)tmpNode;
1085                   break;
1086                }
1087             }
1088 
1089             if(coords == NULL){
1090                String dialogName = (char *) "No coordinates";
1091                std::string msg = "Could not find the coordinates node"
1092                   " for the picked trajectory."
1093                   " Reference trajectory not set";
1094                This->warningMsgDialog(msg, dialogName, NULL);
1095                return;
1096             }
1097 
1098 
1099             if ((This->lshiftdown)  || (This->rshiftdown))
1100                This->setReferencePath(trajectory, coords, true);
1101             else
1102                This->setReferencePath(trajectory, coords, false);
1103 
1104             return;
1105 
1106          }
1107          else if(This->abbrOutputFlag) {
1108 
1109             G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node);
1110             if(attHolder && attHolder->GetAttDefs().size()) {
1111 
1112                std::string strTrajPoint = "G4TrajectoryPoint:";
1113                std::ostringstream oss;
1114                for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) {
1115                   G4cout << G4AttCheck(attHolder->GetAttValues()[i],
1116                                        attHolder->GetAttDefs()[i]);
1117                   oss << G4AttCheck(attHolder->GetAttValues()[i],
1118                                     attHolder->GetAttDefs()[i]);
1119                   if(oss.str().find(strTrajPoint) != std::string::npos) {
1120 
1121            // Last attribute displayed was a trajectory point.  Since we
1122            // want abbreviated output, display the last one and exit
1123            // (unless we're already at the last (and only) trajectory point)
1124                      if(i != attHolder->GetAttDefs().size()-1) {
1125                         G4cout << G4AttCheck(
1126               attHolder->GetAttValues()[attHolder->GetAttDefs().size()-1],
1127               attHolder->GetAttDefs()[attHolder->GetAttDefs().size()-1]);
1128                      }
1129                      break;
1130                   }
1131                }
1132             } else {
1133                G4String name((char*)node->getName().getString());
1134                G4String cls((char*)node->getTypeId().getName().getString());
1135                G4cout << "SoNode : " << node
1136                       << " SoType : " << cls
1137                       << " name : " << name
1138                       << G4endl;
1139                G4cout << "No attributes attached." << G4endl;
1140             }
1141 
1142             return;
1143          }
1144          else{
1145             //Go to default behavior
1146          }
1147       }
1148       else {
1149          //Go to default behavior
1150       }
1151 
1152       // Default behavior in G4OpenInventorViewer::SelectionCB
1153       G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node);
1154       if(attHolder && attHolder->GetAttDefs().size()) {
1155          for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) {
1156             G4cout << G4AttCheck(attHolder->GetAttValues()[i],
1157                                  attHolder->GetAttDefs()[i]);
1158          }
1159       } else {
1160          G4String name((char*)node->getName().getString());
1161          G4String cls((char*)node->getTypeId().getName().getString());
1162          G4cout << "SoNode : " << node
1163                 << " SoType : " << cls
1164                 << " name : " << name
1165                 << G4endl;
1166          G4cout << "No attributes attached." << G4endl;
1167       }
1168 
1169       //Suppress other event handlers
1170       eventCB->setHandled();
1171    }
1172 }
1173 
1174 
1175 void G4OpenInventorXtExaminerViewer::mouseoverCB(void *aThis, SoEventCallback *eventCB)
1176 {
1177    SoHandleEventAction* action = eventCB->getAction();
1178    const SoPickedPoint* pp = action->getPickedPoint();
1179    G4OpenInventorXtExaminerViewer* This = (G4OpenInventorXtExaminerViewer*)aThis;
1180 
1181    if(!This->abbrOutputFlag)
1182       return;
1183 
1184    if(pp != NULL) {
1185 
1186       const SbViewportRegion & viewportRegion = action->getViewportRegion();
1187 
1188       std::string sLogName;
1189       float x,y,z;
1190       std::stringstream ssZPos;
1191       std::stringstream ssSolids;
1192       std::stringstream ssMaterials;
1193       SoPath * path = pp->getPath();
1194       SoNode* node = ((SoFullPath*)path)->getTail();
1195 
1196       if(node->getTypeId() == Geant4_SoPolyhedron::getClassTypeId()) {
1197 
1198          sLogName = "Logical Volume:  ";
1199          sLogName += ((Geant4_SoPolyhedron *)node)->getName().getString();
1200 
1201          SoGetBoundingBoxAction bAction(viewportRegion);
1202          bAction.apply((SoFullPath*)path);
1203          SbBox3f bBox = bAction.getBoundingBox();
1204          SbVec3f center = bBox.getCenter();
1205          center.getValue(x,y,z);
1206          ssZPos << "Pos:  " << x << "  " << y << "  " << z;
1207 
1208          G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node);
1209          if(attHolder && attHolder->GetAttDefs().size()) {
1210 
1211             std::vector<const std::map<G4String,G4AttDef>*> vecDefs =
1212                attHolder->GetAttDefs();
1213             std::vector<const std::vector<G4AttValue>*> vecVals =
1214                attHolder->GetAttValues();
1215             for (size_t i = 0; i < vecDefs.size(); ++i) {
1216                const std::vector<G4AttValue> * vals = vecVals[i];
1217 
1218                std::vector<G4AttValue>::const_iterator iValue;
1219 
1220                for (iValue = vals->begin(); iValue != vals->end(); ++iValue) {
1221                   const G4String& valueName = iValue->GetName();
1222                   const G4String& value = iValue->GetValue();
1223 
1224                   if(valueName == "Solid") {
1225                      if(ssSolids.str() == "")
1226                         ssSolids << "Solid Name:  " << value;
1227                      else
1228                         ssSolids << ", " << value;
1229                   }
1230 
1231                   if(valueName == "Material") {
1232                      if(ssMaterials.str() == "")
1233                         ssMaterials << "Material Name:  " << value;
1234                      else
1235                         ssMaterials << ", " << value;
1236                   }
1237                }
1238             }
1239          }
1240       }
1241       // FWJ Mouseover for trajectories
1242       else if(node->getTypeId() == SoLineSet::getClassTypeId()) {
1243          //         G4cout << "Trajectory!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << G4endl;
1244          G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(node);
1245          if(attHolder && attHolder->GetAttDefs().size()) {
1246             std::string strTrajPoint = "G4TrajectoryPoint:";
1247             std::ostringstream oss;
1248             G4String t1, t1Ch, t2, t3, t4;
1249             for (size_t i = 0; i < attHolder->GetAttDefs().size(); ++i) {
1250                //               G4cout << "Getting index " << i << " from attHolder" << G4endl;
1251                // No, returns a vector!   G4AttValue* attValue = attHolder->GetAttValues()[i];
1252                const std::vector<G4AttValue>* vals = attHolder->GetAttValues()[i];
1253                std::vector<G4AttValue>::const_iterator iValue;
1254                for (iValue = vals->begin(); iValue != vals->end(); ++iValue) {
1255                   const G4String& valueName = iValue->GetName();
1256                   const G4String& value = iValue->GetValue();
1257                   // G4cout << "  valueName = " << valueName << G4endl;
1258                   // G4cout << "  value = " << value << G4endl;
1259                   // LINE 1
1260                   if (valueName == "PN") t1 = value;
1261                   if (valueName == "Ch") {
1262                      if (atof(value.c_str()) > 0)
1263                         t1Ch = "    +";
1264                      else
1265                         t1Ch = "    ";
1266                      t1Ch += value;
1267                   }
1268                   if (valueName == "PDG") {
1269                      t1 += "    ";
1270                      t1 += value;
1271                      t1 += t1Ch;
1272                      This->mouseOverTextLogName->string.setValue(t1);
1273                   }
1274                   //                  G4cout << "  t1 = " << t1 << G4endl;
1275                   // LINE 2
1276                   if (valueName == "EventID") t2 = "Evt " + value;
1277                   if (valueName == "ID") t2 += "    Trk " + value;
1278                   if (valueName == "PID") {
1279                      t2 += "    Prt " + value;
1280                      This->mouseOverTextSolid->string.setValue(t2);
1281                   }
1282                   // LINE 3
1283                   if (valueName == "IKE") t3 = "KE " + value;
1284                   if (valueName == "IMom") {
1285                      // Remove units
1286                      unsigned ipos = value.rfind(" ");
1287                      G4String value1 = value;
1288                      value1.erase(ipos);
1289                      t3 += "    P (" + value1 + ")";
1290                   }
1291                   if (valueName == "IMag") {
1292                      t3 += " " + value + "/c";
1293                      //                     t3 += " " + value;
1294                      This->mouseOverTextMaterial->string.setValue(t3);
1295                   }
1296                   // LINE 4
1297                   if (valueName == "NTP") {
1298                      std::ostringstream t4oss;
1299                      t4oss << "TrjPts " <<  value;
1300                      t4oss << "    Pos " << pp->getPoint()[0] << " " << pp->getPoint()[1] <<
1301                         " " << pp->getPoint()[2];
1302                      This->mouseOverTextZPos->string.setValue(SbString(t4oss.str().c_str()));
1303                   }
1304                }
1305 //               G4cout << "  NOW CALLING G4AttCheck" << G4endl;
1306 //                G4cout << G4AttCheck(attHolder->GetAttValues()[i],
1307 //                                     attHolder->GetAttDefs()[i]);
1308 //                oss << G4AttCheck(attHolder->GetAttValues()[i],
1309 //                                  attHolder->GetAttDefs()[i]);
1310 //                if(oss.str().find(strTrajPoint) != std::string::npos) {
1311 //                   // Last attribute displayed was a trajectory point.  Since we
1312 //                   // want abbreviated output, display the last one and exit
1313 //                   // (unless we're already at the last (and only) trajectory point)
1314 //                   if(i != attHolder->GetAttDefs().size()-1) {
1315 //                      G4cout << G4AttCheck(
1316 //                                           attHolder->GetAttValues()[attHolder->GetAttDefs().size()-1],
1317 //                                           attHolder->GetAttDefs()[attHolder->GetAttDefs().size()-1]);
1318 //                   }
1319 //                   break;
1320 //                }
1321             }
1322          }
1323          This->setSuperimpositionEnabled(This->superimposition, TRUE);
1324          This->scheduleRedraw();
1325          eventCB->setHandled();
1326          return;
1327       }
1328 
1329       bool redraw = false;
1330       if(std::string(This->mouseOverTextLogName->string.getValues(0)->getString()) != sLogName) {
1331          This->mouseOverTextLogName->string.setValue(SbString(sLogName.c_str()));
1332          redraw = true;
1333       }
1334       if(std::string(This->mouseOverTextSolid->string.getValues(0)->getString()) != ssSolids.str()) {
1335          This->mouseOverTextSolid->string.setValue(SbString(ssSolids.str().c_str()));
1336          redraw = true;
1337       }
1338       if(std::string(This->mouseOverTextMaterial->string.getValues(0)->getString()) != ssMaterials.str()){
1339          This->mouseOverTextMaterial->string.setValue(SbString(ssMaterials.str().c_str()));
1340          redraw = true;
1341       }
1342       if(std::string(This->mouseOverTextZPos->string.getValues(0)->getString()) != ssZPos.str()) {
1343          This->mouseOverTextZPos->string.setValue(SbString(ssZPos.str().c_str()));
1344          redraw = true;
1345       }
1346 
1347       if(redraw) {
1348          This->setSuperimpositionEnabled(This->superimposition, TRUE);
1349          This->scheduleRedraw();
1350       }
1351 
1352       eventCB->setHandled();
1353    }
1354    else {
1355       if(std::string(This->mouseOverTextLogName->string.getValues(0)->getString()) != "") {
1356          This->mouseOverTextLogName->string.setValue(SbString(""));
1357          This->scheduleRedraw();
1358       }
1359       if(std::string(This->mouseOverTextSolid->string.getValues(0)->getString()) != "") {
1360          This->mouseOverTextSolid->string.setValue(SbString(""));
1361          This->scheduleRedraw();
1362       }
1363       if(std::string(This->mouseOverTextMaterial->string.getValues(0)->getString()) != "") {
1364          This->mouseOverTextMaterial->string.setValue(SbString(""));
1365          This->scheduleRedraw();
1366       }
1367       if(std::string(This->mouseOverTextZPos->string.getValues(0)->getString()) != "") {
1368          This->mouseOverTextZPos->string.setValue(SbString(""));
1369          This->scheduleRedraw();
1370       }
1371    }
1372 }
1373 
1374 
1375 SbBool G4OpenInventorXtExaminerViewer::processSoEvent(const SoEvent * const ev) {
1376    SoCamera *cam = getCamera();
1377    const SoType type(ev->getTypeId());
1378 
1379    if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
1380       SoMouseButtonEvent * me = (SoMouseButtonEvent *) ev;
1381 
1382       if (currentState == ANIMATION || currentState == REVERSED_ANIMATION
1383           || currentState == PAUSED_ANIMATION) {
1384          switch (me->getButton()) {
1385          case SoMouseButtonEvent::BUTTON4: // Scroll wheel up
1386             if (me->getState() == SoButtonEvent::DOWN) {
1387                if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
1388                   float hAngle =
1389                      ((SoPerspectiveCamera *) cam)->heightAngle.getValue();
1390                   ((SoPerspectiveCamera *) cam)->heightAngle = hAngle
1391                      + 0.01f;
1392                   return TRUE;
1393                } else if (cam->isOfType(
1394                                         SoOrthographicCamera::getClassTypeId())) {
1395                   float height =
1396                      ((SoOrthographicCamera *) cam)->height.getValue();
1397                   ((SoOrthographicCamera *) cam)->height = height + 5;
1398                   return TRUE;
1399                }
1400             }
1401             break;
1402          case SoMouseButtonEvent::BUTTON5: // Scroll wheel down
1403             if (me->getState() == SoButtonEvent::DOWN) {
1404                if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
1405                   float hAngle =
1406                      ((SoPerspectiveCamera *) cam)->heightAngle.getValue();
1407                   if (hAngle > 0.01)
1408                      ((SoPerspectiveCamera *) cam)->heightAngle = hAngle
1409                         - 0.01f;
1410                   return TRUE;
1411                } else if (cam->isOfType(
1412                                         SoOrthographicCamera::getClassTypeId())) {
1413                   float height =
1414                      ((SoOrthographicCamera *) cam)->height.getValue();
1415                   if (height > 5)
1416                      ((SoOrthographicCamera *) cam)->height = height - 5;
1417                   return TRUE;
1418                }
1419             }
1420             break;
1421          default:
1422             break;
1423          }
1424       }
1425       if (currentState == GENERAL) {
1426 
1427       }
1428    }
1429 
1430    if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
1431       SoKeyboardEvent * ke = (SoKeyboardEvent *) ev;
1432 
1433       if (SoKeyboardEvent::isKeyPressEvent(ev, ke->getKey())) {
1434          switch (ke->getKey()) {
1435          case SoKeyboardEvent::LEFT_SHIFT:
1436             this->lshiftdown = true;
1437             return TRUE;
1438          case SoKeyboardEvent::RIGHT_SHIFT:
1439             this->rshiftdown = true;
1440             return TRUE;
1441          case SoKeyboardEvent::LEFT_CONTROL:
1442             this->lctrldown = true;
1443             return TRUE;
1444          case SoKeyboardEvent::RIGHT_CONTROL:
1445             this->rctrldown = true;
1446             return TRUE;
1447          case SoKeyboardEvent::SPACE:
1448             if (currentState == ANIMATION
1449                 || currentState == REVERSED_ANIMATION) {
1450                beforePausing = currentState;
1451                currentState = PAUSED_ANIMATION;
1452                if (animateSensor->isScheduled())
1453                   animateSensor->unschedule();
1454                return TRUE;
1455             } else if (currentState == PAUSED_ANIMATION) {
1456                if (maxSpeed) {
1457                   if ((beforePausing == ANIMATION
1458                        && refParticleIdx
1459                        < (int) refParticleTrajectory.size() - 1)
1460                       || (beforePausing == REVERSED_ANIMATION
1461                           && refParticleIdx > 0)) {
1462                      currentState = beforePausing;
1463                      animateRefParticle();
1464                   }
1465                }
1466                return TRUE;
1467             }
1468             break;
1469          case SoKeyboardEvent::ESCAPE:
1470             if (currentState == ANIMATION
1471                 || currentState == REVERSED_ANIMATION
1472                 || currentState == PAUSED_ANIMATION) {
1473 
1474                if (animateSensor->isScheduled())
1475                   animateSensor->unschedule();
1476                currentState = prevState;
1477                refParticleIdx = prevRefIdx;
1478                setSuperimpositionEnabled(superimposition, FALSE);
1479                maxSpeed = 0.0f;
1480                step = 1;
1481 
1482                scheduleRedraw();
1483                if (currentState == VIEWPOINT) {
1484                   setSuperimpositionEnabled(superimposition, TRUE);
1485                   axisSwitch->whichChild.setValue(SO_SWITCH_NONE);
1486                   animSpeedOutlineSwitch->whichChild.setValue(
1487                                                               SO_SWITCH_NONE);
1488                   animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE);
1489 
1490                   scheduleRedraw();
1491                }
1492                restoreCamera();
1493                return TRUE;
1494             }
1495             break;
1496          case SoKeyboardEvent::DELETE:
1497             if (viewPtList.size()
1498                 && (currentState != ANIMATION
1499                     && currentState != REVERSED_ANIMATION
1500                     && currentState != PAUSED_ANIMATION)) {
1501                String dialogName = (char *) "Delete Viewpoint";
1502                std::string msg = "Are you sure you want to delete current viewpoint?";
1503                warningMsgDialog(msg, dialogName, deleteViewPtCB);
1504                return TRUE;
1505             }
1506             break;
1507          case SoKeyboardEvent::LEFT_ARROW:
1508             switch (currentState) {
1509             case BEAMLINE:
1510                if ((this->lshiftdown) || (this->rshiftdown)){
1511                   refParticleIdx -= step;
1512                   moveCamera();
1513                }
1514                else if ((this->lctrldown) || (this->rctrldown)){
1515                   if (SoXtExaminerViewer::isAnimating())
1516                      stopAnimating();
1517                   prevState = currentState;
1518                   currentState = ROTATING;
1519                   animateBtwPtsPeriod = 0.08f;
1520 
1521                   SbVec3f tmp = camDir;
1522                   tmp.negate();
1523                   rotAxis = tmp;
1524 
1525                   rotCnt = ROT_CNT;
1526                   moveCamera(); // To make sure camera is perpendicular to the beamline
1527 
1528                   rotateCamera();
1529                }
1530                else{
1531                   if (SoXtExaminerViewer::isAnimating())
1532                      stopAnimating();
1533                   prevState = currentState;
1534                   currentState = ROTATING;
1535                   animateBtwPtsPeriod = 0.08f;
1536 
1537                   SbVec3f tmp = camUpVec;
1538                   tmp.negate();
1539                   rotAxis = tmp;
1540 
1541                   rotCnt = ROT_CNT;
1542                   moveCamera(); // To make sure camera is perpendicular to the beamline
1543 
1544                   rotateCamera();
1545 
1546                }
1547                return TRUE;
1548 
1549             case ANIMATION:
1550             case REVERSED_ANIMATION:
1551                left_right -= 1.5f;
1552                return TRUE;
1553             case PAUSED_ANIMATION:
1554                left_right -= 1.5f;
1555                setStartingPtForAnimation();
1556                cam->position = myCam->position;
1557                return TRUE;
1558             case GENERAL:
1559             case VIEWPOINT:
1560                if ((!this->lshiftdown) && (!this->rshiftdown)) {
1561                   // Using this allows us to look around without
1562                   // changing the camera parameters (camDir, camUpVec)
1563                   this->bottomWheelMotion(
1564                                           this->getBottomWheelValue() + 0.1f);
1565 
1566                   return TRUE;
1567                }
1568                break;
1569             case ROTATING:
1570                // For this state, let the keyboard event
1571                // be handled by superclass
1572                break;
1573             default:
1574                SoDebugError::post("G4OpenInventorXtExaminerViewer::processSoEvent",
1575                                   "Unhandled viewer state");
1576                break;
1577             }
1578             break;
1579 
1580          case SoKeyboardEvent::RIGHT_ARROW:
1581             switch(currentState){
1582             case BEAMLINE:
1583                if ((this->lshiftdown) || (this->rshiftdown)){
1584                   refParticleIdx += step;
1585                   moveCamera();
1586                }
1587                else if ((this->lctrldown) || (this->rctrldown)){
1588                   if (SoXtExaminerViewer::isAnimating())
1589                      stopAnimating();
1590                   prevState = currentState;
1591                   currentState = ROTATING;
1592                   animateBtwPtsPeriod = 0.08f;
1593 
1594                   rotAxis = camDir;
1595 
1596                   rotCnt = ROT_CNT;
1597                   moveCamera(); // To make sure camera is perpendicular to the beamline
1598 
1599                   rotateCamera();
1600                }
1601                else{
1602                   if (SoXtExaminerViewer::isAnimating())
1603                      stopAnimating();
1604                   prevState = currentState;
1605                   currentState = ROTATING;
1606                   animateBtwPtsPeriod = 0.08f;
1607 
1608                   rotAxis = camUpVec;
1609 
1610                   rotCnt = ROT_CNT;
1611                   moveCamera(); // To make sure camera is perpendicular to the beamline
1612 
1613                   rotateCamera();
1614                }
1615                return TRUE;
1616 
1617             case ANIMATION:
1618             case REVERSED_ANIMATION:
1619                left_right += 1.5f;
1620                return TRUE;
1621             case PAUSED_ANIMATION:
1622                left_right += 1.5f;
1623                setStartingPtForAnimation();
1624                cam->position = myCam->position;
1625                return TRUE;
1626             case GENERAL:
1627             case VIEWPOINT:
1628                if ((!this->lshiftdown) && (!this->rshiftdown)) {
1629                   // Using this allows us to look around without
1630                   // changing the camera parameters (camDir, camUpVec)
1631                   this->bottomWheelMotion(
1632                                           this->getBottomWheelValue() - 0.1f);
1633                   return TRUE;
1634                }
1635                break;
1636             case ROTATING:
1637                // For this state, let the keyboard event
1638                // be handled by superclass
1639                break;
1640             default:
1641                SoDebugError::post("G4OpenInventorXtExaminerViewer::processSoEvent",
1642                                   "Unhandled viewer state");
1643                break;
1644             }
1645             break;
1646 
1647          case SoKeyboardEvent::DOWN_ARROW:
1648             switch(currentState){
1649             case BEAMLINE:
1650 
1651                if ((this->lshiftdown) || (this->rshiftdown)){
1652                   refParticleIdx -= step;
1653                   moveCamera();
1654                }
1655                else{
1656                   if (SoXtExaminerViewer::isAnimating())
1657                      stopAnimating();
1658                   prevState = currentState;
1659                   currentState = ROTATING;
1660                   animateBtwPtsPeriod = 0.08f;
1661 
1662                   rotAxis = camDir.cross(camUpVec);
1663 
1664                   rotCnt = ROT_CNT;
1665                   moveCamera(); // To make sure camera is perpendicular to the beamline
1666 
1667                   rotateCamera();
1668 
1669                }
1670                return TRUE;
1671 
1672             case ANIMATION:
1673             case REVERSED_ANIMATION:
1674                up_down -= 1.5f;
1675                return TRUE;
1676             case PAUSED_ANIMATION:
1677                up_down -= 1.5f;
1678                setStartingPtForAnimation();
1679                cam->position = myCam->position;
1680                return TRUE;
1681             case GENERAL:
1682             case VIEWPOINT:
1683                // Using this allows us to look around without
1684                // changing the camera parameters (camDir, camUpVec)
1685                if ((!this->lshiftdown) && (!this->rshiftdown)) {
1686                   this->leftWheelMotion(this->getLeftWheelValue() - 0.1f);
1687                   return TRUE;
1688                }
1689                break;
1690             case ROTATING:
1691                // For this state, let the keyboard event
1692                // be handled by superclass
1693                break;
1694             default:
1695                SoDebugError::post("G4OpenInventorXtExaminerViewer::processSoEvent",
1696                                   "Unhandled viewer state");
1697                break;
1698             }
1699             break;
1700 
1701          case SoKeyboardEvent::UP_ARROW:
1702             switch(currentState){
1703             case BEAMLINE:
1704                if ((this->lshiftdown) || (this->rshiftdown)){
1705                   refParticleIdx -= step;
1706                   moveCamera();
1707                }
1708                else{
1709                   if (SoXtExaminerViewer::isAnimating())
1710                      stopAnimating();
1711                   prevState = currentState;
1712                   currentState = ROTATING;
1713                   animateBtwPtsPeriod = 0.08f;
1714 
1715                   rotAxis = camUpVec.cross(camDir);
1716 
1717                   rotCnt = ROT_CNT;
1718                   moveCamera();
1719 
1720                   rotateCamera();
1721 
1722 
1723                }
1724                return TRUE;
1725             case ANIMATION:
1726             case REVERSED_ANIMATION:
1727                up_down += 1.5f;
1728                return TRUE;
1729             case PAUSED_ANIMATION:
1730                up_down += 1.5f;
1731                setStartingPtForAnimation();
1732                cam->position = myCam->position;
1733                return TRUE;
1734             case GENERAL:
1735             case VIEWPOINT:
1736                // Using this allows us to look around without
1737                // changing the camera parameters (camDir, camUpVec)
1738                if ((!this->lshiftdown) && (!this->rshiftdown)) {
1739                   this->leftWheelMotion(this->getLeftWheelValue() + 0.1f);
1740                   return TRUE;
1741                }
1742                break;
1743             case ROTATING:
1744                // For this state, let the keyboard event
1745                // be handled by superclass
1746                break;
1747             default:
1748                SoDebugError::post("G4OpenInventorXtExaminerViewer::processSoEvent",
1749                                   "Unhandled viewer state");
1750                break;
1751             }
1752             break;
1753 
1754          case SoKeyboardEvent::PAGE_UP:
1755             switch(currentState){
1756             case BEAMLINE:
1757                if (step < (int) refParticleTrajectory.size() / 5) // Magic number
1758                   step++;
1759                return TRUE;
1760             case ANIMATION:
1761                incSpeed();
1762                maxSpeed += SPEED_INDICATOR_STEP;
1763                if (maxSpeed > 0.8)
1764                   maxSpeed = MAX_SPEED_INDICATOR;
1765                scheduleRedraw();
1766 
1767                return TRUE;
1768             case REVERSED_ANIMATION:
1769                if(!animateSensor->isScheduled()){
1770                   currentState = ANIMATION;
1771                   if (refParticleIdx
1772                       < (int) refParticleTrajectory.size() - 1) {
1773                      refParticleIdx++;
1774                      maxSpeed = SPEED_INDICATOR_STEP;
1775                      scheduleRedraw();
1776                      animateRefParticle();
1777                   }
1778                }
1779                else{
1780                   maxSpeed += SPEED_INDICATOR_STEP;
1781                   decSpeed();
1782                   scheduleRedraw();
1783                }
1784                return TRUE;
1785             case PAUSED_ANIMATION:
1786                maxSpeed += SPEED_INDICATOR_STEP;
1787                if (maxSpeed > 0.8)
1788                   maxSpeed = MAX_SPEED_INDICATOR;
1789 
1790                if (beforePausing == ANIMATION) {
1791                   incSpeed();
1792                } else {
1793                   decSpeed();
1794                   if (animateBtwPtsPeriod >= MIN_SPEED)
1795                      beforePausing = ANIMATION;
1796                }
1797 
1798                scheduleRedraw();
1799                return TRUE;
1800             default:  //fall through
1801                break;
1802             }
1803             break;
1804 
1805          case SoKeyboardEvent::PAGE_DOWN:
1806             switch(currentState){
1807             case BEAMLINE:
1808                if (step > 1)
1809                   step--;
1810                return TRUE;
1811             case ANIMATION:
1812                if(!animateSensor->isScheduled()){
1813                   currentState = REVERSED_ANIMATION;
1814                   if (refParticleIdx > 1) {
1815                      refParticleIdx--;
1816                      maxSpeed = -SPEED_INDICATOR_STEP;
1817                      scheduleRedraw();
1818                      animateRefParticle();
1819                   }
1820                }
1821                else{
1822                   maxSpeed -= SPEED_INDICATOR_STEP;
1823                   decSpeed();
1824                   scheduleRedraw();
1825                }
1826                return TRUE;
1827             case REVERSED_ANIMATION:
1828                incSpeed();
1829                maxSpeed -= SPEED_INDICATOR_STEP;
1830                if (maxSpeed < -0.8)
1831                   maxSpeed = -MAX_SPEED_INDICATOR;
1832                scheduleRedraw();
1833                return TRUE;
1834             case PAUSED_ANIMATION:
1835                maxSpeed -= SPEED_INDICATOR_STEP;
1836                if (maxSpeed < -0.8)
1837                   maxSpeed = -MAX_SPEED_INDICATOR;
1838                if (beforePausing == REVERSED_ANIMATION) {
1839                   incSpeed();
1840                } else {
1841                   decSpeed();
1842                   if (animateBtwPtsPeriod >= MIN_SPEED)
1843                      beforePausing = REVERSED_ANIMATION;
1844                }
1845                scheduleRedraw();
1846                return TRUE;
1847             default:
1848                //fall through
1849                break;
1850             }
1851             break;
1852 
1853          case SoKeyboardEvent::E:
1854             this->escapeCallback(this->examinerObject);
1855             break;
1856 
1857          default:
1858             break; // To get rid of compiler warnings
1859          }
1860       }
1861       if (SoKeyboardEvent::isKeyReleaseEvent(ev, ke->getKey())) {
1862          switch (ke->getKey()) {
1863          case SoKeyboardEvent::LEFT_SHIFT:
1864             this->lshiftdown = false;
1865             return TRUE;
1866          case SoKeyboardEvent::RIGHT_SHIFT:
1867             this->rshiftdown = false;
1868             return TRUE;
1869          case SoKeyboardEvent::LEFT_CONTROL:
1870             this->lctrldown = false;
1871             return TRUE;
1872          case SoKeyboardEvent::RIGHT_CONTROL:
1873             this->rctrldown = false;
1874             return TRUE;
1875          default:
1876             break;
1877          }
1878       }
1879    }
1880 
1881    if (currentState == ANIMATION || currentState == REVERSED_ANIMATION
1882        || currentState == ROTATING)
1883       return FALSE;
1884    else
1885       return SoXtExaminerViewer::processSoEvent(ev);
1886 }
1887 
1888 // Called by hitting PageUp during animation.
1889 void G4OpenInventorXtExaminerViewer::incSpeed() {
1890   if (std::ceil(animateBtwPtsPeriod * 100) >= 4) {
1891     if (speedStep > 0.08)
1892       speedStep -= 0.02;
1893     else
1894       speedStep = 0.02;
1895     animateBtwPtsPeriod -= speedStep;
1896   } else
1897     animateBtwPtsPeriod = 0.0;
1898 
1899   if (currentState != PAUSED_ANIMATION) {
1900     int lastIdx = refParticleTrajectory.size() - 1;
1901     if (refParticleIdx < lastIdx && !animateSensor->isScheduled())
1902       animateRefParticle();
1903   }
1904 }
1905 
1906 // Called by hitting PageDown during animation.
1907 void G4OpenInventorXtExaminerViewer::decSpeed() {
1908   animateBtwPtsPeriod += speedStep;
1909   if (animateBtwPtsPeriod < MIN_SPEED) {
1910     if (std::floor(animateBtwPtsPeriod * 100) == 12) { // Errors in double representation
1911       speedStep = 0.08;
1912     } else if (animateBtwPtsPeriod > 0.12)
1913       speedStep += 0.02;
1914   } else {
1915     animateBtwPtsPeriod = MIN_SPEED;
1916     speedStep = START_STEP;
1917     maxSpeed = 0.0f;
1918     if (animateSensor->isScheduled())
1919       animateSensor->unschedule();
1920   }
1921 }
1922 
1923 // Based on the user's interaction the speed indicator bar needs to be adjusted.
1924 void G4OpenInventorXtExaminerViewer::updateSpeedIndicator(void) {
1925   assert(this->sgeometry != NULL);
1926 
1927   SbVec3f * points = this->sgeometry->point.startEditing();
1928 
1929   if (points[10][0] == 0.0f)
1930     this->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_ALL);
1931   if (points[14][0] == 0.0f)
1932     this->animSpeedSwitch->whichChild.setValue(SO_SWITCH_ALL);
1933   points[10][0] = this->maxSpeed;
1934   points[11][0] = this->maxSpeed;
1935   points[14][0] = this->maxSpeed;
1936   points[15][0] = this->maxSpeed;
1937   this->sgeometry->point.finishEditing();
1938 
1939   if (this->maxSpeed == 0.0f) {
1940     this->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE);
1941     this->animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE);
1942   }
1943 }
1944 
1945 void G4OpenInventorXtExaminerViewer::actualRedraw(void) {
1946   switch (currentState) {
1947   case ANIMATION:
1948   case REVERSED_ANIMATION:
1949   case PAUSED_ANIMATION:
1950     updateSpeedIndicator();
1951     SoXtExaminerViewer::actualRedraw();
1952     break;
1953   default:
1954     SoXtExaminerViewer::actualRedraw();
1955     break;
1956   }
1957 }
1958 
1959 void G4OpenInventorXtExaminerViewer::setReferencePath(SoLineSet *lineset, SoCoordinate3 *coords, bool append)
1960 {
1961    // TODO:  Color the reference path
1962    // Disable the color stuff for now: changes all trajectories
1963 
1964 // // We change the color of the trajectory too, so we get its material
1965 //  nodeIndex = grpNode->findChild(trajectory);
1966 //  SoMaterial * mat;
1967 //  for(int i = 0; i < 100; ++i){
1968 //    --nodeIndex;
1969 //
1970 //    tmpNode = grpNode->getChild(nodeIndex);
1971 //    if(tmpNode->getTypeId() == SoMaterial::getClassTypeId()){
1972 //      //node found
1973 //      mat = (SoMaterial *)tmpNode;
1974 //
1975 //      break;
1976 //    }
1977 //  }
1978 //
1979 //
1980 // // Restore default color for previously picked trajectory
1981 // // and set different color for current pick
1982 //  if(This->prevColorField)
1983 //    ((SoMFColor *)This->prevColorField)->setValue(0.0, 1.0, 0.0);
1984 //  This->prevColorField = (void *)&mat->diffuseColor;
1985 //
1986 //
1987 //  if(mat->diffuseColor.isConnected())
1988 //    std::cout << "connected" << std::endl;
1989 //
1990 //  mat->diffuseColor.setValue(41.0/255.0, 230.0/255.0, 230.0/255.0);
1991 //
1992 //  std::cout << "R: " << mat->diffuseColor[0][0] << " ";
1993 //  std::cout << "G: " << mat->diffuseColor[0][1] << " ";
1994 //  std::cout << "B: " << mat->diffuseColor[0][2] << std::endl;
1995 
1996    // The trajectory is composed of all the polyline segments in the
1997    // multiple value field (SoMFInt32) numVertices.
1998    // For each of the numVertices.getNum()* polyline segments,
1999    // retrieve the points from the SoCoordinate3 node
2000    SbVec3f refParticlePt;
2001 
2002    if(!append)
2003       this->refParticleTrajectory.clear();
2004 
2005    for(int i = 0; i < lineset->numVertices.getNum(); ++i){
2006       for(int j = 0; j < lineset->numVertices[i]; ++j){
2007          refParticlePt = coords->point[j];
2008          this->refParticleTrajectory.push_back(refParticlePt);
2009       }
2010    }
2011    // Remove points that are too close to each other
2012    this->evenOutRefParticlePts();
2013    this->setReferencePathZPos();
2014    this->sortElements();
2015 }
2016 
2017 
2018 void G4OpenInventorXtExaminerViewer::setReferencePathZPos()
2019 {
2020    refZPositions.clear();
2021    refZPositions.push_back(0);
2022    float dist;
2023    for(unsigned int i=0; i < this->refParticleTrajectory.size() - 1; ++i){
2024       dist = (refParticleTrajectory[i] - 
2025               refParticleTrajectory[i + 1]).length();
2026       refZPositions.push_back(refZPositions[i] + dist);
2027    }
2028 }
2029 
2030 
2031 void G4OpenInventorXtExaminerViewer::findAndSetRefPath()
2032 {
2033    SoSearchAction action;
2034    action.setType(SoLineSet::getClassTypeId(),false);
2035    action.setInterest(SoSearchAction::ALL);
2036    action.apply(this->getSceneGraph());
2037 
2038    SoPathList &pathList = action.getPaths();
2039 
2040    if(pathList.getLength() != 0){
2041 
2042       SoCoordinate3 * coords = NULL;
2043       std::vector<SoCoordinate3 *> coordvec;
2044       std::vector<SoLineSet *> linevec;
2045 
2046       bool refPathFound = false;
2047       for(int i = 0; i < pathList.getLength(); ++i) {
2048          SoFullPath *path = (SoFullPath *)pathList[i];
2049 
2050          G4AttHolder* attHolder = dynamic_cast<G4AttHolder*>(path->getTail());
2051          for (size_t j = 0; j < attHolder->GetAttDefs().size(); ++j) {
2052             std::ostringstream oss;
2053             oss << G4AttCheck(attHolder->GetAttValues()[j], attHolder->GetAttDefs()[j]);
2054 
2055             std::string findStr = "Type of trajectory (Type): ";
2056             std::string compareValue = "REFERENCE";
2057             size_t idx = oss.str().find(findStr);
2058 
2059             if(idx != std::string::npos) {
2060                if(oss.str().substr(idx + findStr.size(), compareValue.size()) == compareValue) {
2061                   coords = this->getCoordsNode(path);
2062                   if(coords != NULL){
2063                      refPathFound = true;
2064                      coordvec.push_back(coords);
2065                      linevec.push_back((SoLineSet *)path->getTail());
2066                   }
2067                   break;
2068                }
2069             }
2070 
2071             findStr = "Track ID (ID): ";
2072             idx = oss.str().find(findStr);
2073             if(idx != std::string::npos) {
2074                //index all primary tracks
2075                std::string tmpstr = oss.str().substr(idx + findStr.size(),1);
2076                std::istringstream buffer(tmpstr);
2077                int num;
2078                buffer >> num;
2079                if(num == 1) {
2080 
2081                   // Check if next character is a number, 
2082                   // in which case we don't have Track ID 1
2083                   // FWJ attempt to fix Coverity issue.
2084                   char nextChar = oss.str().at(idx+findStr.size()+1);
2085                   // const char * nextChar = 
2086                   // oss.str().substr(idx + findStr.size() + 1,1).c_str();
2087                   if(std::isdigit(nextChar))
2088                   // if(std::isdigit(nextChar[0]))
2089                      break; //Not a primary track, continue with next track
2090 
2091                   coords = this->getCoordsNode(path);
2092                   if(coords != NULL){
2093                      coordvec.push_back(coords);
2094                      linevec.push_back((SoLineSet *)path->getTail());
2095                      break; //Found coords node, continue with next track
2096                   }
2097                }
2098                else
2099                   break;  //Not a primary track, continue with next track
2100             }
2101             else{
2102                //Not a Track ID attribute, fall through
2103             }
2104          }
2105 
2106          if(refPathFound)
2107             break;
2108       }
2109 
2110       if(coordvec.empty())
2111          return;    //No track with a Coordinate3 node found
2112 
2113       if(refPathFound){
2114          //set ref path to last traj, coord in the vecs
2115          this->setReferencePath(linevec.back(), coordvec.back());
2116          return;
2117       }
2118       //else
2119 
2120       int longestIdx = 0;
2121       float longestLength = 0.0;
2122       // For all paths
2123       for(unsigned int i=0;i < linevec.size(); ++i){
2124 
2125          //First generate a vector with all the points in this lineset
2126          std::vector<SbVec3f> trajectory;
2127          // For all lines in the i path
2128          for(int j=0; j < linevec[i]->numVertices.getNum(); ++j){
2129             // For all points in line j
2130             for(int k=0; k < linevec[i]->numVertices[j]; ++k){
2131                trajectory.push_back(coordvec[i]->point[k]);
2132             }
2133          }
2134 
2135          // Then calculate the total length
2136          float tmpLength=0.0;
2137          for(unsigned int j=0; j < trajectory.size() - 1; ++j){
2138             tmpLength += (trajectory[j] - trajectory[j + 1]).length();
2139          }
2140 
2141          if(tmpLength > longestLength){
2142             longestIdx = i;
2143             longestLength = tmpLength;
2144          }
2145       }
2146 
2147       // Set the longest path as the reference path
2148       this->setReferencePath(linevec[longestIdx], coordvec[longestIdx]);
2149    }
2150 }
2151 
2152 
2153 SoCoordinate3 * G4OpenInventorXtExaminerViewer::getCoordsNode(SoFullPath *path)
2154 {
2155    SoLineSet *trajectory = (SoLineSet *)path->getTail();
2156    SoSeparator * grpNode = (SoSeparator*)(((SoFullPath*)path)->getNodeFromTail(1));
2157    int nodeIndex = grpNode->findChild(trajectory);
2158    SoNode * tmpNode;
2159 
2160    // We allow only 100 iterations, in case the node isn't found
2161    // (should take only a few iterations)
2162    for(int i = 0; i < 100; ++i){
2163       --nodeIndex;
2164 
2165       tmpNode = grpNode->getChild(nodeIndex);
2166       if(tmpNode->getTypeId() == SoCoordinate3::getClassTypeId()){
2167          //node found
2168          return (SoCoordinate3 *)tmpNode;
2169       }
2170    }
2171    return NULL; //coords node not found
2172 }
2173 
2174 
2175 // Displays scene elements on the right side of listsDialog.
2176 // else: scene graph is searched for Geant4_SoPolyhedron type nodes
2177 void G4OpenInventorXtExaminerViewer::getSceneElements()
2178 {
2179    std::string field, eltName;
2180 
2181    std::map<std::string, int> duplicates;
2182    std::map<std::string, int> sceneElts;
2183    SoSearchAction search;
2184    Geant4_SoPolyhedron *node;
2185    SoGroup *root = (SoGroup *)getSceneManager()->getSceneGraph();
2186 
2187    SoBaseKit::setSearchingChildren(TRUE);
2188 
2189    search.reset();
2190    search.setSearchingAll(TRUE);
2191    search.setInterest(SoSearchAction::ALL);
2192    search.setType(Geant4_SoPolyhedron::getClassTypeId(), 0);
2193    search.apply(root);
2194 
2195    SoPathList &pl = search.getPaths();
2196 
2197 
2198    // First find which names occur more than once so we can append a counter to them
2199    for(int i = 0; i < pl.getLength(); i++) {
2200       SoFullPath *path = (SoFullPath *)pl[i];
2201       node = (Geant4_SoPolyhedron *)path->getTail();
2202       eltName = node->getName();
2203       if(duplicates.count(eltName))
2204          duplicates[eltName]++;
2205       else
2206          duplicates[eltName] = 1;
2207    }
2208 
2209    for(int i = 0; i < pl.getLength(); i++) {
2210       float x,y,z;
2211       std::stringstream ssCount;
2212       SoFullPath *path = (SoFullPath *)pl[i];
2213       node = (Geant4_SoPolyhedron *)path->getTail();
2214       eltName = node->getName();
2215       field = eltName;
2216       if(duplicates[eltName] == 1)
2217          ssCount << "";//duplicates[field]
2218       else {
2219          if(sceneElts.count(eltName))
2220             sceneElts[eltName]++;
2221          else
2222             sceneElts[eltName] = 1;
2223 
2224          ssCount << sceneElts[eltName];
2225          field += "_";
2226       }
2227 
2228       field += ssCount.str();
2229 
2230       SoGetBoundingBoxAction bAction(getViewportRegion());
2231       bAction.apply(path);
2232       SbBox3f bBox = bAction.getBoundingBox();
2233 
2234       SbVec3f centr = bBox.getCenter();
2235       centr.getValue(x,y,z);
2236 
2237       path->ref();
2238       sceneElement el = { field, path, centr, 0.0 };
2239       this->sceneElements.push_back(el);
2240    }
2241 }
2242 
2243 
2244 float G4OpenInventorXtExaminerViewer::sqrlen(const SbVec3f &a)
2245 {
2246    float x,y,z;
2247    a.getValue(x,y,z);
2248    return x*x + y*y + z*z;
2249 }
2250 
2251 
2252 void G4OpenInventorXtExaminerViewer::distanceToTrajectory(const SbVec3f &q,
2253                                                           float &dist,
2254                                                 SbVec3f &closestPoint,
2255                                                           int &index)
2256 {
2257    // a : Previous point on trajectory
2258    // b : Next point on trajectory
2259    // q : the point in space
2260    // dab, daq, dbq: distance between a & b, a & q, b & q
2261    //    
2262    // Theory:  A point p on a line ab is defined as:
2263    //
2264    //         p(t) = a+t⋅(b–a)
2265    //
2266    //       note: All are vectors except the parameter t
2267    //
2268    // When t is between 0 and 1 the point p is situated between a and b on ab.
2269    // The point p is defined in terms of the parameter t, subsequently so does
2270    // the distance from the query point q to the point p. To find the minimum
2271    // of that distance we differentiate it and set equal to zero:
2272    //
2273    //       diff(Norm(p(t)- q)) = 0
2274    //
2275    //     note: diff means taking the derivative with regard to t
2276    //
2277    // The resulting t is given in the code below. The square of the distance
2278    // between p and q is given by:
2279    //
2280    //       d^2 = (Norm(p(t)-q))^2
2281    //
2282    // The expression found is given in the code below (current_dist)
2283    //
2284    // Ref: http://programmizm.sourceforge.net/blog/2012/
2285    //           distance-from-a-point-to-a-polyline
2286    //
2287    //    --PLG
2288 
2289    const size_t count = this->refParticleTrajectory.size();
2290    assert(count>0);
2291 
2292    SbVec3f b = this->refParticleTrajectory[0];
2293    SbVec3f dbq = b - q;
2294    float sqrDist = sqrlen(dbq);
2295    closestPoint = b;
2296    index = 0;
2297    for (size_t i = 1; i < count; ++i) {
2298       const SbVec3f a = b;
2299       const SbVec3f daq = dbq;
2300       b = this->refParticleTrajectory[i];
2301       dbq = b - q;
2302       const SbVec3f dab = a - b;
2303 
2304       float dab_x, dab_y, dab_z;
2305       dab.getValue(dab_x,dab_y,dab_z);
2306       float daq_x, daq_y, daq_z;
2307       daq.getValue(daq_x, daq_y, daq_z);
2308       float dbq_x, dbq_y, dbq_z;
2309       dbq.getValue(dbq_x, dbq_y, dbq_z);
2310 
2311       const float inv_sqrlen = 1./sqrlen(dab);
2312       const float t = (dab_x*daq_x + dab_y*daq_y + dab_z*daq_z)*inv_sqrlen;
2313 
2314       if (t<0.){
2315          // The trajectory point occurs before point a
2316          // Go to the next point
2317          continue;
2318       }
2319       float current_dist;
2320       if (t<=1.){
2321          // The trajectory point occurs between a and b.
2322          // Compute the distance to that point
2323          current_dist = daq_x*daq_x + daq_y*daq_y + daq_z*daq_z
2324             - t*(daq_x*dab_x + daq_y*dab_y + daq_z*dab_z)
2325             + t*t*(dab_x*dab_x + dab_y*dab_y + dab_z*dab_z);
2326       }
2327       else { //t>1.
2328          // The trajectory point occurs after b.
2329          // Get the distance to point b
2330          current_dist = sqrlen(dbq);
2331       }
2332 
2333       if (current_dist < sqrDist){
2334          sqrDist = current_dist;
2335          closestPoint = a + t*(b-a);
2336          index = i;
2337       }
2338    }
2339 
2340    dist = std::sqrt(sqrDist);
2341 }
2342 
2343 
2344 void G4OpenInventorXtExaminerViewer::sortElements()
2345 {
2346    if(this->refParticleTrajectory.empty())
2347       return;
2348 
2349    float * trajLength = new float[this->refParticleTrajectory.size()];
2350    typedef std::map<elementForSorting, sceneElement> sortedMap;
2351    sortedMap sorted;
2352 
2353    // For every point on the reference trajectory, compute
2354    // the total length from the start
2355    SbVec3f prevPoint;
2356    std::vector<SbVec3f>::iterator itRef = this->refParticleTrajectory.begin();
2357    int trajIndex = 0;
2358    prevPoint = *itRef;
2359    trajLength[trajIndex] = 0.0;
2360    ++itRef;
2361    ++trajIndex;
2362    for(; itRef != this->refParticleTrajectory.end(); ++itRef, ++trajIndex){
2363       trajLength[trajIndex] = trajLength[trajIndex-1] + (*itRef - prevPoint).length();
2364       prevPoint = *itRef;
2365    }
2366 
2367    // Compute the smallest distance between the element
2368    // and the reference trajectory (find the closest point),
2369    // then map the element to the trajectory length of that
2370    // point (calculated above)
2371    SoGetBoundingBoxAction bAction(this->getViewportRegion());
2372    SbVec3f elementCoord;
2373    std::vector<sceneElement>::iterator itEl;
2374    int elementIndex;
2375    elementForSorting el;
2376    for(itEl = this->sceneElements.begin(), elementIndex = 0;
2377        itEl != this->sceneElements.end(); ++itEl, ++elementIndex){
2378       bAction.apply(itEl->path);
2379 
2380       // FWJ sceneElement already has a center
2381       elementCoord = itEl->center;
2382       // ... and this sometimes returns an empty box!
2383       //      elementCoord = bAction.getBoundingBox().getCenter();
2384       //      if (bAction.getBoundingBox().isEmpty()) {
2385       //         G4cout << "sortElements: Box is empty!" << G4endl;
2386       //         G4cout << "   element name=" << itEl->name << G4endl;
2387       //      }
2388 
2389       int index;
2390       distanceToTrajectory(elementCoord, el.smallestDistance, el.closestPoint, index);
2391       itEl->closestPointZCoord = el.closestPointZCoord = trajLength[index];
2392       el.distanceToBeamlineStart = (itEl->center - this->refParticleTrajectory[0]).length();
2393 
2394       // This map of the scene elements (or their coordinates rather)
2395       // is automatically sorted by trajectory length (Z coord), then
2396       // by the distance between the element and the point in case the Z coord
2397       // is the same as another element.  This is done by using as a key
2398       // an element structure which implements the operator for weak ordering
2399       sorted.insert(std::make_pair(el,*itEl));
2400    }
2401 
2402    // store the sorted elements into the vector field
2403    this->sceneElements.clear();
2404 
2405    sortedMap::iterator itSorted = sorted.begin();
2406    for(; itSorted != sorted.end(); itSorted++)
2407       this->sceneElements.push_back(itSorted->second);
2408 
2409    this->zcoordSetFlag = true;
2410 
2411 
2412    Widget formTop = XtNameToWidget(this->listsDialog, "FormTop");
2413    Widget formTopRight = XtNameToWidget(formTop, "FormTopRight");
2414 
2415    this->createElementsList(formTopRight);
2416 
2417    delete[] trajLength;
2418 }
2419 
2420 
2421 void G4OpenInventorXtExaminerViewer::createElementsList(Widget formTopRight)
2422 {
2423    if(this->myElementList != NULL)
2424       XtUnmanageChild(this->myElementList);
2425 
2426    int size = this->sceneElements.size();
2427    XmString *elements = (XmString *) XtMalloc(size * sizeof(XmString));
2428 
2429    std::vector<sceneElement>::const_iterator it;
2430    int count = 0;
2431    std::stringstream ss;
2432    for(it=this->sceneElements.begin(); it!=this->sceneElements.end(); ++it) {
2433       ss << it->name;
2434       if(zcoordSetFlag)
2435          ss << " [" << it->closestPointZCoord << "]";
2436       elements[count] = XmStringCreateLocalized((char *)ss.str().c_str());
2437       ++count;
2438       ss.str("");
2439    }
2440 
2441    Arg args[10];
2442    int n;
2443 
2444    // Label Right
2445    n = 0;
2446    Widget labelRight;
2447    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
2448 
2449    labelRight = XmCreateLabelGadget(formTopRight, (char*)"Element [S mm]",
2450                                     args, n);
2451    XtManageChild(labelRight);
2452 
2453    // List Right
2454    n = 0;
2455    XtSetArg(args[n], XmNvisibleItemCount, 7); n++;
2456    XtSetArg(args[n], XmNitemCount, size); n++;
2457    XtSetArg(args[n], XmNitems, elements); n++;
2458    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);  n++;
2459    XtSetArg(args[n], XmNtopWidget, labelRight); n++;
2460    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);  n++;
2461    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2462    // FWJ
2463    XtSetArg(args[n], XmNwidth, 240);  n++;
2464    //   XtSetArg(args[n], XmNwidth, 280); n++;
2465    // XtSetArg(args[n], XmNwidth, 300); n++;
2466 
2467    this->myElementList = XmCreateScrolledList(formTopRight, (char *) "ListRight", args, n);
2468 
2469    XtAddCallback(this->myElementList, XmNbrowseSelectionCallback,
2470                  (XtCallbackProc) lookAtSceneElementCB, this);
2471    xmAddMouseEventHandler(this->myElementList); // Add scrolling functionality
2472    XtManageChild(this->myElementList);
2473 
2474    if (elements != NULL) {
2475       for (int i = 0; i < size; i++)
2476          XmStringFree(elements[i]);
2477       XtFree((char *) elements);
2478    }
2479 }
2480 
2481 
2482 // Pops up a custom dialog listsDialog containing 
2483 // scene elements and viewpoints.
2484 
2485 void G4OpenInventorXtExaminerViewer::constructListsDialog(Widget w,
2486                                              XtPointer client_data,
2487                                              XtPointer)
2488 {
2489    // G4cout << "DEBUG constructListsDialog w = " << w << G4endl;
2490    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
2491    if (This->listsDialog) {
2492       return;
2493    }
2494 
2495    if (This->currentState == ANIMATION || This->currentState == PAUSED_ANIMATION) {
2496       if (This->animateSensor->isScheduled())
2497          This->animateSensor->unschedule();
2498       This->refParticleIdx = This->prevRefIdx;
2499       This->restoreCamera();
2500       This->currentState = This->prevState;
2501    }
2502 
2503    This->step = 1; // Default values
2504    This->refParticleIdx = 0;
2505    if (This->refParticleTrajectory.size()){
2506       This->prevPt = This->refParticleTrajectory[0]; // For calculating distance
2507    }
2508 
2509    This->getSceneElements();
2510 
2511    int n = 0;
2512    Arg args[10];
2513    Atom WM_DELETE_WINDOW;
2514 
2515    ///////////////////////CUSTOM listsDialog///////////////////////////////
2516 
2517    Widget topShell;
2518    // FWJ gets the topmost window containing This->getParentWidget()
2519    // This is unnecessary because the parent is passed in
2520    //   topShell = SoXt::getShellWidget(This->getParentWidget());
2521    topShell = w;
2522    // G4cout << "DEBUG PARENT (topShell) FOR AUX WINDOW = " << topShell << G4endl;
2523 
2524    // Shell Dialog
2525    std::string dialogNameStr = This->fileName.substr(This->fileName.rfind('/') + 1);
2526    const int nDialog = dialogNameStr.size() + 1;
2527    char *dialogName = new char[nDialog];
2528    strncpy(dialogName, dialogNameStr.c_str(), nDialog);
2529 
2530    n = 0;
2531    XtSetArg(args[n], XmNx, 610);  n++;
2532    This->myShellDialog = XmCreateDialogShell(topShell, dialogName, args, n);
2533 
2534    delete[] dialogName;
2535    WM_DELETE_WINDOW = XInternAtom(XtDisplay(w), "WM_DELETE_WINDOW", False);
2536    XmAddWMProtocolCallback(This->myShellDialog, WM_DELETE_WINDOW,
2537                            (XtCallbackProc)closeListsDialogCB, This);
2538 
2539    // Main Pane(listsDialog)
2540    n = 0;
2541    XtSetArg(args[n], XmNsashWidth, 1);  n++;
2542    XtSetArg(args[n], XmNsashHeight, 1); n++;
2543    XtSetArg(args[n], XmNseparatorOn, False);  n++;
2544    // FWJ
2545    This->listsDialog = XmCreatePanedWindow(This->myShellDialog, (char *) "MainPane",
2546                                            args, n);
2547 
2548 
2549    ////////////////////////TOP FORM//////////////////////////
2550    n = 0;
2551    // FWJ fails compile
2552    //   Widget formTop = XmCreateForm(This, (char *) "FormTop", args, n);
2553    Widget formTop = XmCreateForm(This->listsDialog, (char *) "FormTop", args, n);
2554 
2555    n = 0;
2556    XtSetArg(args[n], XmNmarginWidth, 8);  n++;
2557    XtSetArg(args[n], XmNmarginHeight, 8); n++;
2558    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
2559    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);  n++;
2560    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2561    Widget formTopRight = XmCreateForm(formTop, (char *) "FormTopRight", args,
2562                                       n);
2563 
2564    n = 0;
2565    XtSetArg(args[n], XmNmarginWidth, 8);  n++;
2566    XtSetArg(args[n], XmNmarginHeight, 8); n++;
2567    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
2568    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2569    XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET);  n++;
2570    XtSetArg(args[n], XmNrightWidget, formTopRight); n++;
2571    XtSetArg(args[n], XmNrightOffset, 10); n++;
2572    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2573    Widget formTopLeft = XmCreateForm(formTop, (char *) "FormTopLeft", args, n);
2574 
2575    /////TOP RIGHT/////
2576 
2577    This->createElementsList(formTopRight);
2578    XtManageChild(formTopRight);
2579 
2580    /////TOP LEFT/////
2581 
2582    // Label Left
2583    n = 0;
2584    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);  n++;
2585    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2586    Widget labelLeft = XmCreateLabelGadget(formTopLeft, (char *) "ViewPoints",
2587                                           args, n);
2588    XtManageChild(labelLeft);
2589 
2590    // List Left
2591    n = 0;
2592    XtSetArg(args[n], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE);  n++;
2593    XtSetArg(args[n], XmNvisibleItemCount, 7); n++;
2594    // XtSetArg(args[n], XmNwidth, 140); n++;
2595    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);  n++;
2596    XtSetArg(args[n], XmNtopWidget, labelLeft);  n++;
2597    XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET);  n++;
2598    XtSetArg(args[n], XmNrightWidget, This->myElementList);  n++;
2599    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2600    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2601    // FWJ
2602    XtSetArg(args[n], XmNwidth, 160);  n++;
2603    // XtSetArg(args[n], XmNwidth, 200); n++;
2604 
2605    This->myViewPtList = XmCreateScrolledList(formTopLeft, (char *) "ListLeft",
2606                                              args, n);
2607    if (This->viewPtList.size())
2608       This->addViewPoints();
2609    XtAddCallback(This->myViewPtList, XmNbrowseSelectionCallback,
2610                  (XtCallbackProc) loadBookmarkCB, This);
2611    xmAddMouseEventHandler(This->myViewPtList); // Add scrolling functionality
2612 
2613    XtManageChild(This->myViewPtList);
2614 
2615    XtManageChild(formTopLeft);
2616 
2617    XtManageChild(formTop);
2618 
2619    ////////////////////MIDDLE FORM///////////////////////////
2620    n = 0;
2621    XtSetArg(args[n], XmNmarginWidth, 6);  n++;
2622    // FWJ fails compile
2623    //   Widget formMiddle = XmCreateForm(This->canvas, (char *) "MiddleForm", args, n);
2624    Widget formMiddle = XmCreateForm(This->listsDialog, (char *) "MiddleForm", args, n);
2625 
2626    // Label
2627    n = 0;
2628    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2629    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);  n++;
2630    XtSetArg(args[n], XmNtopWidget, This->myViewPtList); n++;
2631    Widget label = XmCreateLabelGadget(formMiddle, (char *) "Selection", args,
2632                                       n);
2633    XtManageChild(label);
2634 
2635    // Text
2636    n = 0;
2637    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2638    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);  n++;
2639    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);  n++;
2640    XtSetArg(args[n], XmNtopWidget, label);  n++;
2641    XtSetArg(args[n], XmNtopOffset, 3);  n++;
2642    XtSetArg(args[n], XmNmaxLength, This->MAX_VP_NAME);  n++;
2643    This->viewPtSelection = XmCreateText(formMiddle, (char *) "Txt", args, n);
2644    XtManageChild(This->viewPtSelection);
2645 
2646    Dimension h1, h2, h;
2647    XtVaGetValues(label, XmNheight, &h1, NULL);
2648    XtVaGetValues(This->viewPtSelection, XmNheight, &h2, NULL);
2649 
2650    h = (Dimension) (1.1 * (h1 + h2));
2651 
2652    XtVaSetValues(formMiddle, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL);
2653    XtManageChild(formMiddle);
2654 
2655    /////////////////////BOTTOM FORM///////////////////////////
2656    // Action Area Form
2657    n = 0;
2658    XtSetArg(args[n], XmNfractionBase, 4); n++;
2659    XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);  n++;
2660    XtSetArg(args[n], XmNtopWidget, This->viewPtSelection);  n++;
2661    // FWJ fails compile
2662    //   Widget formAction = XmCreateForm(This, (char *) "ActionForm", args, n);
2663    Widget formAction = XmCreateForm(This->listsDialog, (char *) "ActionForm", args, n);
2664 
2665    n = 0;
2666    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2667    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);  n++;
2668    XtSetArg(args[n], XmNtopOffset, 3);  n++;
2669    XtSetArg(args[n], XmNbottomOffset, 5); n++;
2670    Widget separator = XmCreateSeparatorGadget(formAction, (char *) "Sep", args, n);
2671 
2672    XtManageChild(separator);
2673 
2674    Widget button = XmCreatePushButton(formAction, (char *) "Delete", NULL, 0);
2675    XtVaSetValues(button, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,
2676                  separator, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment,
2677                  XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment,
2678                  XmATTACH_POSITION, XmNrightPosition, 1,
2679                  XmNdefaultButtonShadowThickness, 2, XmNwidth, 40, XmNheight, 30,
2680                  NULL);
2681 
2682    XtAddCallback(button, XmNactivateCallback,
2683                  (XtCallbackProc) deleteBookmarkCB, This);
2684    XtManageChild(button);
2685 
2686    button = XmCreatePushButton(formAction, (char *) "Rename", NULL, 0);
2687    XtVaSetValues(button, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,
2688                  separator, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment,
2689                  XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,
2690                  XmATTACH_POSITION, XmNrightPosition, 2,
2691                  XmNdefaultButtonShadowThickness, 2, XmNwidth, 40, XmNheight, 30,
2692                  NULL);
2693 
2694    XtAddCallback(button, XmNactivateCallback,
2695                  (XtCallbackProc) renameBookmarkCB, This);
2696    XtManageChild(button);
2697 
2698    button = XmCreatePushButton(formAction, (char *) "Sort", NULL, 0);
2699    XtVaSetValues(button, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,
2700                  separator, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment,
2701                  XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,
2702                  XmATTACH_POSITION, XmNrightPosition, 3,
2703                  XmNdefaultButtonShadowThickness, 2, XmNwidth, 40, XmNheight, 30,
2704                  NULL);
2705 
2706    XtAddCallback(button, XmNactivateCallback, (XtCallbackProc) sortBookmarksCB, This);
2707    XtManageChild(button);
2708 
2709    button = XmCreatePushButton(formAction, (char *) "Close", NULL, 0);
2710    XtVaSetValues(button, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,
2711                  separator, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment,
2712                  XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment,
2713                  XmATTACH_POSITION, XmNrightPosition, 4,
2714                  XmNdefaultButtonShadowThickness, 2, XmNwidth, 40, XmNheight, 30,
2715                  NULL);
2716 
2717    XtAddCallback(button, XmNactivateCallback, (XtCallbackProc) closeListsDialogCB, This);
2718    XtManageChild(button);
2719 
2720    XtManageChild(formAction);
2721    XtVaGetValues(button, XmNheight, &h1, NULL);
2722    XtVaSetValues(formAction, XmNpaneMaximum, h1, XmNpaneMinimum, h1, NULL);
2723 
2724    XtManageChild(This->listsDialog);
2725 
2726    ////////////////////////CUSTOM listsDialog///////////////////////////////
2727 }
2728 
2729 
2730 // Called when user clicks a scene element in listsDialog.
2731 // Zooms onto that element.
2732 void G4OpenInventorXtExaminerViewer::lookAtSceneElementCB(Widget,
2733                                            XtPointer client_data,
2734                                            XtPointer call_data)
2735 {
2736    char *value;
2737    std::string elementField;
2738    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
2739    SoCamera * cam = This->getCamera();
2740 
2741    if (This->SoXtExaminerViewer::isAnimating())
2742       This->stopAnimating();
2743 
2744    XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
2745 
2746    value = (char *) XmStringUnparse(cbs->item, XmFONTLIST_DEFAULT_TAG,
2747                                     XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
2748    if (This->currentState == ANIMATION || This->currentState == REVERSED_ANIMATION
2749        || This->currentState == PAUSED_ANIMATION ) {
2750       if (This->animateSensor->isScheduled())
2751          This->animateSensor->unschedule();
2752       This->setSuperimpositionEnabled(This->superimposition, FALSE);
2753       This->maxSpeed = 0.0f;
2754       This->scheduleRedraw();
2755       This->restoreCamera();
2756       This->currentState = This->prevState;
2757    } else if (This->currentState == VIEWPOINT)
2758       This->setSuperimpositionEnabled(This->superimposition, FALSE);
2759 
2760    elementField = value;
2761 
2762    int idx = elementField.find_last_of("[");
2763    if(idx == -1)
2764       idx = elementField.size(); //if "[" not found for whatever reason (list not sorted)
2765    else
2766       idx--; // To get rid of the space that is between the name and '['
2767 
2768    bool error = false;
2769    SoFullPath *path;
2770    SoSearchAction search;
2771    SoNode *root = This->getSceneManager()->getSceneGraph();
2772    int counter(1), idxUnderscore = elementField.find_last_of("_");
2773 
2774    This->parseString<int>(counter, elementField.substr(idxUnderscore + 1, idx), error);
2775 
2776    SoBaseKit::setSearchingChildren(TRUE);
2777    search.reset();
2778    search.setSearchingAll(TRUE);
2779 
2780    if(error) { // No counter is present => element name was not modified
2781       This->curEltName = elementField.substr(0, idx);
2782       search.setName(This->curEltName.c_str());
2783       search.apply(root);
2784 
2785       path = (SoFullPath *)search.getPath();
2786    }
2787    else {
2788       This->curEltName = elementField.substr(0, idxUnderscore);
2789       search.setInterest(SoSearchAction::ALL);
2790       search.setName(This->curEltName.c_str());
2791       search.apply(root);
2792 
2793       SoPathList &pl = search.getPaths();
2794       path = (SoFullPath *)pl[counter - 1]; // Since counter starts at 1, not 0
2795    }
2796 
2797    G4ThreeVector global;
2798 
2799    if ((idx > 0) && (path)) {
2800 
2801       if(!This->refParticleTrajectory.empty()){
2802 
2803          SoGetBoundingBoxAction bAction(This->getViewportRegion());
2804          bAction.apply(path);
2805          SbBox3f bBox = bAction.getBoundingBox();
2806          SbVec3f elementCoord = bBox.getCenter();
2807 
2808          This->refParticleIdx = 0;
2809          SbVec3f p;
2810 
2811          float absLengthNow, absLengthMin;
2812          int maxIdx = This->refParticleTrajectory.size() - 2;
2813          int targetIdx = 0;
2814          SbVec3f dir;
2815 
2816          p = This->refParticleTrajectory[This->refParticleIdx];
2817          absLengthMin = (p - elementCoord).length();
2818          This->refParticleIdx++;
2819 
2820          // Find a ref. particle's point closest to element's global coords
2821          while (This->refParticleIdx < maxIdx) {
2822             p = This->refParticleTrajectory[This->refParticleIdx];
2823             absLengthNow = (p - elementCoord).length();
2824 
2825             if (absLengthNow < absLengthMin) {
2826                absLengthMin = absLengthNow;
2827                targetIdx = This->refParticleIdx;
2828             }
2829             This->refParticleIdx++;
2830          }
2831 
2832          if (This->currentState != BEAMLINE) { // Set up default zoom
2833             SbVec3f p1, pN;
2834             This->currentState = BEAMLINE;
2835             This->prevParticleDir = SbVec3f(0,0,0); //so that moveCamera() knows sets default parameters
2836             
2837             p1 = This->prevPt = This->refParticleTrajectory[0];
2838             pN = This->refParticleTrajectory[This->refParticleTrajectory.size() - 1];
2839             This->distance = (pN - p1).length() / 10;
2840 
2841             // FWJ Rather than switching to a default height, it is more flexible
2842             // to keep the same height(magnification) while moving the camera.
2843             // if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
2844             //    ((SoOrthographicCamera *) cam)->height.setValue(This->defaultHeight);
2845             // // FWJ Restore the default height instead of hard-wired value
2846             // // ((SoOrthographicCamera *) cam)->height.setValue(10000.0f);
2847             // }
2848             // else if (cam->isOfType(SoPerspectiveCamera::getClassTypeId()))
2849 
2850             // FWJ required to avoid extreme perspective after camera move:
2851             if (cam->isOfType(SoPerspectiveCamera::getClassTypeId()))
2852                ((SoPerspectiveCamera*)cam)->heightAngle.setValue(This->defaultHeightAngle);
2853 
2854          } else {
2855             if (cam->isOfType(SoPerspectiveCamera::getClassTypeId()))
2856                This->distance = (This->prevPt - cam->position.getValue()).length();
2857          }
2858          This->refParticleIdx = targetIdx;
2859 
2860          //////////////////////////////////////////////////////////////
2861          This->setSuperimpositionEnabled(This->superimposition, TRUE);
2862          This->axisSwitch->whichChild.setValue(SO_SWITCH_NONE);
2863          This->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE);
2864          This->animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE);
2865          This->scheduleRedraw();
2866          //////////////////////////////////////////////////////////////
2867 
2868          This->moveCamera(This->distance);
2869          XtFree(value);
2870 
2871       }
2872       
2873       else{
2874          This->offsetFromCenter.setValue(0, 0, 1);
2875          This->distance = 50;// small number since using viewAll() for default zoom
2876          This->upVector.setValue(0, 1, 0);
2877          This->moveCamera(This->distance);
2878          cam->viewAll(path, This->getViewportRegion());
2879       }
2880    }
2881 
2882    XmTextSetString(This->viewPtSelection, NULL);
2883 }
2884 
2885 
2886 // Destroyes listsDialog and resets necessary member fields.
2887 
2888 void G4OpenInventorXtExaminerViewer::closeListsDialogCB(Widget, 
2889                                          XtPointer client_data,
2890                                          XtPointer)
2891 {
2892    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
2893 
2894    This->sceneElements.clear();
2895    This->refParticleTrajectory.clear();
2896 
2897    This->currentState = GENERAL;
2898    XtDestroyWidget(This->myShellDialog);
2899    This->listsDialog = NULL;
2900 }
2901 
2902 // Called when user clicks left arrow button. Loads previous viewpoint.
2903 void G4OpenInventorXtExaminerViewer::prevViewPtCB(Widget, XtPointer client_data,
2904                                                   XtPointer) {
2905    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
2906 
2907    if (This->viewPtIdx == 0)
2908       This->viewPtIdx = This->viewPtList.size() - 1;
2909    else
2910       This->viewPtIdx--;
2911 
2912    This->writeViewPtIdx();
2913    This->setViewPt();
2914 }
2915 
2916 // Called when user clicks right arrow button. Loads next viewpoint.
2917 void G4OpenInventorXtExaminerViewer::nextViewPtCB(Widget, XtPointer client_data,
2918                                                   XtPointer) {
2919    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
2920 
2921    if (This->viewPtIdx >= (int) This->viewPtList.size() - 1)
2922       This->viewPtIdx = 0;
2923    else
2924       This->viewPtIdx++;
2925 
2926    This->writeViewPtIdx();
2927    This->setViewPt();
2928 }
2929 
2930 
2931 // Updates the viewPtIdx in a viewpoint file.
2932 
2933 void G4OpenInventorXtExaminerViewer::writeViewPtIdx()
2934 {
2935    std::string idxStr;
2936    std::stringstream out;
2937    out << viewPtIdx;
2938    idxStr = out.str();
2939    fileOut.seekp(0, std::ios::beg);
2940 
2941    while ((int) idxStr.length() < MAX_VP_IDX) {
2942       idxStr += " ";
2943    }
2944 
2945    fileOut << idxStr << "\n";
2946    fileOut.flush();
2947    fileOut.seekp(0, std::ios::end);
2948 }
2949 
2950 
2951 // Sets the viewpoint based on camera data that viewPtIdx is pointing to.
2952 
2953 void G4OpenInventorXtExaminerViewer::setViewPt()
2954 {
2955    if (currentState == ANIMATION || currentState == REVERSED_ANIMATION
2956        || currentState == ROTATING) {
2957 
2958       if (animateSensor->isScheduled())
2959          animateSensor->unschedule();
2960       setSuperimpositionEnabled(superimposition, FALSE);
2961       maxSpeed = 0.0f;
2962       scheduleRedraw();
2963    }
2964 
2965    SoCamera * camera = getCamera();
2966    if (camera == NULL) {
2967       String dialogName = (char *) "Missing Camera Node";
2968       std::string msg = "Camera is null. Unable to set the viewpoint.";
2969       warningMsgDialog(msg, dialogName, NULL);
2970       return;
2971    }
2972 
2973    if (!viewPtList.size()) {
2974       String dialogName = (char *) "Missing Viewpoints";
2975       std::string msg = "There are no viewpoints to load.";
2976       warningMsgDialog(msg, dialogName, NULL);
2977       return;
2978    }
2979 
2980    if (SoXtExaminerViewer::isAnimating())
2981       stopAnimating();
2982 
2983    if (currentState != VIEWPOINT) {
2984       currentState = VIEWPOINT;
2985       //////////////////////////////////////////////////////////////
2986       setSuperimpositionEnabled(superimposition, TRUE);
2987       axisSwitch->whichChild.setValue(SO_SWITCH_NONE);
2988       animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE);
2989       animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE);
2990 
2991       scheduleRedraw();
2992       ///////////////////////////////////////////////////////////////
2993    }
2994 
2995    curViewPtName = viewPtList[viewPtIdx].viewPtName;
2996    camera->viewportMapping = viewPtList[viewPtIdx].viewportMapping;
2997    camera->position = viewPtList[viewPtIdx].position;
2998    camera->orientation = viewPtList[viewPtIdx].orientation;
2999    camera->aspectRatio = viewPtList[viewPtIdx].aspectRatio;
3000    camera->nearDistance = viewPtList[viewPtIdx].nearDistance;
3001    camera->farDistance = viewPtList[viewPtIdx].farDistance;
3002    camera->focalDistance = viewPtList[viewPtIdx].focalDistance;
3003 
3004    // Restore camera height (changed by zooming)
3005    if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) {
3006       if (viewPtList[viewPtIdx].camType == ORTHOGRAPHIC) {
3007          toggleCameraType();
3008          camera = getCamera();
3009          ((SoOrthographicCamera *) camera)->height.setValue(
3010                                                             viewPtList[viewPtIdx].height);
3011       } else
3012          ((SoPerspectiveCamera *) camera)->heightAngle.setValue(
3013                                                                 viewPtList[viewPtIdx].height);
3014    } else if (camera->isOfType(SoOrthographicCamera::getClassTypeId())) {
3015       if (viewPtList[viewPtIdx].camType == PERSPECTIVE) {
3016          toggleCameraType();
3017          camera = getCamera();
3018          ((SoPerspectiveCamera *) camera)->heightAngle.setValue(
3019                                                                 viewPtList[viewPtIdx].height);
3020       } else
3021          ((SoOrthographicCamera *) camera)->height.setValue(
3022                                                             viewPtList[viewPtIdx].height);
3023    } else {
3024       SoDebugError::post("G4OpenInventorXtExaminerViewer::setViewPt",
3025                          "Only Perspective and Orthographic cameras are supported.");
3026       return;
3027    }
3028 
3029 }
3030 
3031 
3032 // Pops up a prompt asking for a new viewpoint name.
3033 
3034 void G4OpenInventorXtExaminerViewer::saveViewPtCB(Widget w, 
3035                                      XtPointer client_data,
3036                                      XtPointer)
3037 {
3038    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3039 
3040    if (This->fileName.empty()) {
3041       newViewPtFileCB(w, This, NULL);
3042       This->returnToSaveVP = true;
3043       return; // Need to return and call this fn again from newViewPtFileCB since flow of control does not stall here but keeps going
3044    }
3045 
3046    int n = 0;
3047    Arg args[4];
3048    Widget nameViewPtDialog;
3049    Widget parent = This->getParentWidget(); //gets the dialogshell of the ExaminerViewer widget
3050    XmString label = XmStringCreateLocalized((char *) "Name the viewpoint:");
3051 
3052    XtSetArg(args[n], XmNselectionLabelString, label); n++;
3053 // Prevent the dialog from closing automatically, in case the name is wrong
3054    XtSetArg(args[n], XmNautoUnmanage, False); n++;
3055 // FWJ
3056    XtSetArg(args[n], XmNtitle, "Save Bookmark"); n++;
3057    nameViewPtDialog = XmCreatePromptDialog(parent, String("Save Bookmark"),
3058                                            args, n);
3059 
3060    XmStringFree(label);
3061    XtAddCallback(nameViewPtDialog, XmNokCallback, getViewPtNameCB, This);
3062    XtAddCallback(nameViewPtDialog, XmNcancelCallback,
3063                  getViewPtNameCancelCB, This);
3064    // Coverity gcc8 bad cast warning
3065    //            (XtCallbackProc) XtDestroyWidget, NULL);
3066 
3067    Widget text = XtNameToWidget(nameViewPtDialog, "Text");
3068    XtVaSetValues(text, XmNmaxLength, This->MAX_VP_NAME, NULL);
3069    std::string autoName = "";
3070    if (!This->warningFlag) { //leave the TextField as it is if coming back from warning dialog
3071       autoName = This->viewPtAutoName();
3072    }
3073    This->warningFlag = false;
3074    XmTextSetString(text, (char *) autoName.c_str());
3075    XmTextSetInsertionPosition(text, autoName.length());
3076 
3077    XtUnmanageChild(XtNameToWidget(nameViewPtDialog, "Help"));
3078    XtManageChild(nameViewPtDialog);
3079 }
3080 
3081 
3082 std::string G4OpenInventorXtExaminerViewer::viewPtAutoName()
3083 {
3084    std::string viewPt;
3085    std::stringstream sstream;
3086    std::vector<int> existingViewPts;
3087    int tmp;
3088 
3089    //Build the list of names of the form viewpoint_* already present
3090    for (unsigned int i = 0; i < this->viewPtList.size(); ++i) {
3091       viewPt = this->viewPtList[i].viewPtName;
3092       if (viewPt.find("viewpoint_") != std::string::npos) {
3093          tmp = atoi(viewPt.substr(10).c_str());
3094          if (tmp == 0) {
3095             //0 means couldn't convert to integer OR viewpoint_0
3096             if (!viewPt.compare("viewpoint_0"))
3097                existingViewPts.push_back(0);
3098          } else
3099             existingViewPts.push_back(tmp);
3100       }
3101    }
3102 
3103    sstream.str("");
3104    sstream.clear();
3105 
3106    //Return the view viewpoint_* name available
3107    if (existingViewPts.size() > 0) {
3108       int vpNum = 0;
3109       while (true) {
3110          if (std::find(existingViewPts.begin(), existingViewPts.end(), vpNum)
3111              == existingViewPts.end()) {
3112             sstream << "viewpoint_" << vpNum;
3113             return sstream.str();
3114          }
3115          ++vpNum;
3116       }
3117    } else {
3118       return "viewpoint_0";
3119    }
3120    return "";
3121 }
3122 
3123 
3124 void G4OpenInventorXtExaminerViewer::abbrOutputCB(Widget,
3125                                    XtPointer client_data,
3126                                    XtPointer)
3127 {
3128    G4OpenInventorXtExaminerViewer * This =
3129       (G4OpenInventorXtExaminerViewer *) client_data;
3130 // G4cout << "DISARMCALLBACK abbrOutputFlag=" << This->abbrOutputFlag << G4endl;
3131    This->abbrOutputFlag = !(This->abbrOutputFlag);
3132 }
3133 
3134 
3135 void G4OpenInventorXtExaminerViewer::pickRefPathCB(Widget,
3136                                     XtPointer client_data,
3137                                     XtPointer)
3138 {
3139    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3140 
3141    // Save viewing state and go to picking mode
3142    This->viewingBeforePickRef = This->isViewing();
3143    if(This->isViewing())
3144       This->setViewing(false);
3145    This->setComponentCursor(SoXtCursor(SoXtCursor::CROSSHAIR));
3146    This->pickRefPathFlag = true;
3147 }
3148 
3149 
3150 void G4OpenInventorXtExaminerViewer::switchWireFrameCB(Widget w,
3151                                     XtPointer client_data,
3152                                     XtPointer)
3153 {
3154    G4OpenInventorXtExaminerViewer* This = 
3155       (G4OpenInventorXtExaminerViewer*)client_data;
3156    //   xmToggleButton theToggleButton = (xmToggleButton)w;
3157    if (XmToggleButtonGetState(w)) {
3158          This->setDrawStyle(SoXtViewer::STILL, SoXtViewer::VIEW_LINE);
3159          This->setDrawStyle(SoXtViewer::INTERACTIVE, SoXtViewer::VIEW_LINE);
3160       } else {
3161          This->setDrawStyle(SoXtViewer::STILL, SoXtViewer::VIEW_AS_IS);
3162          This->setDrawStyle(SoXtViewer::INTERACTIVE,
3163                             SoXtViewer::VIEW_SAME_AS_STILL);
3164       }
3165 }
3166 
3167 
3168 // Examines new viewpoint name and if OK calls saveViewPt.
3169 
3170 void G4OpenInventorXtExaminerViewer::getViewPtNameCB(Widget w, 
3171                                         XtPointer client_data,
3172                                         XtPointer call_data)
3173 {
3174    char *name = NULL;
3175    std::string strName;
3176    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3177    XmSelectionBoxCallbackStruct *cbs =
3178       (XmSelectionBoxCallbackStruct *) call_data;
3179    XmStringGetLtoR(cbs->value, XmFONTLIST_DEFAULT_TAG, &name);
3180 
3181    if (!name) {
3182       return;
3183    }
3184    if (!*name) {
3185       XtFree(name);
3186       return;
3187    }
3188 
3189    strName = name;
3190    XtFree(name);
3191 
3192    int beg = strName.find_first_not_of(' '); // Remove leading/trailing spaces
3193    int end = strName.find_last_not_of(' ');
3194    strName = strName.substr(beg, end - beg + 1);
3195 
3196    bool nameExists = false;
3197    int size = This->viewPtList.size();
3198    for (int i = 0; i < size; i++) {
3199       if (!strcmp(This->viewPtList[i].viewPtName, strName.c_str())) {
3200          nameExists = true;
3201          break;
3202       }
3203    }
3204 
3205    if (!nameExists) {
3206       const int nVPName = This->MAX_VP_NAME + 1;
3207       name = new char[nVPName];
3208       strncpy(name, strName.c_str(), nVPName);
3209       if (This->viewPtIdx == -1)
3210          This->viewPtIdx = 0;
3211       This->saveViewPt(name);
3212       if (This->listsDialog) {
3213          XmListAddItemUnselected(This->myViewPtList, cbs->value, 0); // vpName
3214       }
3215       //Dismiss the nameViewPtDialog dialog
3216       XtUnmanageChild(w);
3217    } else {
3218       String dialogName = (char *) "Existing Viewpoint";
3219       std::string msg = "The viewpoint already exists.";
3220       This->warningMsgDialog(msg, dialogName, NULL);
3221 
3222    }
3223 }
3224 
3225 void G4OpenInventorXtExaminerViewer::getViewPtNameCancelCB(Widget w,
3226                                         XtPointer,
3227                                         XtPointer)
3228 {
3229    XtUnmanageChild(w);
3230 }   
3231 
3232 
3233 // Saves current camera parameters to a viewpoint file.
3234 
3235 void G4OpenInventorXtExaminerViewer::saveViewPt(char *name)
3236 {
3237    SbVec3f axis;
3238    viewPtData tmp;
3239    float x, y, z, angle;
3240    SoCamera * camera = getCamera();
3241 
3242    if (viewPtList.size() == 0) {
3243       writeViewPtIdx();
3244       XtSetSensitive(nextViewPtButton, True); // Makes arrow buttons clickable
3245       XtSetSensitive(prevViewPtButton, True);
3246    }
3247 
3248    tmp.viewPtName = name;
3249    tmp.viewportMapping = camera->viewportMapping.getValue();
3250    tmp.position = camera->position.getValue();
3251    tmp.orientation = camera->orientation.getValue();
3252    tmp.aspectRatio = camera->aspectRatio.getValue();
3253    tmp.nearDistance = camera->nearDistance.getValue();
3254    tmp.farDistance = camera->farDistance.getValue();
3255    tmp.focalDistance = camera->focalDistance.getValue();
3256 
3257    // Save camera height (changed by zooming)
3258    if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) {
3259       tmp.height = ((SoPerspectiveCamera *) camera)->heightAngle.getValue();
3260       tmp.camType = PERSPECTIVE;
3261    } else if (camera->isOfType(SoOrthographicCamera::getClassTypeId())) {
3262       tmp.height = ((SoOrthographicCamera *) camera)->height.getValue();
3263       tmp.camType = ORTHOGRAPHIC;
3264    } else {
3265       SoDebugError::post("G4OpenInventorXtExaminerViewer::saveViewPtCB",
3266                          "Only Perspective and Orthographic cameras are supported.");
3267       return;
3268    }
3269 
3270    viewPtList.push_back(tmp);
3271 
3272    // Now save the view point to a .txt file
3273    std::string vpName = name;
3274 
3275    while ((int) vpName.size() <= MAX_VP_NAME)
3276       vpName += " ";
3277 
3278    fileOut << vpName << std::endl;
3279    tmp.position.getValue(x, y, z);
3280    fileOut << x << " " << y << " " << z << std::endl;
3281 
3282    // Reusing x, y and z for storing the axis
3283    tmp.orientation.getValue(axis, angle);
3284    axis.getValue(x, y, z);
3285    fileOut << x << " " << y << " " << z << " " << angle << std::endl;
3286 
3287    fileOut << tmp.camType << " " << tmp.height << std::endl;
3288    fileOut << tmp.focalDistance << " ";
3289    fileOut << tmp.nearDistance << " ";
3290    fileOut << tmp.farDistance << std::endl;
3291    fileOut << tmp.viewportMapping << " ";
3292    fileOut << tmp.aspectRatio << "\n" << std::endl;
3293    fileOut.flush();
3294    viewPtIdx++;
3295 }
3296 
3297 
3298 void G4OpenInventorXtExaminerViewer::deleteViewPtCB(Widget,
3299                                      XtPointer client_data,
3300                                      XtPointer)
3301 {
3302    G4OpenInventorXtExaminerViewer * This =
3303       (G4OpenInventorXtExaminerViewer *) client_data;
3304    This->deleteViewPt();
3305 }
3306 
3307 
3308 // Deletes current viewpoint the user is looking at.
3309 // Updates the input file and bookmarks as well.
3310 
3311 void G4OpenInventorXtExaminerViewer::deleteViewPt(char *vpName)
3312 {
3313    std::string line;
3314    int end;
3315    fileIn.open(fileName.c_str());
3316    std::ofstream out("temporaryFile.txt");
3317 
3318    if (!vpName)
3319       vpName = viewPtList[viewPtIdx].viewPtName;
3320 
3321    if (listsDialog) {
3322       XmString vpNameStr = XmStringCreateLocalized(vpName);
3323 
3324       XmListDeleteItem(myViewPtList, vpNameStr);
3325       XmStringFree(vpNameStr);
3326    }
3327 
3328    getline(fileIn, line); // Printing the viewpoint idx
3329    out << line << "\n";
3330 
3331    while (getline(fileIn, line)) {
3332       end = line.find_last_not_of(' ');
3333       line = line.substr(0, end + 1);
3334       if (!strcmp(line.c_str(), vpName)) { // Equal
3335          while (line.size()) {
3336             getline(fileIn, line);
3337          }
3338 
3339          while (getline(fileIn, line))
3340             out << line << "\n";
3341       } else {
3342          while (line.size()) {
3343             out << line << "\n";
3344             getline(fileIn, line);
3345          }
3346          out << "\n";
3347       }
3348    }
3349 
3350    int idx = 0; // Remove viewpoint from the vector
3351    int size = viewPtList.size();
3352    while (idx < size) {
3353       if (!strcmp(viewPtList[idx].viewPtName, vpName)) {
3354          viewPtList.erase(viewPtList.begin() + idx);
3355          break;
3356       }
3357       idx++;
3358    }
3359 
3360    out.close();
3361    fileOut.close();
3362    fileIn.clear();
3363    fileIn.close();
3364 
3365    // FWJ check return status
3366    int istat = remove(fileName.c_str());
3367    if (istat == -1) {
3368       char dialogName[] = "Warning";
3369       warningMsgDialog("Error removing bookmarks file", dialogName,
3370                        NULL);
3371    }
3372    istat = rename("temporaryFile.txt", fileName.c_str());
3373    if (istat == -1) {
3374       char dialogName[] = "Warning";
3375       warningMsgDialog("Error renaming bookmarks file", dialogName,
3376                        NULL);
3377    }
3378    fileOut.open(fileName.c_str(), std::ios::in);
3379    fileOut.seekp(0, std::ios::end);
3380 
3381    if (!viewPtList.size()) { // viewPtList is empty
3382       curViewPtName = (char *) "";
3383       scheduleRedraw();
3384       XtSetSensitive(nextViewPtButton, False);
3385       XtSetSensitive(prevViewPtButton, False);
3386    } else {
3387       if (viewPtIdx >= (int) viewPtList.size())
3388          viewPtIdx--;
3389       writeViewPtIdx();
3390       setViewPt();
3391    }
3392 }
3393 
3394 
3395 // Renames currently selected viewpoint.
3396 
3397 void G4OpenInventorXtExaminerViewer::renameViewPt(char *vpName)
3398 {
3399    int idx = 0, end, pos;
3400    int size = viewPtList.size();
3401    std::string line, newName;
3402    fileIn.open(fileName.c_str());
3403 
3404    newName = vpName;
3405    while ((int) newName.size() < MAX_VP_NAME)
3406       newName += " ";
3407 
3408    getline(fileIn, line);
3409    pos = fileIn.tellg();
3410    while (getline(fileIn, line)) {
3411       end = line.find_last_not_of(' ');
3412       line = line.substr(0, end + 1);
3413       if (!strcmp(line.c_str(), curViewPtName)) {
3414          fileOut.seekp(pos);
3415          fileOut << newName;
3416          fileOut.seekp(0, std::ios::end); // Set the file pointer to the end of the file
3417          break;
3418       }
3419       while (line.size())
3420          getline(fileIn, line);
3421       pos = fileIn.tellg();
3422    }
3423 
3424    fileIn.close();
3425    fileIn.clear();
3426 
3427    while (idx < size) {
3428       if (!strcmp(viewPtList[idx].viewPtName, curViewPtName)) {
3429          strcpy(viewPtList[idx].viewPtName, vpName);
3430          break;
3431       }
3432       idx++;
3433    }
3434 }
3435 
3436 
3437 // Rewrites entire viewpoint file with sorted viewpoints.
3438 
3439 void G4OpenInventorXtExaminerViewer::sortViewPts(std::vector<std::string> sortedViewPts) 
3440 {
3441    SbVec3f axis;
3442    float x, y, z, angle;
3443    int sortIdx = 0, unsortIdx = 0;
3444 
3445    if (fileOut.is_open())
3446       fileOut.close();
3447 
3448    fileOut.open(fileName.c_str()); // Erase current viewpoint file
3449 
3450    writeViewPtIdx();
3451 
3452    int size = sortedViewPts.size();
3453    while (sortIdx < size) {
3454       while (strcmp(sortedViewPts[sortIdx].c_str(),
3455                     viewPtList[unsortIdx].viewPtName))
3456          unsortIdx++;
3457 
3458       std::string vpName = viewPtList[unsortIdx].viewPtName;
3459 
3460       while ((int) vpName.size() < MAX_VP_NAME)
3461          vpName += " ";
3462       fileOut << vpName << std::endl;
3463       viewPtList[unsortIdx].position.getValue(x, y, z);
3464       fileOut << x << " " << y << " " << z << std::endl;
3465 
3466       // Reusing x, y and z for storing the axis
3467       viewPtList[unsortIdx].orientation.getValue(axis, angle);
3468       axis.getValue(x, y, z);
3469       fileOut << x << " " << y << " " << z << " " << angle << std::endl;
3470 
3471       fileOut << viewPtList[unsortIdx].camType << " "
3472               << viewPtList[unsortIdx].height << std::endl;
3473       fileOut << viewPtList[unsortIdx].focalDistance << " ";
3474 
3475       fileOut << viewPtList[unsortIdx].nearDistance << " ";
3476 
3477       fileOut << viewPtList[unsortIdx].farDistance << std::endl;
3478 
3479       fileOut << viewPtList[unsortIdx].viewportMapping << " ";
3480       fileOut << viewPtList[unsortIdx].aspectRatio << "\n" << std::endl;
3481       fileOut.flush();
3482 
3483       unsortIdx = 0;
3484       sortIdx++;
3485    }
3486 }
3487 
3488 
3489 //  Loads view point data from a file into a vector.
3490 
3491 bool G4OpenInventorXtExaminerViewer::loadViewPts() 
3492 {
3493    bool error = false;
3494    viewPtData tmp;
3495    std::string token;
3496    SbVec3f axis;
3497    SbRotation orient;
3498    float x(0.), y(0.), z(0.), angle(0.);
3499 
3500    // Gets the last view point accessed, stored in the first line of the data file.
3501    fileIn >> token;
3502    parseString<int>(viewPtIdx, token, error);
3503    getline(fileIn, token); // Remove "\n"
3504    // Converts data from string type into necessary types
3505    while (getline(fileIn, token)) {
3506 
3507       int end = token.find_last_not_of(' '); // Remove padded spaces
3508       token = token.substr(0, end + 1);
3509 
3510       char *vpName = new char[token.size() + 1];
3511       strcpy(vpName, token.c_str());
3512       tmp.viewPtName = vpName;
3513       fileIn >> token;
3514 
3515       parseString<float>(x, token, error);
3516       fileIn >> token;
3517       parseString<float>(y, token, error);
3518       fileIn >> token;
3519       parseString<float>(z, token, error);
3520       fileIn >> token;
3521       tmp.position = axis.setValue(x, y, z);
3522 
3523       parseString<float>(x, token, error);
3524       fileIn >> token;
3525       parseString<float>(y, token, error);
3526       fileIn >> token;
3527       parseString<float>(z, token, error);
3528       fileIn >> token;
3529       parseString<float>(angle, token, error);
3530       fileIn >> token;
3531       orient.setValue(axis.setValue(x, y, z), angle);
3532       tmp.orientation = orient.getValue();
3533 
3534       int camType(0);
3535       parseString<int>(camType, token, error);
3536       fileIn >> token;
3537       tmp.camType = (CameraType) camType;
3538 
3539       parseString<float>(tmp.height, token, error);
3540       fileIn >> token;
3541       parseString<float>(tmp.focalDistance, token, error);
3542       fileIn >> token;
3543       parseString<float>(tmp.nearDistance, token, error);
3544       fileIn >> token;
3545       parseString<float>(tmp.farDistance, token, error);
3546       fileIn >> token;
3547       parseString<int>(tmp.viewportMapping, token, error);
3548       fileIn >> token;
3549       parseString<float>(tmp.aspectRatio, token, error);
3550 
3551       getline(fileIn, token); // To remove "\n" characters
3552       getline(fileIn, token);
3553 
3554       if (error) {
3555          viewPtIdx = 0;
3556          viewPtList.clear();
3557          return false;
3558       }
3559       viewPtList.push_back(tmp);
3560    }
3561 
3562    return true;
3563 }
3564 
3565 
3566 // Converts a string type word into a float type.
3567 
3568 template<class T> 
3569 void G4OpenInventorXtExaminerViewer::parseString(T &t, const std::string &s,
3570                                                  bool &error) 
3571 {
3572    std::istringstream str(s);
3573    if ((str >> t).fail())
3574       error = true;
3575 }
3576 
3577 
3578 // Generic fileSelectionDialog creation.
3579 
3580 void G4OpenInventorXtExaminerViewer::popUpFileSelDialog(Widget &dialog,
3581                                                 std::string dialogName,
3582                                                 std::string buttonLabel,
3583                                                 XtCallbackProc cbOK)
3584 {
3585    int n;
3586    Arg args[3];
3587    Widget parent, scrollWidget;
3588    parent = SoXt::getShellWidget(getParentWidget());
3589 
3590    if (dialog == NULL) {
3591 
3592       // Change the 'OK' button to whatever buttonLabel contains
3593       XmString str = XmStringCreateLocalized((char *) buttonLabel.c_str());
3594 
3595       n = 0;
3596       XtSetArg(args[n], XmNokLabelString, str);   n++;
3597       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE);    n++;
3598 
3599       dialog = XmCreateFileSelectionDialog(parent,
3600                                            (char *) dialogName.c_str(), args, n);
3601 
3602       XtAddCallback(dialog, XmNokCallback, cbOK, this);
3603       XtAddCallback(dialog, XmNcancelCallback, cancelFileSelDialogCB, this);
3604 
3605       // Adding scrolling functionality to the widget
3606       scrollWidget = XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST);
3607       if (scrollWidget)
3608          xmAddMouseEventHandler(scrollWidget);
3609       scrollWidget = XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST);
3610       if (scrollWidget)
3611          xmAddMouseEventHandler(scrollWidget);
3612 
3613       XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
3614       XmStringFree(str);
3615    }
3616    XtManageChild(dialog);
3617 }
3618 
3619 
3620 // Generic fileSelectionDialog cancelation.
3621 
3622 void G4OpenInventorXtExaminerViewer::cancelFileSelDialogCB(Widget w,
3623                                                            XtPointer,
3624                                                            XtPointer)
3625 {
3626    XtUnmanageChild(w);
3627 }
3628 
3629 
3630 // Displays a file selection dialog that allows to open a new viewpoint file.
3631 
3632 void G4OpenInventorXtExaminerViewer::openViewPtFileCB(Widget,
3633                                        XtPointer client_data,
3634                                        XtPointer)
3635 {
3636    G4OpenInventorXtExaminerViewer * This =
3637       (G4OpenInventorXtExaminerViewer *) client_data;
3638    This->popUpFileSelDialog(This->openFileDialog, "Open File", "Load",
3639                             viewPtFileSelectedCB);
3640 }
3641 
3642 
3643 void G4OpenInventorXtExaminerViewer::viewPtFileSelectedCB(Widget w, 
3644                                              XtPointer client_data,
3645                                              XtPointer call_data)
3646 {
3647    char *file = NULL;
3648    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3649    XmFileSelectionBoxCallbackStruct *cbs =
3650       (XmFileSelectionBoxCallbackStruct *) call_data;
3651 
3652    // Get the file
3653    if (cbs) {
3654       if (!(file = (char *) XmStringUnparse(cbs->value,
3655                                             XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0,
3656                                             XmOUTPUT_ALL))) {
3657          SoDebugError::post("G4OpenInventorXtExaminerViewer::fileSelectedCB",
3658                             "Internal error during file opening");
3659          return;
3660       }
3661 
3662       This->fileIn.open(file);
3663       if (!This->fileIn.fail()) {
3664          // Opens a file without erasing it
3665          This->cleanUpAfterPrevFile();
3666          if (!This->loadViewPts()) {
3667             String dialogName = (char *) "Error Loading File";
3668             std::string msg = "Wrong or corrupted input file.";
3669             This->warningMsgDialog(msg, dialogName, NULL);
3670          } else {
3671             This->fileName = file;
3672             This->fileOut.open(This->fileName.c_str(), std::ios::in);
3673             This->fileOut.seekp(0, std::ios::end);
3674 
3675             if (!This->listsDialog)
3676                constructListsDialog(w, This, NULL); // Pop up listsDialog
3677             else
3678                This->addViewPoints();
3679 
3680             std::string newDialogName = This->fileName.substr(
3681                                                               This->fileName.rfind('/') + 1);
3682             XtVaSetValues(This->myShellDialog, XmNtitle,
3683                           (char *) newDialogName.c_str(), NULL);
3684 
3685             if (This->viewPtList.size()) {
3686                This->setViewPt();
3687                XmTextSetString(This->viewPtSelection, NULL);
3688                XtSetSensitive(This->nextViewPtButton, True);
3689                XtSetSensitive(This->prevViewPtButton, True);
3690             } else {
3691                XtSetSensitive(This->nextViewPtButton, False);
3692                XtSetSensitive(This->prevViewPtButton, False);
3693             }
3694 
3695             XtUnmanageChild(w);
3696          }
3697 
3698          This->fileIn.close();
3699       } else {
3700          String dialogName = (char *) "Nonexistent File";
3701          std::string msg = "Unable to open file.";
3702          This->warningMsgDialog(msg, dialogName, NULL);
3703       }
3704    }
3705 
3706    This->fileIn.clear();
3707    XtFree(file);
3708 }
3709 
3710 
3711 // Adds bookmarks to listsDialog.
3712 
3713 void G4OpenInventorXtExaminerViewer::addViewPoints()
3714 {
3715    int size = viewPtList.size();
3716    if (!size)
3717       return;
3718 
3719    XmString *viewPts;
3720 
3721    viewPts = (XmString *) XtMalloc(size * sizeof(XmString));
3722    for (int i = 0; i < size; i++)
3723       viewPts[i] = XmStringCreateLocalized(viewPtList[i].viewPtName);
3724 
3725    XmListAddItemsUnselected(myViewPtList, viewPts, size, 1);
3726 
3727    if (viewPts != NULL) {
3728       for (int i = 0; i < size; i++)
3729          XmStringFree(viewPts[i]);
3730       XtFree((char *) viewPts);
3731    }
3732 }
3733 
3734 
3735 // Called before loading a new viewpoint file. 
3736 // Resets member fields to default values.
3737 
3738 void G4OpenInventorXtExaminerViewer::cleanUpAfterPrevFile()
3739 {
3740    viewPtIdx = -1;
3741    viewPtList.clear();
3742    setSuperimpositionEnabled(superimposition, FALSE);
3743    scheduleRedraw();
3744    currentState = GENERAL;
3745    if (fileOut.is_open())
3746       fileOut.close();
3747    if (listsDialog) // Clear viewpoints
3748       XmListDeleteAllItems(myViewPtList);
3749 }
3750 
3751 
3752 // Generic function for displaying a warning dialog.
3753 
3754 void G4OpenInventorXtExaminerViewer::warningMsgDialog(std::string msg,
3755                                                       String dialogName,
3756                                                       XtCallbackProc cb)
3757 {
3758    Arg args[5];
3759    unsigned int n;
3760    XmString warningMsg;
3761 
3762    warningMsg = XmStringCreateLocalized((char *)msg.c_str());
3763 
3764    n = 0;
3765    XtSetArg(args[n], XmNmessageString, warningMsg); n++;
3766    Widget warningDialog = XmCreateWarningDialog(getParentWidget(), dialogName, args, n);
3767    if (cb)
3768       XtAddCallback(warningDialog, XmNokCallback, cb, this);
3769 
3770    XmStringFree(warningMsg);
3771 
3772    XtVaSetValues (warningDialog, XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, NULL);
3773    XtUnmanageChild(XtNameToWidget(warningDialog, "Help"));
3774    XtUnmanageChild(XtNameToWidget(warningDialog, "Cancel"));
3775 
3776    XtManageChild(warningDialog);
3777 }
3778 
3779 
3780 void G4OpenInventorXtExaminerViewer::newViewPtFileCB(Widget,
3781                                                      XtPointer client_data,
3782                                                      XtPointer)
3783 {
3784    G4OpenInventorXtExaminerViewer * This = 
3785       (G4OpenInventorXtExaminerViewer *) client_data;
3786    This->popUpFileSelDialog(This->newFileDialog, "New File", "Save",
3787                             createNewVPFileCB);
3788 }
3789 
3790 
3791 void G4OpenInventorXtExaminerViewer::createNewVPFileCB(Widget w, 
3792                                                        XtPointer client_data,
3793                                                        XtPointer call_data)
3794 {
3795    char *file;
3796    std::string fName;
3797    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3798    XmFileSelectionBoxCallbackStruct *cbs =
3799       (XmFileSelectionBoxCallbackStruct *) call_data;
3800 
3801    // Get the file
3802    if (cbs) {
3803       if (!(file = (char *) XmStringUnparse(cbs->value,
3804                                             XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0,
3805                                             XmOUTPUT_ALL))) {
3806          SoDebugError::post("G4OpenInventorXtExaminerViewer::createNewVPFileCB",
3807                             "Internal error during file opening");
3808          return;
3809       }
3810 
3811       This->fileName = file;
3812       fName = This->fileName.substr(This->fileName.rfind('/') + 1); // Extracts just the name of the file
3813       This->fileIn.open(file);
3814       if (This->fileIn.fail()) { // Filename does not exist
3815          This->cleanUpAfterPrevFile();
3816          This->fileOut.open(file); // Creates a new empty file
3817          XtSetSensitive(This->nextViewPtButton, False);
3818          XtSetSensitive(This->prevViewPtButton, False);
3819          if (This->listsDialog)
3820             closeListsDialogCB(w, This, NULL);
3821          constructListsDialog(w, This, NULL);
3822          XtUnmanageChild(w);
3823          if (This->returnToSaveVP) {
3824             This->returnToSaveVP = false;
3825             saveViewPtCB(NULL, This, NULL);
3826          }
3827       } else { // Filename already exists
3828          String dialogName = (char *) "Existing File";
3829          std::string msg = "'" + fName + "' already exists. Do you want to overwrite it?";
3830          This->warningMsgDialog(msg, dialogName, overwriteFileCB);
3831          This->fileIn.close();
3832       }
3833       This->fileIn.clear();
3834       XtFree(file);
3835    }
3836 }
3837 
3838 
3839 void G4OpenInventorXtExaminerViewer::overwriteFileCB(Widget, 
3840                                                      XtPointer client_data,
3841                                                      XtPointer)
3842 {
3843    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3844    This->cleanUpAfterPrevFile();
3845    XtSetSensitive(This->nextViewPtButton, False);
3846    XtSetSensitive(This->prevViewPtButton, False);
3847 
3848    XtUnmanageChild(This->newFileDialog);
3849 
3850    This->fileOut.open(This->fileName.c_str());
3851 
3852    if (This->returnToSaveVP) {
3853       This->returnToSaveVP = false;
3854       saveViewPtCB(NULL, This, NULL);
3855    }
3856 }
3857 
3858 
3859 void G4OpenInventorXtExaminerViewer::loadRefCoordsDialogCB(Widget,
3860                                             XtPointer client_data,
3861                                             XtPointer)
3862 {
3863    G4OpenInventorXtExaminerViewer * This = 
3864       (G4OpenInventorXtExaminerViewer *)client_data;
3865    This->popUpFileSelDialog(This->loadRefCoordsDialog, "Load Ref Coords",
3866                             "Load", loadRefCoordsCB);
3867 }
3868 
3869 
3870 void G4OpenInventorXtExaminerViewer::loadRefCoordsCB(Widget w, 
3871                                                      XtPointer client_data,
3872                                                      XtPointer call_data)
3873 {
3874    char *file = NULL;
3875    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *)client_data;
3876    XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)call_data;
3877 
3878    // Get the file
3879    if(cbs) {
3880 
3881       file = (char *)XmStringUnparse(cbs->value, XmFONTLIST_DEFAULT_TAG,
3882                                      XmCHARSET_TEXT, XmCHARSET_TEXT,
3883                                      NULL, 0, XmOUTPUT_ALL);
3884 
3885       std::ifstream ifs(file);
3886       if(ifs.is_open()){
3887          This->refParticleTrajectory.clear();
3888          float x,y,z;
3889          while(ifs >> x >> y >> z){
3890             This->refParticleTrajectory.push_back(SbVec3f(x,y,z));
3891          }
3892          ifs.close();
3893          XtUnmanageChild(w);
3894       }
3895       else{
3896          String dialogName = (char *) "Problem reading file";
3897          std::string msg = "Problem reading file";
3898          This->warningMsgDialog(msg, dialogName, NULL);
3899          return;
3900 
3901       }
3902    }
3903 
3904    return;
3905 }
3906 
3907 
3908 void G4OpenInventorXtExaminerViewer::saveRefCoordsDialogCB(Widget,
3909                                             XtPointer client_data,
3910                                             XtPointer)
3911 {
3912    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3913 
3914    if (!This->refParticleTrajectory.size()) {
3915       String dialogName = (char *) "No Reference Trajectory";
3916       std::string msg = "You need to start a run or load a reference trajectory from a file";
3917       This->warningMsgDialog(msg, dialogName, NULL);
3918       return;
3919    }
3920 
3921    int n;
3922    Arg args[3];
3923    Widget parent, scrollWidget;
3924    parent = SoXt::getShellWidget(This->getParentWidget());
3925 
3926    if (This->saveRefCoordsDialog == NULL) {
3927 
3928       // Change the 'OK' button to whatever buttonLabel contains
3929       XmString str = XmStringCreateLocalized((char *)"Save");
3930 
3931       n = 0;
3932       XtSetArg(args[n], XmNokLabelString, str);   n++;
3933       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE);    n++;
3934 
3935       This->saveRefCoordsDialog = XmCreateFileSelectionDialog(parent,(char *)"Save Ref Coords", args, n);
3936 
3937       XtAddCallback(This->saveRefCoordsDialog, XmNokCallback, saveRefCoordsCB, This);
3938       XtAddCallback(This->saveRefCoordsDialog, XmNcancelCallback, cancelFileSelDialogCB, This);
3939 
3940       // Adding scrolling functionality to the widget
3941       scrollWidget = XmFileSelectionBoxGetChild(This->saveRefCoordsDialog, XmDIALOG_DIR_LIST);
3942       if (scrollWidget)
3943          xmAddMouseEventHandler(scrollWidget);
3944       scrollWidget = XmFileSelectionBoxGetChild(This->saveRefCoordsDialog, XmDIALOG_LIST);
3945       if (scrollWidget)
3946          xmAddMouseEventHandler(scrollWidget);
3947 
3948       XtUnmanageChild(XmSelectionBoxGetChild(This->saveRefCoordsDialog, XmDIALOG_HELP_BUTTON));
3949       XmStringFree(str);
3950    }
3951 
3952    //TODO: Auto name?
3953 
3954    XtManageChild(This->saveRefCoordsDialog);
3955 
3956 }
3957 
3958 
3959 void G4OpenInventorXtExaminerViewer::saveRefCoordsCB(Widget w, 
3960                                                      XtPointer client_data,
3961                                                      XtPointer call_data)
3962 {
3963    char *file;
3964    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
3965    XmFileSelectionBoxCallbackStruct *cbs =
3966       (XmFileSelectionBoxCallbackStruct *) call_data;
3967 
3968    // Get the file
3969    if (cbs) {
3970 
3971       file = (char *)XmStringUnparse(cbs->value, XmFONTLIST_DEFAULT_TAG,
3972                                      XmCHARSET_TEXT, XmCHARSET_TEXT,
3973                                      NULL, 0, XmOUTPUT_ALL);
3974 
3975       std::ifstream ifile(file);
3976       if (ifile) {
3977          //File already exists
3978 
3979          Arg args[4];
3980          Widget parent = This->getParentWidget(); //gets the dialogshell of the ExaminerViewer widget
3981          Widget confirmOverwriteDialog;
3982          XmString msg;
3983 
3984          confirmOverwriteDialog = XmCreateQuestionDialog (parent, (char *)"Confirm overwrite", args, 0);
3985          msg = XmStringCreateLocalized ((char *)"File exists. Overwrite?");
3986          XtVaSetValues (confirmOverwriteDialog, XmNmessageString, msg, NULL);
3987 
3988          // If users presses OK, we want to return to this function and
3989          // save the file.  For that to work, pass it the current widget
3990          // to be able to grab the filename.
3991          XtVaSetValues (confirmOverwriteDialog, XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, NULL);
3992          XtAddCallback (confirmOverwriteDialog, XmNokCallback, saveRefCoordsOverWriteCB, client_data);
3993          XtAddCallback (confirmOverwriteDialog, XmNcancelCallback, saveRefCoordsOverWriteCB, client_data);
3994 
3995          XmStringFree (msg);
3996 
3997          //The confirmOverwriteDialog will need this
3998          This->saveRefCoordsFileName = file;
3999          This->saveRefCoordsWidget = w;
4000 
4001          XtUnmanageChild(XtNameToWidget(confirmOverwriteDialog, "Help"));
4002          XtManageChild(confirmOverwriteDialog);
4003 
4004          return;
4005       }
4006       else{
4007 
4008          std::ofstream ofs(file);
4009          if(ofs.is_open()){
4010             float x,y,z;
4011             for(unsigned int i=0; i < This->refParticleTrajectory.size(); ++i){
4012                This->refParticleTrajectory[i].getValue(x,y,z);
4013                ofs << x << " " << y << " " << z << "\n";
4014             }
4015             ofs.close();
4016             XtUnmanageChild(w);
4017          }
4018          else{
4019             String dialogName = (char *) "Error opening file";
4020             std::string msg = "There was a problem trying to open the file '";
4021             msg += This->saveRefCoordsFileName;
4022             msg += "'";
4023 
4024             This->warningMsgDialog(msg, dialogName, NULL);
4025          }
4026       }
4027    }
4028 
4029    return;
4030 }
4031 
4032 
4033 void G4OpenInventorXtExaminerViewer::saveRefCoordsOverWriteCB(Widget w, 
4034                                                  XtPointer client_data,
4035                                                  XtPointer call_data)
4036 {
4037    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data;
4038    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4039 
4040    switch (cbs->reason) {
4041    case XmCR_OK:
4042       {
4043          // Overwrite confirmed, save file and dismiss both
4044          // dialogs (file dialog and overwrite confirmation dialog)
4045          std::ofstream ofs(This->saveRefCoordsFileName.c_str());
4046          if(ofs.is_open()){
4047             float x,y,z;
4048             for(unsigned int i=0; i < This->refParticleTrajectory.size(); ++i){
4049                This->refParticleTrajectory[i].getValue(x,y,z);
4050                ofs << x << " " << y << " " << z << "\n";
4051             }
4052             ofs.close();
4053             XtUnmanageChild(w);
4054             XtUnmanageChild(This->saveRefCoordsWidget);
4055          }
4056          else{
4057             String dialogName = (char *) "Error opening file";
4058             std::string msg = "There was a problem trying to open the file '";
4059             msg += This->saveRefCoordsFileName;
4060             msg += "'";
4061 
4062             This->warningMsgDialog(msg, dialogName, NULL);
4063          }
4064          break;
4065       }
4066    case XmCR_CANCEL:
4067       {
4068          // Overwrite refused, dismiss overwrite confirmation
4069          // dialog and return to file dialog
4070 
4071          // Give focus to the text field instead of the OK button
4072          XmProcessTraversal(XtNameToWidget(This->saveRefCoordsWidget, "Text"), XmTRAVERSE_CURRENT);
4073 
4074          XtUnmanageChild(w);
4075          This->saveRefCoordsFileName.clear();
4076          This->saveRefCoordsWidget = NULL;
4077          break;
4078       }
4079    default:
4080       return;
4081    }
4082 }
4083 
4084 
4085 void G4OpenInventorXtExaminerViewer::loadSceneGraphDialogCB(Widget,
4086                                              XtPointer client_data,
4087                                              XtPointer)
4088 {
4089    G4OpenInventorXtExaminerViewer * This =
4090       (G4OpenInventorXtExaminerViewer *)client_data;
4091    This->popUpFileSelDialog(This->loadSceneGraphDialog, "Load Scene Graph",
4092                             "Load", loadSceneGraphCB);
4093    return;
4094 }
4095 
4096 
4097 void G4OpenInventorXtExaminerViewer::loadSceneGraphCB(Widget w, 
4098                                                       XtPointer client_data,
4099                                                       XtPointer call_data)
4100 {
4101    char *file = NULL;
4102    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *)client_data;
4103    XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)call_data;
4104 
4105    if(cbs) {
4106 
4107       file = (char *)XmStringUnparse(cbs->value, XmFONTLIST_DEFAULT_TAG,
4108                                      XmCHARSET_TEXT, XmCHARSET_TEXT,
4109                                      NULL, 0, XmOUTPUT_ALL);
4110 
4111       SoInput sceneInput;
4112       if (!sceneInput.openFile(file)) {
4113          String dialogName = (char *) "Problem opening file";
4114          std::string msg = "Cannot open file ";
4115          msg += file;
4116          This->warningMsgDialog(msg, dialogName, NULL);
4117 
4118          sceneInput.closeFile();
4119          XtUnmanageChild(w);
4120       }
4121       // Read the whole file into the database
4122       This->newSceneGraph = SoDB::readAll(&sceneInput);
4123       if (This->newSceneGraph == NULL) {
4124          String dialogName = (char *) "Problem reading file";
4125          std::string msg = "Problem reading file";
4126          This->warningMsgDialog(msg, dialogName, NULL);
4127          return;
4128       }
4129 
4130       //This->newSceneGraph->ref();
4131       This->setSceneGraph(This->newSceneGraph);
4132    }
4133 
4134    return;
4135 }
4136 
4137 
4138 void G4OpenInventorXtExaminerViewer::saveSceneGraphDialogCB(Widget, 
4139                                              XtPointer client_data,
4140                                              XtPointer)
4141 {
4142    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4143 
4144    int n;
4145    Arg args[3];
4146    Widget parent, scrollWidget;
4147    parent = SoXt::getShellWidget(This->getParentWidget());
4148 
4149    if (This->saveSceneGraphDialog == NULL) {
4150 
4151       // Change the 'OK' button to whatever buttonLabel contains
4152       XmString str = XmStringCreateLocalized((char *)"Save");
4153 
4154       n = 0;
4155       XtSetArg(args[n], XmNokLabelString, str);   n++;
4156       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE);    n++;
4157 
4158       This->saveSceneGraphDialog = XmCreateFileSelectionDialog(parent,(char *)"Save Scene Graph", args, n);
4159 
4160       XtAddCallback(This->saveSceneGraphDialog, XmNokCallback, saveSceneGraphCB, This);
4161       XtAddCallback(This->saveSceneGraphDialog, XmNcancelCallback, cancelFileSelDialogCB, This);
4162 
4163       // Adding scrolling functionality to the widget
4164       scrollWidget = XmFileSelectionBoxGetChild(This->saveSceneGraphDialog, XmDIALOG_DIR_LIST);
4165       if (scrollWidget)
4166          xmAddMouseEventHandler(scrollWidget);
4167       scrollWidget = XmFileSelectionBoxGetChild(This->saveSceneGraphDialog, XmDIALOG_LIST);
4168       if (scrollWidget)
4169          xmAddMouseEventHandler(scrollWidget);
4170 
4171       XtUnmanageChild(XmSelectionBoxGetChild(This->saveSceneGraphDialog, XmDIALOG_HELP_BUTTON));
4172       XmStringFree(str);
4173    }
4174 
4175    //TODO: Auto name?
4176 
4177    XtManageChild(This->saveSceneGraphDialog);
4178 
4179 }
4180 
4181 
4182 
4183 void G4OpenInventorXtExaminerViewer::saveSceneGraphCB(Widget w, 
4184                                                       XtPointer client_data,
4185                                                       XtPointer call_data)
4186 {
4187    char *file;
4188    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4189    XmFileSelectionBoxCallbackStruct *cbs =
4190       (XmFileSelectionBoxCallbackStruct *) call_data;
4191 
4192    if (cbs) {
4193 
4194       file = (char *)XmStringUnparse(cbs->value, XmFONTLIST_DEFAULT_TAG,
4195                                      XmCHARSET_TEXT, XmCHARSET_TEXT,
4196                                      NULL, 0, XmOUTPUT_ALL);
4197 
4198       std::ifstream ifile(file);
4199       if (ifile) {
4200          //File already exists
4201 
4202          Arg args[4];
4203          Widget parent = This->getParentWidget(); //gets the dialogshell of the ExaminerViewer widget
4204          Widget confirmOverwriteDialog;
4205          XmString msg;
4206 
4207          confirmOverwriteDialog = XmCreateQuestionDialog (parent, (char *)"Confirm overwrite", args, 0);
4208          msg = XmStringCreateLocalized ((char *)"File exists. Overwrite?");
4209          XtVaSetValues (confirmOverwriteDialog, XmNmessageString, msg, NULL);
4210 
4211          // If users presses OK, we want to return to this function and
4212          // save the file.  For that to work, pass it the current widget
4213          // to be able to grab the filename.
4214          XtVaSetValues (confirmOverwriteDialog, XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, NULL);
4215          XtAddCallback (confirmOverwriteDialog, XmNokCallback, saveSceneGraphOverWriteCB, client_data);
4216          XtAddCallback (confirmOverwriteDialog, XmNcancelCallback, saveSceneGraphOverWriteCB, client_data);
4217 
4218          XmStringFree (msg);
4219 
4220          //The confirmOverwriteDialog will need this
4221          This->saveScenegraphFileName = file;
4222          This->saveScenegraphWidget = w;
4223 
4224          XtUnmanageChild(XtNameToWidget(confirmOverwriteDialog, "Help"));
4225          XtManageChild(confirmOverwriteDialog);
4226 
4227          return;
4228       }
4229       else{
4230 
4231          SoWriteAction writeAction;
4232          SoSeparator *root = (SoSeparator *) (This->getSceneGraph());
4233 
4234          SoOutput * out = writeAction.getOutput();
4235 
4236          if(out->openFile(file)){
4237             out->setBinary(FALSE);
4238             writeAction.apply(root);
4239             out->closeFile();
4240 
4241             XtUnmanageChild(w);
4242          }
4243          else{
4244             String dialogName = (char *) "Error opening file";
4245             std::string msg = "There was a problem trying to open the file '";
4246             msg += This->saveScenegraphFileName;
4247             msg += "'";
4248 
4249             This->warningMsgDialog(msg, dialogName, NULL);
4250          }
4251 
4252       }
4253    }
4254 
4255    return;
4256 }
4257 
4258 
4259 
4260 void G4OpenInventorXtExaminerViewer::saveSceneGraphOverWriteCB(Widget w, 
4261                                                   XtPointer client_data,
4262                                                   XtPointer call_data)
4263 {
4264    XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *) call_data;
4265    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4266 
4267    switch (cbs->reason) {
4268    case XmCR_OK:
4269       {
4270          // Overwrite confirmed, save file and dismiss both
4271          // dialogs (file dialog and overwrite confirmation dialog)
4272          SoWriteAction writeAction;
4273          SoSeparator *root = (SoSeparator *) (This->getSceneGraph());
4274 
4275          SoOutput * out = writeAction.getOutput();
4276          if(out->openFile(This->saveScenegraphFileName.c_str())){
4277             out->setBinary(FALSE);
4278             writeAction.apply(root);
4279             out->closeFile();
4280 
4281             XtUnmanageChild(w);
4282             XtUnmanageChild(This->saveScenegraphWidget);
4283             This->saveScenegraphFileName.clear();
4284             This->saveScenegraphWidget = NULL;
4285          }
4286          else{
4287             String dialogName = (char *) "Error opening file";
4288             std::string msg = "There was a problem trying to open the file '";
4289             msg += This->saveScenegraphFileName;
4290             msg += "'";
4291 
4292             This->warningMsgDialog(msg, dialogName, NULL);
4293             This->saveScenegraphFileName.clear();
4294             This->saveScenegraphWidget = NULL;
4295          }
4296          break;
4297       }
4298    case XmCR_CANCEL:
4299       {
4300          // Overwrite refused, dismiss overwrite confirmation
4301          // dialog and return to file dialog
4302 
4303          // Give focus to the text field instead of the OK button
4304          XmProcessTraversal(XtNameToWidget(This->saveScenegraphWidget, "Text"), XmTRAVERSE_CURRENT);
4305 
4306          XtUnmanageChild(w);
4307          This->saveScenegraphFileName.clear();
4308          This->saveScenegraphWidget = NULL;
4309          break;
4310       }
4311    default:
4312       return;
4313    }
4314 }
4315 
4316 
4317 // Receives the name of the bookmark clicked and searches for it in viewPtList.
4318 
4319 void G4OpenInventorXtExaminerViewer::loadBookmarkCB(Widget, 
4320                                                     XtPointer client_data,
4321                                                     XtPointer call_data)
4322 {
4323    char *vpName;
4324    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4325    XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
4326 
4327    vpName = (char *) XmStringUnparse(cbs->item, XmFONTLIST_DEFAULT_TAG,
4328                                      XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
4329 
4330    for (int i = 0; i < (int) This->viewPtList.size(); i++) {
4331       if (!strcmp(This->viewPtList[i].viewPtName, vpName)) {
4332          This->viewPtIdx = i;
4333          break;
4334       }
4335    }
4336    XmTextSetString(This->viewPtSelection, vpName);
4337 
4338    This->writeViewPtIdx();
4339    This->setViewPt();
4340    XtFree(vpName);
4341 }
4342 
4343 
4344 
4345 void G4OpenInventorXtExaminerViewer::deleteBookmarkCB(Widget, 
4346                                                       XtPointer client_data,
4347                                                       XtPointer)
4348 {
4349    char *vpName;
4350    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4351 
4352    vpName = XmTextGetString(This->viewPtSelection);
4353 
4354    XmString vpNameStr = XmStringCreateLocalized(vpName);
4355 
4356    if (XmListItemExists(This->myViewPtList, vpNameStr)) {
4357       XmListDeleteItem(This->myViewPtList, vpNameStr);
4358       This->deleteViewPt(vpName);
4359    }
4360 
4361    XmStringFree(vpNameStr);
4362    XmTextSetString(This->viewPtSelection, NULL);
4363    XtFree(vpName);
4364 }
4365 
4366 
4367 void G4OpenInventorXtExaminerViewer::renameBookmarkCB(Widget, 
4368                                                       XtPointer client_data,
4369                                                       XtPointer)
4370 {
4371    std::string vpNameStr;
4372    char *vpName;
4373    int *pos_list, pos_cnt;
4374    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4375 
4376    vpName = XmTextGetString(This->viewPtSelection);
4377 
4378    if (!strlen(vpName) || !strcmp(This->curViewPtName, vpName)) {
4379       XtFree(vpName);
4380       return;
4381    }
4382 
4383    vpNameStr = vpName;
4384    XtFree(vpName);
4385    int beg = vpNameStr.find_first_not_of(' '); // Remove leading/trailing spaces
4386    int end = vpNameStr.find_last_not_of(' ');
4387    vpNameStr = vpNameStr.substr(beg, end - beg + 1);
4388    const int nVPName = vpNameStr.size() + 1;
4389    char* vpName1 = new char[nVPName];
4390    strncpy(vpName1, vpNameStr.c_str(), nVPName);
4391 
4392    int size = This->viewPtList.size();
4393    for (int i = 0; i < size; i++) {
4394       if (!strcmp(vpName1, This->viewPtList[i].viewPtName)) {
4395 
4396          String dialogName = (char *) "Existing Viewpoint";
4397          std::string msg = "'";
4398          msg += vpName1;
4399          msg += "' already exists. Choose a different name";
4400 
4401          This->warningMsgDialog(msg, dialogName, NULL);
4402          delete[] vpName1;
4403          return;
4404       }
4405    }
4406 
4407    XmString vpNameXmStr = XmStringCreateLocalized(vpName1);
4408 
4409    if (XmListGetSelectedPos(This->myViewPtList, &pos_list, &pos_cnt)) {
4410       XmListReplaceItemsPos(This->myViewPtList, &vpNameXmStr, 1, pos_list[0]);
4411       This->renameViewPt(vpName1);
4412       XtFree((char *) pos_list);
4413    }
4414 
4415    if (This->currentState == VIEWPOINT)
4416       This->scheduleRedraw();
4417 
4418    XmStringFree(vpNameXmStr);
4419    delete[] vpName1;
4420 }
4421 
4422 
4423 void G4OpenInventorXtExaminerViewer::sortBookmarksCB(Widget, 
4424                                                      XtPointer client_data,
4425                                                      XtPointer)
4426 {
4427    int size;
4428    char *vpName;
4429    XmString *strList, *newStrList;
4430    std::vector<std::string> charList;
4431    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4432 
4433    if (This->viewPtList.size() < 2)
4434       return;
4435 
4436    // Get current entries from the list
4437    XtVaGetValues(This->myViewPtList, XmNitemCount, &size, XmNitems, &strList,
4438                  NULL);
4439 
4440    for (int i = 0; i < size; i++) {
4441       vpName = (char *) XmStringUnparse(strList[i], XmFONTLIST_DEFAULT_TAG,
4442                                         XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
4443       charList.push_back(vpName);
4444       XtFree(vpName);
4445    }
4446 
4447    std::sort(charList.begin(), charList.end());
4448 
4449    newStrList = (XmString *) XtMalloc(size * sizeof(XmString));
4450    for (int i = 0; i < size; i++) {
4451       // viewPtIdx has to be changed to account for a different order in viewPtList
4452       if (!strcmp(charList[i].c_str(), This->curViewPtName))
4453          This->viewPtIdx = i;
4454       const int nVPName = charList[i].size() + 1;
4455       char *vpName2 = new char[nVPName];
4456       strncpy(vpName2, charList[i].c_str(), nVPName);
4457       newStrList[i] = XmStringCreateLocalized(vpName2);
4458       delete [] vpName2;
4459    }
4460 
4461    XmListDeleteAllItems(This->myViewPtList);
4462    XmListAddItemsUnselected(This->myViewPtList, newStrList, size, 1);
4463 
4464    This->sortViewPts(charList);
4465 
4466    if (newStrList != NULL) {
4467       for (int i = 0; i < size; i++)
4468          XmStringFree(newStrList[i]);
4469       XtFree((char *) newStrList);
4470    }
4471 }
4472 
4473 
4474 void G4OpenInventorXtExaminerViewer::evenOutRefParticlePts()
4475 {
4476    if(this->refParticleTrajectory.empty())
4477       return;
4478 
4479    SbVec3f p1, p2, p3, dirNow, dirNxt, dir, p2_tmp, p_start, p_corner, p_nxt;
4480    float avgDistBtwPts = 0;
4481    float totalDistBtwPts = 0;
4482    std::vector<SbVec3f> newRefParticleTrajectory;
4483    SbVec3f refPoint;
4484    int size = refParticleTrajectory.size() - 1;
4485    int numOfPts = 0;
4486    for (int i = 0; i < size; i++) {
4487       p1 = refParticleTrajectory[i];
4488       p2 = refParticleTrajectory[i + 1];
4489       if (p1 == p2)
4490          continue;
4491       numOfPts++;
4492       totalDistBtwPts += (p2 - p1).length();
4493    }
4494    // Nothing useful to do (and fix Coverity)
4495    if (numOfPts <= 2) return;
4496 
4497    avgDistBtwPts = totalDistBtwPts / numOfPts;
4498    float minDistAllowed = 0.75 * avgDistBtwPts;
4499    // float maxDistAllowed = 1.25 * avgDistBtwPts; // Pts tend to be close not far
4500 
4501    float x, y, z;
4502    int i = 0, j = 0;
4503    while (i < size) {
4504       p1 = refParticleTrajectory[i];
4505       p2 = refParticleTrajectory[i + 1];
4506 
4507       refPoint = p1;
4508       p1.getValue(x, y, z);
4509 
4510       newRefParticleTrajectory.push_back(refPoint);
4511 
4512       j = i;
4513       while ((p2 - p1).length() < minDistAllowed && j < (size - 1)) {
4514          j++;
4515 
4516          p1 = refParticleTrajectory[j];
4517          p2 = refParticleTrajectory[j + 1];
4518       }
4519       if (j != i)
4520          i = j + 1;
4521       else
4522          i++;
4523    }
4524 
4525    refParticleTrajectory.clear();
4526    refParticleTrajectory = newRefParticleTrajectory;
4527 }
4528 
4529 
4530 // Called when the viewer is closed; closes all open widgets.
4531 
4532 void G4OpenInventorXtExaminerViewer::closeMainWindowCB(Widget, 
4533                                                        XtPointer client_data,
4534                                                        XtPointer)
4535 {
4536    G4OpenInventorXtExaminerViewer * This =
4537       (G4OpenInventorXtExaminerViewer *) client_data;
4538 
4539    if (This->openFileDialog)
4540       XtUnmanageChild(This->openFileDialog);
4541 
4542    if (This->newFileDialog)
4543       XtUnmanageChild(This->newFileDialog);
4544 
4545    if (This->listsDialog)
4546       closeListsDialogCB(NULL, This, NULL);
4547 }
4548 
4549 
4550 void G4OpenInventorXtExaminerViewer::saveCurCamera()
4551 {
4552    SoCamera *cam = getCamera();
4553    camB4Animation.viewportMapping = cam->viewportMapping.getValue();
4554    camB4Animation.position = cam->position.getValue();
4555    camB4Animation.orientation = cam->orientation.getValue();
4556    camB4Animation.aspectRatio = cam->aspectRatio.getValue();
4557    camB4Animation.nearDistance = cam->nearDistance.getValue();
4558    camB4Animation.farDistance = cam->farDistance.getValue();
4559    camB4Animation.focalDistance = cam->focalDistance.getValue();
4560 
4561    if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
4562       camB4Animation.height =
4563          ((SoPerspectiveCamera *) cam)->heightAngle.getValue();
4564       camB4Animation.camType = PERSPECTIVE;
4565    } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
4566       camB4Animation.height =
4567          ((SoOrthographicCamera *) cam)->height.getValue();
4568       camB4Animation.camType = ORTHOGRAPHIC;
4569    }
4570 }
4571 
4572 
4573 void G4OpenInventorXtExaminerViewer::restoreCamera()
4574 {
4575    SoCamera *cam = getCamera();
4576 
4577    cam->viewportMapping = camB4Animation.viewportMapping;
4578    cam->position = camB4Animation.position;
4579    cam->orientation = camB4Animation.orientation;
4580    cam->aspectRatio = camB4Animation.aspectRatio;
4581    cam->nearDistance = camB4Animation.nearDistance;
4582    cam->farDistance = camB4Animation.farDistance;
4583    cam->focalDistance = camB4Animation.focalDistance;
4584 
4585    if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) {
4586       if (camB4Animation.camType == ORTHOGRAPHIC) {
4587          toggleCameraType();
4588          cam = getCamera();
4589          ((SoOrthographicCamera *) cam)->height.setValue(
4590                                                          camB4Animation.height);
4591       } else
4592          ((SoPerspectiveCamera *) cam)->heightAngle.setValue(
4593                                                              camB4Animation.height);
4594    } else if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
4595       if (camB4Animation.camType == PERSPECTIVE) {
4596          toggleCameraType();
4597          cam = getCamera();
4598          ((SoPerspectiveCamera *) cam)->heightAngle.setValue(
4599                                                              camB4Animation.height);
4600       } else
4601          ((SoOrthographicCamera *) cam)->height.setValue(
4602                                                          camB4Animation.height);
4603    }
4604 }
4605 
4606 
4607 void G4OpenInventorXtExaminerViewer::animateSensorRotationCB(void *data, 
4608                                                              SoSensor *sensor)
4609 {
4610    SbTime curTime = SbTime::getTimeOfDay();
4611    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) data;
4612    SoTimerSensor *s = (SoTimerSensor *) sensor;
4613 
4614    float t = float((curTime - s->getBaseTime()).getValue())
4615       / This->animateBtwPtsPeriod;
4616 
4617    if ((t > 1.0f) || (t + s->getInterval().getValue() > 1.0f))
4618       t = 1.0f;
4619    SbBool end = (t == 1.0f);
4620 
4621    if (end) {
4622       This->animateSensorRotation->unschedule();
4623       if(This->rotCnt){
4624          // rotations left
4625          This->rotateCamera();
4626       }
4627       else {
4628          // rotation over
4629          This->currentState = This->prevState;
4630          return;
4631       }
4632    }
4633 
4634 }
4635 
4636 
4637 // Called repeatedly during reference particle animation
4638 
4639 void G4OpenInventorXtExaminerViewer::animateSensorCB(void *data, 
4640                                                      SoSensor *sensor)
4641 {
4642    SbTime curTime = SbTime::getTimeOfDay();
4643    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) data;
4644    SoCamera *cam = This->getCamera();
4645    SoTimerSensor *s = (SoTimerSensor *) sensor;
4646 
4647    float t = float((curTime - s->getBaseTime()).getValue())
4648       / This->animateBtwPtsPeriod;
4649 
4650    if ((t > 1.0f) || (t + s->getInterval().getValue() > 1.0f))
4651       t = 1.0f;
4652    SbBool end = (t == 1.0f);
4653 
4654    cam->orientation = SbRotation::slerp(This->camStartOrient, This->camEndOrient, t);
4655    cam->position = This->camStartPos + (This->camEndPos - This->camStartPos) * t;
4656 
4657    if (end) {
4658       This->animateSensor->unschedule();
4659 
4660       if (This->currentState == ANIMATION) {
4661          if (This->refParticleIdx < (int) (This->refParticleTrajectory.size() - 1))
4662             This->animateRefParticle();
4663          else {
4664             This->animateBtwPtsPeriod = MIN_SPEED;
4665             This->speedStep = START_STEP;
4666          }
4667       }
4668       if (This->currentState == REVERSED_ANIMATION) {
4669          if (This->refParticleIdx >= 1)
4670             This->animateRefParticle();
4671          else {
4672             This->animateBtwPtsPeriod = MIN_SPEED;
4673             This->speedStep = START_STEP;
4674          }
4675       }
4676    }
4677 }
4678 
4679 
4680 void G4OpenInventorXtExaminerViewer::setStartingPtForAnimation()
4681 {
4682    if (SoXtExaminerViewer::isAnimating())
4683       stopAnimating();
4684 
4685    SbRotation rot;
4686    SbVec3f p1(0), p2(0), p2_tmp(0), camUpV(0), camD, camD_tmp, leftRightAxis;
4687    float x1(0.), y1(0.), z1(0.), x2(0.), y2(0.), z2(0.);
4688 
4689    if (currentState == ANIMATION) {
4690       p1 = refParticleTrajectory[refParticleIdx];
4691       p2 = refParticleTrajectory[++(refParticleIdx)];
4692    } else if (currentState == REVERSED_ANIMATION) {
4693       p2 = refParticleTrajectory[refParticleIdx];
4694       p1 = refParticleTrajectory[--(refParticleIdx)];
4695    } else if (currentState == PAUSED_ANIMATION) {
4696       if (refParticleIdx < (int) refParticleTrajectory.size()) {
4697          p1 = refParticleTrajectory[refParticleIdx];
4698          p2 = refParticleTrajectory[refParticleIdx + 1];
4699       } else {
4700          p1 = refParticleTrajectory[refParticleIdx - 1];
4701          p2 = refParticleTrajectory[refParticleIdx];
4702       }
4703    }
4704    p1.getValue(x1, y1, z1);
4705    p2.getValue(x2, y2, z2);
4706 
4707    camD = p2 - p1;
4708    camD.normalize();
4709 
4710    p2_tmp.setValue(x2, y1, z2);
4711    camD_tmp = p2_tmp - p1;
4712    camD_tmp.normalize();
4713 
4714    camUpV.setValue(0, 1, 0);
4715    rot.setValue(camD_tmp, camD);
4716    rot.multVec(camUpV, camUpV);
4717 
4718    leftRightAxis = camD.cross(camUpV);
4719 
4720    myCam->position = p1;
4721    myCam->pointAt(p2, camUpV);
4722 
4723    // Update camera position
4724    p1 = p1 + (up_down * camUpV) + (left_right * leftRightAxis);
4725    myCam->position = p1;
4726    // FWJ Try look-ahead here
4727    int idx = refParticleIdx + pathLookahead;
4728    idx = std::min(idx, (int)refParticleTrajectory.size() - 1);
4729    myCam->pointAt(refParticleTrajectory[idx], camUpV);
4730    //   myCam->pointAt(refParticleTrajectory[idx], camUpVec);
4731    myCam->focalDistance = 0.1f;
4732 }
4733 
4734 
4735 void G4OpenInventorXtExaminerViewer::gotoRefPathStart()
4736 {
4737    G4OpenInventorXtExaminerViewer::gotoRefPathStartCB(NULL, (void *)this, 
4738                                                       NULL);
4739 }
4740 
4741 
4742 void G4OpenInventorXtExaminerViewer::gotoRefPathStartCB(Widget, 
4743                                                         XtPointer client_data, 
4744                                                         XtPointer)
4745 {
4746    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4747 
4748    if (!This->refParticleTrajectory.size()) {
4749       String dialogName = (char *) "No Reference Trajectory";
4750       std::string msg = "You need to start a run or load a reference trajectory from a file";
4751       This->warningMsgDialog(msg, dialogName, NULL);
4752       return;
4753    }
4754 
4755    if (This->currentState == ROTATING)
4756       return;
4757    if (This->currentState == ANIMATION || This->currentState == REVERSED_ANIMATION
4758        || This->currentState == PAUSED_ANIMATION) {
4759       if (This->animateSensor->isScheduled())
4760          This->animateSensor->unschedule();
4761       This->setSuperimpositionEnabled(This->superimposition, FALSE);
4762       This->maxSpeed = 0.0f;
4763       This->scheduleRedraw();
4764    } else {
4765       This->saveCurCamera();
4766       This->prevState = This->currentState;
4767       This->prevRefIdx = This->refParticleIdx;
4768    }
4769 
4770    if (This->SoXtExaminerViewer::isAnimating())
4771       This->stopAnimating();
4772 
4773    This->up_down = 0;
4774    This->left_right = 0;
4775    This->step = 1;
4776 
4777    This->refParticleIdx = 0;
4778    This->currentState = BEAMLINE;
4779    This->setSuperimpositionEnabled(This->superimposition, TRUE);
4780    This->axisSwitch->whichChild.setValue(SO_SWITCH_NONE);
4781    This->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_NONE);
4782    This->animSpeedSwitch->whichChild.setValue(SO_SWITCH_NONE);
4783    This->scheduleRedraw();
4784 
4785    // FWJ Disabled: this is set in moveCamera()
4786    // Zoom in
4787    //   SoCamera *cam = This->getCamera();
4788    //   cam->focalDistance = 0.1f;
4789 
4790    This->prevParticleDir = SbVec3f(0,0,0);
4791 
4792    //Default zoom
4793    SbVec3f p1 = This->refParticleTrajectory[0];
4794    SbVec3f pN = This->refParticleTrajectory[This->refParticleTrajectory.size() - 1];
4795    This->distance = (pN - p1).length() / 10;
4796 
4797    This->moveCamera(This->distance, true);
4798 }
4799 
4800 
4801 void G4OpenInventorXtExaminerViewer::invertRefPathCB(Widget,
4802                                                      XtPointer client_data,
4803                                                      XtPointer)
4804 {
4805    G4OpenInventorXtExaminerViewer * This =
4806       (G4OpenInventorXtExaminerViewer *) client_data;
4807    This->invertRefPath();
4808 }
4809 
4810 
4811 void G4OpenInventorXtExaminerViewer::invertRefPath()
4812 {
4813    std::reverse(this->refParticleTrajectory.begin(),
4814                 this->refParticleTrajectory.end());
4815    this->setReferencePathZPos();
4816    this->sortElements();
4817 }
4818 
4819 
4820 void G4OpenInventorXtExaminerViewer::animateRefParticleCB(Widget, 
4821                                            XtPointer client_data,
4822                                            XtPointer)
4823 {
4824    G4OpenInventorXtExaminerViewer * This = (G4OpenInventorXtExaminerViewer *) client_data;
4825 
4826    if (!This->refParticleTrajectory.size()) {
4827       This->returnToAnim = true;
4828       String dialogName = (char *) "No Reference Trajectory";
4829       std::string msg = "You need to start a run or load a reference trajectory from a file";
4830       This->warningMsgDialog(msg, dialogName, NULL);
4831       return;
4832    }
4833 
4834    if (!This->refParticleTrajectory.size())
4835       return;
4836 
4837    ///////////////////////////////////////////////////////////////
4838    This->setSuperimpositionEnabled(This->superimposition, TRUE);
4839    This->maxSpeed = SPEED_INDICATOR_STEP;
4840    This->axisSwitch->whichChild.setValue(SO_SWITCH_ALL);
4841    This->animSpeedOutlineSwitch->whichChild.setValue(SO_SWITCH_ALL);
4842    This->animSpeedSwitch->whichChild.setValue(SO_SWITCH_ALL);
4843    This->scheduleRedraw();
4844    ///////////////////////////////////////////////////////////////
4845 
4846    SoCamera *cam = This->getCamera();
4847    //   SbVec3f camDirOld, camDirNew, camDirNew_tmp, camUpVec, P0, P1, P1_tmp;
4848 
4849    if (This->currentState == ANIMATION || This->currentState == REVERSED_ANIMATION
4850        || This->currentState == ROTATING)
4851       return;
4852 
4853    if (This->currentState != PAUSED_ANIMATION) {
4854 
4855       This->saveCurCamera();
4856       This->prevState = This->currentState;
4857       This->prevRefIdx = This->refParticleIdx;
4858 
4859       if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) {
4860          This->toggleCameraType();
4861          cam = This->getCamera();
4862       }
4863 
4864       This->refParticleIdx = 0; // Set the camera to the starting point of the animation
4865       This->animateBtwPtsPeriod = MIN_SPEED;
4866       This->speedStep = START_STEP;
4867       This->left_right = This->up_down = 0;
4868 
4869       cam->focalDistance = 0.1f;
4870       ((SoPerspectiveCamera *) cam)->heightAngle = 0.50f;
4871    }
4872 
4873    This->currentState = ANIMATION;
4874    This->setStartingPtForAnimation();
4875 
4876    cam->position = (This->myCam)->position.getValue();
4877    cam->orientation = (This->myCam)->orientation.getValue();
4878    This->animateRefParticle(); // Animate the camera
4879 }
4880 
4881 
4882 void G4OpenInventorXtExaminerViewer::animateRefParticle()
4883 {
4884    SoCamera *cam = getCamera();
4885 
4886    camStartPos = cam->position.getValue();
4887    camStartOrient = cam->orientation.getValue();
4888 
4889    if (currentState != BEAMLINE)
4890       setStartingPtForAnimation();
4891 
4892    camEndPos = myCam->position.getValue();
4893    camEndOrient = myCam->orientation.getValue();
4894 
4895    if (animateSensor->isScheduled())
4896       animateSensor->unschedule();
4897 
4898    animateSensor->setBaseTime(SbTime::getTimeOfDay());
4899    animateSensor->setInterval(SbTime(0.02));
4900 
4901    animateSensor->schedule();
4902 }
4903 
4904 
4905 void G4OpenInventorXtExaminerViewer::addEscapeCallback(
4906                          void (*callback)(void *), void * object)
4907 {
4908    this->escapeCallback = callback;
4909    this->examinerObject = object;
4910 }
4911 
4912 
4913 void G4OpenInventorXtExaminerViewer::sceneChangeCB(void *userData, SoSensor *)
4914 {
4915    G4OpenInventorXtExaminerViewer* This =
4916       (G4OpenInventorXtExaminerViewer*)userData;
4917    if(This->newEvents){
4918       This->findAndSetRefPath();
4919       This->newEvents = false;
4920    }
4921 }
4922 
4923 
4924 HookEventProcState::HookEventProcState(G4OpenInventorXtExaminerViewer* vwr)
4925 {
4926    this->viewer = vwr;
4927 }
4928 
4929 
4930 HookEventProcState::~HookEventProcState()
4931 {;}
4932 
4933 
4934 G4bool HookEventProcState::Notify(G4ApplicationState requiredState)
4935 {
4936    if(requiredState == G4State_EventProc){
4937       this->viewer->newEvents = true;
4938    }
4939    return true;
4940 }
4941