ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4XXXSGSceneHandler.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4XXXSGSceneHandler.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 //
28 //
29 // John Allison 10th March 2006
30 // A template for a sophisticated graphics driver with a scene graph.
31 //?? Lines beginning like this require specialisation for your driver.
32 
33 #include "G4XXXSGSceneHandler.hh"
34 
35 #include "G4XXXSGViewer.hh"
36 #include "G4PhysicalVolumeModel.hh"
37 #include "G4LogicalVolumeModel.hh"
38 #include "G4VPhysicalVolume.hh"
39 #include "G4LogicalVolume.hh"
40 #include "G4Box.hh"
41 #include "G4Polyline.hh"
42 #include "G4Text.hh"
43 #include "G4Circle.hh"
44 #include "G4Square.hh"
45 #include "G4Polyhedron.hh"
46 #include "G4UnitsTable.hh"
47 
48 #include <sstream>
49 
51 // Counter for XXX scene handlers.
52 
54  const G4String& name):
55  G4VSceneHandler(system, fSceneIdCount++, name)
56 {}
57 
59 
60 #ifdef G4XXXSGDEBUG
61 // Useful function...
62 void G4XXXSGSceneHandler::PrintThings() {
63  G4cout <<
64  " with transformation "
65  << (void*)fpObjectTransformation;
66  if (fpModel) {
67  G4cout << " from " << fpModel->GetCurrentDescription()
68  << " (tag " << fpModel->GetCurrentTag()
69  << ')';
70  } else {
71  G4cout << "(not from a model)";
72  }
73  G4PhysicalVolumeModel* pPVModel =
74  dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
75  if (pPVModel) {
76  G4cout <<
77  "\n current physical volume: "
78  << pPVModel->GetCurrentPV()->GetName() <<
79  "\n current logical volume: "
80 // There might be a problem with the LV pointer if this is a G4LogicalVolumeModel
81  << pPVModel->GetCurrentLV()->GetName() <<
82  "\n current depth of geometry tree: "
83  << pPVModel->GetCurrentDepth();
84  }
85  G4cout << G4endl;
86 }
87 #endif
88 
90  // Utility for PreAddSolid and BeginPrimitives.
91 
92  G4PhysicalVolumeModel* pPVModel =
93  dynamic_cast<G4PhysicalVolumeModel*>(fpModel);
94  G4LogicalVolumeModel* pLVModel =
95  dynamic_cast<G4LogicalVolumeModel*>(pPVModel);
96  if (pPVModel && !pLVModel) {
97 
98  // This call comes from a G4PhysicalVolumeModel. drawnPVPath is
99  // the path of the current drawn (non-culled) volume in terms of
100  // drawn (non-culled) ancestors. Each node is identified by a
101  // PVNodeID object, which is a physical volume and copy number. It
102  // is a vector of PVNodeIDs corresponding to the geometry hierarchy
103  // actually selected, i.e., not culled.
105  typedef std::vector<PVNodeID> PVPath;
106  const PVPath& drawnPVPath = pPVModel->GetDrawnPVPath();
107  //G4int currentDepth = pPVModel->GetCurrentDepth();
108  //G4VPhysicalVolume* pCurrentPV = pPVModel->GetCurrentPV();
109  //G4LogicalVolume* pCurrentLV = pPVModel->GetCurrentLV();
110  //G4Material* pCurrentMaterial = pPVModel->GetCurrentMaterial();
111  // Note: pCurrentMaterial may be zero (parallel world).
112 
113  // The simplest algorithm, used by the Open Inventor Driver
114  // developers, is to rely on the fact the G4PhysicalVolumeModel
115  // traverses the geometry hierarchy in an orderly manner. The last
116  // mother, if any, will be the node to which the volume should be
117  // added. So it is enough to keep a map of scene graph nodes keyed
118  // on the volume path ID. Actually, it is enough to use the logical
119  // volume as the key. (An alternative would be to keep the PVNodeID
120  // in the tree and match the PVPath from the root down.)
121 
122  // BUT IN OPENGL, IF THERE ARE TRANSPARENT OBJECTS, VOLUMES DO NOT
123  // ARRIVE IN THE ABOVE ORDER. (TRANSPARENT OBJECTS ARE DRWAN
124  // LAST.) SO WE MUST BE MORE SOPHISTICATED IN CONSTRUCTING A
125  // TREE.
126 
127  /* Debug
128  for (size_t i = 0; i < drawnPVPath.size(); ++i) {
129  std::cout << drawnPVPath[i].GetPhysicalVolume()->GetName() << ":"
130  << drawnPVPath[i].GetCopyNo() << " ("
131  << currentPOListIndex << "), ";
132  }
133  std::cout << std::endl;
134  */
135 
136  static G4int index = 0; // Some index for future reference
137  JA::Insert(&drawnPVPath[0],drawnPVPath.size(),index++,&fSceneGraph);
138  //JA::PrintTree(std::cout,&root);
139 
140  /*** Old algorithm, left here for historical interest!!
141  // Find mother. ri points to drawn mother, if any.
142  PVPath::const_reverse_iterator ri = ++drawnPVPath.rbegin();
143  if (ri != drawnPVPath.rend()) {
144  // This volume has a mother.
145  G4LogicalVolume* drawnMotherLV =
146  ri->GetPhysicalVolume()->GetLogicalVolume();
147  LVMapIterator mother = fLVMap.find(drawnMotherLV);
148  if (mother != fLVMap.end()) {
149  // This adds a child in Troy's tree...
150  fCurrentItem = mother->second.push_back(header);
151  } else {
152  // Mother not previously encountered. Shouldn't happen, since
153  // G4PhysicalVolumeModel sends volumes as it encounters them,
154  // i.e., mothers before daughters, in its descent of the
155  // geometry tree. Error!
156  G4cout << "ERROR: G4XXXSGSceneHandler::PreAddSolid: Mother "
157  << ri->GetPhysicalVolume()->GetName()
158  << ':' << ri->GetCopyNo()
159  << " not previously encountered."
160  "\nShouldn't happen! Please report to visualization coordinator."
161  << G4endl;
162  // Continue anyway. Add to root of scene graph tree...
163  fCurrentItem = fPermanentsRoot.push_back(header);
164  }
165  } else {
166  // This volume has no mother. Must be a top level un-culled
167  // volume. Add to root of scene graph tree...
168  fCurrentItem = fPermanentsRoot.push_back(header);
169  }
170 
171  std::ostringstream oss;
172  oss << "Path of drawn PVs: ";
173  for (PVPath::const_iterator i = drawnPVPath.begin();
174  i != drawnPVPath.end(); ++i) {
175  oss << '/' << i->GetPhysicalVolume()->GetName()
176  << ':' << i->GetCopyNo();
177  }
178  oss << std::endl;
179  *fCurrentItem += oss.str();
180 
181  // Store for future searches. Overwrites previous entries for this
182  // LV, so entry is always the *last* LV.
183  fLVMap[pCurrentLV] = fCurrentItem;
184  ***/
185 
186  } else { // Not from a G4PhysicalVolumeModel.
187 
188  /***
189  // Create a place for current solid in root...
190  if (fReadyForTransients) {
191  fCurrentItem = fTransientsRoot.push_back(header);
192  } else {
193  fCurrentItem = fPermanentsRoot.push_back(header);
194  }
195  ***/
196  }
197 }
198 
200 (const G4Transform3D& objectTransformation,
201  const G4VisAttributes& visAttribs)
202 {
203  G4VSceneHandler::PreAddSolid(objectTransformation, visAttribs);
204  CreateCurrentItem(G4String("\nPreAddSolid:\n"));
205 }
206 
208 {
210 }
211 
213 (const G4Transform3D& objectTransformation)
214 {
215  G4VSceneHandler::BeginPrimitives(objectTransformation);
216 }
217 
219 {
221 }
222 
223 // Note: This function overrides G4VSceneHandler::AddSolid(const
224 // G4Box&). You may not want to do this, but this is how it's done if
225 // you do. Certain other specific solids may be treated this way -
226 // see G4VSceneHandler.hh. The simplest possible driver would *not*
227 // implement these polymorphic functions, with the effect that the
228 // default versions in G4VSceneHandler are used, which simply call
229 // G4VSceneHandler::RequestPrimitives to turn the solid into a
230 // G4Polyhedron usually.
231 // Don't forget, solids can be transients too (e.g., representing a hit).
233 #ifdef G4XXXSGDEBUG
234  G4cout <<
235  "G4XXXSGSceneHandler::AddSolid(const G4Box& box) called for "
236  << box.GetName()
237  << G4endl;
238 #endif
239  //?? Process your box...
240  std::ostringstream oss;
241  oss << "G4Box(" <<
242  G4String
243  (G4BestUnit
245  (box.GetXHalfLength(), box.GetYHalfLength(), box.GetZHalfLength()),
246  "Length")).strip() << ')' << std::endl;
247  //*fCurrentItem += oss.str();
248 }
249 
251 #ifdef G4XXXSGDEBUG
252  G4cout <<
253  "G4XXXSGSceneHandler::AddPrimitive(const G4Polyline& polyline) called.\n"
254  << polyline
255  << G4endl;
256 #endif
257  // Get vis attributes - pick up defaults if none.
258  //const G4VisAttributes* pVA =
259  // fpViewer -> GetApplicableVisAttributes (polyline.GetVisAttributes ());
260  //?? Process polyline.
261  std::ostringstream oss;
262  oss << polyline << std::endl;
263  //*fCurrentItem += oss.str();
264 }
265 
267 #ifdef G4XXXSGDEBUG
268  G4cout <<
269  "G4XXXSGSceneHandler::AddPrimitive(const G4Text& text) called.\n"
270  << text
271  << G4endl;
272 #endif
273  // Get text colour - special method since default text colour is
274  // determined by the default text vis attributes, which may be
275  // specified independent of default vis attributes of other types of
276  // visible objects.
277  //const G4Colour& c = GetTextColour (text); // Picks up default if none.
278  //?? Process text.
279  std::ostringstream oss;
280  oss << text << std::endl;
281  //*fCurrentItem += oss.str();
282 }
283 
285 #ifdef G4XXXSGDEBUG
286  G4cout <<
287  "G4XXXSGSceneHandler::AddPrimitive(const G4Circle& circle) called.\n"
288  << circle
289  << G4endl;
290  MarkerSizeType sizeType;
291  G4double size = GetMarkerSize (circle, sizeType);
292  switch (sizeType) {
293  default:
294  case screen:
295  // Draw in screen coordinates.
296  G4cout << "screen";
297  break;
298  case world:
299  // Draw in world coordinates.
300  G4cout << "world";
301  break;
302  }
303  G4cout << " size: " << size << G4endl;
304 #endif
305  // Get vis attributes - pick up defaults if none.
306  //const G4VisAttributes* pVA =
307  // fpViewer -> GetApplicableVisAttributes (circle.GetVisAttributes ());
308  //?? Process circle.
309  std::ostringstream oss;
310  oss << circle << std::endl;
311  //*fCurrentItem += oss.str();
312 }
313 
315 #ifdef G4XXXSGDEBUG
316  G4cout <<
317  "G4XXXSGSceneHandler::AddPrimitive(const G4Square& square) called.\n"
318  << square
319  << G4endl;
320  MarkerSizeType sizeType;
321  G4double size = GetMarkerSize (square, sizeType);
322  switch (sizeType) {
323  default:
324  case screen:
325  // Draw in screen coordinates.
326  G4cout << "screen";
327  break;
328  case world:
329  // Draw in world coordinates.
330  G4cout << "world";
331  break;
332  }
333  G4cout << " size: " << size << G4endl;
334 #endif
335  // Get vis attributes - pick up defaults if none.
336  //const G4VisAttributes* pVA =
337  // fpViewer -> GetApplicableVisAttributes (square.GetVisAttributes ());
338  //?? Process square.
339  std::ostringstream oss;
340  oss << square << std::endl;
341  //*fCurrentItem += oss.str();
342 }
343 
345 #ifdef G4XXXSGDEBUG
346  G4cout <<
347  "G4XXXSGSceneHandler::AddPrimitive(const G4Polyhedron& polyhedron) called.\n"
348  << polyhedron
349  << G4endl;
350 #endif
351  //?? Process polyhedron.
352  std::ostringstream oss;
353  oss << polyhedron;
354  //*fCurrentItem += oss.str();
355 
356  //?? Or... here are some ideas for decomposing into polygons...
357  //Assume all facets are convex quadrilaterals.
358  //Draw each G4Facet individually
359 
360  //Get colour, etc..
361  if (polyhedron.GetNoFacets() == 0) return;
362 
363  // Get vis attributes - pick up defaults if none.
364  const G4VisAttributes* pVA =
365  fpViewer -> GetApplicableVisAttributes (polyhedron.GetVisAttributes ());
366 
367  // Get view parameters that the user can force through the vis
368  // attributes, thereby over-riding the current view parameter.
369  G4ViewParameters::DrawingStyle drawing_style = GetDrawingStyle (pVA);
370  //G4bool isAuxEdgeVisible = GetAuxEdgeVisible (pVA);
371 
372  //Get colour, etc..
373  //const G4Colour& c = pVA -> GetColour ();
374 
375  // Initial action depending on drawing style.
376  switch (drawing_style) {
377  case (G4ViewParameters::hsr):
378  {
379  break;
380  }
381  case (G4ViewParameters::hlr):
382  {
383  break;
384  }
386  {
387  break;
388  }
389  default:
390  {
391  break;
392  }
393  }
394 
395  // Loop through all the facets...
396 
397  // Look at G4OpenGLSceneHandler::AddPrimitive(const G4Polyhedron&)
398  // for an example of how to get facets out of a G4Polyhedron,
399  // including how to cope with triangles if that's a problem.
400 }
401 
403 {
405 }
406 
408 {
410 }
411 
412 namespace JA {
413 // Ad hoc tree class and utilities.
414 
415 #include "G4VPhysicalVolume.hh"
416 
417 void Insert(const PVNodeID* pvPath, size_t pathLength,
418  G4int index, Node* node) {
419  // Path passed as a PVNodeID* to avoid copying.
420 
421  /* Debug
422  for (size_t i = 0; i < pathLength; ++i) {
423  std::cout << pvPath[i].GetPhysicalVolume()->GetName() << ":"
424  << pvPath[i].GetCopyNo() << " ("
425  << index << "), ";
426  }
427  */
428 
429  // See if node has been encountered before
430  G4bool found = false; size_t foundPosition = 0;
431  for (size_t i = 0; i < node->fDaughters.size(); ++i) {
432  PVNodeID& daughterPVNodeID = node->fDaughters[i]->fPVNodeID;
433  // It is enough to compare volume and copy number at a given position in the tree
434  if (daughterPVNodeID.GetPhysicalVolume() == pvPath[0].GetPhysicalVolume() &&
435  daughterPVNodeID.GetCopyNo() == pvPath[0].GetCopyNo()) {
436  found = true;
437  foundPosition = i;
438  break;
439  }
440  }
441 
442  if (pathLength == 1) { // This is a leaf
443  if (found) { // Update index
444  node->fDaughters[foundPosition]->fIndex = index;
445  } else { // Make a new full entry
446  node->fDaughters.push_back(new Node(pvPath[0],index));
447  }
448  /* Debug
449  std::cout << std::endl;
450  */
451  } else { // Not a leaf - carry on with rest of path
452  if (found) { // Just carry on
453  Insert(pvPath+1,--pathLength,index,
454  node->fDaughters[foundPosition]);
455  } else { // Insert place holder, then carry on
456  node->fDaughters.push_back(new Node(pvPath[0]));
457  Insert(pvPath+1,--pathLength,index,
458  node->fDaughters[node->fDaughters.size()-1]);
459  }
460  }
461 }
462 
463 void PrintTree(std::ostream& os, Node* node)
464 {
465  static G4int depth = -1;
466  depth++;
467  PVNodeID& thisPVNodeID = node->fPVNodeID;
468  G4int& thisIndex = node->fIndex;
469  const size_t& nDaughters = node->fDaughters.size();
470  G4VPhysicalVolume* thisPhysicalVolume= thisPVNodeID.GetPhysicalVolume();
471  if (!thisPhysicalVolume) os << "Root" << std::endl;
472  else {
473  for (G4int i = 0; i < depth; ++i) os << "__";
474  os << thisPVNodeID.GetPhysicalVolume()->GetName() << ":"
475  << thisPVNodeID.GetCopyNo() << " ("
476  << thisIndex << ")" << std::endl;;
477  }
478  for (size_t i = 0; i < nDaughters; ++i) {
479  PrintTree(os, node->fDaughters[i]);
480  }
481  depth--;
482 }
483 
484 void Clear(Node* node)
485 {
486  const size_t& nDaughters = node->fDaughters.size();
487  for (size_t i = 0; i < nDaughters; ++i) {
488  Clear(node->fDaughters[i]);
489  delete node->fDaughters[i];
490  }
491 }
492 
493 } // End namespace JA