TGeoCompositeShape.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoCompositeShape.cxx 36535 2010-11-08 14:41:54Z agheata $
00002 // Author: Andrei Gheata   31/01/02
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 
00013 ///////////////////////////////////////////////////////////////////////////////
00014 // TGeoCompositeShape - class handling Boolean composition of shapes
00015 //
00016 //   Composite shapes are Boolean combination of two or more shape
00017 // components. The supported boolean operations are union (+), intersection (*)
00018 // and subtraction. Composite shapes derive from the base TGeoShape class,
00019 // therefore providing all shape features : computation of bounding box, finding
00020 // if a given point is inside or outside the combination, as well as computing the
00021 // distance to entering/exiting. It can be directly used for creating volumes or
00022 // used in the definition of other composite shapes.
00023 //   Composite shapes are provided in order to complement and extend the set of
00024 // basic shape primitives. They have a binary tree internal structure, therefore
00025 // all shape-related geometry queries are signals propagated from top level down
00026 // to the final leaves, while the provided answers are assembled and interpreted
00027 // back at top. This CSG hierarchy is effective for small number of components,
00028 // while performance drops dramatically for large structures. Building a complete
00029 // geometry in this style is virtually possible but highly not recommended.
00030 //
00031 //   Structure of composite shapes
00032 //
00033 //   A composite shape can always be regarded as the result of a Boolean operation
00034 // between only two shape components. All information identifying these two
00035 // components as well as their positions with respect to the frame of the composite
00036 // is represented by an object called Boolean node. A composite shape just have
00037 // a pointer to such a Boolean node. Since the shape components may also be
00038 // composites, they will also contain binary Boolean nodes branching other two
00039 // shapes in the hierarcy. Any such branch ends-up when the final leaves are no
00040 // longer composite shapes, but basic primitives.
00041 //
00042 //Begin_Html
00043 /*
00044 <img src="gif/t_booltree.jpg">
00045 */
00046 //End_Html
00047 //
00048 //   Suppose that A, B, C and D represent basic shapes, we will illustrate
00049 // how the internal representation of few combinations look like. We do this
00050 // only for the sake of understanding how to create them in a proper way, since
00051 // the user interface for this purpose is in fact very simple. We will ignore
00052 // for the time being the positioning of components. The definition of a composite
00053 // shape takes an expression where the identifiers are shape names. The
00054 // expression is parsed and decomposed in 2 sub-expressions and the top-level
00055 // Boolean operator.
00056 //
00057 // 1.     A+B+C
00058 //   This represent the union of A, B and C. Both union operators are at the
00059 // same level. Since:
00060 //        A+B+C = (A+B)+C = A+(B+C)
00061 // the first (+) is taken as separator, hence the expression splitted:
00062 //        A and B+C
00063 // A Boolean node of type TGeoUnion("A", "B+C") is created. This tries to replace
00064 // the 2 expressions by actual pointers to corresponding shapes.
00065 // The first expression (A) contains no operators therefore is interpreted as
00066 // representing a shape. The shape named "A" is searched into the list of shapes
00067 // handled by the manager class and stored as the "left" shape in the Boolean
00068 // union node. Since the second expression is not yet fully decomposed, the "right"
00069 // shape in the combination is created as a new composite shape. This will split
00070 // at its turn B+C into B and C and create a TGeoUnion("B","C"). The B and C
00071 // identifiers will be looked for and replaced by the pointers to the actual shapes
00072 // into the new node. Finally, the composite "A+B+C" will be represented as:
00073 //
00074 //                 A
00075 //                |
00076 //   [A+B+C] = (+)             B
00077 //                |           |
00078 //                 [B+C] = (+)
00079 //                            |
00080 //                             C
00081 //
00082 // where [] is a composite shape, (+) is a Boolean node of type union and A, B,
00083 // C are pointers to the corresponding shapes.
00084 //   Building this composite shapes takes the following line :
00085 //      TGeoCompositeShape *cs1 = new TGeoCompositeShape("CS1", "A+B+C");
00086 //
00087 // 2.      (A+B)\(C+D)
00088 //   This expression means: subtract the union of C and D from the union of A and
00089 // B. The usage of paranthesys to force operator precedence is always recommended.
00090 // The representation of the corresponding composite shape looks like:
00091 //
00092 //                                   A
00093 //                                  |
00094 //                       [A+B] = (+)
00095 //                      |           |
00096 //   [(A+B)\(C+D)] = (\)           C B
00097 //                      |         |
00098 //                       [C+D]=(+)
00099 //                                |
00100 //                                 D
00101 //
00102 //      TGeoCompositeShape *cs2 = new TGeoCompositeShape("CS2", "(A+B)\(C+D)");
00103 //
00104 //   Building composite shapes as in the 2 examples above is not always quite
00105 // usefull since we were using unpositioned shapes. When suplying just shape
00106 // names as identifiers, the created boolean nodes will assume that the shapes
00107 // are positioned with an identity transformation with respect to the frame of
00108 // the created composite. In order to provide some positioning of the combination
00109 // components, we have to attach after each shape identifier the name of an
00110 // existing transformation, separated by a colon. Obviously all transformations
00111 // created for this purpose have to be objects with unique names in order to be
00112 // properly substituted during parsing.
00113 //   Let's look at the code implementing the second example :
00114 //
00115 //      TGeoTranslation *t1 = new TGeoTranslation("T1",0,0,-20);
00116 //      TGeoTranslation *t2 = new TGeoTranslation("T2",0,0, 20);
00117 //      TGeoRotation *r1 = new TGeoRotation("R1"); // transformations need names
00118 //      r1->SetAngles(90,30,90,120,0,0); // rotation with 30 degrees about Z
00119 //      TGeoTube *a = new TGeoTube(0, 10,20);
00120 //      a->SetName("A");                 // shapes need names too
00121 //      TGeoTube *b = new TGeoTube(0, 20,20);
00122 //      b->SetName("B");
00123 //      TGeoBBox *c = new TGeoBBox(10,10,50);
00124 //      c->SetName("C");
00125 //      TGeoBBox *d = new TGeoBBox(50,10,10);
00126 //      d->SetName("D");
00127 //
00128 //      TGeoCompositeShape *cs;
00129 //      cs = new TGeoCompositeShape("CS", "(A:t1+B:t2)\(C+D:r1)");
00130 //
00131 //   The newly created composite looks like 2 cylinders of different radii sitting
00132 // one on top of the other and having 2 rectangular holes : a longitudinal one
00133 // along Z axis corresponding to C and an other one in the XY plane due to D.
00134 //   One should have in mind that the same shape or matrix identifier can be
00135 // used many times in the same expression. For instance:
00136 //
00137 //      (A:t1-A:t2)*B:t1
00138 //
00139 // is a valid expression. Expressions that cannot be parsed or identifiers that
00140 // cannot be substituted by existing objects generate error messages.
00141 //   Composite shapes can be subsequently used for defining volumes. Moreover,
00142 // these volumes may have daughters but these have to obbey overlapping/extruding
00143 // rules (see TGeoVolume). Volumes created based on composite shapes cannot be
00144 // divided. Visualization of such volumes is currently not implemented.
00145 
00146 #include "Riostream.h"
00147 #include "TRandom3.h"
00148 
00149 #include "TGeoManager.h"
00150 #include "TGeoMatrix.h"
00151 #include "TGeoBoolNode.h"
00152 #include "TVirtualGeoPainter.h"
00153 
00154 #include "TVirtualPad.h"
00155 #include "TVirtualViewer3D.h"
00156 #include "TBuffer3D.h"
00157 #include "TBuffer3DTypes.h"
00158 
00159 #include "TGeoCompositeShape.h"
00160 ClassImp(TGeoCompositeShape)
00161 
00162 //_____________________________________________________________________________
00163 TGeoCompositeShape::TGeoCompositeShape()
00164                    :TGeoBBox(0, 0, 0)
00165 {
00166 // Default constructor
00167    SetShapeBit(TGeoShape::kGeoComb);
00168    fNode  = 0;
00169 }
00170 
00171 //_____________________________________________________________________________
00172 TGeoCompositeShape::TGeoCompositeShape(const char *name, const char *expression)
00173                    :TGeoBBox(0, 0, 0)
00174 {
00175 // Default constructor
00176    SetShapeBit(TGeoShape::kGeoComb);
00177    SetName(name);
00178    fNode  = 0;
00179    MakeNode(expression);
00180    if (!fNode) {
00181       Error("ctor", "Composite %s: cannot parse expression: %s", name, expression);
00182       return;
00183    }
00184    ComputeBBox();
00185 }
00186 
00187 //_____________________________________________________________________________
00188 TGeoCompositeShape::TGeoCompositeShape(const char *expression)
00189                    :TGeoBBox(0, 0, 0)
00190 {
00191 // Default constructor
00192    SetShapeBit(TGeoShape::kGeoComb);
00193    fNode  = 0;
00194    MakeNode(expression);
00195    if (!fNode) {
00196       TString message = TString::Format("Composite (no name) could not parse expression %s", expression);
00197       Error("ctor", "%s", message.Data());
00198       return;
00199    }
00200    ComputeBBox();
00201 }
00202 
00203 //_____________________________________________________________________________
00204 TGeoCompositeShape::TGeoCompositeShape(const char *name, TGeoBoolNode *node)
00205                    :TGeoBBox(0,0,0)
00206 {
00207 // Constructor with a Boolean node
00208    SetName(name);
00209    fNode = node;
00210    if (!fNode) {
00211       Error("ctor", "Composite shape %s has null node", name);
00212       return;
00213    }
00214    ComputeBBox();
00215 }
00216 
00217 //_____________________________________________________________________________
00218 TGeoCompositeShape::~TGeoCompositeShape()
00219 {
00220 // destructor
00221    if (fNode) delete fNode;
00222 }
00223 
00224 //_____________________________________________________________________________
00225 Double_t TGeoCompositeShape::Capacity() const
00226 {
00227 // Computes capacity of this shape [length^3] by sampling with 1% error.
00228    Double_t pt[3];
00229    if (!gRandom) gRandom = new TRandom3();
00230    Double_t vbox = 8*fDX*fDY*fDZ; // cm3
00231    Int_t igen=0;
00232    Int_t iin = 0;
00233    while (iin<10000) {
00234       pt[0] = fOrigin[0]-fDX+2*fDX*gRandom->Rndm();
00235       pt[1] = fOrigin[1]-fDY+2*fDY*gRandom->Rndm();
00236       pt[2] = fOrigin[2]-fDZ+2*fDZ*gRandom->Rndm();
00237       igen++;
00238       if (Contains(pt)) iin++;
00239    }
00240    Double_t capacity = iin*vbox/igen;
00241    return capacity;
00242 }
00243 
00244 //_____________________________________________________________________________
00245 void TGeoCompositeShape::ComputeBBox()
00246 {
00247 // compute bounding box of the sphere
00248    if(fNode) fNode->ComputeBBox(fDX, fDY, fDZ, fOrigin);
00249 }
00250 
00251 //_____________________________________________________________________________
00252 void TGeoCompositeShape::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
00253 {
00254 // Computes normal vector in POINT to the composite shape.
00255    if (fNode) fNode->ComputeNormal(point,dir,norm);
00256 }
00257 
00258 //_____________________________________________________________________________
00259 Bool_t TGeoCompositeShape::Contains(Double_t *point) const
00260 {
00261 // Tests if point is inside the shape.
00262    if (fNode) return fNode->Contains(point);
00263    return kFALSE;
00264 }
00265 
00266 //_____________________________________________________________________________
00267 Int_t TGeoCompositeShape::DistancetoPrimitive(Int_t px, Int_t py)
00268 {
00269 // Compute closest distance from point px,py to each corner.
00270    const Int_t numPoints = GetNmeshVertices();
00271    return ShapeDistancetoPrimitive(numPoints, px, py);
00272 }
00273 
00274 //_____________________________________________________________________________
00275 Double_t TGeoCompositeShape::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact,
00276                                       Double_t step, Double_t *safe) const
00277 {
00278 // Compute distance from outside point to this composite shape.
00279 // Check if the bounding box is crossed within the requested distance
00280    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
00281    if (sdist>=step) return TGeoShape::Big();
00282    if (fNode) return fNode->DistFromOutside(point, dir, iact, step, safe);
00283    return TGeoShape::Big();
00284 }
00285 
00286 //_____________________________________________________________________________
00287 Double_t TGeoCompositeShape::DistFromInside(Double_t *point, Double_t *dir, Int_t iact,
00288                                       Double_t step, Double_t *safe) const
00289 {
00290 // Compute distance from inside point to outside of this composite shape.
00291    if (fNode) return fNode->DistFromInside(point, dir, iact, step, safe);
00292    return TGeoShape::Big();
00293 }
00294 
00295 //_____________________________________________________________________________
00296 TGeoVolume *TGeoCompositeShape::Divide(TGeoVolume  * /*voldiv*/, const char * /*divname*/, Int_t /*iaxis*/,
00297                                        Int_t /*ndiv*/, Double_t /*start*/, Double_t /*step*/)
00298 {
00299 // Divide all range of iaxis in range/step cells
00300    Error("Divide", "Composite shapes cannot be divided");
00301    return 0;
00302 }
00303 
00304 //_____________________________________________________________________________
00305 void TGeoCompositeShape::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
00306 {
00307 // Returns numbers of vertices, segments and polygons composing the shape mesh.
00308    nvert = GetNmeshVertices();
00309    nsegs = 0;
00310    npols = 0;
00311 }
00312 
00313 //_____________________________________________________________________________
00314 void TGeoCompositeShape::InspectShape() const
00315 {
00316 // print shape parameters
00317    printf("*** TGeoCompositeShape : %s = %s\n", GetName(), GetTitle());
00318    printf(" Bounding box:\n");
00319    TGeoBBox::InspectShape();
00320 }
00321 
00322 //_____________________________________________________________________________
00323 void TGeoCompositeShape::MakeNode(const char *expression)
00324 {
00325 // Make a booleann node according to the top level boolean operation of expression.
00326 // Propagates signal to branches until expression is fully decomposed.
00327 //   printf("Making node for : %s\n", expression);
00328    if (fNode) delete fNode;
00329    fNode = 0;
00330    SetTitle(expression);
00331    TString sleft, sright, smat;
00332    Int_t boolop;
00333    boolop = TGeoManager::Parse(expression, sleft, sright, smat);
00334    if (boolop<0) {
00335       // fail
00336       Error("MakeNode", "parser error");
00337       return;
00338    }
00339    if (smat.Length())
00340       Warning("MakeNode", "no geometrical transformation allowed at this level");
00341    switch (boolop) {
00342       case 0:
00343          Error("MakeNode", "Expression has no boolean operation");
00344          return;
00345       case 1:
00346          fNode = new TGeoUnion(sleft.Data(), sright.Data());
00347          return;
00348       case 2:
00349          fNode = new TGeoSubtraction(sleft.Data(), sright.Data());
00350          return;
00351       case 3:
00352          fNode = new TGeoIntersection(sleft.Data(), sright.Data());
00353    }
00354 }
00355 
00356 //_____________________________________________________________________________
00357 Bool_t TGeoCompositeShape::PaintComposite(Option_t *option) const
00358 {
00359    // Paint this composite shape into the current 3D viewer
00360    // Returns bool flag indicating if the caller should continue to
00361    // paint child objects
00362 
00363    Bool_t addChildren = kTRUE;
00364 
00365    TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
00366    TVirtualViewer3D * viewer = gPad->GetViewer3D();
00367    if (!painter || !viewer) return kFALSE;
00368 
00369    if (fNode) {
00370       // Fill out the buffer for the composite shape - nothing extra
00371       // over TGeoBBox
00372       Bool_t preferLocal = viewer->PreferLocalFrame();
00373       if (TBuffer3D::GetCSLevel()) preferLocal = kFALSE;
00374       static TBuffer3D buffer(TBuffer3DTypes::kComposite);
00375       FillBuffer3D(buffer, TBuffer3D::kCore|TBuffer3D::kBoundingBox,
00376                    preferLocal);
00377 
00378       Bool_t paintComponents = kTRUE;
00379 
00380       // Start a composite shape, identified by this buffer
00381       if (!TBuffer3D::GetCSLevel())
00382          paintComponents = viewer->OpenComposite(buffer, &addChildren);
00383 
00384       TBuffer3D::IncCSLevel();
00385 
00386       // Paint the boolean node - will add more buffers to viewer
00387       TGeoHMatrix *matrix = (TGeoHMatrix*)TGeoShape::GetTransform();
00388       TGeoHMatrix backup(*matrix);
00389       if (preferLocal) matrix->Clear();
00390       if (paintComponents) fNode->Paint(option);
00391       if (preferLocal) *matrix = backup;
00392       // Close the composite shape
00393       if (!TBuffer3D::DecCSLevel())
00394          viewer->CloseComposite();
00395    }
00396 
00397    return addChildren;
00398 }
00399 
00400 //_____________________________________________________________________________
00401 void TGeoCompositeShape::RegisterYourself()
00402 {
00403 // Register the shape and all components to TGeoManager class.
00404    if (gGeoManager->GetListOfShapes()->FindObject(this)) return;
00405    gGeoManager->AddShape(this);
00406    TGeoMatrix *matrix;
00407    TGeoShape  *shape;
00408    TGeoCompositeShape *comp;
00409    if (fNode) {
00410       matrix = fNode->GetLeftMatrix();
00411       if (!matrix->IsRegistered()) matrix->RegisterYourself();
00412       else if (!gGeoManager->GetListOfMatrices()->FindObject(matrix)) {
00413          gGeoManager->GetListOfMatrices()->Add(matrix);
00414       }
00415       matrix = fNode->GetRightMatrix();
00416       if (!matrix->IsRegistered()) matrix->RegisterYourself();
00417       else if (!gGeoManager->GetListOfMatrices()->FindObject(matrix)) {
00418          gGeoManager->GetListOfMatrices()->Add(matrix);
00419       }
00420       shape = fNode->GetLeftShape();
00421       if (!gGeoManager->GetListOfShapes()->FindObject(shape)) {
00422          if (shape->IsComposite()) {
00423             comp = (TGeoCompositeShape*)shape;
00424             comp->RegisterYourself();
00425          } else {
00426             gGeoManager->AddShape(shape);
00427          }
00428       }
00429       shape = fNode->GetRightShape();
00430       if (!gGeoManager->GetListOfShapes()->FindObject(shape)) {
00431          if (shape->IsComposite()) {
00432             comp = (TGeoCompositeShape*)shape;
00433             comp->RegisterYourself();
00434          } else {
00435             gGeoManager->AddShape(shape);
00436          }
00437       }
00438    }
00439 }
00440 
00441 //_____________________________________________________________________________
00442 Double_t TGeoCompositeShape::Safety(Double_t *point, Bool_t in) const
00443 {
00444 // computes the closest distance from given point to this shape, according
00445 // to option. The matching point on the shape is stored in spoint.
00446    if (fNode) return fNode->Safety(point,in);
00447    return 0.;
00448 }
00449 
00450 //_____________________________________________________________________________
00451 void TGeoCompositeShape::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
00452 {
00453 // Save a primitive as a C++ statement(s) on output stream "out".
00454    if (TObject::TestBit(kGeoSavePrimitive)) return;
00455    if (fNode) fNode->SavePrimitive(out,option);
00456    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
00457    out << "   TGeoShape *" << GetPointerName() << " = new TGeoCompositeShape(\"" << GetName() << "\", pBoolNode);" << endl;
00458    if (strlen(GetTitle())) out << "   " << GetPointerName() << "->SetTitle(\"" << GetTitle() << "\");" << endl;
00459    TObject::SetBit(TGeoShape::kGeoSavePrimitive);
00460 }
00461 
00462 //_____________________________________________________________________________
00463 void TGeoCompositeShape::SetPoints(Double_t *points) const
00464 {
00465 // create points for a composite shape
00466    if (fNode) fNode->SetPoints(points);
00467 }
00468 
00469 //_____________________________________________________________________________
00470 void TGeoCompositeShape::SetPoints(Float_t *points) const
00471 {
00472 // create points for a composite shape
00473    if (fNode) fNode->SetPoints(points);
00474 }
00475 
00476 //_____________________________________________________________________________
00477 void TGeoCompositeShape::Sizeof3D() const
00478 {
00479 // compute size of this 3D object
00480    if (fNode) fNode->Sizeof3D();
00481 }
00482 
00483 //_____________________________________________________________________________
00484 Int_t TGeoCompositeShape::GetNmeshVertices() const
00485 {
00486 // Return number of vertices of the mesh representation
00487    if (!fNode) return 0;
00488    return fNode->GetNpoints();
00489 }

Generated on Tue Jul 5 14:12:55 2011 for ROOT_528-00b_version by  doxygen 1.5.1