Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /DD4hep/DDCore/src/plugins/ShapePlugins.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
0015 #include <DD4hep/DetFactoryHelper.h>
0016 #include <DD4hep/Printout.h>
0017 #include <XML/Utilities.h>
0018 #include <DD4hep/ShapeTags.h>
0019 #include <TGeoScaledShape.h>
0020 #include <TGeoShapeAssembly.h>
0021 #include <TSystem.h>
0022 #include <TClass.h>
0023 
0024 // C/C++ include files
0025 #include <fstream>
0026 #include <memory>
0027 
0028 using namespace dd4hep;
0029 using namespace dd4hep::detail;
0030 
0031 /// Plugin to create a scaled shape
0032 /**
0033  *  The xml entity 'e' must look like the following: 
0034  *  - name is optional, x,y,z are the values of scaling.
0035  *  - <shape>: some shape understood by a DD4hep factory.
0036  * 
0037  *  <some-tag name="my-solid" x="1.0" y="2.0" z="3.0" ... further xml-attributes not looked at .... >
0038  *       <shape>  ......  </shape>
0039  *       ... further optional xml-elements not looked at .... 
0040  *  </some-tag>
0041  *
0042  *  \author  M.Frank
0043  *  \version 1.0
0044  */
0045 static Handle<TObject> create_Scaled(Detector&, xml_h e)   {
0046   xml_dim_t scale(e);
0047   Solid shape(xml_comp_t(scale.child(_U(shape))).createShape());
0048   Solid solid = Scale(shape.ptr(), scale.x(1.0), scale.y(1.0), scale.z(1.0));
0049   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0050   return solid;
0051 }
0052 DECLARE_XML_SHAPE(Scale__shape_constructor,create_Scaled)
0053 
0054 /// Plugin to create an assembly shape
0055 /**
0056  *  The xml entity 'e' must look like the following: 
0057  *  - name is optional
0058  *
0059  *  <some-tag name="my-assembly"  ......further xml-attributes not looked at .... >
0060  *       ... further optional xml-elements not looked at .... 
0061  *  </some-tag>
0062  *
0063  *  \author  M.Frank
0064  *  \version 1.0
0065  */
0066 static Handle<TObject> create_Assembly(Detector&, xml_h e)   {
0067   xml_dim_t dim(e);
0068   Solid solid = Handle<TNamed>(new TGeoShapeAssembly());
0069   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0070   return solid;
0071 }
0072 DECLARE_XML_SHAPE(Assembly__shape_constructor,create_Assembly)
0073 
0074 /// Plugin to create a 3D box
0075 /**
0076  *  The xml entity 'e' must look like the following: 
0077  *  - name is optional, x,y,z are the dimensions
0078  * 
0079  *  <some-tag name="my-box" x="1.0*cm" y="2.0*cm" z="3.0*cm" ... further xml-attributes not looked at .... >
0080  *       ... further optional xml-elements not looked at .... 
0081  *  </some-tag>
0082  *
0083  *  \author  M.Frank
0084  *  \version 1.0
0085  */
0086 static Handle<TObject> create_Box(Detector&, xml_h e)   {
0087   xml_dim_t dim(e);
0088   Solid solid = Box(dim.dx(),dim.dy(),dim.dz());
0089   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0090   return solid;
0091 }
0092 DECLARE_XML_SHAPE(Box__shape_constructor,create_Box)
0093 
0094 /// Plugin to create a half-space
0095 /**
0096  *  The xml entity 'e' must look like the following: 
0097  *  - name is optional
0098  * 
0099  *  <some-tag name="my-box" ... further xml-attributes not looked at .... >
0100  *     <point  x="1.0*cm" y="2.0*cm" z="3.0*cm"/>
0101  *     <normal x="1.0" y="0.0" z="0.0"/>
0102  *       ... further optional xml-elements not looked at .... 
0103  *  </some-tag>
0104  *
0105  *  \author  M.Frank
0106  *  \version 1.0
0107  */
0108 static Handle<TObject> create_HalfSpace(Detector&, xml_h e)   {
0109   xml_dim_t dim(e);
0110   xml_dim_t point  = e.child(_U(point));
0111   xml_dim_t normal = e.child(_U(normal));
0112   double p[3] = { point.x(),  point.y(),  point.z()};
0113   double n[3] = { normal.x(), normal.y(), normal.z()};
0114   Solid solid = HalfSpace(p, n);
0115   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0116   return solid;
0117 }
0118 DECLARE_XML_SHAPE(HalfSpace__shape_constructor,create_HalfSpace)
0119 
0120 /// Plugin to create a cone
0121 /**
0122  *  The xml entity 'element' must look like the following: 
0123  *  - name is optional, rmin is optional
0124  *  <some-tag name="my-cone" z="10*cm" rmin1="1*cm" rmax1="2.cm" rmin2="2*cm" rmax2="4*cm" 
0125  *                           ... further xml-attributes not looked at .... >
0126  *       ... further optional xml-elements not looked at .... 
0127  *  </some-tag>
0128  *
0129  *  \author  M.Frank
0130  *  \version 1.0
0131  */
0132 static Handle<TObject> create_Cone(Detector&, xml_h element)   {
0133   xml_dim_t e(element);
0134   double rmi1 = e.rmin1(0.0), rma1 = e.rmax1();
0135   Solid solid = Cone(e.z(0.0), rmi1, rma1, e.rmin2(rmi1), e.rmax2(rma1));
0136   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0137   return solid;
0138 }
0139 DECLARE_XML_SHAPE(Cone__shape_constructor,create_Cone)
0140 
0141 /// Plugin to create a poly-cone
0142 /**
0143  *  The xml entity 'element' must look like the following: 
0144  *  - name is optional, startphi, deltaphi are optional
0145  * 
0146  *  <some-tag name="my-polycone" startphi="0*rad" deltaphi="pi" ... further xml-attributes not looked at .... >
0147  *     <zplane rmin="1.0*cm" rmax="2.0*cm"/>
0148  *     <zplane rmin="2.0*cm" rmax="4.0*cm"/>
0149  *     <zplane rmin="3.0*cm" rmax="6.0*cm"/>
0150  *     <zplane rmin="4.0*cm" rmax="8.0*cm"/>
0151  *     <zplane rmin="5.0*cm" rmax="10.0*cm"/>
0152  *       ... further optional xml-elements not looked at .... 
0153  *  </some-tag>
0154  *
0155  *  \author  M.Frank
0156  *  \version 1.0
0157  */
0158 static Handle<TObject> create_Polycone(Detector&, xml_h element)   {
0159   xml_dim_t e(element);
0160   int num = 0;
0161   std::vector<double> rmin,rmax,z;
0162   double start = e.startphi(0e0), deltaphi = e.deltaphi(2*M_PI);
0163   for(xml_coll_t c(e,_U(zplane)); c; ++c, ++num)  {
0164     xml_comp_t plane(c);
0165     rmin.emplace_back(plane.rmin(0.0));
0166     rmax.emplace_back(plane.rmax());
0167     z.emplace_back(plane.z());
0168   }
0169   if ( num < 2 )  {
0170     throw std::runtime_error("PolyCone Shape> Not enough Z planes. minimum is 2!");
0171   }
0172   Solid solid = Polycone(start,deltaphi,rmin,rmax,z);
0173   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0174   return solid;
0175 }
0176 DECLARE_XML_SHAPE(Polycone__shape_constructor,create_Polycone)
0177 
0178 /// Plugin to create a cone-segment
0179 /**
0180  *  This shape implements for historical reasons two alternative constructors,
0181  *  which are automatically recognized depending on the supplied attributes.
0182  *
0183  *  The xml entity 'element' must look like the following: 
0184  *  - name is optional, rmin1, rmin2, startphi, deltaphi are optional
0185  *  <some-tag name="my-polycone" rmin1="1*cm" rmax1="2.cm"  rmin1="2*cm" rmax1="3.cm" 
0186  *                               startphi="0*rad" deltaphi="pi" ... further xml-attributes not looked at .... >
0187  *       ... further optional xml-elements not looked at .... 
0188  *  </some-tag>
0189  *  OR (deprecated):
0190  *  - name is optional, rmin1, rmin2, (phi1 or phi2) are optional
0191  *  <some-tag name="my-polycone" rmin1="1*cm" rmax1="2.cm"  rmin1="2*cm" rmax1="3.cm" 
0192  *                               phi1="0*rad" phi2="pi" ... further xml-attributes not looked at .... >
0193  *       ... further optional xml-elements not looked at .... 
0194  *  </some-tag>
0195  *
0196  *  \author  M.Frank
0197  *  \version 1.0
0198  */
0199 static Handle<TObject> create_ConeSegment(Detector&, xml_h element)   {
0200   Solid solid;
0201   xml_dim_t e(element);
0202   xml_attr_t aphi = element.attr_nothrow(_U(phi1));
0203   xml_attr_t bphi = element.attr_nothrow(_U(phi2));
0204   if ( aphi || bphi )  {
0205     double phi1 = e.phi1(0.0);
0206     double phi2 = e.phi2(2*M_PI);
0207     /// Old naming: angles from [phi1,phi2]
0208     solid = ConeSegment(e.dz(),e.rmin1(0.0),e.rmax1(),e.rmin2(0.0),e.rmax2(),phi1,phi2);
0209   }
0210   else  {
0211     double start_phi = e.startphi(0.0);
0212     double delta_phi = e.deltaphi(2*M_PI);
0213     while ( start_phi > 2.0*M_PI ) start_phi -= 2.0*M_PI;
0214     /// New naming: angles from [startphi,startphi+deltaphi]
0215     solid = ConeSegment(e.dz(),e.rmin1(0.0),e.rmax1(),e.rmin2(0.0),e.rmax2(),start_phi,start_phi+delta_phi);
0216   }
0217   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0218   return solid;
0219 }
0220 DECLARE_XML_SHAPE(ConeSegment__shape_constructor,create_ConeSegment)
0221 
0222 /// Plugin to create a tube
0223 /**
0224  *  This shape implements for historical reasons two alternative constructors,
0225  *  which are automatically recognized depending on the supplied attributes.
0226  *
0227  *  The xml entity 'element' must look like the following: 
0228  *  - name is optional, rmin, startphi, deltaphi are optional
0229  *  <some-tag name="my-tube" rmin="1*cm" rmax="2.cm" 
0230  *                           startphi="0*rad" deltaphi="pi" ... further xml-attributes not looked at .... >
0231  *       ... further optional xml-elements not looked at .... 
0232  *  </some-tag>
0233  *  OR (deprecated):
0234  *  - name is optional, rmin, (phi1 or phi2) are optional
0235  *  <some-tag name="my-tube" rmin="1*cm" rmax="2.cm" 
0236  *                           phi1="0*rad" phi2="pi" ... further xml-attributes not looked at .... >
0237  *       ... further optional xml-elements not looked at .... 
0238  *  </some-tag>
0239  *
0240  *  \author  M.Frank
0241  *  \version 1.0
0242  */
0243 static Handle<TObject> create_Tube(Detector&, xml_h element)   {
0244   Solid solid;
0245   xml_dim_t e(element);
0246   xml_attr_t aphi = element.attr_nothrow(_U(phi1));
0247   xml_attr_t bphi = element.attr_nothrow(_U(phi2));
0248   if ( aphi || bphi )  {
0249     double phi1 = e.phi1(0.0);
0250     double phi2 = e.phi2(2*M_PI);
0251     solid = Tube(e.rmin(0.0),e.rmax(),e.dz(0.0),phi1, phi2);
0252   }
0253   else  {
0254     double phi1 = e.startphi(0.0);
0255     double phi2 = phi1 + e.deltaphi(2*M_PI);
0256     solid = Tube(e.rmin(0.0),e.rmax(),e.dz(0.0),phi1,phi2);
0257   }
0258   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0259   return solid;
0260 }
0261 DECLARE_XML_SHAPE(Tube__shape_constructor,create_Tube)
0262 
0263 /// Plugin to create a twisted tube
0264 /**
0265  *
0266  *  \author  M.Frank
0267  *  \version 1.0
0268  */
0269 static Handle<TObject> create_TwistedTube(Detector&, xml_h element)   {
0270   xml_dim_t e(element);
0271   Solid solid;
0272   int nseg = 1;
0273   double zpos = 0.0, zneg = 0.0;
0274   if ( element.attr_nothrow(_U(nsegments)) )  {
0275     nseg = e.nsegments();
0276   }
0277   if ( element.attr_nothrow(_U(dz)) )  {
0278     zneg = -1.0*(zpos = e.dz());
0279   }
0280   else   {
0281     zpos = e.zpos();
0282     zneg = e.zneg();
0283   }
0284   solid = TwistedTube(e.twist(0.0), e.rmin(0.0),e.rmax(),zneg, zpos, nseg, e.deltaphi(2*M_PI));
0285 
0286   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0287   return solid;
0288 }
0289 DECLARE_XML_SHAPE(TwistedTube__shape_constructor,create_TwistedTube)
0290 
0291 /// Plugin to create a cut tube
0292 /**
0293  *
0294  *  \author  M.Frank
0295  *  \version 1.0
0296  */
0297 static Handle<TObject> create_CutTube(Detector&, xml_h element)   {
0298   xml_dim_t e(element);
0299   Solid solid = CutTube(e.rmin(0.0),e.rmax(),e.dz(),
0300                         e.attr<double>(_U(phi1)),
0301                         e.attr<double>(_U(phi2)),
0302                         e.attr<double>(_U(lx)),
0303                         e.attr<double>(_U(ly)),
0304                         e.attr<double>(_U(lz)),
0305                         e.attr<double>(_U(tx)),
0306                         e.attr<double>(_U(ty)),
0307                         e.attr<double>(_U(tz)));
0308   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0309   return solid;
0310 }
0311 DECLARE_XML_SHAPE(CutTube__shape_constructor,create_CutTube)
0312 
0313 /// Plugin to create an elliptical tube
0314 /**
0315  *
0316  *  \author  M.Frank
0317  *  \version 1.0
0318  */
0319 static Handle<TObject> create_EllipticalTube(Detector&, xml_h element)   {
0320   xml_dim_t e(element);
0321   Solid solid = EllipticalTube(e.a(),e.b(),e.dz());
0322   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0323   return solid;
0324 }
0325 DECLARE_XML_SHAPE(EllipticalTube__shape_constructor,create_EllipticalTube)
0326 
0327 /// Plugin to create an ttruncated tube
0328 /**
0329  *
0330  *  \author  M.Frank
0331  *  \version 1.0
0332  */
0333 static Handle<TObject> create_TruncatedTube(Detector&, xml_h element)   {
0334   xml_dim_t e(element);
0335   double sp = e.startphi(0.0), dp = e.deltaphi(2*M_PI);
0336   Solid solid = TruncatedTube(e.dz(), e.rmin(0.0), e.rmax(), sp, dp,
0337                               e.attr<double>(xml_tag_t("cutAtStart")),
0338                               e.attr<double>(xml_tag_t("cutAtDelta")),
0339                               e.attr<bool>(xml_tag_t("cutInside")));
0340   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0341   return solid;
0342 }
0343 DECLARE_XML_SHAPE(TruncatedTube__shape_constructor,create_TruncatedTube)
0344 
0345 /// Plugin to create a trap
0346 /**
0347  *  The xml entity 'element' must look like the following: 
0348  *  - name is optional, rmin is optional
0349  *  <some-tag name="my-trap" dx="1*cm" dy="2.cm" dz="2*cm" pLTX="..." ... further xml-attributes not looked at .... >
0350  *       ... further optional xml-elements not looked at .... 
0351  *  </some-tag>
0352  *  This constructor is a reduces form for a subset of trap shapes.
0353  *
0354  *  OR:
0355  *  name is optional, z, theta, phi, alpha1, alpha2, x3, x4, y2 is optional
0356  *  <some-tag name="my-trap" z="2*cm" theta="0" phi="0"
0357  *                           y1="1*cm" x1="1*cm" x2="2.cm" alpha1="0" 
0358  *                           y2="2.cm" x3="2*cm" x4="2*cm" alpha2="pi"
0359  *                            ... further xml-attributes not looked at .... >
0360  *  </some-tag>
0361  *
0362  *  \author  M.Frank
0363  *  \version 1.0
0364  */
0365 static Handle<TObject> create_Trap(Detector&, xml_h element)   {
0366   xml_dim_t e(element);
0367   Solid solid;
0368   if ( e.hasAttr(_U(dz)) )   {
0369     solid = Trap(e.dz(),e.dy(),e.dx(),_toDouble(_Unicode(pLTX)));
0370   }
0371   else   {
0372     xml_attr_t attr = 0;
0373     double x1 = e.x1();
0374     double x2 = e.x2();
0375     double x3 = (attr=element.attr_nothrow(_U(x3))) ? element.attr<double>(attr) : x1;
0376     double x4 = (attr=element.attr_nothrow(_U(x4))) ? element.attr<double>(attr) : x2;
0377     double y1 = e.y1();
0378     double y2 = (attr=element.attr_nothrow(_U(y2))) ? element.attr<double>(attr) : y1;
0379     solid = Trap(e.z(0.0),e.theta(0),e.phi(0),y1,x1,x2,e.alpha1(0),y2,x3,x4,e.alpha2(0));
0380   }
0381   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0382   return solid;
0383 }
0384 DECLARE_XML_SHAPE(Trap__shape_constructor,create_Trap)
0385 
0386 /// Plugin to create a pseudo trap
0387 /**
0388  *
0389  *  \author  M.Frank
0390  *  \version 1.0
0391  */
0392 static Handle<TObject> create_PseudoTrap(Detector&, xml_h element)   {
0393   xml_dim_t e(element);
0394   Solid solid = PseudoTrap(e.x1(),e.x2(),e.y1(),e.y2(),e.z(),e.radius(),e.attr<bool>(xml_tag_t("minusZ")));
0395   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0396   return solid;
0397 }
0398 DECLARE_XML_SHAPE(PseudoTrap__shape_constructor,create_PseudoTrap)
0399 
0400 /// Plugin to create a trd1
0401 /**
0402  *  The xml entity 'element' must look like the following: 
0403  *  - name is optional, z is optional
0404  *  <some-tag name="my-trd1" x1="1*cm" x2="2*cm" y="1*cm" z="2*cm" ... further xml-attributes not looked at .... >
0405  *       ... further optional xml-elements not looked at .... 
0406  *  </some-tag>
0407  *
0408  *  \author  M.Frank
0409  *  \version 1.0
0410  */
0411 static Handle<TObject> create_Trd1(Detector&, xml_h element)   {
0412   xml_dim_t e(element);
0413   Solid solid = Trd1(e.x1(),e.x2(),e.y(),e.z(0.0));
0414   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0415   return solid;
0416 }
0417 DECLARE_XML_SHAPE(Trd1__shape_constructor,create_Trd1)
0418 
0419 /// Plugin to create a trd2
0420 /**
0421  *  The xml entity 'element' must look like the following: 
0422  *  - name is optional, z is optional
0423  *  <some-tag name="my-trd2" x1="1*cm" x2="2*cm" y1="1*cm" y2="2*cm" z="2*cm" ... further xml-attributes not looked at .... >
0424  *       ... further optional xml-elements not looked at .... 
0425  *  </some-tag>
0426  *
0427  *  \author  M.Frank
0428  *  \version 1.0
0429  */
0430 static Handle<TObject> create_Trd2(Detector&, xml_h element)   {
0431   xml_dim_t e(element);
0432   Solid solid = Trd2(e.x1(),e.x2(),e.y1(),e.y2(),e.z(0.0));
0433   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0434   return solid;
0435 }
0436 DECLARE_XML_SHAPE(Trapezoid__shape_constructor,create_Trd2)
0437 DECLARE_XML_SHAPE(Trd2__shape_constructor,create_Trd2)
0438 
0439 /// Plugin to create a torus
0440 /**
0441  *  The xml entity 'element' must look like the following: 
0442  *  - name is optional, rmin, startphi, deltaphi are optional
0443  *  <some-tag name="my-torus" r="10*cm" rmin="1*cm" rmax="2.cm" 
0444                               startphi="0*rad" deltaphi="pi" ... further xml-attributes not looked at .... >
0445  *       ... further optional xml-elements not looked at .... 
0446  *  </some-tag>
0447  *  OR (deprecated):
0448  *  - name is optional, rmin, (phi1 or phi2) are optional
0449  *  <some-tag name="my-tube" r="10*cm" rmin="1*cm" rmax="2.cm" 
0450  *                           phi1="0*rad" phi2="2*pi" ... further xml-attributes not looked at .... >
0451  *       ... further optional xml-elements not looked at .... 
0452  *  </some-tag>
0453  *
0454  *  \author  M.Frank
0455  *  \version 1.0
0456  */
0457 static Handle<TObject> create_Torus(Detector&, xml_h element)   {
0458   Solid      solid;
0459   xml_dim_t  e(element);
0460   xml_attr_t aphi = element.attr_nothrow(_U(phi1));
0461   xml_attr_t bphi = element.attr_nothrow(_U(phi2));
0462   if ( aphi || bphi )  {
0463     double phi1 = e.phi1(0.0);
0464     double phi2 = e.phi2(2*M_PI);
0465     /// Old naming: angles from [phi1,phi2]
0466     solid = Torus(e.r(), e.rmin(0.0), e.rmax(), phi1, phi2-phi1);
0467   }
0468   else  {
0469     double start_phi = e.startphi(0.0);
0470     double delta_phi = e.deltaphi(2*M_PI);
0471     while ( start_phi > 2.0*M_PI ) start_phi -= 2.0*M_PI;
0472     /// TGeo naming: angles from [startphi,startphi+deltaphi]
0473     solid = Torus(e.r(), e.rmin(0.0), e.rmax(), start_phi, delta_phi);
0474   }
0475   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0476   return solid;
0477 }
0478 DECLARE_XML_SHAPE(Torus__shape_constructor,create_Torus)
0479 
0480 /// Sphere creation
0481 /** Allow for xml fragments of the form
0482  *  <sphere rmin="..." rmax="..."/>
0483  *  <sphere rmin="..." rmax="..." starttheta="..." endtheta="..."   startphi="..." endphi="..."/>
0484  *  <sphere rmin="..." rmax="..." starttheta="..." deltatheta="..." startphi="..." deltaphi="..."/>
0485  *
0486  *  Defaults:
0487  *  starttheta = 0e0
0488  *  endtheta   = starttheta + pi
0489  *  startphi   = 0e0
0490  *  endphi     = startphi + 2*pi
0491  * 
0492  *  \date   04/09/2020
0493  *  \author M.Frank
0494  */
0495 static Handle<TObject> create_Sphere(Detector&, xml_h element)   {
0496   xml_dim_t e(element);
0497   double startphi   = e.phi(0e0);
0498   double endphi     = startphi + 2.*M_PI;
0499   double starttheta = e.theta(0e0);
0500   double endtheta   = starttheta + M_PI;
0501 
0502   if ( e.hasAttr(_U(startphi)) )  {
0503     startphi = e.startphi();
0504     endphi   = startphi + 2.*M_PI;
0505   }
0506   if ( e.hasAttr(_U(endphi))   )
0507     endphi = e.endphi();
0508   else if ( e.hasAttr(_U(deltaphi)) )
0509     endphi = startphi + e.deltaphi();
0510 
0511   if ( e.hasAttr(_U(starttheta)) )   {
0512     starttheta = e.starttheta();
0513     endtheta = starttheta + M_PI;
0514   }
0515   if ( e.hasAttr(_U(endtheta))   )
0516     endtheta = e.endtheta();
0517   else if ( e.hasAttr(_U(deltatheta)) )
0518     endtheta = starttheta + e.deltatheta();
0519 
0520   Solid solid = Sphere(e.rmin(0e0), e.rmax(), starttheta, endtheta, startphi, endphi);
0521   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0522   return solid;
0523 }
0524 DECLARE_XML_SHAPE(Sphere__shape_constructor,create_Sphere)
0525 
0526 /// Plugin to create a paraboloid
0527 /**
0528  *  The xml entity 'element' must look like the following: 
0529  *  - name is optional, rmin is optional
0530  *  <some-tag name="my-paraboloid" rmin="1*cm" rmax="2*cm" dz="1*cm" ... further xml-attributes not looked at .... >
0531  *       ... further optional xml-elements not looked at .... 
0532  *  </some-tag>
0533  *
0534  *  \author  M.Frank
0535  *  \version 1.0
0536  */
0537 static Handle<TObject> create_Paraboloid(Detector&, xml_h element)   {
0538   xml_dim_t e(element);
0539   Solid solid = Paraboloid(e.rmin(0.0),e.rmax(),e.dz());
0540   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0541   return solid;
0542 }
0543 DECLARE_XML_SHAPE(Paraboloid__shape_constructor,create_Paraboloid)
0544 
0545 /// Plugin to create a hyperboloid
0546 /**
0547  *  The xml entity 'element' must look like the following: 
0548  *  - name is optional, rmin is optional
0549  *  <some-tag name="my-hyperboloid" rmin="1*cm" inner_stereo="pi/2" 
0550  *                                  rmax="2*cm" outer_stereo="pi/2"
0551  *                                  dz="5*cm" ... further xml-attributes not looked at .... >
0552  *       ... further optional xml-elements not looked at .... 
0553  *  </some-tag>
0554  *
0555  *  \author  M.Frank
0556  *  \version 1.0
0557  */
0558 static Handle<TObject> create_Hyperboloid(Detector&, xml_h element)   {
0559   xml_dim_t e(element);
0560   Solid solid = Hyperboloid(e.rmin(), e.inner_stereo(), e.rmax(), e.outer_stereo(), e.dz());
0561   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0562   return solid;
0563 }
0564 DECLARE_XML_SHAPE(Hyperboloid__shape_constructor,create_Hyperboloid)
0565 
0566 /// Plugin to create a regular polyhedron
0567 /**
0568  *  The xml entity 'element' must look like the following: 
0569  *  - name is optional
0570  *  <some-tag name="my-polyhedron"  numsides="5" rmin="1*cm" rmax="2*cm" dz="5*cm"
0571  *                                  dz="5*cm" ... further xml-attributes not looked at .... >
0572  *       ... further optional xml-elements not looked at .... 
0573  *  </some-tag>
0574  *
0575  *  \author  M.Frank
0576  *  \version 1.0
0577  */
0578 static Handle<TObject> create_PolyhedraRegular(Detector&, xml_h element)   {
0579   xml_dim_t e(element);
0580   Solid solid = PolyhedraRegular(e.numsides(),e.rmin(),e.rmax(),e.dz());
0581   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0582   return solid;
0583 }
0584 DECLARE_XML_SHAPE(PolyhedraRegular__shape_constructor,create_PolyhedraRegular)
0585 
0586 /// Plugin to create a irregular polyhedron
0587 /**
0588  *  The xml entity 'element' must look like the following: 
0589  *  - name is optional
0590  *  <some-tag name="my-polyhedron"  numsides="5" startphi="0" deltaphi="2*pi" ... further xml-attributes not looked at .... >
0591  *    <plane rmin="1*cm" rmax="2*cm" z="1*cm"/>
0592  *    <plane rmin="2*cm" rmax="3*cm" z="2*cm"/>
0593  *    <plane rmin="2*cm" rmax="4*cm" z="4*cm"/>
0594  *       ... further optional xml-elements not looked at .... 
0595  *  </some-tag>
0596  *
0597  *  \author  M.Frank
0598  *  \version 1.0
0599  */
0600 static Handle<TObject> create_Polyhedra(Detector&, xml_h element)   {
0601   xml_dim_t e(element);
0602   std::vector<double> z, rmin, rmax;
0603   for ( xml_coll_t c(e,_U(plane)); c; ++c )  {
0604     xml_comp_t plane(c);
0605     rmin.emplace_back(plane.rmin());
0606     rmax.emplace_back(plane.rmax());
0607     z.emplace_back(plane.z());
0608   }
0609   Solid solid = Polyhedra(e.numsides(),e.startphi(),e.deltaphi(),z,rmin,rmax);
0610   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0611   return solid;
0612 }
0613 DECLARE_XML_SHAPE(Polyhedra__shape_constructor,create_Polyhedra)
0614 
0615 /// Plugin factory to create extruded polygons
0616 /**
0617  *
0618  *  \author  M.Frank
0619  *  \version 1.0
0620  */
0621 static Handle<TObject> create_ExtrudedPolygon(Detector&, xml_h element)   {
0622   xml_dim_t e(element);
0623   std::vector<double> pt_x, pt_y, sec_z, sec_x, sec_y, sec_scale;
0624   for ( xml_coll_t sec(element, _U(section)); sec; ++sec )   {
0625     xml_dim_t section(sec);
0626     sec_z.emplace_back(section.attr<double>(_U(z)));
0627     sec_x.emplace_back(section.attr<double>(_U(x)));
0628     sec_y.emplace_back(section.attr<double>(_U(y)));
0629     sec_scale.emplace_back(section.attr<double>(_U(scale),1.0));
0630   }
0631   for ( xml_coll_t pt(element, _U(point)); pt; ++pt )   {
0632     xml_dim_t point(pt);
0633     pt_x.emplace_back(point.attr<double>(_U(x)));
0634     pt_y.emplace_back(point.attr<double>(_U(y)));
0635   }
0636   Solid solid = ExtrudedPolygon(pt_x, pt_y, sec_z, sec_x, sec_y, sec_scale);
0637   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0638   return solid;
0639 }
0640 DECLARE_XML_SHAPE(ExtrudedPolygon__shape_constructor,create_ExtrudedPolygon)
0641 
0642 /// Plugin factory to create arbitrary 8-point solids
0643 /**
0644  *
0645  *  \author  M.Frank
0646  *  \version 1.0
0647  */
0648 static Handle<TObject> create_EightPointSolid(Detector&, xml_h element)   {
0649   xml_dim_t e(element);
0650   double v[8][2];
0651   int num = 0;
0652   memset(&v[0][0],0,sizeof(v));
0653   for(xml_coll_t c(e,_Unicode(vertex)); c && num<8; ++c, ++num)  {
0654     xml_comp_t vtx(c);
0655     v[num][0] = vtx.x();
0656     v[num][1] = vtx.y();
0657   }
0658   Solid solid = EightPointSolid(e.dz(),&v[0][0]);
0659   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0660   return solid;
0661 }
0662 DECLARE_XML_SHAPE(EightPointSolid__shape_constructor,create_EightPointSolid)
0663 
0664 /// Plugin factory to create tessellated shapes
0665 /**
0666  *
0667  *  \author  M.Frank
0668  *  \version 1.0
0669  */
0670 static Handle<TObject> create_TessellatedSolid(Detector&, xml_h element)   {
0671   xml_dim_t e(element);
0672   std::vector<TessellatedSolid::Vertex> vertices;
0673   for ( xml_coll_t vtx(element, _U(vertex)); vtx; ++vtx )   {
0674     xml_dim_t v(vtx);
0675     vertices.emplace_back(v.x(), v.y(), v.z());
0676   }
0677   int num_facets = 0;
0678   for ( xml_coll_t facet(element, _U(facet)); facet; ++facet ) ++num_facets;
0679   TessellatedSolid solid = TessellatedSolid(num_facets);
0680   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0681   for ( xml_coll_t facet(element, _U(facet)); facet; ++facet )   {
0682     xml_dim_t f(facet);
0683     size_t i0 = f.attr<size_t>(_U(v0));
0684     size_t i1 = f.attr<size_t>(_U(v1));
0685     size_t i2 = f.attr<size_t>(_U(v2));
0686     if ( f.hasAttr(_U(v3)) )   {
0687       size_t i3 = f.attr<size_t>(_U(v3));
0688       solid.addFacet(vertices[i0], vertices[i1], vertices[i2], vertices[i3]);
0689     }
0690     else   {
0691       solid.addFacet(vertices[i0], vertices[i1], vertices[i2]);
0692     }
0693   }
0694   return solid;
0695 }
0696 DECLARE_XML_SHAPE(TessellatedSolid__shape_constructor,create_TessellatedSolid)
0697 
0698 /** Plugin function for creating a boolean solid from an xml element <shape type=\"BooleanShape\"/>. 
0699  *  Expects exactly two child elements <shape/> and a std::string attribute 'operation', which is one of
0700  *  'subtraction', 'union' or 'intersection'. Optionally <position/> and/or <rotation/> can be specified.
0701  *  More complex boolean solids can be created by nesting the xml elements accordingly.
0702  *
0703  * @date 03/2015
0704  * @author F.Gaede, CERN/DESY
0705  */
0706 static Handle<TObject> create_BooleanShape(Detector&, xml_h element)   {
0707 
0708   xml_det_t e(element);
0709 
0710   // get the two shape elements
0711   xml_coll_t c( e ,_U(shape)) ;
0712   xml_comp_t x_shape1( c ) ;
0713   ++c ;
0714   xml_comp_t x_shape2( c ) ;
0715   
0716   // and create solids
0717   Solid solid1( xml_comp_t( std::move(x_shape1) ).createShape()) ;
0718   Solid solid2( xml_comp_t( std::move(x_shape2) ).createShape())  ;
0719 
0720 
0721   std::string op = e.attr<std::string>(_U(operation)) ;
0722   std::transform( op.begin(), op.end(), op.begin(), ::tolower);
0723   
0724   Solid resultSolid ;
0725 
0726   bool useRot(false), usePos(false), useTrans(false); 
0727   Position    pos ;
0728   RotationZYX rot ;
0729 
0730   if( e.hasChild( _U(transformation) ) ) {
0731     useTrans = true ;
0732   }
0733   if( e.hasChild( _U(position) ) ) {
0734     usePos = true ;
0735     xml_comp_t x_pos = e.position();
0736     pos = Position( x_pos.x(0.0),x_pos.y(0.0),x_pos.z(0.0) );  
0737   }
0738   if( e.hasChild( _U(rotation) ) ) {
0739     useRot = true ;
0740     xml_comp_t  x_rot = e.rotation();
0741     rot = RotationZYX( x_rot.z(0.0),x_rot.y(0.0),x_rot.x(0.0) ) ;
0742   }
0743 
0744   if( op == "subtraction" ) {
0745     if ( useTrans )   {
0746       Transform3D tr = xml::createTransformation(e.child(_U(transformation)));
0747       resultSolid = SubtractionSolid(solid1, solid2, tr);
0748     }
0749     else if( useRot && usePos )   {
0750       resultSolid = SubtractionSolid(solid1, solid2, Transform3D(rot, pos));
0751     }
0752     else if( useRot ) 
0753       resultSolid = SubtractionSolid(solid1, solid2, rot);
0754     else if( usePos) 
0755       resultSolid = SubtractionSolid(solid1, solid2, pos);
0756     else
0757       resultSolid = SubtractionSolid(solid1, solid2);
0758   }
0759   else if( op == "union" ) {
0760     if ( useTrans )  {
0761       Transform3D tr = xml::createTransformation(e.child(_U(transformation)));
0762       resultSolid = UnionSolid(solid1, solid2, tr);
0763     }
0764     else if( useRot && usePos )
0765       resultSolid = UnionSolid(solid1, solid2, Transform3D(rot, pos));
0766     else if( useRot) 
0767       resultSolid = UnionSolid(solid1, solid2, rot);
0768     else if( usePos)
0769       resultSolid = UnionSolid(solid1, solid2, pos);
0770     else
0771       resultSolid = UnionSolid(solid1, solid2);
0772   }
0773   else if( op == "intersection" ) {
0774     if ( useTrans )  {
0775       Transform3D tr = xml::createTransformation(e.child(_U(transformation)));
0776       resultSolid = IntersectionSolid(solid1, solid2, tr);
0777     }
0778     else if( useRot && usePos )
0779       resultSolid = IntersectionSolid(solid1, solid2, Transform3D(rot, pos));
0780     else if( useRot) 
0781       resultSolid = IntersectionSolid(solid1, solid2, rot);
0782     else if( usePos) 
0783       resultSolid = IntersectionSolid(solid1, solid2, pos);
0784     else
0785       resultSolid = IntersectionSolid(solid1, solid2) ;
0786 
0787   } else  {
0788 
0789     throw std::runtime_error(std::string(" create_BooleanShape - unknown operation given: ") + op + 
0790                              std::string(" - needs to be one of 'subtraction','union' or 'intersection' ") ) ;  
0791   }
0792   Solid solid = resultSolid ;
0793   if ( e.hasAttr(_U(name)) ) solid->SetName(e.attr<std::string>(_U(name)).c_str());
0794   return solid;
0795 }
0796 DECLARE_XML_SHAPE(BooleanShapeOld__shape_constructor,create_BooleanShape)
0797 
0798 
0799 static Handle<TObject> create_BooleanMulti(Detector& description, xml_h element)   {
0800   xml_det_t e(element);
0801   // get the two shape elements
0802   Solid tmp, solid, result;
0803   int flag = 0;
0804   Transform3D position, rotation, trafo;
0805 
0806   xml_attr_t attr = 0;
0807   std::string op = e.attr<std::string>(_U(operation)) ;
0808   std::transform( op.begin(), op.end(), op.begin(), ::tolower);
0809   //printout(ALWAYS,"","Boolean shape ---> %s",op.c_str());
0810   for (xml_coll_t i(e ,_U(star)); i; ++i )   {
0811     xml_comp_t x_elt = i;
0812     std::string tag = x_elt.tag();
0813     if ( tag == "shape" && !result.isValid() )  {
0814       result = xml::createShape(description, x_elt.typeStr(), x_elt);
0815       if ( (attr=i.attr_nothrow(_U(name))) ) result->SetName(i.attr<std::string>(attr).c_str());
0816       flag = 1;
0817     }
0818     else if ( tag == "shape" && !solid.isValid() )  {
0819       solid = xml::createShape(description,  x_elt.typeStr(), x_elt); 
0820       if ( (attr=i.attr_nothrow(_U(name))) ) result->SetName(i.attr<std::string>(attr).c_str());
0821       flag = 3;
0822     }
0823     else if ( result.isValid() && solid.isValid() )  {
0824       if ( tag == "position" )  {
0825         if      ( flag == 4 ) trafo = position  * trafo;
0826         else if ( flag == 5 ) trafo = (position * rotation) * trafo;
0827         Position pos(x_elt.x(0), x_elt.y(0), x_elt.z(0));
0828         position = Transform3D(pos);
0829         rotation = Transform3D();
0830         flag = 4;
0831       }
0832       else if ( tag == "positionRZPhi" )  {
0833         if      ( flag == 4 ) trafo = position  * trafo;
0834         else if ( flag == 5 ) trafo = (position * rotation) * trafo;
0835         ROOT::Math::RhoZPhiVector pos(x_elt.r(0), x_elt.z(0), x_elt.phi(0));
0836         position = Transform3D(pos);
0837         rotation = Transform3D();
0838         flag = 4;
0839       }
0840       else if ( tag == "transformation" )   {
0841         if      ( flag == 4 ) trafo = position  * trafo;
0842         else if ( flag == 5 ) trafo = (position * rotation) * trafo;
0843         Transform3D tr = xml::createTransformation(x_elt);
0844         trafo   = tr * trafo;
0845         position = rotation = Transform3D();
0846         flag = 3;
0847       }
0848       else if ( tag == "rotation" )  {
0849         rotation = Transform3D(RotationZYX(x_elt.z(0), x_elt.y(0), x_elt.x(0)));
0850         flag = 5;
0851       }
0852       else if ( tag == "shape" )   {
0853         //cout << solid.name() << " Flag:" << flag << endl;
0854         if      ( flag == 4 ) trafo = position  * trafo;
0855         else if ( flag == 5 ) trafo = (position * rotation) * trafo;
0856         tmp = Solid();
0857         if( op == "subtraction" )
0858           tmp = SubtractionSolid(result, solid, trafo);
0859         else if( op == "union" )
0860           tmp = UnionSolid(result, solid, trafo);
0861         else if( op == "intersection" )
0862           tmp = IntersectionSolid(result, solid, trafo);
0863         else  {          // Error!
0864           throw std::runtime_error(" create_BooleanShape - unknown operation given: " + op + 
0865                                    " - needs to be one of 'subtraction','union' or 'intersection' ");  
0866         }
0867         result = tmp;
0868         trafo  = position = rotation = Transform3D();
0869         solid = xml::createShape(description,  x_elt.typeStr(), x_elt); 
0870         if ( (attr=i.attr_nothrow(_U(name))) ) result->SetName(i.attr<std::string>(attr).c_str());
0871         flag = 3;
0872       }
0873     }
0874   }
0875   if ( flag >= 3 )  {
0876     //cout << solid.name() << " Flag:" << flag << endl;
0877     if      ( flag == 4 ) trafo = position  * trafo;
0878     else if ( flag == 5 ) trafo = (position * rotation) * trafo;
0879     if( op == "subtraction" )
0880       tmp = SubtractionSolid(result, solid, trafo);
0881     else if( op == "union" )
0882       tmp = UnionSolid(result, solid, trafo);
0883     else if( op == "intersection" )
0884       tmp = IntersectionSolid(result, solid, trafo);
0885     else  {          // Error!
0886       throw std::runtime_error(" create_BooleanShape - unknown operation given: " + op + 
0887                                " - needs to be one of 'subtraction','union' or 'intersection' ");  
0888     }
0889     result = tmp;
0890   }
0891   attr = element.attr_nothrow(_U(name));
0892   if ( attr )   {
0893     std::string nam = element.attr<std::string>(attr);
0894     result->SetName(nam.c_str());
0895   }
0896   return result;
0897 }
0898 DECLARE_XML_SHAPE(BooleanShape__shape_constructor,create_BooleanMulti)
0899 
0900 /// Plugin factory to create arbitrary volumes using the xml::createStdVolume utility
0901 /**
0902  *  For details see the implementation in DDCore/src/XML/Utilities.cpp
0903  *
0904  *  \author  M.Frank
0905  *  \version 1.0
0906  */
0907 static Handle<TObject> create_std_volume(Detector& description, xml_h element)   {
0908   return xml::createStdVolume(description, element);
0909 }
0910 DECLARE_XML_VOLUME(DD4hep_StdVolume,create_std_volume)
0911 
0912 /// Plugin factory to create arbitrary volumes using the xml::createVolume utility
0913 /**
0914  *  For details see the implementation in DDCore/src/XML/Utilities.cpp
0915  *
0916  *  \author  M.Frank
0917  *  \version 1.0
0918  */
0919 static Handle<TObject> create_gen_volume(Detector& description, xml_h element)   {
0920   xml_dim_t   elt = element;
0921   std::string typ = elt.attr<std::string>(_U(type));
0922   return xml::createVolume(description, typ, element);
0923 }
0924 DECLARE_XML_VOLUME(DD4hep_GenericVolume,create_gen_volume)
0925 
0926 TGeoCombiTrans* createPlacement(const Rotation3D& iRot, const Position& iTrans) {
0927   double elements[9];
0928   iRot.GetComponents(elements);
0929   TGeoRotation r;
0930   r.SetMatrix(elements);
0931   TGeoTranslation t(iTrans.x(), iTrans.y(), iTrans.z());
0932   return new TGeoCombiTrans(t, r);
0933 }
0934 
0935 /// Plugin factory to create shapes for shape check tests
0936 /**
0937  *
0938  *  \author  M.Frank
0939  *  \version 1.0
0940  */
0941 static Ref_t create_shape(Detector& description, xml_h e, SensitiveDetector sens)  {
0942   xml_det_t    x_det     = e;
0943   std::string  name      = x_det.nameStr();
0944   xml_dim_t    x_reflect = x_det.child(_U(reflect), false);
0945   DetElement   det         (name,x_det.id());
0946   Material     mat       = description.air();
0947   Assembly     assembly    (name);
0948   PlacedVolume pv;
0949   int count = 0;
0950   
0951   printout(DEBUG,"TestShape","+++ Create shape: %s build type is: %s",
0952            name.c_str(), buildTypeName(description.buildType()).c_str());
0953   if ( x_det.hasChild(_U(material)) )  {
0954     mat = description.material(x_det.child(_U(material)).attr<std::string>(_U(name)));
0955     printout(INFO,"TestShape","+++ Volume material is %s", mat.name());      
0956   }
0957   for ( xml_coll_t itm(e, _U(check)); itm; ++itm, ++count )  {
0958     xml_dim_t   x_check  = itm;
0959     xml_comp_t  shape      (x_check.child(_U(shape)));
0960     xml_dim_t   pos        (x_check.child(_U(position), false));
0961     xml_dim_t   rot        (x_check.child(_U(rotation), false));
0962     bool        reflect  = x_check.hasChild(_U(reflect));
0963     bool        reflectZ = x_check.hasChild(_U(reflect_z));
0964     bool        reflectY = x_check.hasChild(_U(reflect_y));
0965     bool        reflectX = x_check.hasChild(_U(reflect_x));
0966     std::string shape_type = shape.typeStr();
0967     Volume      volume;
0968     Solid       solid;
0969 
0970     if ( shape_type == "CAD_Assembly" || shape_type == "CAD_MultiVolume" )  {
0971       volume = xml::createVolume(description, shape_type, shape);
0972       solid  = volume->GetShape();
0973     }
0974     else if ( shape_type == "StdVolume" )  {
0975       volume = xml::createStdVolume(description, shape.child(_U(volume)));
0976       solid  = volume->GetShape();
0977     }
0978     else if ( shape_type == "GenVolume" )  {
0979       volume = xml::createVolume(description, shape_type, shape.child(_U(volume)));
0980       solid  = volume->GetShape();
0981     }
0982     else   {
0983       solid  = xml::createShape(description, shape_type, shape);
0984       volume = Volume(name+_toString(count,"_vol_%d"),solid, mat);
0985     }
0986     if ( x_det.hasChild(_U(sensitive)) )  {
0987       std::string sens_type = x_det.child(_U(sensitive)).attr<std::string>(_U(type));
0988       volume.setSensitiveDetector(sens);
0989       sens.setType(sens_type);
0990       printout(INFO,"TestShape","+++ Sensitive type is %s", sens_type.c_str());
0991     }
0992     volume.setVisAttributes(description, x_check.visStr());
0993     solid->SetName(shape_type.c_str());
0994 
0995     Transform3D tr;
0996     if ( pos.ptr() && rot.ptr() )  {
0997       Rotation3D  rot3D(RotationZYX(rot.z(0),rot.y(0),rot.x(0)));
0998       Position    pos3D(pos.x(0),pos.y(0),pos.z(0));
0999       tr = Transform3D(rot3D, pos3D);
1000     }
1001     else if ( pos.ptr() )  {
1002       tr = Transform3D(Rotation3D(),Position(pos.x(0),pos.y(0),pos.z(0)));
1003     }
1004     else if ( rot.ptr() )  {
1005       Rotation3D rot3D(RotationZYX(rot.z(0),rot.y(0),rot.x(0)));
1006       tr = Transform3D(rot3D,Position());
1007     }
1008 
1009     if ( reflect )  {
1010       tr = tr * Rotation3D(1., 0., 0., 0., 1., 0., 0., 0., -1.);
1011     }
1012     if ( reflectX )   {
1013       tr = tr * Rotation3D(-1.,0.,0.,0.,1.,0.,0.,0.,1.);
1014     }
1015     if ( reflectY )   {
1016       tr = tr * Rotation3D(1.,0.,0.,0.,-1.,0.,0.,0.,1.);
1017     }
1018     if ( reflectZ )   {
1019       tr = tr * Rotation3D(1.,0.,0.,0.,1.,0.,0.,0.,-1.);
1020     }
1021     pv = assembly.placeVolume(volume,tr);
1022 
1023     if ( x_check.hasAttr(_U(id)) )  {
1024       pv.addPhysVolID("check",x_check.id());
1025       printout(INFO,"TestShape","+++ Volume id is %d", x_check.id());      
1026     }
1027     const char* nam = solid->GetName();
1028     printout(INFO,"TestShape","Created successfull shape of type: %s %c%s%c",
1029          shape_type.c_str(), nam ? '[' : ' ', nam ? nam : "" ,nam ? ']' : ' ');
1030       
1031     bool instance_test = false;
1032     if ( shape_type == "CAD_Assembly" || shape_type == "CAD_MultiVolume" )   {
1033       solid->SetTitle(shape_type.c_str());
1034       instance_test = true;
1035     }
1036     else if ( 0 == strcasecmp(solid->GetTitle(),BOX_TAG) )
1037       instance_test = isInstance<Box>(solid);
1038     else if ( 0 == strcasecmp(solid->GetTitle(),TUBE_TAG) )
1039       instance_test = isInstance<Tube>(solid);
1040     else if ( 0 == strcasecmp(solid->GetTitle(),CUTTUBE_TAG) )
1041       instance_test = isInstance<CutTube>(solid);
1042     else if ( 0 == strcasecmp(solid->GetTitle(),CONE_TAG) )
1043       instance_test = isInstance<Cone>(solid);
1044     else if ( 0 == strcasecmp(solid->GetTitle(),TRD1_TAG) )
1045       instance_test = isInstance<Trd1>(solid);
1046     else if ( 0 == strcasecmp(solid->GetTitle(),TRD2_TAG) )
1047       instance_test = isInstance<Trd2>(solid);
1048     else if ( 0 == strcasecmp(solid->GetTitle(),TORUS_TAG) )
1049       instance_test = isInstance<Torus>(solid);
1050     else if ( 0 == strcasecmp(solid->GetTitle(),SPHERE_TAG) )
1051       instance_test = isInstance<Sphere>(solid);
1052     else if ( 0 == strcasecmp(solid->GetTitle(),HALFSPACE_TAG) )
1053       instance_test = isInstance<HalfSpace>(solid);
1054     else if ( 0 == strcasecmp(solid->GetTitle(),CONESEGMENT_TAG) )
1055       instance_test = isInstance<ConeSegment>(solid);
1056     else if ( 0 == strcasecmp(solid->GetTitle(),PARABOLOID_TAG) )
1057       instance_test = isInstance<Paraboloid>(solid);
1058     else if ( 0 == strcasecmp(solid->GetTitle(),HYPERBOLOID_TAG) )
1059       instance_test = isInstance<Hyperboloid>(solid);
1060     else if ( 0 == strcasecmp(solid->GetTitle(),"PolyhedraRegular") )
1061       instance_test = isInstance<PolyhedraRegular>(solid);
1062     else if ( 0 == strcasecmp(solid->GetTitle(),POLYHEDRA_TAG) )
1063       instance_test = isInstance<Polyhedra>(solid);
1064     else if ( 0 == strcasecmp(solid->GetTitle(),ELLIPTICALTUBE_TAG) )
1065       instance_test = isInstance<EllipticalTube>(solid);
1066     else if ( 0 == strcasecmp(solid->GetTitle(),EXTRUDEDPOLYGON_TAG) )
1067       instance_test = isInstance<ExtrudedPolygon>(solid);
1068     else if ( 0 == strcasecmp(solid->GetTitle(),SCALE_TAG) )
1069       instance_test = isInstance<Scale>(solid);
1070     else if ( 0 == strcasecmp(solid->GetTitle(),TESSELLATEDSOLID_TAG) )  {
1071       instance_test = isInstance<TessellatedSolid>(solid);
1072       shape_type = TESSELLATEDSOLID_TAG;
1073     }
1074     else if ( 0 == strcasecmp(solid->GetTitle(),POLYCONE_TAG) )
1075       instance_test = isInstance<Polycone>(solid);
1076     else if ( 0 == strcasecmp(solid->GetTitle(),TWISTEDTUBE_TAG) )   {
1077       instance_test  =  isInstance<TwistedTube>(solid);
1078       instance_test &=  isInstance<Tube>(solid);
1079       instance_test &=  isA<TwistedTube>(solid);
1080       instance_test &= !isA<Tube>(solid);
1081     }
1082     else if ( 0 == strcasecmp(solid->GetTitle(),EIGHTPOINTSOLID_TAG) )   {
1083       instance_test  =  isInstance<EightPointSolid>(solid);
1084       instance_test &= !isInstance<Trap>(solid);
1085       instance_test &=  isA<EightPointSolid>(solid);
1086       instance_test &= !isA<Trap>(solid);
1087     }
1088     else if ( 0 == strcasecmp(solid->GetTitle(),TRAP_TAG) )   {
1089       instance_test  =  isInstance<EightPointSolid>(solid);
1090       instance_test &=  isInstance<Trap>(solid);
1091       instance_test &=  isA<Trap>(solid);
1092       instance_test &= !isA<EightPointSolid>(solid);
1093     }
1094     else if ( 0 == strcasecmp(solid->GetTitle(),SUBTRACTION_TAG) )  {
1095       instance_test  =  isInstance<BooleanSolid>(solid);
1096       instance_test &=  isInstance<SubtractionSolid>(solid);
1097       instance_test &= !isA<IntersectionSolid>(solid);
1098       instance_test &= !isA<UnionSolid>(solid);
1099       instance_test &=  isA<SubtractionSolid>(solid);
1100       instance_test &= !isA<PseudoTrap>(solid);
1101     }
1102     else if ( 0 == strcasecmp(solid->GetTitle(),UNION_TAG) )  {
1103       instance_test  =  isInstance<BooleanSolid>(solid);
1104       instance_test &=  isInstance<UnionSolid>(solid);
1105       instance_test &= !isA<IntersectionSolid>(solid);
1106       instance_test &=  isA<UnionSolid>(solid);
1107       instance_test &= !isA<SubtractionSolid>(solid);
1108       instance_test &= !isA<PseudoTrap>(solid);
1109     }
1110     else if ( 0 == strcasecmp(solid->GetTitle(),INTERSECTION_TAG) )  {
1111       instance_test  =  isInstance<BooleanSolid>(solid);
1112       instance_test &=  isInstance<IntersectionSolid>(solid);
1113       instance_test &=  isA<IntersectionSolid>(solid);
1114       instance_test &= !isA<UnionSolid>(solid);
1115       instance_test &= !isA<SubtractionSolid>(solid);
1116       instance_test &= !isA<PseudoTrap>(solid);
1117     }
1118     else if ( 0 == strcasecmp(solid->GetTitle(),TRUNCATEDTUBE_TAG) )  {
1119       instance_test  =  isInstance<BooleanSolid>(solid);
1120       instance_test &=  isInstance<TruncatedTube>(solid);
1121       instance_test &=  isA<TruncatedTube>(solid);
1122       instance_test &= !isA<PseudoTrap>(solid);
1123       instance_test &= !isA<IntersectionSolid>(solid);
1124       instance_test &= !isA<UnionSolid>(solid);
1125       instance_test &= !isA<SubtractionSolid>(solid);
1126     }
1127     else if ( 0 == strcasecmp(solid->GetTitle(),PSEUDOTRAP_TAG) )  {
1128       instance_test  =  isInstance<BooleanSolid>(solid);
1129       instance_test &=  isInstance<PseudoTrap>(solid);
1130       instance_test &=  isA<PseudoTrap>(solid);
1131       instance_test &= !isA<TruncatedTube>(solid);
1132       instance_test &= !isA<IntersectionSolid>(solid);
1133       instance_test &= !isA<UnionSolid>(solid);
1134       instance_test &= !isA<SubtractionSolid>(solid);
1135     }
1136 
1137     if ( !instance_test || ::strcasecmp(shape_type.c_str(),solid->GetTitle()) != 0 )   {
1138       printout(ERROR,"TestShape","BAD shape type: %s <-> %s Instance test: %s",
1139                shape_type.c_str(), solid->GetTitle(),
1140                instance_test ? "OK" : "FAILED");
1141     }
1142     else   {
1143       printout(INFO,"TestShape","Correct shape type: %s %s <-> %s Instance test: %s",
1144                solid->GetName(), shape_type.c_str(), solid->GetTitle(), "OK");
1145     }
1146   }
1147   if ( x_reflect )   {
1148     xml_dim_t   x_pos(x_reflect.child(_U(position), false));
1149     xml_dim_t   x_rot(x_reflect.child(_U(rotation), false));
1150     DetElement  full_detector(name+"_full",100+x_det.id());
1151     Assembly    full_assembly(name+"_full");
1152     RotationZYX refl_rot;
1153     Position    refl_pos;
1154 
1155     if ( x_rot ) refl_rot = RotationZYX(x_rot.z(0),x_rot.y(0),x_rot.x(0));
1156     if ( x_pos ) refl_pos = Position(x_pos.x(0),x_pos.y(0),x_pos.z(0));
1157     Transform3D refl_trafo(Rotation3D(refl_rot),refl_pos);
1158 
1159     /// Place the regular detector
1160     pv = full_assembly.placeVolume(assembly);
1161     full_detector.add(det);
1162     det.setPlacement(pv);
1163 
1164     /// Place reflected object
1165     auto reflected = det.reflect(name+"_reflected",100+x_det.id());
1166     pv = full_assembly.placeVolume(reflected.second, refl_trafo);
1167     full_detector.add(reflected.first);
1168     reflected.first.setPlacement(pv);
1169 
1170     /// Place mother
1171     pv = description.worldVolume().placeVolume(full_assembly);
1172     full_detector.setPlacement(pv);
1173     
1174     det = full_detector;
1175   }
1176   else  {
1177     pv = description.worldVolume().placeVolume(assembly);
1178     pv.addPhysVolID("system", x_det.id());
1179     det.setPlacement(pv);
1180   }
1181   /// Execute test plugin(s) on the placed volume if desired
1182   for ( xml_coll_t itm(e, xml_tag_t("test")); itm; ++itm, ++count )   {
1183     xml_comp_t   x_test = itm;
1184     std::string typ = x_test.typeStr();
1185     const void* argv[] = { &e, &pv, 0};
1186     Ref_t result = (NamedObject*)PluginService::Create<void*>(typ, &description, 2, (char**)argv);
1187     if ( !result.isValid() )  {
1188       printout(INFO,"TestShape","+++ Shape verification FAILED. [Plugin not found]");
1189       except("TestShape","+++ Shape verification FAILED.");
1190     }
1191     else if ( ::strcmp(result->GetName(),"SUCCESS") == 0 )  {
1192       printout(INFO,"TestShape","+++ Shape verification SUCCESSFUL. [type=%s]",name.c_str());
1193       delete result.ptr();
1194     }
1195     else   {
1196       printout(INFO,"TestShape","+++ Shape verification FAILED [result=%s]",result->GetName());
1197       printout(INFO,"TestShape","+++ Diagnosis: \n%s",result->GetTitle());
1198       delete result.ptr();
1199       except("TestShape","+++ Shape verification FAILED.");
1200     }
1201   }
1202   return det;
1203 }
1204 
1205 // first argument is the type from the xml file
1206 DECLARE_DETELEMENT(DD4hep_TestShape_Creator,create_shape)
1207 
1208 /// Plugin factory to check shape meshes against a reference file
1209 /**
1210  *
1211  *  \author  M.Frank
1212  *  \version 1.0
1213  */
1214 void* shape_mesh_verifier(Detector& description, int argc, char** argv)    {
1215   if ( argc != 2 )   {  }
1216   xml_det_t    x_det  = *(xml_h*)argv[0];
1217   PlacedVolume pv     = *(PlacedVolume*)argv[1];
1218   xml_comp_t   x_test = x_det.child(xml_tag_t("test"));
1219   int          ref_cr = x_test.hasAttr(_U(create)) ? x_test.attr<int>(_U(create)) : 0;
1220   int          nseg   = x_test.hasAttr(_U(segmentation)) ? x_test.attr<int>(_U(segmentation)) : -1;
1221   TString      ref    = x_test.refStr().c_str();
1222   std::string  ref_str;  
1223   std::stringstream os;
1224 
1225   if ( nseg > 0 )   {
1226     description.manager().SetNsegments(nseg);
1227   }
1228   Volume v = pv.volume();
1229   for (Int_t ipv=0, npv=v->GetNdaughters(); ipv < npv; ipv++) {
1230     PlacedVolume place = v->GetNode(ipv);
1231     auto vol   = place.volume();
1232     auto solid = vol.solid();
1233     os << "ShapeCheck[" << ipv << "] ";
1234     os << toStringMesh(place, 2);
1235     printout(INFO,"Mesh_Verifier","+++ Checking mesh of %s %s [%s] vol:%s.",
1236          solid->IsA()->GetName(),
1237          solid->GetName(), solid->GetTitle(),
1238          vol->GetName());
1239   }
1240   gSystem->ExpandPathName(ref);
1241   if ( ref_cr )   {
1242     std::ofstream out(ref, std::fstream::out);
1243     if ( !out.is_open() )   {
1244       except("Mesh_Verifier","+++ FAILED to open(WRITE) reference file: "+x_test.refStr());
1245     }
1246     out << os.str();
1247     out.close();
1248     printout(INFO,"Mesh_Verifier","+++ Successfully wrote reference file: "+x_test.refStr());
1249   }
1250   else if ( ref.Length() > 0 )  {
1251     char c;
1252     std::ifstream in(ref.Data(), std::fstream::in);
1253     if ( !in.is_open() )   {
1254       except("Mesh_Verifier","+++ FAILED to access reference file: "+x_test.refStr());
1255     }
1256     while (in.get(c))          // loop getting single characters
1257       ref_str += c;
1258     in.close();
1259     printout(INFO,"Mesh_Verifier","+++ Successfully read reference file: "+x_test.refStr());
1260     if ( ref_str != os.str() )  {
1261       printout(ERROR,"Mesh_Verifier","+++ Output and reference differ! Please check.");
1262       return Constant("FAILURE",os.str().c_str()).ptr();
1263     }
1264     printout(INFO,"Mesh_Verifier","+++ Successfully checked CREATED shapes.");
1265     os.str("");
1266     for (Int_t ipv=0, npv=v->GetNdaughters(); ipv < npv; ipv++) {
1267       PlacedVolume place = v->GetNode(ipv);
1268       Solid solid = place.volume().solid();
1269       if ( isInstance<TruncatedTube>(solid) )   {
1270         auto params = solid.dimensions();
1271         solid.setDimensions(params);
1272       }
1273       else if ( isInstance<PseudoTrap>(solid) )   {
1274         auto params = solid.dimensions();
1275         solid.setDimensions(params);
1276       }
1277       else if ( solid->IsA() != TGeoCompositeShape::Class() )   {
1278         auto params = solid.dimensions();
1279         solid.setDimensions(params);
1280       }
1281       else   {
1282         printout(INFO,"Mesh_Verifier","+++ Skip re-dimensioning of %s [%s].",
1283                  solid->IsA()->GetName(), solid->GetTitle());
1284       }
1285     }
1286     for (Int_t ipv=0, npv=v->GetNdaughters(); ipv < npv; ipv++) {
1287       PlacedVolume place = v->GetNode(ipv);
1288       os << "ShapeCheck[" << ipv << "] ";
1289       os << toStringMesh(place, 2);
1290     }
1291     if ( ref_str != os.str() )  {
1292       printout(DEBUG,"Mesh_Verifier","+++ REFERENCE shape mesh:\n%s",ref_str.c_str());
1293       printout(DEBUG,"Mesh_Verifier","+++ REDIMENSIONED shape mesh:\n%s",os.str().c_str());
1294       printout(ERROR,"Mesh_Verifier","+++ Output and reference differ after re-dimension! Please check.");
1295       return Constant("FAILURE",os.str().c_str()).ptr();
1296     }
1297     printout(INFO,"Mesh_Verifier","+++ Successfully checked REDIMENSIONED shapes.");
1298   }
1299   return Constant("SUCCESS",os.str().c_str()).ptr();
1300 }
1301 DECLARE_DD4HEP_CONSTRUCTOR(DD4hep_Mesh_Verifier,shape_mesh_verifier)