EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicCadFile.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicCadFile.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/03/07; revamped in Oct'2017;
3 //
4 // EicRoot CAD files manipulation routines; main C++ file; a major clean up
5 // occured on 2017/10/05; in particular commented out XCAF stuff removed
6 // (see older versions if ever want to recover it);
7 //
8 // NB: one may want to limit the main loop in EicCadFile::HandleThisSolid()
9 // to only plane and cylindrical cutting surfaces; these days one can also
10 // try out McCAD libraries (or implement more sophisticated logic similar to
11 // theirs, without breaking the existing EicCadFile code flow);
12 //
13 
14 #include <assert.h>
15 
16 // NB: certain functionality (.stl, .mphtxt import ) is available without
17 // OpenCascade libraries; so make things configurable;
18 #ifdef _OPENCASCADE_
19 #include <STEPCAFControl_Reader.hxx>
20 #include <IGESCAFControl_Reader.hxx>
21 #include <TopExp_Explorer.hxx>
22 #include <XSControl_WorkSession.hxx>
23 #include <XSControl_TransferReader.hxx>
24 #include <Interface_InterfaceModel.hxx>
25 #include <StlAPI_Writer.hxx>
26 #include <Transfer_TransientProcess.hxx>
27 #include <TransferBRep.hxx>
28 
29 #include <TopoDS_Shape.hxx>
30 #include <TopoDS_Solid.hxx>
31 
32 #include <BRepAlgoAPI_Fuse.hxx>
33 #include <BRepAlgoAPI_Cut.hxx>
34 #include <BRepAlgoAPI_Common.hxx>
35 
36 #include <BRepPrimAPI_MakeBox.hxx>
37 #include <BRepPrimAPI_MakeCylinder.hxx>
38 #include <BRepPrimAPI_MakeSphere.hxx>
39 #include <BRepPrimAPI_MakeTorus.hxx>
40 #include <BRepPrimAPI_MakeCone.hxx>
41 #include <BRepPrimAPI_MakeHalfSpace.hxx>
42 
43 #include <Bnd_Box.hxx>
44 #include <BRepBndLib.hxx>
45 
46 #include <Geom_CylindricalSurface.hxx>
47 #include <Geom_ToroidalSurface.hxx>
48 #include <Geom_SphericalSurface.hxx>
49 #include <Geom_ConicalSurface.hxx>
50 #include <Geom_Plane.hxx>
51 
52 #include <BRepBuilderAPI_MakeFace.hxx>
53 #include <BRepBuilderAPI_Transform.hxx>
54 
55 #include <BRepBuilderAPI_MakeSolid.hxx>
56 #include <BRepOffsetAPI_Sewing.hxx>
57 #include <BRepBuilderAPI_Sewing.hxx>
58 #include <Geom_Curve.hxx>
59 
60 #include <gp_Pln.hxx>
61 #include <gp_Torus.hxx>
62 #include <gp_Cone.hxx>
63 #include <gp_Sphere.hxx>
64 #include <gp_Cylinder.hxx>
65 #include <gp_Trsf.hxx>
66 #endif
67 
68 #include <TColor.h>
69 #include <TGeoSphere.h>
70 #include <TGeoTorus.h>
71 #include <TGeoCone.h>
72 #include <TGeoTube.h>
73 #include <TGeoArb8.h>
74 #include <TGeoHalfSpace.h>
75 #include <TGeoCompositeShape.h>
76 
77 #include <EicCompositeShape.h>
78 #include <EicCadFile.h>
79 #include <EicStlFactory.h>
80 
81 // Optional StepCode support;
82 #ifdef _STEPCODE_
83 #include <EicStepMaterialReader.h>
84 #endif
85 
86 // Optional Elmer include files;
87 #ifdef _ELMER_
88 #include "src/meshtype.h"
89 #include "plugins/egmain.h"
90 #endif
91 
92 #define SQR(x) ((x)*(x))
93 
94 // Make them configurable later;
95 #define _ANGULAR_TOLERANCE_ (1E-10)
96 #define _SPATIAL_TOLERANCE_ (1E-10)
97 
98 // =======================================================================================
99 
100 bool EicStlKeyCompare(const EicStlKey *lh, const EicStlKey *rh) {
101  return memcmp(lh->GetData(), rh->GetData(), rh->GetDim()*sizeof(/*float*/double)) < 0;
102 } // EicStlKeyCompare()
103 
104 // ---------------------------------------------------------------------------------------
105 
106 bool EicStlKeyEqual(const EicStlKey *lh, const EicStlKey *rh) {
107  return memcmp(lh->GetData(), rh->GetData(), rh->GetDim()*sizeof(/*float*/double)) == 0;
108 } // EicStlKeyEqual()
109 
110 // =======================================================================================
111 
112 #ifdef _OPENCASCADE_
113 bool EicCadShapeEqual(const std::pair<unsigned, EicOpenCascadeShape> &lh,
114  const std::pair<unsigned, EicOpenCascadeShape> &rh)
115 {
116  // No comparisons between faces of different topology;
117  if (lh.second.sType != rh.second.sType) return false;
118 
119  // Half-space differs from other shapes since it can be defined in two equivalent ways
120  // (differ in cut/common and normal sign); so need to check on that;
121  if (lh.second.sType == EicOpenCascadeShape::_OCC_PLANE_)
122  {
123  const gp_Pln *pll = (gp_Pln *)lh.second.object, *plr = (gp_Pln *)rh.second.object;
124 
125  if (pll->Axis().Direction().IsParallel(plr->Axis().Direction(), _ANGULAR_TOLERANCE_)) {
126  if (pll->Distance(plr->Location()) > _SPATIAL_TOLERANCE_) return false;
127 
128  // Ok, do it better later; should not happen;
129  assert(lh.first == rh.first);
130 
131  return true;
132  } else {
133  // Try anti-parallel option; gp_Dir does not have easy reflection methods, sorry;
134  gp_Dir anti(-plr->Axis().Direction().X(),
135  -plr->Axis().Direction().Y(),
136  -plr->Axis().Direction().Z());
137 
138  if (pll->Axis().Direction().IsParallel(anti, _ANGULAR_TOLERANCE_))
139  {
140  if (pll->Distance(plr->Location()) > _SPATIAL_TOLERANCE_) return false;
141 
142  // Ok, do it better later; should not happen;
143  assert(lh.first != rh.first);
144 
145  return true;
146  }
147  else
148  return false;
149  } //if
150  }
151  else
152  {
153  switch (lh.second.sType) {
154  case EicOpenCascadeShape::_OCC_SPHERE_:
155  {
156  // Allow for some tolerance later, please!;
157  const gp_Sphere *spl = (gp_Sphere *)lh.second.object, *spr = (gp_Sphere *)rh.second.object;
158 
159  if (fabs(spl->Radius() - spr->Radius()) > _SPATIAL_TOLERANCE_) return false;
160 
161  {
162  double dc = sqrt(SQR(spl->Location().X() - spr->Location().X()) +
163  SQR(spl->Location().Y() - spr->Location().Y()) +
164  SQR(spl->Location().Z() - spr->Location().Z()));
165 
166  if (dc > _SPATIAL_TOLERANCE_) return false;
167  }
168  break;
169  }
170  case EicOpenCascadeShape::_OCC_CYLINDER_:
171  {
172  const gp_Cylinder *cyl = (gp_Cylinder *)lh.second.object, *cyr = (gp_Cylinder *)rh.second.object;
173 
174  // Do not need to check length (assume cylinders are "infinitely" long);
175  if (!cyl->Axis().Direction().IsParallel(cyr->Axis().Direction(), _ANGULAR_TOLERANCE_))
176  return false;
177 
178  // Radius match;
179  if (fabs(cyl->Radius() - cyr->Radius()) > _SPATIAL_TOLERANCE_) return false;
180 
181  {
182  gp_XYZ diff(cyl->Location().X() - cyr->Location().X(),
183  cyl->Location().Y() - cyr->Location().Y(),
184  cyl->Location().Z() - cyr->Location().Z());
185 
186  // Check transverse component only (it can be, that two origins are sitting
187  // on the same axis);
188  gp_XYZ axis(cyl->Axis().Direction().X(),
189  cyl->Axis().Direction().Y(),
190  cyl->Axis().Direction().Z());
191  double pro = diff.Dot(axis);
192  gp_XYZ vpro = pro*axis, vnorm = diff - vpro;
193 
194  if (vnorm.Modulus() > _SPATIAL_TOLERANCE_) return false;
195  }
196  break;
197  }
198  case EicOpenCascadeShape::_OCC_TORUS_:
199  {
200  const gp_Torus *tol = (gp_Torus *)lh.second.object, *tor = (gp_Torus *)rh.second.object;
201 
202  if (fabs(tol->MajorRadius() - tor->MajorRadius()) > _SPATIAL_TOLERANCE_) return false;
203  if (fabs(tol->MinorRadius() - tor->MinorRadius()) > _SPATIAL_TOLERANCE_) return false;
204 
205  if (!tol->Axis().Direction().IsParallel(tor->Axis().Direction(), _ANGULAR_TOLERANCE_))
206  return false;
207 
208  {
209  double dc = sqrt(SQR(tol->Location().X() - tor->Location().X()) +
210  SQR(tol->Location().Y() - tor->Location().Y()) +
211  SQR(tol->Location().Z() - tor->Location().Z()));
212 
213  if (dc > _SPATIAL_TOLERANCE_) return false;
214  }
215  break;
216  }
217  case EicOpenCascadeShape::_OCC_CONE_:
218  {
219  const gp_Cone *col = (gp_Cone *)lh.second.object, *cor = (gp_Cone *)rh.second.object;
220 
221  // Axis direction;
222  if (!col->Axis().Direction().IsParallel(cor->Axis().Direction(), _ANGULAR_TOLERANCE_))
223  return false;
224 
225  // Opening angle;
226  if (fabs(col->SemiAngle() - cor->SemiAngle()) > _ANGULAR_TOLERANCE_) return false;
227 
228  // Apex;
229  {
230  double dc = sqrt(SQR(col->Location().X() - cor->Location().X()) +
231  SQR(col->Location().Y() - cor->Location().Y()) +
232  SQR(col->Location().Z() - cor->Location().Z()));
233 
234  if (dc > _SPATIAL_TOLERANCE_) return false;
235  }
236 
237  break;
238  }
239  default:
240  assert(0);
241  } //case
242 
243  // Ok, do it better later; should not happen;
244  assert(lh.first == rh.first);
245 
246  return true;
247  } //if
248 } // EicCadShapeEqual()
249 #endif
250 // =======================================================================================
251 
253 {
254  mStlVolumeCounter = 0;
255  mConfig = new EicCadFileConfig();
256 #ifdef _OPENCASCADE_
257  boundarySphereCenter = NULL;
258  boundarySphereRadius = 0.0;
259 #endif
260 
261  // FIXME: return back to some reasonable defaults;
263  mStlSolidCreationAllowed = false;
264 
265 #ifdef _ELMER_
266  mElmerMesh = NULL;
267 #endif
268 
269  // Set whatever default;
270  mFillColor = _COLOR_DEFAULT_;//kBlue;
271  mSwapXY = mKillerFlag = false; //mWireframeMode = false;
272 } // EicCadFile::ResetVariables()
273 
274 // ---------------------------------------------------------------------------------------
275 
276 EicCadFile::EicCadFile(const char *Name, char *geometryName, char *mediaName, int color) :
277  EicDummyDetector(Name, geometryName), mCreateStlMirrorCopyXY(false), mCreateStlMirrorCopyXZ(false)
278 {
279  ResetVariables();
280  mFillColor = color;
281 
283 
284  //mediaHub = new EicMediaHub(mediaName);
285  mConfig->CreateMediaHub(mediaName);
286 } // EicCadFile::EicCadFile()
287 
288 // ---------------------------------------------------------------------------------------
289 
290 #ifdef _OPENCASCADE_
291 Bool_t EicCadFile::elementaryFaceType(TopoDS_Face &face, FaceType fType)
292 {
293  Handle(Geom_Surface) SS = BRep_Tool::Surface(face);
294 
295  if (SS->IsKind(STANDARD_TYPE(Geom_Plane)) && fType != FaceTypeCurved) return kTRUE;
296 
297  if ((SS->IsKind(STANDARD_TYPE(Geom_CylindricalSurface))
298  || SS->IsKind(STANDARD_TYPE(Geom_ConicalSurface))
299  || SS->IsKind(STANDARD_TYPE(Geom_ToroidalSurface))
300  || SS->IsKind(STANDARD_TYPE(Geom_SphericalSurface))
301  ) &&
302  fType != FaceTypeFlat)
303  return kTRUE;
304 
305  return kFALSE;
306 } // EicCadFile::elementaryFaceType()
307 
308 // ---------------------------------------------------------------------------------------
309 
310 //#include <ShapeFix_Shape.hxx>
311 
312 Bool_t EicCadFile::splitSolidByInfiniteFace(const TopoDS_Shape &solid, const TopoDS_Face &face,
313  EicOpenCascadeShape &cuttingShape,
314  std::vector<TopoDS_Shape> &commonSolids,
315  std::vector<TopoDS_Shape> &cutSolids)
316 {
317  Handle(Geom_Surface) SS = BRep_Tool::Surface(face);
318 
319  if (SS->IsKind(STANDARD_TYPE(Geom_Plane))) {
320  Handle(Geom_Plane) es = Handle(Geom_Plane)::DownCast(SS);
321 
322  // Arrange an infinite plane -> convert to face -> make an infinite half-space;
323  //printf("Here-1!\n");
324  TopoDS_Face aFace = BRepBuilderAPI_MakeFace(es->Pln());
325  gp_Dir dir = es->Pln().Axis().Direction();
326  // Whatever non-zero number;
327  double t = 0.1;
328  //double t = -0.0001;
329  // Well, put "-" sign here, because dir[] is an outer normal in ROOT halfspace volume;
330  gp_Pnt x0(es->Location()), pt(x0.X() - t*dir.X(), x0.Y() - t*dir.Y(), x0.Z() - t*dir.Z());
331 
332  //printf("Here-2!\n");
333  cuttingShape.solid = new TopoDS_Shape(BRepPrimAPI_MakeHalfSpace(aFace, pt).Solid());
334 
335  cuttingShape.sType = EicOpenCascadeShape::_OCC_PLANE_;
336  //cuttingShape.object = new gp_Pln(es->Pln());
337  cuttingShape.object = new gp_Pln(x0, dir);
338  //printf("Here-3!\n");
339  assert(dir.IsEqual(gp_Pln(x0, dir).Axis().Direction(), _ANGULAR_TOLERANCE_));
340  }
341  else
342  if (SS->IsKind(STANDARD_TYPE(Geom_CylindricalSurface))) {
343  Handle(Geom_CylindricalSurface) es = Handle(Geom_CylindricalSurface)::DownCast(SS);
344 
345  gp_Cylinder gcylinder = es->Cylinder();
346  double r = gcylinder.Radius();
347 
348  gp_Ax1 ax1 = gcylinder.Axis();
349  gp_Dir dir = ax1.Direction();
350  gp_Ax2 ax2 = gcylinder.Position().Ax2();
351  gp_Pnt x0 = gcylinder.Location();
352  double dist_to_sphere = es->Location().Distance(*boundarySphereCenter);
353  double safe_dimension = dist_to_sphere + boundarySphereRadius;
354  double t = safe_dimension;
355  gp_Pnt x1(x0.X() - t*dir.X(), x0.Y()- t*dir.Y(), x0.Z()- t*dir.Z());
356  ax2.SetLocation(x1);
357  ax2.SetDirection(dir);
358  cuttingShape.solid =
359  new TopoDS_Shape(BRepPrimAPI_MakeCylinder(ax2, r, 2 * safe_dimension).Solid());
360 
361  cuttingShape.sType = EicOpenCascadeShape::_OCC_CYLINDER_;
362  cuttingShape.object = new gp_Cylinder(gp_Ax3(ax2), r);
363  cuttingShape.dimension = safe_dimension;
364  }
365  else
366  if (SS->IsKind(STANDARD_TYPE(Geom_SphericalSurface))) {
367  Handle(Geom_SphericalSurface) es = Handle(Geom_SphericalSurface)::DownCast(SS);
368 
369  gp_Sphere sphere = es->Sphere();
370 
371  // Just need exactly this sphere, please;
372  cuttingShape.sType = EicOpenCascadeShape::_OCC_SPHERE_;
373  cuttingShape.object = new gp_Sphere(es->Sphere());
374  cuttingShape.solid =
375  new TopoDS_Shape(BRepPrimAPI_MakeSphere(sphere.Location(), sphere.Radius()).Solid());
376  }
377  else
378  if (SS->IsKind(STANDARD_TYPE(Geom_ToroidalSurface))) {
379  Handle(Geom_ToroidalSurface) es = Handle(Geom_ToroidalSurface)::DownCast(SS);
380 
381  gp_Torus torus = es->Torus();
382 
383  // Just need exactly this torus, please;
384  cuttingShape.sType = EicOpenCascadeShape::_OCC_TORUS_;
385  cuttingShape.object = new gp_Torus(es->Torus());
386  cuttingShape.solid =
387  new TopoDS_Shape(BRepPrimAPI_MakeTorus(torus.Position().Ax2(), torus.MajorRadius(),
388  torus.MinorRadius()).Solid());
389  }
390  else
391  if (SS->IsKind(STANDARD_TYPE(Geom_ConicalSurface))) {
392  Handle(Geom_ConicalSurface) es = Handle(Geom_ConicalSurface)::DownCast(SS);
393 
394  gp_Cone cone = es->Cone();
395  gp_Pnt apex = cone.Apex();
396  gp_Ax1 axis = cone.Axis();
397  gp_Ax2 ax2(apex, axis.Direction());
398 
399  double dist_to_sphere = apex.Distance(*boundarySphereCenter);
400  // This should suffice in all cases;
401  double safe_dimension = dist_to_sphere + boundarySphereRadius;
402  double semiAngle = cone.SemiAngle(), r0 = 0.0, r1 = safe_dimension*tan(semiAngle);
403 
404  cuttingShape.sType = EicOpenCascadeShape::_OCC_CONE_;
405  cuttingShape.object = new gp_Cone(gp_Ax3(ax2), semiAngle, r0);
406  cuttingShape.dimension = safe_dimension;
407  cuttingShape.solid =
408  new TopoDS_Shape(BRepPrimAPI_MakeCone(ax2, r0, r1, safe_dimension).Solid());
409  }
410  else
411  assert(0);
412 
413  {
414  //ShapeFix_Shape sfix(solid);
415  //sfix.Perform();
416 
417  //printf("Here-4!\n");
418  TopoDS_Shape commonHalf = BRepAlgoAPI_Common(solid, *cuttingShape.solid);
419  //TopoDS_Shape commonHalf = BRepAlgoAPI_Common(sfix.Shape(), *cuttingShape.solid);
420  //printf("Here-5!\n");
421  for (TopExp_Explorer itq(commonHalf,TopAbs_SOLID); itq.More(); itq.Next())
422  commonSolids.push_back(itq.Current());
423 
424  //printf("Here-6!\n");
425  TopoDS_Shape cutHalf = BRepAlgoAPI_Cut(solid, *cuttingShape.solid);
426  //printf("Here-7!\n");
427  for (TopExp_Explorer itq(cutHalf,TopAbs_SOLID); itq.More(); itq.Next())
428  cutSolids.push_back(itq.Current());
429 
430  return (commonSolids.size() + cutSolids.size() >= 2);
431  }
432 } // EicCadFile::splitSolidByInfiniteFace()
433 
434 // ---------------------------------------------------------------------------------------
435 
436 void EicCadFile::DumpAsStlSolid(const TopoDS_Shape &solid, TGeoMedium *medium)
437 {
438  char buffer[128], vname[128];
439  snprintf(vname, 128-1, "%s-%06d", dname->Name().Data(), mStlVolumeCounter);
440  snprintf(buffer, 128-1, "/tmp/%05d-%06d-step.stl", getpid(), mStlVolumeCounter++);
441 
442  {
443  StlAPI_Writer writer;
444 
445  writer.ASCIIMode() = true;
446  //printf("GetStlQualityCoefficient(): %f\n", config()->GetStlQualityCoefficient());
447  printf("Here!\n");
448 #if _TODAY_
449  writer.SetCoefficient(config()->GetStlQualityCoefficient());
450 #endif
451  writer.Write(solid, buffer);
452  //printf("ret: %d\n", ret);
453  }
454 
455  {
456  // 'false': yes, here I should ignore units and scaling given in mConfig because
457  // they were taken into account when creating the STEP model;
458  EicStlFactory stl_factory(vname, buffer, mConfig, false);
459 
460  // FIXME: (0,0,0) or mExtraStlTranslation here?;
461  stl_factory._ConstructGeometry(mCave, TVector3());
462  }
463 } // EicCadFile::DumpAsStlSolid()
464 
465 // ---------------------------------------------------------------------------------------
466 
467 TGeoCombiTrans *EicCadFile::Ax3ToCombiTrans(char *name, const gp_Ax3 &ax3, double offset)
468 {
469  gp_Pnt x0 = ax3.Location();
470  gp_Dir xDir = ax3.XDirection(), yDir = ax3.YDirection(), zDir = ax3.Axis().Direction();
471 
472  double data[9] = {xDir.X(), yDir.X(), zDir.X(),
473  xDir.Y(), yDir.Y(), zDir.Y(),
474  xDir.Z(), yDir.Z(), zDir.Z()};
475  TGeoRotation *grr = new TGeoRotation();
476  grr->SetMatrix(data);
477 
478  return new TGeoCombiTrans(name,
479  x0.X() + offset * zDir.X(),
480  x0.Y() + offset * zDir.Y(),
481  x0.Z() + offset * zDir.Z(), grr);
482 } // EicCadFile::Ax3ToCombiTrans()
483 
484 // ---------------------------------------------------------------------------------------
485 
486 void EicCadFile::DumpAsRootSolid(const TopoDS_Shape &solid,
487  std::vector< std::pair<unsigned, EicOpenCascadeShape> > &facets,
488  TGeoMedium *medium, double *color)
489 {
490  TString cmd(":");
491 
492  {
493  static unsigned counter;
494  char vname[128], tname[128];
495 
496  //printf("counter=%d\n", counter);
497 
498  snprintf(vname, 128-1, "VS%04d", counter);
499  snprintf(tname, 128-1, "TS%04d", counter++);
500 
501  cmd = vname + cmd + tname;
502 
503  // Define big enough ROOT sphere;
504  TGeoSphere *shell = new TGeoSphere(vname, 0.0, boundarySphereRadius + 1E-10*counter);
505  TGeoCombiTrans *ts = new TGeoCombiTrans(tname, boundarySphereCenter->X(),
506  boundarySphereCenter->Y(),
507  boundarySphereCenter->Z(), 0);
508  ts->RegisterYourself();
509  }
510 
511  for(unsigned fc=0; fc<facets.size(); fc++) {
512  EicOpenCascadeShape &cuttingShape = facets[fc].second;
513 
514  {
515  static unsigned counter;
516  char vname[128], tname[128];
517 
518  snprintf(vname, 128-1, "V%04d", counter);
519  snprintf(tname, 128-1, "T%04d", counter++);
520 
521  TGeoCombiTrans *ts = 0;
522  switch (cuttingShape.sType) {
523  case EicOpenCascadeShape::_OCC_PLANE_:
524  {
525  const gp_Pln *plane = (gp_Pln *)cuttingShape.object;
526 
527  double x0[3] = {plane->Location().X(), plane->Location().Y(), plane->Location().Z()};
528  double n0[3] = {plane->Axis().Direction().X(), plane->Axis().Direction().Y(), plane->Axis().Direction().Z()};
529 
530  printf("PL (%s) -> x0[]: %7.2f %7.2f %7.2f; n0[]: %7.2f %7.2f %7.2f\n",
531  facets[fc].first ? "-" : "*", x0[0], x0[1], x0[2], n0[0], n0[1], n0[2]);
532 
533  TGeoHalfSpace *shell = new TGeoHalfSpace(vname, x0, n0);
534  break;
535  }
536  case EicOpenCascadeShape::_OCC_SPHERE_:
537  {
538  gp_Sphere *sphere = (gp_Sphere *)cuttingShape.object;
539 
540  TGeoSphere *shell = new TGeoSphere(vname, 0.0, sphere->Radius());
541  ts = new TGeoCombiTrans(tname, sphere->Location().X(),
542  sphere->Location().Y(),
543  sphere->Location().Z(), 0);
544  printf("SP (%s) x0[]: %f %f %f, r = %f\n", facets[fc].first ? "-" : "*",
545  sphere->Location().X(),
546  sphere->Location().Y(), sphere->Location().Z(), sphere->Radius());
547  break;
548  }
549  case EicOpenCascadeShape::_OCC_CYLINDER_:
550  {
551  gp_Cylinder *cylinder = (gp_Cylinder *)cuttingShape.object;
552 
553  TGeoTube *shell = new TGeoTube(vname, 0.0, cylinder->Radius(), cuttingShape.dimension);
554 
555  ts = Ax3ToCombiTrans(tname, cylinder->Position(), cuttingShape.dimension);
556 
557  printf("CY (%s) x0[]: %f %f %f, r = %f\n", facets[fc].first ? "-" : "*",
558  cylinder->Location().X(),
559  cylinder->Location().Y(), cylinder->Location().Z(), cylinder->Radius());
560  break;
561  }
562  case EicOpenCascadeShape::_OCC_CONE_:
563  {
564  gp_Cone *cone = (gp_Cone *)cuttingShape.object;
565 
566  TGeoCone *shell = new TGeoCone(vname, cuttingShape.dimension/2.,
567  0.0, 0.0,
568  0.0, cuttingShape.dimension*tan(cone->SemiAngle()));
569 
570  ts = Ax3ToCombiTrans(tname, cone->Position(), cuttingShape.dimension/2.);
571 
572  printf("CO (%s) x0[]: %f %f %f\n", facets[fc].first ? "-" : "*",
573  cone->Location().X(), cone->Location().Y(), cone->Location().Z());
574  break;
575  }
576  case EicOpenCascadeShape::_OCC_TORUS_:
577  {
578  gp_Torus *torus = (gp_Torus *)cuttingShape.object;
579 
580  TGeoTorus *shell = new TGeoTorus(vname, torus->MajorRadius(),
581  0.0, torus->MinorRadius(), 0.0, 360.0);
582 
583  ts = Ax3ToCombiTrans(tname, torus->Position(), 0.0);
584 
585  printf("TO (%s) x0[]: %f %f %f, rMa = %f, rMi = %f\n", facets[fc].first ? "-" : "*",
586  torus->Location().X(),
587  torus->Location().Y(), torus->Location().Z(),
588  torus->MajorRadius(), torus->MinorRadius());
589  break;
590  }
591  default:
592  assert(0);
593  } //switch
594 
595  if (ts) ts->RegisterYourself();
596 
597  cmd = "(" + cmd + ")" + (facets[fc].first ? "-" : "*") + vname + (ts ? TString(":") + tname : "");
598  }
599  _skip_it:;
600  } //for fc
601 
602  printf("%s\n", cmd.Data());
603 
604  TopoDS_Shape myShape = solid;
605 #if _OLD_
606  BRepPrimAPI_MakeSphere(*boundarySphereCenter, boundarySphereRadius).Shape();
607 
608  for(unsigned fc=0; fc<facets.size(); fc++) {
609  EicOpenCascadeShape &cuttingShape = facets[fc].second;
610 
611  if (facets[fc].first)
612  myShape = BRepAlgoAPI_Cut (myShape, *cuttingShape.solid);
613  else
614  myShape = BRepAlgoAPI_Common(myShape, *cuttingShape.solid);
615  } //for fc
616 #endif
617 
618  {
619  static unsigned ccounter;
620  char cname[128];
621 
622  snprintf(cname, 128-1, "C%04d", ccounter++);
623 
624  //TGeoCompositeShape *comp = new TGeoCompositeShape(cname, cmd.Data());
625  //TGeoBBox *comp = new TGeoBBox(cname, 1., 1., 2.);
626  EicCompositeShape *comp = new EicCompositeShape(cname, cmd.Data(), &myShape);
627  comp->LocalFillBuffer3D(config()->GetStlQualityCoefficient());
628  TGeoVolume *vcomp = new TGeoVolume(cname, comp, medium);
629 #if 1
630  {
631  static unsigned current_color_id = 1000;
632  static std::vector<TColor*> colors;
633 
634  int cid = -1;
635  for(unsigned c=0; c<colors.size(); c++)
636  {
637  TColor *clr = colors[c];
638 
639  if (clr->GetRed() == float(color[0]) &&
640  clr->GetGreen() == float(color[1]) &&
641  clr->GetBlue() == float(color[2]))
642  {
643  cid = clr->GetNumber();
644  break;
645  } //if
646  } //for c
647 
648  if (cid == -1)
649  {
650  TColor *clr = new TColor(++current_color_id, color[0], color[1], color[2]);
651  colors.push_back(clr);
652  printf(" @C@ %d, %f, %f, %f\n", current_color_id,
653  float(color[0]), float(color[1]), float(color[2]));
654 
655  cid = current_color_id;
656  } //if
657 
658  //EicColorExtension *ext = new EicColorExtension();
659  //ext->r = 1.11;
660 
661  //static unsigned flag = 0;
662  //unsigned id = 1115;
663 #if 0
664  if (!flag)
665  {
666  TColor *color = new TColor(id, 1., 0., 1.);
667  //color->RegisterYourself();
668  flag = 1;
669  }
670 #endif
671  vcomp->SetLineColor(cid);
672  vcomp->SetFillColor(cid);
673  //vcomp->SetUserExtension(ext);
674  }
675 #endif
676  mCave->AddNode(vcomp, 0, new TGeoCombiTrans(0, 0, 0, 0));
677  vcomp->RegisterYourself();
678  }
679 } // EicCadFile::DumpAsRootSolid()
680 
681 // ---------------------------------------------------------------------------------------
682 
683 #include <Geom_BSplineCurve.hxx>
684 #include <Geom_Circle.hxx>
685 
686 void EicCadFile::HandleThisSolid(const TopoDS_Shape &solid, TGeoMedium *medium, double *color)
687 {
688  // See whether I can split this solid into a set of more basic ones;
689  // loop through all Geom_Plane faces and try to cut a solid along this plane;
690  printf("EicCadFile::HandleThisSolid() ...\n");
691 
692  std::vector< std::pair<unsigned, EicOpenCascadeShape> > facets;
693 
694  unsigned hasCurvedFaces = 0;
695 
696  // Want them in this sequence; not dramatically efficient; optimize later;
697  const Standard_Transient *shapeIds[] = {
698  STANDARD_TYPE(Geom_Plane),
699  STANDARD_TYPE(Geom_CylindricalSurface),
700  STANDARD_TYPE(Geom_SphericalSurface),
701  STANDARD_TYPE(Geom_ToroidalSurface),
702  STANDARD_TYPE(Geom_ConicalSurface)};
703 
704  // For now limit myself by only plane and cylindrical surface cuts;
705  //for(unsigned pass=1; pass<2; pass++) {
706  for(unsigned pass=0; pass<(sizeof(shapeIds)/sizeof(shapeIds[0])); pass++) {
707  for (TopExp_Explorer itg(solid,TopAbs_FACE); itg.More(); itg.Next()) {
708  TopoDS_Face &face = (TopoDS_Face&)itg.Current();
709 
710  //if (!elementaryFaceType(face)) hasComplexFaces = 1;
711 
712  Handle(Geom_Surface) SS = BRep_Tool::Surface(face);
713  cout << " " << SS->DynamicType() << endl;
714 
715  if (SS->IsKind((const Standard_Type*)shapeIds[pass])) {
716  EicOpenCascadeShape cuttingShape;
717  std::vector<TopoDS_Shape> commonSolids, cutSolids;
718 
719  assert(elementaryFaceType(face));
720 
721  printf("Splitting ...\n");
722  if (splitSolidByInfiniteFace(solid, face, cuttingShape,
723  commonSolids, cutSolids)) {
724  printf(" Will now handle %d (common) & %d (cut) sub-solids ...\n",
725  commonSolids.size(), cutSolids.size());
726 #if 1//_TODAY_
727  for(unsigned sh=0; sh<commonSolids.size(); sh++)
728  HandleThisSolid(commonSolids[sh], medium, color);
729 
730  for(unsigned sh=0; sh<cutSolids.size(); sh++)
731  HandleThisSolid(cutSolids[sh], medium, color);
732 
733  return;
734 #endif
735  } else {
736  assert(commonSolids.size() + cutSolids.size() == 1);
737 
738 #if 1//_TODAY_
739  // Solids, which have plane faces only, will go directly to STL as well;
740  // may want to optimize at least for BOX shapes later;
741  if (!SS->IsKind(STANDARD_TYPE(Geom_Plane))) hasCurvedFaces = 1;
742 
743  // Loop through already defined shapes and check that there is no
744  // such one is already present; NB: I guess ordering here does not
745  // make sense -> vector suffices;
746  {
747  unsigned exists = 0;
748  std::pair<unsigned, EicOpenCascadeShape> qPair(cutSolids.size(), cuttingShape);
749 
750  for(unsigned fc=0; fc<facets.size(); fc++)
751  if (EicCadShapeEqual(qPair, facets[fc])) {
752  exists = 1;
753  break;
754  } //for fc..if
755 
756  if (!exists) facets.push_back(qPair);
757  }
758 #endif
759  } //if
760  } //if
761  } //for itg
762  } //for pass
763 
764 #if 1//_TODAY_
765  // Ok, solid can not be split any longer; see whether it consists of "basic" faces
766  // only (plane, sphere, cone, cylinder); in this case pass it through the logical
767  // decomposition filter (and represent *exactly* in ROOT equivalents); otherwise
768  // pass it through STL modeler (and represent *approximately* as a collection of
769  // tetrahedra;
770  {
771  unsigned hasComplexFaces = 0;
772 
773  for (TopExp_Explorer itg(solid,TopAbs_FACE); itg.More(); itg.Next()) {
774  TopoDS_Face &face = (TopoDS_Face&)itg.Current();
775 
776  //if (!elementaryFaceType(face))
777  {
778  //printf(" One more complex face: \n");
779 #if 1//_DEBUG_
780  Handle(Geom_Surface) SS = BRep_Tool::Surface(face);
781  cout << " " << SS->DynamicType() << endl;
782  if (SS->IsKind(STANDARD_TYPE(Geom_Plane))) {
783 
784  } //if
785 
786  for (TopExp_Explorer ith(itg.Current(),TopAbs_EDGE); ith.More(); ith.Next()) {
787  TopoDS_Edge &edge = (TopoDS_Edge&)ith.Current();
788  double first, last;
789  Handle(Geom_Curve) SC = BRep_Tool::Curve(edge, first, last);
790 
791  //printf(" One more edge: ");
792  cout << " --> " << SC->DynamicType() << endl;
793  if (SC->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
794  Handle(Geom_BSplineCurve) spline = Handle(Geom_BSplineCurve)::DownCast(SC);
795 
796  gp_Pnt start = spline->StartPoint(), end = spline->EndPoint();
797 
798  printf("%d %d\n", spline->NbKnots(), spline->NbPoles());
799  printf("%d %d\n", spline->Degree(), spline->MaxDegree());
800  printf("%f %f %f -> %f %f %f\n", start.X(), start.Y(), start.Z(),
801  end.X(), end.Y(), end.Z());
802  } //if
803 #if 1
804  if (SC->IsKind(STANDARD_TYPE(Geom_Circle))) {
805  Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(SC);
806  gp_Pnt center = circle->Location();
807 
808  printf("%f %f %f; %f\n", center.X(), center.Y(), center.Z(), circle->Radius());
809  } //if
810 #endif
811  } //for ith
812 #endif
813  if (!elementaryFaceType(face)) hasComplexFaces = 1;
814  } //if
815  } //for itg
816 
817  if (hasComplexFaces /*|| !hasCurvedFaces*/) {
818  printf("Complex face found -> dump as STL!\n");
819  assert(mStlSolidCreationAllowed);
820  DumpAsStlSolid(solid, medium);
821  return;
822  } //if
823  }
824 
825  // Ok, now the tricky part comes; represent this solid as an overlap of
826  // simple basic shapes;
828  printf("Can decompose into basic ROOT shapes!\n");
829  DumpAsRootSolid(solid, facets, medium, color);
830  } else {
831  assert(mStlSolidCreationAllowed);
832  DumpAsStlSolid(solid, medium);
833  } //if
834 #endif
835 } // EicCadFile::HandleThisSolid()
836 
837 // ---------------------------------------------------------------------------------------
838 
839 void EicCadFile::HandleThisSolidWrapper(const TopoDS_Shape &solid, TGeoMedium *medium, double *color)
840 {
841  // This should be determined once (for the "main" shape) -> optimize later;
842  double xMin, yMin, zMin, xMax, yMax, zMax;
843  Bnd_Box Boundary;
844  BRepBndLib::Add(solid, Boundary);
845 
846  Boundary.Get(xMin, yMin, zMin, xMax, yMax, zMax);
847 
848  if (boundarySphereCenter) delete boundarySphereCenter;
849 
850  // Be lazy; determine bounding sphere;
851  boundarySphereCenter = new gp_Pnt((xMin+xMax)/2., (yMin+yMax)/2., (zMin+zMax)/2.);
852  boundarySphereRadius = sqrt(SQR(xMax-xMin) + SQR(yMax-yMin) + SQR(zMax-zMin))/2.;
853 
854  // FIXME: was the beginning of this routine necessary in case shape goes directly to STL factory?;
856  HandleThisSolid(solid, medium, color);
857  else
858  DumpAsStlSolid(solid, medium);
859 } // EicCadFile::HandleThisSolidWrapper()
860 
861 // ---------------------------------------------------------------------------------------
862 
863 //
864 // FIXME: it looks like units will be default here, so [mm] (?);
865 //
866 
867 void EicCadFile::ConstructDummyStepGeometry()
868 {
869  gp_Pnt p0(-1,-1,-2), p1(1,1,2), p2(1, 0, 0), p3(0,0,-2);
870  //gp_Pnt p0(-1,-1,2), p1(1,1,5), p2(1, 0, 0), p3(0,0,-2);
871  TopoDS_Solid rect1 = BRepPrimAPI_MakeBox(p0, p1).Solid();
872  TopoDS_Solid sphere = BRepPrimAPI_MakeSphere(p3, 0.7).Solid();
873 
874  gp_Pnt p000(0,0,0), p111(3,3,3);
875  TopoDS_Solid rect2 = BRepPrimAPI_MakeBox(p000, p111).Solid();
876 
877  //gp_Pnt q000(4,4,4), q111(5,5,5);
878  //gp_Pnt q000(-2,-2,2), q111(2,2,6);
879  gp_Pnt q000(-2,-1,2), q111(1,1,6);
880  TopoDS_Solid rect3 = BRepPrimAPI_MakeBox(q000, q111).Solid();
881 
882  gp_Pnt r000(-1,-1,-4), r111(1,1,-3);
883  TopoDS_Solid rect4 = BRepPrimAPI_MakeBox(r000, r111).Solid();
884 
885  //gp_Dir dir(0,1/sqrt(2.),1/sqrt(2.));
886  gp_Dir dir(0,1,0);
887  gp_Pnt x0(0,-3,-4);
888  gp_Ax2 ax2;
889  ax2.SetLocation(x0);
890  ax2.SetDirection(dir);
891  TopoDS_Solid cylinder = BRepPrimAPI_MakeCylinder(ax2, 3., 10.).Solid();
892 
893  TopoDS_Solid torus = BRepPrimAPI_MakeTorus(ax2, 3., 2.).Solid();
894 
895  TopoDS_Solid cone = BRepPrimAPI_MakeCone(ax2, 0.0, 5.0, 10.0).Solid();
896 
897  //TopoDS_Shape solid = BRepAlgoAPI_Fuse(rect1, rect2);
898  //TopoDS_Shape solid = BRepAlgoAPI_Fuse(rect1, cylinder);
899  //const TopoDS_Shape solid = BRepAlgoAPI_Fuse(rect1, cone);
900  TopoDS_Shape solid = BRepAlgoAPI_Fuse(rect1, sphere);
901 
902  {
903  double color[3] = {0., 0., 0.};
904 
905  HandleThisSolidWrapper(solid, mConfig->mhub()->fSingleMedium, color);
906  //HandleThisSolidWrapper(rect1, mediaHub->fSingleMedium, color);
907  //HandleThisSolidWrapper(rect2, mediaHub->fSingleMedium);
908  //HandleThisSolidWrapper(rect4, mediaHub->fSingleMedium);
909  //HandleThisSolidWrapper(sphere, mediaHub->fSingleMedium, color);
910  //HandleThisSolidWrapper(cylinder, mediaHub->fSingleMedium, color);
911  //HandleThisSolidWrapper(torus, mediaHub->fSingleMedium, color);
912  //HandleThisSolidWrapper(cone, mediaHub->fSingleMedium, color);
913  }
914 } // EicCadFile::ConstructDummyStepGeometry()
915 
916 // ---------------------------------------------------------------------------------------
917 
918 void EicCadFile::ConstructStepGeometry()
919 {
920 #ifdef _STEPCODE_
921  EicStepMaterialReader stReader;
922 #endif
923 
924  // Well, if medium name (then the same for all volumes in this STEP file) was
925  // given, use it; otherwise do a fairly stupid thing: read .stp file in using
926  // StepCode, extract material->volume information from it and later establish
927  // a relationship between StepCode internals and OpenCascade internals in
928  // order to couple OpenCascade solids with StepCode-imported material names;
929  if (!mConfig->mhub()->fSingleMedium) {
930 #ifdef _STEPCODE_
931  if (stReader.ReadFile(GetGeometryFileName()))
932  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Failed to parse '%s' "
933  "using StepCode library! \033[0m", GetGeometryFileName().Data());
934 #else
935  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m STEP file '%s': no media name "
936  "given and StepCode support is not compiled in! \033[0m",
937  GetGeometryFileName().Data());
938 #endif
939  } //if
940 
941  // Well, consider to use plain STEPControl_Reader for now; eventually should be able
942  // to get materials out of the file using STEPCAFControl_Reader; see EicCadFile.cxx
943  // versions before 2017/10/05; for now just use StepCode bypass;
944  STEPControl_Reader cReader;
945  // Read file; need to check import result later, here and below;
946  IFSelect_ReturnStatus cstatus = cReader.ReadFile(GetGeometryFileName());
947  // FIXME: may want to loop through all roots; should be easy fix?;
948  //assert(cReader.NbRootsForTransfer() == 1);
949  cReader.TransferRoots();//(1);
950  printf("%d root(s) in STEP file; %d shape(s)\n", cReader.NbRootsForTransfer(), cReader.NbShapes());
951  //cReader.TransferRoot(1);
952 
953  // A tricky part: find STEP entity number in the original file and use this
954  // tag in order to match against StepCode numbering scheme;
955  Handle(Transfer_TransientProcess) TP = cReader.WS()->TransferReader()->TransientProcess();
956  Handle(Interface_InterfaceModel) Model =cReader.Model();
957  printf("OpenCascade Model->NbEntities(): %d\n", Model->NbEntities());
958 
959  {
960  gp_Trsf scaling;
961  scaling.SetScaleFactor(config()->scale() * config()->units());
962  BRepBuilderAPI_Transform sc(scaling);
963 
964  // Loop through all shapes one by one; NB: it can happen, that this sequence
965  // of actions does not work for ANY .stp file; generalize later as needed;
966  for(unsigned sh=0; sh<cReader.NbShapes(); sh++) {
967  TopoDS_Shape shape = cReader.Shape(sh+1);
968 
969  // Loop through all solids in this shape;
970  for (TopExp_Explorer itf(shape,TopAbs_SOLID); itf.More(); itf.Next()) {
971  TGeoMedium *medium = mConfig->mhub()->fSingleMedium;
972 
973  if (!medium) {
974  // Try to get medium tag directly from STEP file; FIXME: requires further debugging;
975 #ifdef _STEPCODE_
976  // Figure out STEP file entity number; assume entity numbering is the same
977  // in OpenCascade and StepCode -> bridge to that internal tree and get access
978  // to material properties; somebody smart please make original OpenCascade
979  // do this, I'm too lazy/stupid, sorry; optimize later ...;
980  for (unsigned iqq=0; iqq<Model->NbEntities(); iqq++) {
981  Handle(Standard_Transient) enti = Model->Value(iqq+1);
982 
983  // This may not always work -> comment out completely and loop through all
984  // entities in this case; once again, need to optimize this loop anyway;
985  if(enti->IsKind(STANDARD_TYPE(StepRepr_NextAssemblyUsageOccurrence))) {
986  Standard_Integer index = TP->MapIndex(enti);
987 
988  if (index > 0) {
989  Handle(Transfer_Binder) binder = TP->MapItem (index);
990  TopoDS_Shape S = TransferBRep::ShapeResult(binder);
991  if (S.IsEqual(itf.Current())) {
992  printf(" .. found (%4d)!\n", iqq);
993 
994  {
995  const char *mediumName = stReader.GetMediumName(iqq);
996  if (!mediumName)
997  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Solid (%d) has no material assignment"
998  "in step file (and no medium given by hand)! \033[0m", iqq);
999 
1000  medium = mConfig->mhub()->GetMedium(mediumName);
1001  // Otherwise stReader.GetMedium() would have triggered mLogger->Fatal();
1002  //assert(medium);
1003  if (!medium)
1004  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m No such medium - %s - "
1005  "check media.geo file! \033[0m", mediumName);
1006  }
1007  }
1008  }
1009  }
1010  } //for iqq
1011 #else
1012  // FIXME: isn't this message redundant (see the very beginning of this routine)?;
1013  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m STEP file '%s': no medium name "
1014  "given and StepCode support is not compiled in! \033[0m",
1015  GetGeometryFileName().Data());
1016 #endif
1017  } //if
1018 
1019  double color[3] = {0., 0., 0.};
1020  // Try to get color directly from STEP file; FIXME: requires further debugging;
1021 #ifdef _STEPCODE_
1022  {
1023  // Pick up the very first face; assume they are all of the same color;
1024  TopExp_Explorer itg(itf.Current(),TopAbs_FACE);
1025 
1026  // Figure out STEP file entity number; assume entity numbering is the same
1027  // in OpenCascade and StepCode -> bridge to that internal tree and get access
1028  // to material properties; somebody smart please make original OpenCascade
1029  // do this, I'm too lazy/stupid, sorry; optimize later ...;
1030  for (unsigned iqq=0; iqq<Model->NbEntities(); iqq++) {
1031  Handle(Standard_Transient) enti = Model->Value(iqq+1);
1032 
1033  // This may not always work -> comment out completely and loop through all
1034  // entities in this case; once again, need to optimize this loop anyway;
1035  //if(enti->IsKind(STANDARD_TYPE(StepRepr_NextAssemblyUsageOccurrence)))
1036  {
1037  //cout << enti->DynamicType() << endl;
1038 
1039  Standard_Integer index = TP->MapIndex(enti);
1040 
1041  if (index > 0) {
1042  Handle(Transfer_Binder) binder = TP->MapItem (index);
1043  TopoDS_Shape S = TransferBRep::ShapeResult(binder);
1044  if (S.IsEqual(itg.Current())) {
1045  //printf(" .. found (%4d)!\n", iqq); exit(0);
1046 
1047  if (!stReader.GetColor(iqq, color))
1048  {
1049  //printf("@@@ Success: %f %f %f\n", arr[0], arr[1], arr[2]);
1050 
1051  } //if
1052 
1053  {
1054 #if 0
1055  const char *mediumName = stReader.GetMediumName(iqq);
1056  if (!mediumName)
1057  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Solid (%d) has no material assignment"
1058  "in step file (and no medium given by hand)! \033[0m", iqq);
1059 
1060  medium = mediaHub->GetMedium(mediumName);
1061  // Otherwise stReader.GetMedium() would have triggered mLogger->Fatal();
1062  //assert(medium);
1063  if (!medium)
1064  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m No such medium - %s - "
1065  "check media.geo file! \033[0m", mediumName);
1066 #endif
1067  }
1068  }
1069  }
1070  }
1071  } //for iqq
1072  } //if
1073 #endif
1074 
1075  // Rescale the object;
1076  sc.Perform(itf.Current());
1077  {
1078  static unsigned counter;
1079 
1080  //counter++;
1081  printf("counter: %d\n", counter);
1082  //if (counter == 188)
1083  //if (/*counter == 10 || counter == 12 ||*/ counter == 5 || //counter == 8 ||
1084  // counter == 1 || counter == 4 || counter == 9 || counter == 11)
1085  //if (counter == 12)
1086  // counter == 3 || counter == 5 || counter == 6 || counter == 8)
1087  //if (counter == 3 || counter == 5 || counter == 6 || counter == 8)
1088  //if (counter != 2 && counter != 9)
1089  //if (counter == 1 || counter == 4 || counter == 7 || counter == 6 || counter == 10 || counter == 11 || counter == 12)
1090  //if (counter == 1 || (counter >= 7 && counter <= 8) || (counter >= 10 && counter <= 12))
1091  HandleThisSolidWrapper(sc.ModifiedShape(itf.Current()), medium, color);
1092 
1093  counter++;
1094  }
1095  } //for itf
1096  } //for sh
1097  }
1098 } // EicCadFile::ConstructStepGeometry()
1099 
1100 // ---------------------------------------------------------------------------------------
1101 
1102 #include <STEPControl_Writer.hxx>
1103 //#include <STEPControl_StepModelType.hxx>
1104 
1106 {
1107  //EicGeoParData *geo = new EicGeoParData("DUMMY", 0, 0);
1108  EicGeoParData *geo = new EicGeoParData(dname->NAME().Data(), 0, 0);
1109  char fname[1024];
1110  snprintf(fname, 1024-1, "%s.root", dname->name().Data());
1111  geo->SetFileName(fname);
1112 
1113  mConfig->mhub()->Init(); mCave = geo->GetTopVolume();
1114  //mCave = gGeoManager->GetTopVolume(); assert(mCave);
1115 
1116  STEPControl_Reader cReader;
1117  IFSelect_ReturnStatus cstatus = cReader.ReadFile(GetGeometryFileName());
1118  // FIXME: may want to loop through all roots; should be easy fix?;
1119  //assert(cReader.NbRootsForTransfer() == 1);
1120  cReader.TransferRoots();//(1);
1121  printf("%d root(s) in STEP file; %d shape(s)\n", cReader.NbRootsForTransfer(), cReader.NbShapes());
1122  //cReader.TransferRoot(1);
1123 
1124  // A tricky part: find STEP entity number in the original file and use this
1125  // tag in order to match against StepCode numbering scheme;
1126  Handle(Transfer_TransientProcess) TP = cReader.WS()->TransferReader()->TransientProcess();
1127  Handle(Interface_InterfaceModel) Model = cReader.Model();
1128  printf("OpenCascade Model->NbEntities(): %d\n", Model->NbEntities());
1129 
1130  {
1131  gp_Trsf scaling;
1132  if (config()->GetRotationAxis() != EicCadFileConfig::_UNDEFINED_) {
1133  gp_Pnt x0(0.0, 0.0, 0.0);
1134  // FIXME: do it better later;
1135  assert(config()->GetRotationAxis() == EicCadFileConfig::_Y_);
1136  gp_Dir n0(0.0, 1.0, 0.0);
1137  gp_Ax1 axis(x0, n0);
1138 
1139  scaling.SetRotation(axis, config()->GetRotationAngle() * TMath::DegToRad());
1140  } //if
1141  // Yes, first rotate, then re-scale (otherwise scaling takes no effect);
1142  scaling.SetScaleFactor(config()->scale() * config()->units());
1143  BRepBuilderAPI_Transform sc(scaling);
1144 
1145  // Loop through all shapes one by one; NB: it can happen, that this sequence
1146  // of actions does not work for ANY .stp file; generalize later as needed;
1147  for(unsigned sh=0; sh<cReader.NbShapes(); sh++) {
1148  TopoDS_Shape shape = cReader.Shape(sh+1);
1149 
1150  // Loop through all solids in this shape;
1151  for (TopExp_Explorer itf(shape,TopAbs_SOLID); itf.More(); itf.Next()) {
1152  TGeoMedium *medium = mConfig->mhub()->fSingleMedium;
1153 
1154  double color[3] = {0., 0., 0.};
1155 
1156  // Rotate and rescale the object;
1157  sc.Perform(itf.Current());
1158 #if _TODAY_
1159  {
1160  static unsigned counter;
1161  printf("counter: %d\n", counter);
1162  const TopoDS_Shape &solid = sc.ModifiedShape(itf.Current());
1163 
1164  STEPControl_Writer cWriter;
1165  cWriter.Transfer(solid, STEPControl_ManifoldSolidBrep);
1166  char name[1024];
1167  snprintf(name, 1024-1, "%s-%05d.stp", GetGeometryFileName().Data(), counter);
1168  cWriter.Write(name);
1169 
1170  counter++;
1171  }
1172 #endif
1173 #if _TODAY_
1174  HandleThisSolidWrapper(sc.ModifiedShape(itf.Current()), medium, color);
1175 #endif
1176 #if _TODAY_
1177  {
1178  const TopoDS_Shape &solid = sc.ModifiedShape(itf.Current());
1179  std::vector<TopoDS_Shape> parts;
1180  gp_Pnt x0(0.0, 0.0, 0.0);
1181  gp_Dir n0(0.0, 1.0, 0.0);
1182  gp_Pln pl(x0, n0);
1183  TopoDS_Face face = BRepBuilderAPI_MakeFace(pl);
1184  double t = 0.1;
1185  gp_Pnt pt(x0.X() - t*n0.X(), x0.Y() - t*n0.Y(), x0.Z() - t*n0.Z());
1186  TopoDS_Shape *cut = new TopoDS_Shape(BRepPrimAPI_MakeHalfSpace(face, pt).Solid());
1187 
1188  TopoDS_Shape commonHalf = BRepAlgoAPI_Common(solid, *cut);
1189  for (TopExp_Explorer itq(commonHalf,TopAbs_SOLID); itq.More(); itq.Next())
1190  parts.push_back(itq.Current());
1191 
1192  TopoDS_Shape cutHalf = BRepAlgoAPI_Cut(solid, *cut);
1193  for (TopExp_Explorer itq(cutHalf,TopAbs_SOLID); itq.More(); itq.Next())
1194  parts.push_back(itq.Current());
1195  {
1196  unsigned rCounter = 0;
1197  printf("--> %d\n", parts.size());
1198  for(unsigned pt=0; pt<parts.size(); pt++) {
1199  STEPControl_Writer cWriter;
1200  cWriter.Transfer(parts[pt], STEPControl_ManifoldSolidBrep);
1201  char name[1024];
1202  snprintf(name, 1024-1, "test-%05d.stp", rCounter);
1203  cWriter.Write(name);
1204 
1205  rCounter++;
1206  } //for pt
1207  //for(unsigned pt=0; pt<parts.size(); pt++) {
1208  //DumpAsStlSolid(parts[pt], medium);
1209  //} //for pt
1210  }
1211  }
1212 #endif
1213 #if 1//_TODAY_
1214  {
1215  //const TopoDS_Shape &solid = sc.ModifiedShape(itf.Current());
1216  const TopoDS_Shape &solid = itf.Current();
1217 
1218  {
1219  double xMin, yMin, zMin, xMax, yMax, zMax;
1220  Bnd_Box Boundary;
1221  BRepBndLib::Add(solid, Boundary);
1222 
1223  Boundary.Get(xMin, yMin, zMin, xMax, yMax, zMax);
1224 
1225  if (boundarySphereCenter) delete boundarySphereCenter;
1226 
1227  // Be lazy; determine bounding sphere;
1228  boundarySphereCenter = new gp_Pnt((xMin+xMax)/2., (yMin+yMax)/2., (zMin+zMax)/2.);
1229  boundarySphereRadius = sqrt(SQR(xMax-xMin) + SQR(yMax-yMin) + SQR(zMax-zMin))/2.;
1230  }
1231 
1232  unsigned faceCounter = 0;
1233  int rfCounter = -1;
1234  for (TopExp_Explorer itg(solid,TopAbs_FACE); itg.More(); itg.Next())
1235  faceCounter++;
1236  printf("%3d faces total!\n", faceCounter);
1237  for (TopExp_Explorer itg(solid,TopAbs_FACE); itg.More(); itg.Next()) {
1238  TopoDS_Face &face = (TopoDS_Face&)itg.Current();
1239 
1240  rfCounter++;
1241  //assert(elementaryFaceType(face));
1242 
1243  Handle(Geom_Surface) SS = BRep_Tool::Surface(face);
1244  cout << " " << SS->DynamicType() << endl; //continue;
1245  if (!elementaryFaceType(face)) continue;
1246  //if (SS->IsKind(STANDARD_TYPE(Geom_Plane))) continue;
1247  //if (SS->IsKind(STANDARD_TYPE(Geom_CylindricalSurface))) continue;
1248  //if (SS->IsKind(STANDARD_TYPE(Geom_ConicalSurface))) continue;
1249  //if (SS->IsKind(STANDARD_TYPE(Geom_SphericalSurface))) continue;
1250  //if (SS->IsKind(STANDARD_TYPE(Geom_ToroidalSurface))) continue;
1251 
1252  {
1253  EicOpenCascadeShape cuttingShape;
1254  std::vector<TopoDS_Shape> commonSolids, cutSolids;
1255  std::vector<TopoDS_Shape> *arr[2] = {&commonSolids, &cutSolids};
1256  unsigned pCounter[2], fCounter[2] = {0, 0};
1257 
1258  splitSolidByInfiniteFace(solid, face, cuttingShape, commonSolids, cutSolids);
1259  //printf("%3d %3d\n", commonSolids.size(), cutSolids.size());
1260 
1261  for(unsigned gr=0; gr<2; gr++) {
1262  std::vector<TopoDS_Shape> *group = arr[gr];
1263 
1264  pCounter[gr] = group->size();
1265  for(unsigned pt=0; pt<group->size(); pt++) {
1266  const TopoDS_Shape &shape = (*group)[pt];
1267 
1268  for (TopExp_Explorer itx(shape,TopAbs_FACE); itx.More(); itx.Next())
1269  fCounter[gr]++;
1270  } //for pt
1271 
1272  //printf(" gr#%d -> %3d solids & %4d faces\n", gr, group->size(), fCounter[gr]);
1273  } //for gr
1274 
1275  if (pCounter[0] + pCounter[1] >= 2) {
1276  for(unsigned gr=0; gr<2; gr++)
1277  printf(" gr#%d -> %3d solids & %4d faces\n", gr, pCounter[gr], fCounter[gr]);
1278  printf(" --> %4d faces total!\n", fCounter[0] + fCounter[1]);
1279  } //if
1280 #if 1//_OFF_
1281  if (pCounter[0] + pCounter[1] >= 2) {
1282  unsigned rCounter = 0;
1283 
1284  for(unsigned gr=0; gr<2; gr++) {
1285  std::vector<TopoDS_Shape> *group = arr[gr];
1286 
1287  for(unsigned pt=0; pt<group->size(); pt++) {
1288  const TopoDS_Shape &shape = (*group)[pt];
1289 
1290  STEPControl_Writer cWriter;
1291  //TopoDS_Face body = BRepBuilderAPI_MakeSolid(TopoDS_Shell(shape));
1292 
1293  cWriter.Transfer(shape, STEPControl_ManifoldSolidBrep);
1294  char name[1024];
1295  snprintf(name, 1024-1, "test-%03d-%05d.stp", rfCounter, rCounter);
1296  cWriter.Write(name);
1297 
1298  rCounter++;
1299  } //for pt
1300  } //for gr
1301  } //if
1302 #endif
1303  }
1304 
1305 
1306  } //for itg
1307  }
1308 #endif
1309  } //for itf
1310  } //for sh
1311  }
1312 
1313  //geo->GetColorTable()->AddPatternMatch ("00", kGray);
1314  //geo->GetTransparencyTable()->AddPatternMatch("00", 0);
1315  geo->GetColorTable()->AddPatternMatch ("Dummy-666", kRed);
1316  geo->GetColorTable()->AddPatternMatch ("Dummy-777", kBlue);
1317  geo->GetColorTable()->AddPatternMatch ("Dummy-888", kGray);
1318  geo->GetColorTable()->AddPatternMatch ("Dummy-999", kGreen);
1319  geo->GetTransparencyTable()->AddPatternMatch("00", 0);
1320 
1321  geo->FinalizeOutput();
1322 } // EicCadFile::WizardTestbed()
1323 
1324 // ---------------------------------------------------------------------------------------
1325 
1326 //
1327 // -> FIXME: merge with ConstructStepGeometry() later; NB: admittedly this code is very raw
1328 // and can handle only very "clean" shapes only;
1329 //
1330 // -> FIXME: need to set units!;
1331 //
1332 
1333 void EicCadFile::ConstructIgesGeometry()
1334 {
1335  // Keep it easy for now; FIXME: re-implement XDE data parser via IGESCAFControl_Reader;
1336  IGESControl_Reader cReader;
1337 
1338  // Read file; FIXME: need to check import result later, here and below;
1339  IFSelect_ReturnStatus cstatus = cReader.ReadFile(GetGeometryFileName());
1340  //assert(cReader.NbRootsForTransfer() == 1);
1341  cReader.TransferRoots();
1342  //printf("OpenCascade cReader.NbShapes(): %d\n", cReader.NbShapes());
1343 
1344  {
1345  BRepBuilderAPI_Sewing *Sew = new BRepBuilderAPI_Sewing();
1346 
1347  // Loop through all shapes one by one; NB: it can happen, that this sequence
1348  // of actions does not work for ANY .igs file; generalize later as needed;
1349  for(unsigned sh=0; sh<cReader.NbShapes(); sh++) {
1350  const TopoDS_Shape shape = cReader.Shape(sh+1);
1351 
1352  // Prefer to keep these debugging printouts here and below;
1353 #if _DEBUG_
1354  for (TopExp_Explorer itf(shape,TopAbs_EDGE); itf.More(); itf.Next()) {
1355  double first, last;
1356  TopoDS_Edge &edge = (TopoDS_Edge&)itf.Current();
1357  Handle(Geom_Curve) SC = BRep_Tool::Curve(edge, first, last);
1358 
1359  cout << SC->DynamicType() << endl;
1360  } //for itf
1361 #endif
1362 
1363  // Loop through all faces;
1364  for (TopExp_Explorer itf(shape,TopAbs_FACE); itf.More(); itf.Next()) {
1365  static unsigned counter;
1366  //printf("adding face #%04d ...\n", counter++);
1367  Sew->Add(itf.Current());
1368 
1369 #if _DEBUG_
1370  TopoDS_Face &face = (TopoDS_Face&)itf.Current();
1371  if (!elementaryFaceType(face)) {
1372  printf(" One more complex face: \n");
1373  Handle(Geom_Surface) SS = BRep_Tool::Surface(face);
1374  cout << " " << SS->DynamicType() << endl;
1375 #if _DEBUG_
1376  for (TopExp_Explorer ith(itg.Current(),TopAbs_EDGE); ith.More(); ith.Next()) {
1377  TopoDS_Edge &edge = (TopoDS_Edge&)ith.Current();
1378  double first, last;
1379  Handle(Geom_Curve) SC = BRep_Tool::Curve(edge, first, last);
1380 
1381  //printf(" One more edge: ");
1382  cout << " --> " << SC->DynamicType() << endl;
1383  } //for ith
1384 #endif
1385  } //if
1386 #endif
1387  } //for itf
1388 
1389  } //for sh
1390 
1391  {
1392  Sew->Perform(); Sew->Dump();
1393  TopoDS_Shape result = Sew->SewedShape();
1394  for (TopExp_Explorer itf(result,TopAbs_SHELL); itf.More(); itf.Next()) {
1395  TopoDS_Shell &shell = (TopoDS_Shell&)itf.Current();
1396 
1397  HandleThisSolidWrapper(BRepBuilderAPI_MakeSolid(shell).Solid(), mConfig->mhub()->fSingleMedium, 0);
1398  } //for itf
1399  }
1400  }
1401 } // EicCadFile::ConstructIgesGeometry()
1402 #endif
1403 
1404 // ---------------------------------------------------------------------------------------
1405 
1406 #ifdef _ELMER_
1407 void EicCadFile::ConstructElmerGeometry()
1408 {
1409  mElmerMesh = new mesh_t();
1410 
1411  // Perform basic Elmer import; FIXME: check error codes;
1412  if (eg_loadmesh(GetGeometryFileName().Data()) || eg_transfermesh(mElmerMesh, "test"))
1413  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Elmer library import calls failed on %s ..! \033[0m",
1414  GetGeometryFileName().Data());
1415 
1416  printf("@@@: %d elements\n", mElmerMesh->getElements());
1417  for(unsigned el=0; el<mElmerMesh->getElements(); el++) {
1418  element_t *element = mElmerMesh->getElement(el);
1419 
1420  assert(element->getCode() == 504 && element->getNodes() == 4);
1421  //if (element->getCode() != 504 || element->getNodes() != 4) continue;
1422  //if (element->getCode() != 504)
1423  //printf("@@@ element %5d -> code# %4d; %d nodes; index: %5d\n",
1424  // el, element->getCode(), element->getNodes(), element->getIndex());
1425 
1426  TVector3 points[4];
1427  for(unsigned nd=0; nd<element->getNodes(); nd++) {
1428  //unsigned node = element->getNodeIndex(nd);
1429  //printf(" -> %5d\n", node);
1430  node_t *node = mElmerMesh->getNode(element->getNodeIndex(nd));//node);
1431  //printf("%10.4f %10.4f %10.4f; %5d\n",
1432  // node->getXvec()[0], node->getXvec()[1], node->getXvec()[2], node->getIndex());
1433 
1434  points[nd] = config()->scale() * config()->units() * TVector3(node->getXvec());
1435  } //for nd
1436 
1437  {
1438  char name[128];
1439  snprintf(name, 128-1, "%sTet%06d", dname->Name().Data(), el);
1440 
1441  TGeoVolume *vtet = CreateTetrahedron(points[0], points[1], points[2], points[3], name, mCave, mConfig->mhub()->fSingleMedium,
1443  vtet->SetFillColor(mFillColor);
1444  //vtet->SetTransparency(70);
1445  // FIXME: this is crap of course;
1446  if (mCreateStlMirrorCopyXZ) {
1447  TVector3 qpoints[4];
1448  char qname[128];
1449  snprintf(qname, 128-1, "%sTet%06dxz", dname->Name().Data(), el);
1450 
1451  for(unsigned pt=0; pt<4; pt++) {
1452  qpoints[pt] = points[pt];
1453  qpoints[pt].SetY(-qpoints[pt].y());
1454  } //for pt
1455 
1456  CreateTetrahedron(qpoints[0], qpoints[1], qpoints[2], qpoints[3], qname, mCave, mConfig->mhub()->fSingleMedium,
1458  } //if
1459  if (mCreateStlMirrorCopyXY) {
1460  TVector3 qpoints[4];
1461  char qname[128];
1462  snprintf(qname, 128-1, "%sTet%06dxy", dname->Name().Data(), el);
1463 
1464  for(unsigned pt=0; pt<4; pt++) {
1465  qpoints[pt] = points[pt];
1466  qpoints[pt].SetZ(-qpoints[pt].z());
1467  } //for pt
1468 
1469  CreateTetrahedron(qpoints[0], qpoints[1], qpoints[2], qpoints[3], qname, mCave, mConfig->mhub()->fSingleMedium,
1471  } //if
1473  TVector3 qpoints[4];
1474  char qname[128];
1475  snprintf(qname, 128-1, "%sTet%06dxyz", dname->Name().Data(), el);
1476 
1477  for(unsigned pt=0; pt<4; pt++) {
1478  qpoints[pt] = points[pt];
1479  qpoints[pt].SetY(-qpoints[pt].y());
1480  qpoints[pt].SetZ(-qpoints[pt].z());
1481  } //for pt
1482 
1483  CreateTetrahedron(qpoints[0], qpoints[1], qpoints[2], qpoints[3], qname, mCave, mConfig->mhub()->fSingleMedium,
1485  } //if
1486  } //for nd
1487  } //for el
1488 } // EicCadFile::ConstructElmerGeometry()
1489 #endif
1490 
1491 // ---------------------------------------------------------------------------------------
1492 
1494 {
1495  mConfig->mhub()->Init();
1496 
1497  // Well, for IGES file fSingleMedium should be clearly non-zero; check right here;
1498  if (GetGeometryFileName().EndsWith(".igs") && !mConfig->mhub()->fSingleMedium)
1499  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Unknown medium (%s) for .igs file! \033[0m",
1500  mConfig->mhub()->fMediaName.Data());
1501 
1502  // Assume CAVE volume is available as well (and it is the top volume);
1503  mCave = gGeoManager->GetTopVolume();
1504 
1505  if (GetGeometryFileName().EndsWith(".stp")) {
1506 #ifdef _OPENCASCADE_
1507  //ConstructDummyStepGeometry();
1508  ConstructStepGeometry();
1509 #else
1510  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m .stp file import error: OpenCascade "
1511  "support is not compiled in! \033[0m");
1512 #endif
1513  }
1514  else if (GetGeometryFileName().EndsWith(".igs"))
1515 #ifdef _OPENCASCADE_
1516  ConstructIgesGeometry();
1517 #else
1518  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m .igs file import error: OpenCascade "
1519  "support is not compiled in! \033[0m");
1520 #endif
1521  else if (GetGeometryFileName().EndsWith(".stl") || GetGeometryFileName().EndsWith(".slp")) {
1522  EicStlFactory stl_factory(dname->Name().Data(), GetGeometryFileName(), mConfig);//, mConfig->mhub()mediaHub);
1523  std::vector<TGeoVolume*> volumes;
1524 
1525  //stl_factory.SetVertexMergingTolerance(mStlVertexMergingTolerance);
1526  stl_factory._ConstructGeometry(mCave, mExtraStlTranslation, mSwapXY, /*mWireframvmeMode,*/ &volumes);
1527  if (mKillerFlag)
1528  for(unsigned iq=0; iq<volumes.size(); iq++)
1529  AddKillerVolume(volumes[iq]);
1530  }
1531  // NB: this may (in fact should) work with any other 3D mesh, as long as 1) Elmer
1532  // supports respective format, 2) 3D elements are tetrahedra; FIXME: would not be
1533  // a big deal to extend functionality to other elementary cell shapes (like pyramids,
1534  // prisms, etc);
1535  else if (GetGeometryFileName().EndsWith(".mphtxt"))
1536 #ifdef _ELMER_
1537  ConstructElmerGeometry();
1538 #else
1539  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m .mphtxt file import error: Elmer "
1540  "support is not compiled in! \033[0m");
1541 #endif
1542  else
1543  mLogger->Fatal(MESSAGE_ORIGIN, "\033[5m\033[31m Only .stp, .igs, .stl, .slp, .mphtxt files "
1544  "allowed (and only if support is compiled in)! \033[0m");
1545 } // EicCadFile::ConstructGeometry()
1546 
1547 // =======================================================================================
1548