diff --git a/DDCore/include/DD4hep/Readout.h b/DDCore/include/DD4hep/Readout.h
index e8c7d1da1812e9cddb7e884ed9b014961b2c8738..2083f7211923d9793ad924b3c50d1152cbeb95af 100644
--- a/DDCore/include/DD4hep/Readout.h
+++ b/DDCore/include/DD4hep/Readout.h
@@ -74,7 +74,6 @@ namespace DD4hep {
       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;
     };
 
diff --git a/DDCore/src/Readout.cpp b/DDCore/src/Readout.cpp
index e66580aa345f13131b15cb23cbe7ac56005661ca..240eb572874b7db13868bfc05629042387155666 100644
--- a/DDCore/src/Readout.cpp
+++ b/DDCore/src/Readout.cpp
@@ -90,14 +90,14 @@ DetElement Readout::getDetectorElement(const long64& cellID) const {
 	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()->getLocalPosition(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()->getLocalPosition(cellID);
-	return Position(v[0], v[1], v[2]);
+	std::vector<double> position = segmentation().segmentation()->getPosition(cellID);
+	if (segmentation().segmentation()->isLocal()) {
+		double global[3] = {0., 0., 0.};
+		volMan.worldTransformation(cellID).LocalToMaster(&position[0], global);
+		return Position(global[0]/tgeo::mm, global[1]/tgeo::mm, global[2]/tgeo::mm);
+	}
+	return Position(position[0]/tgeo::mm, position[1]/tgeo::mm, position[2]/tgeo::mm);
 }
 const TGeoMatrix& Readout::getWorldTransformation(const long64& cellID) const {
 	VolumeManager volMan = LCDD::getInstance().volumeManager();
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGrid.h b/DDSegmentation/include/DDSegmentation/CartesianGrid.h
index 1a3a13212458668104f843b31dc8d7c9e534efd5..1df3494d5da72a961263c9e1fa8af4904cf971d0 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGrid.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGrid.h
@@ -20,13 +20,6 @@ public:
 protected:
 	/// default constructor using an arbitrary type
 	template <typename TYPE> CartesianGrid(TYPE cellEncoding);
-	/// default constructor using an existing decoder
-	CartesianGrid(BitField64* decoder);
-
-	/// helper method to convert a bin number to a 1D position
-	double binToPosition(long64 bin, double cellSize, double ofset) const;
-	/// helper method to convert a 1D position to a cell ID
-	int positionToBin(double position, double cellSize, double offset) const;
 };
 
 } /* namespace DDSegmentation */
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGridXY.h b/DDSegmentation/include/DDSegmentation/CartesianGridXY.h
index 42e1fd3ef4e1ea9b3e261d22af3f987da147dd45..52cd121e09670bd560ffbc878e2d7400166e6090 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGridXY.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGridXY.h
@@ -17,16 +17,13 @@ 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., std::string xField = "x", std::string yField = "y");
-	/// default constructor using an existing decoder
-	CartesianGridXY(BitField64* decoder, double gridSizeX = 1., double gridSizeY = 1., double offsetX = 0.,
-			double offsetY = 0., std::string xField = "x", std::string yField = "y");
+			double offsetY = 0., const std::string& xField = "x", const std::string& yField = "y");
 	/// destructor
 	virtual ~CartesianGridXY();
 
-	/// 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
+	/// determine the position based on the cell ID
+	virtual std::vector<double> getPosition(const long64& cellID) const;
+	/// determine the cell ID based on the position
 	virtual long64 getCellID(double x, double y, double z) const;
 	/// access the grid size in X
 	double getGridSizeX() const {
@@ -69,11 +66,11 @@ public:
 		_offsetY = offset;
 	}
 	/// set the field name used for X
