Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:54:53

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