From e8765bcdab3be977cd5536531cacb24bf3378a59 Mon Sep 17 00:00:00 2001
From: Wim van Aarle <wimvanaarle@gmail.com>
Date: Thu, 12 Mar 2015 17:32:28 +0100
Subject: added parallel_vec to the python bindings

---
 python/astra/PyIncludes.pxd |  4 ++++
 python/astra/creators.py    | 13 +++++++++++++
 python/astra/data2d_c.pyx   |  4 ++++
 python/astra/functions.py   | 22 +++++++++++++++++++++-
 python/astra/utils.pyx      |  2 ++
 5 files changed, 44 insertions(+), 1 deletion(-)

(limited to 'python/astra')

diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd
index fc5980f..5a81844 100644
--- a/python/astra/PyIncludes.pxd
+++ b/python/astra/PyIncludes.pxd
@@ -109,6 +109,10 @@ cdef extern from "astra/FanFlatVecProjectionGeometry2D.h" namespace "astra":
 	cdef cppclass CFanFlatVecProjectionGeometry2D:
 		CFanFlatVecProjectionGeometry2D()
 
+cdef extern from "astra/ParallelVecProjectionGeometry2D.h" namespace "astra":
+	cdef cppclass CParallelVecProjectionGeometry2D:
+		CParallelVecProjectionGeometry2D()
+
 cdef extern from "astra/ParallelProjectionGeometry2D.h" namespace "astra":
 	cdef cppclass CParallelProjectionGeometry2D:
 		CParallelProjectionGeometry2D()
diff --git a/python/astra/creators.py b/python/astra/creators.py
index 9aba464..b5ecd5a 100644
--- a/python/astra/creators.py
+++ b/python/astra/creators.py
@@ -139,6 +139,13 @@ This method can be called in a number of ways:
 :type angles: :class:`numpy.ndarray`
 :returns: A parallel projection geometry.
 
+``create_proj_geom('parallel_vec', det_count, V)``:
+
+:param det_count: Number of detector pixels.
+:type det_count: :class:`int`
+:param V: Vector array.
+:type V: :class:`numpy.ndarray`
+:returns: A parallel-beam projection geometry.
 
 ``create_proj_geom('fanflat', det_width, det_count, angles, source_origin, source_det)``:
 
@@ -226,6 +233,12 @@ This method can be called in a number of ways:
             raise Exception(
                 'not enough variables: astra_create_proj_geom(parallel, detector_spacing, det_count, angles)')
         return {'type': 'parallel', 'DetectorWidth': args[0], 'DetectorCount': args[1], 'ProjectionAngles': args[2]}
+    elif intype == 'parallel_vec':
+        if len(args) < 2:
+            raise Exception('not enough variables: astra_create_proj_geom(parallel_vec, det_count, V)')
+        if not args[1].shape[1] == 6:
+            raise Exception('V should be a Nx6 matrix, with N the number of projections')
+        return {'type':'parallel_vec', 'DetectorCount':args[0], 'Vectors':args[1]}
     elif intype == 'fanflat':
         if len(args) < 5:
             raise Exception('not enough variables: astra_create_proj_geom(fanflat, det_width, det_count, angles, source_origin, source_det)')
diff --git a/python/astra/data2d_c.pyx b/python/astra/data2d_c.pyx
index ec1b478..dbe1c2f 100644
--- a/python/astra/data2d_c.pyx
+++ b/python/astra/data2d_c.pyx
@@ -90,6 +90,8 @@ def create(datatype, geometry, data=None):
             ppGeometry = <CProjectionGeometry2D * >new CFanFlatProjectionGeometry2D()
         elif (tpe == 'fanflat_vec'):
             ppGeometry = <CProjectionGeometry2D * >new CFanFlatVecProjectionGeometry2D()
+        elif (tpe == 'parallel_vec'):
+            ppGeometry = <CProjectionGeometry2D * >new CParallelVecProjectionGeometry2D()
         else:
             ppGeometry = <CProjectionGeometry2D * >new CParallelProjectionGeometry2D()
         if not ppGeometry.initialize(cfg):
@@ -181,6 +183,8 @@ def change_geometry(i, geom):
             ppGeometry = <CProjectionGeometry2D * >new CFanFlatProjectionGeometry2D()
         elif (tpe == 'fanflat_vec'):
             ppGeometry = <CProjectionGeometry2D * >new CFanFlatVecProjectionGeometry2D()
+        elif (tpe == 'parallel_vec'):
+            ppGeometry = <CProjectionGeometry2D * >new CParallelVecProjectionGeometry2D()
         else:
             ppGeometry = <CProjectionGeometry2D * >new CParallelProjectionGeometry2D()
         if not ppGeometry.initialize(cfg):
