Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/Vtk/src/G4VtkViewer.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 #include <cmath>
 27 
 28 #include "G4VtkViewer.hh"
 29 
 30 #include <CLHEP/Units/PhysicalConstants.h>
 31 
 32 #include "G4Transform3D.hh"
 33 #include "G4VSceneHandler.hh"
 34 #include "G4VtkCutterPipeline.hh"
 35 #include "G4VtkPolydataInstanceAppendPipeline.hh"
 36 #include "G4VtkPolydataInstanceBakePipeline.hh"
 37 #include "G4VtkPolydataInstancePipeline.hh"
 38 #include "G4VtkPolydataInstanceTensorPipeline.hh"
 39 #include "G4VtkSceneHandler.hh"
 40 #include "G4VtkUtility.hh"
 41 #include "G4VtkVisContext.hh"
 42 
 43 #include <vtk3DSImporter.h>
 44 #include <vtkBMPWriter.h>
 45 #include <vtkIVExporter.h>  // open inventor
 46 #include <vtkImageWriter.h>
 47 #include <vtkImplicitPlaneRepresentation.h>
 48 #include <vtkImplicitPlaneWidget2.h>
 49 #include <vtkJPEGWriter.h>
 50 #include <vtkLightCollection.h>
 51 #include <vtkOBJExporter.h>
 52 #include <vtkOBJImporter.h>
 53 #include <vtkGLTFExporter.h>
 54 #include <vtkOOGLExporter.h>
 55 #include <vtkX3DExporter.h>
 56 #include <vtkJSONRenderWindowExporter.h>
 57 #include <vtkVtkJSSceneGraphSerializer.h>
 58 //#include <vtkBufferedArchiver.h>
 59 #include <vtkPNGWriter.h>
 60 #include <vtkPNMWriter.h>
 61 #include <vtkPOVExporter.h>
 62 #include <vtkPostScriptWriter.h>
 63 #include <vtkRIBExporter.h>  // Renderman
 64 #include <vtkRendererCollection.h>
 65 #include <vtkSingleVTPExporter.h>
 66 #include <vtkTIFFWriter.h>
 67 #include <vtkVRMLExporter.h>
 68 #include <vtkVRMLImporter.h>
 69 #include <vtkWindowToImageFilter.h>
 70 #include <vtkX3DExporter.h>
 71 
 72 // Readers (vtkDataReader)
 73 
 74 #include <vtkCameraPass.h>
 75 #include <vtkOpenGLRenderer.h>
 76 #include <vtkRenderPass.h>
 77 #include <vtkRenderPassCollection.h>
 78 #include <vtkSequencePass.h>
 79 #include <vtkShadowMapBakerPass.h>
 80 #include <vtkShadowMapPass.h>
 81 
 82 G4VtkViewer::G4VtkViewer(G4VSceneHandler& sceneHandler, const G4String& name)
 83   : G4VViewer(sceneHandler, sceneHandler.IncrementViewCount(), name)
 84 {
 85   vtkObject::GlobalWarningDisplayOff();
 86 
 87   // Set default and current view parameters
 88   fVP.SetAutoRefresh(true);
 89   fDefaultVP.SetAutoRefresh(true);
 90 }
 91 
 92 void G4VtkViewer::Initialise()
 93 {
 94   _renderWindow = vtkRenderWindow::New();
 95   renderWindowInteractor = vtkRenderWindowInteractor::New();
 96 
 97 #ifdef G4VTKDEBUG
 98   G4cout << "G4VtkViewer::G4VtkViewer" << G4endl;
 99   G4cout << "G4VtkViewer::G4VtkViewer> " << fVP.GetWindowSizeHintX() << " "
100          << fVP.GetWindowSizeHintY() << G4endl;
101   G4cout << "G4VtkViewer::G4VtkViewer> " << fVP.GetWindowLocationHintX() << " "
102          << fVP.GetWindowLocationHintY() << G4endl;
103 #endif
104 
105   // Need windowSizeX/Y - obtain from _renderWindow?
106   G4int screenSizeX = _renderWindow->GetScreenSize()[0];
107   G4int screenSizeY = _renderWindow->GetScreenSize()[1];
108   G4int positionX = fVP.GetWindowLocationHintX();
109   if (fVP.IsWindowLocationHintXNegative()) {
110     positionX = screenSizeX + positionX - fVP.GetWindowSizeHintX();
111   }
112   G4int positionY = fVP.GetWindowLocationHintY();
113   if (!fVP.IsWindowLocationHintYNegative()) {
114     positionY = screenSizeY + positionY - fVP.GetWindowSizeHintY();
115   }
116   _renderWindow->SetPosition(positionX, positionY);
117 #ifdef __APPLE__
118   // Adjust window size for Apple to make it correspond to OpenGL.
119   // Maybe it's OpenGL that shoud be adjusted.
120   const G4double pixelFactor = 2.;
121 #else
122   const G4double pixelFactor = 1.;
123 #endif
124   _renderWindow->SetSize(pixelFactor * fVP.GetWindowSizeHintX(),
125                          pixelFactor * fVP.GetWindowSizeHintY());
126   _renderWindow->SetWindowName("Vtk viewer");
127 
128   _renderWindow->AddRenderer(renderer);
129   renderWindowInteractor->SetRenderWindow(_renderWindow);
130 
131   // TODO proper camera parameter settings
132   camera->SetPosition(0, 0, 1000);
133   camera->SetFocalPoint(0, 0, 0);
134   renderer->SetActiveCamera(camera);
135 
136   // Hidden line removal
137   renderer->SetUseHiddenLineRemoval(0);
138 
139   // Shadows
140   renderer->SetUseShadows(0);
141 
142   // Set callback to match VTK parameters to Geant4
143   geant4Callback->SetGeant4ViewParameters(&fVP);
144   renderer->AddObserver(vtkCommand::EndEvent, geant4Callback);
145 
146   vtkSmartPointer<G4VtkInteractorStyle> style = vtkSmartPointer<G4VtkInteractorStyle>::New();
147   renderWindowInteractor->SetInteractorStyle(style);
148 }
149 
150 G4VtkViewer::~G4VtkViewer()
151 {
152 #ifdef G4VTKDEBUG
153   G4cout << "G4VtkViewer::~G4VtkViewer()" << G4endl;
154 #endif
155 }
156 
157 void G4VtkViewer::SetView()
158 {
159 #ifdef G4VTKDEBUG
160   G4cout << "G4VtkViewer::SetView()" << G4endl;
161 #endif
162   // background colour
163   const G4Colour backgroundColour = fVP.GetBackgroundColour();
164   renderer->SetBackground(backgroundColour.GetRed(), backgroundColour.GetGreen(),
165                           backgroundColour.GetBlue());
166 
167   // target and camera positions
168   G4double radius = fSceneHandler.GetExtent().GetExtentRadius();
169   if (radius <= 0.) {
170     radius = 1.;
171   }
172 
173   if (firstSetView) cameraDistance = fVP.GetCameraDistance(radius);
174   G4Point3D viewpointDirection = fVP.GetViewpointDirection();
175   G4Point3D targetPosition = fVP.GetCurrentTargetPoint();
176   G4double zoomFactor = fVP.GetZoomFactor();
177   G4double fieldHalfAngle = fVP.GetFieldHalfAngle();
178 
179   G4Point3D cameraPosition = targetPosition + viewpointDirection.unit() /zoomFactor  * cameraDistance;
180 
181   vtkCamera* activeCamera = renderer->GetActiveCamera();
182   activeCamera->SetFocalPoint(targetPosition.x(), targetPosition.y(), targetPosition.z());
183   activeCamera->SetViewAngle(2*fieldHalfAngle / CLHEP::pi * 180);
184   activeCamera->SetPosition(cameraPosition.x(), cameraPosition.y(), cameraPosition.z());
185   activeCamera->SetParallelScale(cameraDistance / zoomFactor);
186 
187   if (fieldHalfAngle == 0) {
188     activeCamera->SetParallelProjection(1);
189   }
190   else {
191     activeCamera->SetParallelProjection(0);
192   }
193 
194   // need to set camera distance and parallel scale on first set view
195   if (firstSetView) {
196     geant4Callback->SetVtkInitialValues(cameraDistance, cameraDistance);
197     activeCamera->SetParallelScale(cameraDistance);
198     firstSetView = false;
199   }
200 
201   // camera up direction
202   const G4Vector3D upVector = fVP.GetUpVector();
203   renderer->GetActiveCamera()->SetViewUp(upVector.x(), upVector.y(), upVector.z());
204 
205   // Light
206   const G4Vector3D lightDirection = fVP.GetLightpointDirection();
207   G4bool lightsMoveWithCamera = fVP.GetLightsMoveWithCamera();
208   G4Vector3D lightPosition = targetPosition + lightDirection.unit() * cameraDistance;
209 
210   vtkLightCollection* currentLights = renderer->GetLights();
211   if (currentLights->GetNumberOfItems() != 0) {
212     auto currentLight = dynamic_cast<vtkLight*>(currentLights->GetItemAsObject(0));
213     if (currentLight != nullptr) {
214       currentLight->SetPosition(lightPosition.x(), lightPosition.y(), lightPosition.z());
215       if (lightsMoveWithCamera) {
216         currentLight->SetLightTypeToCameraLight();
217       }
218       else {
219         currentLight->SetLightTypeToSceneLight();
220       }
221     }
222   }
223 
224   // cut away
225   if (fVP.IsCutaway()) {
226     G4cout << "Add cutaway planes" << G4endl;
227   }
228 
229   // section
230   if (fVP.IsSection()) {
231     G4cout << "Add section" << G4endl;
232   }
233 }
234 
235 void G4VtkViewer::ClearView()
236 {
237 #ifdef G4VTKDEBUG
238   G4cout << "G4VtkViewer::ClearView()" << G4endl;
239 #endif
240 
241   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
242   G4VtkStore& ts = fVtkSceneHandler.GetTransientStore();
243   ts.Clear();
244 
245   G4VtkStore& s = fVtkSceneHandler.GetStore();
246   s.Clear();
247 }
248 
249 void G4VtkViewer::DrawView()
250 {
251 #ifdef G4VTKDEBUG
252   G4cout << "G4VtkViewer::DrawView()" << G4endl;
253 #endif
254 
255   // First, a view should decide when to re-visit the G4 kernel.
256   // Sometimes it might not be necessary, e.g., if the scene is stored
257   // in a graphical database (e.g., OpenGL's display lists) and only
258   // the viewing angle has changed.  But graphics systems without a
259   // graphical database will always need to visit the G4 kernel.
260 
261   NeedKernelVisit();  // Default is - always visit G4 kernel.
262 
263   // Note: this routine sets the fNeedKernelVisit flag of *all* the
264   // views of the scene.
265 
266   ProcessView();  // The basic logic is here.
267 
268   // Add HUD
269   AddViewHUD();
270 
271   // Add clipper and cutter widgets
272   auto g4p = G4Plane3D();
273   AddCutterPlaneWidget(g4p);
274   AddClipperPlaneWidget(g4p);
275 
276   // Add camera orientation widget
277   AddCameraOrientationWidget();
278 
279   // ...before finally...
280   FinishView();  // Flush streams and/or swap buffers.
281 }
282 
283 void G4VtkViewer::DrawShadows()
284 {
285   _renderWindow->SetMultiSamples(0);
286 
287   vtkNew<vtkShadowMapPass> shadows;
288   vtkNew<vtkSequencePass> seq;
289 
290   vtkNew<vtkRenderPassCollection> passes;
291   passes->AddItem(shadows->GetShadowMapBakerPass());
292   passes->AddItem(shadows);
293   seq->SetPasses(passes);
294 
295   vtkNew<vtkCameraPass> cameraP;
296   cameraP->SetDelegatePass(seq);
297 
298   // tell the renderer to use our render pass pipeline
299   auto glrenderer = dynamic_cast<vtkOpenGLRenderer*>(renderer.GetPointer());
300   glrenderer->SetPass(cameraP);
301 }
302 
303 void G4VtkViewer::ShowView()
304 {
305 #ifdef G4VTKDEBUG
306   G4cout << "G4VtkViewer::ShowView()" << G4endl;
307 #endif
308 
309   infoTextActor->GetTextProperty()->SetFontSize(28);
310   G4Colour colour = fVP.GetBackgroundColour();
311 
312   // make sure text is always visible
313   infoTextActor->GetTextProperty()->SetColor(std::fmod(colour.GetRed() + 0.5, 1.0),
314                                              std::fmod(colour.GetGreen() + 0.5, 1.0),
315                                              std::fmod(colour.GetBlue() + 0.5, 1.0));
316   infoTextActor->GetTextProperty()->SetFontSize(20);
317   infoCallback->SetTextActor(infoTextActor);
318   renderer->AddObserver(vtkCommand::EndEvent, infoCallback);
319   geant4Callback->SetGeant4ViewParameters(&fVP);
320   renderer->AddObserver(vtkCommand::EndEvent, geant4Callback);
321 }
322 
323 void G4VtkViewer::FinishView()
324 {
325 #ifdef G4VTKDEBUG
326   G4cout << "G4VtkViewer::FinishView()" << G4endl;
327 #endif
328 
329   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
330   fVtkSceneHandler.Modified();
331 
332   _renderWindow->GetInteractor()->Initialize();
333   _renderWindow->Render();
334 
335   if (firstFinishView) {
336     firstFinishView = false;
337   }
338   else {
339     _renderWindow->GetInteractor()->Start();
340   }
341 }
342 
343 void G4VtkViewer::ExportScreenShot(G4String path, G4String format)
344 {
345   vtkImageWriter* imWriter = nullptr;
346 
347   if (format == "bmp") {
348     imWriter = vtkBMPWriter::New();
349   }
350   else if (format == "jpg") {
351     imWriter = vtkJPEGWriter::New();
352   }
353   else if (format == "pnm") {
354     imWriter = vtkPNMWriter::New();
355   }
356   else if (format == "png") {
357     imWriter = vtkPNGWriter::New();
358   }
359   else if (format == "tiff") {
360     imWriter = vtkTIFFWriter::New();
361   }
362   else if (format == "ps") {
363     imWriter = vtkPostScriptWriter::New();
364   }
365   else {
366     return;
367   }
368 
369   _renderWindow->Render();
370 
371   vtkSmartPointer<vtkWindowToImageFilter> winToImage =
372     vtkSmartPointer<vtkWindowToImageFilter>::New();
373   winToImage->SetInput(_renderWindow);
374   winToImage->SetScale(1);
375   if (format == "ps") {
376     winToImage->SetInputBufferTypeToRGB();
377     winToImage->ReadFrontBufferOff();
378     winToImage->Update();
379   }
380   else {
381     winToImage->SetInputBufferTypeToRGBA();
382   }
383 
384   imWriter->SetFileName((path + "." + format).c_str());
385   imWriter->SetInputConnection(winToImage->GetOutputPort());
386   imWriter->Write();
387 }
388 
389 void G4VtkViewer::ExportOBJScene(G4String path)
390 {
391   vtkSmartPointer<vtkOBJExporter> exporter = vtkSmartPointer<vtkOBJExporter>::New();
392   exporter->SetRenderWindow(_renderWindow);
393   exporter->SetFilePrefix(path.c_str());
394   exporter->Write();
395 }
396 
397 void G4VtkViewer::ExportVRMLScene(G4String path)
398 {
399   vtkSmartPointer<vtkVRMLExporter> exporter = vtkSmartPointer<vtkVRMLExporter>::New();
400   exporter->SetRenderWindow(_renderWindow);
401   exporter->SetFileName((path + ".vrml").c_str());
402   exporter->Write();
403 }
404 
405 void G4VtkViewer::ExportVTPScene(G4String path)
406 {
407   vtkSmartPointer<vtkSingleVTPExporter> exporter = vtkSmartPointer<vtkSingleVTPExporter>::New();
408   exporter->SetRenderWindow(_renderWindow);
409   exporter->SetFileName((path + ".vtp").c_str());
410   exporter->Write();
411 }
412 
413 void G4VtkViewer::ExportGLTFScene(G4String fileName) {
414   vtkSmartPointer<vtkGLTFExporter> exporter = vtkSmartPointer<vtkGLTFExporter>::New();
415   exporter->SetRenderWindow(_renderWindow);
416   exporter->SetFileName((fileName+".gltf").c_str());
417   exporter->InlineDataOn();
418   exporter->Write();
419 }
420 
421 void G4VtkViewer::ExportX3DScene(G4String fileName) {
422   vtkSmartPointer<vtkX3DExporter> exporter = vtkSmartPointer<vtkX3DExporter>::New();
423   exporter->SetRenderWindow(_renderWindow);
424   exporter->SetFileName((fileName+".x3d").c_str());
425   exporter->Write();
426 }
427 
428 
429 void G4VtkViewer::ExportJSONRenderWindowScene(G4String /*fileName*/) {
430   vtkSmartPointer<vtkJSONRenderWindowExporter> exporter = vtkSmartPointer<vtkJSONRenderWindowExporter>::New();
431   vtkSmartPointer<vtkVtkJSSceneGraphSerializer> serializer = vtkSmartPointer<vtkVtkJSSceneGraphSerializer>::New();
432   exporter->SetRenderWindow(_renderWindow);
433   exporter->SetSerializer(serializer);
434   exporter->Write();
435 }
436 
437 void G4VtkViewer::ExportVTPCutter(G4String fileName)
438 {
439   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
440   G4VtkStore& s = fVtkSceneHandler.GetStore();
441 
442   // create new renderer
443   vtkNew<vtkRenderer> tempRenderer;
444 
445   // loop over pipelines
446   auto separate = s.GetSeparatePipeMap();
447   for (const auto& i : separate) {
448     i.second->GetActor();
449     auto children = i.second->GetChildPipelines();
450     for (auto child : children) {
451       if (child->GetTypeName() == "G4VtkCutterPipeline") {
452         auto childCutter = dynamic_cast<G4VtkCutterPipeline*>(child);
453         tempRenderer->AddActor(childCutter->GetActor());
454       }
455     }
456   }
457 
458   auto tensor = s.GetTensorPipeMap();
459   for (const auto& i : tensor) {
460     i.second->GetActor();
461     auto children = i.second->GetChildPipelines();
462     for (auto child : children) {
463       if (child->GetTypeName() == "G4VtkCutterPipeline") {
464         auto childCutter = dynamic_cast<G4VtkCutterPipeline*>(child);
465         tempRenderer->AddActor(childCutter->GetActor());
466       }
467     }
468   }
469 
470   auto append = s.GetAppendPipeMap();
471   for (const auto& i : append) {
472     i.second->GetActor();
473     auto children = i.second->GetChildPipelines();
474     for (auto child : children) {
475       if (child->GetTypeName() == "G4VtkCutterPipeline") {
476         auto childCutter = dynamic_cast<G4VtkCutterPipeline*>(child);
477         tempRenderer->AddActor(childCutter->GetActor());
478       }
479     }
480   }
481 
482   auto baked = s.GetBakePipeMap();
483   for (const auto& i : baked) {
484     i.second->GetActor();
485     auto children = i.second->GetChildPipelines();
486     for (auto child : children) {
487       if (child->GetTypeName() == "G4VtkCutterPipeline") {
488         auto childCutter = dynamic_cast<G4VtkCutterPipeline*>(child);
489         tempRenderer->AddActor(childCutter->GetActor());
490       }
491     }
492   }
493 
494   vtkNew<vtkRenderWindow> tempRenderWindow;
495   tempRenderWindow->AddRenderer(tempRenderer);
496   vtkNew<vtkSingleVTPExporter> exporter;
497   exporter->SetRenderWindow(tempRenderWindow);
498   exporter->SetFileName(fileName.c_str());
499   exporter->Write();
500 }
501 
502 void G4VtkViewer::ExportFormatStore(G4String fileName, G4String storeName)
503 {
504   vtkSmartPointer<vtkRenderWindow> tempRenderWindow;
505   vtkNew<vtkRenderer> tempRenderer;
506   tempRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
507   tempRenderWindow->AddRenderer(tempRenderer);
508 
509   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
510 
511   if (storeName == "transient") {
512     G4VtkStore& store = fVtkSceneHandler.GetTransientStore();
513     store.AddToRenderer(tempRenderer);
514   }
515   else {
516     G4VtkStore& store = fVtkSceneHandler.GetStore();
517     store.AddToRenderer(tempRenderer);
518   }
519 
520   if (fileName.find("obj") != std::string::npos) {
521     vtkNew<vtkOBJExporter> exporter;
522     exporter->SetRenderWindow(tempRenderWindow);
523     exporter->SetFilePrefix(fileName.c_str());
524     exporter->Write();
525   }
526   else if (fileName.find("vrml") != std::string::npos) {
527     vtkNew<vtkVRMLExporter> exporter;
528     exporter->SetRenderWindow(tempRenderWindow);
529     exporter->SetFileName(fileName.c_str());
530     exporter->Write();
531   }
532   else if (fileName.find("vtp") != std::string::npos) {
533     vtkNew<vtkSingleVTPExporter> exporter;
534     exporter->SetRenderWindow(tempRenderWindow);
535     exporter->SetFileName(fileName.c_str());
536     exporter->Write();
537   }
538   else if (fileName.find("gltf") != std::string::npos) {
539     vtkNew<vtkGLTFExporter> exporter;
540     exporter->SetRenderWindow(tempRenderWindow);
541     exporter->SetFileName(fileName.c_str());
542     exporter->InlineDataOn();
543     exporter->Write();
544   }
545 }
546 
547 void G4VtkViewer::AddViewHUD()
548 {
549   // make sure text is always visible
550   G4Colour colour = fVP.GetBackgroundColour();
551   infoTextActor->GetTextProperty()->SetColor(std::fmod(colour.GetRed() + 0.5, 1.0),
552                                              std::fmod(colour.GetGreen() + 0.5, 1.0),
553                                              std::fmod(colour.GetBlue() + 0.5, 1.0));
554   infoTextActor->GetTextProperty()->SetFontSize(20);
555   infoCallback->SetTextActor(infoTextActor);
556   renderer->AddObserver(vtkCommand::EndEvent, infoCallback);
557   renderer->AddActor(infoTextActor);
558   infoTextActor->SetVisibility(0);
559 }
560 
561 void G4VtkViewer::AddClipperPlaneWidget(const G4Plane3D& plane)
562 {
563   vtkNew<vtkIPWCallback> clipperCallback;
564   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
565   G4VtkStore& store = fVtkSceneHandler.GetStore();
566   clipperCallback->SetStore(&store);
567   clipperCallback->SetUpdatePipelineName("clipper", "clipper");
568 
569   G4double bounds[6];
570   store.GetBounds(bounds);
571   auto vplane = G4Plane3DToVtkPlane(plane);
572   clipperPlaneRepresentation->SetPlaceFactor(
573     1.25);  // This must be set prior to placing the widget.
574   clipperPlaneRepresentation->PlaceWidget(bounds);
575   clipperPlaneRepresentation->SetNormal(vplane->GetNormal());
576 
577   vtkNew<vtkPropCollection> planeRepActors;
578   clipperPlaneRepresentation->GetActors(planeRepActors);
579   planeRepActors->InitTraversal();
580 
581   SetWidgetInteractor(clipperPlaneWidget);
582   clipperPlaneWidget->SetRepresentation(clipperPlaneRepresentation);
583   clipperPlaneWidget->AddObserver(vtkCommand::InteractionEvent, clipperCallback);
584 
585   clipperPlaneWidget->SetEnabled(0);
586 }
587 
588 void G4VtkViewer::AddCutterPlaneWidget(const G4Plane3D& plane)
589 {
590   vtkNew<vtkIPWCallback> cutterCallback;
591   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
592   G4VtkStore& store = fVtkSceneHandler.GetStore();
593   cutterCallback->SetStore(&store);
594   cutterCallback->SetUpdatePipelineName("cutter", "cutter");
595 
596   G4double bounds[6];
597   store.GetBounds(bounds);
598   auto vplane = G4Plane3DToVtkPlane(plane);
599   cutterPlaneRepresentation->SetPlaceFactor(1.25);  // This must be set prior to placing the widget.
600   cutterPlaneRepresentation->PlaceWidget(bounds);
601   cutterPlaneRepresentation->SetNormal(vplane->GetNormal());
602 
603   SetWidgetInteractor(cutterPlaneWidget);
604   cutterPlaneWidget->SetRepresentation(cutterPlaneRepresentation);
605   cutterPlaneWidget->AddObserver(vtkCommand::InteractionEvent, cutterCallback);
606 
607   cutterPlaneWidget->SetEnabled(0);
608 }
609 
610 void G4VtkViewer::EnableShadows()
611 {
612   renderer->SetUseShadows(1);
613 }
614 
615 void G4VtkViewer::DisableShadows()
616 {
617   renderer->SetUseShadows(0);
618 }
619 
620 void G4VtkViewer::EnableHUD()
621 {
622   infoTextActor->SetVisibility(1);
623 }
624 
625 void G4VtkViewer::DisableHUD()
626 {
627   infoTextActor->SetVisibility(0);
628 }
629 
630 void G4VtkViewer::EnableClipper(const G4Plane3D& plane, G4bool bWidget)
631 {
632   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
633   G4VtkStore& s = fVtkSceneHandler.GetStore();
634   G4String name = G4String("clipper");
635   s.AddClipper(name, plane);
636   if (bWidget) {
637     EnableClipperWidget();
638   }
639 }
640 
641 void G4VtkViewer::DisableClipper()
642 {
643   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
644   G4VtkStore& s = fVtkSceneHandler.GetStore();
645   s.RemoveClipper("clipper");
646 }
647 
648 void G4VtkViewer::EnableClipperWidget()
649 {
650   clipperPlaneWidget->SetEnabled(1);
651 }
652 
653 void G4VtkViewer::DisableClipperWidget()
654 {
655   clipperPlaneWidget->SetEnabled(0);
656 }
657 
658 void G4VtkViewer::EnableCutter(const G4Plane3D& plane, G4bool bWidget)
659 {
660   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
661   G4VtkStore& s = fVtkSceneHandler.GetStore();
662   G4String name = G4String("cutter");
663   s.AddCutter(name, plane);
664   if (bWidget) {
665     EnableCutterWidget();
666   }
667 }
668 
669 void G4VtkViewer::DisableCutter(G4String /*name*/)
670 {
671   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
672   G4VtkStore& s = fVtkSceneHandler.GetStore();
673   s.RemoveCutter("cutter");
674 }
675 
676 void G4VtkViewer::EnableCutterWidget()
677 {
678   G4cout << "enable cutter widget" << G4endl;
679   cutterPlaneWidget->SetEnabled(1);
680 }
681 
682 void G4VtkViewer::DisableCutterWidget()
683 {
684   cutterPlaneWidget->SetEnabled(0);
685 }
686 
687 void G4VtkViewer::AddCameraOrientationWidget()
688 {
689   camOrientWidget->SetParentRenderer(renderer);
690   // Enable the widget.
691   camOrientWidget->Off();
692 }
693 
694 void G4VtkViewer::EnableCameraOrientationWidget()
695 {
696   camOrientWidget->On();
697 }
698 
699 void G4VtkViewer::DisableCameraOrientationWidget()
700 {
701   camOrientWidget->Off();
702 }
703 
704 void G4VtkViewer::AddImageOverlay(const G4String& fileName, const G4double alpha,
705                                   const G4double imageBottomLeft[2],
706                                   const G4double worldBottomLeft[2],
707                                   const G4double imageTopRight[2], const G4double worldTopRight[2],
708                                   const G4double rotation[3], const G4double translation[3])
709 {
710   auto xScale = (worldTopRight[0] - worldBottomLeft[0]) / (imageTopRight[0] - imageBottomLeft[0]);
711   auto yScale = -(worldTopRight[1] - worldBottomLeft[1]) / (imageTopRight[1] - imageBottomLeft[1]);
712 
713   G4cout << xScale << " " << yScale << G4endl;
714   auto transformation = G4Transform3D::Identity;
715   auto scal = G4Scale3D(xScale, yScale, 1);
716   auto rotx = G4RotateX3D(rotation[0]/180*CLHEP::pi);
717   auto roty = G4RotateY3D(rotation[1]/180*CLHEP::pi);
718   auto rotz = G4RotateZ3D(rotation[2]/180*CLHEP::pi);
719   auto tranImg = G4Translate3D(  -std::fabs(imageBottomLeft[0] + imageTopRight[0]) / 2.0,
720                                  -std::fabs(imageBottomLeft[1] + imageTopRight[1]) / 2.0,
721                                  0);
722   auto tran = G4Translate3D(translation[0],
723                             translation[1],
724                             translation[2]);
725 
726   G4cout << translation[0] << " " << translation[1] << " " << translation[2] << G4endl;
727   transformation = tran * rotz * roty * rotx * scal * tranImg * transformation;
728 
729   G4cout << transformation.dx() << " " << transformation.dy() << " " << transformation.dz() << G4endl;
730   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
731   G4VtkStore& st = fVtkSceneHandler.GetTransientStore();
732 
733   G4VtkVisContext vc = G4VtkVisContext(this, nullptr, false, transformation);
734   vc.alpha = alpha;
735   st.AddNonG4ObjectImage(fileName, vc);
736 }
737 
738 void G4VtkViewer::AddGeometryOverlay(const G4String& fileName, const G4double colour[3],
739                                      const G4double alpha, const G4String& representation,
740                                      const G4double scale[3], const G4double rotation[3],
741                                      const G4double translation[3])
742 {
743   auto transformation = G4Transform3D::Identity;
744   auto scal = G4Scale3D(scale[0], scale[1], scale[2]);
745   auto rotx = G4RotateX3D(rotation[0]);
746   auto roty = G4RotateY3D(rotation[1]);
747   auto rotz = G4RotateZ3D(rotation[2]);
748   auto tran = G4Translate3D(translation[0], translation[1], translation[2]);
749 
750   transformation = tran * rotz * roty * rotx * scal * transformation;
751 
752   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
753   G4VtkStore& st = fVtkSceneHandler.GetTransientStore();
754 
755 
756   G4VtkVisContext vc = G4VtkVisContext(this, nullptr, false, transformation);
757   if (representation == "w")
758     vc.fDrawingStyle = G4ViewParameters::wireframe;
759   else if (representation == "s")
760     vc.fDrawingStyle = G4ViewParameters::hlhsr;
761   vc.alpha = alpha;
762   vc.red = colour[0];
763   vc.green = colour[1];
764   vc.blue = colour[2];
765   st.AddNonG4ObjectPolydata(fileName, vc);
766 }
767 
768 void G4VtkViewer::Print()
769 {
770   cutterPlaneRepresentation->VisibilityOff();
771 
772   G4cout << "Number of VTK props>  " << renderer->GetNumberOfPropsRendered() << G4endl;
773   G4cout << "Number of VTK actors> " << renderer->GetActors()->GetNumberOfItems() << G4endl;
774   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
775   G4VtkStore& s = fVtkSceneHandler.GetStore();
776   G4VtkStore& st = fVtkSceneHandler.GetTransientStore();
777   s.Print();
778   st.Print();
779 }
780 
781 void G4VtkViewer::SetPolyhedronPipeline(const G4String& type)
782 {
783   // Get the scene handler
784   auto& fVtkSceneHandler = dynamic_cast<G4VtkSceneHandler&>(fSceneHandler);
785   fVtkSceneHandler.SetPolyhedronPipeline(type);
786 }
787 
788 void G4VtkViewer::SetWidgetInteractor(vtkAbstractWidget* widget)
789 {
790   widget->SetInteractor(_renderWindow->GetInteractor());
791 }
792