From 96f504af3f3fbe1ed1f6f09a554976a6900e33d2 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Wed, 30 May 2018 17:29:06 +0200
Subject: [PATCH] Fix shape issues (bugs) for CMS

---
 DDCore/include/DD4hep/Shapes.h              |  10 +-
 DDCore/include/Parsers/detail/Dimension.h   |  12 ++
 DDCore/include/Parsers/detail/Dimension.imp |   6 +
 DDCore/include/XML/UnicodeValues.h          |   4 +
 DDCore/src/Shapes.cpp                       |  55 +++++----
 DDDetectors/src/ConeSegment_geo.cpp         |  54 ++++++++
 examples/DDCodex/CMakeLists.txt             |  34 +++++
 examples/DDCodex/CODEX-b.jpg                | Bin 0 -> 24567 bytes
 examples/DDCodex/README.txt                 |  77 ++++++++++++
 examples/DDCodex/compact/CODEX-b.xml        |  53 ++++++++
 examples/DDCodex/src/CODEXb_geo.cpp         | 130 ++++++++++++++++++++
 11 files changed, 408 insertions(+), 27 deletions(-)
 create mode 100644 DDDetectors/src/ConeSegment_geo.cpp
 create mode 100644 examples/DDCodex/CMakeLists.txt
 create mode 100644 examples/DDCodex/CODEX-b.jpg
 create mode 100644 examples/DDCodex/README.txt
 create mode 100644 examples/DDCodex/compact/CODEX-b.xml
 create mode 100644 examples/DDCodex/src/CODEXb_geo.cpp

diff --git a/DDCore/include/DD4hep/Shapes.h b/DDCore/include/DD4hep/Shapes.h
index 4d7860a01..de932ffae 100644
--- a/DDCore/include/DD4hep/Shapes.h
+++ b/DDCore/include/DD4hep/Shapes.h
@@ -502,8 +502,8 @@ namespace dd4hep {
     template <typename Q> Trap(const Handle<Q>& e) : Solid_type<Object>(e) { }
     /// Constructor to create a new anonymous object with attribute initialization
     Trap(double z, double theta, double phi,
-         double y1, double x1, double x2, double alpha1,
-         double y2, double x3, double x4, double alpha2);
+         double h1, double bl1, double tl1, double alpha1,
+         double h2, double bl2, double tl2, double alpha2);
     /// Constructor to create a new anonymous object for right angular wedge from STEP (Se G4 manual for details)
     Trap(double pz, double py, double px, double pLTX)  {  make(pz,py,px,pLTX);  }
     /// Constructor to create a new anonymous object with attribute initialization
@@ -512,9 +512,9 @@ namespace dd4hep {
     /// Assignment operator
     Trap& operator=(const Trap& copy) = default;
     /// Set the trap dimensions
-    Trap& setDimensions(double z, double theta, double phi, 
-                        double y1, double x1, double x2, double alpha1, 
-                        double y2, double x3, double x4, double alpha2);
+    Trap& setDimensions(double z, double theta, double phi,
+                        double h1, double bl1, double tl1, double alpha1,
+                        double h2, double bl2, double tl2, double alpha2);
   };
 
   /// Class describing a pseudo trap shape (CMS'ism)
