From dc32120d0874bbb9f6765ce0611203c4d5e976d8 Mon Sep 17 00:00:00 2001
From: Christian Grefe <Christian.Grefe@cern.ch>
Date: Mon, 16 Dec 2013 23:37:56 +0000
Subject: [PATCH] Complete redesign of the segmentation business: -
 DDSegmenation now comes with its own factory and with generic access to
 segmentation parameters - Removes the necessity of implementing different XML
 parsers in DDCore - DD4hep::Segmentation becomes a lot simpler and its Object
 is now following a standard decorator pattern, completely removing any need
 of messing with the vtable - compact2lcdd works for example with
 BarrelCalorimeter from CLICSiD example (other examples need to adapt their
 XML to valid segmentation names) - See also
 examples/Segmentation/SegmentationTest for stand alone example - The
 segmentation names and their parameter names do NOT follow current SLIC
 conventions. Once SLIC depends on DDSegmentation this will work
 transparently.

---
 DDCore/include/DD4hep/Primitives.h            |   2 +-
 DDCore/include/DD4hep/Readout.h               |   8 -
 DDCore/include/DD4hep/Segmentations.h         | 236 ++--------------
 DDCore/src/Readout.cpp                        |  33 ---
 DDCore/src/Segementations.cpp                 | 258 ++----------------
 DDCore/src/plugins/Compact2Objects.cpp        | 104 ++-----
 DDCore/src/plugins/LCDDConverter.cpp          |  17 +-
 .../include/DDSegmentation/CartesianGrid.h    |   6 +-
 .../include/DDSegmentation/CartesianGridXY.h  |  23 +-
 .../include/DDSegmentation/CartesianGridXYZ.h |  16 +-
 .../include/DDSegmentation/CartesianGridXZ.h  |  21 +-
 .../DDSegmentation/CylindricalSegmentation.h  |  21 +-
 .../DDSegmentation/ProjectiveCylinder.h       |  30 +-
 .../include/DDSegmentation/Segmentation.h     | 136 ++++++---
 .../DDSegmentation/SegmentationFactory.h      |  77 ++++++
 .../DDSegmentation/SegmentationParameter.h    |  53 ++++
 .../include/DDSegmentation/SegmentationUtil.h | 244 ++---------------
 DDSegmentation/src/CartesianGrid.cpp          |  26 +-
 DDSegmentation/src/CartesianGridXY.cpp        |  69 ++---
 DDSegmentation/src/CartesianGridXYZ.cpp       |  71 ++---
 DDSegmentation/src/CartesianGridXZ.cpp        |  66 ++---
 .../src/CylindricalSegmentation.cpp           |  45 +--
 DDSegmentation/src/ProjectiveCylinder.cpp     |  58 ++--
 DDSegmentation/src/Segmentation.cpp           | 135 +++++----
 DDSegmentation/src/SegmentationFactory.cpp    |  59 ++++
 DDSegmentation/src/SegmentationParameter.cpp  |  62 +++++
 .../CLICSiD/compact/BarrelCalorimeter.xml     |   2 +-
 examples/Segmentation/CMakeLists.txt          |   3 -
 examples/Segmentation/SegmentationTest.cpp    |  36 ++-
 29 files changed, 664 insertions(+), 1253 deletions(-)
 create mode 100644 DDSegmentation/include/DDSegmentation/SegmentationFactory.h
 create mode 100644 DDSegmentation/include/DDSegmentation/SegmentationParameter.h
 create mode 100644 DDSegmentation/src/SegmentationFactory.cpp
 create mode 100644 DDSegmentation/src/SegmentationParameter.cpp