-	void setFieldNameX(std::string name) {
+	void setFieldNameX(const std::string& name) {
 		_xId = name;
 	}
 	/// set the field name used for Y
-	void setFieldNameY(std::string name) {
+	void setFieldNameY(const std::string& name) {
 		_yId = name;
 	}
 	/// access the set of parameters for this segmentation
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h b/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h
index 8e9a3c2ed0faf25e53f6be164d0efc8bf0ad0547..981dd8f0eeff8e357cf819083507a2afbabbc8e5 100644
--- a/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h
+++ b/DDSegmentation/include/DDSegmentation/CartesianGridXYZ.h
@@ -17,18 +17,14 @@ 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., std::string xField = "x",
-			std::string yField = "y", std::string zField = "z");
-	/// default constructor using an existing decoder
-	CartesianGridXYZ(BitField64* decoder, double gridSizeX = 1., double gridSizeY = 1., double gridSizeZ = 1., double offsetX =
-			0., double offsetY = 0., double offsetZ = 0., std::string xField = "x", std::string yField = "y",
-			std::string zField = "z");
+			double offsetX = 0., double offsetY = 0., double offsetZ = 0., const std::string& xField = "x",
+			const std::string& yField = "y", const std::string& zField = "z");
 	/// destructor
 	virtual ~CartesianGridXYZ();
 
-	/// 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
+	/// determine the position based on the cell ID
+	virtual std::vector<double> getPosition(const long64& cellID) const;
+	/// determine the cell ID based on the position
 	virtual long64 getCellID(double x, double y, double z) const;
 	/// access the grid size in Z
 	double getGridSizeZ() const {
@@ -51,7 +47,7 @@ public:
 		_offsetZ = offset;
 	}
 	/// set the field name used for Z