diff --git a/DDCore/include/Parsers/detail/Dimension.h b/DDCore/include/Parsers/detail/Dimension.h
index 07166bbda..eba4aafbd 100644
--- a/DDCore/include/Parsers/detail/Dimension.h
+++ b/DDCore/include/Parsers/detail/Dimension.h
@@ -554,6 +554,16 @@ namespace dd4hep {
       Dimension position(bool throw_if_not_present = true) const;
       /// Child access: rotation
       Dimension rotation(bool throw_if_not_present = true) const;
+      /// Child access: cone
+      Dimension cone(bool throw_if_not_present = true) const;
+      /// Child access: sphere
+      Dimension sphere(bool throw_if_not_present = true) const;
+      /// Child access: torus
+      Dimension torus(bool throw_if_not_present = true) const;
+      /// Child access: trap
+      Dimension trap(bool throw_if_not_present = true) const;
+      /// Child access: trapezoid
+      Dimension trapezoid(bool throw_if_not_present = true) const;
       /// Child access: trd
       Dimension trd(bool throw_if_not_present = true) const;
       /// Child access: tubs
@@ -562,6 +572,8 @@ namespace dd4hep {
       Dimension staves(bool throw_if_not_present = true) const;
       /// Child access: beampipe
       Dimension beampipe(bool throw_if_not_present = true) const;
+      /// Child access: beampipe
+      Dimension envelope(bool throw_if_not_present = true) const;
 
       /// Access "name" attribute as STL string
       std::string nameStr() const;
diff --git a/DDCore/include/Parsers/detail/Dimension.imp b/DDCore/include/Parsers/detail/Dimension.imp
index 1380c248c..411268fd0 100644
--- a/DDCore/include/Parsers/detail/Dimension.imp
+++ b/DDCore/include/Parsers/detail/Dimension.imp
@@ -184,9 +184,15 @@ XML_ATTR_ACCESSOR_DOUBLE(temperature)
 XML_CHILD_ACCESSOR_XML_DIM(dimensions)
 XML_CHILD_ACCESSOR_XML_DIM(position)
 XML_CHILD_ACCESSOR_XML_DIM(rotation)
+XML_CHILD_ACCESSOR_XML_DIM(cone)
+XML_CHILD_ACCESSOR_XML_DIM(sphere)
+XML_CHILD_ACCESSOR_XML_DIM(torus)
+XML_CHILD_ACCESSOR_XML_DIM(trap)
+XML_CHILD_ACCESSOR_XML_DIM(trapezoid)
 XML_CHILD_ACCESSOR_XML_DIM(trd)
 XML_CHILD_ACCESSOR_XML_DIM(tubs)
 XML_CHILD_ACCESSOR_XML_DIM(staves)
+XML_CHILD_ACCESSOR_XML_DIM(envelope)
 XML_CHILD_ACCESSOR_XML_DIM(beampipe)
 
 std::string dd4hep::DD4HEP_DIMENSION_NS::Dimension::padType() const {
diff --git a/DDCore/include/XML/UnicodeValues.h b/DDCore/include/XML/UnicodeValues.h
index e13a9ad5a..f5bf9f125 100644
--- a/DDCore/include/XML/UnicodeValues.h
+++ b/DDCore/include/XML/UnicodeValues.h
@@ -125,6 +125,7 @@ UNICODE (end_module);
 UNICODE (end_modules);
 UNICODE (endcap);
 UNICODE (endphi);
+UNICODE (envelope);
 UNICODE (epsilon);
 UNICODE (eunit);
 UNICODE (end_x);
@@ -387,6 +388,7 @@ UNICODE (sensor);
 UNICODE (sequence);
 UNICODE (setup);
 UNICODE (shape);
+UNICODE (shield);
 UNICODE (show_daughters);
 UNICODE (showDaughters);
 UNICODE (size);
@@ -399,6 +401,7 @@ UNICODE (solids);
 UNICODE (solidref);
 UNICODE (spacer);
 UNICODE (sphere);
+UNICODE (station);
 UNICODE (status);
 UNICODE (start);
 UNICODE (start_x);
@@ -430,6 +433,7 @@ UNICODE (tracker);
 UNICODE (tracking_cylinder);
 UNICODE (tracking_volume);
 UNICODE (trap);
+UNICODE (trapezoid);
 UNICODE (trd);
 UNICODE (true);
 UNICODE (tube);
diff --git a/DDCore/src/Shapes.cpp b/DDCore/src/Shapes.cpp
index dafbadbaf..7fd78f314 100644
--- a/DDCore/src/Shapes.cpp
+++ b/DDCore/src/Shapes.cpp
@@ -452,7 +452,9 @@ Hyperboloid& Hyperboloid::setDimensions(double rin, double stin, double rout, do
 
 /// Constructor to be used when creating a new object with attribute initialization
 Sphere::Sphere(double rmin, double rmax, double theta, double delta_theta, double phi, double delta_phi) {
-  _assign(new TGeoSphere(rmin, rmax, theta/units::deg, delta_theta/units::deg, phi/units::deg, delta_phi/units::deg), "", "sphere", true);
+  _assign(new TGeoSphere(rmin, rmax,
+                         theta/units::deg, delta_theta/units::deg,
+                         phi/units::deg, delta_phi/units::deg), "", "sphere", true);
 }
 
 /// Set the Sphere dimensions
@@ -475,42 +477,51 @@ Torus& Torus::setDimensions(double r, double rmin, double rmax, double phi, doub
 }
 
 /// Constructor to be used when creating a new anonymous object with attribute initialization
-Trap::Trap(double z, double theta, double phi, double y1, double x1, double x2, double alpha1, double y2, double x3, double x4,
-           double alpha2) {
-  _assign(new TGeoTrap(z, theta, phi, y1, x1, x2, alpha1/units::deg, y2, x3, x4, alpha2/units::deg), "", "trap", true);
+Trap::Trap(double z, double theta, double phi,
+           double h1, double bl1, double tl1, double alpha1,
+           double h2, double bl2, double tl2, double alpha2) {
+  _assign(new TGeoTrap(z, theta/units::deg, phi/units::deg,
+                       h1, bl1, tl1, alpha1/units::deg,
+                       h2, bl2, tl2, alpha2/units::deg), "", "trap", true);
 }
 
 /// Constructor to be used when creating a new anonymous object with attribute initialization
 void Trap::make(double pz, double py, double px, double pLTX) {
-  double z = pz / 2e0;
-  double theta = 0e0;
-  double phi = 0e0;
-  double y1 = py / 2e0;
-  double x1 = px / 2e0;
-  double x2 = pLTX / 2e0;
+  double z      = pz / 2e0;
+  double theta  = 0e0;
+  double phi    = 0e0;
+  double h      = py / 2e0;
+  double bl     = px / 2e0;
+  double tl     = pLTX / 2e0;
   double alpha1 = (pLTX - px) / py;
-  _assign(new TGeoTrap(z, theta, phi, y1, x1, x2, alpha1/units::deg, y1, x1, x2, alpha1/units::deg), "", "trap", true);
+  _assign(new TGeoTrap(z, theta, phi,
+                       h, bl, tl, alpha1/units::deg,
+                       h, bl, tl, alpha1/units::deg), "", "trap", true);
 }
 
 /// Set the trap dimensions
-Trap& Trap::setDimensions(double z, double theta, double phi, double y1, double x1, double x2, double alpha1, double y2,
-                          double x3, double x4, double alpha2) {
-  double params[] = { z, theta, phi, y1, x1, x2, alpha1/units::deg, y2, x3, x4, alpha2/units::deg };
+Trap& Trap::setDimensions(double z, double theta, double phi,
+                          double h1, double bl1, double tl1, double alpha1,
+                          double h2, double bl2, double tl2, double alpha2) {
+  double params[] = { z,  theta/units::deg, phi/units::deg,
+                      h1, bl1, tl1, alpha1/units::deg,
+                      h2, bl2, tl2, alpha2/units::deg };
   _setDimensions(params);
   return *this;
 }
 
 /// Internal helper method to support object construction
 void PseudoTrap::make(double x1, double x2, double y1, double y2, double z, double r, bool atMinusZ)    {
-  double x = atMinusZ ? x1 : x2;
-  double h = 0;
-  bool intersec = false; // union or intersection solid
-  double halfOpeningAngle = std::asin( x / std::abs( r ))/units::deg;
+  double x            = atMinusZ ? x1 : x2;
+  double h            = 0;
+  bool   intersec     = false; // union or intersection solid
   double displacement = 0;
-  double startPhi = 0;
-  double halfZ = z/2.;
-  /* calculate the displacement of the tubs w.r.t. to the trap, determine the opening angle of the tubs */
-  double delta = std::sqrt( r * r - x * x );
+  double startPhi     = 0;
+  double halfZ        = z;
+  double halfOpeningAngle = std::asin( x / std::abs( r ))/units::deg;
+  
+  /// calculate the displacement of the tubs w.r.t. to the trap, determine the opening angle of the tubs
+  double delta        = std::sqrt( r * r - x * x );
  
   if( r < 0 && std::abs( r ) >= x )  {
     intersec = true; // intersection solid
diff --git a/DDDetectors/src/ConeSegment_geo.cpp b/DDDetectors/src/ConeSegment_geo.cpp
new file mode 100644
index 000000000..9b9f87826
--- /dev/null
+++ b/DDDetectors/src/ConeSegment_geo.cpp
@@ -0,0 +1,54 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+//
+// Specialized generic detector constructor
+// 
+//==========================================================================
+#include "DD4hep/DetFactoryHelper.h"
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::detail;
+
+static Ref_t create_element(Detector& description, xml_h e, Ref_t sens)  {
+  xml_det_t  x_det  (e);
+  xml_comp_t x_cone = x_det.cone();
+  xml_dim_t  pos    = x_det.position();
+  xml_dim_t  rot    = x_det.rotation();
+  string     name   = x_det.nameStr();
+  Cone       cone   (x_cone.dz(),x_cone.rmin1(),x_cone.rmax1(),x_cone.rmin2(),x_cone.rmax2());
+  Volume     vol    (name,cone,description.material(x_det.materialStr()));
+
+  vol.setVisAttributes(description, x_det.visStr());
+  vol.setLimitSet(description, x_det.limitsStr());
+  vol.setRegion(description, x_det.regionStr());
+  if ( x_det.isSensitive() )   {
+    SensitiveDetector sd = sens;
+    xml_dim_t sd_typ = x_det.child(_U(sensitive));
+    vol.setSensitiveDetector(sens);
+    sd.setType(sd_typ.typeStr());
+  }
+
+  DetElement   sdet(name,x_det.id());
+  Volume       mother = description.pickMotherVolume(sdet);
+  PlacedVolume phv = 
+    mother.placeVolume(vol,Transform3D(RotationZYX(rot.z(),rot.y(),rot.x()),Position(-pos.x(),-pos.y(),pos.z())));
+  if ( x_det.hasAttr(_U(id)) )  {
+    phv.addPhysVolID("system",x_det.id());
+  }
+  sdet.setPlacement(phv);
+  return sdet;
+}
+
+DECLARE_DETELEMENT(DD4hep_ConeSegment,create_element)
+
diff --git a/examples/DDCodex/CMakeLists.txt b/examples/DDCodex/CMakeLists.txt
new file mode 100644
index 000000000..e61b4889c
--- /dev/null
+++ b/examples/DDCodex/CMakeLists.txt
@@ -0,0 +1,34 @@
+#==========================================================================
+#  AIDA Detector description implementation 
+#--------------------------------------------------------------------------
+# Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+# All rights reserved.
+#
+# For the licensing terms see $DD4hepINSTALL/LICENSE.
+# For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+#
+#==========================================================================
+cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
+include ( ${DD4hep_DIR}/cmake/DD4hep.cmake )
+
+#-----------------------------------------------------------------------------------
+dd4hep_configure_output ()
+dd4hep_package ( DDCodex MAJOR 0 MINOR 0 PATCH 1
+  USES  [ROOT   REQUIRED COMPONENTS Geom] 
+        [DD4hep REQUIRED COMPONENTS DDCore]
+ )
+#
+#---DDCodex plugin library -------------------------------------------------------
+dd4hep_add_plugin(DDCodexPlugins
+  SOURCES src/*.cpp
+  USES    [ROOT    REQUIRED COMPONENTS Geom GenVector]
+)
+#
+#
+dd4hep_install_dir( compact scripts DESTINATION ${DD4hep_DIR}/examples/DDCodex )
+#--------------------------------------------------------------------------
+#
+dd4hep_configure_scripts ( DDCodex DEFAULT_SETUP WITH_TESTS )
+#
+#---Testing-------------------------------------------------------------------------
+#
diff --git a/examples/DDCodex/CODEX-b.jpg b/examples/DDCodex/CODEX-b.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6998e2bd3618c8cd8976db3d364f32de5f285a18
GIT binary patch
literal 24567
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

literal 0
HcmV?d00001

diff --git a/examples/DDCodex/README.txt b/examples/DDCodex/README.txt
new file mode 100644
index 000000000..617ba4d5f
--- /dev/null
+++ b/examples/DDCodex/README.txt
@@ -0,0 +1,77 @@
+CODEX starting kit
+==================
+
+
+Small geometry driver for CODEX-b sketch.
+
+
+To execute:
+----------------------------------------------------------------------------
+$> geoPluginRun -ui -inter
+...
+root [0] gDD4hepUI->importROOT("Upgrade.root")
+root [1] gDD4hepUI->fromXML("checkout/examples/DDCodex/compact/CODEX-b.xml")
+root [2] gDD4hepUI->draw()
+
+
+Output:
+----------------------------------------------------------------------------
+17:25:30-frankm~/SW/DD4hep_head_dbg.root_v6.12.06.g4_10.04.p01_MT/build$ geoPluginRun -ui -inter
+PersistencyIO    INFO  +++ Set Streamer to dd4hep::OpaqueDataBlock
+PersistencyIO    INFO  +++ Patching TGeoVolume.fUserExtension to persistent
+PersistencyIO    INFO  +++ Patching TGeoNode.fUserExtension to persistent
+Info in <TGeoManager::TGeoManager>: Geometry world, Detector Geometry created
+geoPluginRun: No geometry input supplied. No geometry will be loaded.
+DD4hepUI               Use the ROOT interpreter variable gDD4hepUI to interact with the detector description.
+   ------------------------------------------------------------
+  | Welcome to ROOT 6.12/06                http://root.cern.ch |
+  |                               (c) 1995-2017, The ROOT Team |
+  | Built for linuxx8664gcc                                    |
+  | From tag v6-12-06, 9 February 2018                         |
+  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
+   ------------------------------------------------------------
+
+root [0] gDD4hepUI->importROOT("Upgrade.root")
+DD4hepRootLoader INFO  +++ Read geometry from root file:Upgrade.root
+Warning in <TGeoManager::Init>: Deleting previous geometry: world/Detector Geometry
+Info in <TGeoManager::CloseGeometry>: Geometry loaded from file...
+Info in <TGeoManager::SetTopVolume>: Top volume is world_volume. Master volume is world_volume
+Info in <TGeoNavigator::BuildCache>: --- Maximum geometry depth set to 100
+Info in <TGeoManager::Voxelize>: Voxelizing...
+Error in <TGeoVoxelFinder::SortAll>: Volume lvAsicGroup16: Cannot make slices on any axis
+Error in <TGeoVoxelFinder::SortAll>: Volume lvAsicGroup4: Cannot make slices on any axis
+Error in <TGeoVoxelFinder::SortAll>: Volume lvAsicGroup8: Cannot make slices on any axis
+Info in <TGeoManager::CountLevels>: max level = 11, max placements = 171
+Info in <TGeoManager::CloseGeometry>: 18553873 nodes/ 2754 volume UID's in Detector Geometry
+Info in <TGeoManager::CloseGeometry>: ----------------modeler ready----------------
+DD4hepRootPersistency       +++ Fixed 0 segmentation objects.
+DD4hepRootPersistency       +++ Volume manager NOT restored. [Was it ever up when saved?]
+DD4hepRootPersistency       +++ Successfully loaded detector description from file:Upgrade.root  [   7.322 seconds]
+(long) 1
+root [1] gDD4hepUI->fromXML("checkout/examples/DDCodex/compact/CODEX-b.xml")
+CODEX-b          INFO  COBEXb Envelope: dz=2000 r1=0 r2=400 beam-angle=1.0472 atan(cone)=0.0996687
+CODEX-b          INFO  COBEXb Shield: Pb-shield-1  [Lead]       z=    700 dz=    150 r1=69.6526 r2=84.5782
+CODEX-b          INFO  COBEXb Shield: Shield-veto  [Si]         z=    850 dz=     10 r1=84.5782 r2=85.5732
+CODEX-b          INFO  COBEXb Shield: Pb-shield-2  [Lead]       z=    860 dz=     50 r1=85.5732 r2=90.5484
+CODEX-b          INFO  COBEXb X_tot= 532
+CODEX-b          INFO  COBEXb Module:  0 [Si]         x=-307.15 y=0 z=   1732 Dist:22 dx:25.4034 dz:44
+CODEX-b          INFO  COBEXb Module:  1 [Si]         x=-281.747 y=0 z=   1776 Dist:22 dx:25.4034 dz:44
+CODEX-b          INFO  COBEXb Module:  2 [Si]         x=-256.344 y=0 z=   1820 Dist:22 dx:25.4034 dz:44
+CODEX-b          INFO  COBEXb Module:  3 [Si]         x=-230.94 y=0 z=   1864 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module:  4 [Si]         x=-193.99 y=0 z=   1928 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module:  5 [Si]         x=-157.039 y=0 z=   1992 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module:  6 [Si]         x=-120.089 y=0 z=   2056 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module:  7 [Si]         x=-83.1384 y=0 z=   2120 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module:  8 [Si]         x=-46.188 y=0 z=   2184 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module:  9 [Si]         x=-9.2376 y=0 z=   2248 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module: 10 [Si]         x=27.7128 y=0 z=   2312 Dist:32 dx:36.9504 dz:64
+CODEX-b          INFO  COBEXb Module: 11 [Si]         x=64.6632 y=0 z=   2376 Dist:42 dx:48.4974 dz:84
+CODEX-b          INFO  COBEXb Module: 12 [Si]         x=113.161 y=0 z=   2460 Dist:42 dx:48.4974 dz:84
+CODEX-b          INFO  COBEXb Module: 13 [Si]         x=161.658 y=0 z=   2544 Dist:42 dx:48.4974 dz:84
+CODEX-b          INFO  COBEXb Module: 14 [Si]         x=210.155 y=0 z=   2628 Dist:42 dx:48.4974 dz:84
+CODEX-b          INFO  COBEXb Module: 15 [Si]         x=258.653 y=0 z=   2712 Dist:42 dx:48.4974 dz:84
+Compact          INFO  ++ Converted subdetector:COBEXb of type DD4hep_CODEXb 
+root [2] gDD4hepUI->draw()
+Info in <TGeoManager::SetVisLevel>: Automatic visible depth disabled
+Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
+root [3] 
diff --git a/examples/DDCodex/compact/CODEX-b.xml b/examples/DDCodex/compact/CODEX-b.xml
new file mode 100644
index 000000000..4a97c7da0
--- /dev/null
+++ b/examples/DDCodex/compact/CODEX-b.xml
@@ -0,0 +1,53 @@
+<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0" 
+       xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+       xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">
+<!--
+  <includes>
+    <gdmlFile  ref="elements.xml"/>
+    <gdmlFile  ref="materials.xml"/>
+  </includes>
+-->
+  <define>
+    <constant name="COBEX_beam_angle" value="60*degree"/>
+    <constant name="COBEX_cone_len" value="40*m"/>
+  </define> 
+
+  <comment>Common Generic visualization attributes</comment>
+  <display>
+    <vis name="BlackVis"              alpha="1"  r="0.1" g="0.1" b="0.1" showDaughters="false"  visible="true"/>
+    <vis name="Codex_Envelope_Vis"    alpha=".3" r="0.7" g="0.7" b="0.7" showDaughters="true"  visible="true"/>
+    <vis name="Codex_Module1_Vis"     alpha="1"  r="0.8" g="0.2" b="0.2" showDaughters="true"  visible="true"/>
+    <vis name="Codex_Module2_Vis"     alpha="1"  r="0.2" g="0.8" b="0.2" showDaughters="true"  visible="true"/>
+    <vis name="Codex_Module3_Vis"     alpha="1"  r="0.2" g="0.2" b="0.8" showDaughters="true"  visible="true"/>
+    <vis name="Codex_Shield_Pb_Vis"   alpha="1"  r="0.4" g="0.4" b="0.4" showDaughters="false" visible="true"/>
+    <vis name="Codex_Shield_Veto_Vis" alpha="1"  r="0.9" g="0.9" b="0.0" showDaughters="true"  visible="true"/>
+  </display>
+
+  <geometry  open="false" close="false"/>
+
+  <!--  Includes for sensitives and support                -->
+  <detectors>
+
+    <detector name="COBEXb" type="DD4hep_CODEXb" vis="Codex_Envelope_Vis">
+      <envelope angle="COBEX_beam_angle" dz="COBEX_cone_len" rmax="4*m"/>
+      <shield name="Pb-shield-1" z="7*m"   dz="1.5*m" material="Lead" sensitive="false" vis="Codex_Shield_Pb_Vis"/>
+      <shield name="Shield-veto" z="8.5*m" dz="0.1*m" material="Si"   sensitive="true"  vis="Codex_Shield_Veto_Vis"/>
+      <shield name="Pb-shield-2" z="8.6*m" dz="0.5*m" material="Lead" sensitive="false" vis="Codex_Shield_Pb_Vis"/>
+
+      <station z="12*m" width="10*m" height="10*m" thickness="2*cm" 
+               material="Si" sensitive="true" vis="Codex_Module1_Vis"
+               repeat="3" distance="20*cm"/>
+      <station width="10*m" height="10*m" thickness="2*cm"
+               material="Si" sensitive="true" vis="Codex_Module2_Vis"
+               repeat="8" distance="30*cm"/>
+      <station width="10*m" height="10*m" thickness="2*cm"
+               material="Si" sensitive="true" vis="Codex_Module3_Vis"
+               repeat="5" distance="40*cm"/>
+
+      <position x="-sin(COBEX_beam_angle)*COBEX_cone_len/2" y="0"   z="cos(COBEX_beam_angle)*COBEX_cone_len/2"/>
+      <rotation x="0"     y="COBEX_beam_angle"   z="0"/>
+
+    </detector>
+  </detectors>
+
+</lccdd>
diff --git a/examples/DDCodex/src/CODEXb_geo.cpp b/examples/DDCodex/src/CODEXb_geo.cpp
new file mode 100644
index 000000000..7e104a07d
--- /dev/null
+++ b/examples/DDCodex/src/CODEXb_geo.cpp
@@ -0,0 +1,130 @@
+//==========================================================================
+//  AIDA Detector description implementation 
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+//
+// Specialized generic detector constructor
+// 
+//==========================================================================
+#include "DD4hep/DetFactoryHelper.h"
+#include "DD4hep/Printout.h"
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::detail;
+
+
+static Ref_t create_element(Detector& description, xml_h e, Ref_t sens)  {
+  xml_det_t  x_det  (e);
+  xml_comp_t x_envelope = x_det.envelope();
+  xml_dim_t  pos        = x_det.position();
+  xml_dim_t  rot        = x_det.rotation();
+  string     det_name   = x_det.nameStr();
+  DetElement sdet(det_name,x_det.id());
+  double     env_angle  = x_envelope.angle();
+  double     env_dz     = x_envelope.dz()/2.0;
+  double     sin_cone   = std::sin(std::atan(x_envelope.rmax()/env_dz/2.0));
+  double     cos_beam   = std::cos(env_angle);
+  double     sin_beam   = std::sin(env_angle);
+  Cone       env_cone(env_dz,0,0.0001,x_envelope.rmax(),x_envelope.rmax()+0.0001);
+  Volume     env_vol (det_name,env_cone,description.air());
+  PlacedVolume pv;
+
+  env_vol.setRegion(description, x_det.regionStr());
+  env_vol.setLimitSet(description, x_det.limitsStr());
+  env_vol.setVisAttributes(description, x_det.visStr());
+  printout(INFO,"CODEX-b","%s Envelope: dz=%g r1=%g r2=%g beam-angle=%g atan(cone)=%g",
+           det_name.c_str(), env_cone->GetDz(), env_cone->GetRmin1(), env_cone->GetRmax2(),
+           env_angle, std::atan(x_envelope.rmax()/env_dz/2.0));
+
+  Tube tub(0, 3, x_envelope.dz()+500);
+  Volume tub_vol("Tube", tub, description.air());
+  tub_vol.setVisAttributes(description, "BlackVis");
+  pv = env_vol.placeVolume(tub_vol, Position(0,0,0));
+
+  int num_sensitive = 0;
+  for(xml_coll_t i(x_det,_U(shield)); i; ++i)  {
+    xml_comp_t s = i;
+    double     z  = s.z(), dz = s.dz();
+    double     r1 = sin_cone*z, r2 = sin_cone*(z+dz);
+    string     nam = s.nameStr();
+    Cone       con(dz/2., 0., r1, 0., r2);
+    Material   mat(description.material(s.attr<string>(_U(material))));
+    Volume     vol(nam,con,mat);
+
+    printout(INFO,"CODEX-b","%s Shield: %-12s %-12s z=%7g dz=%7g r1=%7g r2=%7g",
+             det_name.c_str(), vol.name(), ('['+string(mat.name())+']').c_str(), z, dz, r1, r2);
+    vol.setVisAttributes(description, s.visStr());
+    pv = env_vol.placeVolume(vol, Position(0,0,-env_dz+z+dz/2.0));
+    if ( s.isSensitive() )   {
+      DetElement det(sdet, "shield_"+nam, x_det.id());
+      pv.addPhysVolID("type", 0);
+      pv.addPhysVolID("module", num_sensitive);
+      det.setPlacement(pv);
+      ++num_sensitive;
+    }
+  }
+
+  int type_num = 0, station_number = 0;
+  double z0 = 0.0, x0 = 0.0, x_tot = 0.0;
+  for(xml_coll_t i(x_det,_U(station)); i; ++i, ++type_num)  {
+    xml_comp_t s = i;
+    x_tot += double(s.repeat())*(s.distance()+s.thickness());
+  }
+  printout(INFO,"CODEX-b","%s X_tot= %g",det_name.c_str(), x_tot);
+  for(xml_coll_t i(x_det,_U(station)); i; ++i, ++type_num)  {
+    xml_comp_t s = i;
+    int        repeat = s.repeat();
+    string     nam = _toString(station_number,"CODEX_station_type%d");
+    Box        box(s.width()/2., s.height()/2., s.thickness()/2.);
+    Material   mat(description.material(s.attr<string>(_U(material))));
+    Volume     vol(nam,box,mat);
+    double     dist = s.thickness()+s.distance();
+    double     dx = dist/sin_beam;
+    double     dz = dist/cos_beam;
+    if ( s.hasAttr(_U(z)) ) {
+      z0 = s.z()+x_tot/2.0/cos_beam;
+      x0 = -x_tot/2.0/sin_beam;
+    }    
+    vol.setVisAttributes(description, s.visStr());
+    for(int j=0; j < repeat; ++j)    {
+      DetElement det(sdet, _toString(station_number,"module%d"), station_number);
+      pv = env_vol.placeVolume(vol, Transform3D(RotationZYX(0,M_PI/2.0-env_angle,0), Position(x0,0,z0)));
+      pv.addPhysVolID("type", 1);
+      pv.addPhysVolID("module", station_number);
+      printout(INFO,"CODEX-b","%s Module: %2d %-12s x=%g y=%g z=%7g Dist:%g dx:%g dz:%g",
+               det_name.c_str(), station_number, ('['+string(mat.name())+']').c_str(),
+               x0, 0.0, z0, dist, dx, dz);
+      det.setPlacement(pv);
+      x0 += dx;
+      z0 += dz;
+      ++station_number;
+    }
+  }
+
+  if ( x_det.isSensitive() )   {
+    SensitiveDetector sd = sens;
+    xml_dim_t sd_typ = x_det.child(_U(sensitive));
+    env_vol.setSensitiveDetector(sens);
+    sd.setType(sd_typ.typeStr());
+  }
+
+  Volume mother = description.pickMotherVolume(sdet);
+  pv = mother.placeVolume(env_vol,Transform3D(RotationZYX(rot.z(),rot.y(),rot.x()),Position(-pos.x(),-pos.y(),pos.z())));
+  if ( x_det.hasAttr(_U(id)) )  {
+    pv.addPhysVolID("system",x_det.id());
+  }
+  sdet.setPlacement(pv);
+  return sdet;
+}
+
+DECLARE_DETELEMENT(DD4hep_CODEXb,create_element)
+
-- 
GitLab