diff --git a/python/astra/functions.py b/python/astra/functions.py
index 4025468..b9deb66 100644
--- a/python/astra/functions.py
+++ b/python/astra/functions.py
@@ -189,7 +189,27 @@ def geom_2vec(proj_geom):
     :param proj_geom: Projection geometry to convert
     :type proj_geom: :class:`dict`
     """
-    if proj_geom['type'] == 'fanflat':
+
+    if proj_geom['type'] == 'parallel':
+        angles = proj_geom['ProjectionAngles']
+        vectors = np.zeros((len(angles), 6))
+        for i in range(len(angles)):
+
+            # source
+            vectors[i, 0] = np.sin(angles[i])
+            vectors[i, 1] = -np.cos(angles[i])
+
+            # center of detector
+            vectors[i, 2] = 0
+            vectors[i, 3] = 0
+
+            # vector from detector pixel 0 to 1
+            vectors[i, 4] = np.cos(angles[i]) * proj_geom['DetectorWidth']
+            vectors[i, 5] = np.sin(angles[i]) * proj_geom['DetectorWidth']
+        proj_geom_out = ac.create_proj_geom(
+        'parallel_vec', proj_geom['DetectorCount'], vectors)
+
+    elif proj_geom['type'] == 'fanflat':
         angles = proj_geom['ProjectionAngles']
         vectors = np.zeros((len(angles), 6))
         for i in range(len(angles)):
diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx
index 53e84a9..0b8d527 100644
--- a/python/astra/utils.pyx
+++ b/python/astra/utils.pyx
@@ -227,6 +227,8 @@ cdef createProjectionGeometryStruct(CProjectionGeometry2D * geom):
         # dct['Vectors'] = vecs
     if (geom.isOfType(< string > six.b('parallel'))):
         dct["type"] = "parallel"
+    if (geom.isOfType(< string > six.b('parallel_vec'))):
+        dct["type"] = "parallel_vec"        
     elif (geom.isOfType(< string > six.b('fanflat'))):
         raise Exception("Not yet implemented")
         # astra::CFanFlatProjectionGeometry2D* pFanFlatGeom = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(_pProjGeom)
-- 
cgit v1.2.3


From 1ca3383b9454c3952c9715c0a8fc52a1031c67ce Mon Sep 17 00:00:00 2001
From: Wim van Aarle <wimvanaarle@gmail.com>
Date: Tue, 17 Mar 2015 16:25:23 +0100
Subject: updated python tools

---
 python/astra/functions.py | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

(limited to 'python/astra')

diff --git a/python/astra/functions.py b/python/astra/functions.py
index b9deb66..bbbb355 100644
--- a/python/astra/functions.py
+++ b/python/astra/functions.py
@@ -171,7 +171,7 @@ def geom_size(geom, dim=None):
     elif geom['type'] == 'parallel3d' or geom['type'] == 'cone':
         s = (geom['DetectorRowCount'], len(
             geom['ProjectionAngles']), geom['DetectorColCount'])
-    elif geom['type'] == 'fanflat_vec':
+    elif geom['type'] == 'parallel_vec' or geom['type'] == 'fanflat_vec':
         s = (geom['Vectors'].shape[0], geom['DetectorCount'])
     elif geom['type'] == 'parallel3d_vec' or geom['type'] == 'cone_vec':
         s = (geom['DetectorRowCount'], geom[
@@ -288,3 +288,37 @@ def geom_2vec(proj_geom):
         raise ValueError(
         'No suitable vector geometry found for type: ' + proj_geom['type'])
     return proj_geom_out
+
+
+def geom_postalignment(proj_geom, factor):
+    """Returns the size of a volume or sinogram, based on the projection or volume geometry.
+
+    :param proj_geom: input projection geometry (vector-based only, use astra.geom_2vec to convert conventional projection geometries)
+    :type proj_geom: :class:`dict`
+    :param factor: Optional axis index to return
+    :type factor: :class:`float`
+    """
+
+    if proj_geom['type'] == 'parallel_vec' or proj_geom['type'] == 'fanflat_vec':
+        for i in range(proj_geom['Vectors'].shape[0]):
+            proj_geom['Vectors'][i,2] = proj_geom['Vectors'][i,2] + factor * proj_geom['Vectors'][i,4];
+            proj_geom['Vectors'][i,3] = proj_geom['Vectors'][i,3] + factor * proj_geom['Vectors'][i,5];
+
+    elif proj_geom['type'] == 'parallel3d_vec' or proj_geom['type'] == 'cone_vec':
+
+        if len(factor) == 1:
+            for i in range(proj_geom['Vectors'].shape[0]):
+                proj_geom['Vectors'][i,3] = proj_geom['Vectors'][i,3] + factor * proj_geom['Vectors'][i,6];
+                proj_geom['Vectors'][i,4] = proj_geom['Vectors'][i,4] + factor * proj_geom['Vectors'][i,7];
+                proj_geom['Vectors'][i,5] = proj_geom['Vectors'][i,5] + factor * proj_geom['Vectors'][i,8];
+
+        elif len(factor) > 1:
+            for i in range(proj_geom['Vectors'].shape[0]):
+                proj_geom['Vectors'][i,3] = proj_geom['Vectors'][i,3] + factor[0] * proj_geom['Vectors'][i,6] + factor[1] * proj_geom['Vectors'][i, 9];
+                proj_geom['Vectors'][i,4] = proj_geom['Vectors'][i,4] + factor[0] * proj_geom['Vectors'][i,7] + factor[1] * proj_geom['Vectors'][i,10];
+                proj_geom['Vectors'][i,5] = proj_geom['Vectors'][i,5] + factor[0] * proj_geom['Vectors'][i,8] + factor[1] * proj_geom['Vectors'][i,11];
+    else:
+        raise ValueError('No suitable geometry for postalignment: ' + proj_geom['type'])
+
+    return proj_geom
+
-- 
cgit v1.2.3


From fb01aaf4cd4e7f22308e07bd94dcfc97083e8ec8 Mon Sep 17 00:00:00 2001
From: Wim van Aarle <wimvanaarle@gmail.com>
Date: Wed, 18 Mar 2015 11:08:20 +0100
Subject: updated python bindings

---
 python/astra/PyIncludes.pxd  |  41 +++++++----
 python/astra/algorithm_c.pyx |  12 ++--
 python/astra/data2d_c.pyx    |  60 +++++++---------
 python/astra/data3d.py       |  38 +++++++----
 python/astra/data3d_c.pyx    |  41 ++++++-----
 python/astra/projector_c.pyx |  14 ++--
 python/astra/utils.pxd       |   6 +-
 python/astra/utils.pyx       | 158 ++++++++++++++++++-------------------------
 8 files changed, 181 insertions(+), 189 deletions(-)

(limited to 'python/astra')

diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd
index 5a81844..ea624fc 100644
--- a/python/astra/PyIncludes.pxd
+++ b/python/astra/PyIncludes.pxd
@@ -40,6 +40,7 @@ cdef extern from "astra/Globals.h" namespace "astra":
 cdef extern from "astra/Config.h" namespace "astra":
 	cdef cppclass Config:
 		Config()
+		void initialize(string rootname)
 		XMLNode *self
 
 cdef extern from "astra/VolumeGeometry2D.h" namespace "astra":
@@ -58,6 +59,7 @@ cdef extern from "astra/VolumeGeometry2D.h" namespace "astra":
 		float32 getWindowMinY()
 		float32 getWindowMaxX()
 		float32 getWindowMaxY()
+		Config* getConfiguration()
 
 
 cdef extern from "astra/Float32VolumeData2D.h" namespace "astra":
@@ -67,6 +69,7 @@ cdef extern from "astra/Float32VolumeData2D.h" namespace "astra":
 		int getWidth()
 		int getHeight()
 		void changeGeometry(CVolumeGeometry2D*)
+		Config* getConfiguration()
 
 
 
@@ -79,10 +82,18 @@ cdef extern from "astra/ProjectionGeometry2D.h" namespace "astra":
 		bool isOfType(string)
 		float32 getProjectionAngle(int)
 		float32 getDetectorWidth()
+		Config* getConfiguration()
 
 cdef extern from "astra/Float32Data2D.h" namespace "astra::CFloat32Data2D":
-	cdef enum EDataType:
-		BASE,PROJECTION,VOLUME
+	cdef enum TWOEDataType "astra::CFloat32Data2D::EDataType":
+		TWOPROJECTION "astra::CFloat32Data2D::PROJECTION"
+		TWOVOLUME "astra::CFloat32Data2D::VOLUME"
+
+cdef extern from "astra/Float32Data3D.h" namespace "astra::CFloat32Data3D":
+	cdef enum THREEEDataType "astra::CFloat32Data3D::EDataType":
+		THREEPROJECTION "astra::CFloat32Data3D::PROJECTION"
+		THREEVOLUME "astra::CFloat32Data3D::VOLUME"
+
 
 cdef extern from "astra/Float32Data2D.h" namespace "astra":
 	cdef cppclass CFloat32Data2D:
@@ -92,7 +103,7 @@ cdef extern from "astra/Float32Data2D.h" namespace "astra":
 		float32 **getData2D()
 		int getWidth()
 		int getHeight()
-		EDataType getType()
+		TWOEDataType getType()
 
 
 
@@ -104,7 +115,7 @@ cdef extern from "astra/SparseMatrixProjectionGeometry2D.h" namespace "astra":
 cdef extern from "astra/FanFlatProjectionGeometry2D.h" namespace "astra":
 	cdef cppclass CFanFlatProjectionGeometry2D:
 		CFanFlatProjectionGeometry2D()
-		
+
 cdef extern from "astra/FanFlatVecProjectionGeometry2D.h" namespace "astra":
 	cdef cppclass CFanFlatVecProjectionGeometry2D:
 		CFanFlatVecProjectionGeometry2D()
@@ -153,8 +164,8 @@ cdef extern from "astra/SparseMatrix.h" namespace "astra":
 		float32* m_pfValues
 		unsigned int* m_piColIndices
 		unsigned long* m_plRowStarts
-		
-cdef extern from "astra/Float32Data3DMemory.h" namespace "astra":		
+
+cdef extern from "astra/Float32Data3DMemory.h" namespace "astra":
 	cdef cppclass CFloat32Data3DMemory:
 		CFloat32Data3DMemory()
 		bool isInitialized()
@@ -165,22 +176,26 @@ cdef extern from "astra/Float32Data3DMemory.h" namespace "astra":
 		void updateStatistics()
 		float32 *getData()
 		float32 ***getData3D()
+		THREEEDataType getType()
 
 
 cdef extern from "astra/VolumeGeometry3D.h" namespace "astra":
 	cdef cppclass CVolumeGeometry3D:
 		CVolumeGeometry3D()
 		bool initialize(Config)
+		Config * getConfiguration()
 
 cdef extern from "astra/ProjectionGeometry3D.h" namespace "astra":
 	cdef cppclass CProjectionGeometry3D:
 		CProjectionGeometry3D()
 		bool initialize(Config)
-		
-		
+		Config * getConfiguration()
+
+
 cdef extern from "astra/Float32VolumeData3DMemory.h" namespace "astra":
 	cdef cppclass CFloat32VolumeData3DMemory:
 		CFloat32VolumeData3DMemory(CVolumeGeometry3D*)
+		CVolumeGeometry3D* getGeometry()
 
 
 cdef extern from "astra/ParallelProjectionGeometry3D.h" namespace "astra":
@@ -195,7 +210,7 @@ cdef extern from "astra/ConeProjectionGeometry3D.h" namespace "astra":
 	cdef cppclass CConeProjectionGeometry3D:
 		CConeProjectionGeometry3D()
 		bool initialize(Config)
-		
+
 cdef extern from "astra/ConeVecProjectionGeometry3D.h" namespace "astra":
 	cdef cppclass CConeVecProjectionGeometry3D:
 		CConeVecProjectionGeometry3D()
@@ -203,9 +218,10 @@ cdef extern from "astra/ConeVecProjectionGeometry3D.h" namespace "astra":
 cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra":
 	cdef cppclass CFloat32ProjectionData3DMemory:
 		CFloat32ProjectionData3DMemory(CProjectionGeometry3D*)
-		CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*)		
+		CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*)
+		CProjectionGeometry3D* getGeometry()
 
-cdef extern from "astra/Float32Data3D.h" namespace "astra":		
+cdef extern from "astra/Float32Data3D.h" namespace "astra":
 	cdef cppclass CFloat32Data3D:
 		CFloat32Data3D()
 		bool isInitialized()
@@ -214,6 +230,3 @@ cdef extern from "astra/Float32Data3D.h" namespace "astra":
 		int getHeight()
 		int getDepth()
 		void updateStatistics()
-
-
-
diff --git a/python/astra/algorithm_c.pyx b/python/astra/algorithm_c.pyx
index 0c2999c..966d3d7 100644
--- a/python/astra/algorithm_c.pyx
+++ b/python/astra/algorithm_c.pyx
@@ -49,19 +49,17 @@ cdef extern from *:
 
 
 def create(config):
-    cdef XMLDocument * xml = utils.dict2XML(six.b('Algorithm'), config)
-    cdef Config cfg
+    cdef Config * cfg = utils.dictToConfig(six.b('Algorithm'), config)
     cdef CAlgorithm * alg
-    cfg.self = xml.getRootNode()
     alg = PyAlgorithmFactory.getSingletonPtr().create(cfg.self.getAttribute(six.b('type')))
     if alg == NULL:
-        del xml
+        del cfg
         raise Exception("Unknown algorithm.")
-    if not alg.initialize(cfg):
-        del xml
+    if not alg.initialize(cfg[0]):
+        del cfg
         del alg
         raise Exception("Algorithm not initialized.")
-    del xml
+    del cfg
     return manAlg.store(alg)
 
 cdef CAlgorithm * getAlg(i) except NULL:
diff --git a/python/astra/data2d_c.pyx b/python/astra/data2d_c.pyx
index dbe1c2f..882051c 100644
--- a/python/astra/data2d_c.pyx
+++ b/python/astra/data2d_c.pyx
@@ -47,10 +47,8 @@ from .PyIncludes cimport *
 cimport utils
 from .utils import wrap_from_bytes
 
-
 cdef CData2DManager * man2d = <CData2DManager * >PyData2DManager.getSingletonPtr()
 
-
 def clear():
     man2d.clear()
 
@@ -64,25 +62,22 @@ def delete(ids):
 
 
 def create(datatype, geometry, data=None):
-    cdef XMLDocument * xml
-    cdef Config cfg
+    cdef Config *cfg
     cdef CVolumeGeometry2D * pGeometry
     cdef CProjectionGeometry2D * ppGeometry
     cdef CFloat32Data2D * pDataObject2D
     if datatype == '-vol':
-        xml = utils.dict2XML(six.b('VolumeGeometry'), geometry)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry)
         pGeometry = new CVolumeGeometry2D()
-        if not pGeometry.initialize(cfg):
-            del xml
+        if not pGeometry.initialize(cfg[0]):
+            del cfg
             del pGeometry
             raise Exception('Geometry class not initialized.')
         pDataObject2D = <CFloat32Data2D * > new CFloat32VolumeData2D(pGeometry)
-        del xml
+        del cfg
         del pGeometry
     elif datatype == '-sino':
-        xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry)
         tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type')))
         if (tpe == 'sparse_matrix'):
             ppGeometry = <CProjectionGeometry2D * >new CSparseMatrixProjectionGeometry2D()
@@ -94,13 +89,13 @@ def create(datatype, geometry, data=None):
             ppGeometry = <CProjectionGeometry2D * >new CParallelVecProjectionGeometry2D()
         else:
             ppGeometry = <CProjectionGeometry2D * >new CParallelProjectionGeometry2D()
-        if not ppGeometry.initialize(cfg):
-            del xml
+        if not ppGeometry.initialize(cfg[0]):
+            del cfg
             del ppGeometry
             raise Exception('Geometry class not initialized.')
         pDataObject2D = <CFloat32Data2D * > new CFloat32ProjectionData2D(ppGeometry)
         del ppGeometry
-        del xml
+        del cfg
     else:
         raise Exception("Invalid datatype.  Please specify '-vol' or '-sino'.")
 
@@ -153,29 +148,27 @@ def get_geometry(i):
     cdef CFloat32Data2D * pDataObject = getObject(i)
     cdef CFloat32ProjectionData2D * pDataObject2
     cdef CFloat32VolumeData2D * pDataObject3
-    if pDataObject.getType() == PROJECTION:
+    if pDataObject.getType() == TWOPROJECTION:
         pDataObject2 = <CFloat32ProjectionData2D * >pDataObject
-        geom = utils.createProjectionGeometryStruct(pDataObject2.getGeometry())
-    elif pDataObject.getType() == VOLUME:
+        geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration())
+    elif pDataObject.getType() == TWOVOLUME:
         pDataObject3 = <CFloat32VolumeData2D * >pDataObject
-        geom = utils.createVolumeGeometryStruct(pDataObject3.getGeometry())
+        geom = utils.configToDict(pDataObject3.getGeometry().getConfiguration())
     else:
         raise Exception("Not a known data object")
     return geom
 
 
 def change_geometry(i, geom):
-    cdef XMLDocument * xml
-    cdef Config cfg
+    cdef Config *cfg
     cdef CVolumeGeometry2D * pGeometry
     cdef CProjectionGeometry2D * ppGeometry
     cdef CFloat32Data2D * pDataObject = getObject(i)
     cdef CFloat32ProjectionData2D * pDataObject2
     cdef CFloat32VolumeData2D * pDataObject3
-    if pDataObject.getType() == PROJECTION:
+    if pDataObject.getType() == TWOPROJECTION:
         pDataObject2 = <CFloat32ProjectionData2D * >pDataObject
-        xml = utils.dict2XML(six.b('ProjectionGeometry'), geom)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geom)
         tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type')))
         if (tpe == 'sparse_matrix'):
             ppGeometry = <CProjectionGeometry2D * >new CSparseMatrixProjectionGeometry2D()
@@ -187,34 +180,33 @@ def change_geometry(i, geom):
             ppGeometry = <CProjectionGeometry2D * >new CParallelVecProjectionGeometry2D()
         else:
             ppGeometry = <CProjectionGeometry2D * >new CParallelProjectionGeometry2D()
-        if not ppGeometry.initialize(cfg):
-            del xml
+        if not ppGeometry.initialize(cfg[0]):
+            del cfg
             del ppGeometry
             raise Exception('Geometry class not initialized.')
         if (ppGeometry.getDetectorCount() != pDataObject2.getDetectorCount() or ppGeometry.getProjectionAngleCount() != pDataObject2.getAngleCount()):
             del ppGeometry
-            del xml
+            del cfg
             raise Exception(
                 "The dimensions of the data do not match those specified in the geometry.")
         pDataObject2.changeGeometry(ppGeometry)
         del ppGeometry
-        del xml
-    elif pDataObject.getType() == VOLUME:
+        del cfg
+    elif pDataObject.getType() == TWOVOLUME:
         pDataObject3 = <CFloat32VolumeData2D * >pDataObject
-        xml = utils.dict2XML(six.b('VolumeGeometry'), geom)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('VolumeGeometry'), geom)
         pGeometry = new CVolumeGeometry2D()
-        if not pGeometry.initialize(cfg):
-            del xml
+        if not pGeometry.initialize(cfg[0]):
+            del cfg
             del pGeometry
             raise Exception('Geometry class not initialized.')
         if (pGeometry.getGridColCount() != pDataObject3.getWidth() or pGeometry.getGridRowCount() != pDataObject3.getHeight()):
-            del xml
+            del cfg
             del pGeometry
             raise Exception(
                 'The dimensions of the data do not match those specified in the geometry.')
         pDataObject3.changeGeometry(pGeometry)
-        del xml
+        del cfg
         del pGeometry
     else:
         raise Exception("Not a known data object")
diff --git a/python/astra/data3d.py b/python/astra/data3d.py
index 33bde51..a2e9201 100644
--- a/python/astra/data3d.py
+++ b/python/astra/data3d.py
@@ -27,7 +27,7 @@ from . import data3d_c as d
 
 def create(datatype,geometry,data=None):
     """Create a 3D object.
