Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/ToolsSG/src/G4ToolsSGSceneHandler.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  6th October 2020
 27 
 28 #include "G4ToolsSGSceneHandler.hh"
 29 
 30 #include "G4ToolsSGNode.hh"
 31 
 32 #include "G4TransportationManager.hh"
 33 #include "G4Polyline.hh"
 34 #include "G4Polymarker.hh"
 35 #include "G4Circle.hh"
 36 #include "G4Square.hh"
 37 #include "G4Polyhedron.hh"
 38 #include "G4Text.hh"
 39 #include "G4Mesh.hh"
 40 #include "G4PlotterManager.hh"
 41 
 42 #include <tools/sg/separator>
 43 #include <tools/sg/matrix>
 44 #include <tools/sg/rgba>
 45 #include <tools/sg/draw_style>
 46 #include <tools/sg/atb_vertices>
 47 #include <tools/sg/markers>
 48 #ifdef TOOLS_USE_FREETYPE
 49 #include <toolx/sg/text_freetype>
 50 #include <tools/sg/strings>
 51 #include <tools/font/lato_regular_ttf>
 52 #include <tools/font/roboto_bold_ttf>
 53 #include <toolx/sg/text_freetype_marker>
 54 #else
 55 #include <tools/sg/dummy_freetype>
 56 #include <tools/sg/text_hershey_marker>
 57 #endif
 58 
 59 //for plotting:
 60 #include <tools/sg/dummy_freetype>
 61 #include <tools/sg/light_off>
 62 #include <tools/sg/plots>
 63 #include <tools/sg/h2plot_cp>
 64 #include <tools/sg/plotter_style>
 65 #include <tools/sg/event_dispatcher>
 66 #include <tools/sg/path>
 67 #include <tools/sg/search>
 68 #include <tools/histo/h1d>
 69 #include <tools/histo/h2d>
 70 #include <tools/sg/plotter_some_styles>
 71 
 72 #include <utility>
 73 
 74 G4int G4ToolsSGSceneHandler::fSceneIdCount = 0;
 75 
 76 G4ToolsSGSceneHandler::G4ToolsSGSceneHandler
 77 (G4VGraphicsSystem& system, const G4String& name)
 78 :parent(system, fSceneIdCount++, name)
 79 ,fFreetypeNode(0)
 80 {
 81   //::printf("debug : G4ToolsSGSceneHandler : %lu, %s\n",this,name.c_str());
 82   EstablishBaseNodes();
 83 #if defined(TOOLS_USE_FREETYPE)
 84   fFreetypeNode = new toolx::sg::text_freetype();
 85   fFreetypeNode->add_embedded_font(tools::sg::font_lato_regular_ttf(),tools::font::lato_regular_ttf);
 86   fFreetypeNode->add_embedded_font(tools::sg::font_roboto_bold_ttf(),tools::font::roboto_bold_ttf);
 87 #else  
 88   fFreetypeNode = new tools::sg::dummy_freetype();
 89 #endif
 90   Messenger::Create();
 91 }
 92 
 93 G4ToolsSGSceneHandler::~G4ToolsSGSceneHandler()
 94 {
 95   //::printf("debug : ~G4ToolsSGSceneHandler : %lu\n",this);
 96   //WARNING : nodes may refer graphics managers (as tools/sg/[GL_manager,gl2ps_manager,zb_manager]
 97   //          used by viewers) to handle gstos (for GPU) or textures, then we have to delete them first.
 98   //          It is assumed that we pass here BEFORE the attached/managed viewers are deleted.
 99   fpTransient2DObjects.clear();
100   fpPersistent2DObjects.clear();
101   fpTransient3DObjects.clear();
102   fpPersistent3DObjects.clear();
103   delete fFreetypeNode;
104 }
105 
106 void G4ToolsSGSceneHandler::EstablishBaseNodes()
107 {
108   // Physical volume objects for each world hang from POs
109   G4TransportationManager* transportationManager = G4TransportationManager::GetTransportationManager ();
110   size_t nWorlds = transportationManager->GetNoWorlds();
111   std::vector<G4VPhysicalVolume*>::iterator iterWorld = transportationManager->GetWorldsIterator();
112   fpPhysicalVolumeObjects.resize(nWorlds);
113   for (size_t i = 0; i < nWorlds; ++i, ++iterWorld) {
114     G4VPhysicalVolume* _world = (*iterWorld);
115     auto entity = new G4ToolsSGNode;
116     fpPersistent3DObjects.add(entity);
117     entity->SetPVNodeID(G4PhysicalVolumeModel::G4PhysicalVolumeNodeID(_world));
118     fpPhysicalVolumeObjects[i] = entity;
119   }
120 }
121 
122 tools::sg::separator* G4ToolsSGSceneHandler::GetOrCreateNode()
123 { // Retrieve or create a G4ToolsSGNode node suitable for next solid or primitive
124 
125   // For time being, avoid errors in MT mode - see G4ToolsSGViewer::SwitchToMasterThread
126   if (!G4Threading::IsMasterThread()) return nullptr;
127 
128   if (fReadyForTransients) {  // All transients hang from this node
129     tools::sg::separator* sep = new tools::sg::separator;
130     fpTransient3DObjects.add(sep);
131     return sep;
132   }
133 
134   auto* pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
135 
136   if (!pPVModel) {  // Persistent objects (e.g., axes)
137     tools::sg::separator* sep = new tools::sg::separator;
138     fpPersistent3DObjects.add(sep);
139     return sep;
140   }
141 
142   // So this is a G4PhysicalVolumeModel
143   typedef G4PhysicalVolumeModel::G4PhysicalVolumeNodeID PVNodeID;
144   typedef std::vector<PVNodeID> PVPath;
145   //const PVPath& drawnPVPath = pPVModel->GetDrawnPVPath();
146   const PVPath& fullPVPath  = pPVModel->GetFullPVPath();
147   //G4int currentDepth = pPVModel->GetCurrentDepth();
148   //G4VPhysicalVolume* pCurrentPV = pPVModel->GetCurrentPV();
149   //G4LogicalVolume* pCurrentLV = pPVModel->GetCurrentLV();
150   //G4Material* pCurrentMaterial = pPVModel->GetCurrentMaterial();
151   // Note: pCurrentMaterial may be zero (parallel world).
152 
153   // Find appropriate root
154   const size_t nWorlds = fpPhysicalVolumeObjects.size();
155   size_t iWorld = 0;
156   for (; iWorld < nWorlds; ++iWorld) {
157     if (fullPVPath[0].GetPhysicalVolume() ==
158         fpPhysicalVolumeObjects[iWorld]->GetPVNodeID().GetPhysicalVolume()) break;
159   }
160   if (iWorld == nWorlds) {
161     G4Exception("G4ToolsSGSceneHandler::GetOrCreateNode", "ToolsSG-0000", FatalException,
162                 "World mis-match - not possible(!?)");
163   }
164 
165   // (Re-)establish pv path of root entity
166   G4ToolsSGNode* _world = fpPhysicalVolumeObjects[iWorld];
167   _world->SetPVNodeID(fullPVPath[0]);
168 
169   // Provide nodes as required - may be a new node or a pre-existing node
170   G4ToolsSGNode* node = _world;  // Working variable - default to world
171   const size_t depth = fullPVPath.size();
172   size_t iDepth = 1;
173   while (iDepth < depth) {
174     const auto& children = node->children();
175     const G4int nChildren = (G4int)children.size();
176     G4int iChild = 0;
177     G4ToolsSGNode* child = nullptr;
178     for (; iChild < nChildren; ++iChild) {
179       child = static_cast<G4ToolsSGNode*>(children[iChild]);
180       if (child->GetPVNodeID() == fullPVPath[iDepth]) break;
181     }
182     if (iChild != nChildren) {  // Existing node found
183       node = child;  // Must be the ancestor of new node (subsequent iteration)
184     } else {
185       // Add a new node as child of node
186       G4ToolsSGNode* newNode = new G4ToolsSGNode;
187       node->add(newNode);
188       newNode->SetPVNodeID(fullPVPath[iDepth]);
189       node = newNode;
190     }
191     ++iDepth;
192   }
193   return node;
194 }
195 
196 void G4ToolsSGSceneHandler::ClearStore ()
197 {
198   fpTransient2DObjects.clear();
199   fpPersistent2DObjects.clear();
200   fpTransient3DObjects.clear();
201   fpPersistent3DObjects.clear();
202   EstablishBaseNodes();
203 }
204 
205 void G4ToolsSGSceneHandler::ClearTransientStore ()
206 {
207   fpTransient2DObjects.clear();
208   fpTransient3DObjects.clear();
209 }
210 
211 void G4ToolsSGSceneHandler::AddPrimitive(const G4Polyline& a_polyline)
212 {
213   //G4cout << "debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Polyline&) : \n" << a_polyline << G4endl;
214   if (a_polyline.size() == 0) return;
215 
216   tools::sg::separator* parentNode = 0;
217   if(fProcessing2D) {
218     parentNode = new tools::sg::separator;
219     if (fReadyForTransients) {
220       fpTransient2DObjects.add(parentNode);
221     } else {
222       fpPersistent2DObjects.add(parentNode);
223     }
224 
225   } else {
226     parentNode = GetOrCreateNode();
227     if(!parentNode) return;
228 
229     tools::sg::matrix* mtx = new tools::sg::matrix;
230     G4Transform3D& elem = fObjectTransformation;
231     mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3),
232                                 elem(1,0),elem(1,1),elem(1,2),elem(1,3),
233                                 elem(2,0),elem(2,1),elem(2,2),elem(2,3),
234                                         0,        0,        0,        1);
235     parentNode->add(mtx);
236   }
237 
238  {const auto& colour = GetColour(a_polyline);
239   tools::sg::rgba* mat = new tools::sg::rgba();
240   mat->color =
241     tools::colorf(float(colour.GetRed()),
242                   float(colour.GetGreen()),
243                   float(colour.GetBlue()),
244                   float(colour.GetAlpha()));
245   parentNode->add(mat);}
246 
247  {tools::sg::draw_style* ds = new tools::sg::draw_style;
248   ds->style = tools::sg::draw_lines;
249   ds->line_width = 1;
250   parentNode->add(ds);}
251 
252   tools::sg::vertices* vtxs = new tools::sg::vertices;
253   vtxs->mode = tools::gl::line_strip();  //polyline
254   parentNode->add(vtxs);
255   
256  {for (size_t i = 0; i < a_polyline.size(); ++i) {
257     vtxs->add(float(a_polyline[i].x()),float(a_polyline[i].y()),float(a_polyline[i].z()));
258   }}
259   
260 }
261 
262 void G4ToolsSGSceneHandler::AddPrimitive (const G4Polymarker& a_polymarker)
263 {
264   //::printf("debug G4ToolsSGSceneHandler::AddPrimitive(const G4Polymarker&) : %lu, type %d\n",
265   //     a_polymarker.size(),a_polymarker.GetMarkerType());
266   if (a_polymarker.size() == 0) return;
267   auto currentNode = GetOrCreateNode();
268   if (!currentNode) return;  // Node not available
269 
270   // Transformation
271  {tools::sg::matrix* mtx = new tools::sg::matrix;
272   G4Transform3D& elem = fObjectTransformation;
273   mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3),
274                               elem(1,0),elem(1,1),elem(1,2),elem(1,3),
275                               elem(2,0),elem(2,1),elem(2,2),elem(2,3),
276                                       0,        0,        0,        1);
277   currentNode->add(mtx);}
278 
279  {const auto& colour = GetColour(a_polymarker);
280   tools::sg::rgba* mat = new tools::sg::rgba();
281   mat->color =
282     tools::colorf(float(colour.GetRed()),
283                   float(colour.GetGreen()),
284                   float(colour.GetBlue()),
285                   float(colour.GetAlpha()));
286   currentNode->add(mat);}
287 
288   MarkerSizeType markerSizeType;
289   G4double markerSize = GetMarkerSize(a_polymarker, markerSizeType);
290 
291   switch (a_polymarker.GetMarkerType()) {
292     default:
293     case G4Polymarker::dots:{
294       //::printf("debug : GB : Add Markers : +++++++++++++++++++++++++++++++++++++++++++ : dots\n");
295       tools::sg::draw_style* ds = new tools::sg::draw_style;
296       ds->style = tools::sg::draw_points;
297       ds->point_size = 1;
298       currentNode->add(ds);
299       tools::sg::vertices* vtxs = new tools::sg::vertices;
300       vtxs->mode = tools::gl::points();
301      {for (size_t i = 0; i < a_polymarker.size(); ++i) {
302         vtxs->add(float(a_polymarker[i].x()),float(a_polymarker[i].y()),float(a_polymarker[i].z()));
303       }}
304       currentNode->add(vtxs);
305     }break;
306     case G4Polymarker::circles:{
307       //::printf("debug : GB : Add Markers : +++++++++++++++++++++++++++++++++++++++++++ : circles\n");
308      {tools::sg::markers* markers = new tools::sg::markers;
309       G4double diameter = markerSize;  // OK for "screen-size" (the usual case)
310       if (markerSizeType == G4VSceneHandler::world ) {
311         const G4double scale = 200.;  // Roughly pixels per scene
312         diameter *= fpScene->GetExtent().GetExtentRadius()/scale;
313       }
314       markers->size = diameter;
315       markers->style = tools::sg::marker_circle_line;
316       for (size_t i = 0; i < a_polymarker.size(); ++i) {
317         markers->add(float(a_polymarker[i].x()),float(a_polymarker[i].y()),float(a_polymarker[i].z()));
318       }
319       currentNode->add(markers);}
320     }break;
321   case G4Polymarker::squares:{
322     //::printf("debug : GB : Add Markers : +++++++++++++++++++++++++++++++++++++++++++ : square\n");
323      {tools::sg::markers* markers = new tools::sg::markers;
324       G4double side = markerSize;  // OK for "screen-size" (the usual case)
325       if (markerSizeType == G4VSceneHandler::world ) {
326         const G4double scale = 200.;  // Roughly pixels per scene
327         side *= fpScene->GetExtent().GetExtentRadius()/scale;
328       }
329       markers->size = side;
330       markers->style = tools::sg::marker_square_line;
331       for (size_t i = 0; i < a_polymarker.size(); ++i) {
332         markers->add(float(a_polymarker[i].x()),float(a_polymarker[i].y()),float(a_polymarker[i].z()));
333       }
334       currentNode->add(markers);}
335   }break;
336   }
337 }
338 
339 void G4ToolsSGSceneHandler::AddPrimitive(const G4Text& a_text)
340 {
341   //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Text&) : 000 : \"%s\"\n",a_text.GetText().c_str());
342   //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Text&) : 2D ? %d\n",fProcessing2D);
343   auto pos = a_text.GetPosition();
344   //::printf("debug : Add Text : pos %g %g %g\n",pos.x(),pos.y(),pos.z());
345 
346   tools::sg::separator* parentNode = 0;
347   if(fProcessing2D) {
348     parentNode = new tools::sg::separator;
349     if (fReadyForTransients) {
350       fpTransient2DObjects.add(parentNode);
351     } else {
352       fpPersistent2DObjects.add(parentNode);
353     }
354 
355     tools::sg::matrix* mtx = new tools::sg::matrix;
356     mtx->set_translate(pos.x(),pos.y(),pos.z());
357     parentNode->add(mtx);
358 
359   } else {
360     parentNode = GetOrCreateNode();
361     if (!parentNode) return;
362 
363     tools::sg::matrix* mtx = new tools::sg::matrix;
364     auto elem = fObjectTransformation*G4Translate3D(pos);
365     mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3),
366                                 elem(1,0),elem(1,1),elem(1,2),elem(1,3),
367                                 elem(2,0),elem(2,1),elem(2,2),elem(2,3),
368                                         0,        0,        0,        1);
369     parentNode->add(mtx);
370   }
371 
372   MarkerSizeType sizeType;
373   G4double size = GetMarkerSize(a_text, sizeType);
374   
375  {const auto& colour = GetTextColour(a_text);
376   tools::sg::rgba* mat = new tools::sg::rgba();
377   mat->color =
378     tools::colorf(float(colour.GetRed()),
379                   float(colour.GetGreen()),
380                   float(colour.GetBlue()),
381                   float(colour.GetAlpha()));
382   parentNode->add(mat);}
383  
384 #ifdef TOOLS_USE_FREETYPE
385   toolx::sg::text_freetype_marker* text = new toolx::sg::text_freetype_marker;
386   text->add_embedded_font(tools::sg::font_lato_regular_ttf(),tools::font::lato_regular_ttf);
387   text->font = tools::sg::font_lato_regular_ttf();
388   text->front_face = tools::sg::winding_cw;
389 //text->modeling = tools::sg::font_pixmap; //problem with Qt/GL. It slows rendering!
390 #else
391   tools::sg::text_hershey_marker* text = new tools::sg::text_hershey_marker;
392 //text->encoding.value(a_encoding);
393 #endif
394   text->height = float(size); //pixels
395   text->strings.add(a_text.GetText());
396  {switch (a_text.GetLayout()) {
397   default:
398   case G4Text::left:
399     text->hjust = tools::sg::left;
400     break;
401   case G4Text::centre:
402     text->hjust = tools::sg::center;
403     break;
404   case G4Text::right:
405     text->hjust = tools::sg::right;
406     break;
407   }}
408 //text->vjust.value(a_vjust);
409   parentNode->add(text);
410 
411 }
412 
413 void G4ToolsSGSceneHandler::AddPrimitive(const G4Circle& a_circle)
414 {
415   G4Polymarker oneCircle(a_circle);
416   oneCircle.push_back(a_circle.GetPosition());
417   oneCircle.SetMarkerType(G4Polymarker::circles);
418   // Call this AddPrimitive to avoid re-doing sub-class code.
419   G4ToolsSGSceneHandler::AddPrimitive(oneCircle);
420 }
421 
422 void G4ToolsSGSceneHandler::AddPrimitive(const G4Square& a_square)
423 {
424   G4Polymarker oneSquare(a_square);
425   oneSquare.push_back(a_square.GetPosition());
426   oneSquare.SetMarkerType(G4Polymarker::squares);
427   // Call this AddPrimitive to avoid re-doing sub-class code.
428   G4ToolsSGSceneHandler::AddPrimitive(oneSquare);
429 }
430 
431 void G4ToolsSGSceneHandler::AddPrimitive(const G4Polyhedron& a_polyhedron)
432 {
433   if (a_polyhedron.GetNoFacets() == 0) return;
434 
435   //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Polyhedron&) : %d\n",a_polyhedron.GetNoFacets());
436   
437   fpVisAttribs = fpViewer->GetApplicableVisAttributes(a_polyhedron.GetVisAttributes());
438 
439   // Roll out vertices and normals for the faces. Note that this means vertices
440   // are duplicated. For example a box has 8 vertices, but to define 6 faces
441   // you need 12 triangles and 36 vertices. If it was just a matter of vertices
442   // we could restrict the number to 8 and use the indices to define the
443   // triangles, but we also have to consider the normals. A vertex can be have
444   // more than one normal, depending on which face it is being used to define.
445   // So we roll out all the vertices and normals for each triangle.
446   std::vector<G4Point3D> vertices;
447   std::vector<G4Normal3D> normals;
448 
449   // Also roll out edges (as lines) for wireframe. Avoid duplicate lines,
450   // including those that differ only in the order of vertices.
451   typedef std::pair<G4Point3D,G4Point3D> Line;
452   std::vector<Line> lines;
453   auto insertIfNew = [&lines](const Line& newLine) {
454 //    for (const auto& line: lines) {
455 //      if ((newLine.first==line.first && newLine.second==line.second) ||
456 //          (newLine.first==line.second && newLine.second==line.first))
457 //      return;
458 //    }
459     lines.push_back(newLine);
460   };
461 
462   G4bool isAuxilaryEdgeVisible = fpViewer->GetViewParameters().IsAuxEdgeVisible();
463   G4bool notLastFace;
464   do {
465     G4int      nEdges;
466     G4Point3D  vertex  [4];
467     G4int      edgeFlag[4];
468     G4Normal3D normal  [4];
469     notLastFace = a_polyhedron.GetNextFacet(nEdges, vertex, edgeFlag, normal);
470     vertices.push_back(vertex[0]);
471     vertices.push_back(vertex[1]);
472     vertices.push_back(vertex[2]);
473     normals.push_back(normal[0]);
474     normals.push_back(normal[1]);
475     normals.push_back(normal[2]);
476     if(isAuxilaryEdgeVisible||edgeFlag[0]>0)insertIfNew(Line(vertex[0],vertex[1]));
477     if(isAuxilaryEdgeVisible||edgeFlag[1]>0)insertIfNew(Line(vertex[1],vertex[2]));
478     if (nEdges == 3) {
479       // Face is a triangle
480       // One more line for wireframe, triangles for surfaces are complete
481       if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[0]));
482     } else if (nEdges == 4) {
483       // Face is a quadrilateral
484       // Create another triangle for surfaces, add two more lines for wireframe
485       vertices.push_back(vertex[2]);
486       vertices.push_back(vertex[3]);
487       vertices.push_back(vertex[0]);
488       normals.push_back(normal[2]);
489       normals.push_back(normal[3]);
490       normals.push_back(normal[0]);
491       if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[3]));
492       if(isAuxilaryEdgeVisible||edgeFlag[3]>0)insertIfNew(Line(vertex[3],vertex[0]));
493     } else {
494       G4cerr
495       << "ERROR: polyhedron face with unexpected number of edges (" << nEdges << ')'
496       << "\n  Tag: " << fpModel->GetCurrentTag()
497       << G4endl;
498       return;
499     }
500   } while (notLastFace);
501 
502   G4ViewParameters::DrawingStyle drawing_style = GetDrawingStyle (fpVisAttribs);
503   switch (drawing_style) {
504     case G4ViewParameters::wireframe:
505       //vertices.clear();
506       break;
507     case G4ViewParameters::hlr:
508       break;
509     case G4ViewParameters::hsr:
510       //lines.clear();
511       break;
512     case G4ViewParameters::hlhsr:
513       break;
514     case G4ViewParameters::cloud:
515       // Shouldn't happen in this function (it's a polyhedron!) - ignore
516       return;
517   }
518 
519   auto currentNode = GetOrCreateNode();
520   if (!currentNode) return;  // Node not available
521   
522   tools::sg::separator* sep = new tools::sg::separator;
523   currentNode->add(sep);
524 
525   // Transformation
526  {tools::sg::matrix* mtx = new tools::sg::matrix;
527   G4Transform3D& elem = fObjectTransformation;
528   mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3),
529                               elem(1,0),elem(1,1),elem(1,2),elem(1,3),
530                               elem(2,0),elem(2,1),elem(2,2),elem(2,3),
531                                       0,        0,        0,        1);
532   sep->add(mtx);}
533 
534  {const auto& colour = GetColour(a_polyhedron);
535   tools::sg::rgba* mat = new tools::sg::rgba();
536   mat->color =
537     tools::colorf(float(colour.GetRed()),
538                   float(colour.GetGreen()),
539                   float(colour.GetBlue()),
540                   float(colour.GetAlpha()));
541   sep->add(mat);}
542 
543   if (drawing_style == G4ViewParameters::hlr ||
544       drawing_style == G4ViewParameters::hsr ||
545       drawing_style == G4ViewParameters::hlhsr) {
546 
547    {tools::sg::draw_style* ds = new tools::sg::draw_style;
548     ds->style = tools::sg::draw_filled;
549   //ds->cull_face = true;
550     sep->add(ds);}
551 
552     tools::sg::atb_vertices* vtxs = new tools::sg::atb_vertices;
553     vtxs->mode = tools::gl::triangles();
554     sep->add(vtxs);
555     
556     const auto nVerts = vertices.size();
557     for (size_t i = 0; i < nVerts; i++) {
558       vtxs->add(float(vertices[i].x()),float(vertices[i].y()),float(vertices[i].z()));
559       vtxs->add_normal(float(normals[i].x()),float(normals[i].y()),float(normals[i].z()));
560     }
561   }
562 
563   if (drawing_style == G4ViewParameters::wireframe ||
564       drawing_style == G4ViewParameters::hlr ||
565       drawing_style == G4ViewParameters::hlhsr) {
566 
567    {tools::sg::draw_style* ds = new tools::sg::draw_style;
568     ds->style = tools::sg::draw_lines;
569     ds->line_width = 1;
570     sep->add(ds);}
571 
572     tools::sg::vertices* vtxs = new tools::sg::vertices;
573     vtxs->mode = tools::gl::lines();  //segments
574     sep->add(vtxs);
575     
576     for (const auto& line: lines) {
577       vtxs->add(float(line.first.x()),float(line.first.y()),float(line.first.z()));
578       vtxs->add(float(line.second.x()),float(line.second.y()),float(line.second.z()));
579     }
580   
581   }
582 }
583 
584 void G4ToolsSGSceneHandler::AddCompound(const G4Mesh& mesh)
585 {
586   StandardSpecialMeshRendering(mesh);
587 }
588 
589 //plotting:
590 inline void SetRegionStyles(tools::xml::styles& a_styles,
591                 tools::sg::plots& a_plots,
592                 tools::sg::plotter& a_plotter,
593                             const G4String& a_style) {
594   if(a_style=="reset") {
595     a_plotter.reset_style(true);
596     a_plots.touch(); //to apply indirectly plots::set_plotter_layout() on _plotter.
597   } else if( (a_style=="inlib_default")|| (a_style=="default")) {
598     tools::sg::set_inlib_default_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_hershey());
599   } else if(a_style=="ROOT_default") {
600     tools::sg::set_ROOT_default_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_roboto_bold_ttf());
601   } else if(a_style=="hippodraw") {
602     tools::sg::set_hippodraw_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_lato_regular_ttf());
603   } else {
604     tools::sg::style_from_res(a_styles,a_style,a_plotter,false);
605   }
606 }
607 
608 inline tools::xml::styles::style_t* find_style(tools::xml::styles& a_styles,const std::string& a_name) {
609   tools_vforit(tools::xml::styles::named_style_t,a_styles.named_styles(),it){
610     if((*it).first==a_name) return &((*it).second);
611   }
612   return 0;
613 }
614 
615 inline void SetPlotterStyles(tools::sg::plots& a_plots,
616                              const std::vector<G4String>& a_plotter_styles,
617                              const std::vector<G4Plotter::RegionStyle>& a_region_styles) {
618 
619   G4PlotterManager::Styles& _styles = G4PlotterManager::GetInstance().GetStyles();
620  
621   tools::xml::styles _tools_styles(G4cout);
622   _tools_styles.add_colormap("default",tools::sg::style_default_colormap());
623   _tools_styles.add_colormap("ROOT",tools::sg::style_ROOT_colormap());
624   
625  {tools_vforcit(G4PlotterManager::NamedStyle,_styles,it) {
626     tools::xml::styles::style_t _tools_style;
627     tools_vforcit(G4PlotterManager::StyleItem,(*it).second,its) {
628       const G4String& param = (*its).first;
629       if(param.find('.')==std::string::npos) {
630         const G4String& value = (*its).second;
631         _tools_style.push_back(tools::xml::styles::style_item_t(param,value));
632       }
633     }
634     _tools_styles.add_style((*it).first,_tools_style);
635   }}
636 
637   // sub styles:
638  {tools_vforcit(G4PlotterManager::NamedStyle,_styles,it) {
639     tools_vforcit(G4PlotterManager::StyleItem,(*it).second,its) {
640       const G4String& param = (*its).first;
641       std::string::size_type pos = param.rfind('.');
642       if(pos!=std::string::npos) {
643   std::string sub_style = (*it).first+"."+param.substr(0,pos);
644         G4String parameter = param.substr(pos+1,param.size()-pos);
645         const G4String& value = (*its).second;
646         tools::xml::styles::style_t* _tools_style = find_style(_tools_styles,sub_style);
647   if(_tools_style) {
648           _tools_style->push_back(tools::xml::styles::style_item_t(parameter,value));
649   } else {
650           tools::xml::styles::style_t _tools_style_2;
651           _tools_style_2.push_back(tools::xml::styles::style_item_t(parameter,value));
652           _tools_styles.add_style(sub_style,_tools_style_2);
653   }
654       }
655     }
656   }}
657 
658  {unsigned int number = a_plots.number();
659   for(unsigned int index=0;index<number;index++) {
660     tools::sg::plotter* _plotter = a_plots.find_plotter(index);
661     if(_plotter) {
662       tools_vforcit(G4String,a_plotter_styles,it) {
663         SetRegionStyles(_tools_styles,a_plots,*_plotter,*it);
664       }
665     }
666   }}
667  {tools_vforcit(G4Plotter::RegionStyle,a_region_styles,it) {
668     tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first);
669     if(_plotter) {
670       SetRegionStyles(_tools_styles,a_plots,*_plotter,(*it).second);
671     }
672   }}
673 }
674 
675 inline void SetPlotterParameters(tools::sg::cmaps_t& a_cmaps,tools::sg::plots& a_plots,
676                                  const std::vector<G4Plotter::RegionParameter>& a_region_parameters) {
677   // parameter/field examples :
678   //   title_automated
679   //   title
680   //   bins_style.0.color
681   //   x_axis.divisions
682   //   x_axis.line_style.color
683   //   background_style.back_color
684   tools_vforcit(G4Plotter::RegionParameter,a_region_parameters,it) {
685     tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first);
686     if(_plotter) {
687       const G4String& parameter = (*it).second.first;
688       const G4String& value = (*it).second.second;
689       tools::sg::field* fd = _plotter->find_field_by_name(parameter);
690       if(!fd) fd = _plotter->find_field_by_name(_plotter->s_cls()+"."+parameter);
691       if(fd) {if(fd->s2value(value)) continue;}
692       // look for sf_enum for which value is given with a string, or
693       // for sf<bool> for which value given with true/false, or
694       // for a style, for example: bins_style.0.color:
695       if(!_plotter->set_from_string(G4cout,a_cmaps,parameter,value)) {
696         G4cout << "G4ToolsSGSceneHandler::SetPlotterParameters: plotter.set_from_string() failed for field "
697                << tools::sout(parameter) << ", and value " << tools::sout(value) << "."
698                << std::endl;
699       }
700     }
701   }
702 }
703 
704 #include "G4UImanager.hh"
705 
706 void G4ToolsSGSceneHandler::SetPlotterHistograms(tools::sg::plots& a_plots) {
707   a_plots.clear();
708   G4UImanager* UI = G4UImanager::GetUIpointer();
709   if(UI==NULL) return;
710  {tools_vforcit(Region_h1,fRegionH1s,it) {
711     tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first);
712     if(_plotter) {
713       int hid = (*it).second;
714       std::ostringstream os;
715       os << hid;
716       std::string cmd("/analysis/h1/get ");
717       cmd += std::string(os.str());
718       auto keepControlVerbose = UI->GetVerboseLevel();
719       UI->SetVerboseLevel(0);
720       G4int status = UI->ApplyCommand(cmd.c_str());
721       UI->SetVerboseLevel(keepControlVerbose);
722       if(status==G4UIcommandStatus::fCommandSucceeded) {
723         G4String hexString = UI->GetCurrentValues("/analysis/h1/get");
724         if(hexString.size()) {
725           void* ptr;
726           std::istringstream is(hexString);
727           is >> ptr;
728           tools::histo::h1d* _h = (tools::histo::h1d*)ptr;
729           tools::sg::plottable* p = new tools::sg::h1d2plot_cp(*_h);
730           _plotter->add_plottable(p); //give ownership of p to sg::plotter.
731         }
732       } else {
733         G4cerr <<
734         "G4ToolsSGSceneHandler::SetPlotterHistograms: cannot get histogram - maybe doesn't exist?"
735         "\n  Maybe this app does not do analysis at all?"
736         << G4endl;
737       }
738     }
739   }}
740  {tools_vforcit(Region_h2,fRegionH2s,it) {
741     tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first);
742     if(_plotter) {
743       int hid = (*it).second;
744       std::ostringstream os;
745       os << hid;
746       std::string cmd("/analysis/h2/get ");
747       cmd += std::string(os.str());
748       auto keepControlVerbose = UI->GetVerboseLevel();
749       UI->SetVerboseLevel(0);
750       G4int status = UI->ApplyCommand(cmd.c_str());
751       UI->SetVerboseLevel(keepControlVerbose);
752       if(status==G4UIcommandStatus::fCommandSucceeded) {
753         G4String hexString = UI->GetCurrentValues("/analysis/h2/get");
754         if(hexString.size()) {
755           void* ptr;
756           std::istringstream is(hexString);
757           is >> ptr;
758           tools::histo::h2d* _h = (tools::histo::h2d*)ptr;
759           tools::sg::plottable* p = new tools::sg::h2d2plot_cp(*_h);
760           _plotter->add_plottable(p); //give ownership of p to sg::plotter.
761         }
762       } else {
763         G4cerr <<
764         "G4ToolsSGSceneHandler::SetPlotterHistograms: cannot get histogram - maybe doesn't exist?"
765         "\n  Maybe this app does not do analysis at all?"
766         << G4endl;
767       }
768     }
769   }}
770 }
771 
772 class plots_cbk : public tools::sg::ecbk {
773   TOOLS_CBK(plots_cbk,plots_cbk,tools::sg::ecbk)
774 public:
775   virtual tools::sg::return_action action() {
776     if(const tools::sg::size_event* sz_evt = tools::sg::event_cast<tools::sg::event,tools::sg::size_event>(*m_event)){
777       m_plots.adjust_size(sz_evt->width(),sz_evt->height());
778       m_event_action->set_done(true);
779       return tools::sg::return_to_render;
780     }
781     return tools::sg::return_none;
782   }
783 public:
784   plots_cbk(tools::sg::plots& a_plots)
785   :parent()
786   ,m_plots(a_plots)
787   {}
788   virtual ~plots_cbk(){}
789 public:
790   plots_cbk(const plots_cbk& a_from)
791   :parent(a_from)
792   ,m_plots(a_from.m_plots)
793   {}
794   plots_cbk& operator=(const plots_cbk& a_from){
795     parent::operator=(a_from);
796     return *this;
797   }
798 protected:
799   tools::sg::plots& m_plots;
800 };
801 
802 void G4ToolsSGSceneHandler::TouchPlotters(tools::sg::node& a_sg) {
803   tools::sg::search_action sa(G4cout);
804   const tools::sg::search_action::paths_t& paths = tools::sg::find_paths<tools::sg::plots>(sa,a_sg);
805   tools_vforcit(tools::sg::path_t,paths,it) {
806     tools::sg::plots* _plots = tools::sg::tail<tools::sg::plots>(*it);    
807     if(_plots) {
808       SetPlotterHistograms(*_plots);
809     }
810   }
811 }
812 
813 void G4ToolsSGSceneHandler::AddPrimitive(const G4Plotter& a_plotter)
814 {
815 //G4cout << "debug : G4ToolsSGSceneHandler::AddPrimitive : 004" << std::endl;
816   if(!fpViewer) return;
817   
818   auto currentNode = GetOrCreateNode();
819   if (!currentNode) return;  // Node not available
820 
821   currentNode->add(new tools::sg::light_off());
822   
823   tools::sg::plots* _plots = new tools::sg::plots(*fFreetypeNode);
824   currentNode->add(_plots);
825   
826   _plots->view_border = false;
827   _plots->set_regions(a_plotter.GetColumns(),a_plotter.GetRows());
828 
829  {tools::sg::event_dispatcher* dpt = new tools::sg::event_dispatcher;
830   dpt->add_callback(new plots_cbk(*_plots));
831   currentNode->add(dpt);}
832 
833   SetPlotterStyles(*_plots,a_plotter.GetStyles(),a_plotter.GetRegionStyles());
834 
835   tools::sg::cmaps_t _cmaps;
836   _cmaps["default"] = tools::sg::style_default_colormap();
837   _cmaps["ROOT"] = tools::sg::style_ROOT_colormap();
838   
839   SetPlotterParameters(_cmaps,*_plots,a_plotter.GetRegionParameters());
840 
841   fRegionH1s = a_plotter.GetRegionH1s();
842   fRegionH2s = a_plotter.GetRegionH2s();
843 
844   SetPlotterHistograms(*_plots);
845 }
846 
847 void G4ToolsSGSceneHandler::Messenger::SetNewValue(G4UIcommand* a_cmd,G4String) {
848   G4VSceneHandler* pSceneHandler = GetVisManager()->GetCurrentSceneHandler();
849   if (!pSceneHandler) {
850     G4cout << "G4ToolsSGSceneHandler::Messenger::SetNewValue: no current sceneHandler.  Please create one." << G4endl;
851     return;
852   }
853   auto* tsg_scene_handler = dynamic_cast<G4ToolsSGSceneHandler*>(pSceneHandler);
854   if(!tsg_scene_handler) {
855     G4cout << "G4ToolsSGSceneHandler::Messenger::SetNewValue: current sceneHandler not a G4ToolsSGSceneHandler." << G4endl;
856     return;
857   }
858   if(a_cmd==print_plotter_params) {
859     tools::sg::dummy_freetype _ttf;
860     tools::sg::plotter _plotter(_ttf);
861     _plotter.print_available_customization(G4cout);
862   }
863 }
864