Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGeoShape.cxx
Go to the documentation of this file.
1 // @(#)root/geom:$Id$
2 // Author: Andrei Gheata 31/01/02
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 /** \class TGeoShape
13 \ingroup Geometry_classes
14 Base abstract class for all shapes.
15 
16  Shapes are geometrical objects that provide the basic modelling
17 functionality. They provide the definition of the LOCAL frame of coordinates,
18 with respect to which they are defined. Any implementation of a shape deriving
19 from the base TGeoShape class has to provide methods for :
20 
21  - finding out if a point defined in their local frame is or not contained
22  inside;
23  - computing the distance from a local point to getting outside/entering the
24  shape, given a known direction;
25  - computing the maximum distance in any direction from a local point that
26  does NOT result in a boundary crossing of the shape (safe distance);
27  - computing the cosines of the normal vector to the crossed shape surface,
28  given a starting local point and an ongoing direction.
29  All the features above are globally managed by the modeller in order to
30  provide navigation functionality. In addition to those, shapes have also to
31  implement additional specific abstract methods :
32  - computation of the minimal box bounding the shape, given that this box have
33  to be aligned with the local coordinates;
34  - algorithms for dividing the shape along a given axis and producing resulting
35  divisions volumes.
36 
37  The modeler currently provides a set of 16 basic shapes, which we will call
38 primitives. It also provides a special class allowing the creation of shapes
39 made as a result of boolean operations between primitives. These are called
40 composite shapes and the composition operation can be recursive (composition
41 of composites). This allows the creation of a quite large number of different
42 shape topologies and combinations.
43 
44  Named shapes register themselves to the manager class at creation time. The
45 manager is responsible for their final deletion. Shapes can be created using their
46 default constructor if their retrieval by name is not needed, but in this case
47 they are owned by the user. A shape may be referenced by several volumes,
48 therefore its deletion is not possible once volumes were defined based on it.
49 
50 ### Creating shapes
51 
52  Shape objects embed only the minimum set of parameters that are fully
53 describing a valid physical shape. For instance, a tube is represented by
54 its half length, the minimum radius and the maximum radius. Shapes are used
55 together with media in order to create volumes, which in their turn
56 are the main components of the geometrical tree. A specific shape can be created
57 stand-alone :
58 
59 ~~~ {.cpp}
60  TGeoBBox *box = new TGeoBBox("s_box", halfX, halfY, halfZ); // named
61  TGeoTube *tub = new TGeoTube(rmin, rmax, halfZ); // no name
62  ... (see each specific shape constructors)
63 ~~~
64 
65  Sometimes it is much easier to create a volume having a given shape in one
66 step, since shapes are not directly linked in the geometrical tree but volumes
67 are :
68 
69 ~~~ {.cpp}
70  TGeoVolume *vol_box = gGeoManager->MakeBox("BOX_VOL", "mat1", halfX, halfY, halfZ);
71  TGeoVolume *vol_tub = gGeoManager->MakeTube("TUB_VOL", "mat2", rmin, rmax, halfZ);
72  ... (see MakeXXX() utilities in TGeoManager class)
73 ~~~
74 
75 ### Shape queries
76 
77 Note that global queries related to a geometry are handled by the manager class.
78 However, shape-related queries might be sometimes useful.
79 
80 #### `Bool_t TGeoShape::Contains(const Double_t *point[3])`
81 
82 this method returns true if POINT is actually inside the shape. The point
83 has to be defined in the local shape reference. For instance, for a box having
84 DX, DY and DZ half-lengths a point will be considered inside if :
85 
86 ~~~ {.cpp}
87  | -DX <= point[0] <= DX
88  | -DY <= point[1] <= DY
89  | -DZ <= point[2] <= DZ
90 ~~~
91 
92 #### `Double_t TGeoShape::DistFromInside(Double_t *point[3], Double_t *dir[3], Int_t iact, Double_t step, Double_t *safe)`
93 
94 computes the distance to exiting a shape from a given point INSIDE, along
95 a given direction. The direction is given by its director cosines with respect
96 to the local shape coordinate system. This method provides additional
97 information according the value of IACT input parameter :
98 
99  - IACT = 0 => compute only safe distance and fill it at the location
100  given by SAFE
101  - IACT = 1 => a proposed STEP is supplied. The safe distance is computed
102  first. If this is bigger than STEP than the proposed step
103  is approved and returned by the method since it does not
104  cross the shape boundaries. Otherwise, the distance to
105  exiting the shape is computed and returned.
106  - IACT = 2 => compute both safe distance and distance to exiting, ignoring
107  the proposed step.
108  - IACT > 2 => compute only the distance to exiting, ignoring anything else.
109 
110 #### `Double_t TGeoShape::DistFromOutside(Double_t *point[3], Double_t *dir[3], Int_t iact, Double_t step, Double_t *safe)`
111 
112 computes the distance to entering a shape from a given point OUTSIDE. Acts
113 in the same way as B).
114 
115 #### `Double_t Safety(const Double_t *point[3], Bool_t inside)`
116 
117 compute maximum shift of a point in any direction that does not change its
118 INSIDE/OUTSIDE state (does not cross shape boundaries). The state of the point
119 have to be properly supplied.
120 
121 #### `Double_t *Normal(Double_t *point[3], Double_t *dir[3], Bool_t inside)`
122 
123 returns director cosines of normal to the crossed shape surface from a
124 given point towards a direction. One has to specify if the point is inside
125 or outside shape. According to this, the normal will be outwards or inwards
126 shape respectively. Normal components are statically stored by shape class,
127 so it has to be copied after retrieval in a different array.
128 
129 ### Dividing shapes
130 
131 Shapes can generally be divided along a given axis. Supported axis are
132 X, Y, Z, Rxy, Phi, Rxyz. A given shape cannot be divided however on any axis.
133 The general rule is that that divisions are possible on whatever axis that
134 produces still known shapes as slices. The division of shapes should not be
135 performed by TGeoShape::Divide() calls, but rather by TGeoVolume::Divide().
136 The algorithm for dividing a specific shape is known by the shape object, but
137 is always invoked in a generic way from the volume level. Details on how to
138 do that can be found in TGeoVolume class. One can see how all division options
139 are interpreted and which is their result inside specific shape classes.
140 
141 \image html geom_t_shape.png
142 */
143 
144 #include "TObjArray.h"
145 #include "TEnv.h"
146 #include "TError.h"
147 
148 #include "TGeoMatrix.h"
149 #include "TGeoManager.h"
150 #include "TGeoVolume.h"
151 #include "TGeoShape.h"
152 #include "TVirtualGeoPainter.h"
153 #include "TBuffer3D.h"
154 #include "TBuffer3DTypes.h"
155 #include "TMath.h"
156 
157 ClassImp(TGeoShape);
158 
159 TGeoMatrix *TGeoShape::fgTransform = NULL;
160 Double_t TGeoShape::fgEpsMch = 2.220446049250313e-16;
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 /// Default constructor
164 
165 TGeoShape::TGeoShape()
166 {
167  fShapeBits = 0;
168  fShapeId = 0;
169  if (!gGeoManager) {
170  gGeoManager = new TGeoManager("Geometry", "default geometry");
171  // gROOT->AddGeoManager(gGeoManager);
172  }
173 // fShapeId = gGeoManager->GetListOfShapes()->GetSize();
174 // gGeoManager->AddShape(this);
175 }
176 
177 ////////////////////////////////////////////////////////////////////////////////
178 /// Default constructor
179 
180 TGeoShape::TGeoShape(const char *name)
181  :TNamed(name, "")
182 {
183  fShapeBits = 0;
184  fShapeId = 0;
185  if (!gGeoManager) {
186  gGeoManager = new TGeoManager("Geometry", "default geometry");
187  // gROOT->AddGeoManager(gGeoManager);
188  }
189  fShapeId = gGeoManager->GetListOfShapes()->GetSize();
190  gGeoManager->AddShape(this);
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 /// Destructor
195 
196 TGeoShape::~TGeoShape()
197 {
198  if (gGeoManager && !gGeoManager->IsCleaning()) gGeoManager->GetListOfShapes()->Remove(this);
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 /// Test for shape navigation methods. Summary for test numbers:
203 ///
204 /// - 1: DistFromInside/Outside. Sample points inside the shape. Generate
205 /// directions randomly in cos(theta). Compute DistFromInside and move the
206 /// point with bigger distance. Compute DistFromOutside back from new point.
207 /// Plot d-(d1+d2)
208 
209 void TGeoShape::CheckShape(Int_t testNo, Int_t nsamples, Option_t *option)
210 {
211  if (!gGeoManager) {
212  Error("CheckShape","No geometry manager");
213  return;
214  }
215  TGeoShape *shape = (TGeoShape*)this;
216  gGeoManager->CheckShape(shape, testNo, nsamples, option);
217 }
218 
219 ////////////////////////////////////////////////////////////////////////////////
220 /// Compute machine round-off double precision error as the smallest number that
221 /// if added to 1.0 is different than 1.0.
222 
223 Double_t TGeoShape::ComputeEpsMch()
224 {
225  Double_t temp1 = 1.0;
226  Double_t temp2 = 1.0 + temp1;
227  Double_t mchEps = 0.;
228  while (temp2>1.0) {
229  mchEps = temp1;
230  temp1 /= 2;
231  temp2 = 1.0 + temp1;
232  }
233  fgEpsMch = mchEps;
234  return fgEpsMch;
235 }
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 ///static function returning the machine round-off error
239 
240 Double_t TGeoShape::EpsMch()
241 {
242  return fgEpsMch;
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// Get the shape name.
247 
248 const char *TGeoShape::GetName() const
249 {
250  if (!fName[0]) {
251  return ((TObject *)this)->ClassName();
252  }
253  return TNamed::GetName();
254 }
255 
256 ////////////////////////////////////////////////////////////////////////////////
257 /// Returns distance to shape primitive mesh.
258 
259 Int_t TGeoShape::ShapeDistancetoPrimitive(Int_t numpoints, Int_t px, Int_t py) const
260 {
261  TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
262  if (!painter) return 9999;
263  return painter->ShapeDistancetoPrimitive(this, numpoints, px, py);
264 }
265 
266 ////////////////////////////////////////////////////////////////////////////////
267 /// True if point is closer than epsil to one of the phi planes defined by c1,s1 or c2,s2
268 
269 Bool_t TGeoShape::IsCloseToPhi(Double_t epsil, const Double_t *point, Double_t c1, Double_t s1, Double_t c2, Double_t s2)
270 {
271  Double_t saf1 = TGeoShape::Big();
272  Double_t saf2 = TGeoShape::Big();
273  if (point[0]*c1+point[1]*s1 >= 0) saf1 = TMath::Abs(-point[0]*s1 + point[1]*c1);
274  if (point[0]*c2+point[1]*s2 >= 0) saf2 = TMath::Abs(point[0]*s2 - point[1]*c2);
275  Double_t saf = TMath::Min(saf1,saf2);
276  if (saf<epsil) return kTRUE;
277  return kFALSE;
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Static method to check if a point is in the phi range (phi1, phi2) [degrees]
282 
283 Bool_t TGeoShape::IsInPhiRange(const Double_t *point, Double_t phi1, Double_t phi2)
284 {
285  Double_t phi = TMath::ATan2(point[1], point[0]) * TMath::RadToDeg();
286  while (phi<phi1) phi+=360.;
287  Double_t ddp = phi-phi1;
288  if (ddp>phi2-phi1) return kFALSE;
289  return kTRUE;
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /// Compute distance from POINT to semiplane defined by PHI angle along DIR. Computes
294 /// also radius at crossing point. This might be negative in case the crossing is
295 /// on the other side of the semiplane.
296 
297 Bool_t TGeoShape::IsCrossingSemiplane(const Double_t *point, const Double_t *dir, Double_t cphi, Double_t sphi, Double_t &snext, Double_t &rxy)
298 {
299  snext = rxy = TGeoShape::Big();
300  Double_t nx = -sphi;
301  Double_t ny = cphi;
302  Double_t rxy0 = point[0]*cphi+point[1]*sphi;
303  Double_t rdotn = point[0]*nx + point[1]*ny;
304  if (TMath::Abs(rdotn)<TGeoShape::Tolerance()) {
305  snext = 0.0;
306  rxy = rxy0;
307  return kTRUE;
308  }
309  if (rdotn<0) {
310  rdotn = -rdotn;
311  } else {
312  nx = -nx;
313  ny = -ny;
314  }
315  Double_t ddotn = dir[0]*nx + dir[1]*ny;
316  if (ddotn<=0) return kFALSE;
317  snext = rdotn/ddotn;
318  rxy = rxy0+snext*(dir[0]*cphi+dir[1]*sphi);
319  if (rxy<0) return kFALSE;
320  return kTRUE;
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// Check if two numbers differ with less than a tolerance.
325 
326 Bool_t TGeoShape::IsSameWithinTolerance(Double_t a, Double_t b)
327 {
328  if (TMath::Abs(a-b)<1.E-10) return kTRUE;
329  return kFALSE;
330 }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// Check if segments (A,B) and (C,D) are crossing,
334 /// where: A(x1,y1), B(x2,y2), C(x3,y3), D(x4,y4)
335 
336 Bool_t TGeoShape::IsSegCrossing(Double_t x1, Double_t y1, Double_t x2, Double_t y2,Double_t x3, Double_t y3,Double_t x4, Double_t y4)
337 {
338  Double_t eps = TGeoShape::Tolerance();
339  Bool_t stand1 = kFALSE;
340  Double_t dx1 = x2-x1;
341  Bool_t stand2 = kFALSE;
342  Double_t dx2 = x4-x3;
343  Double_t xm = 0.;
344  Double_t ym = 0.;
345  Double_t a1 = 0.;
346  Double_t b1 = 0.;
347  Double_t a2 = 0.;
348  Double_t b2 = 0.;
349  if (TMath::Abs(dx1) < eps) stand1 = kTRUE;
350  if (TMath::Abs(dx2) < eps) stand2 = kTRUE;
351  if (!stand1) {
352  a1 = (x2*y1-x1*y2)/dx1;
353  b1 = (y2-y1)/dx1;
354  }
355  if (!stand2) {
356  a2 = (x4*y3-x3*y4)/dx2;
357  b2 = (y4-y3)/dx2;
358  }
359  if (stand1 && stand2) {
360  // Segments parallel and vertical
361  if (TMath::Abs(x1-x3)<eps) {
362  // Check if segments are overlapping
363  if ((y3-y1)*(y3-y2)<-eps || (y4-y1)*(y4-y2)<-eps ||
364  (y1-y3)*(y1-y4)<-eps || (y2-y3)*(y2-y4)<-eps) return kTRUE;
365  return kFALSE;
366  }
367  // Different x values
368  return kFALSE;
369  }
370 
371  if (stand1) {
372  // First segment vertical
373  xm = x1;
374  ym = a2+b2*xm;
375  } else {
376  if (stand2) {
377  // Second segment vertical
378  xm = x3;
379  ym = a1+b1*xm;
380  } else {
381  // Normal crossing
382  if (TMath::Abs(b1-b2)<eps) {
383  // Parallel segments, are they aligned
384  if (TMath::Abs(y3-(a1+b1*x3))>eps) return kFALSE;
385  // Aligned segments, are they overlapping
386  if ((x3-x1)*(x3-x2)<-eps || (x4-x1)*(x4-x2)<-eps ||
387  (x1-x3)*(x1-x4)<-eps || (x2-x3)*(x2-x4)<-eps) return kTRUE;
388  return kFALSE;
389  }
390  xm = (a1-a2)/(b2-b1);
391  ym = (a1*b2-a2*b1)/(b2-b1);
392  }
393  }
394  // Check if crossing point is both between A,B and C,D
395  Double_t check = (xm-x1)*(xm-x2)+(ym-y1)*(ym-y2);
396  if (check > -eps) return kFALSE;
397  check = (xm-x3)*(xm-x4)+(ym-y3)*(ym-y4);
398  if (check > -eps) return kFALSE;
399  return kTRUE;
400 }
401 
402 ////////////////////////////////////////////////////////////////////////////////
403 /// compute distance from point (inside phi) to both phi planes. Return minimum.
404 
405 Double_t TGeoShape::DistToPhiMin(const Double_t *point, const Double_t *dir, Double_t s1, Double_t c1,
406  Double_t s2, Double_t c2, Double_t sm, Double_t cm, Bool_t in)
407 {
408  Double_t sfi1=TGeoShape::Big();
409  Double_t sfi2=TGeoShape::Big();
410  Double_t s=0;
411  Double_t un = dir[0]*s1-dir[1]*c1;
412  if (!in) un=-un;
413  if (un>0) {
414  s=-point[0]*s1+point[1]*c1;
415  if (!in) s=-s;
416  if (s>=0) {
417  s /= un;
418  if (((point[0]+s*dir[0])*sm-(point[1]+s*dir[1])*cm)>=0) sfi1=s;
419  }
420  }
421  un = -dir[0]*s2+dir[1]*c2;
422  if (!in) un=-un;
423  if (un>0) {
424  s=point[0]*s2-point[1]*c2;
425  if (!in) s=-s;
426  if (s>=0) {
427  s /= un;
428  if ((-(point[0]+s*dir[0])*sm+(point[1]+s*dir[1])*cm)>=0) sfi2=s;
429  }
430  }
431  return TMath::Min(sfi1, sfi2);
432 }
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Static method to compute normal to phi planes.
436 
437 void TGeoShape::NormalPhi(const Double_t *point, const Double_t *dir, Double_t *norm, Double_t c1, Double_t s1, Double_t c2, Double_t s2)
438 {
439  Double_t saf1 = TGeoShape::Big();
440  Double_t saf2 = TGeoShape::Big();
441  if (point[0]*c1+point[1]*s1 >= 0) saf1 = TMath::Abs(-point[0]*s1 + point[1]*c1);
442  if (point[0]*c2+point[1]*s2 >= 0) saf2 = TMath::Abs(point[0]*s2 - point[1]*c2);
443  Double_t c,s;
444  if (saf1<saf2) {
445  c=c1;
446  s=s1;
447  } else {
448  c=c2;
449  s=s2;
450  }
451  norm[2] = 0;
452  norm[0] = -s;
453  norm[1] = c;
454  if (dir[0]*norm[0]+dir[1]*norm[1] < 0) {
455  norm[0] = s;
456  norm[1] = -c;
457  }
458 }
459 
460 ////////////////////////////////////////////////////////////////////////////////
461 /// Static method to compute safety w.r.t a phi corner defined by cosines/sines
462 /// of the angles phi1, phi2.
463 
464 Double_t TGeoShape::SafetyPhi(const Double_t *point, Bool_t in, Double_t phi1, Double_t phi2)
465 {
466  Bool_t inphi = TGeoShape::IsInPhiRange(point, phi1, phi2);
467  if (inphi && !in) return -TGeoShape::Big();
468  phi1 *= TMath::DegToRad();
469  phi2 *= TMath::DegToRad();
470  Double_t c1 = TMath::Cos(phi1);
471  Double_t s1 = TMath::Sin(phi1);
472  Double_t c2 = TMath::Cos(phi2);
473  Double_t s2 = TMath::Sin(phi2);
474  Double_t rsq = point[0]*point[0]+point[1]*point[1];
475  Double_t rproj = point[0]*c1+point[1]*s1;
476  Double_t safsq = rsq-rproj*rproj;
477  if (safsq<0) return 0.;
478  Double_t saf1 = (rproj<0)?TGeoShape::Big():TMath::Sqrt(safsq);
479  rproj = point[0]*c2+point[1]*s2;
480  safsq = rsq-rproj*rproj;
481  if (safsq<0) return 0.;
482  Double_t saf2 = (rproj<0)?TGeoShape::Big():TMath::Sqrt(safsq);
483  Double_t safe = TMath::Min(saf1, saf2); // >0
484  if (safe>1E10) {
485  if (in) return TGeoShape::Big();
486  return -TGeoShape::Big();
487  }
488  return safe;
489 }
490 
491 ////////////////////////////////////////////////////////////////////////////////
492 /// Compute distance from point of coordinates (r,z) to segment (r1,z1):(r2,z2)
493 
494 Double_t TGeoShape::SafetySeg(Double_t r, Double_t z, Double_t r1, Double_t z1, Double_t r2, Double_t z2, Bool_t outer)
495 {
496  Double_t crossp = (z2-z1)*(r-r1)-(z-z1)*(r2-r1);
497  crossp *= (outer) ? 1. : -1.;
498  // Positive crossp means point on the requested side of the (1,2) segment
499  if (crossp < -TGeoShape::Tolerance()) {
500 // if (((z-z1)*(z2-z)) > -1.E-10) return 0;
501  if (outer) return TGeoShape::Big();
502  else return 0.;
503  }
504  // Compute (1,P) dot (1,2)
505  Double_t c1 = (z-z1)*(z2-z1)+(r-r1)*(r2-r1);
506  // Negative c1 means point (1) is closest
507  if (c1<1.E-10) return TMath::Sqrt((r-r1)*(r-r1)+(z-z1)*(z-z1));
508  // Compute (2,P) dot (1,2)
509  Double_t c2 = (z-z2)*(z2-z1)+(r-r2)*(r2-r1);
510  // Positive c2 means point (2) is closest
511  if (c2>-1.E-10) return TMath::Sqrt((r-r2)*(r-r2)+(z-z2)*(z-z2));
512  // The closest point is between (1) and (2)
513  c2 = (z2-z1)*(z2-z1)+(r2-r1)*(r2-r1);
514  // projected length factor with respect to (1,2) length
515  Double_t alpha = c1/c2;
516  Double_t rp = r1 + alpha*(r2-r1);
517  Double_t zp = z1 + alpha*(z2-z1);
518  return TMath::Sqrt((r-rp)*(r-rp)+(z-zp)*(z-zp));
519 }
520 
521 ////////////////////////////////////////////////////////////////////////////////
522 /// Equivalent of TObject::SetBit.
523 
524 void TGeoShape::SetShapeBit(UInt_t f, Bool_t set)
525 {
526  if (set) {
527  SetShapeBit(f);
528  } else {
529  ResetShapeBit(f);
530  }
531 }
532 
533 ////////////////////////////////////////////////////////////////////////////////
534 /// Returns current transformation matrix that applies to shape.
535 
536 TGeoMatrix *TGeoShape::GetTransform()
537 {
538  return fgTransform;
539 }
540 
541 ////////////////////////////////////////////////////////////////////////////////
542 /// Set current transformation matrix that applies to shape.
543 
544 void TGeoShape::SetTransform(TGeoMatrix *matrix)
545 {
546  fgTransform = matrix;
547 }
548 
549 ////////////////////////////////////////////////////////////////////////////////
550 /// Tranform a set of points (LocalToMaster)
551 
552 void TGeoShape::TransformPoints(Double_t *points, UInt_t NbPnts) const
553 {
554  UInt_t i,j;
555  Double_t dmaster[3];
556  if (fgTransform) {
557  for (j = 0; j < NbPnts; j++) {
558  i = 3*j;
559  fgTransform->LocalToMaster(&points[i], dmaster);
560  points[i] = dmaster[0];
561  points[i+1] = dmaster[1];
562  points[i+2] = dmaster[2];
563  }
564  return;
565  }
566  if (!gGeoManager) return;
567  Bool_t bomb = (gGeoManager->GetBombMode()==0)?kFALSE:kTRUE;
568 
569  for (j = 0; j < NbPnts; j++) {
570  i = 3*j;
571  if (gGeoManager->IsMatrixTransform()) {
572  TGeoHMatrix *glmat = gGeoManager->GetGLMatrix();
573  if (bomb) glmat->LocalToMasterBomb(&points[i], dmaster);
574  else glmat->LocalToMaster(&points[i], dmaster);
575  } else {
576  if (bomb) gGeoManager->LocalToMasterBomb(&points[i], dmaster);
577  else gGeoManager->LocalToMaster(&points[i],dmaster);
578  }
579  points[i] = dmaster[0];
580  points[i+1] = dmaster[1];
581  points[i+2] = dmaster[2];
582  }
583 }
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 /// Fill the supplied buffer, with sections in desired frame
587 /// See TBuffer3D.h for explanation of sections, frame etc.
588 
589 void TGeoShape::FillBuffer3D(TBuffer3D & buffer, Int_t reqSections, Bool_t localFrame) const
590 {
591  // Catch this common potential error here
592  // We have to set kRawSize (unless already done) to allocate buffer space
593  // before kRaw can be filled
594  if (reqSections & TBuffer3D::kRaw) {
595  if (!(reqSections & TBuffer3D::kRawSizes) && !buffer.SectionsValid(TBuffer3D::kRawSizes)) {
596  R__ASSERT(kFALSE);
597  }
598  }
599 
600  if (reqSections & TBuffer3D::kCore) {
601  // If writing core section all others will be invalid
602  buffer.ClearSectionsValid();
603 
604  // Check/grab some objects we need
605  if (!gGeoManager) {
606  R__ASSERT(kFALSE);
607  return;
608  }
609  const TGeoVolume * paintVolume = gGeoManager->GetPaintVolume();
610  if (!paintVolume) paintVolume = gGeoManager->GetTopVolume();
611  if (!paintVolume) {
612  buffer.fID = const_cast<TGeoShape *>(this);
613  buffer.fColor = 0;
614  buffer.fTransparency = 0;
615 // R__ASSERT(kFALSE);
616 // return;
617  } else {
618  buffer.fID = const_cast<TGeoVolume *>(paintVolume);
619  buffer.fColor = paintVolume->GetLineColor();
620 
621  buffer.fTransparency = paintVolume->GetTransparency();
622  Double_t visdensity = gGeoManager->GetVisDensity();
623  if (visdensity>0 && paintVolume->GetMedium()) {
624  if (paintVolume->GetMaterial()->GetDensity() < visdensity) {
625  buffer.fTransparency = 90;
626  }
627  }
628  }
629 
630  buffer.fLocalFrame = localFrame;
631  Bool_t r1,r2=kFALSE;
632  r1 = gGeoManager->IsMatrixReflection();
633  if (paintVolume && paintVolume->GetShape()) {
634  if (paintVolume->GetShape()->IsReflected()) {
635  // Temporary trick to deal with reflected shapes.
636  // Still lighting gets wrong...
637  if (buffer.Type() < TBuffer3DTypes::kTube) r2 = kTRUE;
638  }
639  }
640  buffer.fReflection = ((r1&(!r2))|(r2&!(r1)));
641 
642  // Set up local -> master translation matrix
643  if (localFrame) {
644  TGeoMatrix * localMasterMat = 0;
645  if (TGeoShape::GetTransform()) {
646  localMasterMat = TGeoShape::GetTransform();
647  } else {
648  localMasterMat = gGeoManager->GetCurrentMatrix();
649 
650  // For overlap drawing the correct matrix needs to obtained in
651  // from GetGLMatrix() - this should not be applied in the case
652  // of composite shapes
653  if (gGeoManager->IsMatrixTransform() && !IsComposite()) {
654  localMasterMat = gGeoManager->GetGLMatrix();
655  }
656  }
657  if (!localMasterMat) {
658  R__ASSERT(kFALSE);
659  return;
660  }
661  localMasterMat->GetHomogenousMatrix(buffer.fLocalMaster);
662  } else {
663  buffer.SetLocalMasterIdentity();
664  }
665 
666  buffer.SetSectionsValid(TBuffer3D::kCore);
667  }
668 }
669 
670 ////////////////////////////////////////////////////////////////////////////////
671 /// Get the basic color (0-7).
672 
673 Int_t TGeoShape::GetBasicColor() const
674 {
675  Int_t basicColor = 0; // TODO: Check on sensible fallback
676  if (gGeoManager) {
677  const TGeoVolume * volume = gGeoManager->GetPaintVolume();
678  if (volume) {
679  basicColor = ((volume->GetLineColor() %8) -1) * 4;
680  if (basicColor < 0) basicColor = 0;
681  }
682  }
683  return basicColor;
684 }
685 
686 ////////////////////////////////////////////////////////////////////////////////
687 /// Stub implementation to avoid forcing implementation at this stage
688 
689 const TBuffer3D &TGeoShape::GetBuffer3D(Int_t /*reqSections*/, Bool_t /*localFrame*/) const
690 {
691  static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
692  Warning("GetBuffer3D", "this must be implemented for shapes in a TGeoPainter hierarchy. This will be come a pure virtual fn eventually.");
693  return buffer;
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 /// Provide a pointer name containing uid.
698 
699 const char *TGeoShape::GetPointerName() const
700 {
701  static TString name;
702  Int_t uid = GetUniqueID();
703  if (uid) name = TString::Format("p%s_%d", GetName(),uid);
704  else name = TString::Format("p%s", GetName());
705  return name.Data();
706 }
707 
708 ////////////////////////////////////////////////////////////////////////////////
709 /// Execute mouse actions on this shape.
710 
711 void TGeoShape::ExecuteEvent(Int_t event, Int_t px, Int_t py)
712 {
713  if (!gGeoManager) return;
714  TVirtualGeoPainter *painter = gGeoManager->GetPainter();
715  painter->ExecuteShapeEvent(this, event, px, py);
716 }
717 
718 ////////////////////////////////////////////////////////////////////////////////
719 /// Draw this shape.
720 
721 void TGeoShape::Draw(Option_t *option)
722 {
723  TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
724  if (option && option[0]) {
725  painter->DrawShape(this, option);
726  } else {
727  painter->DrawShape(this, gEnv->GetValue("Viewer3D.DefaultDrawOption",""));
728  }
729 }
730 
731 ////////////////////////////////////////////////////////////////////////////////
732 /// Paint this shape.
733 
734 void TGeoShape::Paint(Option_t *option)
735 {
736  TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
737  if (option && option[0]) {
738  painter->PaintShape(this, option);
739  } else {
740  painter->PaintShape(this, gEnv->GetValue("Viewer3D.DefaultDrawOption",""));
741  }
742 }