Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveGeoShape.cxx
Go to the documentation of this file.
1 // @(#)root/eve7:$Id$
2 // Author: Matevz Tadel 2007, 2018
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <ROOT/REveGeoShape.hxx>
13 #include <ROOT/REveUtil.hxx>
14 #include <ROOT/REveTrans.hxx>
15 #include <ROOT/REveManager.hxx>
17 #include <ROOT/REveProjections.hxx>
19 
22 #include <ROOT/REveRenderData.hxx>
23 
24 #include "TROOT.h"
25 #include "TBuffer3D.h"
26 #include "TBuffer3DTypes.h"
27 #include "TColor.h"
28 #include "TFile.h"
29 
30 #include "TGeoShape.h"
31 #include "TGeoVolume.h"
32 #include "TGeoNode.h"
33 #include "TGeoShapeAssembly.h"
34 #include "TGeoCompositeShape.h"
35 #include "TGeoBoolNode.h"
36 #include "TGeoManager.h"
37 #include "TGeoMatrix.h"
38 #include "TVirtualGeoPainter.h"
39 
40 #include "json.hpp"
41 
42 
43 namespace
44 {
45  TGeoManager* init_geo_mangeur()
46  {
47  // Create a phony geo manager that can be used for storing free
48  // shapes. Otherwise shapes register themselves to current
49  // geo-manager (or even create one).
50 
51  TGeoManager *old = gGeoManager;
52  TGeoIdentity *old_id = gGeoIdentity;
53  gGeoManager = nullptr;
54  TGeoManager* mgr = new TGeoManager();
55  mgr->SetNameTitle("REveGeoShape::fgGeoManager",
56  "Static geo manager used for wrapped TGeoShapes.");
57  gGeoIdentity = new TGeoIdentity("Identity");
58  gGeoManager = old;
59  gGeoIdentity = old_id;
60  return mgr;
61  }
62 
63  TGeoHMatrix localGeoHMatrixIdentity;
64 }
65 
66 using namespace ROOT::Experimental;
67 namespace REX = ROOT::Experimental;
68 
69 /** \class REveGeoShape
70 \ingroup REve
71 Wrapper for TGeoShape with absolute positioning and color
72 attributes allowing display of extracted TGeoShape's (without an
73 active TGeoManager) and simplified geometries (needed for non-linear
74 projections).
75 
76 TGeoCompositeShapes and TGeoAssemblies are supported.
77 
78 If fNSegments data-member is < 2 (0 by default), the default number of
79 segments is used for tesselation and special GL objects are
80 instantiated for selected shapes (spheres, tubes). If fNSegments is > 2,
81 it gets forwarded to geo-manager and this tesselation detail is
82 used when creating the buffer passed to GL.
83 */
84 
85 TGeoManager *REX::REveGeoShape::fgGeoManager = init_geo_mangeur();
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 /// Return static geo-manager that is used internally to make shapes
89 /// lead a happy life.
90 /// Set gGeoManager to this object when creating TGeoShapes to be
91 /// passed into EveGeoShapes.
92 
93 TGeoManager *REveGeoShape::GetGeoManager()
94 {
95  return fgGeoManager;
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Return static identity matrix in homogeneous representation.
100 /// This is needed because TGeoCompositeShape::PaintComposite()
101 /// assumes TGeoShape::fgTransform is a TGeoHMatrix and we need to pass in
102 /// an identity matrix when painting a composite shape.
103 
104 TGeoHMatrix *REveGeoShape::GetGeoHMatrixIdentity()
105 {
106  return &localGeoHMatrixIdentity;
107 }
108 
109 ////////////////////////////////////////////////////////////////////////////////
110 /// Constructor.
111 
112 REveGeoShape::REveGeoShape(const std::string &name, const std::string &title)
113  : REveShape(name, title), fNSegments(0), fShape(nullptr), fCompositeShape(nullptr)
114 {
115  InitMainTrans();
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 /// Destructor.
120 
121 REveGeoShape::~REveGeoShape()
122 {
123  SetShape(nullptr);
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Create derived REveGeoShape form a TGeoCompositeShape.
128 
129 TGeoShape* REveGeoShape::MakePolyShape()
130 {
131  auto poly = new REveGeoPolyShape();
132  poly->BuildFromComposite(fCompositeShape, fNSegments);
133  return poly;
134 }
135 
136 ////////////////////////////////////////////////////////////////////////////////
137 /// Fill core part of JSON representation.
138 
139 Int_t REveGeoShape::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset)
140 {
141  return REveShape::WriteCoreJson(j, rnr_offset);
142 }
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// Crates 3D point array for rendering.
146 
147 void REveGeoShape::BuildRenderData()
148 {
149  if (!fShape) return;
150 
151  REveGeoPolyShape *egps = nullptr;
152  std::unique_ptr<REveGeoPolyShape> tmp_egps;
153 
154  if (fCompositeShape) {
155 
156  egps = dynamic_cast<REveGeoPolyShape *>(fShape);
157 
158  } else {
159 
160  tmp_egps = std::make_unique<REveGeoPolyShape>();
161 
162  tmp_egps->BuildFromShape(fShape, fNSegments);
163 
164  egps = tmp_egps.get();
165  }
166 
167  fRenderData = std::make_unique<REveRenderData>("makeEveGeoShape");
168 
169  REveElement::BuildRenderData();
170  egps->FillRenderData(*fRenderData);
171 }
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// Set number of segments.
175 
176 void REveGeoShape::SetNSegments(Int_t s)
177 {
178  if (s != fNSegments && fCompositeShape != nullptr) {
179  delete fShape;
180  fShape = MakePolyShape();
181  }
182  fNSegments = s;
183 }
184 
185 ////////////////////////////////////////////////////////////////////////////////
186 /// Set TGeoShape shown by this object.
187 ///
188 /// The shape is owned by REveGeoShape but TGeoShape::fUniqueID is
189 /// used for reference counting so you can pass the same shape to
190 /// several EveGeoShapes.
191 ///
192 /// If it if is taken from an existing TGeoManager, manually
193 /// increase the fUniqueID before passing it to REveGeoShape.
194 
195 void REveGeoShape::SetShape(TGeoShape *s)
196 {
197  REveGeoManagerHolder gmgr(fgGeoManager);
198 
199  if (fCompositeShape) {
200  delete fShape;
201  fShape = fCompositeShape;
202  }
203 
204  if (fShape) {
205  fShape->SetUniqueID(fShape->GetUniqueID() - 1);
206  if (fShape->GetUniqueID() == 0) {
207  delete fShape;
208  }
209  }
210 
211  fShape = s;
212 
213  if (fShape) {
214  fShape->SetUniqueID(fShape->GetUniqueID() + 1);
215  fCompositeShape = dynamic_cast<TGeoCompositeShape *>(fShape);
216  if (fCompositeShape) {
217  fShape = MakePolyShape();
218  }
219  }
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Compute bounding-box.
224 
225 void REveGeoShape::ComputeBBox()
226 {
227  TGeoBBox *bb = dynamic_cast<TGeoBBox *>(fShape);
228  if (bb) {
229  BBoxInit();
230  const Double_t *o = bb->GetOrigin();
231  BBoxCheckPoint(o[0] - bb->GetDX(), o[0] - bb->GetDY(), o[0] - bb->GetDZ());
232  BBoxCheckPoint(o[0] + bb->GetDX(), o[0] + bb->GetDY(), o[0] + bb->GetDZ());
233  } else {
234  BBoxZero();
235  }
236 }
237 
238 ////////////////////////////////////////////////////////////////////////////////
239 /// Save the shape tree as REveGeoShapeExtract.
240 /// File is always recreated.
241 
242 void REveGeoShape::SaveExtract(const char* file, const char* name)
243 {
244  // FIXME: ownership
245  REveGeoShapeExtract* gse = DumpShapeTree(this, nullptr);
246 
247  TFile f(file, "RECREATE");
248  gse->Write(name);
249  f.Close();
250 }
251 
252 ////////////////////////////////////////////////////////////////////////////////
253 /// Write the shape tree as REveGeoShapeExtract to current directory.
254 /// FIXME: SL: no any write into gDirectory
255 
256 void REveGeoShape::WriteExtract(const char* name)
257 {
258  // FIXME: ownership
259  REveGeoShapeExtract* gse = DumpShapeTree(this, nullptr);
260  gse->Write(name);
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Export this shape and its descendants into a geoshape-extract.
265 
266 REveGeoShapeExtract *REveGeoShape::DumpShapeTree(REveGeoShape* gsre,
267  REveGeoShapeExtract* parent)
268 {
269  REveGeoShapeExtract* she = new REveGeoShapeExtract(gsre->GetCName(), gsre->GetCTitle());
270  she->SetTrans(gsre->RefMainTrans().Array());
271  {
272  Int_t ci = gsre->GetFillColor();
273  TColor *c = gROOT->GetColor(ci);
274  Float_t rgba[4] = { 1, 0, 0, Float_t(1 - gsre->GetMainTransparency()/100.) };
275  if (c)
276  {
277  rgba[0] = c->GetRed();
278  rgba[1] = c->GetGreen();
279  rgba[2] = c->GetBlue();
280  }
281  she->SetRGBA(rgba);
282  }
283  {
284  Int_t ci = gsre->GetLineColor();
285  TColor *c = gROOT->GetColor(ci);
286  Float_t rgba[4] = { 1, 0, 0, 1 };
287  if (c)
288  {
289  rgba[0] = c->GetRed();
290  rgba[1] = c->GetGreen();
291  rgba[2] = c->GetBlue();
292  }
293  she->SetRGBALine(rgba);
294  }
295  she->SetRnrSelf(gsre->GetRnrSelf());
296  she->SetRnrElements(gsre->GetRnrChildren());
297  she->SetRnrFrame(gsre->GetDrawFrame());
298  she->SetMiniFrame(gsre->GetMiniFrame());
299  she->SetShape(gsre->GetShape());
300  if (gsre->HasChildren())
301  {
302  TList* ele = new TList();
303  she->SetElements(ele);
304  she->GetElements()->SetOwner(true);
305 
306  for (auto &c: gsre->RefChildren())
307  DumpShapeTree(dynamic_cast<REveGeoShape *>(c), she);
308  }
309  if (parent)
310  parent->GetElements()->Add(she);
311 
312  return she;
313 }
314 
315 ////////////////////////////////////////////////////////////////////////////////
316 /// Import a shape extract 'gse' under element 'parent'.
317 
318 REveGeoShape *REveGeoShape::ImportShapeExtract(REveGeoShapeExtract* gse,
319  REveElement* parent)
320 {
321  REveGeoManagerHolder gmgr(fgGeoManager);
322  REveManager::RRedrawDisabler redrawOff(REX::gEve);
323  REveGeoShape* gsre = SubImportShapeExtract(gse, parent);
324  gsre->StampObjProps();
325  return gsre;
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 /// Recursive version for importing a shape extract tree.
330 
331 REveGeoShape *REveGeoShape::SubImportShapeExtract(REveGeoShapeExtract* gse,
332  REveElement* parent)
333 {
334  REveGeoShape* gsre = new REveGeoShape(gse->GetName(), gse->GetTitle());
335  gsre->RefMainTrans().SetFromArray(gse->GetTrans());
336  const Float_t* rgba = gse->GetRGBA();
337  gsre->SetMainColorRGB(rgba[0], rgba[1], rgba[2]);
338  gsre->SetMainAlpha(rgba[3]);
339  rgba = gse->GetRGBALine();
340  gsre->SetLineColor(TColor::GetColor(rgba[0], rgba[1], rgba[2]));
341  gsre->SetRnrSelf(gse->GetRnrSelf());
342  gsre->SetRnrChildren(gse->GetRnrElements());
343  gsre->SetDrawFrame(gse->GetRnrFrame());
344  gsre->SetMiniFrame(gse->GetMiniFrame());
345  gsre->SetShape(gse->GetShape());
346 
347  if (parent)
348  parent->AddElement(gsre);
349 
350  if (gse->HasElements())
351  {
352  TIter next(gse->GetElements());
353  REveGeoShapeExtract* chld;
354  while ((chld = (REveGeoShapeExtract*) next()) != nullptr)
355  SubImportShapeExtract(chld, gsre);
356  }
357 
358  return gsre;
359 }
360 
361 ////////////////////////////////////////////////////////////////////////////////
362 /// Return class for projected objects:
363 /// - 2D projections: REvePolygonSetProjected,
364 /// - 3D projections: REveGeoShapeProjected.
365 /// Virtual from REveProjectable.
366 
367 TClass *REveGeoShape::ProjectedClass(const REveProjection* p) const
368 {
369  if (p->Is2D())
370  return TClass::GetClass<REvePolygonSetProjected>();
371  else
372  return TClass::GetClass<REveGeoShapeProjected>();
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Create a TBuffer3D suitable for presentation of the shape.
377 /// Transformation matrix is also applied.
378 
379 std::unique_ptr<TBuffer3D> REveGeoShape::MakeBuffer3D()
380 {
381  std::unique_ptr<TBuffer3D> buff;
382 
383  if (!fShape) return buff;
384 
385  if (dynamic_cast<TGeoShapeAssembly*>(fShape)) {
386  // TGeoShapeAssembly makes a bad TBuffer3D.
387  return buff;
388  }
389 
390  REveGeoManagerHolder gmgr(fgGeoManager, fNSegments);
391 
392  buff.reset(fShape->MakeBuffer3D());
393  REveTrans &mx = RefMainTrans();
394  if (mx.GetUseTrans()) {
395  Int_t n = buff->NbPnts();
396  Double_t *pnts = buff->fPnts;
397  for(Int_t k = 0; k < n; ++k) {
398  mx.MultiplyIP(&pnts[3*k]);
399  }
400  }
401  return buff;
402 }
403 
404 
405 //==============================================================================
406 // REveGeoShapeProjected
407 //==============================================================================
408 
409 /** \class REveGeoShapeProjected
410 \ingroup REve
411 A 3D projected REveGeoShape.
412 */
413 
414 ////////////////////////////////////////////////////////////////////////////////
415 /// Constructor.
416 
417 REveGeoShapeProjected::REveGeoShapeProjected() :
418  REveShape("REveGeoShapeProjected"),
419  fBuff()
420 {
421 }
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// Destructor.
425 
426 REveGeoShapeProjected::~REveGeoShapeProjected()
427 {
428  /// should be here because of TBuffer3D destructor
429 }
430 
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// This should never be called as this class is only used for 3D
434 /// projections.
435 /// The implementation is required as this metod is abstract.
436 /// Just emits a warning if called.
437 
438 void REveGeoShapeProjected::SetDepthLocal(Float_t /*d*/)
439 {
440  Warning("SetDepthLocal", "This function only exists to fulfill an abstract interface.");
441 }
442 
443 ////////////////////////////////////////////////////////////////////////////////
444 /// This is virtual method from base-class REveProjected.
445 
446 void REveGeoShapeProjected::SetProjection(REveProjectionManager* mng,
447  REveProjectable* model)
448 {
449  REveProjected::SetProjection(mng, model);
450 
451  REveGeoShape* gre = dynamic_cast<REveGeoShape*>(fProjectable);
452  CopyVizParams(gre);
453 }
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// This is virtual method from base-class REveProjected.
457 
458 void REveGeoShapeProjected::UpdateProjection()
459 {
460  REveGeoShape *gre = dynamic_cast<REveGeoShape*>(fProjectable);
461  REveProjection *prj = fManager->GetProjection();
462 
463  fBuff = gre->MakeBuffer3D();
464 
465  if (fBuff)
466  {
467  fBuff->SetSectionsValid(TBuffer3D::kCore | TBuffer3D::kRawSizes | TBuffer3D::kRaw);
468 
469  Double_t *p = fBuff->fPnts;
470  for (UInt_t i = 0; i < fBuff->NbPnts(); ++i, p+=3)
471  {
472  prj->ProjectPointdv(p, 0);
473  }
474  }
475 
476  ResetBBox();
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 /// Override of virtual method from TAttBBox.
481 
482 void REveGeoShapeProjected::ComputeBBox()
483 {
484  if (fBuff && fBuff->NbPnts() > 0)
485  {
486  BBoxInit();
487 
488  Double_t *p = fBuff->fPnts;
489  for (UInt_t i = 0; i < fBuff->NbPnts(); ++i, p+=3)
490  {
491  BBoxCheckPoint(p[0], p[1], p[2]);
492  }
493  }
494  else
495  {
496  BBoxZero();
497  }
498 }