EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicCompositeShape.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicCompositeShape.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/03/11; revamped in Oct'2017;
3 //
4 // EicRoot CompositeShape ROOT shape; NB: several sections of commented out
5 // debugging stuff were wiped out of this file on 2017/10/04;
6 //
7 
8 #include <assert.h>
9 
10 #include <TVirtualGeoPainter.h>
11 #include <TVirtualViewer3D.h>
12 #include <TBuffer3D.h>
13 #include <TBuffer3DTypes.h>
14 #include <TGeoBoolNode.h>
15 #include <TGeoManager.h>
16 #include <TPad.h>
17 
18 #ifdef _OPENCASCADE_
19 #include <Bnd_Box.hxx>
20 #include <BRepBndLib.hxx>
21 #include <BRepMesh_IncrementalMesh.hxx>
22 
23 #include <StlAPI_Writer.hxx>
24 
25 //#include <EicStlEdge.h>
26 #include <EicStlFactory.h>
27 
28 typedef std::map<const EicStlKey*, unsigned, bool(*)(const EicStlKey*, const EicStlKey*)> qEntry;
29 #endif
30 
31 #include <EicCompositeShape.h>
32 
33 // =======================================================================================
34 
35 int EicCompositeShape::LocalFillBuffer3D(double stl_quality_coefficient)
36 {
37  // Yes, basically a dummy call in case if OpenCascade libraries are not available;
38  // NB: this call is needed only on the EicRoot side (where object is created);
39  // for other purposes like visualization it is not really needed;
40 #ifdef _OPENCASCADE_
41  // For less typing;
43 
44  // Ok, first fill out the bounding box entries;
45  {
46  Bnd_Box Boundary;
47  BRepBndLib::Add(*mSolid, Boundary);
48 
49  Boundary.Get(lb->xMin, lb->yMin, lb->zMin, lb->xMax, lb->yMax, lb->zMax);
50  }
51 
52  // Pass this solid through OpenCascade STL maker; unify with dumpAsStlSolid() later;
53  {
54  char buffer[128];
55  snprintf(buffer, 128-1, "./%05d-tmp.stl", getpid());
56 
57  {
58  StlAPI_Writer writer;
59 
60  BRepMesh_IncrementalMesh(*mSolid, stl_quality_coefficient);
61 
62  writer.ASCIIMode() = false;
63  writer.Write(*mSolid, buffer);
64  }
65 
66  {
67  EicStlFactory stl_factory("", buffer, 0);
68 
69  // And now figure out imported vertex/edge/facet count and fill the 3D buffer;
70  // assume no fixes are needed (reconsider later); only one 'mgroup' in fact, so
71  // no real loop here;
72  //printf("%d mgroup(s)\n", stl_factory.mgroups().size());
73  for (gEntry::iterator it=stl_factory.mgroups().begin(); it!=stl_factory.mgroups().end(); it++) {
74  EicStlMediaGroup *mgroup = &it->second;
75 
76  //
77  // FIXME: unify the codes in the below if();
78  //
79 
80  // Split into assemblies and make sure there is only one; otherwise (if split
81  // procedure failed) fall back to "visually-correct-only" version;
82 #if _TODAY_
83  if (mgroup->SplitIntoAssemblies()) {
84 #endif
85  mgroup->SplitIntoAssemblies(0.0, true);
86  lb->fNbPnts = mgroup->facets()->size() * 3;
87  lb->fNbSegs = mgroup->facets()->size() * 3;
88  lb->fNbPols = mgroup->facets()->size();
89 
90  // '3': XYZ per point;
91  lb->fPntsCapacity = lb->fNbPnts * 3;
92  lb->fPnts = new Double_t[lb->fPntsCapacity];
93  // '2': end point indices;
94  lb->fSegsCapacity = lb->fNbSegs * 2;
95  lb->fSegs = new Int_t [lb->fSegsCapacity];
96  // '3': edge indices;
97  lb->fPolsCapacity = lb->fNbPols * 3;
98  lb->fPols = new Int_t [lb->fPolsCapacity];
99 
100  unsigned vCounter = 0, eCounter = 0, fCounter = 0;
101  //printf("--> %d\n", mgroup->facets()->size());
102  for(fEntry::const_iterator ft=mgroup->facets()->begin(); ft!=mgroup->facets()->end(); ft++) {
103  EicStlFacet *facet = ft->second;
104 
105  // Allocate facet edge indices;
106  lb->fPols[3*fCounter+0] = eCounter+0;
107  lb->fPols[3*fCounter+1] = eCounter+1;
108  lb->fPols[3*fCounter+2] = eCounter+2;
109  fCounter++;
110 
111  // Allocate edge endpoint indices;
112  lb->fSegs[2*eCounter+0] = vCounter+0;
113  lb->fSegs[2*eCounter+1] = vCounter+1;
114  eCounter++;
115  lb->fSegs[2*eCounter+0] = vCounter+1;
116  lb->fSegs[2*eCounter+1] = vCounter+2;
117  eCounter++;
118  lb->fSegs[2*eCounter+0] = vCounter+2;
119  lb->fSegs[2*eCounter+1] = vCounter+0;
120  eCounter++;
121 
122  // Allocate vertices; use "natural" ordering as it was given in the STL file dump;
123  for(unsigned vt=0; vt<3; vt++) {
124  EicStlVertex *vertex = facet->mVbuffer[vt];
125  const double *arr = vertex->key()->GetData();
126 
127  for(unsigned iq=0; iq<3; iq++)
128  lb->fPnts[vCounter*3 + iq] = arr[iq];
129 
130  vCounter++;
131  } //for vt
132  } //for ft
133  //printf("%d %d %d\n", vCounter, eCounter, fCounter);
134 #if _TODAY_
135  } else {
136  if (mgroup->assemblies().size() != 1)
137  printf("mgroup->assemblies().size(): %d\n", mgroup->assemblies().size());
138  assert(mgroup->assemblies().size() == 1);
139 
140  //for(unsigned ass=0; ass<mgroup->assemblies.size(); ass++) {
141  //EicStlAssembly *assembly = mgroup->assemblies[ass];
142  EicStlAssembly *assembly = mgroup->assemblies()[0];
143 
144  // For now assume vertices can not disappear during healing procedure;
145  lb->fNbPnts = mgroup->vertices()->size();
146  // Triangular facets, each edge is shared by two facets;
147  lb->fNbSegs = assembly->facets().size() * 3 / 2;
148  lb->fNbPols = assembly->facets().size();
149 
150  //printf("vtx count: %d; edge count: %d; facet count: %d\n",
151  // mgroup->vertices()->size(), lb->fNbSegs, lb->fNbPols);
152 
153  // '3': XYZ per point;
154  lb->fPntsCapacity = lb->fNbPnts * 3;
155  lb->fPnts = new Double_t[lb->fPntsCapacity];
156  // '2': end point indices;
157  lb->fSegsCapacity = lb->fNbSegs * 2;
158  lb->fSegs = new Int_t [lb->fSegsCapacity];
159  // '3': edge indices;
160  lb->fPolsCapacity = lb->fNbPols * 3;
161  lb->fPols = new Int_t [lb->fPolsCapacity];
162 
163  {
164  unsigned eCounter = 0, vCounter = 0;
165  qEntry edgeKeys(EicStlKeyCompare), vtxKeys(EicStlKeyCompare);
166 
167  // Loop through all facets and assign segment (edge) indices;
168  for(unsigned fc=0; fc<assembly->facets().size(); fc++) {
169  EicStlFacet *facet = assembly->facets()[fc].first;
170  bool orientation = assembly->facets()[fc].second;
171 
172  for(unsigned ee=0; ee<3; ee++) {
173  const EicStlFacetEdge *edge = facet->edge(ee);
174 
175  if (edgeKeys.find(edge->key()) == edgeKeys.end()) {
176  // New edge -> check vertices;
177  unsigned evCounter = 0;
178  for(vEntry::const_iterator vt=edge->vertices()->begin(); vt!=edge->vertices()->end() ; vt++) {
179  EicStlVertex *vertex = vt->second;
180 
181  if (vtxKeys.find(vertex->key()) == vtxKeys.end()) {
182  const double *arr = vertex->key()->GetData();
183 
184  // Vertex coordinates; FIXME: (obsolete) float -> double;
185  for(unsigned iq=0; iq<3; iq++)
186  lb->fPnts[vCounter*3 + iq] = arr[iq];
187 
188  vtxKeys[vertex->key()] = vCounter++;
189  } //if
190 
191  // Segment entry;
192  lb->fSegs[eCounter*2 + evCounter++] = vtxKeys[vertex->key()];
193  } //for vv
194 
195  edgeKeys[edge->key()] = eCounter++;
196  } //if
197 
198  // Facet entry;
199  lb->fPols[fc*3 + (orientation ? 2-ee : ee)] = edgeKeys[edge->key()];
200  } //for ee
201  } //for fc
202 
203  //printf("%d %d\n", edgeKeys.size(), vtxKeys.size()); exit(0);
204  }
205  } //if
206 #endif
207  } //for it
208  }
209 
210  //unlink(buffer);
211  }
212 #endif
213 
214  return 0;
215 } // EicCompositeShape::LocalFillBuffer3D()
216 
217 // ---------------------------------------------------------------------------------------
218 
219 void EicCompositeShape::LocalSetPoints(Double_t *points) const
220 {
221  // Fill box points.
222  if (!points) return;
223 
225 
226  for(unsigned pt=0; pt<lb->fNbPnts; pt++)
227  for(unsigned iq=0; iq<3; iq++)
228  points[pt*3+iq] = lb->fPnts[pt*3+iq];
229 } // EicCompositeShape::LocalSetPoints()
230 
231 // ---------------------------------------------------------------------------------------
232 
233 void EicCompositeShape::LocalSetSegsAndPols(TBuffer3D &buff) const
234 {
235  // Fills TBuffer3D structure for segments and polygons.
236  Int_t c = GetBasicColor();
237 
238  //printf("@@@ basic color -> %d\n", GetBasicColor());
240 
241  for(unsigned sg=0; sg<lb->fNbSegs; sg++) {
242  buff.fSegs[sg*3] = c;
243 
244  for(unsigned iq=0; iq<2; iq++)
245  buff.fSegs[sg*3+iq+1] = lb->fSegs[sg*2+iq];
246  } //for
247 
248  for(unsigned fc=0; fc<lb->fNbPols; fc++) {
249  buff.fPols[fc*5+0] = c;
250  buff.fPols[fc*5+1] = 3;
251 
252  // Change segment sequence (orientation) to make ROOT happy;
253  for(unsigned iq=0; iq<3; iq++)
254  buff.fPols[fc*5+iq+2] = lb->fPols[fc*3+2-iq];
255  } //for
256 } // EicCompositeShape::LocalSetSegsAndPols()
257 
258 // ---------------------------------------------------------------------------------------
259 
260 //
261 // Follow the strange logic to split this stuff into FillBuffer3D() and GetBuffer3D();
262 //
263 
264 void EicCompositeShape::FillBuffer3D(TBuffer3D & buffer, Int_t reqSections, Bool_t localFrame) const
265 {
266  // Fills the supplied buffer, with sections in desired frame
267  // See TBuffer3D.h for explanation of sections, frame etc.
268  TGeoShape::FillBuffer3D(buffer, reqSections, localFrame);
269 
270  // For less typing;
272 
273  double origin[3] = {
274  (lb->xMin + lb->xMax)/2.,
275  (lb->yMin + lb->yMax)/2.,
276  (lb->zMin + lb->zMax)/2.};
277  double halfLengths[3] = {
278  (lb->xMax - lb->xMin)/2.,
279  (lb->yMax - lb->yMin)/2.,
280  (lb->zMax - lb->zMin)/2.};
281 
282  if (reqSections & TBuffer3D::kBoundingBox) {
283  buffer.SetAABoundingBox(origin, halfLengths);
284 
285  if (!buffer.fLocalFrame) {
286  TransformPoints(buffer.fBBVertex[0], 8);
287  } //if
288 
289  buffer.SetSectionsValid(TBuffer3D::kBoundingBox);
290  } //if
291 } // EicCompositeShape::FillBuffer3D()
292 
293 // ---------------------------------------------------------------------------------------
294 
295 const TBuffer3D &EicCompositeShape::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
296 {
297  // Ok, leave this buffer static as it was in the original ROOT codes; TBuffer3D::SetRawSizes()
298  // seem to perform delete/new operations, also according to docs after viewer->AddObject()
299  // buffer can be reused; fine;
300  static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
301 
302  FillBuffer3D(buffer, reqSections, localFrame);
303 
304  //printf("%d %d %d\n", localBuffer3D->NbPnts(), localBuffer3D->NbSegs(),
305  // localBuffer3D->NbPols()); exit(0);
306 
307  // TODO: A box itself has nothing more as already described
308  // by bounding box. How will viewer interpret?
309  if (reqSections & TBuffer3D::kRawSizes) {
310  if (buffer.SetRawSizes(mLocalBuffer3D->NbPnts(), 3 * mLocalBuffer3D->NbPnts(),
313  buffer.SetSectionsValid(TBuffer3D::kRawSizes);
314  } //if
315  } //if
316  if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
317  LocalSetPoints(buffer.fPnts);
318  if (!buffer.fLocalFrame) {
319  TransformPoints(buffer.fPnts, buffer.NbPnts());
320  } //if
321 
322  LocalSetSegsAndPols(buffer);
323  buffer.SetSectionsValid(TBuffer3D::kRaw);
324  } //if
325 
326  return buffer;
327 } // EicCompositeShape::GetBuffer3D()
328 
329 // ---------------------------------------------------------------------------------------
330 
331 Bool_t EicCompositeShape::PaintComposite(Option_t *option) const
332 {
333  // Paint this composite shape into the current 3D viewer
334  // Returns bool flag indicating if the caller should continue to
335  // paint child objects
336  Bool_t addChildren = kTRUE;
337 
338  TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
339  TVirtualViewer3D * viewer = gPad->GetViewer3D();
340  if (!painter || !viewer) return kFALSE;
341 
342  // Does viewer prefer local frame positions?
343  Bool_t localFrame = viewer->PreferLocalFrame();
344  // Perform first fetch of buffer from the shape and try adding it
345  // to the viewer
346  const TBuffer3D & buffer =
347  GetBuffer3D(TBuffer3D::kCore|TBuffer3D::kBoundingBox/*|TBuffer3D::kShapeSpecific*/, localFrame);
348  Int_t reqSections = viewer->AddObject(buffer, &addChildren);
349 
350  // If the viewer requires additional sections fetch from the shape (if possible)
351  // and add again
352  if (reqSections != TBuffer3D::kNone) {
353  GetBuffer3D(reqSections, localFrame);
354  viewer->AddObject(buffer, &addChildren);
355  } //if
356 
357  //printf("@@@ returning %d (true=%d) ...\n", addChildren, kTRUE);
358  return addChildren;
359 } // EicCompositeShape::PaintComposite()
360 
361 // =======================================================================================
362