EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicStlFactory.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicStlFactory.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/03/11; revamped in Oct'2017;
3 //
4 // EicRoot STL/SLP file manipulation routines;
5 //
6 
7 #include <assert.h>
8 #include <iostream>
9 #include <asm/types.h>
10 
11 #ifdef TETLIBRARY
12 #include "tetgen.h"
13 #endif
14 
15 #define _BINARY_STL_HEADER_SIZE_ 80
16 
17 #include <TGeoManager.h>
18 #include <TGeoMedium.h>
19 #include <TRotation.h>
20 #include <TMath.h>
21 #include <TGeoVolume.h>
22 #include <TGeoArb8.h>
23 #include <TGeoMatrix.h>
24 
25 #include <FairLogger.h>
26 
27 #include <EicCadFile.h>
28 #include <EicStlFactory.h>
29 
30 // =======================================================================================
31 
32 void EicStlFactory::PreAllocateFacet(unsigned solidId, const TGeoMedium *medium,
33  const double vCoord1[], const double vCoord2[],
34  const double vCoord3[])
35 {
36  // Start with vertices rather than facets;
37  EicStlVertex *v1 = new EicStlVertex(vCoord1);
38  EicStlVertex *v2 = new EicStlVertex(vCoord2);
39  EicStlVertex *v3 = new EicStlVertex(vCoord3);
40 
41  // Obtain medium group pointer;
42  EicStlMediaGroup *mgroup = &mGroups[std::pair<unsigned, const TGeoMedium*>(solidId, medium)];
43 
44  EicStlVertex *vv[3] = {v1, v2, v3};
45  for(unsigned iq=0; iq<3; iq++)
46  {
47  EicStlVertex *vtx = vv[iq];
48 
49  // Looks stupid, but allows to unify two code branches;
50  if (mgroup->vertices()->find(vtx->key()) == mgroup->vertices()->end()) {
51  // Well, vertices can allocate in the ordered map right away; if any of them is not
52  // needed any longer, it will simply be erased rather than modified (like in case of facets);
53  //(*mgroup->vertices())[vtx->key()] = vtx;
54  mgroup->AddVertex(vtx);//ices())[vtx->key()] = vtx;
55 
56  // FIXME: may want to apply a small fixed rotation in order to avoid a fake 1D coordinate
57  // degeneracy often found in CAD models (consider a cube with its 8 vertices sitting at
58  // identical X(YZ)-coordinates, etc);
59  mgroup->xCoord.insert(std::pair<double, EicStlVertex*>(vtx->key()->GetData()[0], vtx));
60  mgroup->yCoord.insert(std::pair<double, EicStlVertex*>(vtx->key()->GetData()[1], vtx));
61  mgroup->zCoord.insert(std::pair<double, EicStlVertex*>(vtx->key()->GetData()[2], vtx));
62  } else {
63  //vv[iq] = (*mgroup->vertices())[vtx->key()];
64  vv[iq] = (*mgroup->vertices()).at(vtx->key());
65  delete vtx;
66  } //if
67  } //for iq
68 
69  // Allocate facet and store in the intermediate array; the rest will happen in
70  // the EicStlMediaGroup::SplitIntoAssemblies() call during geometry construction;
71  EicStlFacet *facet = new EicStlFacet(vv[0], vv[1], vv[2]);
72  mgroup->mFbuffer.push_back(facet);
73 } // EicStlFactory::PreAllocateFacet()
74 
75 // ---------------------------------------------------------------------------------------
76 
77 void EicStlFactory::ImportBinaryStlFile(FILE *fin, unsigned trCount, double scale)
78 {
79  __u16 attr;
80  float fnn[3], fvCoord1[3], fvCoord2[3], fvCoord3[3];
81 
82  //printf("trCount: %d\n", trCount);
83 
84  // Assume I'm right past 80-byte header and 4-byte triangle count;
85  for(unsigned itr=0; itr<trCount; itr++)
86  {
87  // Assume these fread() calls can not fail;
88  fread(fnn, sizeof(float), 3, fin);
89  fread(fvCoord1, sizeof(float), 3, fin);
90  fread(fvCoord2, sizeof(float), 3, fin);
91  fread(fvCoord3, sizeof(float), 3, fin);
92  fread(&attr, sizeof(__u16), 1, fin);
93  //printf("%7.3f %7.3f %7.3f; %7.3f %7.3f %7.3f; %7.3f %7.3f %7.3f; %7.3f %7.3f %7.3f; %8d\n",
94  // fnn[0], fnn[1], fnn[2],
95  // fvCoord1[0], fvCoord1[1], fvCoord1[2],
96  // fvCoord2[0], fvCoord2[1], fvCoord2[2],
97  // fvCoord3[0], fvCoord3[1], fvCoord3[2], attr);
98 
99  // Prefer to switch to double precision right away at the import stage;
100  {
101  double dnn[3], dvCoord1[3], dvCoord2[3], dvCoord3[3];
102 
103  for(unsigned iq=0; iq<3; iq++) {
104  dnn [iq] = double(fnn [iq]);
105  dvCoord1[iq] = scale * double(fvCoord1[iq]);
106  dvCoord2[iq] = scale * double(fvCoord2[iq]);
107  dvCoord3[iq] = scale * double(fvCoord3[iq]);
108  } //for iq
109 
110  // Add color attribute to the parameter list later;
111  //PreAllocateFacet(0, fMediaHub ? fMediaHub->fSingleMedium : 0, dvCoord1, dvCoord2, dvCoord3);
113  dvCoord1, dvCoord2, dvCoord3);
114  }
115  } //for itr
116 } // EicStlFactory::ImportBinaryStlFile()
117 
118 // ---------------------------------------------------------------------------------------
119 
121 {
122  // Use single medium defined in EicStlFile() constructor call as default; it can be 0
123  // here and then be overriden by STL syntax extention (see below);
124  const TGeoMedium *currentMedium = mConfig->mhub()->fSingleMedium;
125  unsigned solidId = 0, vtxId = 0;
126  Bool_t inSolid = kFALSE, inFacet = kFALSE, inLoop = kFALSE;
127  double vCoord[3][3];
128  TString buffer;
129 
130  std::ifstream is (mGeometryName);
131 
132  while (!is.eof())
133  {
134  buffer.ReadLine(is, kTRUE);
135 
136  // Sanity checks included; require exact case match; require no indent for
137  // both "solid" and "nosolid"; this way object names will not hurt even if
138  // they contain other keywords;
139  if (buffer.BeginsWith("solid"))
140  {
141  assert (inSolid == kFALSE && inFacet == kFALSE && inLoop == kFALSE);
142  inSolid = kTRUE;
143  }
144  else
145  if (buffer.BeginsWith("endsolid"))
146  {
147  assert (inSolid == kTRUE && inFacet == kFALSE && inLoop == kFALSE);
148  solidId++;
149  inSolid = kFALSE;
150  }
151  else
152  // Allow user to define media by hand as many times as needed in STL ASCII
153  // file; this key is searched after "solid", so if solid name contains "medium"
154  // it will not hurt; also, it is searched before all other keys, so may contain
155  // medium name like "siliconvertex" and this also will not hurt;
156  if (mType == AsciiStl && buffer.Contains("medium"))
157  {
158  // Well, let it be only outside of 'facet - endfacet' clause;
159  assert (inFacet == kFALSE && inLoop == kFALSE);
160 
161  // Take it into account only if media name was not given
162  // in EicStlFactory() constructor;
163  if (!mConfig->mhub()->fSingleMedium)
164  {
165  char key[128], medium[128];
166 
167  sscanf(buffer.Data(),"%s %s", key, medium);
168 
169  currentMedium = mConfig->mhub()->GetMedium(medium);
170  assert(currentMedium);
171  } //if
172  }
173  else
174  if (mType == AsciiSlp && buffer.Contains("color"))
175  {
176  assert (inSolid == kTRUE && inFacet == kFALSE && inLoop == kFALSE);
177 
178  if (!mConfig->mhub()->fSingleMedium)
179  {
180  // Parse string, build color key and try to remap;
181  char color[128];
182  // Is it really RGB encoded here?; does not matter;
183  float rgb[3];
184  sscanf(buffer.Data(),"%s %f %f %f", color, rgb + 0, rgb + 1, rgb + 2);
185  //+EicStlKey key(3, rgb);
186 
187  //printf("%f %f %f\n", rgb[0], rgb[1], rgb[2]);
188  assert(0);
189 #if _TODAY_
190  assert(fMediaHub->fMediaMap->find(&key) != fMediaHub->fMediaMap->end());
191  currentMedium = (*fMediaHub->fMediaMap)[&key];
192 #endif
193  } //if
194  }
195  else
196  if ((mType == AsciiStl && buffer.Contains("facet normal")) ||
197  (mType == AsciiSlp && buffer.Contains("facet") && !buffer.Contains("endfacet")))
198  {
199  // Do smart exit later; ignore actual normal data; in case of SLP file
200  // do not pay attention to "normal" lines at all;
201  assert (inSolid == kTRUE && inFacet == kFALSE && inLoop == kFALSE);
202  inFacet = kTRUE;
203  }
204  else
205  if (buffer.Contains("endfacet"))
206  {
207  assert (inSolid == kTRUE && inFacet == kTRUE && inLoop == kFALSE);
208  inFacet = kFALSE;
209  }
210  else
211  if (buffer.Contains("outer loop"))
212  {
213  assert (inSolid == kTRUE && inFacet == kTRUE && inLoop == kFALSE);
214  inLoop = kTRUE;
215  }
216  else
217  if (buffer.Contains("endloop"))
218  {
219  assert (inSolid == kTRUE && inFacet == kTRUE && inLoop == kTRUE);
220  inLoop = kFALSE;
221  vtxId = 0;
222  }
223  else
224  if (buffer.Contains("vertex"))
225  {
226  assert (inSolid == kTRUE && inFacet == kTRUE && inLoop == kTRUE && vtxId <= 2);
227 
228  char vertex[128];
229  sscanf(buffer.Data(),"%s %lf %lf %lf", vertex,
230  vCoord[vtxId] + 0, vCoord[vtxId] + 1, vCoord[vtxId] + 2);
231 
232  // The essential part;
233  if (vtxId == 2)
234  {
235  //printf("%7.3f %7.3f %7.3f; %7.3f %7.3f %7.3f; %7.3f %7.3f %7.3f\n",
236  // vCoord[0][0], vCoord[0][1], vCoord[0][2],
237  // vCoord[1][0], vCoord[1][1], vCoord[1][2],
238  // vCoord[2][0], vCoord[2][1], vCoord[2][2]);
239 
240  // Well, by this point medium should be defined, in whatever way;
241  assert(currentMedium);
242  //printf("%s\n", currentMedium->GetName());
243  for(unsigned ip=0; ip<3; ip++)
244  for(unsigned iq=0; iq<3; iq++)
245  vCoord[ip][iq] *= scale;
246  PreAllocateFacet(solidId, currentMedium, vCoord[0], vCoord[1], vCoord[2]);
247  } //if
248 
249  vtxId++;
250  } //if
251  } // for inf
252 
253  is.close();
254 } // EicStlFactory::ImportAsciiStlSlpFile()
255 
256 // ---------------------------------------------------------------------------------------
257 
258 EicStlFactory::EicStlFactory(const char *vname, const char *geometryName, const EicCadFileConfig *config,
259  bool acknowledge_config_file_scaling): //mWireframeMode(false), mWireframeFeatureSize(0.0),
260  mGeometryName(geometryName), mVolumeName(vname), mConfig(config)
261 {
262  double scale = (config && acknowledge_config_file_scaling) ? config->scale() * config->units() : 1.0;
263 
265 
266  // If file extension is ".slp", it is Pro-E SLP format, no tricks; let it be the default;
268 
269  // Well, I need to handle at least 3 different formats (ASCII and binary STL,
270  // as well as ASCII SLP); makes sense to unify these 3 branches early enough;
271  // however vertex & facet allocation is needed anyway; consider to put this
272  // allocation in a separate call and do an easy switch of input parser
273  // depending on the file type;
274  FILE *fin = fopen(geometryName, "r");
275  if (!fin)
276  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Failed to open geometry file %s!! \033[0m",
277  geometryName);
278 
279  // Used in binary STL case only?;
280  __u32 trCount;
281  if (mGeometryName.EndsWith(".stl")) {
282  // Pro-E binary STL files happily start with the same "solid" keyword as ASCII
283  // files (idiots!), so one can not check on that; assume, that if number of encoded
284  // triangles matches file size, it is a binary file; so first calculate file size in the
285  // most stupid way possible;
286  fseek(fin, 0, SEEK_END);
287  long fSize = ftell(fin);
288 
289  rewind(fin);
290  unsigned char header[_BINARY_STL_HEADER_SIZE_];
291  if (fread(header, 1, _BINARY_STL_HEADER_SIZE_, fin) == _BINARY_STL_HEADER_SIZE_ &&
292  // Well, in fact I guess I know size of 32-bit integer, or?;
293  fread(&trCount, 1, sizeof(__u32), fin) == sizeof(__u32) &&
294  // Calculate expected file size if it is binary;
295  fSize == _BINARY_STL_HEADER_SIZE_ + sizeof(__u32) + trCount*(sizeof(float)*3*4 + sizeof(__u16)))
297  else
299  } // if (mGeometryName.EndsWith(".stl"))
300 
301  // And now arrange an import switch;
302  switch (mType) {
304  // Yes, there is no other easy way to encode media in Pro/E STL files; other packages
305  // may allow this (either in the header or in attribute field); once needed, extend this part;
306  if (mConfig && mConfig->mhub()) assert(mConfig->mhub()->fSingleMedium);
307  ImportBinaryStlFile(fin, trCount, scale);
308  fclose(fin);
309  break;
312  fclose(fin);
313  ImportAsciiStlSlpFile(scale);
314  break;
315  default:
316  assert(0);
317  } // switch(mType)
318 } // EicStlFactory::EicStlFactory()
319 
320 // =======================================================================================
321 
322 #ifdef TETLIBRARY
323 static TVector3 GetTetPoint(tetgenio &io, unsigned index_offset)
324 {
325  // FIXME: think about units;
326  return TVector3( io.pointlist[(io.tetrahedronlist[index_offset]-1)*3+0],
327  io.pointlist[(io.tetrahedronlist[index_offset]-1)*3+1],
328  io.pointlist[(io.tetrahedronlist[index_offset]-1)*3+2]);
329 } // GetTetPoint()
330 #endif
331 
332 // ---------------------------------------------------------------------------------------
333 
334 void EicStlFactory::DumpTmpStlFile(EicStlAssembly *assembly, TString &stlActualFileName)
335 {
336  // Do this better later (Mac OS compatible at least);
337  FILE *fout = fopen(stlActualFileName, "w");
338  if (!fout)
339  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Failed to open file %s!! \033[0m",
340  stlActualFileName.Data());
341 
342  // Dump "solid ..." clause;
343  fprintf(fout, "solid MySolid\n");
344 
345  for(unsigned fc=0; fc<assembly->facets().size(); fc++) {
346  EicStlFacet *facet = assembly->facets()[fc].first;
347  double sign = assembly->facets()[fc].second ? 1.0 : -1.0;
348 
349  // Dump respective facet section; assume %16.8f format suffices for all
350  // practical situations;
351  fprintf(fout, " facet normal %16.8f %16.8f %16.8f\n",
352  sign*facet->GetNormal()[0], sign*facet->GetNormal()[1], sign*facet->GetNormal()[2]);
353  fprintf(fout, " outer loop\n");
354  {
355  // FIXME: does vertex order matter here (it is indeed arbitrary) or normal direction
356  // sufiices to instruct Tetgen (netgen) software about outward-pointing direction?;
357  for(vEntry::const_iterator vt=facet->vertices()->begin(); vt!=facet->vertices()->end() ; vt++) {
358  const double *coord = vt->second->key()->GetData();
359  fprintf(fout, " vertex %16.8f %16.8f %16.8f\n", coord[0], coord[1], coord[2]);
360  } //for vt
361  fprintf(fout, " endloop\n");
362  fprintf(fout, " endfacet\n");
363  }
364  } //for fc
365 
366  // Dump "endsolid ..." clause;
367  fprintf(fout, "endsolid MySolid\n");
368  fclose(fout);
369 } // EicStlFactory::DumpTmpStlFile()
370 
371 // ---------------------------------------------------------------------------------------
372 
373 TGeoVolume *CreateTetrahedron(TVector3 &p1, TVector3 &p2, TVector3 &p3, TVector3 &p4,
374  char name[], TGeoVolume *fMother, const TGeoMedium *medium, TVector3 shift)
375 {
376  // And now the whole mess comes; no G4Tet or similar in ROOT geometry primitives,
377  // so have to calculate TGeoArb8 parameters, including rotation matrix;
378  // Assume, that {p1, p2, p3, p3} are base at -DZ and {p4,p4,p4,p4} is an apex at +DZ;
379 
380  // Figure out translation; start with normal to the triangular base;
381  TVector3 p21 = p2 - p1, p31 = p3 - p1, nn = p31.Cross(p21).Unit();
382  // Base points should be in clockwise direction in TGeoArb8 => need to check
383  // the below scalar product sign (should be positive) and if not, swap p2 & p3;
384  TVector3 p41 = p4 - p1;
385  double projection = p41 * nn;
386  //printf("pro: %f\n", projection);
387  if (projection < 0)
388  {
389  TVector3 bff(p2);
390  p2 = p3;
391  p3 = bff;
392 
393  p21 = p2 - p1;
394  p31 = p3 - p1;
395 
396  nn = -1. * nn;
397  } //if
398  projection = fabs(projection);
399  TVector3 p41perp = projection * nn, translation = p4 - 0.5 * p41perp;
400 
401  // Then calculate rotation matrix;
402  TVector3 zz(0., 0., 1.);
403  double angle = nn.Angle(zz);
404  TVector3 axis = (nn.Cross(zz)).Unit();
405 
406  TRotation rr, qrr; rr.SetToIdentity();
407  // Requires a bit of massaging;
408  if (!angle)
409  qrr.SetToIdentity();
410  else
411  if (angle == TMath::Pi())
412  // Or rr.RotateX(pi), does not matter;
413  qrr = rr.RotateY(TMath::Pi());
414  else
415  qrr = rr.Rotate(angle, axis);
416  TVector3 q1, q2, q3, q4;
417  q1 = qrr * (p1 - translation);
418  q2 = qrr * (p2 - translation);
419  q3 = qrr * (p3 - translation);
420  q4 = qrr * (p4 - translation);
421  //q1.Print(); q2.Print(); q3.Print(); q4.Print(); cout << endl; //exit(0);
422 
423  double vtx[8][2] = {
424  {q1.x(), q1.y()},
425  {q2.x(), q2.y()},
426  {q3.x(), q3.y()},
427  {q3.x(), q3.y()},
428  {q4.x(), q4.y()},
429  {q4.x(), q4.y()},
430  {q4.x(), q4.y()},
431  {q4.x(), q4.y()}};
432 
433  // Is there an easier way to do this?;
434  qrr.Invert();
435  double data[9] = {qrr.XX(), qrr.XY(), qrr.XZ(),
436  qrr.YX(), qrr.YY(), qrr.YZ(),
437  qrr.ZX(), qrr.ZY(), qrr.ZZ()};
438 
439  TGeoRotation *grr = new TGeoRotation();
440  grr->SetMatrix(data);
441 
442  TGeoArb8 *tet = new TGeoArb8 (name, projection/2., (double*)vtx);
443  TGeoVolume *vtet = new TGeoVolume(name, tet, medium);
444  fMother->AddNode(vtet, 0, new TGeoCombiTrans(translation.x() + shift.x(),
445  translation.y() + shift.y(), translation.z() + shift.z(), grr));
446  //vtet->SetFillColor(kBlue);
447  //printf("Here!\n");
448  // THINK: really needed?;
449  //grr->RegisterYourself();
450  vtet->RegisterYourself();
451 
452  return vtet;
453 } // CreateTetrahedron()
454 
455 // ---------------------------------------------------------------------------------------
456 
457 static TVector3 swapXYfun(TVector3 src)
458 {
459  TVector3 ret;
460  ret.SetX(-src.z());
461  ret.SetY( src.y());
462  ret.SetZ( src.x());
463 
464  return ret;
465 } // swapXYfun()
466 
467 //#include <TGeoSphere.h>
468 //#include <TGeoCompositeShape.h>
469 
470 void EicStlFactory::_ConstructGeometry(TGeoVolume *mother, TVector3 shift, bool swapXY,
471  /*bool wireframe,*/ std::vector<TGeoVolume*> *volumes)
472 {
473  for (gEntry::iterator it=mGroups.begin(); it!=mGroups.end(); it++) {
474  EicStlMediaGroup *mgroup = &it->second;
475 
476  //printf("vtx count: %d; buffered facet count: %d\n",
477  // mgroup->vertices()->size(), mgroup->mFbuffer.size());
478 
479 #if _DOES_NOT_WORK_
480  // May want to build just a wireframe model for vizualization purposes;
481  //if (mWireframeMode) {
482  if (wireframe) {
483  double fsize = 5.0 * eic::mm;
484  static unsigned counter;
485 
486  //char sname[128];//, tname[128];
487  //snprintf(sname, 128-1, "Pt%05d", counter);
488  //snprintf(tname, 128-1, "Tr%05d", counter);
489  TGeoSphere *sphere = new TGeoSphere("SPHERE", 0.0, fsize/2);
490  TGeoVolume *vsphere = new TGeoVolume("SPHERE", sphere, it->first.second);
491  vsphere->RegisterYourself();
492  //TGeoCombiTrans *trans = new TGeoCombiTrans(tname, src[0], src[1], src[2], 0);
493  //mother->AddNode(vsphere, 0, new TGeoCombiTrans(src[0], src[1], src[2], 0));
494 
495  char cmd[16384] = "";
496  for (vEntry::const_iterator vt=mgroup->vertices()->begin(); vt != mgroup->vertices()->end(); vt++) {
497  EicStlVertex *vtx = vt->second;
498  //vtx->Print();
499 
500  TVector3 src(vtx->key()->GetData());
501  if (swapXY) src = swapXYfun(src);
502 
503  //char sname[128], tname[128];
504  //snprintf(sname, 128-1, "Pt%05d", counter);
505  //snprintf(tname, 128-1, "Tr%05d", counter);
506  //TGeoSphere *sphere = new TGeoSphere(sname, 0.0, fsize/2);
507  //TGeoVolume *vsphere = new TGeoVolume(sname, sphere, it->first.second);
508  //TGeoCombiTrans *trans = new TGeoCombiTrans(tname, src[0], src[1], src[2], 0);
509  mother->AddNode(vsphere, counter, new TGeoCombiTrans(src[0], src[1], src[2], 0));
510  //trans->RegisterYourself();
511  //vsphere->RegisterYourself();
512 
513  //unsigned len = strlen(cmd);
514  //if (counter) sprintf(cmd + strlen(cmd), "+");
515  //sprintf(cmd + strlen(cmd), "%s:%s", sname, tname);
516  //char cmd[1024], yokeCompName[128];
517  //snprintf(cmd, 1024-1, "%s-%s", yokeIronName, yokeVacuumName);
518  //snprintf(yokeCompName, 128-1, "%sComp", GetDetectorName().Data());
519 
520  //TGeoCompositeShape *comp = new TGeoCompositeShape(yokeCompName/*GetDetectorName().Data()*/, cmd);
521  //mYoke = new TGeoVolume(yokeCompName/*GetDetectorName().Data()*/, comp, mediaHub->GetMedium(_IRON_));
522 
523  //break;
524 
525  counter++;
526  } //for vt
527 
528  //printf("%s\n", cmd);
529  //TGeoCompositeShape *comp = new TGeoCompositeShape("SPHERE", cmd);
530  //TGeoVolume *vcomp = new TGeoVolume("SPHERE", comp, it->first.second);
531  //mother->AddNode(vcomp, 0, new TGeoCombiTrans(0, 0, 0, 0));//src[0], src[1], src[2], 0));
532  //vcomp->RegisterYourself();
533 
534  continue;
535  } //if
536 #endif
537 
539  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m EicStlFactory::ConstructGeometry() "
540  "failed on %s!! \033[0m", mGeometryName.Data());
541 
542  // Assume, that by this point all the remaining issues are resolved; just loop through
543  // assemblies and their facets, dump respective ASCII files, call TETGEN and ROOT Geo Manager;
544  for(unsigned ass=0; ass<mgroup->assemblies().size(); ass++)
545  {
546  EicStlAssembly *assembly = mgroup->assemblies()[ass];
547 
548  // FIXME: should put medium name here as well;
549  char buffer[128];
550  snprintf(buffer, 128-1, "./%05d-%06d-%s.stl", getpid(), ass, it->first.second->GetName());
551  TString stlActualFileName = TString(buffer);
552 
553  DumpTmpStlFile(assembly, stlActualFileName);
554 
555  // NB: yes, comment out like this since eventually may want to add complementary netgen
556  // support as well (so that the routine itself can still be a valid piece of code);
557 #ifdef TETLIBRARY
558  {
559  tetgenio in, out;
560  unsigned ret = in.load_stl((char*)stlActualFileName.Data());
561  std::cout << in.numberofpoints << " points" << std::endl;
562 
563  //printf("Here-1!\n");
564  // The essential part - convertion to tetrahedra; "Y" key is VERY important here
565  // for a multi-piece object!; how about checking return code?;
566  tetrahedralize((char*)"YpQ", &in, &out);
567  //tetrahedralize((char*)"Yp", &in, &out);
568  //printf("Here-2!\n");
569  std::cout << out.numberofpoints << " points" << std::endl;
570  std::cout << mVolumeName.Data() << " @@@ " << out.numberoftetrahedra << " thetrahedra" << std::endl;
571 
572  for (int iq=0; iq<out.numberoftetrahedra; iq++)
573  {
574  char name[128];
575  //snprintf(name, 128-1, "%s-Ass%04d-Tet%06d-%s", mVolumeName.Data(), ass, iq,
576  // it->first.second->GetName());
577  snprintf(name, 128-1, "@RV@%s-Ass%04d-Tet%06d-%s", mVolumeName.Data(), ass, iq,
578  it->first.second->GetName());
579 
580  // Tetrahedron has 4 corners, right?;
581  int index_offset = iq * 4;
582 
583  // Use p1..p4 instead of array p[4] for a better readability;
584  TVector3 p1 = GetTetPoint(out, index_offset );
585  TVector3 p2 = GetTetPoint(out, index_offset + 1);
586  TVector3 p3 = GetTetPoint(out, index_offset + 2);
587  TVector3 p4 = GetTetPoint(out, index_offset + 3);
588  //p1.Print(); p2.Print(); p3.Print(); p4.Print(); cout << endl; //exit(0);
589 
590  //createTetrahedron(p1, p2, p3, p4, name, fSingleMedium);
591  //+CreateTetrahedron(p1, p2, p3, p4, name, mother, it->first.second, shift);
592  {
593  TGeoVolume *vtet;
594 
595  if (swapXY) {
596  TVector3 swpp1 = swapXYfun(p1), swpp2 = swapXYfun(p2), swpp3 = swapXYfun(p3), swpp4 = swapXYfun(p4);
597 
598  vtet = CreateTetrahedron(swpp1, swpp2, swpp3, swpp4, name, mother, it->first.second, shift);
599  } else
600  vtet = CreateTetrahedron(p1, p2, p3, p4, name, mother, it->first.second, shift);
601 
602  if (volumes) volumes->push_back(vtet);
603  //printf("Here!\n");
604  //vtet->SetFillColor(kBlue);
605  //vtet->RegisterYourself();
606  }
607  }
608  }
609 #else
610  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m STL file meshing required but Tetgen "
611  "support is not compiled in! \033[0m");
612 
613 #endif
614  unlink(stlActualFileName.Data());
615  } //for ass
616  } //for it
617 } // EicStlFactory::ConstructGeometry()
618 
619 // ---------------------------------------------------------------------------------------
620 
621 int EicStlFactory::CreateRootFile(TGeoVolume *mother, const char *bname)
622 {
623  for (gEntry::iterator it=mGroups.begin(); it!=mGroups.end(); it++) {
624  EicStlMediaGroup *mgroup = &it->second;
625 
626  //printf("vtx count: %d; buffered facet count: %d\n",
627  // mgroup->vertices()->size(), mgroup->mFbuffer.size());
628 
629  if (mgroup->SplitIntoAssemblies(mConfig->GetStlVertexMergingTolerance())) assert(0);
630 
631  // Assume, that by this point all the remaining issues are resolved; just loop through
632  // assemblies and their facets, dump respective ASCII files, call TETGEN and ROOT Geo Manager;
633  for(unsigned ass=0; ass<mgroup->assemblies().size(); ass++) {
634  EicStlAssembly *assembly = mgroup->assemblies()[ass];
635 
636  // FIXME: should put medium name here as well;
637  char buffer[128];
638  snprintf(buffer, 128-1, "./%05d-%06d-%s.stl", getpid(), ass, it->first.second->GetName());
639  TString stlActualFileName = TString(buffer);
640 
641  DumpTmpStlFile(assembly, stlActualFileName);
642 
643  // NB: yes, comment out like this since eventually may want to add complementary netgen
644  // support as well (so that the routine itself can still be a valid piece of code);
645 #ifdef TETLIBRARY
646  {
647  tetgenio in, out;
648  unsigned ret = in.load_stl((char*)stlActualFileName.Data());
649  std::cout << in.numberofpoints << " points" << std::endl;
650 
651  // The essential part - convertion to tetrahedra; "Y" key is VERY important here
652  // for a multi-piece object!; how about checking return code?;
653  //+tetrahedralize((char*)"YpQ", &in, &out);
654  tetrahedralize((char*)"Yp", &in, &out);
655  std::cout << out.numberofpoints << " points" << std::endl;
656  std::cout << mVolumeName.Data() << " @@@ " << out.numberoftetrahedra << " thetrahedra" << std::endl;
657 
658  for (int iq=0; iq<out.numberoftetrahedra; iq++) {
659  char name[128];
660  snprintf(name, 128-1, "@RV@%s-Ass%04d-Tet%06d-%s", mVolumeName.Data(), ass, iq,
661  it->first.second->GetName());
662 
663  // Tetrahedron has 4 corners, right?;
664  int index_offset = iq * 4;
665 
666  // Use p1..p4 instead of array p[4] for a better readability;
667  TVector3 p1 = GetTetPoint(out, index_offset );
668  TVector3 p2 = GetTetPoint(out, index_offset + 1);
669  TVector3 p3 = GetTetPoint(out, index_offset + 2);
670  TVector3 p4 = GetTetPoint(out, index_offset + 3);
671 
672  //CreateTetrahedron(p1, p2, p3, p4, name, cave, it->first.second, TVector3());
673  CreateTetrahedron(p1, p2, p3, p4, name, mother, mConfig->mhub()->fSingleMedium, TVector3());
674  }
675  }
676 #else
677  printf("STL file meshing required but Tetgen support is not compiled in!\n");
678  assert(0);
679 #endif
680 
681  // No need in these intermediate files;
682  unlink(stlActualFileName.Data());
683  } //for ass
684  } //for it
685 
686  return 0;
687 } // EicStlFactory::CreateRootFile()
688 
689 // =======================================================================================
690