diff --git a/DDCore/include/DD4hep/Primitives.h b/DDCore/include/DD4hep/Primitives.h
index 0b4ccce09..239b7a7a3 100644
--- a/DDCore/include/DD4hep/Primitives.h
+++ b/DDCore/include/DD4hep/Primitives.h
@@ -17,7 +17,7 @@
  */
 namespace DD4hep {
 
-  // Put here global basic type defintiions derived from primitive types of the DD4hep namespace
+  // Put here global basic type definitions derived from primitive types of the DD4hep namespace
   typedef unsigned long long int VolumeID;
 
   /// Helper to delete objects from heap and reset the pointer. Saves many many lines of code
diff --git a/DDCore/include/DD4hep/Readout.h b/DDCore/include/DD4hep/Readout.h
index 328c5eef6..9830fa130 100644
--- a/DDCore/include/DD4hep/Readout.h
+++ b/DDCore/include/DD4hep/Readout.h
@@ -72,14 +72,6 @@ namespace DD4hep {
       void setSegmentation(const Segmentation& segment) const;
       /// Access segmentation structure
       Segmentation segmentation() const;
-
-      /// ID decoder interface
-      PlacedVolume getPlacement(const long64& cellID) const;
-      DetElement getSubDetector(const long64& cellID) const;
-      DetElement getDetectorElement(const long64& cellID) const;
-      Position getPosition(const long64& cellID) const;
-      Position getLocalPosition(const long64& cellID) const;
-      const TGeoMatrix& getWorldTransformation(const long64& cellID) const;
     };
 
     /** @class Alignment  Readoutn.h DD4hep/lcdd/Readout.h
diff --git a/DDCore/include/DD4hep/Segmentations.h b/DDCore/include/DD4hep/Segmentations.h
index 8e7ccb26f..c95e1ff96 100644
--- a/DDCore/include/DD4hep/Segmentations.h
+++ b/DDCore/include/DD4hep/Segmentations.h
@@ -10,9 +10,10 @@
 #define DD4HEP_GEOMETRY_SEGMENTATIONS_H
 
 // Framework include files
+#include "DD4hep/Objects.h"
 #include "DD4hep/Handle.h"
 #include "DD4hep/IDDescriptor.h"
-#include "DDSegmentation/CartesianGridXYZ.h"
+#include "DDSegmentation/Segmentation.h"
 
 // C/C++ include files
 #include <cmath>
@@ -44,15 +45,19 @@ namespace DD4hep {
        * @author  M.Frank
        * @version 1.0
        */
-      struct Object {
+      struct Object : public BaseSegmentation {
         /// Magic word to check object integrity
         unsigned long magic;
         /// Flag to use segmentation for hit positioning
         unsigned char useForHitPosition;
         /// Reference to base segmentation
         BaseSegmentation* segmentation;
+        /// determine the local position based on the cell ID
+        DDSegmentation::Position position(const long64& cellID) const;
+        /// determine the cell ID based on the local position
+        long64 cellID(const DDSegmentation::Position& localPosition, const DDSegmentation::Position& globalPosition, const long64& volumeID) const;
         /// Standard constructor
-        Object();
+        Object(BaseSegmentation* s = 0);
         /// Default destructor
         virtual ~Object();
       };
@@ -72,6 +77,11 @@ namespace DD4hep {
       template <typename Q> Segmentation(const Handle<Q>& e)
           : Handle<Implementation>(e) {
       }
+      /// Constructor to used when creating a new object
+      Segmentation(BaseSegmentation* s, const std::string& nam, const std::string& typ) :
+    	  Handle<Implementation>() {
+    	  assign(new Object(s), nam, typ);
+      }
       /// Access flag for hit positioning
       bool useForHitPosition() const;
       /// Accessor: Segmentation type
@@ -80,224 +90,12 @@ namespace DD4hep {
       void setType(const std::string& new_type);
       /// Access segmentation object
       BaseSegmentation* segmentation() const;
+      /// Access to the parameters
+      DDSegmentation::Parameters parameters() const;
       /// determine the local position based on the cell ID
-      std::vector<double> getLocalPosition(const long64& cellID) const;
+      Position position(const long64& cellID) const;
       /// determine the cell ID based on the local position
-      long64 getCellID(double x, double y, double z) const;
-    };
-
-    /** @class SegmentationParams Segmentations.h DD4hep/Segmentations.h
-     *
-     * @author  M.Frank
-     * @version 1.0
-     */
-    struct SegmentationParams: public Segmentation {
-    public:
-      /// Segmentation parameter definition
-      typedef std::pair<std::string, double> Parameter;
-      /// Segmentation parameter container definition
-      typedef std::vector<Parameter> Parameters;
-      /// Constructor to be used when reading the already parsed object
-      SegmentationParams(const Segmentation& e)
-          : Segmentation(e) {
-      }
-      /// Segmentation type
-      std::string type() const;
-      /// Access to the parameters
-      Parameters parameters() const;
-    };
-
-    /** @class ProjectiveCylinder Segmentations.h DD4hep/Segmentations.h
-     *
-     * @author  M.Frank
-     * @version 1.0
-     */
-    struct ProjectiveCylinder: public Segmentation {
-
-      struct Data: public Object, public BaseSegmentation {
-        int nphi;
-        int ntheta;
-        int nz;
-        /// Default constructor
-        Data(BitField64* decoder = 0)
-            : Object(), BaseSegmentation(decoder), nphi(0), ntheta(0), nz(0) {
-	  segmentation = this;
-        }
-        /// Default destructor
-        virtual ~Data();
-        /// determine the position based on the cell ID
-        virtual std::vector<double> getPosition(const long64& cellID) const;
-        /// determine the local position based on the cell ID
-        virtual std::vector<double> getLocalPosition(const long64& cellID) const;
-        /// determine the cell ID based on the local position
-        virtual long64 getCellID(double x, double y, double z) const;
-      };
-      /// Constructor to be used when reading the already parsed object
-      template <typename Q> ProjectiveCylinder(const Handle<Q>& e)
-          : Segmentation(e) {
-      }
-      /// Constructor to create a new segmentation object
-      ProjectiveCylinder(LCDD& lcdd);
-      /// Accessors: get number of bins in theta
-      int thetaBins() const;
-      /// Accessors: get number of bins in phi
-      int phiBins() const;
-      /// Accessors: get number of bins in z
-      int zBins() const;
-      /// Accessors: set number of bins in theta
-      void setThetaBins(int value);
-      /// Accessors: set number of bins in phi
-      void setPhiBins(int value);
-      /// Accessors: set number of bins in Z
-      void setZBins(int value);
-    };
-
-    /** @class NonProjectiveCylinder Segmentations.h DD4hep/Segmentations.h
-     *
-     * @author  M.Frank
-     * @version 1.0
-     */
-    struct NonProjectiveCylinder: public Segmentation {
-      struct Data: public Object, public BaseSegmentation {
-        double grid_size_phi;
-        double grid_size_theta;
-        double grid_size_z;
-        /// Default constructor
-        Data(BitField64* decoder = 0)
-            : Object(), BaseSegmentation(decoder) {
-          grid_size_phi = grid_size_theta = grid_size_z = 0;
-	  segmentation = this;
-        }
-        /// Default destructor
-        virtual ~Data();
-        /// determine the position based on the cell ID
-        virtual std::vector<double> getPosition(const long64& cellID) const;
-        /// determine the local position based on the cell ID
-        virtual std::vector<double> getLocalPosition(const long64& cellID) const;
-        /// determine the cell ID based on the local position
-        virtual long64 getCellID(double x, double y, double z) const;
-      };
-      /// Constructor to be used when reading the already parsed object
-      template <typename Q> NonProjectiveCylinder(const Handle<Q>& e)
-          : Segmentation(e) {
-      }
-      /// Constructor to create a new segmentation object
-      NonProjectiveCylinder(LCDD& lcdd);
-      /// Accessors: get size of bins in Z
-      double gridSizeZ() const;
-      /// Accessors: get size of bins in phi
-      double gridSizePhi() const;
-      /// Accessors: set number of bins in theta
-      void setThetaBinSize(double value);
-      /// Accessors: set grid size in Y
-      void setPhiBinSize(double value);
-    };
-
-    /** @class ProjectiveZPlane Segmentations.h DD4hep/Segmentations.h
-     *
-     * @author  M.Frank
-     * @version 1.0
-     */
-    struct ProjectiveZPlane: public Segmentation {
-      struct Data: public Object, public BaseSegmentation {
-        int nphi;
-        int ntheta;
-        int nz;
-        /// Default constructor
-        Data(BitField64* decoder = 0)
-            : Object(), BaseSegmentation(decoder) {
-          nphi = ntheta = nz = 0;
-	  segmentation = this;
-        }
-        /// Default destructor
-        virtual ~Data();
-        /// determine the position based on the cell ID
-        virtual std::vector<double> getPosition(const long64& cellID) const;
-        /// determine the local position based on the cell ID
-        virtual std::vector<double> getLocalPosition(const long64& cellID) const;
-        /// determine the cell ID based on the local position
-        virtual long64 getCellID(double x, double y, double z) const;
-      };
-      /// Constructor to be used when reading the already parsed object
-      template <typename Q> ProjectiveZPlane(const Handle<Q>& e)
-          : Segmentation(e) {
-      }
-      /// Constructor to create a new segmentation object
-      ProjectiveZPlane(LCDD& lcdd);
-      /// Accessors: get number of bins in theta
-      int thetaBins() const;
-      /// Accessors: get number of bins in phi
-      int phiBins() const;
-      /// Accessors: set number of bins in theta
-      void setThetaBins(int value);
-      /// Accessors: set grid size in Y
-      void setPhiBins(int value);
-    };
-
-    /** @class GridXY Segmentations.h DD4hep/Segmentations.h
-     *
-     * @author  M.Frank
-     * @version 1.0
-     */
-    struct GridXY: public Segmentation {
-      struct Data: public Object, public DDSegmentation::CartesianGridXY {
-        /// Default constructor
-        Data(BitField64* decoder = 0)
-            : Object(), DDSegmentation::CartesianGridXY(decoder) {
-	  segmentation = this;
-        }
-        /// Default destructor
-        virtual ~Data();
-      };
-      /// Constructor to be used when reading the already parsed object
-      template <typename Q> GridXY(const Handle<Q>& e)
-          : Segmentation(e) {
-      }
-      /// Constructor to create a new segmentation object
-      GridXY(LCDD& lcdd, const std::string& typ);
-      /// Accessors: set grid size in X
-      void setGridSizeX(double value);
-      /// Accessors: set grid size in Y
-      void setGridSizeY(double value);
-      /// Accessors: get grid size in X
-      double getGridSizeX() const;
-      /// Accessors: get grid size in Y
-      double getGridSizeY() const;
-    };
-
-    /** @class GridXYZ Segmentations.h DD4hep/Segmentations.h
-     *
-     * @author  M.Frank
-     * @version 1.0
-     */
-    struct GridXYZ: public Segmentation {
-      struct Data: public Object, public DDSegmentation::CartesianGridXYZ {
-        /// Default constructor
-        Data(BitField64* decoder = 0)
-            : Object(), DDSegmentation::CartesianGridXYZ(decoder) {
-	  segmentation = this;
-        }
-        /// Default destructor
-        virtual ~Data();
-      };
-      /// Constructor to be used when reading the already parsed object
-      template <typename Q> GridXYZ(const Handle<Q>& e)
-          : GridXY(e) {
-      }
-      /// Constructor to be used when creating a new object.
-      GridXYZ(LCDD& lcdd, const std::string& typ);
-      /// Accessors: set grid size in X
-      void setGridSizeX(double value);
-      /// Accessors: set grid size in Y
-      void setGridSizeY(double value);
-      /// Accessors: set grid size in Z
-      void setGridSizeZ(double value);
-      /// Accessors: get grid size in X
-      double getGridSizeX() const;
-      /// Accessors: get grid size in Y
-      double getGridSizeY() const;
-      /// Accessors: get grid size in Z
-      double getGridSizeZ() const;
+      long64 cellID(const Position& localPosition, const Position& globalPosition, const long64& volumeID) const;
     };
 
   } /* End namespace Geometry              */
diff --git a/DDCore/src/Readout.cpp b/DDCore/src/Readout.cpp
index 32a634ef2..3c5b1cba5 100644
--- a/DDCore/src/Readout.cpp
+++ b/DDCore/src/Readout.cpp
@@ -75,39 +75,6 @@ Segmentation Readout::segmentation() const {
   return object<Object>().segmentation;
 }
 
-/// full ID decoder interface
-PlacedVolume Readout::getPlacement(const long64& cellID) const {
-  VolumeManager volMan = LCDD::getInstance().volumeManager();
-  return volMan.lookupPlacement(cellID);
-}
-
-DetElement Readout::getSubDetector(const long64& cellID) const {
-  VolumeManager volMan = LCDD::getInstance().volumeManager();
-  return volMan.lookupDetector(cellID);
-}
-
-DetElement Readout::getDetectorElement(const long64& cellID) const {
-  VolumeManager volMan = LCDD::getInstance().volumeManager();
-  return volMan.lookupDetElement(cellID);
-}
-
-Position Readout::getPosition(const long64& cellID) const {
-  double global[3] = { 0., 0., 0. };
-  VolumeManager volMan = LCDD::getInstance().volumeManager();
-  volMan.worldTransformation(cellID).LocalToMaster(&(segmentation().segmentation()->getPosition(cellID))[0], global);
-  return Position(global[0] / tgeo::mm, global[1] / tgeo::mm, global[2] / tgeo::mm);
-}
-
-Position Readout::getLocalPosition(const long64& cellID) const {
-  std::vector<double> v = segmentation().segmentation()->getPosition(cellID);
-  return Position(v[0], v[1], v[2]);
-}
-
-const TGeoMatrix& Readout::getWorldTransformation(const long64& cellID) const {
-  VolumeManager volMan = LCDD::getInstance().volumeManager();
-  return volMan.worldTransformation(cellID);
-}
-
 /// Standard constructor
 Alignment::Object::Object() {
   InstanceCount::increment(this);
diff --git a/DDCore/src/Segementations.cpp b/DDCore/src/Segementations.cpp
index 6adc202fd..87bdc2815 100644
--- a/DDCore/src/Segementations.cpp
+++ b/DDCore/src/Segementations.cpp
@@ -16,22 +16,9 @@ using namespace std;
 using namespace DD4hep;
 using namespace DD4hep::Geometry;
 
-namespace {
-  void not_implemented_call(const char* tag) {
-    throw runtime_error(tag);
-  }
-  template <typename T> T& _obj(const DDSegmentation::Segmentation* ptr)  {
-    // ---> This would be so much more efficient, but sissies refused....
-    // T* p = (T*)(((const char*)ptr) - sizeof(Segmentation::Object));
-    // return *p;
-    const T* p = dynamic_cast<const T*>(ptr);
-    return *(T*)p;
-  }
-}
-
 /// Standard constructor
-Segmentation::Object::Object()
-  : magic(magic_word()), useForHitPosition(0), segmentation(0) {
+Segmentation::Object::Object(BaseSegmentation* s)
+  : magic(magic_word()), useForHitPosition(0), segmentation(s) {
   InstanceCount::increment(this);
 }
 
@@ -40,23 +27,28 @@ Segmentation::Object::~Object() {
   InstanceCount::decrement(this);
 }
 
+/// determine the local position based on the cell ID
+DDSegmentation::Position Segmentation::Object::position(const long64& cellID) const {
+	return segmentation->position(cellID);
+}
+
+/// determine the cell ID based on the local position
+long64 Segmentation::Object::cellID(const DDSegmentation::Position& localPosition, const DDSegmentation::Position& globalPosition, const long64& volumeID) const {
+	return segmentation->cellID(localPosition,globalPosition, volumeID);
+}
+
 /// Accessor: Segmentation type
 std::string Segmentation::type() const {
   return segmentation()->type();
 }
 
 bool Segmentation::useForHitPosition() const {
-  return _obj<Object>(ptr()).useForHitPosition != 0;
-}
-
-/// Segmentation type
-string SegmentationParams::type() const {
-  return _obj<Object>(ptr()).segmentation->type();
+  return object<Object>().useForHitPosition != 0;
 }
 
 /// Access to the parameters
-SegmentationParams::Parameters SegmentationParams::parameters() const {
-  Object& o = _obj<Object>(ptr());
+DDSegmentation::Parameters Segmentation::parameters() const {
+  Object& o = object<Object>();
   if (o.segmentation != 0)  {
     return o.segmentation->parameters();
   }
@@ -65,7 +57,7 @@ SegmentationParams::Parameters SegmentationParams::parameters() const {
 
 /// Access segmentation object
 DD4hep::DDSegmentation::Segmentation* Segmentation::segmentation() const {
-  Object& o = _obj<Object>(ptr());
+  Object& o = object<Object>();
   if (o.segmentation != 0)
     return o.segmentation;
   throw runtime_error(
@@ -73,222 +65,12 @@ DD4hep::DDSegmentation::Segmentation* Segmentation::segmentation() const {
           + " knows no implementation object [This is no longer allowed in the presence of DDSegmentation]");
 }
 
-/// Default destructor
-ProjectiveCylinder::Data::~Data() {
-}
-
-/// determine the local position based on the cell ID
-std::vector<double> ProjectiveCylinder::Data::getPosition(const long64& cellID) const {
-  not_implemented_call("ProjectiveCylinder::Data::getLocalPosition");
-  return vector<double>();
-}
-
-/// determine the local position based on the cell ID
-std::vector<double> ProjectiveCylinder::Data::getLocalPosition(const long64& cellID) const {
-  not_implemented_call("ProjectiveCylinder::Data::getLocalPosition");
-  return vector<double>();
-}
-
-/// determine the cell ID based on the local position
-long64 ProjectiveCylinder::Data::getCellID(double x, double y, double z) const {
-  not_implemented_call("ProjectiveCylinder::Data::getCellID");
-  return 0;
-}
-
-/// Constructor to create a new segmentation object
-ProjectiveCylinder::ProjectiveCylinder(LCDD&)
-    : Segmentation(new Data(), "segmentation", "projective_cylinder") {
-}
-
-/// Accessors: get number of bins in theta
-int ProjectiveCylinder::thetaBins() const {
-  return _obj<Data>(ptr()).ntheta;
-}
-
-/// Accessors: get number of bins in phi
-int ProjectiveCylinder::phiBins() const {
-  return _obj<Data>(ptr()).nphi;
-}
-
-/// Accessors: get number of bins in z
-int ProjectiveCylinder::zBins() const {
-  return _obj<Data>(ptr()).nz;
-}
-
-/// Accessors: set number of bins in theta
-void ProjectiveCylinder::setThetaBins(int value) {
-  _obj<Data>(ptr()).ntheta = value;
-}
-
-/// Accessors: set grid size in Y
-void ProjectiveCylinder::setPhiBins(int value) {
-  _obj<Data>(ptr()).nphi = value;
-}
-
-/// Accessors: set number of bins in Z
-void ProjectiveCylinder::setZBins(int value) {
-  _obj<Data>(ptr()).nz = value;
-}
-
-/// Default destructor
-NonProjectiveCylinder::Data::~Data() {
-}
-
-/// determine the local position based on the cell ID
-std::vector<double> NonProjectiveCylinder::Data::getPosition(const long64& cellID) const {
-  not_implemented_call("NonProjectiveCylinder::Data::getLocalPosition");
-  return vector<double>();
-}
-
-/// determine the local position based on the cell ID
-std::vector<double> NonProjectiveCylinder::Data::getLocalPosition(const long64& cellID) const {
-  not_implemented_call("NonProjectiveCylinder::Data::getLocalPosition");
-  return vector<double>();
-}
-
-/// determine the cell ID based on the local position
-long64 NonProjectiveCylinder::Data::getCellID(double x, double y, double z) const {
-  not_implemented_call("NonProjectiveCylinder::Data::getCellID");
-  return 0;
-}
-
-/// Constructor to create a new segmentation object
-NonProjectiveCylinder::NonProjectiveCylinder(LCDD&)
-    : Segmentation(new Data(), "segmentation", "nonprojective_cylinder") {
-}
-
-/// Accessors: get size of bins in Z
-double NonProjectiveCylinder::gridSizeZ() const {
-  return _obj<Data>(ptr()).grid_size_z;
-}
-
-/// Accessors: get size of bins in phi
-double NonProjectiveCylinder::gridSizePhi() const {
-  return _obj<Data>(ptr()).grid_size_phi;
-}
-
-/// Accessors: set number of bins in theta
-void NonProjectiveCylinder::setThetaBinSize(double value) {
-  _obj<Data>(ptr()).grid_size_phi = value;
-}
-
-/// Accessors: set grid size in Y
-void NonProjectiveCylinder::setPhiBinSize(double value) {
-  _obj<Data>(ptr()).grid_size_z = value;
-}
-
-/// Default destructor
-ProjectiveZPlane::Data::~Data() {
-}
-
 /// determine the local position based on the cell ID
-std::vector<double> ProjectiveZPlane::Data::getLocalPosition(const long64& cellID) const {
-  not_implemented_call("ProjectiveZPlane::Data::getLocalPosition");
-  return vector<double>();
-}
-
-/// determine the local position based on the cell ID
-std::vector<double> ProjectiveZPlane::Data::getPosition(const long64& cellID) const {
-  not_implemented_call("ProjectiveZPlane::Data::getLocalPosition");
-  return vector<double>();
+Position Segmentation::position(const long64& cellID) const {
+	return Position(segmentation()->position(cellID));
 }
 
 /// determine the cell ID based on the local position
-long64 ProjectiveZPlane::Data::getCellID(double x, double y, double z) const {
-  not_implemented_call("ProjectiveZPlane::Data::getCellID");
-  return 0;
-}
-
-/// Constructor to be used when creating a new object.
-ProjectiveZPlane::ProjectiveZPlane(LCDD&)
-    : Segmentation(new Data(), "segmentation", "projective_zplane") {
-}
-
-/// Accessors: get number of bins in phi
-int ProjectiveZPlane::phiBins() const {
-  return _obj<Data>(ptr()).nphi;
-}
-
-/// Accessors: get number of bins in theta
-int ProjectiveZPlane::thetaBins() const {
-  return _obj<Data>(ptr()).ntheta;
-}
-
-/// Accessors: set number of bins in theta
-void ProjectiveZPlane::setThetaBins(int value) {
-  _obj<Data>(ptr()).ntheta = value;
-}
-
-/// Accessors: set grid size in Y
-void ProjectiveZPlane::setPhiBins(int value) {
-  _obj<Data>(ptr()).nphi = value;
-}
-
-/// Default destructor
-GridXY::Data::~Data() {
-}
-
-/// Constructor to be used when creating a new object.
-GridXY::GridXY(LCDD&, const std::string& typ)
-    : Segmentation(new Data(), "segmentation", typ) {
-}
-
-/// Accessors: get grid size in X
-double GridXY::getGridSizeX() const {
-  return _obj<Data>(ptr()).getGridSizeX();
-}
-
-/// Accessors: get grid size in Y
-double GridXY::getGridSizeY() const {
-  return _obj<Data>(ptr()).getGridSizeY();
-}
-
-/// Accessors: set grid size in X
-void GridXY::setGridSizeX(double value) {
-  _obj<Data>(ptr()).setGridSizeX(value);
-}
-
-/// Accessors: set grid size in Y
-void GridXY::setGridSizeY(double value) {
-  _obj<Data>(ptr()).setGridSizeY(value);
-}
-
-/// Default destructor
-GridXYZ::Data::~Data() {
-}
-
-/// Constructor to be used when creating a new object.
-GridXYZ::GridXYZ(LCDD&, const std::string& typ)
-    : Segmentation(new Data(), "segmentation", typ) {
-  assign(new Data(), "segmentation", typ);
-}
-
-/// Accessors: get grid size in X
-double GridXYZ::getGridSizeX() const {
-  return _obj<Data>(ptr()).getGridSizeX();
-}
-
-/// Accessors: get grid size in Y
-double GridXYZ::getGridSizeY() const {
-  return _obj<Data>(ptr()).getGridSizeY();
-}
-
-/// Accessors: get grid size in Z
-double GridXYZ::getGridSizeZ() const {
-  return _obj<Data>(ptr()).getGridSizeZ();
-}
-
-/// Accessors: set grid size in X
-void GridXYZ::setGridSizeX(double value) {
-  _obj<Data>(ptr()).setGridSizeX(value);
-}
-
-/// Accessors: set grid size in Y
-void GridXYZ::setGridSizeY(double value) {
-  _obj<Data>(ptr()).setGridSizeY(value);
-}
-
-/// Accessors: set grid size in Z
-void GridXYZ::setGridSizeZ(double value) {
-  _obj<Data>(ptr()).setGridSizeZ(value);
+long64 Segmentation::cellID(const Position& localPosition, const Position& globalPosition, const long64& volumeID) const {
+	return segmentation()->cellID(localPosition, globalPosition, volumeID);
 }
diff --git a/DDCore/src/plugins/Compact2Objects.cpp b/DDCore/src/plugins/Compact2Objects.cpp
index 182e460fc..b2cf444e9 100644
--- a/DDCore/src/plugins/Compact2Objects.cpp
+++ b/DDCore/src/plugins/Compact2Objects.cpp
@@ -15,9 +15,7 @@
 #include "DD4hep/Plugins.h"
 #include "XML/DocumentHandler.h"
 #include "XML/Conversions.h"
-
-#include "DDSegmentation/CartesianGridXY.h"
-#include "DDSegmentation/CartesianGridXYZ.h"
+#include "DDSegmentation/SegmentationFactory.h"
 
 // Root/TGeo include files
 #include "TGeoManager.h"
@@ -68,84 +66,6 @@ namespace {
 
 }
 
-static Ref_t create_GridXYZ(lcdd_t& lcdd, xml_h e) {
-  GridXYZ obj(lcdd, "grid_xyz");
-  if (e.hasAttr(_U(gridSizeX)))
-    obj.setGridSizeX(e.attr<float>(_U(gridSizeX)));
-  if (e.hasAttr(_U(gridSizeY)))
-    obj.setGridSizeY(e.attr<float>(_U(gridSizeY)));
-  if (e.hasAttr(_U(gridSizeZ)))
-    obj.setGridSizeZ(e.attr<float>(_U(gridSizeZ)));
-  return obj;
-}
-DECLARE_XMLELEMENT(GridXYZ,create_GridXYZ);
-
-static Ref_t create_GlobalGridXY(lcdd_t& lcdd, xml_h e) {
-  GridXY obj(lcdd, "global_grid_xy");
-  if (e.hasAttr(_U(gridSizeX)))
-    obj.setGridSizeX(e.attr<float>(_U(gridSizeX)));
-  if (e.hasAttr(_U(gridSizeY)))
-    obj.setGridSizeY(e.attr<float>(_U(gridSizeY)));
-  return obj;
-}
-DECLARE_XMLELEMENT(GlobalGridXY,create_GlobalGridXY);
-
-static Ref_t create_CartesianGridXY(lcdd_t& lcdd, xml_h e) {
-  GridXY obj(lcdd, "cartesian_grid_xy");
-  if (e.hasAttr(_U(gridSizeX)))
-    obj.setGridSizeX(e.attr<double>(_U(gridSizeX)));
-  if (e.hasAttr(_U(gridSizeY)))
-    obj.setGridSizeY(e.attr<double>(_U(gridSizeY)));
-  return obj;
-}
-DECLARE_XMLELEMENT(CartesianGridXY,create_CartesianGridXY);
-
-namespace DD4hep {
-  namespace Geometry {
-    typedef GridXY RegularNgonCartesianGridXY;
-  }
-}
-DECLARE_XMLELEMENT(RegularNgonCartesianGridXY,create_CartesianGridXY);
-
-namespace DD4hep {
-  namespace Geometry {
-    typedef GridXYZ CartesianGridXYZ;
-    typedef GridXY EcalBarrelCartesianGridXY;
-  }
-}
-DECLARE_XMLELEMENT(CartesianGridXYZ,create_CartesianGridXY);
-DECLARE_XMLELEMENT(EcalBarrelCartesianGridXY,create_CartesianGridXY);
-
-static Ref_t create_ProjectiveCylinder(lcdd_t& lcdd, xml_h e) {
-  ProjectiveCylinder obj(lcdd);
-  if (e.hasAttr(_U(phiBins)))
-    obj.setPhiBins(e.attr<int>(_U(phiBins)));
-  if (e.hasAttr(_U(thetaBins)))
-    obj.setThetaBins(e.attr<int>(_U(thetaBins)));
-  return obj;
-}
-DECLARE_XMLELEMENT(ProjectiveCylinder,create_ProjectiveCylinder);
-
-static Ref_t create_NonProjectiveCylinder(lcdd_t& lcdd, xml_h e) {
-  NonProjectiveCylinder obj(lcdd);
-  if (e.hasAttr(_U(gridSizePhi)))
-    obj.setThetaBinSize(e.attr<double>(_U(gridSizePhi)));
-  if (e.hasAttr(_U(gridSizeZ)))
-    obj.setPhiBinSize(e.attr<double>(_U(gridSizeZ)));
-  return obj;
-}
-DECLARE_XMLELEMENT(NonProjectiveCylinder,create_NonProjectiveCylinder);
-
-static Ref_t create_ProjectiveZPlane(lcdd_t& lcdd, xml_h e) {
-  ProjectiveZPlane obj(lcdd);
-  if (e.hasAttr(_U(phiBins)))
-    obj.setThetaBins(e.attr<int>(_U(phiBins)));
-  if (e.hasAttr(_U(thetaBins)))
-    obj.setPhiBins(e.attr<int>(_U(thetaBins)));
-  return obj;
-}
-DECLARE_XMLELEMENT(ProjectiveZPlane,create_ProjectiveZPlane);
-
 static Ref_t create_ConstantField(lcdd_t& /* lcdd */, xml_h e) {
   CartesianField obj;
   xml_comp_t field(e), strength(e.child(_U(strength)));
@@ -520,12 +440,24 @@ template <> void Converter<Readout>::operator()(xml_h e) const {
   Ref_t idSpec;
 
   if (seg) {   // Segmentation is not mandatory!
+	typedef DDSegmentation::Segmentation BaseSegmentation;
     string type = seg.attr < string > (_U(type));
-    Ref_t segment(PluginService::Create<TNamed*>(type, &lcdd, &seg));
-    if (!segment.isValid()) {
-      PluginDebug dbg;
-      PluginService::Create<TNamed*>(type, &lcdd, &seg);
-      throw_print("FAILED to create segmentation:" + type + ". " + dbg.missingFactory(type));
+    BaseSegmentation* s = DDSegmentation::SegmentationFactory::instance()->create(type);
+    if (not s) {
+      throw_print("FAILED to create segmentation: " + type + ". Missing factory method for: " + type + "!");
+    }
+    Segmentation segment(s, name, type);
+    if (segment.isValid()) {
+      DDSegmentation::Parameters parameters = s->parameters();
+      DDSegmentation::Parameters::iterator it;
+      for (it = parameters.begin(); it != parameters.end(); ++it) {
+        DDSegmentation::Parameter p = *it;
+    	if (seg.hasAttr(Unicode(p->name()))) {
+    	  p->value() = seg.attr<double>(Unicode(p->name()));
+        } else if (not p->isOptional()) {
+    	  throw_print("FAILED to create segmentation: " + type + ". Missing mandatory parameter: " + p->name() + "!");
+    	}
+      }
     }
     ro.setSegmentation(segment);
   }
diff --git a/DDCore/src/plugins/LCDDConverter.cpp b/DDCore/src/plugins/LCDDConverter.cpp
index 0fadea41f..3bfb0351f 100644
--- a/DDCore/src/plugins/LCDDConverter.cpp
+++ b/DDCore/src/plugins/LCDDConverter.cpp
@@ -800,21 +800,20 @@ xml_h LCDDConverter::handleLimitSet(const std::string& name, const TNamed* limit
 xml_h LCDDConverter::handleSegmentation(Segmentation seg) const {
   xml_h xml;
   if (seg.isValid()) {
-    typedef SegmentationParams::Parameters _P;
+    typedef DDSegmentation::Parameters _P;
     string typ = seg.type();
-    SegmentationParams par(seg);
-    _P p = par.parameters();
+    _P p = seg.parameters();
     xml = xml_elt_t(data().doc, Unicode(typ));
     for (_P::const_iterator i = p.begin(); i != p.end(); ++i) {
       const _P::value_type& v = *i;
-      if (v.first == "lunit") {
-        string val = v.second == _toDouble("mm") ? "mm" : v.second == _toDouble("cm") ? "cm" :
-                     v.second == _toDouble("m") ? "m" : v.second == _toDouble("micron") ? "micron" :
-                     v.second == _toDouble("nanometer") ? "namometer" : "??";
-        xml.setAttr(Unicode(v.first), Unicode(val));
+      if (v->name() == "lunit") {
+        string val = v->value() == _toDouble("mm") ? "mm" : v->value() == _toDouble("cm") ? "cm" :
+                     v->value() == _toDouble("m") ? "m" : v->value() == _toDouble("micron") ? "micron" :
+                     v->value() == _toDouble("nanometer") ? "namometer" : "??";
+        xml.setAttr(Unicode(v->name()), Unicode(val));
         continue;
       }
-      xml.setAttr(Unicode(v.first), v.second);
+      xml.setAttr(Unicode(v->name()), v->value());
     }
   }
   return xml;
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGrid.h b/DDSegmentation/include/DDSegmentation/CartesianGrid.h
index 1df3494d5..f04409902 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGrid.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGrid.h
@@ -15,11 +15,11 @@ namespace DDSegmentation {
 
 class CartesianGrid: public Segmentation {
 public:
-	/// destructor
+	/// Destructor
 	virtual ~CartesianGrid();
 protected:
-	/// default constructor using an arbitrary type
-	template <typename TYPE> CartesianGrid(TYPE cellEncoding);
+	/// Default constructor used by derived classes passing the encoding string
+	CartesianGrid(const std::string& cellEncoding = "");
 };
 
 } /* namespace DDSegmentation */
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGridXY.h b/DDSegmentation/include/DDSegmentation/CartesianGridXY.h
index 52cd121e0..5e470e116 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGridXY.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGridXY.h
@@ -15,38 +15,37 @@ namespace DDSegmentation {
 
 class CartesianGridXY: public CartesianGrid {
 public:
-	/// default constructor using an arbitrary type
-	template <typename TYPE> CartesianGridXY(TYPE cellEncoding, double gridSizeX = 1., double gridSizeY = 1., double offsetX = 0.,
-			double offsetY = 0., const std::string& xField = "x", const std::string& yField = "y");
+	/// Default constructor passing the encoding string
+	CartesianGridXY(const std::string& cellEncoding = "");
 	/// destructor
 	virtual ~CartesianGridXY();
 
 	/// determine the position based on the cell ID
-	virtual std::vector<double> getPosition(const long64& cellID) const;
+	virtual Position position(const CellID& cellID) const;
 	/// determine the cell ID based on the position
-	virtual long64 getCellID(double x, double y, double z) const;
+	virtual CellID cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const;
 	/// access the grid size in X
-	double getGridSizeX() const {
+	double gridSizeX() const {
 		return _gridSizeX;
 	}
 	/// access the grid size in Y
-	double getGridSizeY() const {
+	double gridSizeY() const {
 		return _gridSizeY;
 	}
 	/// access the coordinate offset in X
-	double getOffsetX() const {
+	double offsetX() const {
 		return _offsetX;
 	}
 	/// access the coordinate offset in Y
-	double getOffsetY() const {
+	double offsetY() const {
 		return _offsetY;
 	}
 	/// access the field name used for X
-	std::string getFieldNameX() const {
+	const std::string& fieldNameX() const {
 		return _xId;
 	}
 	/// access the field name used for Y
-	std::string getFieldNameY() const {
+	const std::string& fieldNameY() const {
 		return _yId;
 	}
 	/// set the grid size in X
@@ -73,8 +72,6 @@ public:
 	void setFieldNameY(const std::string& name) {
 		_yId = name;
 	}
-	/// access the set of parameters for this segmentation
-	Parameters parameters() const;
 
 protected:
 	/// the grid size in X
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h b/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h
index 981dd8f0e..b28840df3 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h
@@ -16,26 +16,24 @@ namespace DDSegmentation {
 class CartesianGridXYZ: public CartesianGridXY {
 public:
 	/// default constructor using an arbitrary type
-	template <typename TYPE> CartesianGridXYZ(TYPE cellEncoding, double gridSizeX = 1., double gridSizeY = 1., double gridSizeZ = 1.,
-			double offsetX = 0., double offsetY = 0., double offsetZ = 0., const std::string& xField = "x",
-			const std::string& yField = "y", const std::string& zField = "z");
+	CartesianGridXYZ(const std::string& cellEncoding);
 	/// destructor
 	virtual ~CartesianGridXYZ();
 
 	/// determine the position based on the cell ID
-	virtual std::vector<double> getPosition(const long64& cellID) const;
+	virtual Position position(const CellID& cellID) const;
 	/// determine the cell ID based on the position
-	virtual long64 getCellID(double x, double y, double z) const;
+	virtual CellID cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const;
 	/// access the grid size in Z
-	double getGridSizeZ() const {
+	double gridSizeZ() const {
 		return _gridSizeZ;
 	}
 	/// access the coordinate offset in Z
-	double getOffsetZ() const {
+	double offsetZ() const {
 		return _offsetZ;
 	}
 	/// access the field name used for Z
-	std::string getFieldNameZ() const {
+	const std::string& fieldNameZ() const {
 		return _zId;
 	}
 	/// set the grid size in Z
@@ -50,8 +48,6 @@ public:
 	void setFieldNameZ(const std::string& name) {
 		_zId = name;
 	}
-	/// access the set of parameters for this segmentation
-	Parameters parameters() const;
 
 protected:
 	/// the grid size in Z
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h b/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h
index 5e4c81349..02ab684ef 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h
@@ -16,37 +16,36 @@ namespace DDSegmentation {
 class CartesianGridXZ: public CartesianGrid {
 public:
 	/// default constructor using an arbitrary type
-	template <typename TYPE> CartesianGridXZ(TYPE cellEncoding, double gridSizeX = 1., double gridSizeZ = 1., double offsetX = 0.,
-			double offsetZ = 0., const std::string& xField = "x", const std::string& zField = "z");
+	CartesianGridXZ(const std::string& cellEncoding);
 	/// destructor
 	virtual ~CartesianGridXZ();
 
 	/// determine the local based on the cell ID
-	virtual std::vector<double> getPosition(const long64& cellID) const;
+	virtual Position position(const CellID& cellID) const;
 	/// determine the cell ID based on the position
-	virtual long64 getCellID(double x, double y, double z) const;
+	virtual CellID cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const;
 	/// access the grid size in X
-	double getGridSizeX() const {
+	double gridSizeX() const {
 		return _gridSizeX;
 	}
 	/// access the grid size in Z
-	double getGridSizeZ() const {
+	double gridSizeZ() const {
 		return _gridSizeZ;
 	}
 	/// access the coordinate offset in X
-	double getOffsetX() const {
+	double offsetX() const {
 		return _offsetX;
 	}
 	/// access the coordinate offset in Z
-	double getOffsetZ() const {
+	double offsetZ() const {
 		return _offsetZ;
 	}
 	/// access the field name used for X
-	std::string getFieldNameX() const {
+	const std::string& fieldNameX() const {
 		return _xId;
 	}
 	/// access the field name used for Z
-	std::string getFieldNameZ() const {
+	const std::string& fieldNameZ() const {
 		return _zId;
 	}
 	/// set the grid size in X
@@ -73,8 +72,6 @@ public:
 	void setFieldNameZ(const std::string& name) {
 		_zId = name;
 	}
-	/// access the set of parameters for this segmentation
-	Parameters parameters() const;
 
 protected:
 	/// the grid size in X
diff --git a/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h b/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h
index 1aaafa614..5d12401d6 100644
--- a/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h
+++ b/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h
@@ -20,28 +20,9 @@ public:
 	/// destructor
 	virtual ~CylindricalSegmentation();
 
-	/// determine the radius based on the cell ID
-	double getRadius(const long64& cellID) const;
-	/// access the field name used for layer
-	std::string getFieldNameLayer() const {
-		return _layerID;
-	}
-	/// set the field name used for the layer
-	void setFieldNameLayer(const std::string& name) {
-		_layerID = name;
-	}
-	/// set the radius of the given layer index
-	void setLayerRadius(int layerIndex, double radius) {
-		_layerRadiusMap[layerIndex] = radius;
-	}
 protected:
 	/// default constructor using an arbitrary type
-	template <typename TYPE> CylindricalSegmentation(TYPE cellEncoding, const std::string& layerField = "layer");
-	/// default constructor using an existing decoder
-	CylindricalSegmentation(BitField64* decoder);
-	/// store layer radii
-	std::map<int, double> _layerRadiusMap;
-	std::string _layerID;
+	CylindricalSegmentation(const std::string& cellEncoding);
 };
 
 
diff --git a/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h b/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h
index 6b58a7060..f2c61bae8 100644
--- a/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h
+++ b/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h
@@ -16,42 +16,40 @@ namespace DDSegmentation {
 class ProjectiveCylinder: public CylindricalSegmentation {
 public:
 	/// default constructor using an arbitrary type
-	template<typename TYPE> ProjectiveCylinder(TYPE cellEncoding, int thetaBins = 1, int phiBins = 1,
-			double offsetTheta = 0., double offsetPhi = 0., const std::string& thetaField = "theta",
-			const std::string& phiField = "phi", const std::string& layerField = "layer");
+	ProjectiveCylinder(const std::string& cellEncoding);
 	/// destructor
 	virtual ~ProjectiveCylinder();
 
 	/// determine the position based on the cell ID
-	virtual std::vector<double> getPosition(const long64& cellID) const;
+	virtual Position position(const CellID& cellID) const;
 	/// determine the cell ID based on the position
-	virtual long64 getCellID(double x, double y, double z) const;
+	virtual CellID cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const;
 	/// determine the polar angle theta based on the cell ID
-	double getTheta(const long64& cellID) const;
+	double theta(const long64& cellID) const;
 	/// determine the azimuthal angle phi based on the cell ID
-	double getPhi(const long64& cellID) const;
+	double phi(const long64& cellID) const;
 	/// access the number of bins in theta
-	int getThetaBins() const {
+	int thetaBins() const {
 		return _thetaBins;
 	}
 	/// access the number of bins in theta
-	int getPhiBins() const {
+	int phiBins() const {
 		return _phiBins;
 	}
 	/// access the coordinate offset in theta
-	double getOffsetTheta() const {
+	double offsetTheta() const {
 		return _offsetTheta;
 	}
 	/// access the coordinate offset in phi
-	double getOffsetPhi() const {
+	double offsetPhi() const {
 		return _offsetPhi;
 	}
 	/// access the field name used for theta
-	std::string getFieldNameTheta() const {
+	std::string fieldNameTheta() const {
 		return _thetaID;
 	}
 	/// access the field name used for phi
-	std::string getFieldNamePhi() const {
+	std::string fieldNamePhi() const {
 		return _phiID;
 	}
 	/// set the number of bins in theta
@@ -78,14 +76,12 @@ public:
 	void setFieldNamePhi(const std::string& name) {
 		_phiID = name;
 	}
-	/// access the set of parameters for this segmentation
-	Parameters parameters() const;
 
 protected:
 	/// the number of bins in theta
-	int _thetaBins;
+	double _thetaBins;
 	/// the number of bins in phi
-	int _phiBins;
+	double _phiBins;
 	/// the coordinate offset in theta
 	double _offsetTheta;
 	/// the coordinate offset in phi
diff --git a/DDSegmentation/include/DDSegmentation/Segmentation.h b/DDSegmentation/include/DDSegmentation/Segmentation.h
index c1d5c730e..59beb6753 100644
--- a/DDSegmentation/include/DDSegmentation/Segmentation.h
+++ b/DDSegmentation/include/DDSegmentation/Segmentation.h
@@ -9,7 +9,10 @@
 #define DDSegmentation_SEGMENTATION_H_
 
 #include "DDSegmentation/BitField64.h"
+#include "DDSegmentation/SegmentationFactory.h"
+#include "DDSegmentation/SegmentationParameter.h"
 
+#include <map>
 #include <utility>
 #include <string>
 #include <vector>
@@ -17,81 +20,128 @@
 namespace DD4hep {
 namespace DDSegmentation {
 
-/// Segmentation parameter definition
-typedef std::pair<std::string,double> Parameter;
-/// Segmentation parameter container definition
-typedef std::vector<Parameter>        Parameters;
+typedef SegmentationParameter* Parameter;
+typedef std::vector<Parameter> Parameters;
 
+/// Useful typedefs to differentiate cell IDs and volume IDs
+typedef long long int CellID;
+typedef long long int VolumeID;
+
+/// Simple container for a physics vector
+struct Position {
+	/// Default constructor
+	Position(double x = 0., double y = 0., double z = 0.) :
+			X(x), Y(y), Z(z) {
+	}
+	/// Constructor using a foreign vector class. Requires methods x(), y() and z()
+	template <typename T> Position(const T& v) {
+		X = v.x();
+		Y = v.y();
+		Z = v.Z();
+	}
+	/// Access to x value (required for use with ROOT GenVector)
+	double x() const {
+		return X;
+	}
+	/// Access to y value (required for use with ROOT GenVector)
+	double y() const {
+		return Y;
+	}
+	/// Access to z value (required for use with ROOT GenVector)
+	double z() const {
+		return Z;
+	}
+	double X, Y, Z;
+};
+
+/// Base class for all segmentations
 class Segmentation {
 public:
-	/// default constructor using an arbitrary type
-	template <typename TYPE> Segmentation(TYPE cellEncoding);
-	/// destructor
+	/// Destructor
 	virtual ~Segmentation();
 
-	/// determine the position based on the cell ID
-	virtual std::vector<double> getPosition(const long64& cellID) const = 0;
-	/// determine the cell ID based on the position
-	virtual long64 getCellID(double x, double y, double z) const = 0;
-	/// determine the cell ID based on the position
-	long64 getCellID(const std::vector<double>& position) const;
-	/// determine the cell ID based on the position
-	long64 getCellID(const double* position) const;
-	/// check if it is a local segmentation
-	bool isLocal() const {
-		return _isLocal;
-	}
-	/// set if the segmentation is using local coordinates
-	void setLocal(bool isLocal) {
-		_isLocal = isLocal;
-	}
-	/// access the encoding string
+	/// Determine the local position based on the cell ID
+	virtual Position position(const CellID& cellID) const = 0;
+	/// Determine the cell ID based on the position
+	virtual CellID cellID(const Position& localPosition, const Position& globalPosition,
+			const VolumeID& volumeID) const = 0;
+	/// Access the encoding string
 	std::string fieldDescription() const {
 		return _decoder->fieldDescription();
 	}
-	/// access the segmentation name
-	std::string name() const {
+	/// Access the segmentation name
+	const std::string& name() const {
 		return _name;
 	}
 	/// Set the segmentation name
 	void setName(const std::string& value) {
 		_name = value;
 	}
-	/// access the segmentation type
-	std::string type() const {
+	/// Access the segmentation type
+	const std::string& type() const {
 		return _type;
 	}
 	/// Set the segmentation type
-	void setType(const std::string& value)  {
+	void setType(const std::string& value) {
+		//FIXME: Should not be able to change the type!
 		_type = value;
 	}
-	/// access the underlying decoder
+	/// Access the description of the segmentation
+	const std::string& description() const {
+		return _description;
+	}
+	/// Access the underlying decoder
 	BitField64* decoder() {
 		return _decoder;
 	}
-	/// set the underlying decoder
+	/// Set the underlying decoder
 	void setDecoder(BitField64* decoder);
-	/// access the set of parameters for this segmentation
-	Parameters parameters() const;
+	/// Access the set of parameters
+//	Parameters parameters() const;
+	/// Access to parameter by name
+	SegmentationParameter* parameter(const std::string& parameterName);
+	/// Access to parameter by name
+	const SegmentationParameter* parameter(const std::string& parameterName) const;
+	/// Access to parameter value by name
+	double parameterValue(const std::string& parameterName) const;
+	/// Set the parameter value by name
+	void setParameterValue(const std::string& parameterName, double value);
+	/// Access to all parameters
+	std::vector<SegmentationParameter*> parameters();
+	/// Access to all parameters
+	std::vector<const SegmentationParameter*> parameters() const;
 
 protected:
-	/// the cell ID encoder and decoder
+	/// Default constructor used by derived classes passing the encoding string
+	Segmentation(const std::string& cellEncoding = "");
+
+	/// Add a parameter to this segmentation. Used by derived classes to define their parameters
+	void registerParameter(const std::string& name, const std::string& description, double& parameter, double defaultValue = 0., bool isOptional = false);
+	/// Helper method to convert a bin number to a 1D position
+	double binToPosition(CellID bin, double cellSize, double offset = 0.) const;
+	/// Helper method to convert a 1D position to a cell ID
+	int positionToBin(double position, double cellSize, double offset = 0.) const;
+
+	/// The cell ID encoder and decoder
 	mutable BitField64* _decoder;
-	/// keeps track of the decoder ownership
+	/// Keeps track of the decoder ownership
 	bool _ownsDecoder;
-	/// the segmentation name
+	/// The segmentation name
 	std::string _name;
-	/// the segmentation type
+	/// The segmentation type
 	std::string _type;
-	/// distinguish between local and global coordinate systems
-	bool _isLocal;
+	/// The description of the segmentation
+	std::string _description;
 
-	/// helper method to convert a bin number to a 1D position
-	double binToPosition(long64 bin, double cellSize, double offset = 0.) const;
-	/// helper method to convert a 1D position to a cell ID
-	int positionToBin(double position, double cellSize, double offset = 0.) const;
+private:
+	/// The parameters for this segmentation
+	std::map<std::string, SegmentationParameter*> _parameters;
 };
 
+/// Macro to instantiate a new SegmentationCreator by its type name
+#define REGISTER_SEGMENTATION(classname) \
+	static const SegmentationCreator<classname> classname##_creator(#classname);
+
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
 #endif /* DDSegmentation_SEGMENTATION_H_ */
diff --git a/DDSegmentation/include/DDSegmentation/SegmentationFactory.h b/DDSegmentation/include/DDSegmentation/SegmentationFactory.h
new file mode 100644
index 000000000..8991cba88
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/SegmentationFactory.h
@@ -0,0 +1,77 @@
+/*
+ * SegmentationFactory.h
+ *
+ * Factory and helper classes to allow instantiation of segmentations by name.
+ *
+ *  Created on: Dec 15, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#ifndef DDSegmentation_SEGMENTATIONFACTORY_H_
+#define DDSegmentation_SEGMENTATIONFACTORY_H_
+
+#include "DDSegmentation/Segmentation.h"
+
+#include <map>
+#include <vector>
+#include <string>
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+/// Forward declaration required because of circular dependency
+class Segmentation;
+class SegmentationCreatorBase;
+
+/// Base class for the SegmentationCreator objects. Allows to use the factory without template.
+class SegmentationCreatorBase {
+public:
+	/// Default constructor. Takes the class name as argument and takes care of registration with the factory
+	SegmentationCreatorBase(const std::string& name);
+	/// Destructor
+	virtual ~SegmentationCreatorBase() {};
+	/// Create a new object
+	virtual Segmentation* create() const = 0;
+};
+
+/// Concrete class to create segmentation objects. Every segmentation needs to instantiate a static instance of this.
+template<class TYPE> class SegmentationCreator : public SegmentationCreatorBase {
+public:
+	/// Default constructor. Takes the class name as argument which should match the class type
+	SegmentationCreator<TYPE>(const std::string& name) : SegmentationCreatorBase(name) {};
+	/// Destructor
+	virtual ~SegmentationCreator() {};
+	/// Create a new object of the given type.
+	Segmentation* create() const {return new TYPE("");};
+};
+
+/// Factory for creating segmentation objects by type name
+class SegmentationFactory {
+	/// Allow SegmentationCreators to register themselves with the factory
+	friend class SegmentationCreatorBase;
+public:
+	/// Access to the global factory instance
+	static SegmentationFactory* instance();
+	/// Create a new segmentation object with the given type name. Returns NULL if type name is unknown.
+	Segmentation* create(const std::string& name) const;
+	/// Access to the list of registered segmentations
+	std::vector<std::string> registeredSegmentations() const;
+protected:
+	/// Default constructor
+	SegmentationFactory() {};
+	/// Copy constructor
+	SegmentationFactory(const SegmentationFactory&) {};
+	/// Destructor
+	virtual ~SegmentationFactory() {};
+	/// Registers a new SegmentationCreator with the factory
+	void registerSegmentation(const std::string& name, SegmentationCreatorBase* creator);
+	/// Map to store SegmentationCreators by name
+	std::map<std::string, SegmentationCreatorBase*> _segmentations;
+private:
+	/// The global factory instance
+	static SegmentationFactory* _instance;
+};
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
+#endif /* DDSegmentation_SEGMENTATIONFACTORY_H_ */
diff --git a/DDSegmentation/include/DDSegmentation/SegmentationParameter.h b/DDSegmentation/include/DDSegmentation/SegmentationParameter.h
new file mode 100644
index 000000000..1b9e09f44
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/SegmentationParameter.h
@@ -0,0 +1,53 @@
+/*
+ * SegmentationParameter.h
+ *
+ * Helper class to hold a segmentation parameter with its description.
+ *
+ *  Created on: Dec 16, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#ifndef DDSegmentation_SEGMENTATIONPARAMETER_H_
+#define DDSegmentation_SEGMENTATIONPARAMETER_H_
+
+#include <string>
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+/// Class to hold a segmentation parameter with its description
+class SegmentationParameter {
+public:
+	/// Default constructor
+	SegmentationParameter(const std::string& name, const std::string& description, double& parameter,
+			double defaultValue = 0., bool isOptional = false);
+	/// Destructor
+	virtual ~SegmentationParameter() {};
+	/// Access to the parameter name
+	const std::string& name() const;
+	/// Access to the parameter description
+	const std::string& description() const;
+	/// Access to the parameter value
+	double& value();
+	/// Access to the parameter value
+	double value() const;
+	/// Check if this parameter is optional
+	bool isOptional() const;
+	/// Printable version
+	std::string toString() const;
+protected:
+	/// The parameter name
+	std::string _name;
+	/// The parameter description
+	std::string _description;
+	/// The parameter value
+	double& _parameter;
+	/// The parameter default value
+	double _defaultValue;
+	/// Store if parameter is optional
+	bool _isOptional;
+};
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
+#endif /* DDSegmentation_SEGMENTATIONPARAMETER_H_ */
diff --git a/DDSegmentation/include/DDSegmentation/SegmentationUtil.h b/DDSegmentation/include/DDSegmentation/SegmentationUtil.h
index 267b40570..a310a7f44 100644
--- a/DDSegmentation/include/DDSegmentation/SegmentationUtil.h
+++ b/DDSegmentation/include/DDSegmentation/SegmentationUtil.h
@@ -13,13 +13,13 @@
 
 namespace DD4hep {
 namespace DDSegmentation {
-namespace SegmentationUtil {
+namespace Util {
 
 ///////////////////////////////////////////////////////////////////////
 ///           Conventions                                           ///
 /// - x, y, z are the Cartesian coordinates                         ///
 /// - r is the magnitude in the xy-plane                            ///
-/// - rho is the magnitude                                          ///
+/// - mag is the magnitude                                          ///
 ///////////////////////////////////////////////////////////////////////
 
 
@@ -29,270 +29,70 @@ namespace SegmentationUtil {
 
 
 /// calculates the radius in xyz from Cartesian coordinates
-template <typename TYPE> TYPE getRhoFromXYZ(TYPE x, TYPE y, TYPE z) {
-	return std::sqrt(x * x + y * y + z * z);
+double magFromXYZ(const Position& position) {
+	return std::sqrt(position.X * position.X + position.Y * position.Y + position.Z * position.Z);
 }
-/// calculates the radius in xyz from Cartesian coordinates
-template <typename TYPE> TYPE getRhoFromXYZ(std::vector<TYPE> position) {
-	return getRhoFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in xyz from Cartesian coordinates
-template <typename TYPE> TYPE getRhoFromXYZ(const std::vector<TYPE>& position) {
-	return getRhoFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in xyz from Cartesian coordinates
-template <typename TYPE> TYPE getRhoFromXYZ(TYPE* position) {
-	return getRhoFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in xyz from Cartesian coordinates
-template <typename TYPE> TYPE getRhoFromXYZ(const TYPE* position) {
-	return getRhoFromXYZ(position[0], position[1], position[2]);
-}
-
 
 /// calculates the radius in the xy-plane from Cartesian coordinates
-template <typename TYPE> TYPE getRadiusFromXYZ(TYPE x, TYPE y, TYPE z) {
-	return std::sqrt(x * x + y * y);
-}
-/// calculates the radius in the xy-plane from Cartesian coordinates
-template <typename TYPE> TYPE getRadiusFromXYZ(std::vector<TYPE> position) {
-	return getRadiusFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in the xy-plane from Cartesian coordinates
-template <typename TYPE> TYPE getRadiusFromXYZ(const std::vector<TYPE>& position) {
-	return getRadiusFromXYZ(position[0], position[1], position[2]);
+double radiusFromXYZ(const Position& position) {
+	return std::sqrt(position.X * position.X + position.Y * position.Y);
 }
-/// calculates the radius in the xy-plane from Cartesian coordinates
-template <typename TYPE> TYPE getRadiusFromXYZ(TYPE* position) {
-	return getRadiusFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in the xy-plane from Cartesian coordinates
-template <typename TYPE> TYPE getRadiusFromXYZ(const TYPE* position) {
-	return getRadiusFromXYZ(position[0], position[1], position[2]);
-}
-
 
 /// calculates the polar angle theta from Cartesian coordinates
-template <typename TYPE> TYPE getThetaFromXYZ(TYPE x, TYPE y, TYPE z) {
-	TYPE r = getRadiusFromXYZ(x, y, z);
-	return std::acos(z / r);
-}
-/// calculates the polar angle theta from Cartesian coordinates
-template <typename TYPE> TYPE getThetaFromXYZ(std::vector<TYPE> position) {
-	return getThetaFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the polar angle theta from Cartesian coordinates
-template <typename TYPE> TYPE getThetaFromXYZ(const std::vector<TYPE>& position) {
-	return getThetaFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the polar angle theta from Cartesian coordinates
-template <typename TYPE> TYPE getThetaFromXYZ(TYPE* position) {
-	return getThetaFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the polar angle theta from Cartesian coordinates
-template <typename TYPE> TYPE getThetaFromXYZ(const TYPE* position) {
-	return getThetaFromXYZ(position[0], position[1], position[2]);
+double thetaFromXYZ(const Position& position) {
+	return std::acos(position.Z / radiusFromXYZ(position));
 }
 
-
-/// calculates the azimuthal angle phi from Cartesian coordinates
-template <typename TYPE> TYPE getPhiFromXYZ(TYPE x, TYPE y, TYPE z) {
-	return std::atan2(y, x);
-}
 /// calculates the azimuthal angle phi from Cartesian coordinates
-template <typename TYPE> TYPE getPhiFromXYZ(std::vector<TYPE> position) {
-	return getPhiFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the azimuthal angle phi from Cartesian coordinates
-template <typename TYPE> TYPE getPhiFromXYZ(const std::vector<TYPE>& position) {
-	return getPhiFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the azimuthal angle phi from Cartesian coordinates
-template <typename TYPE> TYPE getPhiFromXYZ(TYPE* position) {
-	return getPhiFromXYZ(position[0], position[1], position[2]);
-}
-/// calculates the azimuthal angle phi from Cartesian coordinates
-template <typename TYPE> TYPE getPhiFromXYZ(const TYPE* position) {
-	return getPhiFromXYZ(position[0], position[1], position[2]);
+double phiFromXYZ(const Position& position) {
+	return std::atan2(position.Y, position.X);
 }
 
-
 /////////////////////////////////////////////////////////////
 /// Conversions from cylindrical to Cartesian coordinates ///
 /////////////////////////////////////////////////////////////
 
 /// calculates the Cartesian position from cylindrical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRPhiZ(TYPE r, TYPE phi, TYPE z) {
-	std::vector<double> position(3);
-	position[0] = getXFromRPhiZ(r, phi, z);
-	position[1] = getYFromRPhiZ(r, phi, z);
-	position[2] = z;
-	return position;
-}
-/// calculates the Cartesian position from cylindrical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRPhiZ(std::vector<TYPE> position) {
-	return getPositionFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from cylindrical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRPhiZ(const std::vector<TYPE>& position) {
-	return getPositionFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from cylindrical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRPhiZ(TYPE* position) {
-	return getPositionFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from cylindrical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRPhiZ(const TYPE* position) {
-	return getPositionFromRPhiZ(position[0], position[1], position[2]);
+Position positionFromRPhiZ(double r, double phi, double z) {
+	return Position(r * std::cos(phi), r * std::sin(phi), z);
 }
 
-
 /// calculates the radius in xyz from cylindrical coordinates
-template <typename TYPE> TYPE getRhoFromRPhiZ(TYPE r, TYPE phi, TYPE z) {
+double magFromRPhiZ(double r, double phi, double z) {
 	return std::sqrt(r * r + z * z);
 }
-/// calculates the radius in xyz from cylindrical coordinates
-template <typename TYPE> TYPE getRhoFromRPhiZ(std::vector<TYPE> position) {
-	return getRhoFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in xyz from cylindrical coordinates
-template <typename TYPE> TYPE getRhoFromRPhiZ(const std::vector<TYPE>& position) {
-	return getRhoFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in xyz from cylindrical coordinates
-template <typename TYPE> TYPE getRhoFromRPhiZ(TYPE* position) {
-	return getRhoFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the radius in xyz from cylindrical coordinates
-template <typename TYPE> TYPE getRhoFromRPhiZ(const TYPE* position) {
-	return getRhoFromRPhiZ(position[0], position[1], position[2]);
-}
-
 
 /// calculates x from cylindrical coordinates
-template <typename TYPE> TYPE getXFromRPhiZ(TYPE r, TYPE phi, TYPE z) {
+double xFromRPhiZ(double r, double phi, double z) {
 	return r * std::cos(phi);
 }
-/// calculates x from cylindrical coordinates
-template <typename TYPE> TYPE getXFromRPhiZ(std::vector<TYPE> position) {
-	return getXFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates x from cylindrical coordinates
-template <typename TYPE> TYPE getXFromRPhiZ(const std::vector<TYPE>& position) {
-	return getXFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates x from cylindrical coordinates
-template <typename TYPE> TYPE getXFromRPhiZ(TYPE* position) {
-	return getXFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates x from cylindrical coordinates
-template <typename TYPE> TYPE getXFromRPhiZ(const TYPE* position) {
-	return getXFromRPhiZ(position[0], position[1], position[2]);
-}
-
 
 /// calculates y from cylindrical coordinates
-template <typename TYPE> TYPE getYFromRPhiZ(TYPE r, TYPE phi, TYPE z) {
+double yFromRPhiZ(double r, double phi, double z) {
 	return r * std::sin(phi);
 }
-/// calculates y from cylindrical coordinates
-template <typename TYPE> TYPE getYFromRPhiZ(std::vector<TYPE> position) {
-	return getYFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates y from cylindrical coordinates
-template <typename TYPE> TYPE getYFromRPhiZ(const std::vector<TYPE>& position) {
-	return getYFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates y from cylindrical coordinates
-template <typename TYPE> TYPE getYFromRPhiZ(TYPE* position) {
-	return getYFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates y from cylindrical coordinates
-template <typename TYPE> TYPE getYFromRPhiZ(const TYPE* position) {
-	return getYFromRPhiZ(position[0], position[1], position[2]);
-}
-
 
 /// calculates the polar angle theta from cylindrical coordinates
-template <typename TYPE> TYPE getThetaFromRPhiZ(TYPE r, TYPE phi, TYPE z) {
+double thetaFromRPhiZ(double r, double phi, double z) {
 	return r * std::atan(z / r);
 }
-/// calculates the polar angle theta from cylindrical coordinates
-template <typename TYPE> TYPE getThetaFromRPhiZ(std::vector<TYPE> position) {
-	return getThetaFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the polar angle theta from cylindrical coordinates
-template <typename TYPE> TYPE getThetaFromRPhiZ(const std::vector<TYPE>& position) {
-	return getThetaFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the polar angle theta from cylindrical coordinates
-template <typename TYPE> TYPE getThetaFromRPhiZ(TYPE* position) {
-	return getThetaFromRPhiZ(position[0], position[1], position[2]);
-}
-/// calculates the polar angle theta from cylindrical coordinates
-template <typename TYPE> TYPE getThetaFromRPhiZ(const TYPE* position) {
-	return getThetaFromRPhiZ(position[0], position[1], position[2]);
-}
-
 
 /////////////////////////////////////////////////////////////
 /// Conversions from spherical to Cartesian coordinates   ///
 /////////////////////////////////////////////////////////////
 
 /// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRThetaPhi(TYPE r, TYPE theta, TYPE phi) {
-	std::vector<double> position(3);
-	position[0] = r * std::cos(phi);
-	position[1] = r * std::sin(phi);
-	position[2] = r * std::tan(theta);
-	return position;
-}
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRThetaPhi(std::vector<TYPE> position) {
-	return getPositionFromRThetaPhi(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRThetaPhi(const std::vector<TYPE>& position) {
-	return getPositionFromRThetaPhi(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRThetaPhi(TYPE* position) {
-	return getPositionFromRThetaPhi(position[0], position[1], position[2]);
+Position positionFromRThetaPhi(double r, double theta, double phi) {
+	return Position(r * std::cos(phi), r * std::sin(phi), r * std::tan(theta));
 }
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRThetaPhi(const TYPE* position) {
-	return getPositionFromRThetaPhi(position[0], position[1], position[2]);
-}
-
 
 /// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRhoThetaPhi(TYPE rho, TYPE theta, TYPE phi) {
-	std::vector<double> position(3);
-	double r = rho * sin(theta);
-	position[0] = r * std::cos(phi);
-	position[1] = r * std::sin(phi);
-	position[2] = rho * std::cos(theta);
-	return position;
-}
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRhoThetaPhi(std::vector<TYPE> position) {
-	return getPositionFromRhoThetaPhi(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRhoThetaPhi(const std::vector<TYPE>& position) {
-	return getPositionFromRhoThetaPhi(position[0], position[1], position[2]);
-}
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRhoThetaPhi(TYPE* position) {
-	return getPositionFromRhoThetaPhi(position[0], position[1], position[2]);
+Position positionFromMagThetaPhi(double mag, double theta, double phi) {
+	double r = mag * sin(theta);
+	return Position(r * std::cos(phi), r * std::sin(phi), mag * std::cos(theta));
 }
-/// calculates the Cartesian position from spherical coordinates
-template <typename TYPE> std::vector<TYPE> getPositionFromRhoThetaPhi(const TYPE* position) {
-	return getPositionFromRhoThetaPhi(position[0], position[1], position[2]);
-}
-
 
-} /* namespace SegmentationUtil */
+} /* namespace Util */
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
 
diff --git a/DDSegmentation/src/CartesianGrid.cpp b/DDSegmentation/src/CartesianGrid.cpp
index 55b970220..6e9d97947 100644
--- a/DDSegmentation/src/CartesianGrid.cpp
+++ b/DDSegmentation/src/CartesianGrid.cpp
@@ -12,33 +12,13 @@ namespace DDSegmentation {
 
 using std::string;
 
-/// default constructor using an encoding string
-template<> CartesianGrid::CartesianGrid(const string& cellEncoding) :
+/// Default constructor used by derived classes passing the encoding string
+CartesianGrid::CartesianGrid(const string& cellEncoding) :
 		Segmentation(cellEncoding) {
-
 }
 
-/// default constructor using an encoding string
-template<> CartesianGrid::CartesianGrid(string cellEncoding) :
-		Segmentation(cellEncoding) {
-
-}
-
-/// default constructor using an encoding string
-template<> CartesianGrid::CartesianGrid(const char* cellEncoding) :
-		Segmentation(cellEncoding) {
-
-}
-
-/// default constructor using an existing decoder
-template<> CartesianGrid::CartesianGrid(BitField64* decoder) :
-		Segmentation(decoder) {
-
-}
-
-/// destructor
+/// Destructor
 CartesianGrid::~CartesianGrid() {
-
 }
 
 } /* namespace DDSegmentation */
diff --git a/DDSegmentation/src/CartesianGridXY.cpp b/DDSegmentation/src/CartesianGridXY.cpp
index 33a8059ff..a345ada3f 100644
--- a/DDSegmentation/src/CartesianGridXY.cpp
+++ b/DDSegmentation/src/CartesianGridXY.cpp
@@ -10,40 +10,22 @@
 namespace DD4hep {
 namespace DDSegmentation {
 
-using std::make_pair;
 using std::string;
-using std::vector;
 
 /// default constructor using an encoding string
-template<> CartesianGridXY::CartesianGridXY(const string& cellEncoding, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, const string& xField, const string& yField) :
-		CartesianGrid(cellEncoding), _gridSizeX(gridSizeX), _gridSizeY(gridSizeY), _offsetX(offsetX), _offsetY(offsetY), _xId(
-				xField), _yId(yField) {
-	_type = "grid_xy";
-}
-
-/// default constructor using an encoding string
-template<> CartesianGridXY::CartesianGridXY(string cellEncoding, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, const string& xField, const string& yField) :
-		CartesianGrid(cellEncoding), _gridSizeX(gridSizeX), _gridSizeY(gridSizeY), _offsetX(offsetX), _offsetY(offsetY), _xId(
-				xField), _yId(yField) {
-	_type = "grid_xy";
-}
+CartesianGridXY::CartesianGridXY(const string& cellEncoding) :
+		CartesianGrid(cellEncoding) {
+	// define type and description
+	_type = "CartesianGridXY";
+	_description = "Cartesian segmentation in the local XY-plane";
 
-/// default constructor using an encoding string
-template<> CartesianGridXY::CartesianGridXY(const char* cellEncoding, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, const string& xField, const string& yField) :
-		CartesianGrid(cellEncoding), _gridSizeX(gridSizeX), _gridSizeY(gridSizeY), _offsetX(offsetX), _offsetY(offsetY), _xId(
-				xField), _yId(yField) {
-	_type = "grid_xy";
-}
-
-/// default constructor using an existing decoder
-template<> CartesianGridXY::CartesianGridXY(BitField64* decoder, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, const string& xField, const string& yField) :
-		CartesianGrid(decoder), _gridSizeX(gridSizeX), _gridSizeY(gridSizeY), _offsetX(offsetX), _offsetY(offsetY), _xId(
-				xField), _yId(yField) {
-	_type = "grid_xy";
+	// register all necessary parameters
+	registerParameter("gridSizeX", "Cell size in X", _gridSizeX, 1.);
+	registerParameter("gridSizeY", "Cell size in Y", _gridSizeY, 1.);
+	registerParameter("offsetX", "Cell offset in X", _offsetX, 0., true);
+	registerParameter("offsetY", "Cell offset in Y", _offsetY, 0., true);
+	_xId = "x";
+	_yId = "y";
 }
 
 /// destructor
@@ -52,32 +34,23 @@ CartesianGridXY::~CartesianGridXY() {
 }
 
 /// determine the position based on the cell ID
-vector<double> CartesianGridXY::getPosition(const long64& cellID) const {
+Position CartesianGridXY::position(const CellID& cellID) const {
 	_decoder->setValue(cellID);
-	vector<double> localPosition(3);
-	localPosition[0] = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
-	localPosition[1] = binToPosition((*_decoder)[_yId].value(), _gridSizeY, _offsetY);
-	localPosition[2] = 0.;
-	return localPosition;
+	Position position;
+	position.X = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
+	position.Y = binToPosition((*_decoder)[_yId].value(), _gridSizeY, _offsetY);
+	return position;
 }
 
 /// determine the cell ID based on the position
-long64 CartesianGridXY::getCellID(double x, double y, double z) const {
+CellID CartesianGridXY::cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const {
 	_decoder->reset();
-	(*_decoder)[_xId] = positionToBin(x, _gridSizeX, _offsetX);
-	(*_decoder)[_yId] = positionToBin(y, _gridSizeY, _offsetY);
+	(*_decoder)[_xId] = positionToBin(localPosition.X, _gridSizeX, _offsetX);
+	(*_decoder)[_yId] = positionToBin(localPosition.Y, _gridSizeY, _offsetY);
 	return _decoder->getValue();
 }
 
-/// access the set of parameters for this segmentation
-Parameters CartesianGridXY::parameters() const {
-	Parameters parameters;
-	parameters.push_back(make_pair("grid_size_x", _gridSizeX));
-	parameters.push_back(make_pair("grid_size_y", _gridSizeY));
-	parameters.push_back(make_pair("offset_x", _offsetX));
-	parameters.push_back(make_pair("offset_y", _offsetY));
-	return parameters;
-}
+REGISTER_SEGMENTATION(CartesianGridXY)
 
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/DDSegmentation/src/CartesianGridXYZ.cpp b/DDSegmentation/src/CartesianGridXYZ.cpp
index 393685b23..524848399 100644
--- a/DDSegmentation/src/CartesianGridXYZ.cpp
+++ b/DDSegmentation/src/CartesianGridXYZ.cpp
@@ -10,40 +10,19 @@
 namespace DD4hep {
 namespace DDSegmentation {
 
-using std::make_pair;
 using std::string;
-using std::vector;
 
 /// default constructor using an encoding string
-template<> CartesianGridXYZ::CartesianGridXYZ(const string& cellEncoding, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, const string& xField, const string& yField, const string& zField) :
-		CartesianGridXY(cellEncoding, gridSizeX, gridSizeY, offsetX, offsetY, xField, yField), _gridSizeZ(gridSizeZ), _offsetZ(
-				offsetZ), _zId(zField) {
-	_type = "grid_xyz";
-}
-
-/// default constructor using an encoding string
-template<> CartesianGridXYZ::CartesianGridXYZ(string cellEncoding, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, const string& xField, const string& yField, const string& zField) :
-		CartesianGridXY(cellEncoding, gridSizeX, gridSizeY, offsetX, offsetY, xField, yField), _gridSizeZ(gridSizeZ), _offsetZ(
-				offsetZ), _zId(zField) {
-	_type = "grid_xyz";
-}
+CartesianGridXYZ::CartesianGridXYZ(const string& cellEncoding) :
+		CartesianGridXY(cellEncoding) {
+	// define type and description
+	_type = "CartesianGridXYZ";
+	_description = "Cartesian segmentation in the local coordinates";
 
-/// default constructor using an encoding string
-template<> CartesianGridXYZ::CartesianGridXYZ(const char* cellEncoding, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, const string& xField, const string& yField, const string& zField) :
-		CartesianGridXY(cellEncoding, gridSizeX, gridSizeY, offsetX, offsetY, xField, yField), _gridSizeZ(gridSizeZ), _offsetZ(
-				offsetZ), _zId(zField) {
-	_type = "grid_xyz";
-}
-
-/// default constructor using an existing decoder
-template<> CartesianGridXYZ::CartesianGridXYZ(BitField64* decoder, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, const string& xField, const string& yField, const string& zField) :
-		CartesianGridXY(decoder, gridSizeX, gridSizeY, offsetX, offsetY, xField, yField), _gridSizeZ(gridSizeZ), _offsetZ(
-				offsetZ), _zId(zField) {
-	_type = "grid_xyz";
+	// register all necessary parameters
+	registerParameter("gridSizeZ", "Cell size in Z", _gridSizeZ, 1.);
+	registerParameter("offsetZ", "Cell offset in Z", _offsetZ, 0., true);
+	_zId = "z";
 }
 
 /// destructor
@@ -52,35 +31,25 @@ CartesianGridXYZ::~CartesianGridXYZ() {
 }
 
 /// determine the position based on the cell ID
-vector<double> CartesianGridXYZ::getPosition(const long64& cellID) const {
+Position CartesianGridXYZ::position(const CellID& cellID) const {
 	_decoder->setValue(cellID);
-	vector<double> localPosition(3);
-	localPosition[0] = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
-	localPosition[1] = binToPosition((*_decoder)[_yId].value(), _gridSizeY, _offsetY);
-	localPosition[2] = binToPosition((*_decoder)[_zId].value(), _gridSizeZ, _offsetZ);
-	return localPosition;
+	Position position;
+	position.X = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
+	position.Y = binToPosition((*_decoder)[_yId].value(), _gridSizeY, _offsetY);
+	position.Z = binToPosition((*_decoder)[_zId].value(), _gridSizeZ, _offsetZ);
+	return position;
 }
 
 /// determine the cell ID based on the position
-long64 CartesianGridXYZ::getCellID(double x, double y, double z) const {
+CellID CartesianGridXYZ::cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const {
 	_decoder->reset();
-	(*_decoder)[_xId] = positionToBin(x, _gridSizeX, _offsetX);
-	(*_decoder)[_yId] = positionToBin(y, _gridSizeY, _offsetY);
-	(*_decoder)[_zId] = positionToBin(z, _gridSizeZ, _offsetZ);
+	(*_decoder)[_xId] = positionToBin(localPosition.X, _gridSizeX, _offsetX);
+	(*_decoder)[_yId] = positionToBin(localPosition.Y, _gridSizeY, _offsetY);
+	(*_decoder)[_zId] = positionToBin(localPosition.Z, _gridSizeZ, _offsetZ);
 	return _decoder->getValue();
 }
 
-/// access the set of parameters for this segmentation
-Parameters CartesianGridXYZ::parameters() const {
-	Parameters parameters;
-	parameters.push_back(make_pair("grid_size_x", _gridSizeX));
-	parameters.push_back(make_pair("grid_size_y", _gridSizeY));
-	parameters.push_back(make_pair("grid_size_z", _gridSizeZ));
-	parameters.push_back(make_pair("offset_x", _offsetX));
-	parameters.push_back(make_pair("offset_y", _offsetY));
-	parameters.push_back(make_pair("offset_z", _offsetZ));
-	return parameters;
-}
+REGISTER_SEGMENTATION(CartesianGridXYZ)
 
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/DDSegmentation/src/CartesianGridXZ.cpp b/DDSegmentation/src/CartesianGridXZ.cpp
index 8c46746b9..61ec209c1 100644
--- a/DDSegmentation/src/CartesianGridXZ.cpp
+++ b/DDSegmentation/src/CartesianGridXZ.cpp
@@ -15,35 +15,19 @@ using std::string;
 using std::vector;
 
 /// default constructor using an encoding string
-template<> CartesianGridXZ::CartesianGridXZ(const string& cellEncoding, double gridSizeX, double gridSizeZ, double offsetX,
-		double offsetZ, const string& xField, const string& zField) :
-		CartesianGrid(cellEncoding), _gridSizeX(gridSizeX), _gridSizeZ(gridSizeZ), _offsetX(offsetX), _offsetZ(offsetZ), _xId(
-				xField), _zId(zField) {
-	_type = "grid_xz";
-}
-
-/// default constructor using an encoding string
-template<> CartesianGridXZ::CartesianGridXZ(string cellEncoding, double gridSizeX, double gridSizeZ, double offsetX,
-		double offsetZ, const string& xField, const string& zField) :
-		CartesianGrid(cellEncoding), _gridSizeX(gridSizeX), _gridSizeZ(gridSizeZ), _offsetX(offsetX), _offsetZ(offsetZ), _xId(
-				xField), _zId(zField) {
-	_type = "grid_xz";
-}
+CartesianGridXZ::CartesianGridXZ(const string& cellEncoding) :
+	CartesianGrid(cellEncoding) {
+	// define type and description
+	_type = "CartesianGridXY";
+	_description = "Cartesian segmentation in the local XY-plane";
 
-/// default constructor using an encoding string
-template<> CartesianGridXZ::CartesianGridXZ(const char* cellEncoding, double gridSizeX, double gridSizeZ, double offsetX,
-		double offsetZ, const string& xField, const string& zField) :
-		CartesianGrid(cellEncoding), _gridSizeX(gridSizeX), _gridSizeZ(gridSizeZ), _offsetX(offsetX), _offsetZ(offsetZ), _xId(
-				xField), _zId(zField) {
-	_type = "grid_xz";
-}
-
-/// default constructor using an existing decoder
-template<> CartesianGridXZ::CartesianGridXZ(BitField64* decoder, double gridSizeX, double gridSizeZ, double offsetX,
-		double offsetZ, const string& xField, const string& zField) :
-		CartesianGrid(decoder), _gridSizeX(gridSizeX), _gridSizeZ(gridSizeZ), _offsetX(offsetX), _offsetZ(offsetZ), _xId(
-				xField), _zId(zField) {
-	_type = "grid_xz";
+	// register all necessary parameters
+	registerParameter("gridSizeX", "Cell size in X", _gridSizeX, 1.);
+	registerParameter("gridSizeZ", "Cell size in Z", _gridSizeZ, 1.);
+	registerParameter("offsetX", "Cell offset in X", _offsetX, 0., true);
+	registerParameter("offsetZ", "Cell offset in Z", _offsetZ, 0., true);
+	_xId = "x";
+	_zId = "y";
 }
 
 /// destructor
@@ -52,32 +36,24 @@ CartesianGridXZ::~CartesianGridXZ() {
 }
 
 /// determine the position based on the cell ID
-vector<double> CartesianGridXZ::getPosition(const long64& cellID) const {
+Position CartesianGridXZ::position(const CellID& cellID) const {
 	_decoder->setValue(cellID);
 	vector<double> localPosition(3);
-	localPosition[0] = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
-	localPosition[1] = 0.;
-	localPosition[2] = binToPosition((*_decoder)[_zId].value(), _gridSizeZ, _offsetZ);
-	return localPosition;
+	Position position;
+	position.X = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
+	position.Z = binToPosition((*_decoder)[_zId].value(), _gridSizeZ, _offsetZ);
+	return position;
 }
 
 /// determine the cell ID based on the position
-long64 CartesianGridXZ::getCellID(double x, double y, double z) const {
+CellID CartesianGridXZ::cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const {
 	_decoder->reset();
-	(*_decoder)[_xId] = positionToBin(x, _gridSizeX, _offsetX);
-	(*_decoder)[_zId] = positionToBin(z, _gridSizeZ, _offsetZ);
+	(*_decoder)[_xId] = positionToBin(localPosition.X, _gridSizeX, _offsetX);
+	(*_decoder)[_zId] = positionToBin(localPosition.Z, _gridSizeZ, _offsetZ);
 	return _decoder->getValue();
 }
 
-/// access the set of parameters for this segmentation
-Parameters CartesianGridXZ::parameters() const {
-	Parameters parameters;
-	parameters.push_back(make_pair("grid_size_x", _gridSizeX));
-	parameters.push_back(make_pair("grid_size_z", _gridSizeZ));
-	parameters.push_back(make_pair("offset_x", _offsetX));
-	parameters.push_back(make_pair("offset_z", _offsetZ));
-	return parameters;
-}
+REGISTER_SEGMENTATION(CartesianGridXZ)
 
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/DDSegmentation/src/CylindricalSegmentation.cpp b/DDSegmentation/src/CylindricalSegmentation.cpp
index ad79bb170..f14443cc6 100644
--- a/DDSegmentation/src/CylindricalSegmentation.cpp
+++ b/DDSegmentation/src/CylindricalSegmentation.cpp
@@ -7,59 +7,20 @@
 
 #include "DDSegmentation/CylindricalSegmentation.h"
 
-#include <sstream>
-#include <stdexcept>
+using std::string;
 
 namespace DD4hep {
 namespace DDSegmentation {
 
-using std::map;
-using std::runtime_error;
-using std::string;
-using std::stringstream;
-
-/// default constructor using an encoding string
-template<> CylindricalSegmentation::CylindricalSegmentation(const string& cellEncoding, const string& layerField) :
-		Segmentation(cellEncoding), _layerID(layerField) {
-	_isLocal = false;
-}
-
-/// default constructor using an encoding string
-template<> CylindricalSegmentation::CylindricalSegmentation(string cellEncoding, const string& layerField) :
-		Segmentation(cellEncoding), _layerID(layerField) {
-	_isLocal = false;
-}
-
 /// default constructor using an encoding string
-template<> CylindricalSegmentation::CylindricalSegmentation(const char* cellEncoding, const string& layerField) :
-		Segmentation(cellEncoding), _layerID(layerField) {
-	_isLocal = false;
-}
-
-/// default constructor using an existing decoder
-template<> CylindricalSegmentation::CylindricalSegmentation(BitField64* decoder, const string& layerField) :
-		Segmentation(decoder), _layerID(layerField) {
-	_isLocal = false;
+CylindricalSegmentation::CylindricalSegmentation(const string& cellEncoding) :
+		Segmentation(cellEncoding) {
 }
 
-
 /// destructor
 CylindricalSegmentation::~CylindricalSegmentation() {
 
 }
 
-/// determine the radius based on the cell ID
-double CylindricalSegmentation::getRadius(const long64& cellID) const {
-	_decoder->setValue(cellID);
-	int layer = (*_decoder)[_layerID];
-	map<int, double>::const_iterator itMap = _layerRadiusMap.find(layer);
-	if (itMap == _layerRadiusMap.end()) {
-		stringstream message;
-		message << "getRadius(): Invalid layer index " << layer << " from cell ID " << cellID;
-		throw runtime_error(message.str());
-	}
-	return itMap->second;
-}
-
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/DDSegmentation/src/ProjectiveCylinder.cpp b/DDSegmentation/src/ProjectiveCylinder.cpp
index 686bc588b..6793435a8 100644
--- a/DDSegmentation/src/ProjectiveCylinder.cpp
+++ b/DDSegmentation/src/ProjectiveCylinder.cpp
@@ -15,40 +15,21 @@ namespace DD4hep {
 namespace DDSegmentation {
 
 using std::string;
-using SegmentationUtil::getPositionFromRThetaPhi;
 
 /// default constructor using an encoding string
-template<> ProjectiveCylinder::ProjectiveCylinder(const string& cellEncoding, int thetaBins, int phiBins,
-		double offsetTheta, double offsetPhi, const string& thetaField, const string& phiField,
-		const string& layerField) :
-		CylindricalSegmentation(cellEncoding, layerField), _thetaBins(thetaBins), _phiBins(phiBins), _offsetTheta(
-				offsetTheta), _offsetPhi(offsetPhi), _thetaID(thetaField), _phiID(phiField) {
-	_type = "projective_cylinder";
-}
-
-/// default constructor using an encoding string
-template<> ProjectiveCylinder::ProjectiveCylinder(string cellEncoding, int thetaBins, int phiBins, double offsetTheta,
-		double offsetPhi, const string& thetaField, const string& phiField, const string& layerField) :
-		CylindricalSegmentation(cellEncoding, layerField), _thetaBins(thetaBins), _phiBins(phiBins), _offsetTheta(
-				offsetTheta), _offsetPhi(offsetPhi), _thetaID(thetaField), _phiID(phiField) {
-	_type = "projective_cylinder";
-}
+ProjectiveCylinder::ProjectiveCylinder(const string& cellEncoding) :
+	CylindricalSegmentation(cellEncoding) {
+	// define type and description
+	_type = "ProjectiveCylinder";
+	_description = "Projective segmentation in the global coordinates";
 
-/// default constructor using an encoding string
-template<> ProjectiveCylinder::ProjectiveCylinder(const char* cellEncoding, int thetaBins, int phiBins,
-		double offsetTheta, double offsetPhi, const string& thetaField, const string& phiField,
-		const string& layerField) :
-		CylindricalSegmentation(cellEncoding, layerField), _thetaBins(thetaBins), _phiBins(phiBins), _offsetTheta(
-				offsetTheta), _offsetPhi(offsetPhi), _thetaID(thetaField), _phiID(phiField) {
-	_type = "projective_cylinder";
-}
-
-/// default constructor using an existing decoder
-template<> ProjectiveCylinder::ProjectiveCylinder(BitField64* decoder, int thetaBins, int phiBins, double offsetTheta,
-		double offsetPhi, const string& thetaField, const string& phiField, const string& layerField) :
-		CylindricalSegmentation(decoder, layerField), _thetaBins(thetaBins), _phiBins(phiBins), _offsetTheta(
-				offsetTheta), _offsetPhi(offsetPhi), _thetaID(thetaField), _phiID(phiField) {
-	_type = "projective_cylinder";
+	// register all necessary parameters
+	registerParameter("thetaBins", "Number of bins theta", _thetaBins, 1.);
+	registerParameter("phiBins", "Number of bins phi", _phiBins, 1.);
+	registerParameter("offsetTheta", "Angular offset in theta", _offsetTheta, 0., true);
+	registerParameter("offsetPhi", "Angular offset in phi", _offsetPhi, 0., true);
+	_thetaID = "theta";
+	_phiID = "phi";
 }
 
 /// destructor
@@ -57,29 +38,28 @@ ProjectiveCylinder::~ProjectiveCylinder() {
 }
 
 /// determine the local based on the cell ID
-std::vector<double> ProjectiveCylinder::getPosition(const long64& cellID) const {
-	double r = getRadius(cellID);
-	double theta = getTheta(cellID);
-	double phi = getPhi(cellID);
-	return getPositionFromRThetaPhi(r, theta, phi);
+Position ProjectiveCylinder::position(const long64& cellID) const {
+	return Util::positionFromRThetaPhi(1.0, theta(cellID), phi(cellID));
 }
 
 /// determine the cell ID based on the position
-long64 ProjectiveCylinder::getCellID(double x, double y, double z) const {
+CellID ProjectiveCylinder::cellID(const Position& localPosition, const Position& globalPosition, const VolumeID& volumeID) const {
 	// TODO
 	return 0;
 }
 
 /// determine the polar angle theta based on the cell ID
-double ProjectiveCylinder::getTheta(const long64& cellID) const {
+double ProjectiveCylinder::theta(const long64& cellID) const {
 	int thetaIndex = (*_decoder)[_thetaID].value();
 	return M_PI * ((double) thetaIndex + 0.5) / (double) _thetaBins;
 }
 /// determine the azimuthal angle phi based on the cell ID
-double ProjectiveCylinder::getPhi(const long64& cellID) const {
+double ProjectiveCylinder::phi(const long64& cellID) const {
 	int phiIndex = (*_decoder)[_phiID].value();
 	return 2. * M_PI * ((double) phiIndex + 0.5) / (double) _phiBins;
 }
 
+REGISTER_SEGMENTATION(ProjectiveCylinder)
+
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/DDSegmentation/src/Segmentation.cpp b/DDSegmentation/src/Segmentation.cpp
index 29a4fe3ad..ce91a8c3f 100644
--- a/DDSegmentation/src/Segmentation.cpp
+++ b/DDSegmentation/src/Segmentation.cpp
@@ -7,86 +7,125 @@
 
 #include "DDSegmentation/Segmentation.h"
 
+#include <iostream>
+#include <sstream>
 #include <stdexcept>
 
 namespace DD4hep {
 namespace DDSegmentation {
 
+using std::cerr;
+using std::endl;
+using std::map;
 using std::string;
+using std::stringstream;
 using std::vector;
 
-/// default constructor using an encoding string
-template<> Segmentation::Segmentation(std::string cellEncoding) {
-	_decoder = new BitField64(cellEncoding);
-	_ownsDecoder = true;
-	_type = "segmentation";
-	_isLocal = true;
+/// Default constructor used by derived classes passing the encoding string
+Segmentation::Segmentation(const string& cellEncoding) :
+	_name("Segmentation"), _type("Segmentation"), _decoder(new BitField64(cellEncoding)), _ownsDecoder(true) {
 }
 
-/// default constructor using an encoding string
-template<> Segmentation::Segmentation(const std::string& cellEncoding) {
-	_decoder = new BitField64(cellEncoding);
-	_ownsDecoder = true;
-	_type = "segmentation";
-	_isLocal = true;
-}
-
-/// default constructor using an encoding string
-template<> Segmentation::Segmentation(const char* cellEncoding) {
-	_decoder = new BitField64(cellEncoding);
-	_ownsDecoder = true;
-	_type = "segmentation";
-	_isLocal = true;
+/// Destructor
+Segmentation::~Segmentation() {
+	if (_ownsDecoder and _decoder != 0) {
+		delete _decoder;
+	}
+	map<string, SegmentationParameter*>::iterator it;
+	for (it = _parameters.begin(); it != _parameters.end(); ++it) {
+		SegmentationParameter* p = it->second;
+		if (p) {
+			delete p;
+			p = 0;
+		}
+	}
 }
 
-/// default constructor using an existing decoder
-template<> Segmentation::Segmentation(BitField64* decoder) {
+/// Set the underlying decoder
+void Segmentation::setDecoder(BitField64* decoder) {
+	if (_ownsDecoder and _decoder != 0) {
+		std::cout << _decoder << std::endl;
+		delete _decoder;
+	}
 	_decoder = decoder;
 	_ownsDecoder = false;
-	_type = "segmentation";
-	_isLocal = true;
 }
 
-/// destructor
-Segmentation::~Segmentation() {
-	if (_ownsDecoder and _decoder != 0) {
-		delete _decoder;
+/// Access to parameter by name
+SegmentationParameter* Segmentation::parameter(const std::string& parameterName) {
+	map<string, SegmentationParameter*>::iterator it;
+	it = _parameters.find(parameterName);
+	if (it != _parameters.end()) {
+		return it->second;
 	}
+	stringstream s;
+	s << "Unknown parameter " << parameterName << " for segmentation type " << _type;
+	throw std::runtime_error(s.str());
 }
-
-/// determine the cell ID based on the position
-long64 Segmentation::getCellID(const vector<double>& position) const {
-	if (position.size() != 3) {
-		throw std::runtime_error("Vector size has to be 3!");
+/// Access to parameter by name
+const SegmentationParameter* Segmentation::parameter(const std::string& parameterName) const {
+	map<string, SegmentationParameter*>::const_iterator it;
+	it = _parameters.find(parameterName);
+	if (it != _parameters.end()) {
+		return it->second;
 	}
-	return getCellID(position[0], position[1], position[2]);
+	stringstream s;
+	s << "Unknown parameter " << parameterName << " for segmentation type " << _type;
+	throw std::runtime_error(s.str());
 }
 
-/// determine the cell ID based on the position
-long64 Segmentation::getCellID(const double* position) const {
-	return getCellID(position[0], position[1], position[2]);
+/// Access to parameter values by name
+double Segmentation::parameterValue(const std::string& parameterName) const {
+	return this->parameter(parameterName)->value();
 }
 
-/// set the underlying decoder
-void Segmentation::setDecoder(BitField64* decoder) {
-	if (_ownsDecoder and _decoder != 0) {
-		delete _decoder;
+/// Set the parameter value by name
+void Segmentation::setParameterValue(const std::string& parameterName, double value) {
+	this->parameter(parameterName)->value() = value;
+}
+
+/// Access to all parameters
+//Parameters Segmentation::parameters() const {
+//	Parameters parameters;
+//	map<string, SegmentationParameter*>::const_iterator it;
+//	for (it = _parameters.begin(); it != _parameters.end(); ++it) {
+//		parameters.push_back(std::make_pair(it->first, it->second->value()));
+//	}
+//	return parameters;
+//}
+
+/// Access to all parameters
+vector<SegmentationParameter*> Segmentation::parameters() {
+	vector<SegmentationParameter*> parameters;
+	map<string, SegmentationParameter*>::iterator it;
+	for (it = _parameters.begin(); it != _parameters.end(); ++it) {
+		parameters.push_back(it->second);
 	}
-	_decoder = decoder;
-	_ownsDecoder = false;
+	return parameters;
+}
+
+/// Access to all parameters
+vector<const SegmentationParameter*> Segmentation::parameters() const {
+	vector<const SegmentationParameter*> parameters;
+	map<string, SegmentationParameter*>::const_iterator it;
+	for (it = _parameters.begin(); it != _parameters.end(); ++it) {
+		parameters.push_back(it->second);
+	}
+	return parameters;
 }
 
-/// access the set of parameters for this segmentation
-Parameters Segmentation::parameters() const {
-	return Parameters();
+/// Add a parameter to this segmentation. Used by derived classes to define their parameters
+void Segmentation::registerParameter(const std::string& name, const std::string& description, double& parameter, double defaultValue, bool isOptional) {
+	_parameters[name] = new SegmentationParameter(name, description, parameter, defaultValue, isOptional);
 }
 
-/// helper method to convert a bin number to a 1D position
+
+/// Helper method to convert a bin number to a 1D position
 double Segmentation::binToPosition(long64 bin, double cellSize, double offset) const {
 	return bin * cellSize + offset;
 }
 
-/// helper method to convert a 1D position to a cell ID
+/// Helper method to convert a 1D position to a cell ID
 int Segmentation::positionToBin(double position, double cellSize, double offset) const {
 	if (cellSize == 0.) {
 		throw std::runtime_error("Invalid cell size: 0.0");
diff --git a/DDSegmentation/src/SegmentationFactory.cpp b/DDSegmentation/src/SegmentationFactory.cpp
new file mode 100644
index 000000000..491527e61
--- /dev/null
+++ b/DDSegmentation/src/SegmentationFactory.cpp
@@ -0,0 +1,59 @@
+/*
+ * SegmentationFactory.cpp
+ *
+ *  Created on: Dec 15, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#include "DDSegmentation/SegmentationFactory.h"
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+using std::map;
+using std::vector;
+using std::string;
+
+/// Default constructor. Takes the class name as argument and takes care of registration with the factory
+SegmentationCreatorBase::SegmentationCreatorBase(const string& name) {
+	SegmentationFactory::instance()->registerSegmentation(name, this);
+}
+
+/// Initialize the global factory instance
+SegmentationFactory* SegmentationFactory::_instance = 0;
+
+/// Access to the global factory instance
+SegmentationFactory* SegmentationFactory::instance() {
+	if (not _instance) {
+		_instance = new SegmentationFactory();
+	}
+	return _instance;
+}
+
+/// Create a new segmentation object with the given type name. Returns NULL if type name is unknown.
+Segmentation* SegmentationFactory::create(const string& name) const {
+	map<string, SegmentationCreatorBase*>::const_iterator it;
+	it = _segmentations.find(name);
+	if (it != _segmentations.end()) {
+		return it->second->create();
+	}
+	return 0;
+}
+
+/// Access to the list of registered segmentations
+vector<string> SegmentationFactory::registeredSegmentations() const {
+	vector<string> segmentationNames;
+	map<string, SegmentationCreatorBase*>::const_iterator it;
+	for (it = _segmentations.begin(); it != _segmentations.end(); ++ it) {
+		segmentationNames.push_back(it->first);
+	}
+	return segmentationNames;
+}
+
+/// Registers a new SegmentationCreator with the factory
+void SegmentationFactory::registerSegmentation(const string& name, SegmentationCreatorBase* creator) {
+	_segmentations[name] = creator;
+}
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
diff --git a/DDSegmentation/src/SegmentationParameter.cpp b/DDSegmentation/src/SegmentationParameter.cpp
new file mode 100644
index 000000000..a172d9b70
--- /dev/null
+++ b/DDSegmentation/src/SegmentationParameter.cpp
@@ -0,0 +1,62 @@
+/*
+ * SegmentationParameter.cpp
+ *
+ *  Created on: Dec 16, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#include "DDSegmentation/SegmentationParameter.h"
+
+#include <sstream>
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+using std::string;
+using std::stringstream;
+
+/// Default constructor
+SegmentationParameter::SegmentationParameter(const string& name, const string& description, double& parameter,
+		double defaultValue, bool isOptional) :
+		_name(name), _description(description), _parameter(parameter), _defaultValue(defaultValue), _isOptional(
+				isOptional) {
+	_parameter = defaultValue;
+}
+
+/// Access to the parameter name
+const string& SegmentationParameter::name() const {
+	return _name;
+}
+
+/// Access to the parameter description
+const string& SegmentationParameter::SegmentationParameter::description() const {
+	return _description;
+}
+
+/// Access to the parameter value
+double& SegmentationParameter::value() {
+	return _parameter;
+}
+
+/// Access to the parameter value
+double SegmentationParameter::value() const {
+	return _parameter;
+}
+
+/// Check if this parameter is optional
+bool SegmentationParameter::isOptional() const {
+	return _isOptional;
+}
+
+/// Printable version
+string SegmentationParameter::toString() const {
+	stringstream s;
+	s << _name << " = " << _parameter;
+	if (not _description.empty()) {
+		s << " (" << _description << ")";
+	}
+	return s.str();
+}
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
diff --git a/examples/CLICSiD/compact/BarrelCalorimeter.xml b/examples/CLICSiD/compact/BarrelCalorimeter.xml
index 84a73e42c..88f952b7e 100644
--- a/examples/CLICSiD/compact/BarrelCalorimeter.xml
+++ b/examples/CLICSiD/compact/BarrelCalorimeter.xml
@@ -396,7 +396,7 @@
     <readouts>
 
         <readout name="MuonBarrelHits">
-            <segmentation type="RegularNgonCartesianGridXY" gridSizeX="3.0*cm" gridSizeY="3.0*cm" />
+            <segmentation type="CartesianGridXY" gridSizeX="3.0*cm" gridSizeY="3.0*cm" />
             <id>system:8,barrel:3,module:4,layer:8,slice:5,x:32:-16,y:-16</id>
         </readout>
 <!--
diff --git a/examples/Segmentation/CMakeLists.txt b/examples/Segmentation/CMakeLists.txt
index 2bf12ba95..fb1cfa6c0 100644
--- a/examples/Segmentation/CMakeLists.txt
+++ b/examples/Segmentation/CMakeLists.txt
@@ -63,9 +63,6 @@ endif()
 
 add_executable(Segmentation SegmentationTest.cpp ${sources})
 
-MESSAGE( STATUS "${DD4hep_LIBRARIES}" ) 
-MESSAGE( STATUS "${ROOT_LIBRARIES}" ) 
-
 target_link_libraries(Segmentation ${DD4hep_LIBRARIES} )
 
 #---Rootmap generation--------------------------------------------------------------
diff --git a/examples/Segmentation/SegmentationTest.cpp b/examples/Segmentation/SegmentationTest.cpp
index e4bea2ce1..238c30dfe 100644
--- a/examples/Segmentation/SegmentationTest.cpp
+++ b/examples/Segmentation/SegmentationTest.cpp
@@ -7,7 +7,8 @@
 
 #include "DD4hep/LCDD.h"
 
-#include "DDSegmentation/BitField64.h"
+#include "DDSegmentation/SegmentationFactory.h"
+#include "DDSegmentation/SegmentationParameter.h"
 
 using namespace std;
 using namespace DD4hep;
@@ -16,23 +17,20 @@ using namespace DDSegmentation;
 
 int main(int argc, char** argv) {
 
-	LCDD& lcdd = LCDD::getInstance();
-	lcdd.fromCompact(argv[1]);
-	lcdd.apply("DD4hepVolumeManager",0,0);
-
-	Readout ro = lcdd.readout("MuonBarrelHits");
-
-	BitField64 idEncoder(ro.idSpec().fieldDescription());
-	idEncoder["system"] = 10;
-	idEncoder["barrel"] = 0;
-	idEncoder["layer"] = 15;
-	idEncoder["module"] = 8;
-	idEncoder["slice"] = 11;
-	idEncoder["x"] = 13;
-	idEncoder["y"] = -10;
-	long64 cellID = idEncoder.getValue();
-	Position gp = ro.getPosition(cellID);
-	std::cout << "Global position: " << gp.x() << ", " << gp.y() << ", " << gp.z() << std::endl;
-
+	SegmentationFactory* f = SegmentationFactory::instance();
+
+	cout << "Registered Segmentations:" << std::endl;
+	vector<string> segmentations = f->registeredSegmentations();
+	vector<string>::const_iterator it;
+	for (it = segmentations.begin(); it != segmentations.end(); ++it) {
+		string typeName = *it;
+		DDSegmentation::Segmentation* s = f->create(typeName);
+		cout << "\t" << typeName << ", " << s->type() << endl;
+		Parameters parameters = s->parameters();
+		Parameters::iterator it;
+		for (it = parameters.begin(); it != parameters.end(); ++it) {
+			cout << "\t\t" << it->first << " = " << it->second << endl;
+		}
+	}
 	return 0;
 };
-- 
GitLab