Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/Qt3D/src/G4Qt3DSceneHandler.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 // John Allison  17th June 2019
 27 
 28 #include "G4Qt3DSceneHandler.hh"
 29 
 30 #include "G4PhysicalVolumeModel.hh"
 31 #include "G4LogicalVolumeModel.hh"
 32 #include "G4VPhysicalVolume.hh"
 33 #include "G4LogicalVolume.hh"
 34 #include "G4TransportationManager.hh"
 35 #include "G4Box.hh"
 36 #include "G4Polyline.hh"
 37 #include "G4Polymarker.hh"
 38 #include "G4Text.hh"
 39 #include "G4Circle.hh"
 40 #include "G4Square.hh"
 41 #include "G4Polyhedron.hh"
 42 #include "G4Scene.hh"
 43 #include "G4Threading.hh"
 44 #include "G4Mesh.hh"
 45 #include "G4PseudoScene.hh"
 46 #include "G4VisManager.hh"
 47 
 48 #include "G4Qt3DViewer.hh"
 49 #include "G4Qt3DUtils.hh"
 50 #include "G4Qt3DQEntity.hh"
 51 
 52 #include <Qt3DCore>
 53 #include <Qt3DExtras>
 54 #include <Qt3DRender>
 55 
 56 #include <utility>
 57 
 58 #define G4warn G4cout
 59 
 60 // Qt3D seems to offer a choice of type - float or double. It would be nice
 61 // to use double since it offers the prospect of higher precision, hopefully
 62 // avoiding some issues that we see at high zoom. But it currently gives the
 63 // following warning:
 64 // Qt5: "findBoundingVolumeComputeData: Position attribute not
 65 // suited for bounding volume computation",
 66 // Qt6: "Failed to build graphics pipeline: Geometry doesn't match expected layout
 67 // An attribute type is not supported "vertexPosition" Qt3DCore::QAttribute::Double"
 68 // so for now we use float.
 69 #define PRECISION float
 70 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
 71 #define BASETYPE Qt3DRender::QAttribute::Float
 72 #else
 73 #define BASETYPE Qt3DCore::QAttribute::Float
 74 #endif
 75 
 76 // Qt3D types move between namespaces between 5 and 6
 77 namespace G4Qt3DCompat
 78 {
 79 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
 80   using Qt3DRender::QAttribute;
 81   using Qt3DRender::QBuffer;
 82   using Qt3DRender::QGeometry;
 83 #else
 84   using Qt3DCore::QAttribute;
 85   using Qt3DCore::QBuffer;
 86   using Qt3DCore::QGeometry;
 87 #endif
 88 }
 89 
 90 G4int G4Qt3DSceneHandler::fSceneIdCount = 0;
 91 
 92 G4Qt3DSceneHandler::G4Qt3DSceneHandler
 93  (G4VGraphicsSystem& system, const G4String& name)
 94 : G4VSceneHandler(system, fSceneIdCount++, name)
 95 ,fpQt3DScene(nullptr)
 96 ,fpTransientObjects(nullptr)
 97 ,fpPersistentObjects(nullptr)
 98 {
 99 #ifdef G4QT3DDEBUG
100   G4cout << "G4Qt3DSceneHandler::G4Qt3DSceneHandler called" << G4endl;
101 #endif
102   fpQt3DScene = new Qt3DCore::QEntity;
103   fpQt3DScene->setObjectName("G4Qt3DSceneRoot");
104   EstablishG4Qt3DQEntities();
105 }
106 
107 G4Qt3DSceneHandler::~G4Qt3DSceneHandler()
108 {
109   if (fpQt3DScene) {
110     G4Qt3DUtils::delete_components_and_children_of_entity_recursively(fpQt3DScene);
111     delete fpQt3DScene;
112   }
113 }
114 
115 void G4Qt3DSceneHandler::EstablishG4Qt3DQEntities()
116 {
117   fpTransientObjects  = new G4Qt3DQEntity(fpQt3DScene);  // Hangs from root
118   fpTransientObjects  ->setObjectName("G4Qt3DTORoot");
119   fpPersistentObjects = new G4Qt3DQEntity(fpQt3DScene);  // Hangs from root
120   fpPersistentObjects ->setObjectName("G4Qt3DPORoot");
121 
122   // Physical volume objects hang from POs
123   fpPhysicalVolumeObjects.clear();
124   if (fpScene) {
125     const auto& sceneModels = fpScene->GetRunDurationModelList();
126     for (const auto& sceneModel : sceneModels) {
127       const auto& pvModel = dynamic_cast<G4PhysicalVolumeModel*>(sceneModel.fpModel);
128       if (pvModel) {
129         auto entity = new G4Qt3DQEntity(fpPersistentObjects);
130         const auto& pv = pvModel->GetTopPhysicalVolume();
131         entity->setObjectName("G4Qt3DPORoot_"+QString(pv->GetName()));
132         entity->SetPVNodeID(G4PhysicalVolumeModel::G4PhysicalVolumeNodeID(pv));
133         fpPhysicalVolumeObjects.push_back(entity);
134       }
135     }
136   }
137 }
138 
139 G4Qt3DQEntity* G4Qt3DSceneHandler::CreateNewNode()
140 {
141   // Create a G4Qt3DQEntity node suitable for next solid or primitive
142 
143   G4Qt3DQEntity* newNode = nullptr;
144 
145   if (fReadyForTransients) {  // All transients hang from this node
146     newNode = new G4Qt3DQEntity(fpTransientObjects);
147     G4String name = fpModel? fpModel->GetGlobalTag(): G4String("User");
148     newNode->setObjectName(name.c_str());
149     return newNode;
150   }
151 
152   G4PhysicalVolumeModel* pPVModel =
153     dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
154 
155   if (!pPVModel) {  // Persistent objects (e.g., axes)
156     newNode = new G4Qt3DQEntity(fpPersistentObjects);
157     newNode->setObjectName(fpModel->GetGlobalTag().c_str());
158     return newNode;
159   }
160 
161   // So this is a G4PhysicalVolumeModel
162   
163   typedef G4PhysicalVolumeModel::G4PhysicalVolumeNodeID PVNodeID;
164   typedef std::vector<PVNodeID> PVPath;
165 //  const PVPath& drawnPVPath = pPVModel->GetDrawnPVPath();
166   const PVPath& fullPVPath  = pPVModel->GetFullPVPath();
167   //G4int currentDepth = pPVModel->GetCurrentDepth();
168   //G4VPhysicalVolume* pCurrentPV = pPVModel->GetCurrentPV();
169   //G4LogicalVolume* pCurrentLV = pPVModel->GetCurrentLV();
170   //G4Material* pCurrentMaterial = pPVModel->GetCurrentMaterial();
171   // Note: pCurrentMaterial may be zero (parallel world).
172 
173 #ifdef G4QTDEBUG
174   G4cout << "A: " << fullPVPath << G4endl;  // DEBUG
175 #endif
176 
177   // Find appropriate root
178   const std::size_t nWorlds = fpPhysicalVolumeObjects.size();
179   std::size_t iWorld = 0;
180   for (; iWorld < nWorlds; ++iWorld) {
181     if (fullPVPath[0].GetPhysicalVolume() ==
182         fpPhysicalVolumeObjects[iWorld]->GetPVNodeID().GetPhysicalVolume()) break;
183   }
184   if (iWorld == nWorlds) {
185     G4Exception("G4Qt3DSceneHandler::CreateNewNode", "qt3D-0000", FatalException,
186                 "World mis-match - not possible(!?)");
187   }
188 
189   // (Re-)establish pv path of root entity
190   G4Qt3DQEntity* wrld = fpPhysicalVolumeObjects[iWorld];
191   wrld->SetPVNodeID(fullPVPath[0]);
192 
193   // Create nodes as required
194   G4Qt3DQEntity* node = wrld;
195   newNode = node;
196   const std::size_t depth = fullPVPath.size();
197   std::size_t iDepth = 1;
198   while (iDepth < depth) {
199     const auto& children = node->children();
200     const G4int nChildren = (G4int)children.size();
201     G4int iChild = 0;
202     G4Qt3DQEntity* child = nullptr;
203     for (; iChild < nChildren; ++iChild) {
204       child = static_cast<G4Qt3DQEntity*>(children[iChild]);
205       if (child->GetPVNodeID() == fullPVPath[iDepth]) break;
206     }
207     if (iChild != nChildren) {  // Existing node found
208       node = child;  // Must be the ancestor of new node (subsequent iteration)
209     } else {
210       // Add a new node as child of node
211       newNode = new G4Qt3DQEntity(node);
212       newNode->SetPVNodeID(fullPVPath[iDepth]);
213       std::ostringstream oss;
214       oss << newNode->GetPVNodeID().GetPhysicalVolume()->GetName()
215       << ':' << newNode->GetPVNodeID().GetCopyNo();
216       newNode->setObjectName(oss.str().c_str());
217       node = newNode;
218     }
219     ++iDepth;
220   }
221 
222   return node;
223 }
224 
225 void G4Qt3DSceneHandler::PreAddSolid
226  (const G4Transform3D& objectTransformation,
227   const G4VisAttributes& visAttribs)
228 {  
229   G4VSceneHandler::PreAddSolid(objectTransformation, visAttribs);
230 }
231 
232 void G4Qt3DSceneHandler::PostAddSolid()
233 {
234   G4VSceneHandler::PostAddSolid();
235 }
236 
237 void G4Qt3DSceneHandler::BeginPrimitives2D(const G4Transform3D& objectTransformation)
238 {
239 // The x,y coordinates of the primitives passed to AddPrimitive are
240 // intrepreted as screen coordinates, -1 < x,y < 1.  The
241 // z-coordinate is ignored.
242 // IMPORTANT: invoke this from your polymorphic versions, e.g.:
243 // void MyXXXSceneHandler::BeginPrimitives2D
244 // (const G4Transform3D& objectTransformation) {
245   static G4bool first = true;
246   if (first) {
247     first = false;
248     G4Exception("G4Qt3DSceneHandler::BeginPrimitives2D", "qt3D-0001",
249                 JustWarning,
250                 "2D drawing not yet implemented");
251   }
252    G4VSceneHandler::BeginPrimitives2D (objectTransformation);
253 //   ...
254 }
255 
256 void G4Qt3DSceneHandler::EndPrimitives2D ()
257 {
258 // IMPORTANT: invoke this from your polymorphic versions, e.g.:
259 // void MyXXXSceneHandler::EndPrimitives2D () {
260 //   ...
261   G4VSceneHandler::EndPrimitives2D ();
262 }
263 
264 void G4Qt3DSceneHandler::BeginPrimitives
265  (const G4Transform3D& objectTransformation)
266 {
267   G4VSceneHandler::BeginPrimitives(objectTransformation);
268 }
269 
270 void G4Qt3DSceneHandler::EndPrimitives ()
271 {
272   G4VSceneHandler::EndPrimitives ();
273 }
274 
275 void G4Qt3DSceneHandler::AddPrimitive(const G4Polyline& polyline)
276 {
277 #ifdef G4QT3DDEBUG
278   G4cout <<
279   "G4Qt3DSceneHandler::AddPrimitive(const G4Polyline& polyline) called.\n"
280   << polyline
281   << G4endl;
282 #endif
283   
284   if (polyline.size() == 0) return;
285 
286   auto currentNode = CreateNewNode();
287   if (!currentNode) {
288     static G4bool first = true;
289     if (first) {
290       first = false;
291       G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Polyline&)",
292       "qt3d-0003", JustWarning,
293       "No available node!");
294     }
295     return;
296   }
297 
298   fpVisAttribs = fpViewer->GetApplicableVisAttributes(polyline.GetVisAttributes());
299 
300   auto transform = G4Qt3DUtils::CreateQTransformFrom(fObjectTransformation);
301   transform->setObjectName("transform");
302 
303   auto polylineEntity = new Qt3DCore::QEntity(currentNode);
304   polylineEntity->addComponent(transform);
305 
306   const auto vertexByteSize  = 3*sizeof(PRECISION);
307 
308   const std::size_t nLines = polyline.size() - 1;
309   QByteArray polylineByteArray;
310   const auto polylineBufferByteSize = 2*nLines*vertexByteSize;
311   polylineByteArray.resize((G4int)polylineBufferByteSize);
312   auto polylineBufferArray = reinterpret_cast<PRECISION*>(polylineByteArray.data());
313   G4int iLine = 0;
314   for (std::size_t i = 0; i < nLines; ++i) {
315     polylineBufferArray[iLine++] = polyline[i].x();
316     polylineBufferArray[iLine++] = polyline[i].y();
317     polylineBufferArray[iLine++] = polyline[i].z();
318     polylineBufferArray[iLine++] = polyline[i+1].x();
319     polylineBufferArray[iLine++] = polyline[i+1].y();
320     polylineBufferArray[iLine++] = polyline[i+1].z();
321   }
322   auto polylineGeometry = new G4Qt3DCompat::QGeometry();
323   polylineGeometry->setObjectName("polylineGeometry");
324 
325   auto polylineBuffer = new G4Qt3DCompat::QBuffer(polylineGeometry);
326   polylineBuffer->setObjectName("Polyline buffer");
327   polylineBuffer->setData(polylineByteArray);
328 
329   auto polylineAtt = new G4Qt3DCompat::QAttribute;
330   polylineAtt->setObjectName("Position attribute");
331   polylineAtt->setName(G4Qt3DCompat::QAttribute::defaultPositionAttributeName());
332   polylineAtt->setBuffer(polylineBuffer);
333   polylineAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
334   polylineAtt->setVertexBaseType(BASETYPE);
335   polylineAtt->setVertexSize(3);
336   polylineAtt->setCount((G4int)nLines);
337   polylineAtt->setByteOffset(0);
338   polylineAtt->setByteStride(vertexByteSize);
339   // Normal attribute (a dummy with count==0) (Qt6 seems to require)
340   auto dummyNormalLineAtt = new G4Qt3DCompat::QAttribute;
341   dummyNormalLineAtt->setObjectName("Normal attribute");
342   dummyNormalLineAtt->setName(G4Qt3DCompat::QAttribute::defaultNormalAttributeName());
343   dummyNormalLineAtt->setBuffer(polylineBuffer);
344   dummyNormalLineAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
345   dummyNormalLineAtt->setVertexBaseType(BASETYPE);
346   dummyNormalLineAtt->setVertexSize(3);
347   dummyNormalLineAtt->setCount(0);
348   dummyNormalLineAtt->setByteOffset(0);
349   dummyNormalLineAtt->setByteStride(vertexByteSize);
350 
351   const auto& colour = fpVisAttribs->GetColour();
352 
353   polylineGeometry->addAttribute(polylineAtt);
354   polylineGeometry->addAttribute(dummyNormalLineAtt);
355 
356   auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
357   material->setObjectName("materialForPolyline");
358   material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
359   material->setShininess(0.);
360   material->setSpecular(0.);
361   polylineEntity->addComponent(material);
362 
363   auto renderer = new Qt3DRender::QGeometryRenderer;
364   renderer->setObjectName("polylineRenderer");
365   renderer->setGeometry(polylineGeometry);
366   renderer->setVertexCount(2*(G4int)nLines);
367   renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
368   polylineEntity->addComponent(renderer);
369 }
370 
371 void G4Qt3DSceneHandler::AddPrimitive (const G4Polymarker& polymarker)
372 {
373   if (polymarker.size() == 0) return;
374 
375   auto currentNode = CreateNewNode();
376   if (!currentNode) {
377     static G4bool first = true;
378     if (first) {
379       first = false;
380       G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Polymarker&)",
381       "qt3d-0003", JustWarning,
382       "No available node!");
383     }
384     return;
385   }
386 
387   fpVisAttribs = fpViewer->GetApplicableVisAttributes(polymarker.GetVisAttributes());
388 
389   MarkerSizeType markerSizeType;
390   G4double markerSize = GetMarkerSize(polymarker, markerSizeType);
391 
392   switch (polymarker.GetMarkerType()) {
393     default:
394     case G4Polymarker::dots:
395     {
396       const std::size_t nDots = polymarker.size();
397 
398       auto transform = G4Qt3DUtils::CreateQTransformFrom(fObjectTransformation);
399       transform->setObjectName("transform");
400 
401       auto polymarkerEntity = new Qt3DCore::QEntity(currentNode);
402       polymarkerEntity->addComponent(transform);
403 
404       const auto vertexByteSize  = 3*sizeof(PRECISION);
405 
406       QByteArray polymarkerByteArray;
407       const auto polymarkerBufferByteSize = nDots*vertexByteSize;
408       polymarkerByteArray.resize((G4int)polymarkerBufferByteSize);
409       auto polymarkerBufferArray = reinterpret_cast<PRECISION*>(polymarkerByteArray.data());
410       G4int iMarker = 0;
411       for (std::size_t i = 0; i < polymarker.size(); ++i) {
412         polymarkerBufferArray[iMarker++] = polymarker[i].x();
413         polymarkerBufferArray[iMarker++] = polymarker[i].y();
414         polymarkerBufferArray[iMarker++] = polymarker[i].z();
415       }
416       auto polymarkerGeometry = new G4Qt3DCompat::QGeometry();
417       polymarkerGeometry->setObjectName("polymarkerGeometry");
418       auto polymarkerBuffer = new G4Qt3DCompat::QBuffer(polymarkerGeometry);
419       polymarkerBuffer->setObjectName("Polymarker buffer");
420       polymarkerBuffer->setData(polymarkerByteArray);
421 
422       auto polymarkerAtt = new G4Qt3DCompat::QAttribute;
423       polymarkerAtt->setObjectName("Position attribute");
424       polymarkerAtt->setName(G4Qt3DCompat::QAttribute::defaultPositionAttributeName());
425       polymarkerAtt->setBuffer(polymarkerBuffer);
426       polymarkerAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
427       polymarkerAtt->setVertexBaseType(BASETYPE);
428       polymarkerAtt->setVertexSize(3);
429       polymarkerAtt->setCount((G4int)nDots);
430       polymarkerAtt->setByteOffset(0);
431       polymarkerAtt->setByteStride(vertexByteSize);
432 
433       const auto& colour = fpVisAttribs->GetColour();
434 
435       polymarkerGeometry->addAttribute(polymarkerAtt);
436 
437       auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
438       material->setObjectName("materialForPolymarker");
439       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
440       material->setShininess(0.);
441       material->setSpecular(0.);
442       polymarkerEntity->addComponent(material);
443 
444       auto renderer = new Qt3DRender::QGeometryRenderer;
445       renderer->setObjectName("polymarkerWireframeRenderer");
446       renderer->setGeometry(polymarkerGeometry);
447       renderer->setVertexCount((G4int)nDots);
448       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Points);
449       polymarkerEntity->addComponent(renderer);
450     }
451       break;
452     case G4Polymarker::circles:
453     {
454       G4Circle circle (polymarker);  // Default circle
455 
456       const auto& colour = fpVisAttribs->GetColour();
457       auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
458       material->setObjectName("materialForCircle");
459       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
460       if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
461 
462       auto sphereMesh = new Qt3DExtras::QSphereMesh;
463       sphereMesh->setObjectName("sphereMesh");
464       G4double radius = markerSize/2.;
465       if (markerSizeType == G4VSceneHandler::screen ) {
466         // Not figured out how to do screen-size, so use scene extent
467         const G4double scale = 200.;  // Roughly pixels per scene
468         radius *= fpScene->GetExtent().GetExtentRadius()/scale;
469       }
470       sphereMesh->setRadius(radius);
471 //      sphereMesh->setInstanceCount(polymarker.size());  // Not undertood instancing yet
472 
473 //      auto currentEntity = new Qt3DCore::QEntity(currentNode);  // Not undertood instancing yet
474       for (std::size_t iPoint = 0; iPoint < polymarker.size(); ++iPoint) {
475         auto position = fObjectTransformation*G4Translate3D(polymarker[iPoint]);
476         auto transform = G4Qt3DUtils::CreateQTransformFrom(position);
477   auto currentEntity = new Qt3DCore::QEntity(currentNode);  // Not undertood instancing yet
478         currentEntity->addComponent(material);
479         currentEntity->addComponent(transform);
480         currentEntity->addComponent(sphereMesh);
481       }
482     }
483       break;
484     case G4Polymarker::squares:
485     {
486       G4Square square (polymarker);  // Default square
487 
488       const auto& colour = fpVisAttribs->GetColour();
489       auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
490       material->setObjectName("materialForSquare");
491       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
492       if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
493 
494       auto boxMesh = new Qt3DExtras::QCuboidMesh();
495       boxMesh->setObjectName("boxMesh");
496       G4double side = markerSize;
497       if (markerSizeType == G4VSceneHandler::screen ) {
498         // Not figured out how to do screen-size, so use scene extent
499         const G4double scale = 200.;  // Roughly pixles per scene
500         side *= fpScene->GetExtent().GetExtentRadius()/scale;
501       }
502       boxMesh->setXExtent(side);
503       boxMesh->setYExtent(side);
504       boxMesh->setZExtent(side);
505 
506       for (std::size_t iPoint = 0; iPoint < polymarker.size(); ++iPoint) {
507         auto position = fObjectTransformation*G4Translate3D(polymarker[iPoint]);
508         auto transform = G4Qt3DUtils::CreateQTransformFrom(position);
509         auto currentEntity = new Qt3DCore::QEntity(currentNode);
510         currentEntity->addComponent(material);
511         currentEntity->addComponent(transform);
512         currentEntity->addComponent(boxMesh);
513       }
514     }
515       break;
516   }
517 }
518 
519 #ifdef G4QT3DDEBUG
520 void G4Qt3DSceneHandler::AddPrimitive(const G4Text& text) {
521   G4cout <<
522   "G4Qt3DSceneHandler::AddPrimitive(const G4Text& text) called.\n"
523   << text
524   << G4endl;
525 #else
526 void G4Qt3DSceneHandler::AddPrimitive(const G4Text& /*text*/) {
527 #endif
528 
529   static G4bool first = true;
530   if (first) {
531     first = false;
532     G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Text&)",
533                 "qt3D-0002", JustWarning,
534                 "Text drawing doesn't work yet");
535   }  // OK. Not working, but let it execute, which it does without error.
536 
537   /* But it crashes after /vis/viewer/rebuild!!!
538   auto currentNode = CreateNewNode();
539    if (!currentNode) {
540    static G4bool first = true;
541    if (first) {
542    first = false;
543    G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Text&)",
544    "qt3d-0003", JustWarning,
545    "No available node!");
546    }
547    return;
548    }
549 
550   fpVisAttribs = fpViewer->GetApplicableVisAttributes(text.GetVisAttributes());
551 
552   auto position = fObjectTransformation*G4Translate3D(text.GetPosition());
553   auto transform = G4Qt3DUtils::CreateQTransformFrom(position);
554 //  transform->setScale(10);
555   transform->setScale(0.1);
556 
557 //  auto currentEntity = new Qt3DCore::QEntity(currentNode);
558 
559   // This simply does not work
560   auto qtext = new Qt3DExtras::QText2DEntity();
561   qtext->setParent(currentNode);
562 //  qtext->setParent(currentEntity);  // ??  Doesn't help
563   qtext->setText(text.GetText().c_str());
564 //  qtext->setHeight(100);
565 //  qtext->setWidth(1000);
566   qtext->setHeight(20);
567   qtext->setWidth(100);
568   qtext->setColor(Qt::green);
569   qtext->setFont(QFont("Courier New", 10));
570   qtext->addComponent(transform);
571 
572   // This produces text in 3D facing +z - not what we want
573 //  const auto& colour = GetTextColour(text);
574 //  auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
575 //  material->setObjectName("materialForText");
576 //  material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
577 //  if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
578 //
579 //  auto textMesh = new Qt3DExtras::QExtrudedTextMesh();
580 //  textMesh->setText(text.GetText().c_str());
581 //  textMesh->setFont(QFont("Courier New", 10));
582 //  textMesh->setDepth(.01f);
583 //
584 //  currentNode->addComponent(material);
585 //  currentNode->addComponent(transform);
586 //  currentNode->addComponent(textMesh);
587    */
588 }
589 
590 void G4Qt3DSceneHandler::AddPrimitive(const G4Circle& circle)
591 {
592 #ifdef G4QT3DDEBUG
593   G4cout <<
594   "G4Qt3DSceneHandler::AddPrimitive(const G4Circle& circle) called.\n"
595   << circle
596   << G4endl;
597 #endif
598 
599 #ifdef G4QT3DDEBUG
600   MarkerSizeType sizeType;
601   G4double size = GetMarkerSize (circle, sizeType);
602   switch (sizeType) {
603     default:
604     case screen:
605       // Draw in screen coordinates.
606       G4cout << "screen";
607       break;
608     case world:
609       // Draw in world coordinates.
610       G4cout << "world";
611       break;
612   }
613   G4cout << " size: " << size << G4endl;
614 #endif
615 
616   auto currentNode = CreateNewNode();
617   if (!currentNode) {
618     static G4bool first = true;
619     if (first) {
620       first = false;
621       G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Circle&)",
622       "qt3d-0003", JustWarning,
623       "No available node!");
624     }
625     return;
626   }
627 
628   fpVisAttribs = fpViewer->GetApplicableVisAttributes(circle.GetVisAttributes());
629 
630   auto position = fObjectTransformation*G4Translate3D(circle.GetPosition());
631   auto transform = G4Qt3DUtils::CreateQTransformFrom(position);
632 
633   const auto& colour = fpVisAttribs->GetColour();
634   auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
635   material->setObjectName("materialForCircle");
636   material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
637   if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
638 
639   auto sphereMesh = new Qt3DExtras::QSphereMesh;
640   sphereMesh->setObjectName("sphereMesh");
641   G4double radius;
642   if (circle.GetSizeType() == G4VMarker::world ) {
643     radius =circle.GetWorldRadius();
644   } else {  // Screen-size or none
645     // Not figured out how to do screen-size, so use scene extent
646     const G4double scale = 200.;  // Roughly pixles per scene
647     radius = circle.GetScreenRadius()*fpScene->GetExtent().GetExtentRadius()/scale;
648   }
649   sphereMesh->setRadius(radius);
650 
651   auto currentEntity = new Qt3DCore::QEntity(currentNode);
652   currentEntity->addComponent(material);
653   currentEntity->addComponent(transform);
654   currentEntity->addComponent(sphereMesh);
655 }
656 
657 void G4Qt3DSceneHandler::AddPrimitive(const G4Square& square)
658 {
659 #ifdef G4QT3DDEBUG
660   G4cout <<
661   "G4Qt3DSceneHandler::AddPrimitive(const G4Square& square) called.\n"
662   << square
663   << G4endl;
664 #endif
665 
666 #ifdef G4QT3DDEBUG
667   MarkerSizeType sizeType;
668   G4double size = GetMarkerSize (square, sizeType);
669   switch (sizeType) {
670     default:
671     case screen:
672       // Draw in screen coordinates.
673       G4cout << "screen";
674       break;
675     case world:
676       // Draw in world coordinates.
677       G4cout << "world";
678       break;
679   }
680   G4cout << " size: " << size << G4endl;
681 #endif
682 
683   auto currentNode = CreateNewNode();
684   if (!currentNode) {
685     static G4bool first = true;
686     if (first) {
687       first = false;
688       G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Square&)",
689       "qt3d-0003", JustWarning,
690       "No available node!");
691     }
692     return;
693   }
694 
695   fpVisAttribs = fpViewer->GetApplicableVisAttributes(square.GetVisAttributes());
696 
697   auto position = fObjectTransformation*G4Translate3D(square.GetPosition());
698   auto transform = G4Qt3DUtils::CreateQTransformFrom(position);
699 
700   const auto& colour = fpVisAttribs->GetColour();
701   auto material = new Qt3DExtras::QDiffuseSpecularMaterial();
702   material->setObjectName("materialForSquare");
703   material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
704   if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
705 
706   auto boxMesh = new Qt3DExtras::QCuboidMesh();
707   boxMesh->setObjectName("boxMesh");
708   G4double side;
709   if (square.GetSizeType() == G4VMarker::world ) {
710     side = square.GetWorldDiameter();
711   } else {  // Screen-size or none
712     // Not figured out how to do screen-size, so use scene extent
713     const G4double scale = 200.;  // Roughly pixles per scene
714     side = square.GetScreenDiameter()*fpScene->GetExtent().GetExtentRadius()/scale;
715   }
716   boxMesh->setXExtent(side);
717   boxMesh->setYExtent(side);
718   boxMesh->setZExtent(side);
719 
720   auto currentEntity = new Qt3DCore::QEntity(currentNode);
721   currentEntity->addComponent(material);
722   currentEntity->addComponent(transform);
723   currentEntity->addComponent(boxMesh);
724 }
725 
726 void G4Qt3DSceneHandler::AddPrimitive(const G4Polyhedron& polyhedron)
727 {
728   auto currentNode = CreateNewNode();
729   if (!currentNode) {
730     static G4bool first = true;
731     if (first) {
732       first = false;
733       G4Exception("G4Qt3DSceneHandler::AddPrimitive(const G4Polyhedron&)",
734       "qt3d-0003", JustWarning,
735       "No available node!");
736     }
737     return;
738   }
739 
740   if (polyhedron.GetNoFacets() == 0) return;
741 
742   fpVisAttribs = fpViewer->GetApplicableVisAttributes(polyhedron.GetVisAttributes());
743 
744   // Roll out vertices and normals for the faces. Note that this means vertices
745   // are duplicated. For example a box has 8 vertices, but to define 6 faces
746   // you need 12 triangles and 36 vertices. If it was just a matter of vertices
747   // we could restrict the number to 8 and use the indices to define the
748   // triangles, but we also have to consider the normals. A vertex can be have
749   // more than one normal, depending on which face it is being used to define.
750   // So we roll out all the vertices and normals for each triangle.
751   std::vector<G4Point3D> vertices;
752   std::vector<G4Normal3D> normals;
753 
754   // Also roll out edges (as lines) for wireframe. Avoid duplicate lines,
755   // including those that differ only in the order of vertices.
756   typedef std::pair<G4Point3D,G4Point3D> Line;
757   std::vector<Line> lines;
758   auto insertIfNew = [&lines](const Line& newLine) {
759     // For a large polyhedron, eliminating lines like this is prohibitively
760     // expensive. Comment out for now, and maybe unwind altogether in future.
761     // Allow the graphics-reps utilities to optimise things like this.
762 //    for (const auto& line: lines) {
763 //      if ((newLine.first==line.first && newLine.second==line.second) ||
764 //          (newLine.first==line.second && newLine.second==line.first))
765 //      return;
766 //    }
767     lines.push_back(newLine);
768   };
769 
770   G4bool isAuxilaryEdgeVisible = fpViewer->GetViewParameters().IsAuxEdgeVisible();
771   G4bool notLastFace;
772   do {
773     G4int      nEdges;
774     G4Point3D  vertex  [4];
775     G4int      edgeFlag[4];
776     G4Normal3D normal  [4];
777     notLastFace = polyhedron.GetNextFacet(nEdges, vertex, edgeFlag, normal);
778     vertices.push_back(vertex[0]);
779     vertices.push_back(vertex[1]);
780     vertices.push_back(vertex[2]);
781     normals.push_back(normal[0]);
782     normals.push_back(normal[1]);
783     normals.push_back(normal[2]);
784     if(isAuxilaryEdgeVisible||edgeFlag[0]>0)insertIfNew(Line(vertex[0],vertex[1]));
785     if(isAuxilaryEdgeVisible||edgeFlag[1]>0)insertIfNew(Line(vertex[1],vertex[2]));
786     if (nEdges == 3) {
787       // Face is a triangle
788       // One more line for wireframe, triangles for surfaces are complete
789       if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[0]));
790     } else if (nEdges == 4) {
791       // Face is a quadrilateral
792       // Create another triangle for surfaces, add two more lines for wireframe
793       vertices.push_back(vertex[2]);
794       vertices.push_back(vertex[3]);
795       vertices.push_back(vertex[0]);
796       normals.push_back(normal[2]);
797       normals.push_back(normal[3]);
798       normals.push_back(normal[0]);
799       if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[3]));
800       if(isAuxilaryEdgeVisible||edgeFlag[3]>0)insertIfNew(Line(vertex[3],vertex[0]));
801     } else {
802       G4warn
803       << "ERROR: polyhedron face with unexpected number of edges (" << nEdges << ')'
804       << "\n  Tag: " << fpModel->GetCurrentTag()
805       << G4endl;
806       return;
807     }
808   } while (notLastFace);
809   const auto nVerts = vertices.size();
810   const auto nLines = lines.size();
811 
812   // Now put stuff into Qt objects
813 
814   auto transform = G4Qt3DUtils::CreateQTransformFrom(fObjectTransformation);
815   transform->setObjectName("transform");
816 
817   Qt3DCore::QEntity* wireframeEntity = nullptr;
818   Qt3DCore::QEntity* surfaceEntity   = nullptr;
819   static G4int errorCount = 0;
820   G4ViewParameters::DrawingStyle drawing_style = GetDrawingStyle (fpVisAttribs);
821   switch (drawing_style) {
822     case G4ViewParameters::wireframe:
823       wireframeEntity = new Qt3DCore::QEntity(currentNode);
824       wireframeEntity->addComponent(transform);
825       break;
826     case G4ViewParameters::hlr:
827       wireframeEntity = new Qt3DCore::QEntity(currentNode);
828       wireframeEntity->addComponent(transform);
829       surfaceEntity = new Qt3DCore::QEntity(currentNode);
830       surfaceEntity->addComponent(transform);
831       break;
832     case G4ViewParameters::hsr:
833       surfaceEntity = new Qt3DCore::QEntity(currentNode);
834       surfaceEntity->addComponent(transform);
835       break;
836     case G4ViewParameters::hlhsr:
837       wireframeEntity = new Qt3DCore::QEntity(currentNode);
838       wireframeEntity->addComponent(transform);
839       surfaceEntity = new Qt3DCore::QEntity(currentNode);
840       surfaceEntity->addComponent(transform);
841       break;
842     case G4ViewParameters::cloud:
843       // Shouldn't happen in this function (it's a polyhedron!)
844       if (errorCount == 0) {
845         ++errorCount;
846         G4warn << "WARNING: Qt3D: cloud drawing not implemented" << G4endl;
847       }
848       return;
849       break;
850   }
851 
852   const auto vertexByteSize  = 3*sizeof(PRECISION);
853 
854   G4Qt3DCompat::QGeometry* vertexGeometry = nullptr;
855   G4Qt3DCompat::QGeometry* lineGeometry   = nullptr;
856 
857   G4Qt3DCompat::QAttribute* positionAtt = nullptr;
858   G4Qt3DCompat::QAttribute* normalAtt   = nullptr;
859   G4Qt3DCompat::QAttribute* lineAtt     = nullptr;
860   G4Qt3DCompat::QAttribute* dummyNormalLineAtt = nullptr;
861 
862   G4Qt3DCompat::QBuffer* vertexBuffer = nullptr;
863   if (drawing_style == G4ViewParameters::hlr ||
864       drawing_style == G4ViewParameters::hsr ||
865       drawing_style == G4ViewParameters::hlhsr) {
866 
867     // Put vertices, normals into  QByteArray
868     // Accomodates both vertices and normals - hence 2*
869     QByteArray vertexByteArray;
870     const auto vertexBufferByteSize = 2*nVerts*vertexByteSize;
871     vertexByteArray.resize((G4int)vertexBufferByteSize);
872     auto vertexBufferArray = reinterpret_cast<PRECISION*>(vertexByteArray.data());
873     G4int i1 = 0;
874     for (std::size_t i = 0; i < nVerts; ++i) {
875       vertexBufferArray[i1++] = vertices[i].x();
876       vertexBufferArray[i1++] = vertices[i].y();
877       vertexBufferArray[i1++] = vertices[i].z();
878       vertexBufferArray[i1++] = normals[i].x();
879       vertexBufferArray[i1++] = normals[i].y();
880       vertexBufferArray[i1++] = normals[i].z();
881     }
882     // Vertex buffer (vertices and normals)
883     vertexGeometry = new G4Qt3DCompat::QGeometry();
884     vertexGeometry->setObjectName("vertexGeometry");
885     vertexBuffer = new G4Qt3DCompat::QBuffer(vertexGeometry);
886     vertexBuffer->setObjectName("Vertex buffer");
887     vertexBuffer->setData(vertexByteArray);
888 
889     // Position attribute
890     positionAtt = new G4Qt3DCompat::QAttribute;
891     positionAtt->setObjectName("Position attribute");
892     positionAtt->setName(G4Qt3DCompat::QAttribute::defaultPositionAttributeName());
893     positionAtt->setBuffer(vertexBuffer);
894     positionAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
895     positionAtt->setVertexBaseType(BASETYPE);
896     positionAtt->setVertexSize(3);
897     positionAtt->setCount((G4int)nVerts);
898     positionAtt->setByteOffset(0);
899     positionAtt->setByteStride(2*vertexByteSize);
900 
901     // Normal attribute
902     normalAtt = new G4Qt3DCompat::QAttribute;
903     normalAtt->setObjectName("Normal attribute");
904     normalAtt->setName(G4Qt3DCompat::QAttribute::defaultNormalAttributeName());
905     normalAtt->setBuffer(vertexBuffer);
906     normalAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
907     normalAtt->setVertexBaseType(BASETYPE);
908     normalAtt->setVertexSize(3);
909     normalAtt->setCount((G4int)nVerts);
910     normalAtt->setByteOffset(vertexByteSize);
911     normalAtt->setByteStride(2*vertexByteSize);
912   }
913 
914   G4Qt3DCompat::QBuffer* lineBuffer = nullptr;
915   if (drawing_style == G4ViewParameters::wireframe ||
916       drawing_style == G4ViewParameters::hlr ||
917       drawing_style == G4ViewParameters::hlhsr) {
918 
919     // Put lines into a QByteArray
920     QByteArray lineByteArray;
921     const auto lineBufferByteSize = 2*nLines*vertexByteSize;
922     lineByteArray.resize((G4int)lineBufferByteSize);
923     auto lineBufferArray = reinterpret_cast<PRECISION*>(lineByteArray.data());
924     G4int i2 = 0;
925     for (const auto& line: lines) {
926       lineBufferArray[i2++] = line.first.x();
927       lineBufferArray[i2++] = line.first.y();
928       lineBufferArray[i2++] = line.first.z();
929       lineBufferArray[i2++] = line.second.x();
930       lineBufferArray[i2++] = line.second.y();
931       lineBufferArray[i2++] = line.second.z();
932     }
933     // Line loop buffer
934     lineGeometry = new G4Qt3DCompat::QGeometry();
935     lineGeometry->setObjectName("lineGeometry");
936     lineBuffer = new G4Qt3DCompat::QBuffer(lineGeometry);
937     lineBuffer->setObjectName("Line buffer");
938     lineBuffer->setData(lineByteArray);
939 
940     // Line attribute
941     lineAtt = new G4Qt3DCompat::QAttribute;
942     lineAtt->setObjectName("Position attribute");
943     lineAtt->setName(G4Qt3DCompat::QAttribute::defaultPositionAttributeName());
944     lineAtt->setBuffer(lineBuffer);
945     lineAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
946     lineAtt->setVertexBaseType(BASETYPE);
947     lineAtt->setVertexSize(3);
948     lineAtt->setCount((G4int)nLines);
949     lineAtt->setByteOffset(0);
950     lineAtt->setByteStride(vertexByteSize);
951     // Normal attribute (a dummy with count==0) (Qt6 seems to require)
952     dummyNormalLineAtt = new G4Qt3DCompat::QAttribute;
953     dummyNormalLineAtt->setObjectName("Normal attribute");
954     dummyNormalLineAtt->setName(G4Qt3DCompat::QAttribute::defaultNormalAttributeName());
955     dummyNormalLineAtt->setBuffer(lineBuffer);
956     dummyNormalLineAtt->setAttributeType(G4Qt3DCompat::QAttribute::VertexAttribute);
957     dummyNormalLineAtt->setVertexBaseType(BASETYPE);
958     dummyNormalLineAtt->setVertexSize(3);
959     dummyNormalLineAtt->setCount(0);
960     dummyNormalLineAtt->setByteOffset(0);
961     dummyNormalLineAtt->setByteStride(vertexByteSize);
962   }
963 
964   // Create material and renderer(s)...
965 
966   const auto& colour = fpVisAttribs->GetColour();
967   Qt3DExtras::QDiffuseSpecularMaterial* material;
968   Qt3DRender::QGeometryRenderer* renderer;
969   switch (drawing_style) {
970       
971     case G4ViewParameters::wireframe:
972 
973       lineGeometry->addAttribute(lineAtt);
974       lineGeometry->addAttribute(dummyNormalLineAtt);
975 
976       material = new Qt3DExtras::QDiffuseSpecularMaterial();
977       material->setObjectName("materialForWireframe");
978       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
979       material->setShininess(0.);
980       material->setSpecular(0.);
981       wireframeEntity->addComponent(material);
982 
983       renderer = new Qt3DRender::QGeometryRenderer;
984       renderer->setObjectName("polyhedronWireframeRenderer");
985       renderer->setGeometry(lineGeometry);
986       renderer->setVertexCount(2*(G4int)nLines);
987       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
988       wireframeEntity->addComponent(renderer);
989 
990       break;
991 
992     case G4ViewParameters::hlr:
993 
994       // Surfaces with background colour to hide the edges
995 
996       vertexGeometry->addAttribute(positionAtt);
997       vertexGeometry->addAttribute(normalAtt);
998 
999       material = new Qt3DExtras::QDiffuseSpecularMaterial();
1000       material->setObjectName("materialForHiddenLines");
1001       material->setAmbient(Qt::white);  // White for now (should be from fVP)
1002       material->setShininess(0.);
1003       material->setSpecular(0.);
1004       surfaceEntity->addComponent(material);
1005 
1006       renderer = new Qt3DRender::QGeometryRenderer;
1007       renderer->setObjectName("polyhedronSurfaceRenderer");
1008       renderer->setGeometry(vertexGeometry);
1009       renderer->setVertexCount((G4int)nVerts);
1010       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
1011       surfaceEntity->addComponent(renderer);
1012 
1013       // Edges
1014 
1015       lineGeometry->addAttribute(lineAtt);
1016       lineGeometry->addAttribute(dummyNormalLineAtt);
1017 
1018       material = new Qt3DExtras::QDiffuseSpecularMaterial();
1019       material->setObjectName("materialForWireFrame");
1020       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
1021       material->setShininess(0.);
1022       material->setSpecular(0.);
1023       wireframeEntity->addComponent(material);
1024 
1025       renderer = new Qt3DRender::QGeometryRenderer;
1026       renderer->setObjectName("polyhedronWireframeRenderer");
1027       renderer->setGeometry(lineGeometry);
1028       renderer->setVertexCount(2*(G4int)nLines);
1029       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
1030       wireframeEntity->addComponent(renderer);
1031 
1032       break;
1033 
1034     case G4ViewParameters::hsr:
1035 
1036       vertexGeometry->addAttribute(positionAtt);
1037       vertexGeometry->addAttribute(normalAtt);
1038 
1039       material = new Qt3DExtras::QDiffuseSpecularMaterial();
1040       material->setObjectName("materialForSurface");
1041       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
1042       if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
1043       surfaceEntity->addComponent(material);
1044 
1045       renderer = new Qt3DRender::QGeometryRenderer;
1046       renderer->setObjectName("polyhedronSurfaceRenderer");
1047       renderer->setGeometry(vertexGeometry);
1048       renderer->setVertexCount((G4int)nVerts);
1049       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
1050       surfaceEntity->addComponent(renderer);
1051 
1052       break;
1053 
1054     case G4ViewParameters::hlhsr:
1055 
1056       // Surfaces
1057 
1058       vertexGeometry->addAttribute(positionAtt);
1059       vertexGeometry->addAttribute(normalAtt);
1060 
1061       material = new Qt3DExtras::QDiffuseSpecularMaterial();
1062       material->setObjectName("materialForSurface");
1063       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
1064       if (colour.GetAlpha() < 1.) material->setAlphaBlendingEnabled(true);
1065       surfaceEntity->addComponent(material);
1066 
1067       renderer = new Qt3DRender::QGeometryRenderer;
1068       renderer->setObjectName("polyhedronSurfaceRenderer");
1069       renderer->setGeometry(vertexGeometry);
1070       renderer->setVertexCount((G4int)nVerts);
1071       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
1072       surfaceEntity->addComponent(renderer);
1073 
1074       // Edges
1075 
1076       lineGeometry->addAttribute(lineAtt);
1077       lineGeometry->addAttribute(dummyNormalLineAtt);
1078 
1079       material = new Qt3DExtras::QDiffuseSpecularMaterial();
1080       material->setObjectName("materialForWireframe");
1081       material->setAmbient(G4Qt3DUtils::ConvertToQColor(colour));
1082       material->setShininess(0.);
1083       material->setSpecular(0.);
1084       wireframeEntity->addComponent(material);
1085 
1086       renderer = new Qt3DRender::QGeometryRenderer;
1087       renderer->setObjectName("polyhedronSurfaceRenderer");
1088       renderer->setGeometry(lineGeometry);
1089       renderer->setVertexCount(2*(G4int)nLines);
1090       renderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
1091       wireframeEntity->addComponent(renderer);
1092 
1093       break;
1094 
1095     case G4ViewParameters::cloud:
1096       // Case trapped at start of function, so no need to implement
1097       break;
1098   }
1099 }
1100 
1101 void G4Qt3DSceneHandler::AddCompound(const G4Mesh& mesh)
1102 {
1103   StandardSpecialMeshRendering(mesh);
1104 }
1105 
1106 void G4Qt3DSceneHandler::ClearStore ()
1107 {
1108   G4Qt3DUtils::delete_components_and_children_of_entity_recursively(fpQt3DScene);
1109   EstablishG4Qt3DQEntities();
1110 }
1111 
1112 void G4Qt3DSceneHandler::ClearTransientStore ()
1113 {
1114   G4Qt3DUtils::delete_components_and_children_of_entity_recursively(fpTransientObjects);
1115 }
1116