-        
+
     :param datatype: Data object type, '-vol' or '-sino'.
     :type datatype: :class:`string`
     :param geometry: Volume or projection geometry.
@@ -35,67 +35,77 @@ def create(datatype,geometry,data=None):
     :param data: Data to fill the constructed object with, either a scalar or array.
     :type data: :class:`float` or :class:`numpy.ndarray`
     :returns: :class:`int` -- the ID of the constructed object.
-    
+
     """
     return d.create(datatype,geometry,data)
 
 def get(i):
     """Get a 3D object.
-    
+
     :param i: ID of object to get.
     :type i: :class:`int`
     :returns: :class:`numpy.ndarray` -- The object data.
-    
+
     """
     return d.get(i)
 
 def get_shared(i):
     """Get a 3D object with memory shared between the ASTRA toolbox and numpy array.
-    
+
     :param i: ID of object to get.
     :type i: :class:`int`
     :returns: :class:`numpy.ndarray` -- The object data.
-    
+
     """
     return d.get_shared(i)
 
 def get_single(i):
     """Get a 3D object in single precision.
-    
+
     :param i: ID of object to get.
     :type i: :class:`int`
     :returns: :class:`numpy.ndarray` -- The object data.
-    
+
     """
     return g.get_single(i)
 
 def store(i,data):
     """Fill existing 3D object with data.
