Belle II Software  release-05-02-19
FBXWriterModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2011 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Leo Piilonen *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <geometry/modules/fbxWriter/FBXWriterModule.h>
12 #include <geometry/GeometryManager.h>
13 
14 #include "G4PhysicalVolumeStore.hh"
15 #include "G4LogicalVolumeStore.hh"
16 #include "G4SolidStore.hh"
17 #include "G4VPhysicalVolume.hh"
18 #include "G4LogicalVolume.hh"
19 #include "G4VSolid.hh"
20 #include "G4DisplacedSolid.hh"
21 #include "G4Material.hh"
22 #include "G4VisAttributes.hh"
23 #include "G4ThreeVector.hh"
24 #include "G4RotationMatrix.hh"
25 #include "G4Transform3D.hh"
26 #include "G4VPVParameterisation.hh"
27 #include <G4Tubs.hh>
28 #include <G4Polyhedron.hh>
29 
30 #include <iomanip>
31 
32 using namespace Belle2;
33 
34 REG_MODULE(FBXWriter);
35 
37 {
38  //Set module properties and the description
39  setDescription("Write the detector geometry in a (semi-)hierarchical FBX format.");
40 
41  //Parameter definition
42  addParam("usePrototypes", m_UsePrototypes, "Use LogVol and PhysVol prototypes", false);
43 
44  //Parameter definition
45  addParam("outputFile", m_Filename, "Output filename", std::string("belle2.fbx"));
46 }
47 
49 {
50  m_First = true;
51 }
52 
54 {
55  if (!m_First) return;
56  m_First = false;
57  G4VPhysicalVolume* topVol = geometry::GeometryManager::getInstance().getTopVolume();
58  if (!topVol) {
59  B2ERROR("No geometry found: add the Geometry module to the path before the FBXWriter module.");
60  return;
61  }
62 
63  G4PhysicalVolumeStore* pvStore = G4PhysicalVolumeStore::GetInstance();
64  G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
65  G4SolidStore* solidStore = G4SolidStore::GetInstance();
66 
67  // Assign legal and unique names to each used physical volume, logical volume and solid
68  m_PVName = new std::vector<std::string>(pvStore->size(), "");
69  m_LVName = new std::vector<std::string>(lvStore->size(), "");
70  m_SolidName = new std::vector<std::string>(solidStore->size(), "");
71  for (G4VPhysicalVolume* physVol : *pvStore) {
72  int pvIndex = std::find(pvStore->begin(), pvStore->end(), physVol) - pvStore->begin();
73  if ((*m_PVName)[pvIndex].length() == 0) {
74  assignName(m_PVName, pvIndex, physVol->GetName(), 0);
75  G4LogicalVolume* logVol = physVol->GetLogicalVolume();
76  int lvIndex = std::find(lvStore->begin(), lvStore->end(), logVol) - lvStore->begin();
77  if ((*m_LVName)[lvIndex].length() == 0) {
78  assignName(m_LVName, lvIndex, logVol->GetName(), 1);
79  G4VSolid* solid = logVol->GetSolid();
80  int solidIndex = std::find(solidStore->begin(), solidStore->end(), solid) - solidStore->begin();
81  if ((*m_SolidName)[solidIndex].length() == 0) {
82  assignName(m_SolidName, solidIndex, solid->GetName(), 2);
83  }
84  }
85  }
86  }
87 
88  // Count the number of references to each physical volume and logical volume and solid
89  // so that these values can be placed in the FBX file's Definitions{} section.
90  m_PVCount = new std::vector<unsigned int>(pvStore->size(), 0);
91  m_LVCount = new std::vector<unsigned int>(lvStore->size(), 0);
92  m_SolidCount = new std::vector<unsigned int>(solidStore->size(), 0);
93  m_PVReplicas = new std::vector<unsigned int>(pvStore->size(), 0);
94  m_LVReplicas = new std::vector<unsigned int>(lvStore->size(), 0);
95  m_SolidReplicas = new std::vector<unsigned int>(solidStore->size(), 0);
96  m_LVUnique = new std::vector<bool>(lvStore->size(), true);
97  countEntities(topVol);
98  unsigned int geometryCount = 0;
99  unsigned int materialCount = 0;
100  unsigned int modelCount = 0;
101  for (unsigned int pvIndex = 0; pvIndex < pvStore->size(); ++pvIndex) {
102  if ((*m_PVName)[pvIndex].length() > 0) {
103  modelCount += (*m_PVCount)[pvIndex] + (*m_PVReplicas)[pvIndex];
104  }
105  }
106  for (unsigned int lvIndex = 0; lvIndex < lvStore->size(); ++lvIndex) {
107  if ((*m_LVName)[lvIndex].length() > 0) {
108  if (!(*m_LVUnique)[lvIndex]) {
109  modelCount += (*m_LVCount)[lvIndex] + (*m_LVReplicas)[lvIndex];
110  }
111  materialCount++;
112  }
113  }
114  for (unsigned int solidIndex = 0; solidIndex < solidStore->size(); ++solidIndex) {
115  if ((*m_SolidName)[solidIndex].length() > 0) {
116  geometryCount += (*m_SolidCount)[solidIndex] + (*m_SolidReplicas)[solidIndex] + 1;
117  }
118  }
119 
120  m_File.open(m_Filename, std::ios_base::trunc);
121  writePreamble(modelCount, materialCount, geometryCount);
122 
123  // Write all solids as Geometry nodes (replicas are written later).
124  // Write all logical volumes as Material nodes (color information).
125  // Write all physical and logical volumes as Model nodes (with replica-solids treated here).
126  m_PVID = new std::vector<unsigned long long>(pvStore->size(), 0x0000010000000000LL);
127  m_LVID = new std::vector<unsigned long long>(lvStore->size(), 0x000000C000000000LL);
128  m_SolidID = new std::vector<unsigned long long>(solidStore->size(), 0x0000008000000000LL);
129  m_MatID = new std::vector<unsigned long long>(lvStore->size(), 0x0000004000000000LL);
130  m_Visible = new std::vector<bool>(lvStore->size(), false);
131  m_File << "Objects: {" << std::endl;
132  for (unsigned int solidIndex = 0; solidIndex < solidStore->size(); ++solidIndex) {
133  (*m_SolidID)[solidIndex] += 0x0000000001000000LL * solidIndex;
134  if ((*m_SolidName)[solidIndex].length() > 0) {
135  for (unsigned int solidCount = 0; solidCount <= (*m_SolidCount)[solidIndex]; ++solidCount) { // note lower and upper limits!
136  writeGeometryNode((*solidStore)[solidIndex], (*m_SolidName)[solidIndex], (*m_SolidID)[solidIndex] + solidCount);
137  }
138  }
139  }
140  for (unsigned int lvIndex = 0; lvIndex < lvStore->size(); ++lvIndex) {
141  (*m_MatID)[lvIndex] += 0x0000000001000000LL * lvIndex;
142  (*m_LVID)[lvIndex] += 0x0000000001000000LL * lvIndex;
143  if ((*m_LVName)[lvIndex].length() > 0) {
144  if (!(*m_LVUnique)[lvIndex]) writeMaterialNode(lvIndex, (*m_LVName)[lvIndex]);
145  }
146  }
147  for (unsigned int pvIndex = 0; pvIndex < pvStore->size(); ++pvIndex) {
148  (*m_PVID)[pvIndex] += 0x0000000001000000LL * pvIndex;
149  }
150  m_PVCount->assign(pvStore->size(), 0);
151  m_LVCount->assign(lvStore->size(), 0);
152  m_SolidCount->assign(solidStore->size(), 0);
153  addModels(topVol, 0);
154  m_File << "}" << std::endl << std::endl;
155 
156  // Recursively write the connections among the solid and logical/physical volume elements
157  m_PVCount->assign(pvStore->size(), 0);
158  m_LVCount->assign(lvStore->size(), 0);
159  m_SolidCount->assign(solidStore->size(), 0);
160  m_File << "Connections: {" << std::endl;
161  addConnections(topVol, 0);
162  int pvIndex = std::find(pvStore->begin(), pvStore->end(), topVol) - pvStore->begin();
163  m_File << "\t; Physical volume Model::" << (*m_PVName)[pvIndex] << " to Model::RootNode" << std::endl <<
164  "\tC: \"OO\"," << (*m_PVID)[pvIndex] << ",0" << std::endl << std::endl <<
165  "}" << std::endl << std::endl;
166 
167  m_File << "Takes: {" << std::endl <<
168  "\tCurrent: \"\"" << std::endl <<
169  "}" << std::endl;
170 
171  m_File.close();
172  B2INFO("FBX written to " << m_Filename);
173 
174  delete m_PVName;
175  delete m_LVName;
176  delete m_SolidName;
177  delete m_PVID;
178  delete m_LVID;
179  delete m_MatID;
180  delete m_SolidID;
181  delete m_PVCount;
182  delete m_LVCount;
183  delete m_SolidCount;
184  delete m_Visible;
185 
186 }
187 
188 void FBXWriterModule::assignName(std::vector<std::string>* names, unsigned int index, const G4String& originalName, int select)
189 {
190  G4PhysicalVolumeStore* pvStore = G4PhysicalVolumeStore::GetInstance();
191  G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
192  G4SolidStore* solidStore = G4SolidStore::GetInstance();
193 
194  G4String name = originalName;
195  if (name.length() == 0) { name = "anonymous"; }
196  // Replace problematic characters with underscore
197  for (char c : " .,:;?'\"*+-=|^!/@#$\\%{}[]()<>") std::replace(name.begin(), name.end(), c, '_');
198  // Avoid duplicate names for entities that will be written to FBX file
199  for (int j = (int)index - 1; j >= 0; --j) {
200  if ((*names)[j].length() == 0) continue;
201  int match = 0;
202  switch (select) {
203  case 0:
204  match = (*pvStore)[j]->GetName().compare((*pvStore)[index]->GetName()); break;
205  case 1:
206  match = (*lvStore)[j]->GetName().compare((*lvStore)[index]->GetName()); break;
207  case 2:
208  match = (*solidStore)[j]->GetName().compare((*solidStore)[index]->GetName()); break;
209  }
210  if (match == 0) {
211  if (name.length() == (*names)[j].length()) {
212  (*names)[j].append("_1");
213  }
214  int n = std::stoi((*names)[j].substr(name.length() + 1), nullptr);
215  name.append("_");
216  name.append(std::to_string(n + 1));
217  break;
218  }
219  }
220  (*names)[index] = name;
221 }
222 
223 void FBXWriterModule::writeGeometryNode(G4VSolid* solid, const std::string& solidName, unsigned long long solidID)
224 {
225  if ((solid->GetEntityType() == "G4IntersectionSolid") ||
226  (solid->GetEntityType() == "G4UnionSolid") ||
227  (solid->GetEntityType() == "G4SubtractionSolid") ||
228  (solid->GetEntityType() == "G4BooleanSolid")) {
229  HepPolyhedron* polyhedron = getBooleanSolidPolyhedron(solid);
230  auto* g4polyhedron = new G4Polyhedron(*polyhedron);
231  writePolyhedron(solid, g4polyhedron, solidName, solidID);
232  delete polyhedron;
233  delete g4polyhedron;
234  } else {
235  writePolyhedron(solid, solid->GetPolyhedron(), solidName, solidID);
236  }
237 }
238 
239 void FBXWriterModule::writeMaterialNode(int lvIndex, const std::string& matName)
240 {
241  G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
242  G4LogicalVolume* logVol = (*lvStore)[lvIndex];
243  unsigned long long matID = (*m_MatID)[lvIndex];
244  G4Color color(0.0, 1.0, 0.0, 0.5); // default is semi-transparent green
245  if ((matName.compare(0, 23, "eclBarrelCrystalLogical") == 0) ||
246  (matName.compare(0, 20, "eclFwdCrystalLogical") == 0) ||
247  (matName.compare(0, 20, "eclBwdCrystalLogical") == 0) ||
248  (matName.compare(0, 24, "eclBarrelCrystalPhysical") == 0) ||
249  (matName.compare(0, 21, "eclFwdCrystalPhysical") == 0) ||
250  (matName.compare(0, 21, "eclBwdCrystalPhysical") == 0)) {
251  color = G4Color(1.0, 0.25, 0.0, 0.7); // orange since ECL crystals have no G4VisAttribute :(
252  }
253  bool visible = true;
254  G4String materialName = logVol->GetMaterial()->GetName();
255  // Hide containers that have vacuum, air or gas
256  if (materialName == "Vacuum") visible = false;
257  if (materialName == "G4_AIR") visible = false;
258  if (materialName == "CDCGas") visible = false;
259  if (materialName == "ColdAir") visible = false;
260  if (materialName == "STR-DryAir") visible = false;
261  if (materialName == "TOPAir") visible = false;
262  if (materialName == "TOPVacuum") visible = false;
263  const G4VisAttributes* visAttr = logVol->GetVisAttributes();
264  if (visAttr) {
265  color = const_cast<G4Color&>(logVol->GetVisAttributes()->GetColor());
266  if (!(visAttr->IsVisible())) visible = false;
267  } else {
268  visible = false;
269  }
270  if (logVol->GetSensitiveDetector() != nullptr) visible = "";
271  (*m_Visible)[lvIndex] = visible;
272  m_File << "\t; Color for LogVol " << logVol->GetName() << std::endl <<
273  "\tMaterial: " << matID << ", \"Material::" << matName << R"(", "" {)" << std::endl <<
274  "\t\tVersion: 102" << std::endl <<
275  "\t\tProperties70: {" << std::endl <<
276  "\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\"" << std::endl <<
277  "\t\t\tP: \"DiffuseColor\", \"RGBColor\", \"Color\", \"A\"," <<
278  color.GetRed() << "," << color.GetGreen() << "," << color.GetBlue() << std::endl <<
279  "\t\t\tP: \"TransparentColor\", \"RGBColor\", \"Color\", \"A\",1,1,1" << std::endl <<
280  "\t\t\tP: \"TransparencyFactor\", \"double\", \"Number\", \"\"," << (visible ? 1.0 - color.GetAlpha() : 1) << std::endl <<
281  "\t\t}" << std::endl <<
282  "\t}" << std::endl;
283 }
284 
285 void FBXWriterModule::writeLVModelNode(G4LogicalVolume* logVol, const std::string& lvName, unsigned long long lvID)
286 {
287  m_File << "\t; LogVol " << logVol->GetName() << " with solid " << logVol->GetSolid()->GetName() << std::endl <<
288  "\tModel: " << lvID << ", \"Model::lv_" << lvName << R"(", "Null" {)" << std::endl <<
289  "\t\tVersion: 232" << std::endl <<
290  "\t\tProperties70: {" << std::endl <<
291  "\t\t}" << std::endl <<
292  "\t\tShading: T" << std::endl <<
293  "\t\tCulling: \"CullingOff\"" << std::endl <<
294  "\t}" << std::endl;
295 }
296 
297 void FBXWriterModule::addModels(G4VPhysicalVolume* physVol, int replica)
298 {
299  // Descend to the leaves of the tree
300  G4LogicalVolume* logVol = physVol->GetLogicalVolume();
301  for (int daughter = 0; daughter < logVol->GetNoDaughters(); ++daughter) {
302  G4VPhysicalVolume* physVolDaughter = logVol->GetDaughter(daughter);
303  for (int j = 0; j < physVolDaughter->GetMultiplicity(); ++j) {
304  addModels(physVolDaughter, j);
305  }
306  }
307 
308  // Write the physical- and logical-volume models as we ascend the recursive tree
309  G4PhysicalVolumeStore* pvStore = G4PhysicalVolumeStore::GetInstance();
310  G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
311  int pvIndex = std::find(pvStore->begin(), pvStore->end(), physVol) - pvStore->begin();
312  unsigned long long pvID = (*m_PVID)[pvIndex];
313  unsigned int pvCount = (*m_PVCount)[pvIndex];
314  std::string pvName = (*m_PVName)[pvIndex];
315  int lvIndex = std::find(lvStore->begin(), lvStore->end(), logVol) - lvStore->begin();
316  unsigned long long lvID = (*m_LVID)[lvIndex];
317  unsigned int lvCount = (*m_LVCount)[lvIndex];
318  std::string lvName = (*m_LVName)[lvIndex];
319  if ((*m_LVUnique)[lvIndex]) writeMaterialNode(lvIndex, (*m_PVName)[pvIndex]);
320  if (physVol->IsReplicated()) {
321  G4VSolid* solid = logVol->GetSolid();
322  G4SolidStore* solidStore = G4SolidStore::GetInstance();
323  int solidIndex = std::find(solidStore->begin(), solidStore->end(), solid) - solidStore->begin();
324  unsigned long long solidID = (*m_SolidID)[solidIndex];
325  EAxis axis;
326  G4int nReplicas;
327  G4double width;
328  G4double offset;
329  G4bool consuming;
330  physVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
331  physVol->SetCopyNo(replica);
332  G4VPVParameterisation* physParameterisation = physVol->GetParameterisation();
333  if (physParameterisation) { // parameterised volume
334  G4VSolid* solidReplica = physParameterisation->ComputeSolid(replica, physVol);
335  physParameterisation->ComputeTransformation(replica, physVol);
336  solidReplica->ComputeDimensions(physParameterisation, replica, physVol);
337  if (!(*solidReplica == *solid)) {
338  std::string solidName = (*m_SolidName)[solidIndex];
339  solidName.append("_R");
340  solidName.append(std::to_string(replica));
341  writeGeometryNode(solidReplica, solidName, solidID + 0x00010000 * replica);
342  }
343  if (m_UsePrototypes && (*solidReplica == *solid)) {
344  if ((replica == 0) && (lvCount == 0)) {
345  if (!(*m_LVUnique)[lvIndex]) writeLVModelNode((*lvStore)[lvIndex], lvName, lvID);
346  }
347  } else {
348  // DIVOT lvName.append("_R");
349  // DIVOT lvName.append(std::to_string(replica));
350  // DIVOT writeLVModelNode((*lvStore)[lvIndex], lvName, lvID+0x00010000*replica+lvCount);
351  }
352  pvName.append("_R");
353  pvName.append(std::to_string(replica));
354  writePVModelNode(physVol, pvName, pvID + 0x00010000 * replica + pvCount);
355  } else { // plain replicated volume
356  G4RotationMatrix* originalRotation = physVol->GetRotation();
357  G4ThreeVector translation; // No translation
358  G4RotationMatrix rotation; // No rotation
359  switch (axis) {
360  default:
361  case kXAxis:
362  translation.setX(width * (replica - 0.5 * (nReplicas - 1)));
363  physVol->SetTranslation(translation);
364  break;
365  case kYAxis:
366  translation.setY(width * (replica - 0.5 * (nReplicas - 1)));
367  physVol->SetTranslation(translation);
368  break;
369  case kZAxis:
370  translation.setZ(width * (replica - 0.5 * (nReplicas - 1)));
371  physVol->SetTranslation(translation);
372  break;
373  case kRho:
374  if (solid->GetEntityType() == "G4Tubs") {
375  double originalRMin = ((G4Tubs*)solid)->GetInnerRadius();
376  double originalRMax = ((G4Tubs*)solid)->GetOuterRadius();
377  ((G4Tubs*)solid)->SetInnerRadius(offset + width * replica);
378  ((G4Tubs*)solid)->SetOuterRadius(offset + width * (replica + 1));
379  std::string solidName = (*m_SolidName)[solidIndex];
380  solidName.append("_R");
381  solidName.append(std::to_string(replica));
382  writeGeometryNode(solid, solidName, (*m_SolidID)[solidIndex] + 0x00010000 * replica);
383  ((G4Tubs*)solid)->SetInnerRadius(originalRMin);
384  ((G4Tubs*)solid)->SetOuterRadius(originalRMax);
385  } else if (replica == 0) {
386  B2WARNING("Built-in volumes replicated along radius for " << solid->GetEntityType() <<
387  " (solid " << solid->GetName() << ") are not visualisable.");
388  }
389  break;
390  case kPhi:
391  physVol->SetRotation(&(rotation.rotateZ(-(offset + (replica + 0.5) * width))));
392  break;
393  }
394  if (m_UsePrototypes && !((axis == kRho) && (solid->GetEntityType() == "G4Tubs"))) {
395  if ((replica == 0) && (lvCount == 0)) {
396  if (!(*m_LVUnique)[lvIndex]) writeLVModelNode((*lvStore)[lvIndex], lvName, lvID);
397  }
398  } else {
399  // DIVOT lvName.append("_R");
400  // DIVOT lvName.append(std::to_string(replica));
401  // DIVOT writeLVModelNode((*lvStore)[lvIndex], lvName, lvID+0x00010000*replica+lvCount);
402  }
403  pvName.append("_R");
404  pvName.append(std::to_string(replica));
405  writePVModelNode(physVol, pvName, pvID + 0x00010000 * replica + pvCount);
406  if (axis == kPhi) physVol->SetRotation(originalRotation);
407  }
408  } else {
409  if (m_UsePrototypes) {
410  if (lvCount == 0) {
411  if (!(*m_LVUnique)[lvIndex]) writeLVModelNode((*lvStore)[lvIndex], lvName, lvID);
412  }
413  if (pvCount == 0) writePVModelNode(physVol, pvName, pvID);
414  } else {
415  // DIVOT writeLVModelNode((*lvStore)[lvIndex], lvName, lvID+lvCount);
416  writePVModelNode(physVol, pvName, pvID + pvCount);
417  }
418  (*m_LVCount)[lvIndex]++;
419  (*m_PVCount)[pvIndex]++;
420  }
421 }
422 
423 void FBXWriterModule::countEntities(G4VPhysicalVolume* physVol)
424 {
425  // Descend to the leaves of the tree
426  G4LogicalVolume* logVol = physVol->GetLogicalVolume();
427  for (int daughter = 0; daughter < logVol->GetNoDaughters(); ++daughter) {
428  G4VPhysicalVolume* physVolDaughter = logVol->GetDaughter(daughter);
429  for (int j = 0; j < physVolDaughter->GetMultiplicity(); ++j) {
430  countEntities(physVolDaughter);
431  }
432  }
433  // Count replicas and duplicates of each physical and logical volume as well as the unique
434  // versions of replicated solids as we ascend the recursive tree
435  G4PhysicalVolumeStore* pvStore = G4PhysicalVolumeStore::GetInstance();
436  G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
437  G4SolidStore* solidStore = G4SolidStore::GetInstance();
438  G4VSolid* solid = logVol->GetSolid();
439  int pvIndex = std::find(pvStore->begin(), pvStore->end(), physVol) - pvStore->begin();
440  int lvIndex = std::find(lvStore->begin(), lvStore->end(), logVol) - lvStore->begin();
441  int solidIndex = std::find(solidStore->begin(), solidStore->end(), solid) - solidStore->begin();
442  if (physVol->IsReplicated()) {
443  EAxis axis;
444  G4int nReplicas;
445  G4double width;
446  G4double offset;
447  G4bool consuming;
448  physVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
449  G4VPVParameterisation* physParameterisation = physVol->GetParameterisation();
450  if (physParameterisation) { // parameterised volume
451  G4VSolid* solidReplica = physParameterisation->ComputeSolid(0, physVol);
452  physParameterisation->ComputeTransformation(0, physVol);
453  solidReplica->ComputeDimensions(physParameterisation, 0, physVol);
454  if (!(*solidReplica == *solid))(*m_SolidReplicas)[solidIndex]++;
455  if (m_UsePrototypes && (*solidReplica == *solid)) {
456  if ((*m_LVReplicas)[lvIndex] > 0)(*m_LVUnique)[lvIndex] = false;
457  (*m_LVReplicas)[lvIndex] = 1;
458  } else {
459  (*m_LVReplicas)[lvIndex]++;
460  }
461  (*m_PVReplicas)[pvIndex]++;
462  } else { // plain replicated volume
463  if ((axis == kRho) && (solid->GetEntityType() == "G4Tubs"))(*m_SolidReplicas)[solidIndex]++;
464  if (m_UsePrototypes && !((axis == kRho) && (solid->GetEntityType() == "G4Tubs"))) {
465  (*m_LVReplicas)[lvIndex] = 1;
466  } else {
467  (*m_LVReplicas)[lvIndex]++;
468  }
469  (*m_PVReplicas)[pvIndex]++;
470  }
471  } else {
472  if ((*m_LVCount)[lvIndex] > 0)(*m_LVUnique)[lvIndex] = false;
473  if (m_UsePrototypes) {
474  (*m_PVCount)[pvIndex] = 1;
475  (*m_LVCount)[lvIndex] = 1;
476  } else {
477  (*m_PVCount)[pvIndex]++;
478  (*m_LVCount)[lvIndex]++;
479  }
480  }
481 }
482 
483 void FBXWriterModule::addConnections(G4VPhysicalVolume* physVol, int replica)
484 {
485  // Write the PhysVolModel-parentLogVolModel connections as we descend the recursive tree.
486  // If the parentLogVol is referenced at most once, use its referencing PhysVol instead.
487  G4PhysicalVolumeStore* pvStore = G4PhysicalVolumeStore::GetInstance();
488  G4LogicalVolumeStore* lvStore = G4LogicalVolumeStore::GetInstance();
489  G4SolidStore* solidStore = G4SolidStore::GetInstance();
490  G4LogicalVolume* logVol = physVol->GetLogicalVolume();
491  int pvIndex = std::find(pvStore->begin(), pvStore->end(), physVol) - pvStore->begin();
492  unsigned long long pvID = (*m_PVID)[pvIndex];
493  unsigned int pvCount = (*m_PVCount)[pvIndex];
494  std::string pvName = (*m_PVName)[pvIndex];
495  int lvIndex = std::find(lvStore->begin(), lvStore->end(), logVol) - lvStore->begin();
496  unsigned long long lvID = (*m_LVID)[lvIndex];
497  unsigned int lvCount = (*m_LVCount)[lvIndex];
498  std::string lvName = (*m_LVName)[lvIndex];
499  for (int daughter = 0; daughter < logVol->GetNoDaughters(); ++daughter) {
500  G4VPhysicalVolume* physVolDaughter = logVol->GetDaughter(daughter);
501  int pvIndexDaughter = std::find(pvStore->begin(), pvStore->end(), physVolDaughter) - pvStore->begin();
502  unsigned long long pvIDDaughter = (*m_PVID)[pvIndexDaughter];
503  unsigned int pvCountDaughter = (*m_PVCount)[pvIndexDaughter];
504  for (int j = 0; j < physVolDaughter->GetMultiplicity(); ++j) {
505  if (m_UsePrototypes) {
506  if ((replica == 0) && (j == 0) && (lvCount == 0) && (pvCountDaughter == 0)) {
507  if ((*m_LVUnique)[lvIndex]) {
508  writePVToParentPV((*m_PVName)[pvIndexDaughter], pvName, pvIDDaughter, pvID);
509  } else {
510  writePVToParentLV((*m_PVName)[pvIndexDaughter], lvName, pvIDDaughter, lvID);
511  }
512  }
513  } else {
514  //writePVToParentLV((*m_PVName)[pvIndexDaughter], lvName, pvIDDaughter+0x00010000*j+pvCountDaughter, lvID+0x00010000*replica+lvCount);
515  writePVToParentPV((*m_PVName)[pvIndexDaughter], pvName, pvIDDaughter + 0x00010000 * j + pvCountDaughter,
516  pvID + 0x00010000 * replica + pvCount);
517  }
518  addConnections(physVolDaughter, j);
519  }
520  }
521 
522  // Write the Geometry-LogVolModel, Material-LogVolModel and PhysVolModel-LogVolModel
523  // connections as we ascend the recursive tree
524  G4VSolid* solid = logVol->GetSolid();
525  int solidIndex = std::find(solidStore->begin(), solidStore->end(), solid) - solidStore->begin();
526  unsigned long long solidID = (*m_SolidID)[solidIndex];
527  unsigned long long matID = (*m_MatID)[lvIndex];
528  std::string solidName = (*m_SolidName)[solidIndex];
529  if (physVol->IsReplicated()) {
530  pvName.append("_R");
531  pvName.append(std::to_string(replica));
532  EAxis axis;
533  G4int nReplicas;
534  G4double width;
535  G4double offset;
536  G4bool consuming;
537  physVol->GetReplicationData(axis, nReplicas, width, offset, consuming);
538  physVol->SetCopyNo(replica);
539  G4VPVParameterisation* physParameterisation = physVol->GetParameterisation();
540  if (physParameterisation) { // parameterised volume
541  G4VSolid* solidReplica = physParameterisation->ComputeSolid(replica, physVol);
542  physParameterisation->ComputeTransformation(replica, physVol);
543  solidReplica->ComputeDimensions(physParameterisation, replica, physVol);
544  if (!(*solidReplica == *solid)) {
545  solidName.append("_R");
546  solidName.append(std::to_string(replica));
547  solidID += 0x00010000 * replica;
548  }
549  if (m_UsePrototypes && (*solidReplica == *solid)) {
550  if ((replica == 0) && (lvCount == 0)) {
551  if ((*m_LVUnique)[lvIndex]) { // bypass the singleton logical volume
552  writeSolidToPV(pvName, solidName, (*m_Visible)[lvIndex], matID, pvID, solidID);
553  } else {
554  writeSolidToLV(lvName, solidName, (*m_Visible)[lvIndex], matID, lvID, solidID);
555  }
556  }
557  } else {
558  lvName.append("_R");
559  lvName.append(std::to_string(replica));
560  if ((*m_LVUnique)[lvIndex]) { // bypass the singleton logical volume
561  writeSolidToPV(pvName, solidName, (*m_Visible)[lvIndex], matID, pvID + 0x00010000 * replica + pvCount, solidID);
562  } else {
563  writeSolidToLV(lvName, solidName, (*m_Visible)[lvIndex], matID, lvID + 0x00010000 * replica + lvCount, solidID);
564  }
565  }
566  if (!(*m_LVUnique)[lvIndex]) {
567  writeLVToPV(pvName, lvName, pvID + 0x00010000 * replica + pvCount, lvID + 0x00010000 * replica + lvCount);
568  }
569  } else { // plain replicated volume
570  if ((axis == kRho) && (solid->GetEntityType() == "G4Tubs")) {
571  solidName.append("_R");
572  solidName.append(std::to_string(replica));
573  solidID += 0x00010000 * replica;
574  }
575  if (m_UsePrototypes && !((axis == kRho) && (solid->GetEntityType() == "G4Tubs"))) {
576  if ((replica == 0) && (lvCount == 0)) {
577  if ((*m_LVUnique)[lvIndex]) { // bypass the singleton logical volume
578  writeSolidToPV(pvName, solidName, (*m_Visible)[lvIndex], matID, pvID, solidID);
579  } else {
580  writeSolidToLV(lvName, solidName, (*m_Visible)[lvIndex], matID, lvID, solidID);
581  }
582  }
583  } else {
584  lvName.append("_R");
585  lvName.append(std::to_string(replica));
586  if ((*m_LVUnique)[lvIndex]) { // bypass the singleton logical volume
587  writeSolidToPV(pvName, solidName, (*m_Visible)[lvIndex], matID, pvID + 0x00010000 * replica + pvCount, solidID);
588  } else {
589  writeSolidToLV(lvName, solidName, (*m_Visible)[lvIndex], matID, lvID + 0x00010000 * replica + lvCount, solidID);
590  }
591  }
592  if (!(*m_LVUnique)[lvIndex]) {
593  writeLVToPV(pvName, lvName, pvID + 0x00010000 * replica + pvCount, lvID + 0x00010000 * replica + lvCount);
594  }
595  }
596  } else {
597  if (m_UsePrototypes) {
598  if (lvCount == 0) {
599  if ((*m_LVUnique)[lvIndex]) { // bypass the singleton logical volume
600  writeSolidToPV(pvName, solidName, (*m_Visible)[lvIndex], matID, pvID, solidID);
601  } else {
602  writeSolidToLV(lvName, solidName, (*m_Visible)[lvIndex], matID, lvID, solidID);
603  }
604  }
605  if (pvCount == 0) {
606  if (!(*m_LVUnique)[lvIndex]) writeLVToPV(pvName, lvName, pvID, lvID);
607  }
608  } else {
609  //writeSolidToLV(lvName, solidName, (*m_Visible)[lvIndex], matID, lvID+lvCount, solidID);
610  //writeLVToPV(pvName, lvName, pvID+pvCount, lvID+lvCount);
611  writeSolidToPV(pvName, solidName, (*m_Visible)[lvIndex], matID, pvID + pvCount, solidID);
612  }
613  (*m_LVCount)[lvIndex]++;
614  (*m_PVCount)[pvIndex]++;
615  }
616 }
617 
618 void FBXWriterModule::writePreamble(int modelCount, int materialCount, int geometryCount)
619 {
620  std::time_t t = std::time(nullptr);
621  struct tm* now = std::localtime(&t);
622  m_File << "; FBX 7.3.0 project file" << std::endl <<
623  "; Copyright (C) 1997-2010 Autodesk Inc. and/or its licensors." << std::endl <<
624  "; All rights reserved." << std::endl << std::endl <<
625  "FBXHeaderExtension: {" << std::endl <<
626  "\tFBXHeaderVersion: 1003" << std::endl <<
627  "\tFBXVersion: 7300" << std::endl <<
628  "\tCreationTime: \"" << std::put_time(now, "%F %T") << ":000\"" << std::endl <<
629  //"\tCreationTimeStamp: {" << std::endl <<
630  //"\t\tVersion: 1000" << std::endl <<
631  //"\t\tYear: " << now->tm_year + 1900 << std::endl <<
632  //"\t\tMonth: " << now->tm_mon + 1 << std::endl <<
633  //"\t\tDay: " << now->tm_mday << std::endl <<
634  //"\t\tHour: " << now->tm_hour << std::endl <<
635  //"\t\tMinute: " << now->tm_min << std::endl <<
636  //"\t\tSecond: " << now->tm_sec << std::endl <<
637  //"\t\tMillisecond: 0" << std::endl <<
638  //"\t}" << std::endl <<
639  "\tCreator: \"FBX SDK/FBX Plugins version 2013.3\"" << std::endl <<
640  "\tSceneInfo: \"SceneInfo::GlobalInfo\", \"UserData\" {" << std::endl <<
641  "\t\tType: \"UserData\"" << std::endl <<
642  "\t\tVersion: 100" << std::endl <<
643  "\t\tMetaData: {" << std::endl <<
644  "\t\t\tVersion: 100" << std::endl <<
645  "\t\t\tTitle: \"Belle II Detector\"" << std::endl <<
646  "\t\t\tSubject: \"Detector Geometry Model\"" << std::endl <<
647  "\t\t\tAuthor: \"Belle II Collaboration\"" << std::endl <<
648  "\t\t\tKeywords: \"\"" << std::endl <<
649  "\t\t\tRevision: \"\"" << std::endl <<
650  "\t\t\tComment: \"\"" << std::endl <<
651  "\t\t}" << std::endl <<
652  "\t}" << std::endl <<
653  "}" << std::endl << std::endl;
654 
655  m_File << "GlobalSettings: {" << std::endl <<
656  "\tVersion: 1000" << std::endl <<
657  "\tProperties70: {" << std::endl <<
658  "\t\tP: \"UpAxis\", \"int\", \"Integer\", \"\",1" << std::endl <<
659  "\t\tP: \"UpAxisSign\", \"int\", \"Integer\", \"\",1" << std::endl <<
660  "\t\tP: \"FrontAxis\", \"int\", \"Integer\", \"\",2" << std::endl <<
661  "\t\tP: \"FrontAxisSign\", \"int\", \"Integer\", \"\",1" << std::endl <<
662  "\t\tP: \"CoordAxis\", \"int\", \"Integer\", \"\",0" << std::endl <<
663  "\t\tP: \"CoordAxisSign\", \"int\", \"Integer\", \"\",1" << std::endl <<
664  "\t\tP: \"OriginalUpAxis\", \"int\", \"Integer\", \"\",1" << std::endl <<
665  "\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1" << std::endl <<
666  "\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
667  "\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
668  "\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",1,1,1" << std::endl <<
669  "\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\"" << std::endl <<
670  "\t\tP: \"TimeMode\", \"enum\", \"\", \"\",0" << std::endl <<
671  "\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0" << std::endl <<
672  "\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",10" << std::endl <<
673  "\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1" << std::endl <<
674  "\t}" << std::endl <<
675  "}" << std::endl << std::endl;
676 
677  m_File << "Documents: {" << std::endl <<
678  "\tCount: 1" << std::endl <<
679  "\tDocument: 4000000000, \"\", \"Scene\" {" << std::endl <<
680  "\t\tProperties70: {" << std::endl <<
681  "\t\t\tP: \"SourceObject\", \"object\", \"\", \"\"" << std::endl <<
682  "\t\t\tP: \"ActiveAnimStackName\", \"KString\", \"\", \"\", \"\"" << std::endl <<
683  "\t\t}" << std::endl <<
684  "\t\tRootNode: 0" << std::endl <<
685  "\t}" << std::endl <<
686  "}" << std::endl << std::endl;
687 
688  m_File << "References: {" << std::endl <<
689  "}" << std::endl << std::endl;
690 
691  m_File << "Definitions: {" << std::endl <<
692  "\tVersion: 100" << std::endl <<
693  "\tCount: 4" << std::endl <<
694  "\tObjectType: \"GlobalSettings\" {" << std::endl <<
695  "\t\tCount: 1" << std::endl <<
696  "\t}" << std::endl;
697  m_File << "\tObjectType: \"Model\" {" << std::endl <<
698  "\t\tCount: " << modelCount << std::endl <<
699  "\t\tPropertyTemplate: \"FbxNode\" {" << std::endl <<
700  "\t\t\tProperties70: {" << std::endl <<
701  "\t\t\t\tP: \"QuaternionInterpolate\", \"enum\", \"\", \"\",0" << std::endl <<
702  "\t\t\t\tP: \"RotationOffset\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
703  "\t\t\t\tP: \"RotationPivot\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
704  "\t\t\t\tP: \"ScalingOffset\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
705  "\t\t\t\tP: \"ScalingPivot\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
706  "\t\t\t\tP: \"TranslationActive\", \"bool\", \"\", \"\",0" << std::endl <<
707  "\t\t\t\tP: \"TranslationMin\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
708  "\t\t\t\tP: \"TranslationMax\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
709  "\t\t\t\tP: \"TranslationMinX\", \"bool\", \"\", \"\",0" << std::endl <<
710  "\t\t\t\tP: \"TranslationMinY\", \"bool\", \"\", \"\",0" << std::endl <<
711  "\t\t\t\tP: \"TranslationMinZ\", \"bool\", \"\", \"\",0" << std::endl <<
712  "\t\t\t\tP: \"TranslationMaxX\", \"bool\", \"\", \"\",0" << std::endl <<
713  "\t\t\t\tP: \"TranslationMaxY\", \"bool\", \"\", \"\",0" << std::endl <<
714  "\t\t\t\tP: \"TranslationMaxZ\", \"bool\", \"\", \"\",0" << std::endl <<
715  "\t\t\t\tP: \"RotationOrder\", \"enum\", \"\", \"\",0" << std::endl <<
716  "\t\t\t\tP: \"RotationSpaceForLimitOnly\", \"bool\", \"\", \"\",0" << std::endl <<
717  "\t\t\t\tP: \"RotationStiffnessX\", \"double\", \"Number\", \"\",0" << std::endl <<
718  "\t\t\t\tP: \"RotationStiffnessY\", \"double\", \"Number\", \"\",0" << std::endl <<
719  "\t\t\t\tP: \"RotationStiffnessZ\", \"double\", \"Number\", \"\",0" << std::endl <<
720  "\t\t\t\tP: \"AxisLen\", \"double\", \"Number\", \"\",10" << std::endl <<
721  "\t\t\t\tP: \"PreRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
722  "\t\t\t\tP: \"PostRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
723  "\t\t\t\tP: \"RotationActive\", \"bool\", \"\", \"\",0" << std::endl <<
724  "\t\t\t\tP: \"RotationMin\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
725  "\t\t\t\tP: \"RotationMax\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
726  "\t\t\t\tP: \"RotationMinX\", \"bool\", \"\", \"\",0" << std::endl <<
727  "\t\t\t\tP: \"RotationMinY\", \"bool\", \"\", \"\",0" << std::endl <<
728  "\t\t\t\tP: \"RotationMinZ\", \"bool\", \"\", \"\",0" << std::endl <<
729  "\t\t\t\tP: \"RotationMaxX\", \"bool\", \"\", \"\",0" << std::endl <<
730  "\t\t\t\tP: \"RotationMaxY\", \"bool\", \"\", \"\",0" << std::endl <<
731  "\t\t\t\tP: \"RotationMaxZ\", \"bool\", \"\", \"\",0" << std::endl <<
732  "\t\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",0" << std::endl <<
733  "\t\t\t\tP: \"ScalingActive\", \"bool\", \"\", \"\",0" << std::endl <<
734  "\t\t\t\tP: \"ScalingMin\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
735  "\t\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
736  "\t\t\t\tP: \"ScalingMinX\", \"bool\", \"\", \"\",0" << std::endl <<
737  "\t\t\t\tP: \"ScalingMinY\", \"bool\", \"\", \"\",0" << std::endl <<
738  "\t\t\t\tP: \"ScalingMinZ\", \"bool\", \"\", \"\",0" << std::endl <<
739  "\t\t\t\tP: \"ScalingMaxX\", \"bool\", \"\", \"\",0" << std::endl <<
740  "\t\t\t\tP: \"ScalingMaxY\", \"bool\", \"\", \"\",0" << std::endl <<
741  "\t\t\t\tP: \"ScalingMaxZ\", \"bool\", \"\", \"\",0" << std::endl <<
742  "\t\t\t\tP: \"GeometricTranslation\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
743  "\t\t\t\tP: \"GeometricRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
744  "\t\t\t\tP: \"GeometricScaling\", \"Vector3D\", \"Vector\", \"\",1,1,1" << std::endl <<
745  "\t\t\t\tP: \"MinDampRangeX\", \"double\", \"Number\", \"\",0" << std::endl <<
746  "\t\t\t\tP: \"MinDampRangeY\", \"double\", \"Number\", \"\",0" << std::endl <<
747  "\t\t\t\tP: \"MinDampRangeZ\", \"double\", \"Number\", \"\",0" << std::endl <<
748  "\t\t\t\tP: \"MaxDampRangeX\", \"double\", \"Number\", \"\",0" << std::endl <<
749  "\t\t\t\tP: \"MaxDampRangeY\", \"double\", \"Number\", \"\",0" << std::endl <<
750  "\t\t\t\tP: \"MaxDampRangeZ\", \"double\", \"Number\", \"\",0" << std::endl <<
751  "\t\t\t\tP: \"MinDampStrengthX\", \"double\", \"Number\", \"\",0" << std::endl <<
752  "\t\t\t\tP: \"MinDampStrengthY\", \"double\", \"Number\", \"\",0" << std::endl <<
753  "\t\t\t\tP: \"MinDampStrengthZ\", \"double\", \"Number\", \"\",0" << std::endl <<
754  "\t\t\t\tP: \"MaxDampStrengthX\", \"double\", \"Number\", \"\",0" << std::endl <<
755  "\t\t\t\tP: \"MaxDampStrengthY\", \"double\", \"Number\", \"\",0" << std::endl <<
756  "\t\t\t\tP: \"MaxDampStrengthZ\", \"double\", \"Number\", \"\",0" << std::endl <<
757  "\t\t\t\tP: \"PreferedAngleX\", \"double\", \"Number\", \"\",0" << std::endl <<
758  "\t\t\t\tP: \"PreferedAngleY\", \"double\", \"Number\", \"\",0" << std::endl <<
759  "\t\t\t\tP: \"PreferedAngleZ\", \"double\", \"Number\", \"\",0" << std::endl <<
760  "\t\t\t\tP: \"LookAtProperty\", \"object\", \"\", \"\"" << std::endl <<
761  "\t\t\t\tP: \"UpVectorProperty\", \"object\", \"\", \"\"" << std::endl <<
762  "\t\t\t\tP: \"Show\", \"bool\", \"\", \"\",1" << std::endl <<
763  "\t\t\t\tP: \"NegativePercentShapeSupport\", \"bool\", \"\", \"\",1" << std::endl <<
764  "\t\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0" << std::endl <<
765  "\t\t\t\tP: \"Freeze\", \"bool\", \"\", \"\",0" << std::endl <<
766  "\t\t\t\tP: \"LODBox\", \"bool\", \"\", \"\",0" << std::endl <<
767  "\t\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",0,0,0" << std::endl <<
768  "\t\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",0,0,0" << std::endl <<
769  "\t\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",1,1,1" << std::endl <<
770  "\t\t\t\tP: \"Visibility\", \"Visibility\", \"\", \"A\",1" << std::endl <<
771  "\t\t\t\tP: \"Visibility Inheritance\", \"Visibility Inheritance\", \"\", \"\",1" << std::endl <<
772  "\t\t\t}" << std::endl <<
773  "\t\t}" << std::endl <<
774  "\t}" << std::endl;
775  m_File << "\tObjectType: \"Material\" {" << std::endl <<
776  "\t\tCount: " << materialCount << std::endl <<
777  "\t\tPropertyTemplate: \"FbxSurfacePhong\" {" << std::endl <<
778  "\t\t\tProperties70: {" << std::endl <<
779  "\t\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"Phong\"" << std::endl <<
780  "\t\t\t\tP: \"MultiLayer\", \"bool\", \"\", \"\",0" << std::endl <<
781  "\t\t\t\tP: \"EmissiveColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
782  "\t\t\t\tP: \"EmissiveFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
783  "\t\t\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
784  "\t\t\t\tP: \"AmbientFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
785  "\t\t\t\tP: \"DiffuseColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
786  "\t\t\t\tP: \"DiffuseFactor\", \"double\", \"Number\", \"A\",1" << std::endl <<
787  "\t\t\t\tP: \"Bump\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
788  "\t\t\t\tP: \"NormalMap\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
789  "\t\t\t\tP: \"BumpFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
790  "\t\t\t\tP: \"TransparentColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
791  "\t\t\t\tP: \"TransparencyFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
792  "\t\t\t\tP: \"DisplacementColor\", \"ColorRGB\", \"Color\", \"\",0,0,0" << std::endl <<
793  "\t\t\t\tP: \"DisplacementFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
794  "\t\t\t\tP: \"VectorDisplacementColor\", \"ColorRGB\", \"Color\", \"\",0,0,0" << std::endl <<
795  "\t\t\t\tP: \"VectorDisplacementFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
796  "\t\t\t\tP: \"SpecularColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
797  "\t\t\t\tP: \"SpecularFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
798  "\t\t\t\tP: \"ShininessExponent\", \"double\", \"Number\", \"A\",20" << std::endl <<
799  "\t\t\t\tP: \"ReflectionColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
800  "\t\t\t\tP: \"ReflectionFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
801  "\t\t\t}" << std::endl <<
802  "\t\t}" << std::endl <<
803  "\t}" << std::endl;
804  /*
805  m_File << "\tObjectType: \"Material\" {" << std::endl <<
806  "\t\tCount: " << materialCount << std::endl <<
807  "\t\tPropertyTemplate: \"FbxSurfaceLambert\" {" << std::endl <<
808  "\t\t\tProperties70: {" << std::endl <<
809  "\t\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"Lambet\"" << std::endl <<
810  "\t\t\t\tP: \"MultiLayer\", \"bool\", \"\", \"\",0" << std::endl <<
811  "\t\t\t\tP: \"EmissiveColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
812  "\t\t\t\tP: \"EmissiveFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
813  "\t\t\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
814  "\t\t\t\tP: \"AmbientFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
815  "\t\t\t\tP: \"DiffuseColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
816  "\t\t\t\tP: \"DiffuseFactor\", \"double\", \"Number\", \"A\",1" << std::endl <<
817  "\t\t\t\tP: \"Bump\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
818  "\t\t\t\tP: \"NormalMap\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
819  "\t\t\t\tP: \"BumpFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
820  "\t\t\t\tP: \"TransparentColor\", \"ColorRGB\", \"Color\", \"A\",0,0,0" << std::endl <<
821  "\t\t\t\tP: \"TransparencyFactor\", \"double\", \"Number\", \"A\",0" << std::endl <<
822  "\t\t\t\tP: \"DisplacementColor\", \"ColorRGB\", \"Color\", \"\",0,0,0" << std::endl <<
823  "\t\t\t\tP: \"DisplacementFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
824  "\t\t\t\tP: \"VectorDisplacementColor\", \"ColorRGB\", \"Color\", \"\",0,0,0" << std::endl <<
825  "\t\t\t\tP: \"VectorDisplacementFactor\", \"double\", \"Number\", \"\",1" << std::endl <<
826  "\t\t\t}" << std::endl <<
827  "\t\t}" << std::endl <<
828  "\t}" << std::endl;
829  */
830  m_File << "\tObjectType: \"Geometry\" {" << std::endl <<
831  "\t\tCount: " << geometryCount << std::endl <<
832  "\t\tPropertyTemplate: \"FbxMesh\" {" << std::endl <<
833  "\t\t\tProperties70: {" << std::endl <<
834  "\t\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",1,1,1" << std::endl <<
835  "\t\t\t\tP: \"BBoxMin\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
836  "\t\t\t\tP: \"BBoxMax\", \"Vector3D\", \"Vector\", \"\",0,0,0" << std::endl <<
837  "\t\t\t\tP: \"Primary Visibility\", \"bool\", \"\", \"\",1" << std::endl <<
838  "\t\t\t\tP: \"Casts Shadows\", \"bool\", \"\", \"\",0" << std::endl <<
839  "\t\t\t\tP: \"Receive Shadows\", \"bool\", \"\", \"\",0" << std::endl <<
840  "\t\t\t}" << std::endl <<
841  "\t\t}" << std::endl <<
842  "\t}" << std::endl <<
843  "}" << std::endl << std::endl;
844 
845 }
846 
847 void FBXWriterModule::writePolyhedron(G4VSolid* solid, G4Polyhedron* polyhedron, const std::string& name,
848  unsigned long long solidID)
849 {
850  if (polyhedron) {
851  polyhedron->SetNumberOfRotationSteps(120);
852  m_File << "\t; Solid " << solid->GetName() << " of type " << solid->GetEntityType() << std::endl <<
853  "\tGeometry: " << solidID << ", \"Geometry::" << name << R"(", "Mesh" {)" << std::endl <<
854  "\t\tVertices: *" << polyhedron->GetNoVertices() * 3 << " {" << std::endl << "\t\t\ta: ";
855  std::streampos startOfLine = m_File.tellp();
856  for (int j = 1; j <= polyhedron->GetNoVertices(); ++j) {
857  m_File << (j == 1 ? "" : ",") <<
858  polyhedron->GetVertex(j).x() << "," <<
859  polyhedron->GetVertex(j).y() << "," <<
860  polyhedron->GetVertex(j).z();
861  if (m_File.tellp() - startOfLine > 100) {
862  startOfLine = m_File.tellp();
863  m_File << std::endl << "\t\t\t\t";
864  }
865  }
866  m_File << std::endl << "\t\t}" << std::endl;
867 
868  std::vector<int> vertices;
869  for (int k = 1; k <= polyhedron->GetNoFacets(); ++k) {
870  G4bool notLastEdge = true;
871  G4int ndx = -1, edgeFlag = 1;
872  do {
873  notLastEdge = polyhedron->GetNextVertexIndex(ndx, edgeFlag);
874  if (notLastEdge) {
875  vertices.push_back(ndx - 1);
876  } else {
877  vertices.push_back(-ndx);
878  }
879  } while (notLastEdge);
880  }
881  m_File << "\t\tPolygonVertexIndex: *" << vertices.size() << " {" << std::endl << "\t\t\ta: ";
882  startOfLine = m_File.tellp();
883  for (unsigned int j = 0; j < vertices.size(); ++j) {
884  m_File << (j == 0 ? "" : ",") << vertices[j];
885  if (m_File.tellp() - startOfLine > 100) {
886  startOfLine = m_File.tellp();
887  m_File << std::endl << "\t\t\t\t";
888  }
889  }
890  m_File << std::endl << "\t\t}" << std::endl;
891 
892  m_File << "\t\tGeometryVersion: 124" << std::endl <<
893  "\t\tLayerElementNormal: 0 {" << std::endl <<
894  "\t\t\tVersion: 101" << std::endl <<
895  // "\t\t\tName: \"\"" << std::endl <<
896  "\t\t\tMappingInformationType: \"ByPolygonVertex\"" << std::endl <<
897  "\t\t\tReferenceInformationType: \"Direct\"" << std::endl <<
898  "\t\t\tNormals: *" << vertices.size() * 3 << " {" << std::endl << "\t\t\t\ta: ";
899  startOfLine = m_File.tellp();
900  unsigned int j = 0;
901  for (int k = 1; k <= polyhedron->GetNoFacets(); ++k) {
902  G4Normal3D normal = polyhedron->GetUnitNormal(k);
903  do {
904  m_File << (j == 0 ? "" : ",") << normal.x() << "," << normal.y() << "," << normal.z();
905  if (m_File.tellp() - startOfLine > 100) {
906  startOfLine = m_File.tellp();
907  m_File << std::endl << "\t\t\t\t";
908  }
909  } while (vertices[j++] >= 0);
910  }
911  m_File << std::endl << "\t\t\t}" << std::endl << "\t\t}" << std::endl <<
912  "\t\tLayerElementMaterial: 0 {" << std::endl <<
913  "\t\t\tVersion: 101" << std::endl <<
914  // "\t\t\tName: \"\"" << std::endl <<
915  "\t\t\tMappingInformationType: \"AllSame\"" << std::endl <<
916  "\t\t\tReferenceInformationType: \"IndexToDirect\"" << std::endl <<
917  "\t\t\tMaterials: *1 {" << std::endl <<
918  "\t\t\t\ta: 0" << std::endl <<
919  "\t\t\t}" << std::endl <<
920  "\t\t}" << std::endl <<
921  "\t\tLayer: 0 {" << std::endl <<
922  "\t\t\tVersion: 100" << std::endl <<
923  "\t\t\tLayerElement: {" << std::endl <<
924  "\t\t\t\tType: \"LayerElementNormal\"" << std::endl <<
925  "\t\t\t\tTypedIndex: 0" << std::endl <<
926  "\t\t\t}" << std::endl <<
927  "\t\t\tLayerElement: {" << std::endl <<
928  "\t\t\t\tType: \"LayerElementMaterial\"" << std::endl <<
929  "\t\t\t\tTypedIndex: 0" << std::endl <<
930  "\t\t\t}" << std::endl <<
931  "\t\t}" << std::endl <<
932  "\t}" << std::endl;
933  } else {
934  B2INFO("Polyhedron representation of solid " << name << " cannot be created");
935  }
936 }
937 
938 void FBXWriterModule::writePVModelNode(G4VPhysicalVolume* physVol, const std::string& pvName, unsigned long long pvID)
939 {
940  G4RotationMatrix* rot = physVol->GetObjectRotation();
941  G4ThreeVector move = physVol->GetObjectTranslation();
942  // FBX uses the Tait-Bryan version of the Euler angles (X then Y then Z rotation)
943  double yaw = std::atan2(rot->yx(), rot->xx()) * 180.0 / M_PI;
944  if (fabs(yaw) < 1.0E-12) yaw = 0.0;
945  double pitch = -std::asin(rot->zx()) * 180.0 / M_PI;
946  if (fabs(pitch) < 1.0E-12) pitch = 0.0;
947  double roll = std::atan2(rot->zy(), rot->zz()) * 180.0 / M_PI;
948  if (fabs(roll) < 1.0E-12) roll = 0.0;
949  m_File << "\t; PhysVol " << physVol->GetName();
950  if (physVol->IsReplicated()) {
951  m_File << " (replicated: copy " << physVol->GetCopyNo() << ")";
952  }
953  m_File << ", placing LogVol " << physVol->GetLogicalVolume()->GetName() << std::endl <<
954  "\tModel: " << pvID << ", \"Model::" << pvName << R"(", "Null" {)" << std::endl <<
955  "\t\tVersion: 232" << std::endl <<
956  "\t\tProperties70: {" << std::endl <<
957  "\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\"," <<
958  move.x() << "," << move.y() << "," << move.z() << std::endl <<
959  "\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\"," <<
960  roll << "," << pitch << "," << yaw << std::endl <<
961  "\t\t}" << std::endl <<
962  "\t\tShading: T" << std::endl <<
963  "\t\tCulling: \"CullingOff\"" << std::endl <<
964  "\t}" << std::endl;
965 }
966 
967 void FBXWriterModule::writeSolidToLV(const std::string& lvName, const std::string& solidName, bool visible,
968  unsigned long long matID, unsigned long long lvID, unsigned long long solidID)
969 {
970  m_File << "\t; Solid Geometry::" << solidName << ", LogVol Model::lv_" << lvName << std::endl <<
971  "\t" << (visible ? "" : "; ") << "C: \"OO\"," << solidID << "," << lvID << std::endl << std::endl <<
972  "\t; Color Material::" << lvName << ", LogVol Model::lv_" << lvName << std::endl <<
973  "\t" << (visible ? "" : "; ") << "C: \"OO\"," << matID << "," << lvID << std::endl << std::endl;
974 }
975 
976 void FBXWriterModule::writeSolidToPV(const std::string& pvName, const std::string& solidName, bool visible,
977  unsigned long long matID, unsigned long long pvID, unsigned long long solidID)
978 {
979  m_File << "\t; Solid Geometry::" << solidName << ", PhysVol Model::" << pvName << std::endl <<
980  "\t" << (visible ? "" : "; ") << "C: \"OO\"," << solidID << "," << pvID << std::endl << std::endl <<
981  "\t; Color Material::" << pvName << ", PhysVol Model::" << pvName << std::endl <<
982  "\t" << (visible ? "" : "; ") << "C: \"OO\"," << matID << "," << pvID << std::endl << std::endl;
983 }
984 
985 void FBXWriterModule::writeLVToPV(const std::string& pvName, const std::string& lvName, unsigned long long pvID,
986  unsigned long long lvID)
987 {
988  m_File << "\t; LogVol Model::lv_" << lvName << ", PhysVol Model::" << pvName << std::endl <<
989  "\tC: \"OO\"," << lvID << "," << pvID << std::endl << std::endl;
990 }
991 
992 void FBXWriterModule::writePVToParentLV(const std::string& pvNameDaughter, const std::string& lvName,
993  unsigned long long pvIDDaughter, unsigned long long lvID)
994 {
995  m_File << "\t; PhysVol Model::" << pvNameDaughter << ", parent LogVol Model::lv_" << lvName << std::endl <<
996  "\tC: \"OO\"," << pvIDDaughter << "," << lvID << std::endl << std::endl;
997 }
998 
999 void FBXWriterModule::writePVToParentPV(const std::string& pvNameDaughter, const std::string& pvName,
1000  unsigned long long pvIDDaughter, unsigned long long pvID)
1001 {
1002  m_File << "\t; PhysVol Model::" << pvNameDaughter << ", parent PhysVol Model::" << pvName << std::endl <<
1003  "\tC: \"OO\"," << pvIDDaughter << "," << pvID << std::endl << std::endl;
1004 }
1005 
1006 // The code in GEANT4 geometry/solids/Boolean/src/G4BooleanSolid.cc is buggy so avoid it.
1007 // Recursively combine the polyhedrons of two solids to make a resulting polyhedron.
1008 HepPolyhedron* FBXWriterModule::getBooleanSolidPolyhedron(G4VSolid* solid)
1009 {
1010  G4VSolid* solidA = solid->GetConstituentSolid(0);
1011  G4VSolid* solidB = solid->GetConstituentSolid(1);
1012  HepPolyhedron* polyhedronA = nullptr;
1013  if ((solidA->GetEntityType() == "G4IntersectionSolid") ||
1014  (solidA->GetEntityType() == "G4UnionSolid") ||
1015  (solidA->GetEntityType() == "G4SubtractionSolid") ||
1016  (solidA->GetEntityType() == "G4BooleanSolid")) {
1017  polyhedronA = getBooleanSolidPolyhedron(solidA);
1018  } else {
1019  polyhedronA = new HepPolyhedron(*(solidA->GetPolyhedron()));
1020  }
1021  HepPolyhedron* polyhedronB = nullptr;
1022  G4VSolid* solidB2 = solidB;
1023  if (solidB->GetEntityType() == "G4DisplacedSolid") {
1024  solidB2 = ((G4DisplacedSolid*)solidB)->GetConstituentMovedSolid();
1025  }
1026  if ((solidB2->GetEntityType() == "G4IntersectionSolid") ||
1027  (solidB2->GetEntityType() == "G4UnionSolid") ||
1028  (solidB2->GetEntityType() == "G4SubtractionSolid") ||
1029  (solidB2->GetEntityType() == "G4BooleanSolid")) {
1030  polyhedronB = getBooleanSolidPolyhedron(solidB2);
1031  if (solidB != solidB2) { // was solidB a G4DisplacedSolid?
1032  polyhedronB->Transform(G4Transform3D(
1033  ((G4DisplacedSolid*)solidB)->GetObjectRotation(),
1034  ((G4DisplacedSolid*)solidB)->GetObjectTranslation()));
1035  }
1036  } else {
1037  polyhedronB = new HepPolyhedron(*(solidB->GetPolyhedron()));
1038  }
1039  auto* result = new HepPolyhedron();
1040  if (solid->GetEntityType() == "G4UnionSolid") {
1041  *result = polyhedronA->add(*polyhedronB);
1042  } else if (solid->GetEntityType() == "G4SubtractionSolid") {
1043  *result = polyhedronA->subtract(*polyhedronB);
1044  } else if (solid->GetEntityType() == "G4IntersectionSolid") {
1045  *result = polyhedronA->intersect(*polyhedronB);
1046  } else {
1047  B2WARNING("getBooleanSolidPolyhedron(): Unrecognized boolean solid " << solid->GetName() <<
1048  " of type " << solid->GetEntityType());
1049  }
1050  delete polyhedronA;
1051  delete polyhedronB;
1052  return result;
1053 }
Belle2::FBXWriterModule::writeLVModelNode
void writeLVModelNode(G4LogicalVolume *, const std::string &, unsigned long long)
Write FBX definition for each logical volume.
Definition: FBXWriterModule.cc:285
Belle2::FBXWriterModule::m_PVReplicas
std::vector< unsigned int > * m_PVReplicas
Count of number of replicas of each replicated physical volume.
Definition: FBXWriterModule.h:153
Belle2::FBXWriterModule::m_MatID
std::vector< unsigned long long > * m_MatID
Unique identifiers for logical volumes' color information (Material nodes)
Definition: FBXWriterModule.h:135
Belle2::FBXWriterModule::addConnections
void addConnections(G4VPhysicalVolume *, int)
Write FBX connections among all of the nodes in the tree (recursive)
Definition: FBXWriterModule.cc:483
Belle2::FBXWriterModule::writePVToParentPV
void writePVToParentPV(const std::string &, const std::string &, unsigned long long, unsigned long long)
Write FBX connection for each physical-volume daughter of a parent physical volume (bypass singleton ...
Definition: FBXWriterModule.cc:999
Belle2::FBXWriterModule::m_PVID
std::vector< unsigned long long > * m_PVID
Unique identifiers for physical volumes (Model nodes with transformation information)
Definition: FBXWriterModule.h:129
Belle2::FBXWriterModule::countEntities
void countEntities(G4VPhysicalVolume *)
Count the physical volumes, logical volumes, materials and solids (recursive)
Definition: FBXWriterModule.cc:423
Belle2::FBXWriterModule::m_SolidName
std::vector< std::string > * m_SolidName
Modified (legal-character and unique) solid name.
Definition: FBXWriterModule.h:126
Belle2::Module::setDescription
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:216
Belle2::FBXWriterModule::event
void event() override
Called for each event: this runs the FBX writer only for the first event.
Definition: FBXWriterModule.cc:53
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::FBXWriterModule::writeMaterialNode
void writeMaterialNode(int, const std::string &)
Write FBX definition for each logical volume's color information.
Definition: FBXWriterModule.cc:239
Belle2::FBXWriterModule::FBXWriterModule
FBXWriterModule()
Constructor of the module.
Definition: FBXWriterModule.cc:36
Belle2::geometry::GeometryManager::getTopVolume
G4VPhysicalVolume * getTopVolume()
Return a pointer to the top volume.
Definition: GeometryManager.h:59
Belle2::FBXWriterModule::m_Visible
std::vector< bool > * m_Visible
Flag to indicate that the logical volume is visible.
Definition: FBXWriterModule.h:141
Belle2::geometry::GeometryManager::getInstance
static GeometryManager & getInstance()
Return a reference to the instance.
Definition: GeometryManager.cc:98
Belle2::FBXWriterModule::m_LVID
std::vector< unsigned long long > * m_LVID
Unique identifiers for logical volumes (Model nodes with links to Geometry and Material)
Definition: FBXWriterModule.h:132
Belle2::FBXWriterModule::m_SolidReplicas
std::vector< unsigned int > * m_SolidReplicas
Count of number of replicas of each solid (extras for replicas with modified solids)
Definition: FBXWriterModule.h:159
Belle2::FBXWriterModule::m_SolidID
std::vector< unsigned long long > * m_SolidID
Unique identifiers for solids (Geometry nodes)
Definition: FBXWriterModule.h:138
Belle2::FBXWriterModule::m_LVReplicas
std::vector< unsigned int > * m_LVReplicas
Count of number of replicas of each logical volume associated with a replicated physical volume.
Definition: FBXWriterModule.h:156
Belle2::FBXWriterModule::assignName
void assignName(std::vector< std::string > *, unsigned int, const G4String &, int)
Create unique and legal name for each solid, logical volume, physical volume.
Definition: FBXWriterModule.cc:188
Belle2::FBXWriterModule::m_UsePrototypes
bool m_UsePrototypes
User-specified flag to select whether to write and re-use logical- and physical-volume prototypes onc...
Definition: FBXWriterModule.h:111
Belle2::FBXWriterModule::m_SolidCount
std::vector< unsigned int > * m_SolidCount
Count of number of instances of each solid (typically 1)
Definition: FBXWriterModule.h:150
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::FBXWriterModule::m_LVName
std::vector< std::string > * m_LVName
Modified (legal-character and unique) logical-volume name.
Definition: FBXWriterModule.h:123
Belle2::FBXWriterModule::m_LVUnique
std::vector< bool > * m_LVUnique
Flag to indicate that a logical volume is referenced at most once (eligible for bypass)
Definition: FBXWriterModule.h:162
Belle2::FBXWriterModule::writeLVToPV
void writeLVToPV(const std::string &, const std::string &, unsigned long long, unsigned long long)
Write FBX connection for the (unique) logical volume of a physical volume.
Definition: FBXWriterModule.cc:985
Belle2::FBXWriterModule::writePreamble
void writePreamble(int, int, int)
Write FBX at the start of the file.
Definition: FBXWriterModule.cc:618
Belle2::FBXWriterModule::writePolyhedron
void writePolyhedron(G4VSolid *, G4Polyhedron *, const std::string &, unsigned long long)
Write FBX definition for the solid's polyhedron.
Definition: FBXWriterModule.cc:847
Belle2::FBXWriterModule::getBooleanSolidPolyhedron
HepPolyhedron * getBooleanSolidPolyhedron(G4VSolid *)
Create polyhedron for a boolean solid (recursive)
Definition: FBXWriterModule.cc:1008
Belle2::FBXWriterModule::m_Filename
std::string m_Filename
User-specified output filename.
Definition: FBXWriterModule.h:114
Belle2::FBXWriterModule::writeSolidToLV
void writeSolidToLV(const std::string &, const std::string &, bool, unsigned long long, unsigned long long, unsigned long long)
Write FBX connection for each logical volume's solid and color info.
Definition: FBXWriterModule.cc:967
Belle2::Module::addParam
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:562
Belle2::FBXWriterModule::addModels
void addModels(G4VPhysicalVolume *, int)
Process one physical volume for FBX-node writing (recursive)
Definition: FBXWriterModule.cc:297
Belle2::FBXWriterModule::writeSolidToPV
void writeSolidToPV(const std::string &, const std::string &, bool, unsigned long long, unsigned long long, unsigned long long)
Write FBX connection for each physical volume's solid and color info (bypass singleton logical volume...
Definition: FBXWriterModule.cc:976
Belle2::FBXWriterModule::m_First
bool m_First
Once-only flag to write FBX only on the first event.
Definition: FBXWriterModule.h:107
Belle2::FBXWriterModule::m_PVName
std::vector< std::string > * m_PVName
Modified (legal-character and unique) physical-volume name.
Definition: FBXWriterModule.h:120
Belle2::FBXWriterModule::m_LVCount
std::vector< unsigned int > * m_LVCount
Count of number of instances of each logical volume.
Definition: FBXWriterModule.h:147
Belle2::FBXWriterModule::writePVToParentLV
void writePVToParentLV(const std::string &, const std::string &, unsigned long long, unsigned long long)
Write FBX connection for each physical-volume daughter of a parent logical volume.
Definition: FBXWriterModule.cc:992
Belle2::FBXWriterModule::m_File
std::ofstream m_File
Output file.
Definition: FBXWriterModule.h:117
Belle2::FBXWriterModule::m_PVCount
std::vector< unsigned int > * m_PVCount
Count of number of instances of each physical volume.
Definition: FBXWriterModule.h:144
Belle2::FBXWriterModule::writeGeometryNode
void writeGeometryNode(G4VSolid *, const std::string &, unsigned long long)
Write FBX definition for each solid's polyhedron.
Definition: FBXWriterModule.cc:223
Belle2::FBXWriterModule::writePVModelNode
void writePVModelNode(G4VPhysicalVolume *, const std::string &, unsigned long long)
Write FBX definition for each physical volume.
Definition: FBXWriterModule.cc:938
Belle2::FBXWriterModule::initialize
void initialize() override
Initialize at the start of a job.
Definition: FBXWriterModule.cc:48