ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4ViewParameters.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4ViewParameters.cc
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 //
28 //
29 // John Allison 19th July 1996
30 // View parameters and options.
31 
32 #include "G4ViewParameters.hh"
33 
34 #include "G4VisManager.hh"
35 #include "G4VPhysicalVolume.hh"
36 #include "G4UnitsTable.hh"
37 #include "G4SystemOfUnits.hh"
38 #include "G4Polyhedron.hh"
39 
40 #include <sstream>
41 #include <cmath>
42 
44  fDrawingStyle (wireframe),
45  fNumberOfCloudPoints(10000),
46  fAuxEdgeVisible (false),
47  fCulling (true),
48  fCullInvisible (true),
49  fDensityCulling (false),
50  fVisibleDensity (0.01 * g / cm3),
51  fCullCovered (false),
52  fCBDAlgorithmNumber (0),
53  fSection (false),
54  fSectionPlane (),
55  fCutawayMode (cutawayUnion),
56  fCutawayPlanes (),
57  fExplodeFactor (1.),
58  fNoOfSides (),
59  fViewpointDirection (G4Vector3D (0., 0., 1.)), // On z-axis.
60  fUpVector (G4Vector3D (0., 1., 0.)), // y-axis up.
61  fFieldHalfAngle (0.), // Orthogonal projection.
62  fZoomFactor (1.),
63  fScaleFactor (G4Vector3D (1., 1., 1.)),
64  fCurrentTargetPoint (),
65  fDolly (0.),
66  fLightsMoveWithCamera (false),
67  fRelativeLightpointDirection (G4Vector3D (1., 1., 1.)),
68  fActualLightpointDirection (G4Vector3D (1., 1., 1.)),
69  fDefaultVisAttributes (),
70  fDefaultTextVisAttributes (G4Colour (0., 0., 1.)),
71  fDefaultMarker (),
72  fGlobalMarkerScale (1.),
73  fGlobalLineWidthScale (1.),
74  fMarkerNotHidden (true),
75  fWindowSizeHintX (600),
76  fWindowSizeHintY (600),
77  fWindowLocationHintX(0),
78  fWindowLocationHintY(0),
79  fWindowLocationHintXNegative(true),
80  fWindowLocationHintYNegative(false),
81  fGeometryMask(0),
82  fAutoRefresh (false),
83  fBackgroundColour (G4Colour(0.,0.,0.)), // Black
84  fPicking (false),
85  fRotationStyle (constrainUpDirection),
86  fStartTime(-G4VisAttributes::fVeryLongTime),
87  fEndTime(G4VisAttributes::fVeryLongTime),
88  fFadeFactor(0.),
89  fDisplayHeadTime(false),
90  fDisplayHeadTimeX(-0.9),
91  fDisplayHeadTimeY(-0.9),
92  fDisplayHeadTimeSize(24.),
93  fDisplayHeadTimeRed(0.),
94  fDisplayHeadTimeGreen(1.),
95  fDisplayHeadTimeBlue(1.),
96  fDisplayLightFront(false),
97  fDisplayLightFrontX(0.),
98  fDisplayLightFrontY(0.),
99  fDisplayLightFrontZ(0.),
100  fDisplayLightFrontT(0.),
101  fDisplayLightFrontRed(0.),
102  fDisplayLightFrontGreen(1.),
103  fDisplayLightFrontBlue(0.)
104 {
105  // Pick up default no of sides from G4Polyhedron.
106  // Note that this parameter is variously called:
107  // No of sides
108  // NumberOfRotationSteps
109  // Line segments per circle
110  // It refers to the approximation of a circle by a polygon of
111  // stated number of sides.
113 
115  // Markers are 5 pixels "overall" size, i.e., diameter.
116 }
117 
119 
121 (const G4Vector3D& scaleFactorMultiplier) {
122  fScaleFactor.setX(fScaleFactor.x() * scaleFactorMultiplier.x());
123  fScaleFactor.setY(fScaleFactor.y() * scaleFactorMultiplier.y());
124  fScaleFactor.setZ(fScaleFactor.z() * scaleFactorMultiplier.z());
125 }
126 
130 }
131 
132 // Useful quantities - begin snippet.
133 // Here Follow functions to evaluate the above algorithms as a
134 // function of the radius of the Bounding Sphere of the object being
135 // viewed. Call them in the order given - for efficiency, later
136 // functions depend on the results of earlier ones (Store the
137 // results of earlier functions in your own temporary variables -
138 // see, for example, G4OpenGLView::SetView ().)
139 
141  G4double cameraDistance;
142  if (fFieldHalfAngle == 0.) {
143  cameraDistance = radius;
144  }
145  else {
146  cameraDistance = radius / std::sin (fFieldHalfAngle) - fDolly;
147  }
148  return cameraDistance;
149 }
150 
152  G4double radius) const {
153  const G4double small = 1.e-6 * radius;
154  G4double nearDistance = cameraDistance - radius;
155  if (nearDistance < small) nearDistance = small;
156  return nearDistance;
157 }
158 
160  G4double nearDistance,
161  G4double radius) const {
162  G4double farDistance = cameraDistance + radius;
163  if (farDistance < nearDistance) farDistance = nearDistance;
164  return farDistance;
165 }
166 
168  G4double radius) const {
169  G4double frontHalfHeight;
170  if (fFieldHalfAngle == 0.) {
171  frontHalfHeight = radius / fZoomFactor;
172  }
173  else {
174  frontHalfHeight = nearDistance * std::tan (fFieldHalfAngle) / fZoomFactor;
175  }
176  return frontHalfHeight;
177 }
178 // Useful quantities - end snippet.
179 
180 void G4ViewParameters::AddCutawayPlane (const G4Plane3D& cutawayPlane) {
181  if (fCutawayPlanes.size () < 3 ) {
182  fCutawayPlanes.push_back (cutawayPlane);
183  }
184  else {
185  G4cerr <<
186  "ERROR: G4ViewParameters::AddCutawayPlane:"
187  "\n A maximum of 3 cutaway planes supported." << G4endl;
188  }
189 }
190 
192 (size_t index, const G4Plane3D& cutawayPlane) {
193  if (index >= fCutawayPlanes.size()) {
194  G4cerr <<
195  "ERROR: G4ViewParameters::ChangeCutawayPlane:"
196  "\n Plane " << index << " does not exist." << G4endl;
197  } else {
198  fCutawayPlanes[index] = cutawayPlane;
199  }
200 }
201 
203  const G4double reasonableMaximum = 10.0 * g / cm3;
204  if (visibleDensity < 0) {
205  G4cout << "G4ViewParameters::SetVisibleDensity: attempt to set negative "
206  "density - ignored." << G4endl;
207  }
208  else {
209  if (visibleDensity > reasonableMaximum) {
210  G4cout << "G4ViewParameters::SetVisibleDensity: density > "
211  << G4BestUnit (reasonableMaximum, "Volumic Mass")
212  << " - did you mean this?"
213  << G4endl;
214  }
215  fVisibleDensity = visibleDensity;
216  }
217 }
218 
221  if (nSides < nSidesMin) {
222  nSides = nSidesMin;
223  G4cout << "G4ViewParameters::SetNoOfSides: attempt to set the"
224  "\nnumber of sides per circle < " << nSidesMin
225  << "; forced to " << nSides << G4endl;
226  }
227  fNoOfSides = nSides;
228  return fNoOfSides;
229 }
230 
232  const G4int nPointsMin = 100;
233  if (nPoints < nPointsMin) {
234  nPoints = nPointsMin;
235  G4cout << "G4ViewParameters::SetNumberOfCloudPoints:"
236  "\nnumber of points per cloud set to minimum " << nPoints
237  << G4endl;
238  }
239  fNumberOfCloudPoints = nPoints;
240  return fNumberOfCloudPoints;
241 }
242 
244 (const G4Vector3D& viewpointDirection) {
245 
246  fViewpointDirection = viewpointDirection;
247 
248  // If the requested viewpoint direction is parallel to the up
249  // vector, the orientation of the view is undefined...
250  if (fViewpointDirection.unit() * fUpVector.unit() > .9999) {
251  static G4bool firstTime = true;
252  if (firstTime) {
253  firstTime = false;
254  G4cout <<
255  "WARNING: Viewpoint direction is very close to the up vector direction."
256  "\n Change the up vector or \"/vis/viewer/set/rotationStyle freeRotation\"."
257  << G4endl;
258  }
259  }
260 
261  // Move the lights too if requested...
262  if (fLightsMoveWithCamera) {
263  G4Vector3D zprime = fViewpointDirection.unit ();
264  G4Vector3D xprime = (fUpVector.cross (zprime)).unit ();
265  G4Vector3D yprime = zprime.cross (xprime);
266  fActualLightpointDirection =
267  fRelativeLightpointDirection.x () * xprime +
268  fRelativeLightpointDirection.y () * yprime +
269  fRelativeLightpointDirection.x () * zprime;
270  } else {
271  fActualLightpointDirection = fRelativeLightpointDirection;
272  }
273 }
274 
276 (const G4Vector3D& lightpointDirection) {
277  fRelativeLightpointDirection = lightpointDirection;
278  SetViewAndLights (fViewpointDirection);
279 }
280 
282  G4Vector3D unitRight = (fUpVector.cross (fViewpointDirection)).unit();
283  G4Vector3D unitUp = (fViewpointDirection.cross (unitRight)).unit();
284  fCurrentTargetPoint = right * unitRight + up * unitUp;
285 }
286 
288  IncrementPan (right,up, 0);
289 }
290 
292  G4Vector3D unitRight = (fUpVector.cross (fViewpointDirection)).unit();
293  G4Vector3D unitUp = (fViewpointDirection.cross (unitRight)).unit();
294  fCurrentTargetPoint += right * unitRight + up * unitUp + distance * fViewpointDirection;
295 }
296 
299  // If target exists with same signifier just change vis attributes.
300  G4bool duplicateTarget = false;
301  auto i = fVisAttributesModifiers.begin();
302  for (; i < fVisAttributesModifiers.end(); ++i) {
303  if (vam.GetPVNameCopyNoPath() == (*i).GetPVNameCopyNoPath() &&
304  vam.GetVisAttributesSignifier() == (*i).GetVisAttributesSignifier()) {
305  duplicateTarget = true;
306  break;
307  }
308  }
309  if (duplicateTarget) (*i).SetVisAttributes(vam.GetVisAttributes());
310  else fVisAttributesModifiers.push_back(vam);
311 }
312 
314 (const G4Point3D standardTargetPoint) const
315 {
316  std::ostringstream oss;
317 
318  oss << "#\n# Camera and lights commands";
319 
320  oss << "\n/vis/viewer/set/viewpointVector "
321  << fViewpointDirection.x()
322  << ' ' << fViewpointDirection.y()
323  << ' ' << fViewpointDirection.z();
324 
325  oss << "\n/vis/viewer/set/upVector "
326  << fUpVector.x()
327  << ' ' << fUpVector.y()
328  << ' ' << fUpVector.z();
329 
330  oss << "\n/vis/viewer/set/projection ";
331  if (fFieldHalfAngle == 0.) {
332  oss
333  << "orthogonal";
334  } else {
335  oss
336  << "perspective "
337  << fFieldHalfAngle/deg
338  << " deg";
339  }
340 
341  oss << "\n/vis/viewer/zoomTo "
342  << fZoomFactor;
343 
344  oss << "\n/vis/viewer/scaleTo "
345  << fScaleFactor.x()
346  << ' ' << fScaleFactor.y()
347  << ' ' << fScaleFactor.z();
348 
349  oss << "\n/vis/viewer/set/targetPoint "
350  << G4BestUnit(standardTargetPoint+fCurrentTargetPoint,"Length")
351  << "\n# Note that if you have not set a target point, the vis system sets"
352  << "\n# a target point based on the scene - plus any panning and dollying -"
353  << "\n# so don't be alarmed by strange coordinates here.";
354 
355  oss << "\n/vis/viewer/dollyTo "
356  << G4BestUnit(fDolly,"Length");
357 
358  oss << "\n/vis/viewer/set/lightsMove ";
359  if (fLightsMoveWithCamera) {
360  oss << "camera";
361  } else {
362  oss << "object";
363  }
364 
365  oss << "\n/vis/viewer/set/lightsVector "
366  << fRelativeLightpointDirection.x()
367  << ' ' << fRelativeLightpointDirection.y()
368  << ' ' << fRelativeLightpointDirection.z();
369 
370  oss << "\n/vis/viewer/set/rotationStyle ";
371  if (fRotationStyle == constrainUpDirection) {
372  oss << "constrainUpDirection";
373  } else {
374  oss << "freeRotation";
375  }
376 
377  G4Colour c = fBackgroundColour;
378  oss << "\n/vis/viewer/set/background "
379  << c.GetRed()
380  << ' ' << c.GetGreen()
381  << ' ' << c.GetBlue()
382  << ' ' << c.GetAlpha();
383 
384  c = fDefaultVisAttributes.GetColour();
385  oss << "\n/vis/viewer/set/defaultColour "
386  << c.GetRed()
387  << ' ' << c.GetGreen()
388  << ' ' << c.GetBlue()
389  << ' ' << c.GetAlpha();
390 
391  c = fDefaultTextVisAttributes.GetColour();
392  oss << "\n/vis/viewer/set/defaultTextColour "
393  << c.GetRed()
394  << ' ' << c.GetGreen()
395  << ' ' << c.GetBlue()
396  << ' ' << c.GetAlpha();
397 
398  oss << std::endl;
399 
400  return oss.str();
401 }
402 
404 {
405  std::ostringstream oss;
406 
407  oss << "#\n# Drawing style commands";
408 
409  oss << "\n/vis/viewer/set/style ";
410  switch (fDrawingStyle) {
411  case wireframe:
412  case hlr:
413  oss << "wireframe";
414  break;
415  case hsr:
416  case hlhsr:
417  oss << "surface";
418  break;
419  case cloud:
420  oss << "cloud";
421  break;
422  }
423 
424  oss << "\n/vis/viewer/set/hiddenEdge ";
425  if (fDrawingStyle == hlr || fDrawingStyle == hlhsr) {
426  oss << "true";
427  } else {
428  oss << "false";
429  }
430 
431  oss << "\n/vis/viewer/set/auxiliaryEdge ";
432  if (fAuxEdgeVisible) {
433  oss << "true";
434  } else {
435  oss << "false";
436  }
437 
438  oss << "\n/vis/viewer/set/hiddenMarker ";
439  if (fMarkerNotHidden) {
440  oss << "false";
441  } else {
442  oss << "true";
443  }
444 
445  oss << "\n/vis/viewer/set/globalLineWidthScale "
447 
448  oss << "\n/vis/viewer/set/globalMarkerScale "
450 
451  oss << "\n/vis/viewer/set/numberOfCloudPoints "
453 
454  oss << std::endl;
455 
456  return oss.str();
457 }
458 
460 {
461  std::ostringstream oss;
462 
463  oss << "#\n# Scene-modifying commands";
464 
465  oss << "\n/vis/viewer/set/culling global ";
466  if (fCulling) {
467  oss << "true";
468  } else {
469  oss << "false";
470  }
471 
472  oss << "\n/vis/viewer/set/culling invisible ";
473  if (fCullInvisible) {
474  oss << "true";
475  } else {
476  oss << "false";
477  }
478 
479  oss << "\n/vis/viewer/set/culling density ";
480  if (fDensityCulling) {
481  oss << "true " << fVisibleDensity/(g/cm3) << " g/cm3";
482  } else {
483  oss << "false";
484  }
485 
486  oss << "\n/vis/viewer/set/culling coveredDaughters ";
487  if (fCullCovered) {
488  oss << "true";
489  } else {
490  oss << "false";
491  }
492 
493  oss << "\n/vis/viewer/colourByDensity "
494  << fCBDAlgorithmNumber << " g/cm3";
495  for (auto p: fCBDParameters) {
496  oss << ' ' << p/(g/cm3);
497  }
498 
499  oss << "\n/vis/viewer/set/sectionPlane ";
500  if (fSection) {
501  oss << "on "
502  << G4BestUnit(fSectionPlane.point(),"Length")
503  << fSectionPlane.normal().x()
504  << ' ' << fSectionPlane.normal().y()
505  << ' ' << fSectionPlane.normal().z();
506  } else {
507  oss << "off";
508  }
509 
510  oss << "\n/vis/viewer/set/cutawayMode ";
511  if (fCutawayMode == cutawayUnion) {
512  oss << "union";
513  } else {
514  oss << "intersection";
515  }
516 
517  oss << "\n/vis/viewer/clearCutawayPlanes";
518  if (fCutawayPlanes.size()) {
519  for (size_t i = 0; i < fCutawayPlanes.size(); i++) {
520  oss << "\n/vis/viewer/addCutawayPlane "
521  << G4BestUnit(fCutawayPlanes[i].point(),"Length")
522  << fCutawayPlanes[i].normal().x()
523  << ' ' << fCutawayPlanes[i].normal().y()
524  << ' ' << fCutawayPlanes[i].normal().z();
525  }
526  } else {
527  oss << "\n# No cutaway planes defined.";
528  }
529 
530  oss << "\n/vis/viewer/set/explodeFactor "
531  << fExplodeFactor
532  << ' ' << G4BestUnit(fExplodeCentre,"Length");
533 
534  oss << "\n/vis/viewer/set/lineSegmentsPerCircle "
535  << fNoOfSides;
536 
537  oss << std::endl;
538 
539  return oss.str();
540 }
541 
543 {
544  std::ostringstream oss;
545 
546  oss << "#\n# Touchable commands";
547 
548  const std::vector<G4ModelingParameters::VisAttributesModifier>& vams =
550 
551  if (vams.empty()) {
552  oss
553  << "\n# None"
554  << "\n/vis/viewer/clearVisAttributesModifiers";
555  oss << std::endl;
556  return oss.str();
557  }
558 
559  oss
560  << "\n/vis/viewer/clearVisAttributesModifiers";
561 
563  std::vector<G4ModelingParameters::VisAttributesModifier>::const_iterator
564  iModifier;
565  for (iModifier = vams.begin();
566  iModifier != vams.end();
567  ++iModifier) {
569  iModifier->GetPVNameCopyNoPath();
570  if (vamPath != lastPath) {
571  lastPath = vamPath;
572  oss << "\n/vis/set/touchable";
574  for (iVAM = vamPath.begin();
575  iVAM != vamPath.end();
576  ++iVAM) {
577  oss << ' ' << iVAM->GetName() << ' ' << iVAM->GetCopyNo();
578  }
579  }
580  const G4VisAttributes& vamVisAtts = iModifier->GetVisAttributes();
581  const G4Colour& c = vamVisAtts.GetColour();
582  switch (iModifier->GetVisAttributesSignifier()) {
584  oss << "\n/vis/touchable/set/visibility ";
585  if (vamVisAtts.IsVisible()) {
586  oss << "true";
587  } else {
588  oss << "false";
589  }
590  break;
592  oss << "\n/vis/touchable/set/daughtersInvisible ";
593  if (vamVisAtts.IsDaughtersInvisible()) {
594  oss << "true";
595  } else {
596  oss << "false";
597  }
598  break;
600  oss << "\n/vis/touchable/set/colour "
601  << c.GetRed()
602  << ' ' << c.GetGreen()
603  << ' ' << c.GetBlue()
604  << ' ' << c.GetAlpha();
605  break;
607  oss << "\n/vis/touchable/set/lineStyle ";
608  switch (vamVisAtts.GetLineStyle()) {
610  oss << "unbroken";
611  break;
613  oss << "dashed";
614  break;
616  oss << "dotted";
617  }
618  break;
620  oss << "\n/vis/touchable/set/lineWidth "
621  << vamVisAtts.GetLineWidth();
622  break;
624  if (vamVisAtts.IsForceDrawingStyle()) {
626  oss << "\n/vis/touchable/set/forceWireframe ";
627  if (vamVisAtts.IsForceDrawingStyle()) {
628  oss << "true";
629  } else {
630  oss << "false";
631  }
632  }
633  }
634  break;
636  if (vamVisAtts.IsForceDrawingStyle()) {
637  if (vamVisAtts.GetForcedDrawingStyle() == G4VisAttributes::solid) {
638  oss << "\n/vis/touchable/set/forceSolid ";
639  if (vamVisAtts.IsForceDrawingStyle()) {
640  oss << "true";
641  } else {
642  oss << "false";
643  }
644  }
645  }
646  break;
648  if (vamVisAtts.IsForceDrawingStyle()) {
649  if (vamVisAtts.GetForcedDrawingStyle() == G4VisAttributes::cloud) {
650  oss << "\n/vis/touchable/set/forceCloud ";
651  if (vamVisAtts.IsForceDrawingStyle()) {
652  oss << "true";
653  } else {
654  oss << "false";
655  }
656  }
657  }
658  break;
660  if (vamVisAtts.IsForceAuxEdgeVisible()) {
661  oss << "\n/vis/touchable/set/forceAuxEdgeVisible ";
662  if (vamVisAtts.IsForcedAuxEdgeVisible()) {
663  oss << "true";
664  } else {
665  oss << "false";
666  }
667  }
668  break;
670  oss << "\n/vis/touchable/set/lineSegmentsPerCircle "
671  << vamVisAtts.GetForcedLineSegmentsPerCircle();
672  break;
674  oss << "\n/vis/touchable/set/numberOfCloudPoints "
675  << vamVisAtts.GetForcedNumberOfCloudPoints();
676  break;
677  }
678  }
679 
680  oss << std::endl;
681 
682  return oss.str();
683 }
684 
686 {
687  std::ostringstream oss;
688 
689  oss << "#\n# Time window commands";
690 
691  oss
692  << "\n/vis/viewer/set/timeWindow/startTime "
693  << fStartTime/ns << " ns ";
694 
695  oss
696  << "\n/vis/viewer/set/timeWindow/endTime "
697  << fEndTime/ns << " ns ";
698 
699  oss << "\n/vis/viewer/set/timeWindow/fadeFactor "
700  << fFadeFactor;
701 
702  oss
703  << "\n/vis/viewer/set/timeWindow/displayHeadTime ";
704  if (!fDisplayHeadTime) {
705  oss << "false";
706  } else {
707  oss
708  << "true"
709  << ' ' << fDisplayHeadTimeX
710  << ' ' << fDisplayHeadTimeY
711  << ' ' << fDisplayHeadTimeSize
712  << ' ' << fDisplayHeadTimeRed
713  << ' ' << fDisplayHeadTimeGreen
714  << ' ' << fDisplayHeadTimeBlue;
715  }
716 
717  oss
718  << "\n/vis/viewer/set/timeWindow/displayLightFront ";
719  if (!fDisplayLightFront) {
720  oss << "false";
721  } else {
722  oss
723  << "true"
724  << ' ' << fDisplayLightFrontX/mm
725  << ' ' << fDisplayLightFrontY/mm
726  << ' ' << fDisplayLightFrontZ/mm
727  << " mm"
728  << ' ' << fDisplayLightFrontT/ns
729  << " ns"
730  << ' ' << fDisplayLightFrontRed
731  << ' ' << fDisplayLightFrontGreen
732  << ' ' << fDisplayLightFrontBlue;
733  }
734 
735  oss << std::endl;
736 
737  return oss.str();
738 }
739 
741 
742  // Put performance-sensitive parameters first.
743  if (
744  // This first to optimise spin, etc.
746 
747  // No particular order from here on.
748  (fDrawingStyle != v.fDrawingStyle) ||
751  (fCulling != v.fCulling) ||
755  (fCullCovered != v.fCullCovered) ||
757  (fSection != v.fSection) ||
758  (fNoOfSides != v.fNoOfSides) ||
759  (fUpVector != v.fUpVector) ||
761  (fZoomFactor != v.fZoomFactor) ||
762  (fScaleFactor != v.fScaleFactor) ||
764  (fDolly != v.fDolly) ||
776  (fGeometryMask != v.fGeometryMask) ||
777  (fAutoRefresh != v.fAutoRefresh) ||
779  (fPicking != v.fPicking) ||
781  )
782  G4cout << "Difference in 1st batch." << G4endl;
783 
784  if (fCBDAlgorithmNumber > 0) {
785  if (fCBDParameters.size() != v.fCBDParameters.size()) {
786  G4cout << "Difference in number of colour by density parameters." << G4endl;
787  } else if (fCBDParameters != v.fCBDParameters) {
788  G4cout << "Difference in values of colour by density parameters." << G4endl;
789  }
790  }
791 
792  if (fSection) {
793  if (!(fSectionPlane == v.fSectionPlane))
794  G4cout << "Difference in section planes batch." << G4endl;
795  }
796 
797  if (IsCutaway()) {
798  if (fCutawayPlanes.size () != v.fCutawayPlanes.size ()) {
799  G4cout << "Difference in no of cutaway planes." << G4endl;
800  }
801  else {
802  for (size_t i = 0; i < fCutawayPlanes.size (); i++) {
803  if (!(fCutawayPlanes[i] == v.fCutawayPlanes[i]))
804  G4cout << "Difference in cutaway plane no. " << i << G4endl;
805  }
806  }
807  }
808 
809  if (IsExplode()) {
811  G4cout << "Difference in explode factor." << G4endl;
813  G4cout << "Difference in explode centre." << G4endl;
814  }
815 
817  G4cout << "Difference in vis attributes modifiers." << G4endl;
818  }
819 
820  if (fStartTime != v.fStartTime ||
821  fEndTime != v.fEndTime) {
822  G4cout << "Difference in time window." << G4endl;
823  }
824 
825  if (fFadeFactor != v.fFadeFactor) {
826  G4cout << "Difference in time window fade factor." << G4endl;
827  }
828 
830  G4cout << "Difference in display head time flag." << G4endl;
831  } else {
838  G4cout << "Difference in display head time parameters." << G4endl;
839  }
840  }
841 
843  G4cout << "Difference in display light front flag." << G4endl;
844  } else {
852  G4cout << "Difference in display light front parameters." << G4endl;
853  }
854  }
855 }
856 
857 std::ostream& operator <<
858 (std::ostream& os, const G4ViewParameters::DrawingStyle& style)
859 {
860  switch (style) {
862  os << "wireframe"; break;
864  os << "hlr - hidden lines removed"; break;
866  os << "hsr - hidden surfaces removed"; break;
868  os << "hlhsr - hidden line, hidden surface removed"; break;
870  os << "cloud - draw volume as a cloud of dots"; break;
871  default: os << "unrecognised"; break;
872  }
873  return os;
874 }
875 
876 std::ostream& operator << (std::ostream& os, const G4ViewParameters& v) {
877  os << "View parameters and options:";
878 
879  os << "\n Drawing style: " << v.fDrawingStyle;
880 
881  os << "\n Number of cloud points: " << v.fNumberOfCloudPoints;
882 
883  os << "\n Auxiliary edges: ";
884  if (!v.fAuxEdgeVisible) os << "in";
885  os << "visible";
886 
887  os << "\n Culling: ";
888  if (v.fCulling) os << "on";
889  else os << "off";
890 
891  os << "\n Culling invisible objects: ";
892  if (v.fCullInvisible) os << "on";
893  else os << "off";
894 
895  os << "\n Density culling: ";
896  if (v.fDensityCulling) {
897  os << "on - invisible if density less than "
898  << v.fVisibleDensity / (1. * g / cm3) << " g cm^-3";
899  }
900  else os << "off";
901 
902  os << "\n Culling daughters covered by opaque mothers: ";
903  if (v.fCullCovered) os << "on";
904  else os << "off";
905 
906  os << "\n Colour by density: ";
907  if (v.fCBDAlgorithmNumber <= 0) {
908  os << "inactive";
909  } else {
910  os << "Algorithm " << v.fCBDAlgorithmNumber << ", Parameters:";
911  for (auto p: v.fCBDParameters) {
912  os << ' ' << G4BestUnit(p,"Volumic Mass");
913  }
914  }
915 
916  os << "\n Section flag: ";
917  if (v.fSection) os << "true, section/cut plane: " << v.fSectionPlane;
918  else os << "false";
919 
920  if (v.IsCutaway()) {
921  os << "\n Cutaway planes: ";
922  for (size_t i = 0; i < v.fCutawayPlanes.size (); i++) {
923  os << ' ' << v.fCutawayPlanes[i];
924  }
925  }
926  else {
927  os << "\n No cutaway planes";
928  }
929 
930  os << "\n Explode factor: " << v.fExplodeFactor
931  << " about centre: " << v.fExplodeCentre;
932 
933  os << "\n No. of sides used in circle polygon approximation: "
934  << v.fNoOfSides;
935 
936  os << "\n Viewpoint direction: " << v.fViewpointDirection;
937 
938  os << "\n Up vector: " << v.fUpVector;
939 
940  os << "\n Field half angle: " << v.fFieldHalfAngle;
941 
942  os << "\n Zoom factor: " << v.fZoomFactor;
943 
944  os << "\n Scale factor: " << v.fScaleFactor;
945 
946  os << "\n Current target point: " << v.fCurrentTargetPoint;
947 
948  os << "\n Dolly distance: " << v.fDolly;
949 
950  os << "\n Light ";
951  if (v.fLightsMoveWithCamera) os << "moves";
952  else os << "does not move";
953  os << " with camera";
954 
955  os << "\n Relative lightpoint direction: "
957 
958  os << "\n Actual lightpoint direction: "
960 
961  os << "\n Derived parameters for standard view of object of unit radius:";
962  G4ViewParameters tempVP = v;
963  tempVP.fDolly = 0.;
964  tempVP.fZoomFactor = 1.;
965  const G4double radius = 1.;
966  const G4double cameraDistance = tempVP.GetCameraDistance (radius);
967  const G4double nearDistance =
968  tempVP.GetNearDistance (cameraDistance, radius);
969  const G4double farDistance =
970  tempVP.GetFarDistance (cameraDistance, nearDistance, radius);
971  const G4double right = tempVP.GetFrontHalfHeight (nearDistance, radius);
972  os << "\n Camera distance: " << cameraDistance;
973  os << "\n Near distance: " << nearDistance;
974  os << "\n Far distance: " << farDistance;
975  os << "\n Front half height: " << right;
976 
977  os << "\n Default VisAttributes:\n " << v.fDefaultVisAttributes;
978 
979  os << "\n Default TextVisAttributes:\n " << v.fDefaultTextVisAttributes;
980 
981  os << "\n Default marker: " << v.fDefaultMarker;
982 
983  os << "\n Global marker scale: " << v.fGlobalMarkerScale;
984 
985  os << "\n Global lineWidth scale: " << v.fGlobalLineWidthScale;
986 
987  os << "\n Marker ";
988  if (v.fMarkerNotHidden) os << "not ";
989  os << "hidden by surfaces.";
990 
991  os << "\n Window size hint: "
992  << v.fWindowSizeHintX << 'x'<< v.fWindowSizeHintX;
993 
994  os << "\n X geometry string: " << v.fXGeometryString;
995  os << "\n X geometry mask: "
996  << std::showbase << std::hex << v.fGeometryMask
997  << std::noshowbase << std::dec;
998 
999  os << "\n Auto refresh: ";
1000  if (v.fAutoRefresh) os << "true";
1001  else os << "false";
1002 
1003  os << "\n Background colour: " << v.fBackgroundColour;
1004 
1005  os << "\n Picking requested: ";
1006  if (v.fPicking) os << "true";
1007  else os << "false";
1008 
1009  os << "\n Rotation style: ";
1010  switch (v.fRotationStyle) {
1012  os << "constrainUpDirection (conventional HEP view)"; break;
1014  os << "freeRotation (Google-like rotation, using mouse-grab)"; break;
1015  default: os << "unrecognised"; break;
1016  }
1017 
1018  os << "\n Vis attributes modifiers: ";
1019  const std::vector<G4ModelingParameters::VisAttributesModifier>& vams =
1021  if (vams.empty()) {
1022  os << "None";
1023  } else {
1024  os << vams;
1025  }
1026 
1027  os << "\n Time window parameters:"
1028  << "\n Start time: " << v.fStartTime/ns << " ns"
1029  << "\n End time: " << v.fEndTime/ns << " ns"
1030  << "\n Fade factor: " << v.fFadeFactor;
1031  if (!v.fDisplayHeadTime) {
1032  os << "\n Head time display not requested.";
1033  } else {
1034  os
1035  << "\n Head time position: "
1036  << v.fDisplayHeadTimeX << ' ' << v.fDisplayHeadTimeY
1037  << "\n Head time size: " << v.fDisplayHeadTimeSize
1038  << "\n Head time colour: " << v.fDisplayHeadTimeRed
1039  << ' ' << v.fDisplayHeadTimeGreen << ' ' << v.fDisplayHeadTimeBlue;
1040  }
1041  if (!v.fDisplayLightFront) {
1042  os << "\n Light front display not requested.";
1043  } else {
1044  os
1045  << "\n Light front position: "
1046  << v.fDisplayLightFrontX/mm << ' ' << v.fDisplayLightFrontY/mm
1047  << ' ' << v.fDisplayLightFrontZ/mm << " mm"
1048  << "\n Light front time: " << v.fDisplayLightFrontT/ns << " ns"
1049  << "\n Light front colour: " << v.fDisplayLightFrontRed
1050  << ' ' << v.fDisplayLightFrontGreen << ' ' << v.fDisplayLightFrontBlue;
1051  }
1052 
1053  return os;
1054 }
1055 
1057 
1058  // Put performance-sensitive parameters first.
1059  if (
1060  // This first to optimise spin, etc.
1062 
1063  // No particular order from here on.
1064  (fDrawingStyle != v.fDrawingStyle) ||
1067  (fCulling != v.fCulling) ||
1068  (fCullInvisible != v.fCullInvisible) ||
1070  (fCullCovered != v.fCullCovered) ||
1072  (fSection != v.fSection) ||
1073  (IsCutaway() != v.IsCutaway()) ||
1074  (IsExplode() != v.IsExplode()) ||
1075  (fNoOfSides != v.fNoOfSides) ||
1076  (fUpVector != v.fUpVector) ||
1078  (fZoomFactor != v.fZoomFactor) ||
1079  (fScaleFactor != v.fScaleFactor) ||
1081  (fDolly != v.fDolly) ||
1086  (fDefaultMarker != v.fDefaultMarker) ||
1093  (fGeometryMask != v.fGeometryMask) ||
1094  (fAutoRefresh != v.fAutoRefresh) ||
1096  (fPicking != v.fPicking) ||
1098  )
1099  return true;
1100 
1101  if (fDensityCulling &&
1102  (fVisibleDensity != v.fVisibleDensity)) return true;
1103 
1104  if (fCBDAlgorithmNumber > 0) {
1105  if (fCBDParameters.size() != v.fCBDParameters.size()) return true;
1106  else if (fCBDParameters != v.fCBDParameters) return true;
1107  }
1108 
1109  if (fSection &&
1110  (!(fSectionPlane == v.fSectionPlane))) return true;
1111 
1112  if (IsCutaway()) {
1113  if (fCutawayPlanes.size () != v.fCutawayPlanes.size ())
1114  return true;
1115  else {
1116  for (size_t i = 0; i < fCutawayPlanes.size (); i++) {
1117  if (!(fCutawayPlanes[i] == v.fCutawayPlanes[i])) return true;
1118  }
1119  }
1120  }
1121 
1122  if (IsExplode() &&
1123  ((fExplodeFactor != v.fExplodeFactor) ||
1124  (fExplodeCentre != v.fExplodeCentre))) return true;
1125 
1126  if (fVisAttributesModifiers != v.fVisAttributesModifiers) return true;
1127 
1128  if (fStartTime != v.fStartTime ||
1129  fEndTime != v.fEndTime ||
1130  fFadeFactor != v.fFadeFactor) return true;
1131 
1132  if (fDisplayHeadTime != v.fDisplayHeadTime) return true;
1133  if (fDisplayHeadTime) {
1140  return true;
1141  }
1142  }
1143 
1144  if (fDisplayLightFront != v.fDisplayLightFront) return true;
1145  if (fDisplayLightFront) {
1153  return true;
1154  }
1155  }
1156 
1157  return false;
1158 }
1159 
1161 {
1162  G4int x = 0, y = 0;
1163  unsigned int w = 0, h = 0;
1164  G4String geomString = geomStringArg;
1165  // Parse windowSizeHintString for backwards compatibility...
1166  const G4String delimiters("xX+-");
1167  G4String::size_type i = geomString.find_first_of(delimiters);
1168  if (i == G4String::npos) { // Does not contain "xX+-". Assume single number
1169  std::istringstream iss(geomString);
1170  G4int size;
1171  iss >> size;
1172  if (!iss) {
1173  size = 600;
1174  G4cout << "Unrecognised windowSizeHint string: \""
1175  << geomString
1176  << "\". Asuuming " << size << G4endl;
1177  }
1178  std::ostringstream oss;
1179  oss << size << 'x' << size;
1180  geomString = oss.str();
1181  }
1182 
1183  fGeometryMask = ParseGeometry( geomString, &x, &y, &w, &h );
1184 
1185  // Handle special case :
1186  if ((fGeometryMask & fYValue) == 0)
1187  { // Using default
1189  }
1190  if ((fGeometryMask & fXValue) == 0)
1191  { // Using default
1193  }
1194 
1195  // Check errors
1196  // if there is no Width and Height
1197  if ( ((fGeometryMask & fHeightValue) == 0 ) &&
1198  ((fGeometryMask & fWidthValue) == 0 )) {
1199  h = fWindowSizeHintY;
1200  w = fWindowSizeHintX;
1201  } else if ((fGeometryMask & fHeightValue) == 0 ) {
1202 
1203  // if there is only Width. Special case to be backward compatible
1204  // We set Width and Height the same to obtain a square windows.
1205 
1206  G4cout << "Unrecognised geometry string \""
1207  << geomString
1208  << "\". No Height found. Using Width value instead"
1209  << G4endl;
1210  h = w;
1211  }
1212  if ( ((fGeometryMask & fXValue) == 0 ) ||
1213  ((fGeometryMask & fYValue) == 0 )) {
1214  //Using defaults
1217  }
1218  // Set the string
1219  fXGeometryString = geomString;
1220 
1221  // Set values
1222  fWindowSizeHintX = w;
1223  fWindowSizeHintY = h;
1226 
1227  if ( ((fGeometryMask & fXValue)) &&
1228  ((fGeometryMask & fYValue))) {
1229 
1230  if ( (fGeometryMask & fXNegative) ) {
1232  } else {
1234  }
1235  if ( (fGeometryMask & fYNegative) ) {
1237  } else {
1239  }
1240  }
1241 }
1242 
1245  return sizeX + fWindowLocationHintX - fWindowSizeHintX;
1246  }
1247  return fWindowLocationHintX;
1248 }
1249 
1252  return sizeY + fWindowLocationHintY - fWindowSizeHintY;
1253  }
1254  return fWindowLocationHintY;
1255 }
1256 
1257 /* Keep from :
1258  * ftp://ftp.trolltech.com/qt/source/qt-embedded-free-3.0.6.tar.gz/qt-embedded-free-3.0.6/src/kernel/qapplication_qws.cpp
1259  *
1260  * ParseGeometry parses strings of the form
1261  * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
1262  * width, height, xoffset, and yoffset are unsigned integers.
1263  * Example: "=80x24+300-49"
1264  * The equal sign is optional.
1265  * It returns a bitmask that indicates which of the four values
1266  * were actually found in the string. For each value found,
1267  * the corresponding argument is updated; for each value
1268  * not found, the corresponding argument is left unchanged.
1269  */
1270 
1272  const char *string,
1273  G4int *x,
1274  G4int *y,
1275  unsigned int *width,
1276  unsigned int *height)
1277 {
1278 
1279  G4int mask = fNoValue;
1280  char *strind;
1281  unsigned int tempWidth = 0;
1282  unsigned int tempHeight = 0;
1283  G4int tempX = 0;
1284  G4int tempY = 0;
1285  char *nextCharacter;
1286  if ( (string == NULL) || (*string == '\0')) {
1287  return(mask);
1288  }
1289  if (*string == '=')
1290  string++; /* ignore possible '=' at beg of geometry spec */
1291  strind = (char *)string;
1292  if (*strind != '+' && *strind != '-' && *strind != 'x') {
1293  tempWidth = ReadInteger(strind, &nextCharacter);
1294  if (strind == nextCharacter)
1295  return (0);
1296  strind = nextCharacter;
1297  mask |= fWidthValue;
1298  }
1299  if (*strind == 'x' || *strind == 'X') {
1300  strind++;
1301  tempHeight = ReadInteger(strind, &nextCharacter);
1302  if (strind == nextCharacter)
1303  return (0);
1304  strind = nextCharacter;
1305  mask |= fHeightValue;
1306  }
1307 
1308  if ((*strind == '+') || (*strind == '-')) {
1309  if (*strind == '-') {
1310  strind++;
1311  tempX = -ReadInteger(strind, &nextCharacter);
1312  if (strind == nextCharacter)
1313  return (0);
1314  strind = nextCharacter;
1315  mask |= fXNegative;
1316 
1317  }
1318  else
1319  { strind++;
1320  tempX = ReadInteger(strind, &nextCharacter);
1321  if (strind == nextCharacter)
1322  return(0);
1323  strind = nextCharacter;
1324  }
1325  mask |= fXValue;
1326  if ((*strind == '+') || (*strind == '-')) {
1327  if (*strind == '-') {
1328  strind++;
1329  tempY = -ReadInteger(strind, &nextCharacter);
1330  if (strind == nextCharacter)
1331  return(0);
1332  strind = nextCharacter;
1333  mask |= fYNegative;
1334  }
1335  else
1336  {
1337  strind++;
1338  tempY = ReadInteger(strind, &nextCharacter);
1339  if (strind == nextCharacter)
1340  return(0);
1341  strind = nextCharacter;
1342  }
1343  mask |= fYValue;
1344  }
1345  }
1346  /* If strind isn't at the end of the string the it's an invalid
1347  geometry specification. */
1348  if (*strind != '\0') return (0);
1349  if (mask & fXValue)
1350  *x = tempX;
1351  if (mask & fYValue)
1352  *y = tempY;
1353  if (mask & fWidthValue)
1354  *width = tempWidth;
1355  if (mask & fHeightValue)
1356  *height = tempHeight;
1357  return (mask);
1358 }
1359 
1360 /* Keep from :
1361  * ftp://ftp.trolltech.com/qt/source/qt-embedded-free-3.0.6.tar.gz/qt-embedded-free-3.0.6/src/kernel/qapplication_qws.cpp
1362  *
1363  */
1364 G4int G4ViewParameters::ReadInteger(char *string, char **NextString)
1365 {
1366  G4int Result = 0;
1367  G4int Sign = 1;
1368 
1369  if (*string == '+')
1370  string++;
1371  else if (*string == '-')
1372  {
1373  string++;
1374  Sign = -1;
1375  }
1376  for (; (*string >= '0') && (*string <= '9'); string++)
1377  {
1378  Result = (Result * 10) + (*string - '0');
1379  }
1380  *NextString = string;
1381  if (Sign >= 0)
1382  return (Result);
1383  else
1384  return (-Result);
1385 }
1386 
1388 (const std::vector<G4ViewParameters>& views,
1389  G4int nInterpolationPoints) // No of interpolations points per interval
1390 {
1391  // Returns a null pointer when no more to be done. For example:
1392  // do {
1393  // G4ViewParameters* vp =
1394  // G4ViewParameters::CatmullRomCubicSplineInterpolation(viewVector,nInterpolationPoints);
1395  // if (!vp) break;
1396  // ...
1397  // } while (true);
1398 
1399  // See https://en.wikipedia.org/wiki/Cubic_Hermite_spline
1400 
1401  // Assumes equal intervals
1402 
1403  if (views.size() < 2) {
1404  G4Exception
1405  ("G4ViewParameters::CatmullRomCubicSplineInterpolation",
1406  "visman0301", JustWarning,
1407  "There must be at least two views.");
1408  return 0;
1409  }
1410 
1411  if (nInterpolationPoints < 1) {
1412  G4Exception
1413  ("G4ViewParameters::CatmullRomCubicSplineInterpolation",
1414  "visman0302", JustWarning,
1415  "Number of interpolation points cannot be zero or negative.");
1416  return 0;
1417  }
1418 
1419  const size_t nIntervals = views.size() - 1;
1420  const G4double dt = 1./nInterpolationPoints;
1421 
1422  static G4ViewParameters holdingValues;
1423  static G4double t = 0.; // 0. <= t <= 1.
1424  static G4int iInterpolationPoint = 0;
1425  static size_t iInterval = 0;
1426 
1427 // G4cout << "Interval " << iInterval << ", t = " << t << G4endl;
1428 
1429  // Hermite polynomials.
1430  const G4double h00 = 2.*t*t*t - 3.*t*t +1;
1431  const G4double h10 = t*t*t -2.*t*t + t;
1432  const G4double h01 = -2.*t*t*t + 3.*t*t;
1433  const G4double h11 = t*t*t - t*t;
1434 
1435  // Aliases (to simplify code)
1436  const size_t& n = nIntervals;
1437  size_t& i = iInterval;
1438  const std::vector<G4ViewParameters>& v = views;
1439 
1440  // The Catmull-Rom cubic spline prescription is as follows:
1441  // Slope at first way point is v[1] - v[0].
1442  // Slope at last way point is v[n] - v[n-1].
1443  // Otherwise slope at way point i is 0.5*(v[i+1] - v[i-1]).
1444  // Result = h00*v[i] + h10*m[i] + h01*v[i+1] + h11*m[i+1],
1445  // where m[i] amd m[i+1] are the slopes at the start and end
1446  // of the interval for the particular value.
1447  // If (n == 1), linear interpolation results.
1448  // If (n == 2), quadratic interpolation results.
1449 
1450  // Working variables
1451  G4double mi, mi1, real, x, y, z;
1452 
1453  // First, a crude interpolation of all parameters. Then, below, a
1454  // smooth interpolation of those for which it makes sense.
1455  holdingValues = t < 0.5? v[i]: v[i+1];
1456 
1457  // Catmull-Rom cubic spline interpolation
1458 #define INTERPOLATE(param) \
1459 /* This works out the interpolated param in i'th interval */ \
1460 /* Assumes n >= 1 */ \
1461 if (i == 0) { \
1462 /* First interval */ \
1463 mi = v[1].param - v[0].param; \
1464 /* If there is only one interval, make start and end slopes equal */ \
1465 /* (This results in a linear interpolation) */ \
1466 if (n == 1) mi1 = mi; \
1467 /* else the end slope of the interval takes account of the next waypoint along */ \
1468 else mi1 = 0.5 * (v[2].param - v[0].param); \
1469 } else if (i >= n - 1) { \
1470 /* Similarly for last interval */ \
1471 mi1 = v[i+1].param - v[i].param; \
1472 /* If there is only one interval, make start and end slopes equal */ \
1473 if (n == 1) mi = mi1; \
1474 /* else the start slope of the interval takes account of the previous waypoint */ \
1475 else mi = 0.5 * (v[i+1].param - v[i-1].param); \
1476 } else { \
1477 /* Full Catmull-Rom slopes use previous AND next waypoints */ \
1478 mi = 0.5 * (v[i+1].param - v[i-1].param); \
1479 mi1 = 0.5 * (v[i+2].param - v[i ].param); \
1480 } \
1481 real = h00 * v[i].param + h10 * mi + h01 * v[i+1].param + h11 * mi1;
1482 
1483 #define INTERPOLATELOG(param) \
1484 if (i == 0) { \
1485 mi = std::log(v[1].param) - std::log(v[0].param); \
1486 if (n == 1) mi1 = mi; \
1487 else mi1 = 0.5 * (std::log(v[2].param) - std::log(v[0].param)); \
1488 } else if (i >= n - 1) { \
1489 mi1 = std::log(v[i+1].param) - std::log(v[i].param); \
1490 if (n == 1) mi = mi1; \
1491 else mi = 0.5 * (std::log(v[i+1].param) - std::log(v[i-1].param)); \
1492 } else { \
1493 mi = 0.5 * (std::log(v[i+1].param) - std::log(v[i-1].param)); \
1494 mi1 = 0.5 * (std::log(v[i+2].param) - std::log(v[i ].param)); \
1495 } \
1496 real = std::exp(h00 * std::log(v[i].param) + h10 * mi + h01 * std::log(v[i+1].param) + h11 * mi1);
1497 
1498  // Real parameters
1499  INTERPOLATE(fVisibleDensity);
1500  if (real < 0.) real = 0.;
1501  holdingValues.fVisibleDensity = real;
1502  INTERPOLATELOG(fExplodeFactor);
1503  holdingValues.fExplodeFactor = real;
1504  INTERPOLATE(fFieldHalfAngle);
1505  if (real < 0.) real = 0.;
1506  holdingValues.fFieldHalfAngle = real;
1507  INTERPOLATELOG(fZoomFactor);
1508  holdingValues.fZoomFactor = real;
1509  INTERPOLATE(fDolly);
1510  holdingValues.fDolly = real;
1511  INTERPOLATE(fGlobalMarkerScale);
1512  if (real < 0.) real = 0.;
1513  holdingValues.fGlobalMarkerScale = real;
1514  INTERPOLATE(fGlobalLineWidthScale);
1515  if (real < 0.) real = 0.;
1516  holdingValues.fGlobalLineWidthScale = real;
1517 
1518  // Unit vectors
1519 #define INTERPOLATEUNITVECTOR(vector) \
1520 INTERPOLATE(vector.x()); x = real; \
1521 INTERPOLATE(vector.y()); y = real; \
1522 INTERPOLATE(vector.z()); z = real;
1523  INTERPOLATEUNITVECTOR(fViewpointDirection);
1524  holdingValues.fViewpointDirection = G4Vector3D(x,y,z).unit();
1525  INTERPOLATEUNITVECTOR(fUpVector);
1526  holdingValues.fUpVector = G4Vector3D(x,y,z).unit();
1527  INTERPOLATEUNITVECTOR(fRelativeLightpointDirection);
1528  holdingValues.fRelativeLightpointDirection = G4Vector3D(x,y,z).unit();
1529  INTERPOLATEUNITVECTOR(fActualLightpointDirection);
1530  holdingValues.fActualLightpointDirection = G4Vector3D(x,y,z).unit();
1531 
1532  // Un-normalised vectors
1533 #define INTERPOLATEVECTOR(vector) \
1534 INTERPOLATE(vector.x()); x = real; \
1535 INTERPOLATE(vector.y()); y = real; \
1536 INTERPOLATE(vector.z()); z = real;
1537  INTERPOLATEVECTOR(fScaleFactor);
1538  holdingValues.fScaleFactor = G4Vector3D(x,y,z);
1539 
1540  // Points
1541 #define INTERPOLATEPOINT(point) \
1542 INTERPOLATE(point.x()); x = real; \
1543 INTERPOLATE(point.y()); y = real; \
1544 INTERPOLATE(point.z()); z = real;
1545  INTERPOLATEPOINT(fExplodeCentre);
1546  holdingValues.fExplodeCentre = G4Point3D(x,y,z);
1547  INTERPOLATEPOINT(fCurrentTargetPoint);
1548  holdingValues.fCurrentTargetPoint = G4Point3D(x,y,z);
1549 
1550  // Colour
1551  G4double red, green, blue, alpha;
1552 #define INTERPOLATECOLOUR(colour) \
1553 INTERPOLATE(colour.GetRed()); red = real; \
1554 INTERPOLATE(colour.GetGreen()); green = real; \
1555 INTERPOLATE(colour.GetBlue()); blue = real; \
1556 INTERPOLATE(colour.GetAlpha()); alpha = real;
1557  INTERPOLATECOLOUR(fBackgroundColour);
1558  // Components are clamped to 0. <= component <= 1.
1559  holdingValues.fBackgroundColour = G4Colour(red,green,blue,alpha);
1560 
1561  // For some parameters we need to check some continuity
1562  G4bool continuous;
1563 #define CONTINUITY(quantity) \
1564  continuous = false; \
1565  /* This follows the logic of the INTERPOLATE macro above; see comments therein */ \
1566  if (i == 0) { \
1567  if (v[1].quantity == v[0].quantity) { \
1568  if (n == 1) continuous = true; \
1569  else if (v[2].quantity == v[0].quantity) \
1570  continuous = true; \
1571  } \
1572  } else if (i >= n - 1) { \
1573  if (v[i+1].quantity == v[i].quantity) { \
1574  if (n == 1) continuous = true; \
1575  else if (v[i+1].quantity == v[i-1].quantity) \
1576  continuous = true; \
1577  } \
1578  } else { \
1579  if (v[i-1].quantity == v[i].quantity && \
1580  v[i+1].quantity == v[i].quantity && \
1581  v[i+2].quantity == v[i].quantity) \
1582  continuous = true; \
1583  }
1584 
1585  G4double a, b, c, d;
1586 #define INTERPOLATEPLANE(plane) \
1587 INTERPOLATE(plane.a()); a = real; \
1588 INTERPOLATE(plane.b()); b = real; \
1589 INTERPOLATE(plane.c()); c = real; \
1590 INTERPOLATE(plane.d()); d = real;
1591 
1592  // Section plane
1593  CONTINUITY(fSection);
1594  if (continuous) {
1595  INTERPOLATEPLANE(fSectionPlane);
1596  holdingValues.fSectionPlane = G4Plane3D(a,b,c,d);
1597  }
1598 
1599  // Cutaway planes
1600  if (v[i].fCutawayPlanes.size()) {
1601  CONTINUITY(fCutawayPlanes.size());
1602  if (continuous) {
1603  for (size_t j = 0; j < v[i].fCutawayPlanes.size(); ++j) {
1604  INTERPOLATEPLANE(fCutawayPlanes[j]);
1605  holdingValues.fCutawayPlanes[j] = G4Plane3D(a,b,c,d);
1606  }
1607  }
1608  }
1609 
1610  // Vis attributes modifiers
1611  // Really, we are only interested in colour - other attributes can follow
1612  // the "crude" interpolation that is guaranteed above.
1613  static G4VisAttributes workingVA;
1614  if (v[i].fVisAttributesModifiers.size()) {
1615  CONTINUITY(fVisAttributesModifiers.size());
1616  if (continuous) {
1617  for (size_t j = 0; j < v[i].fVisAttributesModifiers.size(); ++j) {
1618  CONTINUITY(fVisAttributesModifiers[j].GetPVNameCopyNoPath());
1619  if (continuous) {
1620  CONTINUITY(fVisAttributesModifiers[j].GetVisAttributesSignifier());
1621  if (continuous) {
1622  if (v[i].fVisAttributesModifiers[j].GetVisAttributesSignifier() ==
1624  INTERPOLATECOLOUR(fVisAttributesModifiers[j].GetVisAttributes().GetColour());
1625  workingVA = v[i].fVisAttributesModifiers[j].GetVisAttributes();
1626  workingVA.SetColour(G4Colour(red,green,blue,alpha));
1627  holdingValues.fVisAttributesModifiers[j].SetVisAttributes(workingVA);
1628  }
1629  }
1630  }
1631  }
1632  }
1633  }
1634 
1635  // Time window parameters (for showing particles in flight)
1636  // Only two parameters are interpolated. The others are usually chosen
1637  // once and for all by the user for a given series of views - or at least,
1638  // if not, they will be interpolated by the default "crude" method above.
1639  INTERPOLATE(fStartTime)
1640  holdingValues.fStartTime = real;
1641  INTERPOLATE(fEndTime)
1642  holdingValues.fEndTime = real;
1643 
1644  // Increment counters
1645  iInterpolationPoint++;
1646  t += dt;
1647  if (iInterpolationPoint > nInterpolationPoints) {
1648  iInterpolationPoint = 1; // Ready for next interval.
1649  t = dt;
1650  iInterval++;
1651  }
1652  if (iInterval >= nIntervals) {
1653  iInterpolationPoint = 0; // Ready for a complete restart.
1654  t = 0.;
1655  iInterval = 0;
1656  return 0;
1657  }
1658 
1659  return &holdingValues;
1660 }