-	void setFieldNameZ(std::string name) {
+	void setFieldNameZ(const std::string& name) {
 		_zId = name;
 	}
 	/// access the set of parameters for this segmentation
diff --git a/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h b/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e4c813496150b48545988b1959333819b8a6af2
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/CartesianGridXZ.h
@@ -0,0 +1,96 @@
+/*
+ * CartesianGridXY.h
+ *
+ *  Created on: Jun 28, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#ifndef DDSegmentation_CARTESIANGRIDXZ_H_
+#define DDSegmentation_CARTESIANGRIDXZ_H_
+
+#include "DDSegmentation/CartesianGrid.h"
+
+namespace DD4hep {
+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");
+	/// destructor
+	virtual ~CartesianGridXZ();
+
+	/// determine the local based on the cell ID
+	virtual std::vector<double> getPosition(const long64& cellID) const;
+	/// determine the cell ID based on the position
+	virtual long64 getCellID(double x, double y, double z) const;
+	/// access the grid size in X
+	double getGridSizeX() const {
+		return _gridSizeX;
+	}
+	/// access the grid size in Z
+	double getGridSizeZ() const {
+		return _gridSizeZ;
+	}
+	/// access the coordinate offset in X
+	double getOffsetX() const {
+		return _offsetX;
+	}
+	/// access the coordinate offset in Z
+	double getOffsetZ() const {
+		return _offsetZ;
+	}
+	/// access the field name used for X
+	std::string getFieldNameX() const {
+		return _xId;
+	}
+	/// access the field name used for Z
+	std::string getFieldNameZ() const {
+		return _zId;
+	}
+	/// set the grid size in X
+	void setGridSizeX(double cellSize) {
+		_gridSizeX = cellSize;
+	}
+	/// set the grid size in Z
+	void setGridSizeZ(double cellSize) {
+		_gridSizeZ = cellSize;
+	}
+	/// set the coordinate offset in X
+	void setOffsetX(double offset) {
+		_offsetX = offset;
+	}
+	/// set the coordinate offset in Z
+	void setOffsetZ(double offset) {
+		_offsetZ = offset;
+	}
+	/// set the field name used for X
+	void setFieldNameX(const std::string& name) {
+		_xId = name;
+	}
+	/// set the field name used for Y
+	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
+	double _gridSizeX;
+	/// the coordinate offset in X
+	double _offsetX;
+	/// the grid size in Z
+	double _gridSizeZ;
+	/// the coordinate offset in Z
+	double _offsetZ;
+	/// the field name used for X
+	std::string _xId;
+	/// the field name used for Z
+	std::string _zId;
+};
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
+#endif /* DDSegmentation_CARTESIANGRIDXZ_H_ */
diff --git a/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h b/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h
new file mode 100644
index 0000000000000000000000000000000000000000..f492d805d28c1e0b6d8d5e2c20246a7d84b340eb
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/CylindricalSegmentation.h
@@ -0,0 +1,50 @@
+/*
+ * CylindricalSegmentation.h
+ *
+ *  Created on: Oct 31, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#ifndef DDSegmentation_CYLINDRICALSEGMENTATION_H_
+#define DDSegmentation_CYLINDRICALSEGMENTATION_H_
+
+#include "DDSegmentation/Segmentation.h"
+
+#include <map>
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+class CylindricalSegmentation: public Segmentation {
+public:
+	/// destructor
+	virtual ~CylindricalSegmentation();
+
+	/// determine the radius based on the cell ID
+	std::string 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;
+};
+
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
+#endif /* DDSegmentation_CYLINDRICALSEGMENTATION_H_ */
diff --git a/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h b/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b58a7060b849ac721092d7153369b37ee66ef31
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/ProjectiveCylinder.h
@@ -0,0 +1,101 @@
+/*
+ * ProjectiveCylinder.h
+ *
+ *  Created on: Oct 31, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#ifndef PROJECTIVECYLINDER_H_
+#define PROJECTIVECYLINDER_H_
+
+#include "CylindricalSegmentation.h"
+
+namespace DD4hep {
+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");
+	/// destructor
+	virtual ~ProjectiveCylinder();
+
+	/// determine the position based on the cell ID
+	virtual std::vector<double> getPosition(const long64& cellID) const;
+	/// determine the cell ID based on the position
+	virtual long64 getCellID(double x, double y, double z) const;
+	/// determine the polar angle theta based on the cell ID
+	double getTheta(const long64& cellID) const;
+	/// determine the azimuthal angle phi based on the cell ID
+	double getPhi(const long64& cellID) const;
+	/// access the number of bins in theta
+	int getThetaBins() const {
+		return _thetaBins;
+	}
+	/// access the number of bins in theta
+	int getPhiBins() const {
+		return _phiBins;
+	}
+	/// access the coordinate offset in theta
+	double getOffsetTheta() const {
+		return _offsetTheta;
+	}
+	/// access the coordinate offset in phi
+	double getOffsetPhi() const {
+		return _offsetPhi;
+	}
+	/// access the field name used for theta
+	std::string getFieldNameTheta() const {
+		return _thetaID;
+	}
+	/// access the field name used for phi
+	std::string getFieldNamePhi() const {
+		return _phiID;
+	}
+	/// set the number of bins in theta
+	void setThetaBins(int bins) {
+		_thetaBins = bins;
+	}
+	/// set the number of bins in phi
+	void setPhiBins(int bins) {
+		_phiBins = bins;
+	}
+	/// set the coordinate offset in theta
+	void setOffsetTheta(double offset) {
+		_offsetTheta = offset;
+	}
+	/// set the coordinate offset in phi
+	void setOffsetPhi(double offset) {
+		_offsetPhi = offset;
+	}
+	/// set the field name used for theta
+	void setFieldNameTheta(const std::string& name) {
+		_thetaID = name;
+	}
+	/// set the field name used for phi
+	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;
+	/// the number of bins in phi
+	int _phiBins;
+	/// the coordinate offset in theta
+	double _offsetTheta;
+	/// the coordinate offset in phi
+	double _offsetPhi;
+	/// the field name used for theta
+	std::string _thetaID;
+	/// the field name used for phi
+	std::string _phiID;
+};
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
+#endif /* PROJECTIVECYLINDER_H_ */
diff --git a/DDSegmentation/include/DDSegmentation/Segmentation.h b/DDSegmentation/include/DDSegmentation/Segmentation.h
index 3a17412040492d9107b70495e5a01c7aa5da107b..da499f12047bd3766529d1a6aa643cef29a1795a 100644
--- a/DDSegmentation/include/DDSegmentation/Segmentation.h
+++ b/DDSegmentation/include/DDSegmentation/Segmentation.h
@@ -26,19 +26,25 @@ class Segmentation {
 public:
 	/// default constructor using an arbitrary type
 	template <typename TYPE> Segmentation(TYPE cellEncoding);
-	/// default constructor using an existing decoder
-	Segmentation(BitField64* decoder);
 	/// destructor
 	virtual ~Segmentation();
 
-	/// determine the local position based on the cell ID
-	virtual std::vector<double> getLocalPosition(const long64& cellID) const = 0;
-	/// determine the cell ID based on the local position
+	/// 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 local position
-	long64 getCellID(const std::vector<double>& localPosition) const;
-	/// determine the cell ID based on the local position
-	long64 getCellID(const double* localPosition) const;
+	/// 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
 	std::string fieldDescription() const {
 		return _decoder->fieldDescription();
@@ -63,6 +69,13 @@ protected:
 	bool _ownsDecoder;
 	/// the segmentation type
 	std::string _type;
+	/// distinguish between local and global coordinate systems
+	bool _isLocal;
+
+	/// 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;
 };
 
 } /* namespace DDSegmentation */
diff --git a/DDSegmentation/include/DDSegmentation/SegmentationUtil.h b/DDSegmentation/include/DDSegmentation/SegmentationUtil.h
new file mode 100644
index 0000000000000000000000000000000000000000..267b405706f331291645b92dc6d912329f9e600d
--- /dev/null
+++ b/DDSegmentation/include/DDSegmentation/SegmentationUtil.h
@@ -0,0 +1,299 @@
+/*
+ * SegmentationUtil.h
+ *
+ *  Created on: Oct 31, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#ifndef DDSegmentation_SEGMENTATIONUTIL_H_
+#define DDSegmentation_SEGMENTATIONUTIL_H_
+
+#include <cmath>
+#include <vector>
+
+namespace DD4hep {
+namespace DDSegmentation {
+namespace SegmentationUtil {
+
+///////////////////////////////////////////////////////////////////////
+///           Conventions                                           ///
+/// - x, y, z are the Cartesian coordinates                         ///
+/// - r is the magnitude in the xy-plane                            ///
+/// - rho is the magnitude                                          ///
+///////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////
+/// Conversions from Cartesian to cylindrical/spherical coordinates ///
+///////////////////////////////////////////////////////////////////////
+
+
+/// 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);
+}
+/// 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]);
+}
+/// 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]);
+}
+
+
+/// 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]);
+}
+
+
+/////////////////////////////////////////////////////////////
+/// 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]);
+}
+
+
+/// calculates the radius in xyz from cylindrical coordinates
+template <typename TYPE> TYPE getRhoFromRPhiZ(TYPE r, TYPE phi, TYPE 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) {
+	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) {
+	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) {
+	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]);
+}
+/// 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]);
+}
+/// 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 DDSegmentation */
+} /* namespace DD4hep */
+
+#endif /* DDSegmentation_SEGMENTATIONUTIL_H_ */
diff --git a/DDSegmentation/src/CartesianGrid.cpp b/DDSegmentation/src/CartesianGrid.cpp
index 1c137444f6444a91670df1108ac5803e892787c1..55b97022051fa0e7408518444d7c4930bcbff67e 100644
--- a/DDSegmentation/src/CartesianGrid.cpp
+++ b/DDSegmentation/src/CartesianGrid.cpp
@@ -7,8 +7,6 @@
 
 #include "DDSegmentation/CartesianGrid.h"
 
