EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicStlMediaGroup.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicStlMediaGroup.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/01/08; revamped in Oct'2017;
3 //
4 // EicRoot CAD manipulation routines; facets/vertices/etc with a given medium type;
5 //
6 
7 #include <assert.h>
8 
9 #include <TMath.h>
10 #include <TRotation.h>
11 
12 #include <EicStlMediaGroup.h>
13 
14 // =======================================================================================
15 
17  mEdgeTotalOwnerCountOk(true), mEdgeSimpleSharingOk(true)
18 {
22 } // EicStlMediaGroup::EicStlMediaGroup()
23 
24 // ---------------------------------------------------------------------------------------
25 
26 void EicStlMediaGroup::AddVertexToCurrentGroup(std::vector<std::vector<EicStlVertex*> > &ngroups,
28 {
29  std::vector<EicStlVertex*> &current = ngroups[ngroups.size()-1];
30  current.push_back(vtx);
31  vtx->SetMergedFlag();
32 
33  for(unsigned iq=0; iq<vtx->DegenerateNeighbors3D().size(); iq++) {
34  EicStlVertex *qtx = vtx->DegenerateNeighbors3D()[iq];
35  if (!qtx->IsMerged()) AddVertexToCurrentGroup(ngroups, qtx);
36  } //for iq
37 } // EicStlMediaGroup::AddVertexToCurrentGroup()
38 
39 // ---------------------------------------------------------------------------------------
40 
42 {
43  if (!tolerance) return;
44 
45  // Loop through all vertices once and find their 3D neighbors;
46  for (vEntry::iterator vt=mVertices->begin(); vt!=mVertices->end(); vt++) {
47  //printf("Next vertex!\n");
48  EicStlVertex *vtx = vt->second;
49  TVector3 vtx3d(vtx->key()->GetData()[0], vtx->key()->GetData()[1], vtx->key()->GetData()[2]);
50 
51  // FIXME: yes, do it, please (a loop, etc);
52  {
53  double xMin = vtx->key()->GetData()[0] - tolerance, xMax = vtx->key()->GetData()[0] + tolerance;
54  std::multimap<double, EicStlVertex*>::iterator xLower = xCoord.lower_bound(xMin);
55  std::multimap<double, EicStlVertex*>::iterator xUpper = xCoord.upper_bound(xMax);
56  for(std::multimap<double, EicStlVertex*>::iterator ix = xLower; ix != xUpper; ix++) {
57  EicStlVertex *qtx = ix->second;
58 
59  if (qtx != vtx) vtx->IncrementDegenerateNeighbor1D(qtx);//]++;
60  //printf(" --> %f\n", qtx->key()->GetData()[0]);
61  } //for ix
62  }
63  {
64  double xMin = vtx->key()->GetData()[1] - tolerance, xMax = vtx->key()->GetData()[1] + tolerance;
65  std::multimap<double, EicStlVertex*>::iterator xLower = yCoord.lower_bound(xMin);
66  std::multimap<double, EicStlVertex*>::iterator xUpper = yCoord.upper_bound(xMax);
67  for(std::multimap<double, EicStlVertex*>::iterator ix = xLower; ix != xUpper; ix++) {
68  EicStlVertex *qtx = ix->second;
69 
70  if (qtx != vtx) vtx->IncrementDegenerateNeighbor1D(qtx);//]++;
71  //printf(" --> %f\n", qtx->key()->GetData()[0]);
72  } //for ix
73  }
74  {
75  double xMin = vtx->key()->GetData()[2] - tolerance, xMax = vtx->key()->GetData()[2] + tolerance;
76  std::multimap<double, EicStlVertex*>::iterator xLower = zCoord.lower_bound(xMin);
77  std::multimap<double, EicStlVertex*>::iterator xUpper = zCoord.upper_bound(xMax);
78  for(std::multimap<double, EicStlVertex*>::iterator ix = xLower; ix != xUpper; ix++) {
79  EicStlVertex *qtx = ix->second;
80 
81  if (qtx != vtx) vtx->IncrementDegenerateNeighbor1D(qtx);//]++;
82  //printf(" --> %f\n", qtx->key()->GetData()[0]);
83  } //for ix
84  }
85 
86  // Now check 3D distances for those neighbors, which are suspiciously close in all 3 projections;
87  for(std::map<EicStlVertex*, unsigned>::const_iterator iq = vtx->DegenerateNeighbors1D().begin();
88  iq != vtx->DegenerateNeighbors1D().end(); iq++) {
89  EicStlVertex *qtx = iq->first;
90  if (iq->second != 3) continue;
91 
92  TVector3 qtx3d(qtx->key()->GetData()[0], qtx->key()->GetData()[1], qtx->key()->GetData()[2]);
93  double dist = (qtx3d - vtx3d).Mag();
94  if (dist < tolerance) {
95  printf(" ... %d %f\n", iq->second, dist);
96  vtx->AddDegenerateNeighbors3D(qtx);
97  } //if
98  } //for iq
99  } //for vt
100 
101  // Loop for the second time and construct neighbor classes;
102  {
103  std::vector<std::vector<EicStlVertex*> > ngroups;
104 
105  for (vEntry::iterator vt=mVertices->begin(); vt!=mVertices->end(); vt++) {
106  EicStlVertex *vtx = vt->second;
107  if (vtx->IsMerged() || !vtx->DegenerateNeighbors3D().size()) continue;
108 
109  {
110  // Add empty vector and recursively add vertices to it; NB: since this
111  // vertex was not yet accounted in any neighbor group and neighbor
112  // assignment procedure was "symmetric" and neighbor array has non-zero
113  // size, there definitely should be other unaccounted neighbors there;
114  std::vector<EicStlVertex*> gr;
115  ngroups.push_back(gr);
116  AddVertexToCurrentGroup(ngroups, vtx);
117  }
118  } //for vt
119 
120  //printf("%d\n", ngroups.size());
121  for(unsigned iq=0; iq<ngroups.size(); iq++) {
122  // NB: make calculation symmetric wrt the neighbor vertices;
123  TVector3 vsum;
124 
125  for(unsigned iv=0; iv<ngroups[iq].size(); iv++) {
126  EicStlVertex *qtx = ngroups[iq][iv];
127 
128  TVector3 vadd(qtx->key()->GetData()[0], qtx->key()->GetData()[1], qtx->key()->GetData()[2]);
129  vsum += vadd;
130  } //for iv
131 
132  vsum *= 1.0/ngroups[iq].size();
133 
134  //printf(" %d -> %d; %f %f %f\n", iq, ngroups[iq].size(), vsum[0], vsum[1], vsum[2]);
135 
136  // FIXME: do this better later;
137  double buffer[3] = {vsum[0], vsum[1], vsum[2]};
138  // Create brand new vertex; NB: per construction it can happen that such
139  // vertex does exist already; take this case into account;
140  EicStlVertex *vnew = new EicStlVertex(buffer);
141  if (mVertices->find(vnew->key()) == mVertices->end()) {
142  (*mVertices)[vnew->key()] = vnew;
143  } else {
144  EicStlVertex *vcopy = (*mVertices)[vnew->key()];
145  delete vnew;
146  vnew = vcopy;
147  } //if
148 
149  // Assign merged vertex pointers for neighbor group members;
150  for(unsigned iv=0; iv<ngroups[iq].size(); iv++) {
151  EicStlVertex *qtx = ngroups[iq][iv];
152 
153  qtx->SetMergedVertex(vnew);
154  } //for iv
155  } //for iq
156  }
157 } // EicStlMediaGroup::MergeDegenerateVertices()
158 
159 // ---------------------------------------------------------------------------------------
160 
162 {
163  // Loop through all buffered facets, calculate them (now that all vertices are known)
164  // and allocate in an ordered map;
165  for(unsigned fc=0; fc<mFbuffer.size(); fc++) {
166  EicStlFacet *facet = mFbuffer[fc];
167 
168  // Facet is most likely degenerate -> kill it right away;
169  if (facet->Calculate()) {
170  delete facet;
171  continue;
172  } //if
173 
174  if (mFacets->find(facet->key()) == mFacets->end()) {
175  // Facet is new -> allocate in the ordered map and set counter to 1;
176  (*mFacets)[facet->key()] = facet;
177  facet->SetCounter(1);
178  } else {
179  // Facet is duplicate (perhaps up to orientation) -> increment counter;
180  mFacets->find(facet->key())->second->IncrementCounter();
181  delete facet;
182  } //if
183  } //for fc
184 
185  // Do not need facet buffer any longer;
186  mFbuffer.clear();
187 
188  // Clean up unused vertices; FIXME: check this in-progress erase(), please;
189  for (vEntry::iterator vt=mVertices->begin(); vt!=mVertices->end(); ) {
190  EicStlVertex *vtx = vt->second;
191 
192  if (vtx->IsMerged() && vtx->GetMergedVertex() != vtx) {
193  mVertices->erase(vt++);
194  delete vtx;
195  }
196  else
197  vt++;
198  } //for vt
199 
200  // Build vertex->facet relationships;
201  for (fEntry::iterator fc=mFacets->begin(); fc!=mFacets->end(); fc++) {
202  EicStlFacet *facet = fc->second;
203 
204  for(vEntry::const_iterator vt=facet->vertices()->begin(); vt!=facet->vertices()->end() ; vt++)
205  vt->second->AddFacet(facet);
206  } //for fc
207 } // EicStlMediaGroup::CalculateFacets()
208 
209 // ---------------------------------------------------------------------------------------
210 
212 {
213  for (fEntry::iterator fc=mFacets->begin(); fc != mFacets->end(); fc++) {
214  EicStlFacet *facet = fc->second;
215 
216  // Initialize edges; FIXME: this style here and below is awkward;
217  EicStlVertex *vv[3];
218  unsigned counter = 0;
219  for(vEntry::const_iterator vt=facet->vertices()->begin(); vt!=facet->vertices()->end() ; vt++)
220  vv[counter++] = vt->second;
221 
222  EicStlFacetEdge *e1 = new EicStlFacetEdge(vv[0], vv[1]);
223  EicStlFacetEdge *e2 = new EicStlFacetEdge(vv[1], vv[2]);
224  EicStlFacetEdge *e3 = new EicStlFacetEdge(vv[2], vv[0]);
225  EicStlFacetEdge *ee[3] = {e1, e2, e3};
226 
227  for(unsigned iq=0; iq<3; iq++) {
228  EicStlFacetEdge *edge = ee[iq];
229 
230  if (mEdges->find(edge->key()) == mEdges->end()) {
231  (*mEdges)[edge->key()] = edge;
232  } else {
233  ee[iq] = (*mEdges)[edge->key()];
234  delete edge;
235  } //if
236 
237  ee[iq]->AddFacet(facet);
238  } //for iq
239 
240  for(unsigned iq=0; iq<3; iq++)
241  facet->SetEdge(iq, ee[iq]);
242  } //for fc
243 
244  for (eEntry::iterator ee=mEdges->begin(); ee != mEdges->end(); ee++) {
245  EicStlFacetEdge *edge = ee->second;
246 
247  unsigned owner_counter = 0;
248  for(unsigned fc=0; fc<edge->facets().size(); fc++)
249  owner_counter += edge->facets()[fc]->GetCounter();
250 
251  if (owner_counter%2) {
252  printf("-> %d\n", owner_counter);
253 
254  for (vEntry::const_iterator vt=edge->vertices()->begin(); vt!=edge->vertices()->end(); vt++) {
255  EicStlVertex *vtx = vt->second;
256 
257  vtx->Print();
258  //printf(" --> %7.2f %7.2f %7.2f\n", vtx->);
259  } //fot vt
260  }
261  if (owner_counter%2) mEdgeTotalOwnerCountOk = false;
262  if (owner_counter != 2) mEdgeSimpleSharingOk = false;
263 
264  //printf("edge -> %d facet(s)\n", edge->facets.size());
265  } //for ee
266 } // EicStlMediaGroup::AllocateEdges()
267 
268 // ---------------------------------------------------------------------------------------
269 
271 {
272  // Facet accounted already -> sanity check;
273  assert(facet->GetCounter());
274 
275  // Arrange direct and reverse links;
276  EicStlAssembly *current = mAssemblies[mAssemblies.size()-1];
277  current->AddFacet(facet, flip);
278 
279  facet->DecrementCounter();
280 
281  // Loop through all 3 edges, find matching facet (which is trivial in case of
282  // 'edge->mTotalOwnerCount == 2' and more complicated otherwise) and add it to this
283  // same assembly recursively;
284  for(unsigned iq=0; iq<3; iq++) {
285  const EicStlFacetEdge *edge = facet->edge(iq);
286  bool orientation = iq <= 1;
287 
288  if (edge->facets().size() == 2) {
289  for(unsigned fc=0; fc<edge->facets().size(); fc++) {
290  EicStlFacet *other_facet = edge->facets()[fc];
291 
292  if (/*other_facet == facet ||*/ !other_facet->GetCounter()) continue;
293 
294  bool edge_orientations_match = true;
295 
296  // FIXME: do it better later;
297  for(unsigned ie=0; ie<3; ie++) {
298  const EicStlFacetEdge *other_edge = other_facet->edge(ie);
299  bool other_orientation = ie <= 1;
300 
301  if (other_edge == edge) {
302  edge_orientations_match = orientation != other_orientation;
303  break;
304  } //if
305  } //for ie
306 
307  {
308  bool other_flip = (flip && edge_orientations_match) ||
309  (!flip && !edge_orientations_match);
310 
311  CoupleFacetToAssembly(other_facet, other_flip);
312  break;
313  }
314  } //for fc
315  } else {
316  assert(0);
317 
318  // Calculate edge 3D axis;
319  TVector3 v1 = TVector3(edge->vertices()-> begin()->second->key()->GetData());
320  TVector3 v2 = TVector3(edge->vertices()->rbegin()->second->key()->GetData());
321  TVector3 axis = (v2 - v1).Unit();
322 
323  TVector3 n0 = (flip ? 1.0 : -1.0)*facet->GetNormal();
324  TVector3 n02d = (n0 - n0.Dot(axis)*axis).Unit();
325 
326  //TVector3 nn[edge->facets.size()
327  for(unsigned fc=0; fc<edge->facets().size(); fc++) {
328  EicStlFacet *other_facet = edge->facets()[fc];
329 
330  if (/*other_facet == facet ||*/ !other_facet->GetCounter()) continue;
331 
332  bool edge_orientations_match = true;
333 
334  // FIXME: do it better later;
335  for(unsigned ie=0; ie<3; ie++) {
336  const EicStlFacetEdge *other_edge = other_facet->edge(ie);
337  bool other_orientation = ie <= 1;
338 
339  if (other_edge == edge) {
340  //edge_orientations_match = facet->edges[iq].second != other_facet->edges[ie].second;
341  edge_orientations_match = orientation != other_orientation;
342  break;
343  } //if
344  } //for ie
345 
346  {
347  bool other_flip = (flip && edge_orientations_match) ||
348  (!flip && !edge_orientations_match);
349 
350  TVector3 n1 = (other_flip ? 1.0 : -1.0)*other_facet->GetNormal();
351  TVector3 n12d = (n1 - n1.Dot(axis)*axis).Unit();
352 
353  double alfa = acos(n12d.Dot(n02d));
354  printf("alfa: %f\n", (180.0/TMath::Pi())*alfa);
355 
356  TRotation rp, rm; rp.Rotate(alfa, axis); rm.Rotate(-alfa, axis);
357  TVector3 dp = rp * n12d - n02d, dm = rm * n12d - n02d;
358  //printf("%f %f\n", dp.Mag(), dm.Mag());
359 
360  //CoupleFacetToAssembly(other_facet, other_flip);
361  //break;
362  }
363  } //for fc
364  } //if
365  } //for ee
366 } // EicStlMediaGroup::CoupleFacetToAssembly()
367 
368 // ---------------------------------------------------------------------------------------
369 
371 {
372  // First do easy fix: merge vertices, which are "too close" to each other;
373  MergeDegenerateVertices(tolerance);
374 
375  // Calculate facets and build vertex->facet relationships;
376  CalculateFacets();
377  if (easy) return -1;
378 
379  // Then resolve edges and check generic model consistency;
380  AllocateEdges();
381  // Now if any of the edges has odd number of owners, we quit; FIXME: later on
382  // may want to try filling "triangular holes" as well;
383  if (!mEdgeTotalOwnerCountOk) return -1;
384  printf("EicStlMediaGroup::SplitIntoAssemblies() -> ok#1\n");
385 
386  // FIXME: consider more complicated cases later; for now fall out if any edge is
387  // owned by more than two facets;
388  //assert(mEdgeSimpleSharingOk);
389  if (!mEdgeSimpleSharingOk) return -1;
390  printf("EicStlMediaGroup::SplitIntoAssemblies() -> ok#2\n");
391 
392  // The rest is a bit tricky and not necessarily most efficient; but all the algorithms
393  // are (seemingly :-) linear in the number of facets, so why bother; we iteratively
394  // allocate facets into independent assemblies (assuming they do not overlap, so the
395  // surface orientation should be such, that it surrounds a finite volume) in the
396  // following way:
397  //
398  // - take one of the (few) remaining facets, which is further away from the (0,0,0);
399  // - its orientation is "known" from geometric considerations;
400  // - attach recursively its neighbor facets, using simple edge ownership for edges
401  // owned by exactly two facets and geometric considerations for edges owned by
402  // more than two facets (so 4, 6, etc);
403  //
404  // The procedure is repeated until "free" facet list is exhausted;
405  //
406  // One can indeed perform a check on "hole" volumes later; for now assume all
407  // volumes are not overlapping with each other;
408  {
409  // Create and populate <distance,vertex*> multimap;
410  std::multimap<double, EicStlVertex*> distances;
411  for (vEntry::iterator vt=mVertices->begin(); vt != mVertices->end(); vt++) {
412  EicStlVertex *vtx = vt->second;
413 
414  //printf("%d facets at this vertex\n", vtx->facets.size());
415  distances.insert(std::pair<double, EicStlVertex*>(vtx->DistanceToOrigin(), vtx));
416  } //for vt
417  printf("distances size: %d\n", distances.size()); //return 0;
418 
419  // Loop through the remaining vertices with "free" associated facets, until no one left;
420  for( ; distances.size(); ) {
421  //printf("size: %d\n", distances.size()); //return 0;
422 
423  // Yes, I need rbegin() here, so the largest disance from (0,0,0);
424  EicStlVertex *vtx = distances.rbegin()->second;
425  printf("distance: %f\n", distances.rbegin()->first);
426 
427  {
428  // Calculate 3D unit vector from (0,0,0) to this vertex; I guess it can not
429  // happen that this vertex itself is (0,0,0), right?;
430  TVector3 nv = TVector3(vtx->key()->GetData()).Unit();
431 
432  // Loop through all facets associated with this vertex and find the one with
433  // the normal closest to the 90 degrees to <nv> ; NB: at least one facet should be
434  // available (in fact at least three), otherwise vertex should have been removed
435  // from the multimap already;
436  std::multimap<double, EicStlFacet*> diffs;
437  for(std::set<EicStlFacet*>::iterator fc = vtx->facets().begin(); fc != vtx->facets().end(); fc++) {
438  EicStlFacet *facet = *fc;
439 
440  if (!facet->GetCounter()) continue;
441 
442  double scal = fabs(nv.Dot(facet->GetNormal()));
443  //printf("scal: %f\n", scal);
444 
445  diffs.insert(std::pair<double, EicStlFacet*>(scal, facet));
446  } //for fc
447 
448  //printf("Here-0!\n");
449  assert(diffs.size());
450  //printf("There!\n");
451 
452  // Start new assembly;
453  EicStlAssembly *assembly = new EicStlAssembly();
454  mAssemblies.push_back(assembly);
455 
456  {
457  // Yes, I need rbegin() here (the largest scalar product), so the facet
458  // which normal vector is as close to <nv> as possible;
459  EicStlFacet *facet = diffs.rbegin()->second;
460 
461  // And account this facet and all its neighbors in this assembly;
462  //printf("Here-1!\n");
463  CoupleFacetToAssembly(facet, nv.Dot(facet->GetNormal()) < 0.0);
464  //printf("Here-2!\n");
465  }
466  }
467 
468  // Purge remaining facets multimap;
469  for(std::multimap<double, EicStlVertex*>::iterator vt=distances.begin();
470  vt!=distances.end(); ) {
471  EicStlVertex *vtx = vt->second;
472 
473  bool free_facets_exist = false;
474  for(std::set<EicStlFacet*>::iterator fc = vtx->facets().begin(); fc != vtx->facets().end(); fc++) {
475  EicStlFacet *facet = *fc;
476 
477  if (facet->GetCounter()) {
478  free_facets_exist = true;
479  break;
480  } //if
481  } //for fc
482 
483  if (!free_facets_exist) {
484  //printf("size: %d\n", distances.size());
485  distances.erase(vt++);
486  }
487  else
488  vt++;
489  } //for it
490  } //for inf
491  }
492 
493  {
494  printf("%d preliminary assembly(ies) found!\n", mAssemblies.size());
495 
496  for(unsigned ass=0; ass<mAssemblies.size(); ass++) {
497  EicStlAssembly *assembly = mAssemblies[ass];
498 
499  printf("#%02d: %5d facet(s)\n", ass, assembly->facets().size());
500  } //for ass
501  }
502 
503  return 0;
504 } // EicStlMediaGroup::SplitIntoAssemblies()
505 
506 // =======================================================================================