-    
+
     :param i: ID of object to fill.
     :type i: :class:`int`
     :param data: Data to fill the object with, either a scalar or array.
     :type data: :class:`float` or :class:`numpy.ndarray`
-    
+
     """
     return d.store(i,data)
 
+def get_geometry(i):
+    """Get the geometry of a 3D object.
+
+    :param i: ID of object.
+    :type i: :class:`int`
+    :returns: :class:`dict` -- The geometry of object with ID ``i``.
+
+    """
+    return d.get_geometry(i)
+
 def dimensions(i):
     """Get dimensions of a 3D object.
-    
+
     :param i: ID of object.
     :type i: :class:`int`
     :returns: :class:`tuple` -- dimensions of object with ID ``i``.
-    
+
     """
     return d.dimensions(i)
 
 def delete(ids):
     """Delete a 2D object.
-    
+
     :param ids: ID or list of ID's to delete.
     :type ids: :class:`int` or :class:`list`
-    
+
     """
     return d.delete(ids)
 
diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx
index f821aaf..4b069f7 100644
--- a/python/astra/data3d_c.pyx
+++ b/python/astra/data3d_c.pyx
@@ -51,26 +51,23 @@ cdef extern from *:
     CFloat32Data3DMemory * dynamic_cast_mem "dynamic_cast<astra::CFloat32Data3DMemory*>" (CFloat32Data3D * ) except NULL
 
 def create(datatype,geometry,data=None):
-    cdef XMLDocument * xml
-    cdef Config cfg
+    cdef Config *cfg
     cdef CVolumeGeometry3D * pGeometry
     cdef CProjectionGeometry3D * ppGeometry
     cdef CFloat32Data3DMemory * pDataObject3D
     cdef CConeProjectionGeometry3D* pppGeometry
     if datatype == '-vol':
-        xml = utils.dict2XML(six.b('VolumeGeometry'), geometry)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry)
         pGeometry = new CVolumeGeometry3D()
-        if not pGeometry.initialize(cfg):
-            del xml
+        if not pGeometry.initialize(cfg[0]):
+            del cfg
             del pGeometry
             raise Exception('Geometry class not initialized.')
         pDataObject3D = <CFloat32Data3DMemory * > new CFloat32VolumeData3DMemory(pGeometry)
-        del xml
+        del cfg
         del pGeometry
     elif datatype == '-sino' or datatype == '-proj3d':
-        xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry)
         tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type')))
         if (tpe == "parallel3d"):
             ppGeometry = <CProjectionGeometry3D*> new CParallelProjectionGeometry3D();
@@ -83,19 +80,18 @@ def create(datatype,geometry,data=None):
         else:
             raise Exception("Invalid geometry type.")
 
-        if not ppGeometry.initialize(cfg):
-            del xml
+        if not ppGeometry.initialize(cfg[0]):
+            del cfg
             del ppGeometry
             raise Exception('Geometry class not initialized.')
         pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(ppGeometry)
         del ppGeometry
-        del xml
+        del cfg
     elif datatype == "-sinocone":
-        xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry)
-        cfg.self = xml.getRootNode()
+        cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry)
         pppGeometry = new CConeProjectionGeometry3D()
-        if not pppGeometry.initialize(cfg):
-            del xml
+        if not pppGeometry.initialize(cfg[0]):
+            del cfg
             del pppGeometry
             raise Exception('Geometry class not initialized.')
         pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(pppGeometry)
@@ -112,6 +108,19 @@ def create(datatype,geometry,data=None):
 
     return man3d.store(<CFloat32Data3D*>pDataObject3D)
 
+def get_geometry(i):
+    cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i))
+    cdef CFloat32ProjectionData3DMemory * pDataObject2
+    cdef CFloat32VolumeData3DMemory * pDataObject3
+    if pDataObject.getType() == THREEPROJECTION:
+        pDataObject2 = <CFloat32ProjectionData3DMemory * >pDataObject
+        geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration())
+    elif pDataObject.getType() == THREEVOLUME:
+        pDataObject3 = <CFloat32VolumeData3DMemory * >pDataObject
+        geom = utils.configToDict(pDataObject3.getGeometry().getConfiguration())
+    else:
+        raise Exception("Not a known data object")
+    return geom
 
 cdef fillDataObject(CFloat32Data3DMemory * obj, data):
     if data is None:
diff --git a/python/astra/projector_c.pyx b/python/astra/projector_c.pyx
index 978ca09..f91a8dd 100644
--- a/python/astra/projector_c.pyx
+++ b/python/astra/projector_c.pyx
@@ -49,15 +49,13 @@ cdef CMatrixManager * manM = <CMatrixManager * >PyMatrixManager.getSingletonPtr(
 
 
 def create(config):
-    cdef XMLDocument * xml = utils.dict2XML(six.b('Projector2D'), config)
-    cdef Config cfg
+    cdef Config * cfg = utils.dictToConfig(six.b('Projector2D'), config)
     cdef CProjector2D * proj
-    cfg.self = xml.getRootNode()
-    proj = PyProjector2DFactory.getSingletonPtr().create(cfg)
+    proj = PyProjector2DFactory.getSingletonPtr().create(cfg[0])
     if proj == NULL:
-        del xml
+        del cfg
         raise Exception("Error creating projector.")
-    del xml
+    del cfg
     return manProj.store(proj)
 
 
@@ -87,12 +85,12 @@ cdef CProjector2D * getObject(i) except NULL:
 
 def projection_geometry(i):
     cdef CProjector2D * proj = getObject(i)
-    return utils.createProjectionGeometryStruct(proj.getProjectionGeometry())
+    return utils.configToDict(proj.getProjectionGeometry().getConfiguration())
 
 
 def volume_geometry(i):
     cdef CProjector2D * proj = getObject(i)
-    return utils.createVolumeGeometryStruct(proj.getVolumeGeometry())
+    return utils.configToDict(proj.getVolumeGeometry().getConfiguration())
 
 
 def weights_single_ray(i, projection_index, detector_index):
diff --git a/python/astra/utils.pxd b/python/astra/utils.pxd
index 55db9d3..ca84836 100644
--- a/python/astra/utils.pxd
+++ b/python/astra/utils.pxd
@@ -31,7 +31,5 @@ from .PyXMLDocument cimport XMLNode
 
 from .PyIncludes cimport *
 
-cdef XMLDocument *dict2XML(string rootname, dc)
-cdef XML2dict(XMLDocument *)
-cdef createVolumeGeometryStruct(CVolumeGeometry2D* geom)
-cdef createProjectionGeometryStruct(CProjectionGeometry2D* geom)
+cdef configToDict(Config *)
+cdef Config * dictToConfig(string rootname, dc)
diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx
index 0b8d527..0439f1b 100644
--- a/python/astra/utils.pyx
+++ b/python/astra/utils.pyx
@@ -31,7 +31,7 @@ import six
 from libcpp.string cimport string
 from libcpp.list cimport list
 from libcpp.vector cimport vector
-from cython.operator cimport dereference as deref
+from cython.operator cimport dereference as deref, preincrement as inc
 from cpython.version cimport PY_MAJOR_VERSION
 
 cimport PyXMLDocument
@@ -40,18 +40,16 @@ from .PyXMLDocument cimport XMLNode
 from .PyIncludes cimport *
 
 
-cdef XMLDocument * dict2XML(string rootname, dc):
-    cdef XMLDocument * doc = PyXMLDocument.createDocument(rootname)
-    cdef XMLNode * node = doc.getRootNode()
+cdef Config * dictToConfig(string rootname, dc):
+    cdef Config * cfg = new Config()
+    cfg.initialize(rootname)
     try:
-        readDict(node, dc)
-    except:
-        six.print_('Error reading XML')
-        del doc
-        doc = NULL
-    finally:
-        del node
-    return doc
+        readDict(cfg.self, dc)
+    except Exception as e:
+        del cfg
+        six.print_(e.strerror)
+        return NULL
+    return cfg
 
 def convert_item(item):
     if isinstance(item, six.string_types):
@@ -166,97 +164,73 @@ cdef void readOptions(XMLNode * node, dc):
         else:
             node.addOption(item, wrap_to_bytes(val))
 
-cdef vectorToNumpy(vector[float32] inp):
-    cdef int i
-    cdef int sz = inp.size()
-    ret = np.empty(sz)
-    for i in range(sz):
-        ret[i] = inp[i]
-    return ret
+cdef configToDict(Config *cfg):
+    return XMLNode2dict(cfg.self)
+
+def castString3(input):
+    return input.decode('utf-8')
+
+def castString2(input):
+    return input
+
+if six.PY3:
+    castString = castString3
+else:
+    castString = castString2
+
+def stringToPythonValue(inputIn):
+    input = castString(inputIn)
+    # matrix
+    if ';' in input:
+        row_strings = input.split(';')
+        col_strings = row_strings[0].split(',')
+        nRows = len(row_strings)
+        nCols = len(col_strings)
+
+        out = np.empty((nRows,nCols))
+        for ridx, row in enumerate(row_strings):
+            col_strings = row.split(',')
+            for cidx, col in enumerate(col_strings):
+                out[ridx,cidx] = float(col)
+        return out
+
+    # vector
+    if ',' in input:
+        items = input.split(',')
+        out = np.empty(len(items))
+        for idx,item in enumerate(items):
+            out[idx] = float(item)
+        return out
+
+    try:
+        # integer
+        return int(input)
+    except ValueError:
+        try:
+            #float
+            return float(input)
+        except ValueError:
+            # string
+            return str(input)
+
 
 cdef XMLNode2dict(XMLNode * node):
     cdef XMLNode * subnode
     cdef list[XMLNode * ] nodes
     cdef list[XMLNode * ].iterator it
     dct = {}
+    opts = {}
     if node.hasAttribute(six.b('type')):
-        dct['type'] = node.getAttribute(six.b('type'))
+        dct['type'] = castString(node.getAttribute(six.b('type')))
     nodes = node.getNodes()
     it = nodes.begin()
     while it != nodes.end():
         subnode = deref(it)
-        if subnode.hasAttribute(six.b('listsize')):
-            dct[subnode.getName(
-                )] = vectorToNumpy(subnode.getContentNumericalArray())
+        if castString(subnode.getName())=="Option":
+            opts[castString(subnode.getAttribute('key'))] = stringToPythonValue(subnode.getAttribute('value'))
         else:
-            dct[subnode.getName()] = subnode.getContent()
+            dct[castString(subnode.getName())] = stringToPythonValue(subnode.getContent())
         del subnode
+        inc(it)
+    if len(opts)>0: dct['options'] = opts
     return dct
-
-cdef XML2dict(XMLDocument * xml):
-    cdef XMLNode * node = xml.getRootNode()
-    dct = XMLNode2dict(node)
-    del node;
-    return dct;
-
-cdef createProjectionGeometryStruct(CProjectionGeometry2D * geom):
-    cdef int i
-    cdef CFanFlatVecProjectionGeometry2D * fanvecGeom
-    # cdef SFanProjection* p
-    dct = {}
-    dct['DetectorCount'] = geom.getDetectorCount()
-    if not geom.isOfType(< string > six.b('fanflat_vec')):
-        dct['DetectorWidth'] = geom.getDetectorWidth()
-        angles = np.empty(geom.getProjectionAngleCount())
-        for i in range(geom.getProjectionAngleCount()):
-            angles[i] = geom.getProjectionAngle(i)
-        dct['ProjectionAngles'] = angles
-    else:
-        raise Exception("Not yet implemented")
-        # fanvecGeom = <CFanFlatVecProjectionGeometry2D*> geom
-        # vecs = np.empty(fanvecGeom.getProjectionAngleCount()*6)
-        # iDetCount = pVecGeom.getDetectorCount()
-        # for i in range(fanvecGeom.getProjectionAngleCount()):
-        #	p = &fanvecGeom.getProjectionVectors()[i];
-        #	out[6*i + 0] = p.fSrcX
-        #	out[6*i + 1] = p.fSrcY
-        #	out[6*i + 2] = p.fDetSX + 0.5f*iDetCount*p.fDetUX
-        #	out[6*i + 3] = p.fDetSY + 0.5f*iDetCount*p.fDetUY
-        #	out[6*i + 4] = p.fDetUX
-        #	out[6*i + 5] = p.fDetUY
-        # dct['Vectors'] = vecs
-    if (geom.isOfType(< string > six.b('parallel'))):
-        dct["type"] = "parallel"
-    if (geom.isOfType(< string > six.b('parallel_vec'))):
-        dct["type"] = "parallel_vec"        
-    elif (geom.isOfType(< string > six.b('fanflat'))):
-        raise Exception("Not yet implemented")
-        # astra::CFanFlatProjectionGeometry2D* pFanFlatGeom = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(_pProjGeom)
-        # mGeometryInfo["DistanceOriginSource"] = mxCreateDoubleScalar(pFanFlatGeom->getOriginSourceDistance())
-        # mGeometryInfo["DistanceOriginDetector"] =
-        # mxCreateDoubleScalar(pFanFlatGeom->getOriginDetectorDistance())
-        dct["type"] = "fanflat"
-    elif (geom.isOfType(< string > six.b('sparse_matrix'))):
-        raise Exception("Not yet implemented")
-        # astra::CSparseMatrixProjectionGeometry2D* pSparseMatrixGeom =
-        # dynamic_cast<astra::CSparseMatrixProjectionGeometry2D*>(_pProjGeom);
-        dct["type"] = "sparse_matrix"
-        # dct["MatrixID"] =
-        # mxCreateDoubleScalar(CMatrixManager::getSingleton().getIndex(pSparseMatrixGeom->getMatrix()))
-    elif(geom.isOfType(< string > six.b('fanflat_vec'))):
-        dct["type"] = "fanflat_vec"
-    return dct
-
-cdef createVolumeGeometryStruct(CVolumeGeometry2D * geom):
-    mGeometryInfo = {}
-    mGeometryInfo["GridColCount"] = geom.getGridColCount()
-    mGeometryInfo["GridRowCount"] = geom.getGridRowCount()
-
-    mGeometryOptions = {}
-    mGeometryOptions["WindowMinX"] = geom.getWindowMinX()
-    mGeometryOptions["WindowMaxX"] = geom.getWindowMaxX()
-    mGeometryOptions["WindowMinY"] = geom.getWindowMinY()
-    mGeometryOptions["WindowMaxY"] = geom.getWindowMaxY()
-
-    mGeometryInfo["option"] = mGeometryOptions
-    return mGeometryInfo
-- 
cgit v1.2.3


From a3dc1d2ee6e683dadfd4ec418c72aa13eea6a2db Mon Sep 17 00:00:00 2001
From: Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>
Date: Tue, 19 Sep 2017 16:45:33 +0200
Subject: Fix spaces/tabs

---
 python/astra/PyIncludes.pxd | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'python/astra')

diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd
index 1c7973a..cf3f902 100644
--- a/python/astra/PyIncludes.pxd
+++ b/python/astra/PyIncludes.pxd
@@ -129,8 +129,8 @@ cdef extern from "astra/FanFlatVecProjectionGeometry2D.h" namespace "astra":
         CFanFlatVecProjectionGeometry2D()
 
 cdef extern from "astra/ParallelVecProjectionGeometry2D.h" namespace "astra":
-	cdef cppclass CParallelVecProjectionGeometry2D:
-		CParallelVecProjectionGeometry2D()
+    cdef cppclass CParallelVecProjectionGeometry2D:
+        CParallelVecProjectionGeometry2D()
 
 cdef extern from "astra/ParallelProjectionGeometry2D.h" namespace "astra":
     cdef cppclass CParallelProjectionGeometry2D:
-- 
cgit v1.2.3


From bf92d2d8dfacd7125ed48403145dbd4dc6181e4a Mon Sep 17 00:00:00 2001
From: Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>
Date: Mon, 9 Oct 2017 15:12:14 +0200
Subject: Support parallel_vec in python geom_size

---
 python/astra/pythonutils.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'python/astra')

diff --git a/python/astra/pythonutils.py b/python/astra/pythonutils.py
index 27fa8fd..1028a0a 100644
--- a/python/astra/pythonutils.py
+++ b/python/astra/pythonutils.py
@@ -51,7 +51,7 @@ def geom_size(geom, dim=None):
     elif geom['type'] == 'parallel3d' or geom['type'] == 'cone':
         s = (geom['DetectorRowCount'], len(
             geom['ProjectionAngles']), geom['DetectorColCount'])
-    elif geom['type'] == 'fanflat_vec':
+    elif geom['type'] == 'fanflat_vec' or geom['type'] == 'parallel_vec':
         s = (geom['Vectors'].shape[0], geom['DetectorCount'])
     elif geom['type'] == 'parallel3d_vec' or geom['type'] == 'cone_vec':
         s = (geom['DetectorRowCount'], geom[
-- 
cgit v1.2.3