-#include <stdexcept>
-
 namespace DD4hep {
 namespace DDSegmentation {
 
@@ -33,7 +31,7 @@ template<> CartesianGrid::CartesianGrid(const char* cellEncoding) :
 }
 
 /// default constructor using an existing decoder
-CartesianGrid::CartesianGrid(BitField64* decoder) :
+template<> CartesianGrid::CartesianGrid(BitField64* decoder) :
 		Segmentation(decoder) {
 
 }
@@ -43,18 +41,5 @@ CartesianGrid::~CartesianGrid() {
 
 }
 
-/// helper method to convert a bin number to a 1D position
-double CartesianGrid::binToPosition(long64 bin, double cellSize, double offset) const {
-	return bin * cellSize + offset;
-}
-
-/// helper method to convert a 1D position to a cell ID
-int CartesianGrid::positionToBin(double position, double cellSize, double offset) const {
-	if (cellSize == 0.) {
-		throw std::runtime_error("Invalid cell size: 0.0");
-	}
-	return int((position + 0.5 * cellSize - offset)/cellSize);
-}
-
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/DDSegmentation/src/CartesianGridXY.cpp b/DDSegmentation/src/CartesianGridXY.cpp
index 33ab1d5f416c3a76478d052b70c4ab1d83b773cc..33a8059ffd48a177c3021639f83f118e0a3ca029 100644
--- a/DDSegmentation/src/CartesianGridXY.cpp
+++ b/DDSegmentation/src/CartesianGridXY.cpp
@@ -16,7 +16,7 @@ using std::vector;
 
 /// default constructor using an encoding string
 template<> CartesianGridXY::CartesianGridXY(const string& cellEncoding, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, string xField, string yField) :
+		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";
@@ -24,7 +24,7 @@ template<> CartesianGridXY::CartesianGridXY(const string& cellEncoding, double g
 
 /// default constructor using an encoding string
 template<> CartesianGridXY::CartesianGridXY(string cellEncoding, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, string xField, string yField) :
+		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";
@@ -32,15 +32,15 @@ template<> CartesianGridXY::CartesianGridXY(string cellEncoding, double gridSize
 
 /// default constructor using an encoding string
 template<> CartesianGridXY::CartesianGridXY(const char* cellEncoding, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, string xField, string yField) :
+		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
-CartesianGridXY::CartesianGridXY(BitField64* decoder, double gridSizeX, double gridSizeY, double offsetX,
-		double offsetY, string xField, string yField) :
+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";
@@ -51,8 +51,8 @@ CartesianGridXY::~CartesianGridXY() {
 
 }
 
-/// determine the local position based on the cell ID
-vector<double> CartesianGridXY::getLocalPosition(const long64& cellID) const {
+/// determine the position based on the cell ID
+vector<double> CartesianGridXY::getPosition(const long64& cellID) const {
 	_decoder->setValue(cellID);
 	vector<double> localPosition(3);
 	localPosition[0] = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
@@ -61,7 +61,7 @@ vector<double> CartesianGridXY::getLocalPosition(const long64& cellID) const {
 	return localPosition;
 }
 
-/// determine the cell ID based on the local position
+/// determine the cell ID based on the position
 long64 CartesianGridXY::getCellID(double x, double y, double z) const {
 	_decoder->reset();
 	(*_decoder)[_xId] = positionToBin(x, _gridSizeX, _offsetX);
@@ -74,6 +74,8 @@ 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;
 }
 
diff --git a/DDSegmentation/src/CartesianGridXYZ.cpp b/DDSegmentation/src/CartesianGridXYZ.cpp
index 4a21e554d4806e67c87fbd7774e8d97e9bb8a3c4..393685b23ef9ac041ba6b8d440b62a95766befd5 100644
--- a/DDSegmentation/src/CartesianGridXYZ.cpp
+++ b/DDSegmentation/src/CartesianGridXYZ.cpp
@@ -16,7 +16,7 @@ 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, string xField, string yField, string zField) :
+		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";
@@ -24,7 +24,7 @@ template<> CartesianGridXYZ::CartesianGridXYZ(const string& cellEncoding, double
 
 /// default constructor using an encoding string
 template<> CartesianGridXYZ::CartesianGridXYZ(string cellEncoding, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, string xField, string yField, string zField) :
+		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";
@@ -32,15 +32,15 @@ template<> CartesianGridXYZ::CartesianGridXYZ(string cellEncoding, double gridSi
 
 /// default constructor using an encoding string
 template<> CartesianGridXYZ::CartesianGridXYZ(const char* cellEncoding, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, string xField, string yField, string zField) :
+		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
-CartesianGridXYZ::CartesianGridXYZ(BitField64* decoder, double gridSizeX, double gridSizeY, double gridSizeZ,
-		double offsetX, double offsetY, double offsetZ, string xField, string yField, string zField) :
+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";
@@ -51,8 +51,8 @@ CartesianGridXYZ::~CartesianGridXYZ() {
 
 }
 
-/// determine the local position based on the cell ID
-vector<double> CartesianGridXYZ::getLocalPosition(const long64& cellID) const {
+/// determine the position based on the cell ID
+vector<double> CartesianGridXYZ::getPosition(const long64& cellID) const {
 	_decoder->setValue(cellID);
 	vector<double> localPosition(3);
 	localPosition[0] = binToPosition((*_decoder)[_xId].value(), _gridSizeX, _offsetX);
@@ -61,7 +61,7 @@ vector<double> CartesianGridXYZ::getLocalPosition(const long64& cellID) const {
 	return localPosition;
 }
 
-/// determine the cell ID based on the local position
+/// determine the cell ID based on the position
 long64 CartesianGridXYZ::getCellID(double x, double y, double z) const {
 	_decoder->reset();
 	(*_decoder)[_xId] = positionToBin(x, _gridSizeX, _offsetX);
@@ -76,6 +76,9 @@ Parameters CartesianGridXYZ::parameters() const {
 	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;
 }
 
diff --git a/DDSegmentation/src/CartesianGridXZ.cpp b/DDSegmentation/src/CartesianGridXZ.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8c46746b9276e20f6aad1c0e658f872b8ed4f407
--- /dev/null
+++ b/DDSegmentation/src/CartesianGridXZ.cpp
@@ -0,0 +1,83 @@
+/*
+ * CartesianGridXY.cpp
+ *
+ *  Created on: Jun 28, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#include "DDSegmentation/CartesianGridXZ.h"
+
+namespace DD4hep {
+namespace DDSegmentation {
+
+using std::make_pair;
+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";
+}
+
+/// 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";
+}
+
+/// destructor
+CartesianGridXZ::~CartesianGridXZ() {
+
+}
+
+/// determine the position based on the cell ID
+vector<double> CartesianGridXZ::getPosition(const long64& 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;
+}
+
+/// determine the cell ID based on the position
+long64 CartesianGridXZ::getCellID(double x, double y, double z) const {
+	_decoder->reset();
+	(*_decoder)[_xId] = positionToBin(x, _gridSizeX, _offsetX);
+	(*_decoder)[_zId] = positionToBin(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;
+}
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
diff --git a/DDSegmentation/src/CylindricalSegmentation.cpp b/DDSegmentation/src/CylindricalSegmentation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d3b16631996e03a5255949c7ab51670fe3d54feb
--- /dev/null
+++ b/DDSegmentation/src/CylindricalSegmentation.cpp
@@ -0,0 +1,65 @@
+/*
+ * CylindricalSegmentation.cpp
+ *
+ *  Created on: Oct 31, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#include "DDSegmentation/CylindricalSegmentation.h"
+
+#include <sstream>
+#include <stdexcept>
+
+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;
+}
+
+
+/// destructor
+CylindricalSegmentation::~CylindricalSegmentation() {
+
+}
+
+/// determine the radius based on the cell ID
+string 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
new file mode 100644
index 0000000000000000000000000000000000000000..b5bacda6cae8b119b1a8dc08eee41a37d9fd122e
--- /dev/null
+++ b/DDSegmentation/src/ProjectiveCylinder.cpp
@@ -0,0 +1,85 @@
+/*
+ * ProjectiveCylinder.cpp
+ *
+ *  Created on: Oct 31, 2013
+ *      Author: Christian Grefe, CERN
+ */
+
+#include "DDSegmentation/ProjectiveCylinder.h"
+#include "DDSegmentation/SegmentationUtil.h"
+
+#define _USE_MATH_DEFINES
+#include <cmath>
+
+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";
+}
+
+/// 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";
+}
+
+/// destructor
+ProjectiveCylinder::~ProjectiveCylinder() {
+
+}
+
+/// determine the local based on the cell ID
+virtual 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);
+}
+
+/// determine the cell ID based on the position
+virtual long64 ProjectiveCylinder::getCellID(double x, double y, double z) const {
+	// TODO
+	return 0;
+}
+
+/// determine the polar angle theta based on the cell ID
+double ProjectiveCylinder::getTheta(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 {
+	int phiIndex = (*_decoder)[_phiID].value();
+	return 2. * M_PI * ((double) phiIndex + 0.5) / (double) _phiBins;
+}
+
+} /* namespace DDSegmentation */
+} /* namespace DD4hep */
diff --git a/DDSegmentation/src/Segmentation.cpp b/DDSegmentation/src/Segmentation.cpp
index 5efba3ac61510288bfafd072753ce39e12485ba2..0604f1136fdffe2244d79324afd1123689397136 100644
--- a/DDSegmentation/src/Segmentation.cpp
+++ b/DDSegmentation/src/Segmentation.cpp
@@ -20,6 +20,7 @@ template<> Segmentation::Segmentation(std::string cellEncoding) {
 	_decoder = new BitField64(cellEncoding);
 	_ownsDecoder = true;
 	_type = "segmentation";
+	_isLocal = true;
 }
 
 /// default constructor using an encoding string
@@ -27,6 +28,7 @@ template<> Segmentation::Segmentation(const std::string& cellEncoding) {
 	_decoder = new BitField64(cellEncoding);
 	_ownsDecoder = true;
 	_type = "segmentation";
+	_isLocal = true;
 }
 
 /// default constructor using an encoding string
@@ -34,13 +36,15 @@ template<> Segmentation::Segmentation(const char* cellEncoding) {
 	_decoder = new BitField64(cellEncoding);
 	_ownsDecoder = true;
 	_type = "segmentation";
+	_isLocal = true;
 }
 
 /// default constructor using an existing decoder
-Segmentation::Segmentation(BitField64* decoder) {
+template<> Segmentation::Segmentation(BitField64* decoder) {
 	_decoder = decoder;
 	_ownsDecoder = false;
 	_type = "segmentation";
+	_isLocal = true;
 }
 
 /// destructor
@@ -50,17 +54,17 @@ Segmentation::~Segmentation() {
 	}
 }
 
-/// determine the cell ID based on the local position
-long64 Segmentation::getCellID(const vector<double>& localPosition) const {
-	if (localPosition.size() != 3) {
+/// 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!");
 	}
-	return getCellID(localPosition[0], localPosition[1], localPosition[2]);
+	return getCellID(position[0], position[1], position[2]);
 }
 
-/// determine the cell ID based on the local position
-long64 Segmentation::getCellID(const double* localPosition) const {
-	return getCellID(localPosition[0], localPosition[1], localPosition[2]);
+/// determine the cell ID based on the position
+long64 Segmentation::getCellID(const double* position) const {
+	return getCellID(position[0], position[1], position[2]);
 }
 
 /// set the underlying decoder
@@ -77,5 +81,18 @@ Parameters Segmentation::parameters() const {
 	return Parameters();
 }
 
+/// helper method to convert a bin number to a 1D position
+double CartesianGrid::binToPosition(long64 bin, double cellSize, double offset) const {
+	return bin * cellSize + offset;
+}
+
+/// helper method to convert a 1D position to a cell ID
+int CartesianGrid::positionToBin(double position, double cellSize, double offset) const {
+	if (cellSize == 0.) {
+		throw std::runtime_error("Invalid cell size: 0.0");
+	}
+	return int((position + 0.5 * cellSize - offset)/cellSize);
+}
+
 } /* namespace DDSegmentation */
 } /* namespace DD4hep */
diff --git a/examples/Segmentation/SegmentationTest.cpp b/examples/Segmentation/SegmentationTest.cpp
index 5777b8680fe6f3f15e9b3ea0b579f662aa9097d3..e4bea2ce1d5599a7745ad24c55f8d18d58a01375 100644
--- a/examples/Segmentation/SegmentationTest.cpp
+++ b/examples/Segmentation/SegmentationTest.cpp
@@ -31,9 +31,7 @@ int main(int argc, char** argv) {
 	idEncoder["x"] = 13;
 	idEncoder["y"] = -10;
 	long64 cellID = idEncoder.getValue();
-	Position lp = ro.getLocalPosition(cellID);
 	Position gp = ro.getPosition(cellID);
-	std::cout << "Local position: " << lp.x() << ", " << lp.y() << ", " << lp.z() << std::endl;
 	std::cout << "Global position: " << gp.x() << ", " << gp.y() << ", " << gp.z() << std::endl;
 
 	return 0;