summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorWillem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>2016-07-28 17:05:24 +0200
committerWillem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>2016-07-28 17:05:24 +0200
commitb2611a03577c285ddf48edab0d05dafa09ab362c (patch)
treec1d2f1b5166ba23f55e68e8faf0832f7c540f787 /src
parent1ff4a270a7df1edb54dd91fe653d6a936b959b3a (diff)
parent53249b3ad63f0d08b9862a75602acf263d230d77 (diff)
downloadastra-b2611a03577c285ddf48edab0d05dafa09ab362c.tar.gz
astra-b2611a03577c285ddf48edab0d05dafa09ab362c.tar.bz2
astra-b2611a03577c285ddf48edab0d05dafa09ab362c.tar.xz
astra-b2611a03577c285ddf48edab0d05dafa09ab362c.zip
Merge branch 'master' into parvec
Diffstat (limited to 'src')
-rw-r--r--src/ArtAlgorithm.cpp12
-rw-r--r--src/AstraObjectManager.cpp16
-rw-r--r--src/BackProjectionAlgorithm.cpp2
-rw-r--r--src/CglsAlgorithm.cpp2
-rw-r--r--src/CompositeGeometryManager.cpp1448
-rw-r--r--src/ConeProjectionGeometry3D.cpp96
-rw-r--r--src/ConeVecProjectionGeometry3D.cpp88
-rw-r--r--src/CudaBackProjectionAlgorithm.cpp5
-rw-r--r--src/CudaBackProjectionAlgorithm3D.cpp146
-rw-r--r--src/CudaCglsAlgorithm.cpp6
-rw-r--r--src/CudaCglsAlgorithm3D.cpp84
-rw-r--r--src/CudaDartMaskAlgorithm.cpp5
-rw-r--r--src/CudaDartMaskAlgorithm3D.cpp5
-rw-r--r--src/CudaDartSmoothingAlgorithm.cpp5
-rw-r--r--src/CudaDartSmoothingAlgorithm3D.cpp5
-rw-r--r--src/CudaDataOperationAlgorithm.cpp7
-rw-r--r--src/CudaEMAlgorithm.cpp6
-rw-r--r--src/CudaFDKAlgorithm3D.cpp49
-rw-r--r--src/CudaFilteredBackProjectionAlgorithm.cpp73
-rw-r--r--src/CudaForwardProjectionAlgorithm.cpp79
-rw-r--r--src/CudaForwardProjectionAlgorithm3D.cpp118
-rw-r--r--src/CudaProjector2D.cpp25
-rw-r--r--src/CudaProjector3D.cpp15
-rw-r--r--src/CudaReconstructionAlgorithm2D.cpp213
-rw-r--r--src/CudaRoiSelectAlgorithm.cpp3
-rw-r--r--src/CudaSartAlgorithm.cpp22
-rw-r--r--src/CudaSirtAlgorithm.cpp52
-rw-r--r--src/CudaSirtAlgorithm3D.cpp91
-rw-r--r--src/FanFlatBeamLineKernelProjector2D.cpp1
-rw-r--r--src/FanFlatBeamStripKernelProjector2D.cpp1
-rw-r--r--src/FanFlatProjectionGeometry2D.cpp5
-rw-r--r--src/FanFlatVecProjectionGeometry2D.cpp15
-rw-r--r--src/FilteredBackProjectionAlgorithm.cpp67
-rw-r--r--src/Float32ProjectionData3D.cpp36
-rw-r--r--src/Float32VolumeData3DMemory.cpp1
-rw-r--r--src/ForwardProjectionAlgorithm.cpp12
-rw-r--r--src/Fourier.cpp3460
-rw-r--r--src/GeometryUtil3D.cpp172
-rw-r--r--src/Globals.cpp3
-rw-r--r--src/Logging.cpp60
-rw-r--r--src/ParallelBeamBlobKernelProjector2D.cpp7
-rw-r--r--src/ParallelBeamLineKernelProjector2D.cpp1
-rw-r--r--src/ParallelBeamLinearKernelProjector2D.cpp1
-rw-r--r--src/ParallelBeamStripKernelProjector2D.cpp1
-rw-r--r--src/ParallelProjectionGeometry2D.cpp6
-rw-r--r--src/ParallelProjectionGeometry3D.cpp80
-rw-r--r--src/ParallelVecProjectionGeometry3D.cpp91
-rw-r--r--src/PluginAlgorithm.cpp36
-rw-r--r--src/ProjectionGeometry2D.cpp6
-rw-r--r--src/ProjectionGeometry3D.cpp10
-rw-r--r--src/ReconstructionAlgorithm2D.cpp35
-rw-r--r--src/ReconstructionAlgorithm3D.cpp29
-rw-r--r--src/ReconstructionAlgorithmMultiSlice2D.cpp8
-rw-r--r--src/SartAlgorithm.cpp34
-rw-r--r--src/SirtAlgorithm.cpp13
-rw-r--r--src/SparseMatrixProjectionGeometry2D.cpp3
-rw-r--r--src/SparseMatrixProjector2D.cpp1
-rw-r--r--src/Utilities.cpp156
-rw-r--r--src/VolumeGeometry2D.cpp5
-rw-r--r--src/VolumeGeometry3D.cpp10
-rw-r--r--src/XMLNode.cpp81
61 files changed, 6036 insertions, 1089 deletions
diff --git a/src/ArtAlgorithm.cpp b/src/ArtAlgorithm.cpp
index 6a699ec..526c263 100644
--- a/src/ArtAlgorithm.cpp
+++ b/src/ArtAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ArtAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
using namespace std;
@@ -158,8 +156,12 @@ bool CArtAlgorithm::initialize(const Config& _cfg)
return false;
}
+ // "Lambda" is replaced by the more descriptive "Relaxation"
m_fLambda = _cfg.self.getOptionNumerical("Lambda", 1.0f);
- CC.markOptionParsed("Lambda");
+ m_fLambda = _cfg.self.getOptionNumerical("Relaxation", m_fLambda);
+ if (!_cfg.self.hasOption("Relaxation"))
+ CC.markOptionParsed("Lambda");
+ CC.markOptionParsed("Relaxation");
// success
m_bIsInitialized = _check();
@@ -234,7 +236,7 @@ map<string,boost::any> CArtAlgorithm::getInformation()
{
map<string, boost::any> res;
res["RayOrder"] = getInformation("RayOrder");
- res["Lambda"] = getInformation("Lambda");
+ res["Relaxation"] = getInformation("Relaxation");
return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
};
@@ -242,7 +244,7 @@ map<string,boost::any> CArtAlgorithm::getInformation()
// Information - Specific
boost::any CArtAlgorithm::getInformation(std::string _sIdentifier)
{
- if (_sIdentifier == "Lambda") { return m_fLambda; }
+ if (_sIdentifier == "Relaxation") { return m_fLambda; }
if (_sIdentifier == "RayOrder") {
vector<float32> res;
for (int i = 0; i < m_iRayCount; i++) {
diff --git a/src/AstraObjectManager.cpp b/src/AstraObjectManager.cpp
index c49f273..46eae4b 100644
--- a/src/AstraObjectManager.cpp
+++ b/src/AstraObjectManager.cpp
@@ -31,13 +31,13 @@ $Id$
namespace astra {
-int CAstraIndexManager::m_iPreviousIndex = 0;
-
-DEFINE_SINGLETON(CAstraObjectManager<CProjector2D>);
-DEFINE_SINGLETON(CAstraObjectManager<CProjector3D>);
-DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data2D>);
-DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data3D>);
-DEFINE_SINGLETON(CAstraObjectManager<CAlgorithm>);
-DEFINE_SINGLETON(CAstraObjectManager<CSparseMatrix>);
+DEFINE_SINGLETON(CProjector2DManager);
+DEFINE_SINGLETON(CProjector3DManager);
+DEFINE_SINGLETON(CData2DManager);
+DEFINE_SINGLETON(CData3DManager);
+DEFINE_SINGLETON(CAlgorithmManager);
+DEFINE_SINGLETON(CMatrixManager);
+
+DEFINE_SINGLETON(CAstraIndexManager);
} // end namespace
diff --git a/src/BackProjectionAlgorithm.cpp b/src/BackProjectionAlgorithm.cpp
index f561a90..c9beee1 100644
--- a/src/BackProjectionAlgorithm.cpp
+++ b/src/BackProjectionAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/BackProjectionAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/DataProjectorPolicies.h"
diff --git a/src/CglsAlgorithm.cpp b/src/CglsAlgorithm.cpp
index b9031e3..1ca2549 100644
--- a/src/CglsAlgorithm.cpp
+++ b/src/CglsAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/CglsAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
using namespace std;
diff --git a/src/CompositeGeometryManager.cpp b/src/CompositeGeometryManager.cpp
new file mode 100644
index 0000000..084ba8c
--- /dev/null
+++ b/src/CompositeGeometryManager.cpp
@@ -0,0 +1,1448 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+ 2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The ASTRA Toolbox is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+*/
+
+#include "astra/CompositeGeometryManager.h"
+
+#ifdef ASTRA_CUDA
+
+#include "astra/GeometryUtil3D.h"
+#include "astra/VolumeGeometry3D.h"
+#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/ConeVecProjectionGeometry3D.h"
+#include "astra/ParallelProjectionGeometry3D.h"
+#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/Projector3D.h"
+#include "astra/CudaProjector3D.h"
+#include "astra/Float32ProjectionData3DMemory.h"
+#include "astra/Float32VolumeData3DMemory.h"
+#include "astra/Logging.h"
+
+#include "../cuda/3d/mem3d.h"
+
+#include <cstring>
+#include <sstream>
+#include <climits>
+
+#ifndef USE_PTHREADS
+#include <boost/thread/mutex.hpp>
+#include <boost/thread.hpp>
+#endif
+
+
+namespace astra {
+
+SGPUParams* CCompositeGeometryManager::s_params = 0;
+
+CCompositeGeometryManager::CCompositeGeometryManager()
+{
+ m_iMaxSize = 0;
+
+ if (s_params) {
+ m_iMaxSize = s_params->memory;
+ m_GPUIndices = s_params->GPUIndices;
+ }
+}
+
+
+// JOB:
+//
+// VolumePart
+// ProjectionPart
+// FP-or-BP
+// SET-or-ADD
+
+
+// Running a set of jobs:
+//
+// [ Assume OUTPUT Parts in a single JobSet don't alias?? ]
+// Group jobs by output Part
+// One thread per group?
+
+// Automatically split parts if too large
+// Performance model for odd-sized tasks?
+// Automatically split parts if not enough tasks to fill available GPUs
+
+
+// Splitting:
+// Constraints:
+// number of sub-parts divisible by N
+// max size of sub-parts
+
+// For splitting on both input and output side:
+// How to divide up memory? (Optimization problem; compute/benchmark)
+// (First approach: 0.5/0.5)
+
+
+bool CCompositeGeometryManager::splitJobs(TJobSet &jobs, size_t maxSize, int div, TJobSet &split)
+{
+ int maxBlockDim = astraCUDA3d::maxBlockDimension();
+ ASTRA_DEBUG("Found max block dim %d", maxBlockDim);
+
+ split.clear();
+
+ for (TJobSet::const_iterator i = jobs.begin(); i != jobs.end(); ++i)
+ {
+ CPart* pOutput = i->first;
+ const TJobList &L = i->second;
+
+ // 1. Split output part
+ // 2. Per sub-part:
+ // a. reduce input part
+ // b. split input part
+ // c. create jobs for new (input,output) subparts
+
+ TPartList splitOutput;
+ pOutput->splitZ(splitOutput, maxSize/3, UINT_MAX, div);
+#if 0
+ TPartList splitOutput2;
+ for (TPartList::iterator i_out = splitOutput.begin(); i_out != splitOutput.end(); ++i_out) {
+ boost::shared_ptr<CPart> outputPart = *i_out;
+ outputPart.get()->splitX(splitOutput2, UINT_MAX, UINT_MAX, 1);
+ }
+ splitOutput.clear();
+ for (TPartList::iterator i_out = splitOutput2.begin(); i_out != splitOutput2.end(); ++i_out) {
+ boost::shared_ptr<CPart> outputPart = *i_out;
+ outputPart.get()->splitY(splitOutput, UINT_MAX, UINT_MAX, 1);
+ }
+ splitOutput2.clear();
+#endif
+
+
+ for (TJobList::const_iterator j = L.begin(); j != L.end(); ++j)
+ {
+ const SJob &job = *j;
+
+ for (TPartList::iterator i_out = splitOutput.begin();
+ i_out != splitOutput.end(); ++i_out)
+ {
+ boost::shared_ptr<CPart> outputPart = *i_out;
+
+ SJob newjob;
+ newjob.pOutput = outputPart;
+ newjob.eType = j->eType;
+ newjob.eMode = j->eMode;
+ newjob.pProjector = j->pProjector;
+
+ CPart* input = job.pInput->reduce(outputPart.get());
+
+ if (input->getSize() == 0) {
+ ASTRA_DEBUG("Empty input");
+ newjob.eType = SJob::JOB_NOP;
+ split[outputPart.get()].push_back(newjob);
+ continue;
+ }
+
+ size_t remainingSize = ( maxSize - outputPart->getSize() ) / 2;
+
+ TPartList splitInput;
+ input->splitZ(splitInput, remainingSize, maxBlockDim, 1);
+ delete input;
+ TPartList splitInput2;
+ for (TPartList::iterator i_in = splitInput.begin(); i_in != splitInput.end(); ++i_in) {
+ boost::shared_ptr<CPart> inputPart = *i_in;
+ inputPart.get()->splitX(splitInput2, UINT_MAX, maxBlockDim, 1);
+ }
+ splitInput.clear();
+ for (TPartList::iterator i_in = splitInput2.begin(); i_in != splitInput2.end(); ++i_in) {
+ boost::shared_ptr<CPart> inputPart = *i_in;
+ inputPart.get()->splitY(splitInput, UINT_MAX, maxBlockDim, 1);
+ }
+ splitInput2.clear();
+
+ ASTRA_DEBUG("Input split into %d parts", splitInput.size());
+
+ for (TPartList::iterator i_in = splitInput.begin();
+ i_in != splitInput.end(); ++i_in)
+ {
+ newjob.pInput = *i_in;
+
+ split[outputPart.get()].push_back(newjob);
+
+ // Second and later (input) parts should always be added to
+ // output of first (input) part.
+ newjob.eMode = SJob::MODE_ADD;
+ }
+
+
+ }
+
+ }
+ }
+
+ return true;
+}
+
+CCompositeGeometryManager::CPart::CPart(const CPart& other)
+{
+ eType = other.eType;
+ pData = other.pData;
+ subX = other.subX;
+ subY = other.subY;
+ subZ = other.subZ;
+}
+
+CCompositeGeometryManager::CVolumePart::CVolumePart(const CVolumePart& other)
+ : CPart(other)
+{
+ pGeom = other.pGeom->clone();
+}
+
+CCompositeGeometryManager::CVolumePart::~CVolumePart()
+{
+ delete pGeom;
+}
+
+void CCompositeGeometryManager::CVolumePart::getDims(size_t &x, size_t &y, size_t &z)
+{
+ if (!pGeom) {
+ x = y = z = 0;
+ return;
+ }
+
+ x = pGeom->getGridColCount();
+ y = pGeom->getGridRowCount();
+ z = pGeom->getGridSliceCount();
+}
+
+size_t CCompositeGeometryManager::CPart::getSize()
+{
+ size_t x, y, z;
+ getDims(x, y, z);
+ return x * y * z;
+}
+
+
+
+CCompositeGeometryManager::CPart* CCompositeGeometryManager::CVolumePart::reduce(const CPart *_other)
+{
+ const CProjectionPart *other = dynamic_cast<const CProjectionPart *>(_other);
+ assert(other);
+
+ // TODO: Is 0.5 sufficient?
+ double umin = -0.5;
+ double umax = other->pGeom->getDetectorColCount() + 0.5;
+ double vmin = -0.5;
+ double vmax = other->pGeom->getDetectorRowCount() + 0.5;
+
+ double uu[4];
+ double vv[4];
+ uu[0] = umin; vv[0] = vmin;
+ uu[1] = umin; vv[1] = vmax;
+ uu[2] = umax; vv[2] = vmin;
+ uu[3] = umax; vv[3] = vmax;
+
+ double pixx = pGeom->getPixelLengthX();
+ double pixy = pGeom->getPixelLengthY();
+ double pixz = pGeom->getPixelLengthZ();
+
+ double xmin = pGeom->getWindowMinX() - 0.5 * pixx;
+ double xmax = pGeom->getWindowMaxX() + 0.5 * pixx;
+ double ymin = pGeom->getWindowMinY() - 0.5 * pixy;
+ double ymax = pGeom->getWindowMaxY() + 0.5 * pixy;
+
+ // NB: Flipped
+ double zmax = pGeom->getWindowMinZ() - 2.5 * pixz;
+ double zmin = pGeom->getWindowMaxZ() + 2.5 * pixz;
+
+ // TODO: This isn't as tight as it could be.
+ // In particular it won't detect the detector being
+ // missed entirely on the u side.
+
+ for (int i = 0; i < other->pGeom->getProjectionCount(); ++i) {
+ for (int j = 0; j < 4; ++j) {
+ double px, py, pz;
+
+ other->pGeom->backprojectPointX(i, uu[j], vv[j], xmin, py, pz);
+ //ASTRA_DEBUG("%f %f (%f - %f)", py, pz, ymin, ymax);
+ if (pz < zmin) zmin = pz;
+ if (pz > zmax) zmax = pz;
+ other->pGeom->backprojectPointX(i, uu[j], vv[j], xmax, py, pz);
+ //ASTRA_DEBUG("%f %f (%f - %f)", py, pz, ymin, ymax);
+ if (pz < zmin) zmin = pz;
+ if (pz > zmax) zmax = pz;
+
+ other->pGeom->backprojectPointY(i, uu[j], vv[j], ymin, px, pz);
+ //ASTRA_DEBUG("%f %f (%f - %f)", px, pz, xmin, xmax);
+ if (pz < zmin) zmin = pz;
+ if (pz > zmax) zmax = pz;
+ other->pGeom->backprojectPointY(i, uu[j], vv[j], ymax, px, pz);
+ //ASTRA_DEBUG("%f %f (%f - %f)", px, pz, xmin, xmax);
+ if (pz < zmin) zmin = pz;
+ if (pz > zmax) zmax = pz;
+ }
+ }
+
+ //ASTRA_DEBUG("coord extent: %f - %f", zmin, zmax);
+
+ // Clip both zmin and zmax to get rid of extreme (or infinite) values
+ // NB: When individual pz values are +/-Inf, the sign is determined
+ // by ray direction and on which side of the face the ray passes.
+ if (zmin < pGeom->getWindowMinZ() - 2*pixz)
+ zmin = pGeom->getWindowMinZ() - 2*pixz;
+ if (zmin > pGeom->getWindowMaxZ() + 2*pixz)
+ zmin = pGeom->getWindowMaxZ() + 2*pixz;
+ if (zmax < pGeom->getWindowMinZ() - 2*pixz)
+ zmax = pGeom->getWindowMinZ() - 2*pixz;
+ if (zmax > pGeom->getWindowMaxZ() + 2*pixz)
+ zmax = pGeom->getWindowMaxZ() + 2*pixz;
+
+ zmin = (zmin - pixz - pGeom->getWindowMinZ()) / pixz;
+ zmax = (zmax + pixz - pGeom->getWindowMinZ()) / pixz;
+
+ int _zmin = (int)floor(zmin);
+ int _zmax = (int)ceil(zmax);
+
+ //ASTRA_DEBUG("index extent: %d - %d", _zmin, _zmax);
+
+ if (_zmin < 0)
+ _zmin = 0;
+ if (_zmax > pGeom->getGridSliceCount())
+ _zmax = pGeom->getGridSliceCount();
+
+ if (_zmax <= _zmin) {
+ _zmin = _zmax = 0;
+ }
+ //ASTRA_DEBUG("adjusted extent: %d - %d", _zmin, _zmax);
+
+ CVolumePart *sub = new CVolumePart();
+ sub->subX = this->subX;
+ sub->subY = this->subY;
+ sub->subZ = this->subZ + _zmin;
+ sub->pData = pData;
+
+ if (_zmin == _zmax) {
+ sub->pGeom = 0;
+ } else {
+ sub->pGeom = new CVolumeGeometry3D(pGeom->getGridColCount(),
+ pGeom->getGridRowCount(),
+ _zmax - _zmin,
+ pGeom->getWindowMinX(),
+ pGeom->getWindowMinY(),
+ pGeom->getWindowMinZ() + _zmin * pixz,
+ pGeom->getWindowMaxX(),
+ pGeom->getWindowMaxY(),
+ pGeom->getWindowMinZ() + _zmax * pixz);
+ }
+
+ ASTRA_DEBUG("Reduce volume from %d - %d to %d - %d", this->subZ, this->subZ + pGeom->getGridSliceCount(), this->subZ + _zmin, this->subZ + _zmax);
+
+ return sub;
+}
+
+
+
+static size_t ceildiv(size_t a, size_t b) {
+ return (a + b - 1) / b;
+}
+
+static size_t computeLinearSplit(size_t maxBlock, int div, size_t sliceCount)
+{
+ size_t blockSize = maxBlock;
+ size_t blockCount;
+ if (sliceCount <= blockSize)
+ blockCount = 1;
+ else
+ blockCount = ceildiv(sliceCount, blockSize);
+
+ // Increase number of blocks to be divisible by div
+ size_t divCount = div * ceildiv(blockCount, div);
+
+ // If divCount is above sqrt(number of slices), then
+ // we can't guarantee divisibility by div, but let's try anyway
+ if (ceildiv(sliceCount, ceildiv(sliceCount, divCount)) % div == 0) {
+ blockCount = divCount;
+ } else {
+ // If divisibility isn't achievable, we may want to optimize
+ // differently.
+ // TODO: Figure out how to model and optimize this.
+ }
+
+ // Final adjustment to make blocks more evenly sized
+ // (This can't make the blocks larger)
+ blockSize = ceildiv(sliceCount, blockCount);
+
+ ASTRA_DEBUG("%ld %ld -> %ld * %ld", sliceCount, maxBlock, blockCount, blockSize);
+
+ assert(blockSize <= maxBlock);
+ assert((divCount * divCount > sliceCount) || (blockCount % div) == 0);
+
+ return blockSize;
+}
+
+template<class V, class P>
+static V* getProjectionVectors(const P* geom);
+
+template<>
+SConeProjection* getProjectionVectors(const CConeProjectionGeometry3D* pProjGeom)
+{
+ return genConeProjections(pProjGeom->getProjectionCount(),
+ pProjGeom->getDetectorColCount(),
+ pProjGeom->getDetectorRowCount(),
+ pProjGeom->getOriginSourceDistance(),
+ pProjGeom->getOriginDetectorDistance(),
+ pProjGeom->getDetectorSpacingX(),
+ pProjGeom->getDetectorSpacingY(),
+ pProjGeom->getProjectionAngles());
+}
+
+template<>
+SConeProjection* getProjectionVectors(const CConeVecProjectionGeometry3D* pProjGeom)
+{
+ int nth = pProjGeom->getProjectionCount();
+
+ SConeProjection* pProjs = new SConeProjection[nth];
+ for (int i = 0; i < nth; ++i)
+ pProjs[i] = pProjGeom->getProjectionVectors()[i];
+
+ return pProjs;
+}
+
+template<>
+SPar3DProjection* getProjectionVectors(const CParallelProjectionGeometry3D* pProjGeom)
+{
+ return genPar3DProjections(pProjGeom->getProjectionCount(),
+ pProjGeom->getDetectorColCount(),
+ pProjGeom->getDetectorRowCount(),
+ pProjGeom->getDetectorSpacingX(),
+ pProjGeom->getDetectorSpacingY(),
+ pProjGeom->getProjectionAngles());
+}
+
+template<>
+SPar3DProjection* getProjectionVectors(const CParallelVecProjectionGeometry3D* pProjGeom)
+{
+ int nth = pProjGeom->getProjectionCount();
+
+ SPar3DProjection* pProjs = new SPar3DProjection[nth];
+ for (int i = 0; i < nth; ++i)
+ pProjs[i] = pProjGeom->getProjectionVectors()[i];
+
+ return pProjs;
+}
+
+
+template<class V>
+static void translateProjectionVectorsU(V* pProjs, int count, double du)
+{
+ for (int i = 0; i < count; ++i) {
+ pProjs[i].fDetSX += du * pProjs[i].fDetUX;
+ pProjs[i].fDetSY += du * pProjs[i].fDetUY;
+ pProjs[i].fDetSZ += du * pProjs[i].fDetUZ;
+ }
+}
+
+template<class V>
+static void translateProjectionVectorsV(V* pProjs, int count, double dv)
+{
+ for (int i = 0; i < count; ++i) {
+ pProjs[i].fDetSX += dv * pProjs[i].fDetVX;
+ pProjs[i].fDetSY += dv * pProjs[i].fDetVY;
+ pProjs[i].fDetSZ += dv * pProjs[i].fDetVZ;
+ }
+}
+
+
+static CProjectionGeometry3D* getSubProjectionGeometryU(const CProjectionGeometry3D* pProjGeom, int u, int size)
+{
+ // First convert to vectors, then translate, then convert into new object
+
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(pProjGeom);
+ const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(pProjGeom);
+ const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(pProjGeom);
+ const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(pProjGeom);
+
+ if (conegeom || conevec3dgeom) {
+ SConeProjection* pConeProjs;
+ if (conegeom) {
+ pConeProjs = getProjectionVectors<SConeProjection>(conegeom);
+ } else {
+ pConeProjs = getProjectionVectors<SConeProjection>(conevec3dgeom);
+ }
+
+ translateProjectionVectorsU(pConeProjs, pProjGeom->getProjectionCount(), u);
+
+ CProjectionGeometry3D* ret = new CConeVecProjectionGeometry3D(pProjGeom->getProjectionCount(),
+ pProjGeom->getDetectorRowCount(),
+ size,
+ pConeProjs);
+
+
+ delete[] pConeProjs;
+ return ret;
+ } else {
+ assert(par3dgeom || parvec3dgeom);
+ SPar3DProjection* pParProjs;
+ if (par3dgeom) {
+ pParProjs = getProjectionVectors<SPar3DProjection>(par3dgeom);
+ } else {
+ pParProjs = getProjectionVectors<SPar3DProjection>(parvec3dgeom);
+ }
+
+ translateProjectionVectorsU(pParProjs, pProjGeom->getProjectionCount(), u);
+
+ CProjectionGeometry3D* ret = new CParallelVecProjectionGeometry3D(pProjGeom->getProjectionCount(),
+ pProjGeom->getDetectorRowCount(),
+ size,
+ pParProjs);
+
+ delete[] pParProjs;
+ return ret;
+ }
+
+}
+
+
+
+static CProjectionGeometry3D* getSubProjectionGeometryV(const CProjectionGeometry3D* pProjGeom, int v, int size)
+{
+ // First convert to vectors, then translate, then convert into new object
+
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(pProjGeom);
+ const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(pProjGeom);
+ const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(pProjGeom);
+ const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(pProjGeom);
+
+ if (conegeom || conevec3dgeom) {
+ SConeProjection* pConeProjs;
+ if (conegeom) {
+ pConeProjs = getProjectionVectors<SConeProjection>(conegeom);
+ } else {
+ pConeProjs = getProjectionVectors<SConeProjection>(conevec3dgeom);
+ }
+
+ translateProjectionVectorsV(pConeProjs, pProjGeom->getProjectionCount(), v);
+
+ CProjectionGeometry3D* ret = new CConeVecProjectionGeometry3D(pProjGeom->getProjectionCount(),
+ size,
+ pProjGeom->getDetectorColCount(),
+ pConeProjs);
+
+
+ delete[] pConeProjs;
+ return ret;
+ } else {
+ assert(par3dgeom || parvec3dgeom);
+ SPar3DProjection* pParProjs;
+ if (par3dgeom) {
+ pParProjs = getProjectionVectors<SPar3DProjection>(par3dgeom);
+ } else {
+ pParProjs = getProjectionVectors<SPar3DProjection>(parvec3dgeom);
+ }
+
+ translateProjectionVectorsV(pParProjs, pProjGeom->getProjectionCount(), v);
+
+ CProjectionGeometry3D* ret = new CParallelVecProjectionGeometry3D(pProjGeom->getProjectionCount(),
+ size,
+ pProjGeom->getDetectorColCount(),
+ pParProjs);
+
+ delete[] pParProjs;
+ return ret;
+ }
+
+}
+
+
+
+// split self into sub-parts:
+// - each no bigger than maxSize
+// - number of sub-parts is divisible by div
+// - maybe all approximately the same size?
+void CCompositeGeometryManager::CVolumePart::splitX(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div)
+{
+ if (true) {
+ // Split in vertical direction only at first, until we figure out
+ // a model for splitting in other directions
+
+ size_t sliceSize = ((size_t) pGeom->getGridSliceCount()) * pGeom->getGridRowCount();
+ int sliceCount = pGeom->getGridColCount();
+ size_t m = std::min(maxSize / sliceSize, maxDim);
+ size_t blockSize = computeLinearSplit(m, div, sliceCount);
+
+ int rem = sliceCount % blockSize;
+
+ ASTRA_DEBUG("From %d to %d step %d", -(rem / 2), sliceCount, blockSize);
+
+ for (int x = -(rem / 2); x < sliceCount; x += blockSize) {
+ int newsubX = x;
+ if (newsubX < 0) newsubX = 0;
+ int endX = x + blockSize;
+ if (endX > sliceCount) endX = sliceCount;
+ int size = endX - newsubX;
+
+ CVolumePart *sub = new CVolumePart();
+ sub->subX = this->subX + newsubX;
+ sub->subY = this->subY;
+ sub->subZ = this->subZ;
+
+ ASTRA_DEBUG("VolumePart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub);
+
+ double shift = pGeom->getPixelLengthX() * newsubX;
+
+ sub->pData = pData;
+ sub->pGeom = new CVolumeGeometry3D(size,
+ pGeom->getGridRowCount(),
+ pGeom->getGridSliceCount(),
+ pGeom->getWindowMinX() + shift,
+ pGeom->getWindowMinY(),
+ pGeom->getWindowMinZ(),
+ pGeom->getWindowMinX() + shift + size * pGeom->getPixelLengthX(),
+ pGeom->getWindowMaxY(),
+ pGeom->getWindowMaxZ());
+
+ out.push_back(boost::shared_ptr<CPart>(sub));
+ }
+ }
+}
+
+void CCompositeGeometryManager::CVolumePart::splitY(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div)
+{
+ if (true) {
+ // Split in vertical direction only at first, until we figure out
+ // a model for splitting in other directions
+
+ size_t sliceSize = ((size_t) pGeom->getGridColCount()) * pGeom->getGridSliceCount();
+ int sliceCount = pGeom->getGridRowCount();
+ size_t m = std::min(maxSize / sliceSize, maxDim);
+ size_t blockSize = computeLinearSplit(m, div, sliceCount);
+
+ int rem = sliceCount % blockSize;
+
+ ASTRA_DEBUG("From %d to %d step %d", -(rem / 2), sliceCount, blockSize);
+
+ for (int y = -(rem / 2); y < sliceCount; y += blockSize) {
+ int newsubY = y;
+ if (newsubY < 0) newsubY = 0;
+ int endY = y + blockSize;
+ if (endY > sliceCount) endY = sliceCount;
+ int size = endY - newsubY;
+
+ CVolumePart *sub = new CVolumePart();
+ sub->subX = this->subX;
+ sub->subY = this->subY + newsubY;
+ sub->subZ = this->subZ;
+
+ ASTRA_DEBUG("VolumePart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub);
+
+ double shift = pGeom->getPixelLengthY() * newsubY;
+
+ sub->pData = pData;
+ sub->pGeom = new CVolumeGeometry3D(pGeom->getGridColCount(),
+ size,
+ pGeom->getGridSliceCount(),
+ pGeom->getWindowMinX(),
+ pGeom->getWindowMinY() + shift,
+ pGeom->getWindowMinZ(),
+ pGeom->getWindowMaxX(),
+ pGeom->getWindowMinY() + shift + size * pGeom->getPixelLengthY(),
+ pGeom->getWindowMaxZ());
+
+ out.push_back(boost::shared_ptr<CPart>(sub));
+ }
+ }
+}
+
+void CCompositeGeometryManager::CVolumePart::splitZ(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div)
+{
+ if (true) {
+ // Split in vertical direction only at first, until we figure out
+ // a model for splitting in other directions
+
+ size_t sliceSize = ((size_t) pGeom->getGridColCount()) * pGeom->getGridRowCount();
+ int sliceCount = pGeom->getGridSliceCount();
+ size_t m = std::min(maxSize / sliceSize, maxDim);
+ size_t blockSize = computeLinearSplit(m, div, sliceCount);
+
+ int rem = sliceCount % blockSize;
+
+ ASTRA_DEBUG("From %d to %d step %d", -(rem / 2), sliceCount, blockSize);
+
+ for (int z = -(rem / 2); z < sliceCount; z += blockSize) {
+ int newsubZ = z;
+ if (newsubZ < 0) newsubZ = 0;
+ int endZ = z + blockSize;
+ if (endZ > sliceCount) endZ = sliceCount;
+ int size = endZ - newsubZ;
+
+ CVolumePart *sub = new CVolumePart();
+ sub->subX = this->subX;
+ sub->subY = this->subY;
+ sub->subZ = this->subZ + newsubZ;
+
+ ASTRA_DEBUG("VolumePart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub);
+
+ double shift = pGeom->getPixelLengthZ() * newsubZ;
+
+ sub->pData = pData;
+ sub->pGeom = new CVolumeGeometry3D(pGeom->getGridColCount(),
+ pGeom->getGridRowCount(),
+ size,
+ pGeom->getWindowMinX(),
+ pGeom->getWindowMinY(),
+ pGeom->getWindowMinZ() + shift,
+ pGeom->getWindowMaxX(),
+ pGeom->getWindowMaxY(),
+ pGeom->getWindowMinZ() + shift + size * pGeom->getPixelLengthZ());
+
+ out.push_back(boost::shared_ptr<CPart>(sub));
+ }
+ }
+}
+
+CCompositeGeometryManager::CVolumePart* CCompositeGeometryManager::CVolumePart::clone() const
+{
+ return new CVolumePart(*this);
+}
+
+CCompositeGeometryManager::CProjectionPart::CProjectionPart(const CProjectionPart& other)
+ : CPart(other)
+{
+ pGeom = other.pGeom->clone();
+}
+
+CCompositeGeometryManager::CProjectionPart::~CProjectionPart()
+{
+ delete pGeom;
+}
+
+void CCompositeGeometryManager::CProjectionPart::getDims(size_t &x, size_t &y, size_t &z)
+{
+ if (!pGeom) {
+ x = y = z = 0;
+ return;
+ }
+
+ x = pGeom->getDetectorColCount();
+ y = pGeom->getProjectionCount();
+ z = pGeom->getDetectorRowCount();
+}
+
+
+CCompositeGeometryManager::CPart* CCompositeGeometryManager::CProjectionPart::reduce(const CPart *_other)
+{
+ const CVolumePart *other = dynamic_cast<const CVolumePart *>(_other);
+ assert(other);
+
+ double vmin_g, vmax_g;
+
+ // reduce self to only cover intersection with projection of VolumePart
+ // (Project corners of volume, take bounding box)
+
+ for (int i = 0; i < pGeom->getProjectionCount(); ++i) {
+
+ double vol_u[8];
+ double vol_v[8];
+
+ double pixx = other->pGeom->getPixelLengthX();
+ double pixy = other->pGeom->getPixelLengthY();
+ double pixz = other->pGeom->getPixelLengthZ();
+
+ // TODO: Is 0.5 sufficient?
+ double xmin = other->pGeom->getWindowMinX() - 0.5 * pixx;
+ double xmax = other->pGeom->getWindowMaxX() + 0.5 * pixx;
+ double ymin = other->pGeom->getWindowMinY() - 0.5 * pixy;
+ double ymax = other->pGeom->getWindowMaxY() + 0.5 * pixy;
+ double zmin = other->pGeom->getWindowMinZ() - 0.5 * pixz;
+ double zmax = other->pGeom->getWindowMaxZ() + 0.5 * pixz;
+
+ pGeom->projectPoint(xmin, ymin, zmin, i, vol_u[0], vol_v[0]);
+ pGeom->projectPoint(xmin, ymin, zmax, i, vol_u[1], vol_v[1]);
+ pGeom->projectPoint(xmin, ymax, zmin, i, vol_u[2], vol_v[2]);
+ pGeom->projectPoint(xmin, ymax, zmax, i, vol_u[3], vol_v[3]);
+ pGeom->projectPoint(xmax, ymin, zmin, i, vol_u[4], vol_v[4]);
+ pGeom->projectPoint(xmax, ymin, zmax, i, vol_u[5], vol_v[5]);
+ pGeom->projectPoint(xmax, ymax, zmin, i, vol_u[6], vol_v[6]);
+ pGeom->projectPoint(xmax, ymax, zmax, i, vol_u[7], vol_v[7]);
+
+ double vmin = vol_v[0];
+ double vmax = vol_v[0];
+
+ for (int j = 1; j < 8; ++j) {
+ if (vol_v[j] < vmin)
+ vmin = vol_v[j];
+ if (vol_v[j] > vmax)
+ vmax = vol_v[j];
+ }
+
+ if (i == 0 || vmin < vmin_g)
+ vmin_g = vmin;
+ if (i == 0 || vmax > vmax_g)
+ vmax_g = vmax;
+ }
+
+ // fprintf(stderr, "v extent: %f %f\n", vmin_g, vmax_g);
+
+ int _vmin = (int)floor(vmin_g - 1.0f);
+ int _vmax = (int)ceil(vmax_g + 1.0f);
+ if (_vmin < 0)
+ _vmin = 0;
+ if (_vmax > pGeom->getDetectorRowCount())
+ _vmax = pGeom->getDetectorRowCount();
+
+ if (_vmin >= _vmax) {
+ _vmin = _vmax = 0;
+ }
+
+ CProjectionPart *sub = new CProjectionPart();
+ sub->subX = this->subX;
+ sub->subY = this->subY;
+ sub->subZ = this->subZ + _vmin;
+
+ sub->pData = pData;
+
+ if (_vmin == _vmax) {
+ sub->pGeom = 0;
+ } else {
+ sub->pGeom = getSubProjectionGeometryV(pGeom, _vmin, _vmax - _vmin);
+ }
+
+ ASTRA_DEBUG("Reduce projection from %d - %d to %d - %d", this->subZ, this->subZ + pGeom->getDetectorRowCount(), this->subZ + _vmin, this->subZ + _vmax);
+
+ return sub;
+}
+
+
+void CCompositeGeometryManager::CProjectionPart::splitX(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div)
+{
+ if (true) {
+ // Split in vertical direction only at first, until we figure out
+ // a model for splitting in other directions
+
+ size_t sliceSize = ((size_t) pGeom->getDetectorRowCount()) * pGeom->getProjectionCount();
+ int sliceCount = pGeom->getDetectorColCount();
+ size_t m = std::min(maxSize / sliceSize, maxDim);
+ size_t blockSize = computeLinearSplit(m, div, sliceCount);
+
+ int rem = sliceCount % blockSize;
+
+ for (int x = -(rem / 2); x < sliceCount; x += blockSize) {
+ int newsubX = x;
+ if (newsubX < 0) newsubX = 0;
+ int endX = x + blockSize;
+ if (endX > sliceCount) endX = sliceCount;
+ int size = endX - newsubX;
+
+ CProjectionPart *sub = new CProjectionPart();
+ sub->subX = this->subX + newsubX;
+ sub->subY = this->subY;
+ sub->subZ = this->subZ;
+
+ ASTRA_DEBUG("ProjectionPart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub);
+
+ sub->pData = pData;
+
+ sub->pGeom = getSubProjectionGeometryU(pGeom, newsubX, size);
+
+ out.push_back(boost::shared_ptr<CPart>(sub));
+ }
+ }
+}
+
+void CCompositeGeometryManager::CProjectionPart::splitY(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div)
+{
+ // TODO
+ out.push_back(boost::shared_ptr<CPart>(clone()));
+}
+
+void CCompositeGeometryManager::CProjectionPart::splitZ(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div)
+{
+ if (true) {
+ // Split in vertical direction only at first, until we figure out
+ // a model for splitting in other directions
+
+ size_t sliceSize = ((size_t) pGeom->getDetectorColCount()) * pGeom->getProjectionCount();
+ int sliceCount = pGeom->getDetectorRowCount();
+ size_t m = std::min(maxSize / sliceSize, maxDim);
+ size_t blockSize = computeLinearSplit(m, div, sliceCount);
+
+ int rem = sliceCount % blockSize;
+
+ for (int z = -(rem / 2); z < sliceCount; z += blockSize) {
+ int newsubZ = z;
+ if (newsubZ < 0) newsubZ = 0;
+ int endZ = z + blockSize;
+ if (endZ > sliceCount) endZ = sliceCount;
+ int size = endZ - newsubZ;
+
+ CProjectionPart *sub = new CProjectionPart();
+ sub->subX = this->subX;
+ sub->subY = this->subY;
+ sub->subZ = this->subZ + newsubZ;
+
+ ASTRA_DEBUG("ProjectionPart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub);
+
+ sub->pData = pData;
+
+ sub->pGeom = getSubProjectionGeometryV(pGeom, newsubZ, size);
+
+ out.push_back(boost::shared_ptr<CPart>(sub));
+ }
+ }
+
+}
+
+CCompositeGeometryManager::CProjectionPart* CCompositeGeometryManager::CProjectionPart::clone() const
+{
+ return new CProjectionPart(*this);
+}
+
+CCompositeGeometryManager::SJob CCompositeGeometryManager::createJobFP(CProjector3D *pProjector,
+ CFloat32VolumeData3DMemory *pVolData,
+ CFloat32ProjectionData3DMemory *pProjData)
+{
+ ASTRA_DEBUG("CCompositeGeometryManager::createJobFP");
+ // Create single job for FP
+
+ CVolumePart *input = new CVolumePart();
+ input->pData = pVolData;
+ input->subX = 0;
+ input->subY = 0;
+ input->subZ = 0;
+ input->pGeom = pVolData->getGeometry()->clone();
+ ASTRA_DEBUG("Main FP VolumePart -> %p", (void*)input);
+
+ CProjectionPart *output = new CProjectionPart();
+ output->pData = pProjData;
+ output->subX = 0;
+ output->subY = 0;
+ output->subZ = 0;
+ output->pGeom = pProjData->getGeometry()->clone();
+ ASTRA_DEBUG("Main FP ProjectionPart -> %p", (void*)output);
+
+ SJob FP;
+ FP.pInput = boost::shared_ptr<CPart>(input);
+ FP.pOutput = boost::shared_ptr<CPart>(output);
+ FP.pProjector = pProjector;
+ FP.eType = SJob::JOB_FP;
+ FP.eMode = SJob::MODE_SET;
+
+ return FP;
+}
+
+CCompositeGeometryManager::SJob CCompositeGeometryManager::createJobBP(CProjector3D *pProjector,
+ CFloat32VolumeData3DMemory *pVolData,
+ CFloat32ProjectionData3DMemory *pProjData)
+{
+ ASTRA_DEBUG("CCompositeGeometryManager::createJobBP");
+ // Create single job for BP
+
+ CProjectionPart *input = new CProjectionPart();
+ input->pData = pProjData;
+ input->subX = 0;
+ input->subY = 0;
+ input->subZ = 0;
+ input->pGeom = pProjData->getGeometry()->clone();
+
+ CVolumePart *output = new CVolumePart();
+ output->pData = pVolData;
+ output->subX = 0;
+ output->subY = 0;
+ output->subZ = 0;
+ output->pGeom = pVolData->getGeometry()->clone();
+
+ SJob BP;
+ BP.pInput = boost::shared_ptr<CPart>(input);
+ BP.pOutput = boost::shared_ptr<CPart>(output);
+ BP.pProjector = pProjector;
+ BP.eType = SJob::JOB_BP;
+ BP.eMode = SJob::MODE_SET;
+
+ return BP;
+}
+
+bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
+ CFloat32ProjectionData3DMemory *pProjData)
+{
+ TJobList L;
+ L.push_back(createJobFP(pProjector, pVolData, pProjData));
+
+ return doJobs(L);
+}
+
+bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, CFloat32VolumeData3DMemory *pVolData,
+ CFloat32ProjectionData3DMemory *pProjData)
+{
+ TJobList L;
+ L.push_back(createJobBP(pProjector, pVolData, pProjData));
+
+ return doJobs(L);
+}
+
+bool CCompositeGeometryManager::doFP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3DMemory *>& volData, const std::vector<CFloat32ProjectionData3DMemory *>& projData)
+{
+ ASTRA_DEBUG("CCompositeGeometryManager::doFP, multi-volume");
+
+ std::vector<CFloat32VolumeData3DMemory *>::const_iterator i;
+ std::vector<boost::shared_ptr<CPart> > inputs;
+
+ for (i = volData.begin(); i != volData.end(); ++i) {
+ CVolumePart *input = new CVolumePart();
+ input->pData = *i;
+ input->subX = 0;
+ input->subY = 0;
+ input->subZ = 0;
+ input->pGeom = (*i)->getGeometry()->clone();
+
+ inputs.push_back(boost::shared_ptr<CPart>(input));
+ }
+
+ std::vector<CFloat32ProjectionData3DMemory *>::const_iterator j;
+ std::vector<boost::shared_ptr<CPart> > outputs;
+
+ for (j = projData.begin(); j != projData.end(); ++j) {
+ CProjectionPart *output = new CProjectionPart();
+ output->pData = *j;
+ output->subX = 0;
+ output->subY = 0;
+ output->subZ = 0;
+ output->pGeom = (*j)->getGeometry()->clone();
+
+ outputs.push_back(boost::shared_ptr<CPart>(output));
+ }
+
+ std::vector<boost::shared_ptr<CPart> >::iterator i2;
+ std::vector<boost::shared_ptr<CPart> >::iterator j2;
+ TJobList L;
+
+ for (i2 = outputs.begin(); i2 != outputs.end(); ++i2) {
+ SJob FP;
+ FP.eMode = SJob::MODE_SET;
+ for (j2 = inputs.begin(); j2 != inputs.end(); ++j2) {
+ FP.pInput = *j2;
+ FP.pOutput = *i2;
+ FP.pProjector = pProjector;
+ FP.eType = SJob::JOB_FP;
+ L.push_back(FP);
+
+ // Set first, add rest
+ FP.eMode = SJob::MODE_ADD;
+ }
+ }
+
+ return doJobs(L);
+}
+
+bool CCompositeGeometryManager::doBP(CProjector3D *pProjector, const std::vector<CFloat32VolumeData3DMemory *>& volData, const std::vector<CFloat32ProjectionData3DMemory *>& projData)
+{
+ ASTRA_DEBUG("CCompositeGeometryManager::doBP, multi-volume");
+
+
+ std::vector<CFloat32VolumeData3DMemory *>::const_iterator i;
+ std::vector<boost::shared_ptr<CPart> > outputs;
+
+ for (i = volData.begin(); i != volData.end(); ++i) {
+ CVolumePart *output = new CVolumePart();
+ output->pData = *i;
+ output->subX = 0;
+ output->subY = 0;
+ output->subZ = 0;
+ output->pGeom = (*i)->getGeometry()->clone();
+
+ outputs.push_back(boost::shared_ptr<CPart>(output));
+ }
+
+ std::vector<CFloat32ProjectionData3DMemory *>::const_iterator j;
+ std::vector<boost::shared_ptr<CPart> > inputs;
+
+ for (j = projData.begin(); j != projData.end(); ++j) {
+ CProjectionPart *input = new CProjectionPart();
+ input->pData = *j;
+ input->subX = 0;
+ input->subY = 0;
+ input->subZ = 0;
+ input->pGeom = (*j)->getGeometry()->clone();
+
+ inputs.push_back(boost::shared_ptr<CPart>(input));
+ }
+
+ std::vector<boost::shared_ptr<CPart> >::iterator i2;
+ std::vector<boost::shared_ptr<CPart> >::iterator j2;
+ TJobList L;
+
+ for (i2 = outputs.begin(); i2 != outputs.end(); ++i2) {
+ SJob BP;
+ BP.eMode = SJob::MODE_SET;
+ for (j2 = inputs.begin(); j2 != inputs.end(); ++j2) {
+ BP.pInput = *j2;
+ BP.pOutput = *i2;
+ BP.pProjector = pProjector;
+ BP.eType = SJob::JOB_BP;
+ L.push_back(BP);
+
+ // Set first, add rest
+ BP.eMode = SJob::MODE_ADD;
+ }
+ }
+
+ return doJobs(L);
+}
+
+
+
+
+static bool doJob(const CCompositeGeometryManager::TJobSet::const_iterator& iter)
+{
+ CCompositeGeometryManager::CPart* output = iter->first;
+ const CCompositeGeometryManager::TJobList& L = iter->second;
+
+ assert(!L.empty());
+
+ bool zero = L.begin()->eMode == CCompositeGeometryManager::SJob::MODE_SET;
+
+ size_t outx, outy, outz;
+ output->getDims(outx, outy, outz);
+
+ if (L.begin()->eType == CCompositeGeometryManager::SJob::JOB_NOP) {
+ // just zero output?
+ if (zero) {
+ for (size_t z = 0; z < outz; ++z) {
+ for (size_t y = 0; y < outy; ++y) {
+ float* ptr = output->pData->getData();
+ ptr += (z + output->subX) * (size_t)output->pData->getHeight() * (size_t)output->pData->getWidth();
+ ptr += (y + output->subY) * (size_t)output->pData->getWidth();
+ ptr += output->subX;
+ memset(ptr, 0, sizeof(float) * outx);
+ }
+ }
+ }
+ return true;
+ }
+
+
+ astraCUDA3d::SSubDimensions3D dstdims;
+ dstdims.nx = output->pData->getWidth();
+ dstdims.pitch = dstdims.nx;
+ dstdims.ny = output->pData->getHeight();
+ dstdims.nz = output->pData->getDepth();
+ dstdims.subnx = outx;
+ dstdims.subny = outy;
+ dstdims.subnz = outz;
+ ASTRA_DEBUG("dstdims: %d,%d,%d in %d,%d,%d", dstdims.subnx, dstdims.subny, dstdims.subnz, dstdims.nx, dstdims.ny, dstdims.nz);
+ dstdims.subx = output->subX;
+ dstdims.suby = output->subY;
+ dstdims.subz = output->subZ;
+ float *dst = output->pData->getData();
+
+ astraCUDA3d::MemHandle3D outputMem = astraCUDA3d::allocateGPUMemory(outx, outy, outz, zero ? astraCUDA3d::INIT_ZERO : astraCUDA3d::INIT_NO);
+ bool ok = outputMem;
+
+ for (CCompositeGeometryManager::TJobList::const_iterator i = L.begin(); i != L.end(); ++i) {
+ const CCompositeGeometryManager::SJob &j = *i;
+
+ assert(j.pInput);
+
+ CCudaProjector3D *projector = dynamic_cast<CCudaProjector3D*>(j.pProjector);
+ Cuda3DProjectionKernel projKernel = ker3d_default;
+ int detectorSuperSampling = 1;
+ int voxelSuperSampling = 1;
+ if (projector) {
+ projKernel = projector->getProjectionKernel();
+ detectorSuperSampling = projector->getDetectorSuperSampling();
+ voxelSuperSampling = projector->getVoxelSuperSampling();
+ }
+
+ size_t inx, iny, inz;
+ j.pInput->getDims(inx, iny, inz);
+ astraCUDA3d::MemHandle3D inputMem = astraCUDA3d::allocateGPUMemory(inx, iny, inz, astraCUDA3d::INIT_NO);
+
+ astraCUDA3d::SSubDimensions3D srcdims;
+ srcdims.nx = j.pInput->pData->getWidth();
+ srcdims.pitch = srcdims.nx;
+ srcdims.ny = j.pInput->pData->getHeight();
+ srcdims.nz = j.pInput->pData->getDepth();
+ srcdims.subnx = inx;
+ srcdims.subny = iny;
+ srcdims.subnz = inz;
+ srcdims.subx = j.pInput->subX;
+ srcdims.suby = j.pInput->subY;
+ srcdims.subz = j.pInput->subZ;
+ const float *src = j.pInput->pData->getDataConst();
+
+ ok = astraCUDA3d::copyToGPUMemory(src, inputMem, srcdims);
+ if (!ok) ASTRA_ERROR("Error copying input data to GPU");
+
+ if (j.eType == CCompositeGeometryManager::SJob::JOB_FP) {
+ assert(dynamic_cast<CCompositeGeometryManager::CVolumePart*>(j.pInput.get()));
+ assert(dynamic_cast<CCompositeGeometryManager::CProjectionPart*>(j.pOutput.get()));
+
+ ASTRA_DEBUG("CCompositeGeometryManager::doJobs: doing FP");
+
+ ok = astraCUDA3d::FP(((CCompositeGeometryManager::CProjectionPart*)j.pOutput.get())->pGeom, outputMem, ((CCompositeGeometryManager::CVolumePart*)j.pInput.get())->pGeom, inputMem, detectorSuperSampling, projKernel);
+ if (!ok) ASTRA_ERROR("Error performing sub-FP");
+ ASTRA_DEBUG("CCompositeGeometryManager::doJobs: FP done");
+ } else if (j.eType == CCompositeGeometryManager::SJob::JOB_BP) {
+ assert(dynamic_cast<CCompositeGeometryManager::CVolumePart*>(j.pOutput.get()));
+ assert(dynamic_cast<CCompositeGeometryManager::CProjectionPart*>(j.pInput.get()));
+
+ ASTRA_DEBUG("CCompositeGeometryManager::doJobs: doing BP");
+
+ ok = astraCUDA3d::BP(((CCompositeGeometryManager::CProjectionPart*)j.pInput.get())->pGeom, inputMem, ((CCompositeGeometryManager::CVolumePart*)j.pOutput.get())->pGeom, outputMem, voxelSuperSampling);
+ if (!ok) ASTRA_ERROR("Error performing sub-BP");
+ ASTRA_DEBUG("CCompositeGeometryManager::doJobs: BP done");
+ } else {
+ assert(false);
+ }
+
+ ok = astraCUDA3d::freeGPUMemory(inputMem);
+ if (!ok) ASTRA_ERROR("Error freeing GPU memory");
+
+ }
+
+ ok = astraCUDA3d::copyFromGPUMemory(dst, outputMem, dstdims);
+ if (!ok) ASTRA_ERROR("Error copying output data from GPU");
+
+ ok = astraCUDA3d::freeGPUMemory(outputMem);
+ if (!ok) ASTRA_ERROR("Error freeing GPU memory");
+
+ return true;
+}
+
+
+class WorkQueue {
+public:
+ WorkQueue(CCompositeGeometryManager::TJobSet &_jobs) : m_jobs(_jobs) {
+#ifdef USE_PTHREADS
+ pthread_mutex_init(&m_mutex, 0);
+#endif
+ m_iter = m_jobs.begin();
+ }
+ bool receive(CCompositeGeometryManager::TJobSet::const_iterator &i) {
+ lock();
+
+ if (m_iter == m_jobs.end()) {
+ unlock();
+ return false;
+ }
+
+ i = m_iter++;
+
+ unlock();
+
+ return true;
+ }
+#ifdef USE_PTHREADS
+ void lock() {
+ // TODO: check mutex op return values
+ pthread_mutex_lock(&m_mutex);
+ }
+ void unlock() {
+ // TODO: check mutex op return values
+ pthread_mutex_unlock(&m_mutex);
+ }
+#else
+ void lock() {
+ m_mutex.lock();
+ }
+ void unlock() {
+ m_mutex.unlock();
+ }
+#endif
+
+private:
+ CCompositeGeometryManager::TJobSet &m_jobs;
+ CCompositeGeometryManager::TJobSet::const_iterator m_iter;
+#ifdef USE_PTHREADS
+ pthread_mutex_t m_mutex;
+#else
+ boost::mutex m_mutex;
+#endif
+};
+
+struct WorkThreadInfo {
+ WorkQueue* m_queue;
+ unsigned int m_iGPU;
+};
+
+#ifndef USE_PTHREADS
+
+void runEntries_boost(WorkThreadInfo* info)
+{
+ ASTRA_DEBUG("Launching thread on GPU %d\n", info->m_iGPU);
+ CCompositeGeometryManager::TJobSet::const_iterator i;
+ while (info->m_queue->receive(i)) {
+ ASTRA_DEBUG("Running block on GPU %d\n", info->m_iGPU);
+ astraCUDA3d::setGPUIndex(info->m_iGPU);
+ boost::this_thread::interruption_point();
+ doJob(i);
+ boost::this_thread::interruption_point();
+ }
+ ASTRA_DEBUG("Finishing thread on GPU %d\n", info->m_iGPU);
+}
+
+
+#else
+
+void* runEntries_pthreads(void* data) {
+ WorkThreadInfo* info = (WorkThreadInfo*)data;
+
+ ASTRA_DEBUG("Launching thread on GPU %d\n", info->m_iGPU);
+
+ CCompositeGeometryManager::TJobSet::const_iterator i;
+
+ while (info->m_queue->receive(i)) {
+ ASTRA_DEBUG("Running block on GPU %d\n", info->m_iGPU);
+ astraCUDA3d::setGPUIndex(info->m_iGPU);
+ pthread_testcancel();
+ doJob(i);
+ pthread_testcancel();
+ }
+ ASTRA_DEBUG("Finishing thread on GPU %d\n", info->m_iGPU);
+
+ return 0;
+}
+
+#endif
+
+
+void runWorkQueue(WorkQueue &queue, const std::vector<int> & iGPUIndices) {
+ int iThreadCount = iGPUIndices.size();
+
+ std::vector<WorkThreadInfo> infos;
+#ifdef USE_PTHREADS
+ std::vector<pthread_t> threads;
+#else
+ std::vector<boost::thread*> threads;
+#endif
+ infos.resize(iThreadCount);
+ threads.resize(iThreadCount);
+
+ for (int i = 0; i < iThreadCount; ++i) {
+ infos[i].m_queue = &queue;
+ infos[i].m_iGPU = iGPUIndices[i];
+#ifdef USE_PTHREADS
+ pthread_create(&threads[i], 0, runEntries_pthreads, (void*)&infos[i]);
+#else
+ threads[i] = new boost::thread(runEntries_boost, &infos[i]);
+#endif
+ }
+
+ // Wait for them to finish
+ for (int i = 0; i < iThreadCount; ++i) {
+#ifdef USE_PTHREADS
+ pthread_join(threads[i], 0);
+#else
+ threads[i]->join();
+ delete threads[i];
+ threads[i] = 0;
+#endif
+ }
+}
+
+
+void CCompositeGeometryManager::setGPUIndices(const std::vector<int>& GPUIndices)
+{
+ m_GPUIndices = GPUIndices;
+}
+
+bool CCompositeGeometryManager::doJobs(TJobList &jobs)
+{
+ ASTRA_DEBUG("CCompositeGeometryManager::doJobs");
+
+ // Sort job list into job set by output part
+ TJobSet jobset;
+
+ for (TJobList::iterator i = jobs.begin(); i != jobs.end(); ++i) {
+ jobset[i->pOutput.get()].push_back(*i);
+ }
+
+ size_t maxSize = m_iMaxSize;
+ if (maxSize == 0) {
+ // Get memory from first GPU. Not optimal...
+ if (!m_GPUIndices.empty())
+ astraCUDA3d::setGPUIndex(m_GPUIndices[0]);
+ maxSize = astraCUDA3d::availableGPUMemory();
+ if (maxSize == 0) {
+ ASTRA_WARN("Unable to get available GPU memory. Defaulting to 1GB.");
+ maxSize = 1024 * 1024 * 1024;
+ } else {
+ ASTRA_DEBUG("Detected %lu bytes of GPU memory", maxSize);
+ }
+ } else {
+ ASTRA_DEBUG("Set to %lu bytes of GPU memory", maxSize);
+ }
+ maxSize = (maxSize * 9) / 10;
+
+ maxSize /= sizeof(float);
+ int div = 1;
+ if (!m_GPUIndices.empty())
+ div = m_GPUIndices.size();
+
+ // Split jobs to fit
+ TJobSet split;
+ splitJobs(jobset, maxSize, div, split);
+ jobset.clear();
+
+ if (m_GPUIndices.size() <= 1) {
+
+ // Run jobs
+ ASTRA_DEBUG("Running single-threaded");
+
+ if (!m_GPUIndices.empty())
+ astraCUDA3d::setGPUIndex(m_GPUIndices[0]);
+
+ for (TJobSet::const_iterator iter = split.begin(); iter != split.end(); ++iter) {
+ doJob(iter);
+ }
+
+ } else {
+
+ ASTRA_DEBUG("Running multi-threaded");
+
+ WorkQueue wq(split);
+
+ runWorkQueue(wq, m_GPUIndices);
+
+ }
+
+ return true;
+}
+
+
+
+
+//static
+void CCompositeGeometryManager::setGlobalGPUParams(const SGPUParams& params)
+{
+ delete s_params;
+
+ s_params = new SGPUParams;
+ *s_params = params;
+
+ ASTRA_DEBUG("CompositeGeometryManager: Setting global GPU params:");
+ std::ostringstream s;
+ s << "GPU indices:";
+ for (unsigned int i = 0; i < params.GPUIndices.size(); ++i)
+ s << " " << params.GPUIndices[i];
+ std::string ss = s.str();
+ ASTRA_DEBUG(ss.c_str());
+ ASTRA_DEBUG("Memory: %llu", params.memory);
+}
+
+
+}
+
+#endif
diff --git a/src/ConeProjectionGeometry3D.cpp b/src/ConeProjectionGeometry3D.cpp
index dd22eba..96b04fb 100644
--- a/src/ConeProjectionGeometry3D.cpp
+++ b/src/ConeProjectionGeometry3D.cpp
@@ -29,8 +29,8 @@ $Id$
#include "astra/ConeProjectionGeometry3D.h"
#include "astra/Logging.h"
+#include "astra/GeometryUtil3D.h"
-#include <boost/lexical_cast.hpp>
#include <cstring>
using namespace std;
@@ -89,13 +89,13 @@ bool CConeProjectionGeometry3D::initialize(const Config& _cfg)
// Required: DistanceOriginDetector
XMLNode node = _cfg.self.getSingleNode("DistanceOriginDetector");
ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginDetector tag specified.");
- m_fOriginDetectorDistance = boost::lexical_cast<float32>(node.getContent());
+ m_fOriginDetectorDistance = node.getContentNumerical();
CC.markNodeParsed("DistanceOriginDetector");
// Required: DetectorOriginSource
node = _cfg.self.getSingleNode("DistanceOriginSource");
ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginSource tag specified.");
- m_fOriginSourceDistance = boost::lexical_cast<float32>(node.getContent());
+ m_fOriginSourceDistance = node.getContentNumerical();
CC.markNodeParsed("DistanceOriginSource");
// success
@@ -230,14 +230,14 @@ CVector3D CConeProjectionGeometry3D::getProjectionDirection(int _iProjectionInde
return ret;
}
-void CConeProjectionGeometry3D::projectPoint(float32 fX, float32 fY, float32 fZ,
- int iAngleIndex,
- float32 &fU, float32 &fV) const
+void CConeProjectionGeometry3D::projectPoint(double fX, double fY, double fZ,
+ int iAngleIndex,
+ double &fU, double &fV) const
{
ASTRA_ASSERT(iAngleIndex >= 0);
ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
- float alpha = m_pfProjectionAngles[iAngleIndex];
+ double alpha = m_pfProjectionAngles[iAngleIndex];
// Project point onto optical axis
@@ -245,21 +245,97 @@ void CConeProjectionGeometry3D::projectPoint(float32 fX, float32 fY, float32 fZ,
// Vector source->origin is (-sin(alpha), cos(alpha))
// Distance from source, projected on optical axis
- float fD = -sin(alpha) * fX + cos(alpha) * fY + m_fOriginSourceDistance;
+ double fD = -sin(alpha) * fX + cos(alpha) * fY + m_fOriginSourceDistance;
// Scale fZ to detector plane
fV = detectorOffsetYToRowIndexFloat( (fZ * (m_fOriginSourceDistance + m_fOriginDetectorDistance)) / fD );
// Orthogonal distance in XY-plane to optical axis
- float fS = cos(alpha) * fX + sin(alpha) * fY;
+ double fS = cos(alpha) * fX + sin(alpha) * fY;
// Scale fS to detector plane
fU = detectorOffsetXToColIndexFloat( (fS * (m_fOriginSourceDistance + m_fOriginDetectorDistance)) / fD );
+}
+
+void CConeProjectionGeometry3D::backprojectPointX(int iAngleIndex, double fU, double fV,
+ double fX, double &fY, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SConeProjection *projs = genConeProjections(1, m_iDetectorColCount, m_iDetectorRowCount,
+ m_fOriginSourceDistance,
+ m_fOriginDetectorDistance,
+ m_fDetectorSpacingX, m_fDetectorSpacingY,
+ &m_pfProjectionAngles[iAngleIndex]);
+
+ SConeProjection &proj = projs[0];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fX - proj.fSrcX) / (px - proj.fSrcX);
+
+ fY = proj.fSrcY + a * (py - proj.fSrcY);
+ fZ = proj.fSrcZ + a * (pz - proj.fSrcZ);
+
+ delete[] projs;
+}
+
+void CConeProjectionGeometry3D::backprojectPointY(int iAngleIndex, double fU, double fV,
+ double fY, double &fX, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
- ASTRA_DEBUG("alpha: %f, D: %f, V: %f, S: %f, U: %f", alpha, fD, fV, fS, fU);
+ SConeProjection *projs = genConeProjections(1, m_iDetectorColCount, m_iDetectorRowCount,
+ m_fOriginSourceDistance,
+ m_fOriginDetectorDistance,
+ m_fDetectorSpacingX, m_fDetectorSpacingY,
+ &m_pfProjectionAngles[iAngleIndex]);
+ SConeProjection &proj = projs[0];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fY - proj.fSrcY) / (py - proj.fSrcY);
+
+ fX = proj.fSrcX + a * (px - proj.fSrcX);
+ fZ = proj.fSrcZ + a * (pz - proj.fSrcZ);
+
+ delete[] projs;
+}
+
+void CConeProjectionGeometry3D::backprojectPointZ(int iAngleIndex, double fU, double fV,
+ double fZ, double &fX, double &fY) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SConeProjection *projs = genConeProjections(1, m_iDetectorColCount, m_iDetectorRowCount,
+ m_fOriginSourceDistance,
+ m_fOriginDetectorDistance,
+ m_fDetectorSpacingX, m_fDetectorSpacingY,
+ &m_pfProjectionAngles[iAngleIndex]);
+
+ SConeProjection &proj = projs[0];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fZ - proj.fSrcZ) / (pz - proj.fSrcZ);
+
+ fX = proj.fSrcX + a * (px - proj.fSrcX);
+ fY = proj.fSrcY + a * (py - proj.fSrcY);
+
+ delete[] projs;
}
+
} // end namespace astra
diff --git a/src/ConeVecProjectionGeometry3D.cpp b/src/ConeVecProjectionGeometry3D.cpp
index 47ed630..f4f900d 100644
--- a/src/ConeVecProjectionGeometry3D.cpp
+++ b/src/ConeVecProjectionGeometry3D.cpp
@@ -27,9 +27,9 @@ $Id$
*/
#include "astra/ConeVecProjectionGeometry3D.h"
+#include "astra/Utilities.h"
#include <cstring>
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -82,13 +82,13 @@ bool CConeVecProjectionGeometry3D::initialize(const Config& _cfg)
// Required: DetectorRowCount
node = _cfg.self.getSingleNode("DetectorRowCount");
ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorRowCount tag specified.");
- m_iDetectorRowCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorRowCount = node.getContentInt();
CC.markNodeParsed("DetectorRowCount");
// Required: DetectorColCount
node = _cfg.self.getSingleNode("DetectorColCount");
ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorColCount tag specified.");
- m_iDetectorColCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorColCount = node.getContentInt();
m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount;
CC.markNodeParsed("DetectorColCount");
@@ -212,18 +212,18 @@ Config* CConeVecProjectionGeometry3D::getConfiguration() const
std::string vectors = "";
for (int i = 0; i < m_iProjectionAngleCount; ++i) {
SConeProjection& p = m_pProjectionAngles[i];
- vectors += boost::lexical_cast<string>(p.fSrcX) + ",";
- vectors += boost::lexical_cast<string>(p.fSrcY) + ",";
- vectors += boost::lexical_cast<string>(p.fSrcZ) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSX + 0.5f*m_iDetectorRowCount*p.fDetVX + 0.5f*m_iDetectorColCount*p.fDetUX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSY + 0.5f*m_iDetectorRowCount*p.fDetVY + 0.5f*m_iDetectorColCount*p.fDetUY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSZ + 0.5f*m_iDetectorRowCount*p.fDetVZ + 0.5f*m_iDetectorColCount*p.fDetUZ) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUZ) + ",";
- vectors += boost::lexical_cast<string>(p.fDetVX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetVY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetVZ);
+ vectors += StringUtil::toString(p.fSrcX) + ",";
+ vectors += StringUtil::toString(p.fSrcY) + ",";
+ vectors += StringUtil::toString(p.fSrcZ) + ",";
+ vectors += StringUtil::toString(p.fDetSX + 0.5f*m_iDetectorRowCount*p.fDetVX + 0.5f*m_iDetectorColCount*p.fDetUX) + ",";
+ vectors += StringUtil::toString(p.fDetSY + 0.5f*m_iDetectorRowCount*p.fDetVY + 0.5f*m_iDetectorColCount*p.fDetUY) + ",";
+ vectors += StringUtil::toString(p.fDetSZ + 0.5f*m_iDetectorRowCount*p.fDetVZ + 0.5f*m_iDetectorColCount*p.fDetUZ) + ",";
+ vectors += StringUtil::toString(p.fDetUX) + ",";
+ vectors += StringUtil::toString(p.fDetUY) + ",";
+ vectors += StringUtil::toString(p.fDetUZ) + ",";
+ vectors += StringUtil::toString(p.fDetVX) + ",";
+ vectors += StringUtil::toString(p.fDetVY) + ",";
+ vectors += StringUtil::toString(p.fDetVZ);
if (i < m_iProjectionAngleCount-1) vectors += ';';
}
cfg->self.addChildNode("Vectors", vectors);
@@ -241,9 +241,9 @@ CVector3D CConeVecProjectionGeometry3D::getProjectionDirection(int _iProjectionI
return CVector3D(p.fDetSX + (u+0.5)*p.fDetUX + (v+0.5)*p.fDetVX - p.fSrcX, p.fDetSY + (u+0.5)*p.fDetUY + (v+0.5)*p.fDetVY - p.fSrcY, p.fDetSZ + (u+0.5)*p.fDetUZ + (v+0.5)*p.fDetVZ - p.fSrcZ);
}
-void CConeVecProjectionGeometry3D::projectPoint(float32 fX, float32 fY, float32 fZ,
+void CConeVecProjectionGeometry3D::projectPoint(double fX, double fY, double fZ,
int iAngleIndex,
- float32 &fU, float32 &fV) const
+ double &fU, double &fV) const
{
ASTRA_ASSERT(iAngleIndex >= 0);
ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
@@ -262,6 +262,60 @@ void CConeVecProjectionGeometry3D::projectPoint(float32 fX, float32 fY, float32
}
+void CConeVecProjectionGeometry3D::backprojectPointX(int iAngleIndex, double fU, double fV,
+ double fX, double &fY, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SConeProjection &proj = m_pProjectionAngles[iAngleIndex];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fX - proj.fSrcX) / (px - proj.fSrcX);
+
+ fY = proj.fSrcY + a * (py - proj.fSrcY);
+ fZ = proj.fSrcZ + a * (pz - proj.fSrcZ);
+}
+
+void CConeVecProjectionGeometry3D::backprojectPointY(int iAngleIndex, double fU, double fV,
+ double fY, double &fX, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SConeProjection &proj = m_pProjectionAngles[iAngleIndex];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fY - proj.fSrcY) / (py - proj.fSrcY);
+
+ fX = proj.fSrcX + a * (px - proj.fSrcX);
+ fZ = proj.fSrcZ + a * (pz - proj.fSrcZ);
+}
+
+void CConeVecProjectionGeometry3D::backprojectPointZ(int iAngleIndex, double fU, double fV,
+ double fZ, double &fX, double &fY) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SConeProjection &proj = m_pProjectionAngles[iAngleIndex];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fZ - proj.fSrcZ) / (pz - proj.fSrcZ);
+
+ fX = proj.fSrcX + a * (px - proj.fSrcX);
+ fY = proj.fSrcY + a * (py - proj.fSrcY);
+}
+
//----------------------------------------------------------------------------------------
bool CConeVecProjectionGeometry3D::_check()
diff --git a/src/CudaBackProjectionAlgorithm.cpp b/src/CudaBackProjectionAlgorithm.cpp
index 365e058..a73f895 100644
--- a/src/CudaBackProjectionAlgorithm.cpp
+++ b/src/CudaBackProjectionAlgorithm.cpp
@@ -76,10 +76,9 @@ bool CCudaBackProjectionAlgorithm::initialize(const Config& _cfg)
// Initialize - C++
bool CCudaBackProjectionAlgorithm::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
- CFloat32VolumeData2D* _pReconstruction,
- int _iGPUindex, int _iPixelSuperSampling)
+ CFloat32VolumeData2D* _pReconstruction)
{
- m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, 1, _iPixelSuperSampling);
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction);
if (!m_bIsInitialized)
return false;
diff --git a/src/CudaBackProjectionAlgorithm3D.cpp b/src/CudaBackProjectionAlgorithm3D.cpp
index fbb8f28..76d7b35 100644
--- a/src/CudaBackProjectionAlgorithm3D.cpp
+++ b/src/CudaBackProjectionAlgorithm3D.cpp
@@ -28,14 +28,16 @@ $Id$
#include "astra/CudaBackProjectionAlgorithm3D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
+#include "astra/CudaProjector3D.h"
#include "astra/ConeProjectionGeometry3D.h"
#include "astra/ParallelProjectionGeometry3D.h"
#include "astra/ParallelVecProjectionGeometry3D.h"
#include "astra/ConeVecProjectionGeometry3D.h"
+#include "astra/CompositeGeometryManager.h"
+
+#include "astra/Logging.h"
#include "../cuda/3d/astra3d.h"
@@ -86,6 +88,24 @@ bool CCudaBackProjectionAlgorithm3D::_check()
}
//---------------------------------------------------------------------------------------
+void CCudaBackProjectionAlgorithm3D::initializeFromProjector()
+{
+ m_iVoxelSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ CCudaProjector3D* pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector3D passed to BP3D_CUDA");
+ }
+ } else {
+ m_iVoxelSuperSampling = pCudaProjector->getVoxelSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+
+}
+
+//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg)
{
@@ -102,21 +122,21 @@ bool CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg)
return false;
}
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- CC.markOptionParsed("GPUindex");
- m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", 1);
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", m_iVoxelSuperSampling);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", m_iGPUIndex);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
CC.markOptionParsed("VoxelSuperSampling");
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
+
- CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
- ASTRA_ASSERT(pSinoMem);
- const CProjectionGeometry3D* projgeom = pSinoMem->getGeometry();
-const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
- const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
- if (parvec3dgeom || par3dgeom) {
- // This option is only supported for Par3D currently
- m_bSIRTWeighting = _cfg.self.getOptionBool("SIRTWeighting", false);
- CC.markOptionParsed("SIRTWeighting");
- }
+
+ m_bSIRTWeighting = _cfg.self.getOptionBool("SIRTWeighting", false);
+ CC.markOptionParsed("SIRTWeighting");
// success
m_bIsInitialized = _check();
@@ -139,6 +159,8 @@ bool CCudaBackProjectionAlgorithm3D::initialize(CProjector3D* _pProjector,
m_pSinogram = _pSinogram;
m_pReconstruction = _pReconstruction;
+ initializeFromProjector();
+
// success
m_bIsInitialized = _check();
return m_bIsInitialized;
@@ -172,88 +194,24 @@ void CCudaBackProjectionAlgorithm3D::run(int _iNrIterations)
ASTRA_ASSERT(pReconMem);
const CProjectionGeometry3D* projgeom = pSinoMem->getGeometry();
- const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
- const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
- const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
- const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
const CVolumeGeometry3D& volgeom = *pReconMem->getGeometry();
- if (conegeom) {
- astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- conegeom->getProjectionCount(),
- conegeom->getDetectorColCount(),
- conegeom->getDetectorRowCount(),
- conegeom->getOriginSourceDistance(),
- conegeom->getOriginDetectorDistance(),
- conegeom->getDetectorSpacingX(),
- conegeom->getDetectorSpacingY(),
- conegeom->getProjectionAngles(),
- m_iGPUIndex, m_iVoxelSuperSampling);
- } else if (par3dgeom) {
- if (!m_bSIRTWeighting) {
- astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- par3dgeom->getProjectionCount(),
- par3dgeom->getDetectorColCount(),
- par3dgeom->getDetectorRowCount(),
- par3dgeom->getDetectorSpacingX(),
- par3dgeom->getDetectorSpacingY(),
- par3dgeom->getProjectionAngles(),
- m_iGPUIndex, m_iVoxelSuperSampling);
- } else {
- astraCudaPar3DBP_SIRTWeighted(pReconMem->getData(),
- pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- par3dgeom->getProjectionCount(),
- par3dgeom->getDetectorColCount(),
- par3dgeom->getDetectorRowCount(),
- par3dgeom->getDetectorSpacingX(),
- par3dgeom->getDetectorSpacingY(),
- par3dgeom->getProjectionAngles(),
- m_iGPUIndex, m_iVoxelSuperSampling);
- }
- } else if (parvec3dgeom) {
- if (!m_bSIRTWeighting) {
- astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- parvec3dgeom->getProjectionCount(),
- parvec3dgeom->getDetectorColCount(),
- parvec3dgeom->getDetectorRowCount(),
- parvec3dgeom->getProjectionVectors(),
- m_iGPUIndex, m_iVoxelSuperSampling);
- } else {
- astraCudaPar3DBP_SIRTWeighted(pReconMem->getData(),
- pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- parvec3dgeom->getProjectionCount(),
- parvec3dgeom->getDetectorColCount(),
- parvec3dgeom->getDetectorRowCount(),
- parvec3dgeom->getProjectionVectors(),
- m_iGPUIndex, m_iVoxelSuperSampling);
- }
- } else if (conevecgeom) {
- astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- conevecgeom->getProjectionCount(),
- conevecgeom->getDetectorColCount(),
- conevecgeom->getDetectorRowCount(),
- conevecgeom->getProjectionVectors(),
- m_iGPUIndex, m_iVoxelSuperSampling);
+ if (m_bSIRTWeighting) {
+ astraCudaBP_SIRTWeighted(pReconMem->getData(),
+ pSinoMem->getDataConst(),
+ &volgeom, projgeom,
+ m_iGPUIndex, m_iVoxelSuperSampling);
} else {
- ASTRA_ASSERT(false);
+
+#if 1
+ CCompositeGeometryManager cgm;
+
+ cgm.doBP(m_pProjector, pReconMem, pSinoMem);
+#else
+ astraCudaBP(pReconMem->getData(), pSinoMem->getDataConst(),
+ &volgeom, projgeom,
+ m_iGPUIndex, m_iVoxelSuperSampling);
+#endif
}
}
diff --git a/src/CudaCglsAlgorithm.cpp b/src/CudaCglsAlgorithm.cpp
index 0cedff6..9dd4f78 100644
--- a/src/CudaCglsAlgorithm.cpp
+++ b/src/CudaCglsAlgorithm.cpp
@@ -77,11 +77,9 @@ bool CCudaCglsAlgorithm::initialize(const Config& _cfg)
// Initialize - C++
bool CCudaCglsAlgorithm::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
- CFloat32VolumeData2D* _pReconstruction,
- int _iGPUindex, int _iDetectorSuperSampling,
- int _iPixelSuperSampling)
+ CFloat32VolumeData2D* _pReconstruction)
{
- m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling);
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction);
if (!m_bIsInitialized)
return false;
diff --git a/src/CudaCglsAlgorithm3D.cpp b/src/CudaCglsAlgorithm3D.cpp
index 3457b81..930a71e 100644
--- a/src/CudaCglsAlgorithm3D.cpp
+++ b/src/CudaCglsAlgorithm3D.cpp
@@ -28,14 +28,15 @@ $Id$
#include "astra/CudaCglsAlgorithm3D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
+#include "astra/CudaProjector3D.h"
#include "astra/ConeProjectionGeometry3D.h"
#include "astra/ParallelVecProjectionGeometry3D.h"
#include "astra/ConeVecProjectionGeometry3D.h"
+#include "astra/Logging.h"
+
#include "../cuda/3d/astra3d.h"
using namespace std;
@@ -89,6 +90,26 @@ bool CCudaCglsAlgorithm3D::_check()
}
//---------------------------------------------------------------------------------------
+void CCudaCglsAlgorithm3D::initializeFromProjector()
+{
+ m_iVoxelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ CCudaProjector3D* pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector3D passed to CGLS3D_CUDA");
+ }
+ } else {
+ m_iVoxelSuperSampling = pCudaProjector->getVoxelSuperSampling();
+ m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+
+}
+
+//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaCglsAlgorithm3D::initialize(const Config& _cfg)
{
@@ -106,12 +127,20 @@ bool CCudaCglsAlgorithm3D::initialize(const Config& _cfg)
return false;
}
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- CC.markOptionParsed("GPUindex");
- m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
- CC.markOptionParsed("DetectorSuperSampling");
- m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", 1);
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", m_iVoxelSuperSampling);
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", m_iDetectorSuperSampling);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", m_iGPUIndex);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
CC.markOptionParsed("VoxelSuperSampling");
+ CC.markOptionParsed("DetectorSuperSampling");
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
+
+
m_pCgls = new AstraCGLS3d();
@@ -139,6 +168,8 @@ bool CCudaCglsAlgorithm3D::initialize(CProjector3D* _pProjector,
m_pSinogram = _pSinogram;
m_pReconstruction = _pReconstruction;
+ initializeFromProjector();
+
m_pCgls = new AstraCGLS3d;
m_bAstraCGLSInit = false;
@@ -171,9 +202,6 @@ void CCudaCglsAlgorithm3D::run(int _iNrIterations)
ASTRA_ASSERT(m_bIsInitialized);
const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry();
- const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
- const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
- const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry();
bool ok = true;
@@ -182,41 +210,7 @@ void CCudaCglsAlgorithm3D::run(int _iNrIterations)
ok &= m_pCgls->setGPUIndex(m_iGPUIndex);
- ok &= m_pCgls->setReconstructionGeometry(volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount());
-/*
- unsigned int iProjAngles,
- unsigned int iProjU,
- unsigned int iProjV,
- float fOriginSourceDistance,
- float fOriginDetectorDistance,
- float fDetUSize,
- float fDetVSize,
- const float *pfAngles)
-*/
- if (conegeom) {
- ok &= m_pCgls->setConeGeometry(conegeom->getProjectionCount(),
- conegeom->getDetectorColCount(),
- conegeom->getDetectorRowCount(),
- conegeom->getOriginSourceDistance(),
- conegeom->getOriginDetectorDistance(),
- conegeom->getDetectorSpacingX(),
- conegeom->getDetectorSpacingY(),
- conegeom->getProjectionAngles());
- } else if (parvec3dgeom) {
- ok &= m_pCgls->setPar3DGeometry(parvec3dgeom->getProjectionCount(),
- parvec3dgeom->getDetectorColCount(),
- parvec3dgeom->getDetectorRowCount(),
- parvec3dgeom->getProjectionVectors());
- } else if (conevec3dgeom) {
- ok &= m_pCgls->setConeGeometry(conevec3dgeom->getProjectionCount(),
- conevec3dgeom->getDetectorColCount(),
- conevec3dgeom->getDetectorRowCount(),
- conevec3dgeom->getProjectionVectors());
- } else {
- ASTRA_ASSERT(false);
- }
+ ok &= m_pCgls->setGeometry(&volgeom, projgeom);
ok &= m_pCgls->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling);
diff --git a/src/CudaDartMaskAlgorithm.cpp b/src/CudaDartMaskAlgorithm.cpp
index 950b428..c2a4cca 100644
--- a/src/CudaDartMaskAlgorithm.cpp
+++ b/src/CudaDartMaskAlgorithm.cpp
@@ -34,7 +34,6 @@ $Id$
#include "../cuda/2d/algo.h"
#include "astra/AstraObjectManager.h"
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -67,14 +66,14 @@ bool CCudaDartMaskAlgorithm::initialize(const Config& _cfg)
// reconstruction data
XMLNode node = _cfg.self.getSingleNode("SegmentationDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pSegmentation = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("SegmentationDataId");
// reconstruction data
node = _cfg.self.getSingleNode("MaskDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("MaskDataId");
diff --git a/src/CudaDartMaskAlgorithm3D.cpp b/src/CudaDartMaskAlgorithm3D.cpp
index b0dfc5b..dd12c58 100644
--- a/src/CudaDartMaskAlgorithm3D.cpp
+++ b/src/CudaDartMaskAlgorithm3D.cpp
@@ -34,7 +34,6 @@ $Id$
#include "../cuda/3d/dims3d.h"
#include "astra/AstraObjectManager.h"
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -67,14 +66,14 @@ bool CCudaDartMaskAlgorithm3D::initialize(const Config& _cfg)
// reconstruction data
XMLNode node = _cfg.self.getSingleNode("SegmentationDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pSegmentation = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("SegmentationDataId");
// reconstruction data
node = _cfg.self.getSingleNode("MaskDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pMask = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("MaskDataId");
diff --git a/src/CudaDartSmoothingAlgorithm.cpp b/src/CudaDartSmoothingAlgorithm.cpp
index 7e22809..425f0a3 100644
--- a/src/CudaDartSmoothingAlgorithm.cpp
+++ b/src/CudaDartSmoothingAlgorithm.cpp
@@ -34,7 +34,6 @@ $Id$
#include "../cuda/2d/algo.h"
#include "astra/AstraObjectManager.h"
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -67,14 +66,14 @@ bool CCudaDartSmoothingAlgorithm::initialize(const Config& _cfg)
// reconstruction data
XMLNode node = _cfg.self.getSingleNode("InDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pIn = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("InDataId");
// reconstruction data
node = _cfg.self.getSingleNode("OutDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pOut = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("OutDataId");
diff --git a/src/CudaDartSmoothingAlgorithm3D.cpp b/src/CudaDartSmoothingAlgorithm3D.cpp
index 9c4437a..df7e0df 100644
--- a/src/CudaDartSmoothingAlgorithm3D.cpp
+++ b/src/CudaDartSmoothingAlgorithm3D.cpp
@@ -34,7 +34,6 @@ $Id$
#include "../cuda/3d/dims3d.h"
#include "astra/AstraObjectManager.h"
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -67,14 +66,14 @@ bool CCudaDartSmoothingAlgorithm3D::initialize(const Config& _cfg)
// reconstruction data
XMLNode node = _cfg.self.getSingleNode("InDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pIn = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("InDataId");
// reconstruction data
node = _cfg.self.getSingleNode("OutDataId");
ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pOut = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("OutDataId");
diff --git a/src/CudaDataOperationAlgorithm.cpp b/src/CudaDataOperationAlgorithm.cpp
index ae133c2..82b676b 100644
--- a/src/CudaDataOperationAlgorithm.cpp
+++ b/src/CudaDataOperationAlgorithm.cpp
@@ -35,7 +35,6 @@ $Id$
#include "../cuda/2d/arith.h"
#include "astra/AstraObjectManager.h"
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -77,8 +76,8 @@ bool CCudaDataOperationAlgorithm::initialize(const Config& _cfg)
node = _cfg.self.getSingleNode("DataId");
ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No DataId tag specified.");
vector<string> data = node.getContentArray();
- for (vector<string>::iterator it = data.begin(); it != data.end(); it++){
- int id = boost::lexical_cast<int>(*it);
+ for (vector<string>::iterator it = data.begin(); it != data.end(); ++it){
+ int id = StringUtil::stringToInt(*it);
m_pData.push_back(dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id)));
}
CC.markNodeParsed("DataId");
@@ -97,7 +96,7 @@ bool CCudaDataOperationAlgorithm::initialize(const Config& _cfg)
CC.markOptionParsed("GPUIndex");
if (_cfg.self.hasOption("MaskId")) {
- int id = boost::lexical_cast<int>(_cfg.self.getOption("MaskId"));
+ int id = _cfg.self.getOptionInt("MaskId");
m_pMask = dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id));
}
CC.markOptionParsed("MaskId");
diff --git a/src/CudaEMAlgorithm.cpp b/src/CudaEMAlgorithm.cpp
index 5c71f3d..d0afd80 100644
--- a/src/CudaEMAlgorithm.cpp
+++ b/src/CudaEMAlgorithm.cpp
@@ -76,11 +76,9 @@ bool CCudaEMAlgorithm::initialize(const Config& _cfg)
// Initialize - C++
bool CCudaEMAlgorithm::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
- CFloat32VolumeData2D* _pReconstruction,
- int _iGPUindex, int _iDetectorSuperSampling,
- int _iPixelSuperSampling)
+ CFloat32VolumeData2D* _pReconstruction)
{
- m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling);
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction);
if (!m_bIsInitialized)
return false;
diff --git a/src/CudaFDKAlgorithm3D.cpp b/src/CudaFDKAlgorithm3D.cpp
index 467e641..b5ce545 100644
--- a/src/CudaFDKAlgorithm3D.cpp
+++ b/src/CudaFDKAlgorithm3D.cpp
@@ -28,12 +28,13 @@ $Id$
#include "astra/CudaFDKAlgorithm3D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
+#include "astra/CudaProjector3D.h"
#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/Logging.h"
+
#include "../cuda/3d/astra3d.h"
using namespace std;
@@ -84,6 +85,24 @@ bool CCudaFDKAlgorithm3D::_check()
}
//---------------------------------------------------------------------------------------
+void CCudaFDKAlgorithm3D::initializeFromProjector()
+{
+ m_iVoxelSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ CCudaProjector3D* pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector3D passed to FDK_CUDA");
+ }
+ } else {
+ m_iVoxelSuperSampling = pCudaProjector->getVoxelSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+
+}
+
+//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaFDKAlgorithm3D::initialize(const Config& _cfg)
{
@@ -100,10 +119,18 @@ bool CCudaFDKAlgorithm3D::initialize(const Config& _cfg)
return false;
}
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- CC.markOptionParsed("GPUindex");
- m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", 1);
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", m_iVoxelSuperSampling);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", m_iGPUIndex);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
CC.markOptionParsed("VoxelSuperSampling");
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
+
+
m_bShortScan = _cfg.self.getOptionBool("ShortScan", false);
CC.markOptionParsed("ShortScan");
@@ -171,17 +198,7 @@ void CCudaFDKAlgorithm3D::run(int _iNrIterations)
bool ok = true;
ok = astraCudaFDK(pReconMem->getData(), pSinoMem->getDataConst(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- conegeom->getProjectionCount(),
- conegeom->getDetectorColCount(),
- conegeom->getDetectorRowCount(),
- conegeom->getOriginSourceDistance(),
- conegeom->getOriginDetectorDistance(),
- conegeom->getDetectorSpacingX(),
- conegeom->getDetectorSpacingY(),
- conegeom->getProjectionAngles(),
+ &volgeom, conegeom,
m_bShortScan, m_iGPUIndex, m_iVoxelSuperSampling);
ASTRA_ASSERT(ok);
diff --git a/src/CudaFilteredBackProjectionAlgorithm.cpp b/src/CudaFilteredBackProjectionAlgorithm.cpp
index 5d6c166..aa97eec 100644
--- a/src/CudaFilteredBackProjectionAlgorithm.cpp
+++ b/src/CudaFilteredBackProjectionAlgorithm.cpp
@@ -28,10 +28,10 @@ $Id$
#include <astra/CudaFilteredBackProjectionAlgorithm.h>
#include <astra/FanFlatProjectionGeometry2D.h>
-#include <boost/lexical_cast.hpp>
#include <cstring>
#include "astra/AstraObjectManager.h"
+#include "astra/CudaProjector2D.h"
#include "../cuda/2d/astra.h"
#include "astra/Logging.h"
@@ -66,6 +66,24 @@ CCudaFilteredBackProjectionAlgorithm::~CCudaFilteredBackProjectionAlgorithm()
}
}
+void CCudaFilteredBackProjectionAlgorithm::initializeFromProjector()
+{
+ m_iPixelSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ // Projector
+ CCudaProjector2D* pCudaProjector = dynamic_cast<CCudaProjector2D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector2D passed to FBP_CUDA");
+ }
+ } else {
+ m_iPixelSuperSampling = pCudaProjector->getVoxelSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+
+}
+
bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
{
ASTRA_ASSERT(_cfg.self);
@@ -77,17 +95,31 @@ bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
clear();
}
+ // Projector
+ XMLNode node = _cfg.self.getSingleNode("ProjectorId");
+ CCudaProjector2D* pCudaProjector = 0;
+ if (node) {
+ int id = node.getContentInt();
+ CProjector2D *projector = CProjector2DManager::getSingleton().get(id);
+ pCudaProjector = dynamic_cast<CCudaProjector2D*>(projector);
+ if (!pCudaProjector) {
+ ASTRA_WARN("non-CUDA Projector2D passed");
+ }
+ }
+ CC.markNodeParsed("ProjectorId");
+
+
// sinogram data
- XMLNode node = _cfg.self.getSingleNode("ProjectionDataId");
+ node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ProjectionDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("ProjectionDataId");
// reconstruction data
node = _cfg.self.getSingleNode("ReconstructionDataId");
ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ReconstructionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("ReconstructionDataId");
@@ -107,7 +139,7 @@ bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
node = _cfg.self.getSingleNode("FilterSinogramId");
if (node)
{
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
const CFloat32ProjectionData2D * pFilterData = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
m_iFilterWidth = pFilterData->getGeometry()->getDetectorCount();
int iFilterProjectionCount = pFilterData->getGeometry()->getProjectionAngleCount();
@@ -126,7 +158,7 @@ bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
node = _cfg.self.getSingleNode("FilterParameter");
if (node)
{
- float fParameter = boost::lexical_cast<float>(node.getContent());
+ float fParameter = node.getContentNumerical();
m_fFilterParameter = fParameter;
}
else
@@ -139,7 +171,7 @@ bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
node = _cfg.self.getSingleNode("FilterD");
if (node)
{
- float fD = boost::lexical_cast<float>(node.getContent());
+ float fD = node.getContentNumerical();
m_fFilterD = fD;
}
else
@@ -148,29 +180,30 @@ bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
}
CC.markNodeParsed("FilterD"); // TODO: Only for some types!
- // GPU number
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- CC.markOptionParsed("GPUindex");
-
- // Pixel supersampling factor
- m_iPixelSuperSampling = (int)_cfg.self.getOptionNumerical("PixelSuperSampling", 1);
- CC.markOptionParsed("PixelSuperSampling");
-
// Fan beam short scan mode
if (m_pSinogram && dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry())) {
m_bShortScan = (int)_cfg.self.getOptionBool("ShortScan", false);
CC.markOptionParsed("ShortScan");
}
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iPixelSuperSampling = (int)_cfg.self.getOptionNumerical("PixelSuperSampling", m_iPixelSuperSampling);
+ CC.markOptionParsed("PixelSuperSampling");
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
m_pFBP = new AstraFBP;
m_bAstraFBPInit = false;
- // success
- m_bIsInitialized = true;
- return m_bIsInitialized;
+ return check();
}
bool CCudaFilteredBackProjectionAlgorithm::initialize(CFloat32ProjectionData2D * _pSinogram, CFloat32VolumeData2D * _pReconstruction, E_FBPFILTER _eFilter, const float * _pfFilter /* = NULL */, int _iFilterWidth /* = 0 */, int _iGPUIndex /* = 0 */, float _fFilterParameter /* = -1.0f */)
@@ -220,7 +253,7 @@ bool CCudaFilteredBackProjectionAlgorithm::initialize(CFloat32ProjectionData2D *
m_fFilterParameter = _fFilterParameter;
- return m_bIsInitialized;
+ return check();
}
void CCudaFilteredBackProjectionAlgorithm::run(int _iNrIterations /* = 0 */)
@@ -340,7 +373,7 @@ bool CCudaFilteredBackProjectionAlgorithm::check()
ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "FBP_CUDA", "Reconstruction Data Object Not Initialized.");
// check gpu index
- ASTRA_CONFIG_CHECK(m_iGPUIndex >= -1, "FBP_CUDA", "GPUIndex must be a non-negative integer.");
+ ASTRA_CONFIG_CHECK(m_iGPUIndex >= -1, "FBP_CUDA", "GPUIndex must be a non-negative integer or -1.");
// check pixel supersampling
ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 0, "FBP_CUDA", "PixelSuperSampling must be a non-negative integer.");
diff --git a/src/CudaForwardProjectionAlgorithm.cpp b/src/CudaForwardProjectionAlgorithm.cpp
index 0f97d59..80f2e02 100644
--- a/src/CudaForwardProjectionAlgorithm.cpp
+++ b/src/CudaForwardProjectionAlgorithm.cpp
@@ -35,11 +35,12 @@ $Id$
#include <driver_types.h>
#include <cuda_runtime_api.h>
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
+#include "astra/ParallelProjectionGeometry2D.h"
#include "astra/FanFlatProjectionGeometry2D.h"
#include "astra/FanFlatVecProjectionGeometry2D.h"
+#include "astra/Float32ProjectionData2D.h"
+#include "astra/Float32VolumeData2D.h"
#include "astra/CudaProjector2D.h"
#include "astra/Logging.h"
@@ -66,49 +67,67 @@ CCudaForwardProjectionAlgorithm::~CCudaForwardProjectionAlgorithm()
}
//---------------------------------------------------------------------------------------
+void CCudaForwardProjectionAlgorithm::initializeFromProjector()
+{
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ // Projector
+ CCudaProjector2D* pCudaProjector = dynamic_cast<CCudaProjector2D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector2D passed to FP_CUDA");
+ }
+ } else {
+ m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+}
+
+//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaForwardProjectionAlgorithm::initialize(const Config& _cfg)
{
ASTRA_ASSERT(_cfg.self);
ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm", this, _cfg);
+
+ // Projector
+ m_pProjector = 0;
+ XMLNode node = _cfg.self.getSingleNode("ProjectorId");
+ if (node) {
+ int id = node.getContentInt();
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ }
+ CC.markNodeParsed("ProjectorId");
+
+
// sinogram data
- XMLNode node = _cfg.self.getSingleNode("ProjectionDataId");
+ node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No ProjectionDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("ProjectionDataId");
// volume data
node = _cfg.self.getSingleNode("VolumeDataId");
ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No VolumeDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("VolumeDataId");
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", m_iDetectorSuperSampling);
+ CC.markOptionParsed("DetectorSuperSampling");
// GPU number
m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
- CC.markOptionParsed("GPUindex");
- if (!_cfg.self.hasOption("GPUindex"))
- CC.markOptionParsed("GPUIndex");
-
- // Detector supersampling factor
- m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
- CC.markOptionParsed("DetectorSuperSampling");
-
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
- // This isn't used yet, but passing it is not something to warn about
- node = _cfg.self.getSingleNode("ProjectorId");
- if (node) {
- id = boost::lexical_cast<int>(node.getContent());
- CProjector2D *projector = CProjector2DManager::getSingleton().get(id);
- if (!dynamic_cast<CCudaProjector2D*>(projector)) {
- ASTRA_WARN("non-CUDA Projector2D passed to FP_CUDA");
- }
- }
- CC.markNodeParsed("ProjectorId");
-
// return success
@@ -117,20 +136,16 @@ bool CCudaForwardProjectionAlgorithm::initialize(const Config& _cfg)
//----------------------------------------------------------------------------------------
// Initialize - C++
-bool CCudaForwardProjectionAlgorithm::initialize(CProjectionGeometry2D* _pProjectionGeometry,
- CVolumeGeometry2D* _pReconstructionGeometry,
+bool CCudaForwardProjectionAlgorithm::initialize(CProjector2D* _pProjector,
CFloat32VolumeData2D* _pVolume,
- CFloat32ProjectionData2D* _pSinogram,
- int _iGPUindex, int _iDetectorSuperSampling)
+ CFloat32ProjectionData2D* _pSinogram)
{
// store classes
- //m_pProjectionGeometry = _pProjectionGeometry;
- //m_pReconstructionGeometry = _pReconstructionGeometry;
+ m_pProjector = _pProjector;
m_pVolume = _pVolume;
m_pSinogram = _pSinogram;
- m_iDetectorSuperSampling = _iDetectorSuperSampling;
- m_iGPUIndex = _iGPUindex;
+ initializeFromProjector();
// return success
return check();
diff --git a/src/CudaForwardProjectionAlgorithm3D.cpp b/src/CudaForwardProjectionAlgorithm3D.cpp
index e29b5a9..f709e34 100644
--- a/src/CudaForwardProjectionAlgorithm3D.cpp
+++ b/src/CudaForwardProjectionAlgorithm3D.cpp
@@ -30,8 +30,6 @@ $Id$
#ifdef ASTRA_CUDA
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/CudaProjector3D.h"
@@ -40,6 +38,8 @@ $Id$
#include "astra/ParallelVecProjectionGeometry3D.h"
#include "astra/ConeVecProjectionGeometry3D.h"
+#include "astra/CompositeGeometryManager.h"
+
#include "astra/Logging.h"
#include "../cuda/3d/astra3d.h"
@@ -72,6 +72,23 @@ CCudaForwardProjectionAlgorithm3D::~CCudaForwardProjectionAlgorithm3D()
}
//---------------------------------------------------------------------------------------
+void CCudaForwardProjectionAlgorithm3D::initializeFromProjector()
+{
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ CCudaProjector3D* pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector3D passed to FP3D_CUDA");
+ }
+ } else {
+ m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+}
+
+//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg)
{
@@ -84,32 +101,34 @@ bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg)
// sinogram data
node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No ProjectionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pProjections = dynamic_cast<CFloat32ProjectionData3DMemory*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("ProjectionDataId");
// reconstruction data
node = _cfg.self.getSingleNode("VolumeDataId");
ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No VolumeDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pVolume = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("VolumeDataId");
// optional: projector
node = _cfg.self.getSingleNode("ProjectorId");
+ m_pProjector = 0;
if (node) {
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pProjector = CProjector3DManager::getSingleton().get(id);
- } else {
- m_pProjector = 0; // TODO: or manually construct default projector?
}
CC.markNodeParsed("ProjectorId");
- // GPU number
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- CC.markOptionParsed("GPUindex");
- m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", m_iDetectorSuperSampling);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", m_iGPUIndex);
CC.markOptionParsed("DetectorSuperSampling");
+ CC.markOptionParsed("GPUindex");
+
// success
m_bIsInitialized = check();
@@ -132,8 +151,15 @@ bool CCudaForwardProjectionAlgorithm3D::initialize(CProjector3D* _pProjector,
m_pProjections = _pProjections;
m_pVolume = _pVolume;
- m_iDetectorSuperSampling = _iDetectorSuperSampling;
- m_iGPUIndex = _iGPUindex;
+ CCudaProjector3D* pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ if (!pCudaProjector) {
+ // TODO: Report
+ m_iDetectorSuperSampling = _iDetectorSuperSampling;
+ m_iGPUIndex = _iGPUindex;
+ } else {
+ m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
// success
m_bIsInitialized = check();
@@ -237,11 +263,13 @@ void CCudaForwardProjectionAlgorithm3D::run(int)
// check initialized
assert(m_bIsInitialized);
+#if 1
+ CCompositeGeometryManager cgm;
+
+ cgm.doFP(m_pProjector, m_pVolume, m_pProjections);
+
+#else
const CProjectionGeometry3D* projgeom = m_pProjections->getGeometry();
- const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
- const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
- const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
- const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
const CVolumeGeometry3D& volgeom = *m_pVolume->getGeometry();
Cuda3DProjectionKernel projKernel = ker3d_default;
@@ -269,58 +297,10 @@ void CCudaForwardProjectionAlgorithm3D::run(int)
}
#endif
- if (conegeom) {
- astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- conegeom->getProjectionCount(),
- conegeom->getDetectorColCount(),
- conegeom->getDetectorRowCount(),
- conegeom->getOriginSourceDistance(),
- conegeom->getOriginDetectorDistance(),
- conegeom->getDetectorSpacingX(),
- conegeom->getDetectorSpacingY(),
- conegeom->getProjectionAngles(),
- m_iGPUIndex, m_iDetectorSuperSampling);
- } else if (par3dgeom) {
- astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- par3dgeom->getProjectionCount(),
- par3dgeom->getDetectorColCount(),
- par3dgeom->getDetectorRowCount(),
- par3dgeom->getDetectorSpacingX(),
- par3dgeom->getDetectorSpacingY(),
- par3dgeom->getProjectionAngles(),
- m_iGPUIndex, m_iDetectorSuperSampling,
- projKernel);
- } else if (parvec3dgeom) {
- astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- parvec3dgeom->getProjectionCount(),
- parvec3dgeom->getDetectorColCount(),
- parvec3dgeom->getDetectorRowCount(),
- parvec3dgeom->getProjectionVectors(),
- m_iGPUIndex, m_iDetectorSuperSampling,
- projKernel);
- } else if (conevecgeom) {
- astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(),
- volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount(),
- conevecgeom->getProjectionCount(),
- conevecgeom->getDetectorColCount(),
- conevecgeom->getDetectorRowCount(),
- conevecgeom->getProjectionVectors(),
- m_iGPUIndex, m_iDetectorSuperSampling);
- } else {
- ASTRA_ASSERT(false);
- }
-
+ astraCudaFP(m_pVolume->getDataConst(), m_pProjections->getData(),
+ &volgeom, projgeom,
+ m_iGPUIndex, m_iDetectorSuperSampling, projKernel);
+#endif
}
diff --git a/src/CudaProjector2D.cpp b/src/CudaProjector2D.cpp
index fa024c8..acf6000 100644
--- a/src/CudaProjector2D.cpp
+++ b/src/CudaProjector2D.cpp
@@ -59,6 +59,9 @@ void CCudaProjector2D::_clear()
m_bIsInitialized = false;
m_projectionKernel = ker2d_default;
+ m_iVoxelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
}
//----------------------------------------------------------------------------------------
@@ -117,18 +120,24 @@ bool CCudaProjector2D::initialize(const Config& _cfg)
}
CC.markNodeParsed("ProjectionKernel");
+ m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", 1);
+ CC.markOptionParsed("VoxelSuperSampling");
+
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
+
+
m_bIsInitialized = _check();
return m_bIsInitialized;
}
-/*
-bool CProjector2D::initialize(astra::CProjectionGeometry2D *, astra::CVolumeGeometry2D *)
-{
- ASTRA_ASSERT(false);
-
- return false;
-}
-*/
std::string CCudaProjector2D::description() const
{
diff --git a/src/CudaProjector3D.cpp b/src/CudaProjector3D.cpp
index 41529a5..bbfbd34 100644
--- a/src/CudaProjector3D.cpp
+++ b/src/CudaProjector3D.cpp
@@ -62,6 +62,9 @@ void CCudaProjector3D::_clear()
m_bIsInitialized = false;
m_projectionKernel = ker3d_default;
+ m_iVoxelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
}
//----------------------------------------------------------------------------------------
@@ -120,6 +123,18 @@ bool CCudaProjector3D::initialize(const Config& _cfg)
}
CC.markNodeParsed("ProjectionKernel");
+ m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", 1);
+ CC.markOptionParsed("VoxelSuperSampling");
+
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
+
m_bIsInitialized = _check();
return m_bIsInitialized;
}
diff --git a/src/CudaReconstructionAlgorithm2D.cpp b/src/CudaReconstructionAlgorithm2D.cpp
index db99d42..2798434 100644
--- a/src/CudaReconstructionAlgorithm2D.cpp
+++ b/src/CudaReconstructionAlgorithm2D.cpp
@@ -30,8 +30,6 @@ $Id$
#include "astra/CudaReconstructionAlgorithm2D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/FanFlatProjectionGeometry2D.h"
#include "astra/FanFlatVecProjectionGeometry2D.h"
@@ -84,103 +82,51 @@ void CCudaReconstructionAlgorithm2D::_clear()
}
//---------------------------------------------------------------------------------------
+void CCudaReconstructionAlgorithm2D::initializeFromProjector()
+{
+ m_iPixelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ // Projector
+ CCudaProjector2D* pCudaProjector = dynamic_cast<CCudaProjector2D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector2D passed");
+ }
+ } else {
+ m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
+ m_iPixelSuperSampling = pCudaProjector->getVoxelSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+}
+
+//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaReconstructionAlgorithm2D::initialize(const Config& _cfg)
{
ASTRA_ASSERT(_cfg.self);
ConfigStackCheck<CAlgorithm> CC("CudaReconstructionAlgorithm2D", this, _cfg);
- // if already initialized, clear first
- if (m_bIsInitialized) {
- clear();
- }
-
- // sinogram data
- XMLNode node = _cfg.self.getSingleNode("ProjectionDataId");
- ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ProjectionDataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
- m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
- CC.markNodeParsed("ProjectionDataId");
-
- // reconstruction data
- node = _cfg.self.getSingleNode("ReconstructionDataId");
- ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ReconstructionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
- m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
- CC.markNodeParsed("ReconstructionDataId");
-
- // fixed mask
- if (_cfg.self.hasOption("ReconstructionMaskId")) {
- m_bUseReconstructionMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("ReconstructionMaskId"));
- m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
- ASTRA_CONFIG_CHECK(m_pReconstructionMask, "CudaReconstruction2D", "Invalid ReconstructionMaskId.");
- }
- CC.markOptionParsed("ReconstructionMaskId");
- // fixed mask
- if (_cfg.self.hasOption("SinogramMaskId")) {
- m_bUseSinogramMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("SinogramMaskId"));
- m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
- ASTRA_CONFIG_CHECK(m_pSinogramMask, "CudaReconstruction2D", "Invalid SinogramMaskId.");
- }
- CC.markOptionParsed("SinogramMaskId");
+ m_bIsInitialized = CReconstructionAlgorithm2D::initialize(_cfg);
- // Constraints - NEW
- if (_cfg.self.hasOption("MinConstraint")) {
- m_bUseMinConstraint = true;
- m_fMinValue = _cfg.self.getOptionNumerical("MinConstraint", 0.0f);
- CC.markOptionParsed("MinConstraint");
- } else {
- // Constraint - OLD
- m_bUseMinConstraint = _cfg.self.getOptionBool("UseMinConstraint", false);
- CC.markOptionParsed("UseMinConstraint");
- if (m_bUseMinConstraint) {
- m_fMinValue = _cfg.self.getOptionNumerical("MinConstraintValue", 0.0f);
- CC.markOptionParsed("MinConstraintValue");
- }
- }
- if (_cfg.self.hasOption("MaxConstraint")) {
- m_bUseMaxConstraint = true;
- m_fMaxValue = _cfg.self.getOptionNumerical("MaxConstraint", 255.0f);
- CC.markOptionParsed("MaxConstraint");
- } else {
- // Constraint - OLD
- m_bUseMaxConstraint = _cfg.self.getOptionBool("UseMaxConstraint", false);
- CC.markOptionParsed("UseMaxConstraint");
- if (m_bUseMaxConstraint) {
- m_fMaxValue = _cfg.self.getOptionNumerical("MaxConstraintValue", 0.0f);
- CC.markOptionParsed("MaxConstraintValue");
- }
- }
+ if (!m_bIsInitialized)
+ return false;
- // GPU number
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
- CC.markOptionParsed("GPUindex");
- if (!_cfg.self.hasOption("GPUindex"))
- CC.markOptionParsed("GPUIndex");
+ initializeFromProjector();
- // Detector supersampling factor
- m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
+ // Deprecated options
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", m_iDetectorSuperSampling);
+ m_iPixelSuperSampling = (int)_cfg.self.getOptionNumerical("PixelSuperSampling", m_iPixelSuperSampling);
CC.markOptionParsed("DetectorSuperSampling");
-
- // Pixel supersampling factor
- m_iPixelSuperSampling = (int)_cfg.self.getOptionNumerical("PixelSuperSampling", 1);
CC.markOptionParsed("PixelSuperSampling");
-
- // This isn't used yet, but passing it is not something to warn about
- node = _cfg.self.getSingleNode("ProjectorId");
- if (node) {
- id = boost::lexical_cast<int>(node.getContent());
- CProjector2D *projector = CProjector2DManager::getSingleton().get(id);
- if (!dynamic_cast<CCudaProjector2D*>(projector)) {
- ASTRA_WARN("non-CUDA Projector2D passed");
- }
- }
- CC.markNodeParsed("ProjectorId");
-
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
return _check();
}
@@ -191,32 +137,18 @@ bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
CFloat32VolumeData2D* _pReconstruction)
{
- return initialize(_pProjector, _pSinogram, _pReconstruction, 0, 1);
-}
-
-//---------------------------------------------------------------------------------------
-// Initialize - C++
-bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
- CFloat32ProjectionData2D* _pSinogram,
- CFloat32VolumeData2D* _pReconstruction,
- int _iGPUindex,
- int _iDetectorSuperSampling,
- int _iPixelSuperSampling)
-{
// if already initialized, clear first
if (m_bIsInitialized) {
clear();
}
- m_pProjector = 0;
+ m_pProjector = _pProjector;
// required classes
m_pSinogram = _pSinogram;
m_pReconstruction = _pReconstruction;
- m_iDetectorSuperSampling = _iDetectorSuperSampling;
- m_iPixelSuperSampling = _iPixelSuperSampling;
- m_iGPUIndex = _iGPUindex;
+ initializeFromProjector();
return _check();
}
@@ -226,40 +158,13 @@ bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
// Check
bool CCudaReconstructionAlgorithm2D::_check()
{
- // TODO: CLEAN UP
-
-
- // check pointers
- //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object.");
- ASTRA_CONFIG_CHECK(m_pSinogram, "SIRT_CUDA", "Invalid Projection Data Object.");
- ASTRA_CONFIG_CHECK(m_pReconstruction, "SIRT_CUDA", "Invalid Reconstruction Data Object.");
-
- // check initializations
- //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized.");
- ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "SIRT_CUDA", "Projection Data Object Not Initialized.");
- ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "SIRT_CUDA", "Reconstruction Data Object Not Initialized.");
-
- ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "SIRT_CUDA", "DetectorSuperSampling must be a positive integer.");
- ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 1, "SIRT_CUDA", "PixelSuperSampling must be a positive integer.");
- ASTRA_CONFIG_CHECK(m_iGPUIndex >= -1, "SIRT_CUDA", "GPUIndex must be a non-negative integer.");
-
- // check compatibility between projector and data classes
-// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector.");
-// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector.");
-
- // todo: turn some of these back on
+ if (!CReconstructionAlgorithm2D::_check())
+ return false;
-// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified.");
-// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized.");
-// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified.");
-// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized.");
+ ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "CudaReconstructionAlgorithm2D", "DetectorSuperSampling must be a positive integer.");
+ ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 1, "CudaReconstructionAlgorithm2D", "PixelSuperSampling must be a positive integer.");
+ ASTRA_CONFIG_CHECK(m_iGPUIndex >= -1, "CudaReconstructionAlgorithm2D", "GPUIndex must be a non-negative integer or -1.");
- // check dimensions
- //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch.");
- //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch.");
- //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch.");
- //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch.");
-
// check restrictions
// TODO: check restrictions built into cuda code
@@ -424,6 +329,20 @@ bool CCudaReconstructionAlgorithm2D::setupGeometry()
}
//----------------------------------------------------------------------------------------
+
+void CCudaReconstructionAlgorithm2D::initCUDAAlgorithm()
+{
+ bool ok;
+
+ ok = setupGeometry();
+ ASTRA_ASSERT(ok);
+
+ ok = m_pAlgo->allocateBuffers();
+ ASTRA_ASSERT(ok);
+}
+
+
+//----------------------------------------------------------------------------------------
// Iterate
void CCudaReconstructionAlgorithm2D::run(int _iNrIterations)
{
@@ -434,13 +353,7 @@ void CCudaReconstructionAlgorithm2D::run(int _iNrIterations)
const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
if (!m_bAlgoInit) {
-
- ok = setupGeometry();
- ASTRA_ASSERT(ok);
-
- ok = m_pAlgo->allocateBuffers();
- ASTRA_ASSERT(ok);
-
+ initCUDAAlgorithm();
m_bAlgoInit = true;
}
@@ -454,10 +367,18 @@ void CCudaReconstructionAlgorithm2D::run(int _iNrIterations)
ASTRA_ASSERT(ok);
- if (m_bUseMinConstraint)
- ok &= m_pAlgo->setMinConstraint(m_fMinValue);
- if (m_bUseMaxConstraint)
- ok &= m_pAlgo->setMaxConstraint(m_fMaxValue);
+ if (m_bUseMinConstraint) {
+ bool ret = m_pAlgo->setMinConstraint(m_fMinValue);
+ if (!ret) {
+ ASTRA_WARN("This algorithm ignores MinConstraint");
+ }
+ }
+ if (m_bUseMaxConstraint) {
+ bool ret= m_pAlgo->setMaxConstraint(m_fMaxValue);
+ if (!ret) {
+ ASTRA_WARN("This algorithm ignores MaxConstraint");
+ }
+ }
ok &= m_pAlgo->iterate(_iNrIterations);
ASTRA_ASSERT(ok);
diff --git a/src/CudaRoiSelectAlgorithm.cpp b/src/CudaRoiSelectAlgorithm.cpp
index 7635c69..dfb8056 100644
--- a/src/CudaRoiSelectAlgorithm.cpp
+++ b/src/CudaRoiSelectAlgorithm.cpp
@@ -34,7 +34,6 @@ $Id$
#include "../cuda/2d/algo.h"
#include "astra/AstraObjectManager.h"
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -68,7 +67,7 @@ bool CCudaRoiSelectAlgorithm::initialize(const Config& _cfg)
// reconstruction data
XMLNode node = _cfg.self.getSingleNode("DataId");
ASTRA_CONFIG_CHECK(node, "CudaRoiSelect", "No DataId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pData = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("DataId");
diff --git a/src/CudaSartAlgorithm.cpp b/src/CudaSartAlgorithm.cpp
index 8c0c6d7..bf97224 100644
--- a/src/CudaSartAlgorithm.cpp
+++ b/src/CudaSartAlgorithm.cpp
@@ -107,7 +107,8 @@ bool CCudaSartAlgorithm::initialize(const Config& _cfg)
CC.markOptionParsed("ProjectionOrderList");
}
-
+ m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f);
+ CC.markOptionParsed("Relaxation");
return true;
}
@@ -116,20 +117,33 @@ bool CCudaSartAlgorithm::initialize(const Config& _cfg)
// Initialize - C++
bool CCudaSartAlgorithm::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
- CFloat32VolumeData2D* _pReconstruction,
- int _iGPUindex, int _iDetectorSuperSampling)
+ CFloat32VolumeData2D* _pReconstruction)
{
- m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, 1);
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction);
if (!m_bIsInitialized)
return false;
+ m_fLambda = 1.0f;
+
m_pAlgo = new astraCUDA::SART();
m_bAlgoInit = false;
return true;
}
+//----------------------------------------------------------------------------------------
+
+void CCudaSartAlgorithm::initCUDAAlgorithm()
+{
+ CCudaReconstructionAlgorithm2D::initCUDAAlgorithm();
+
+ astraCUDA::SART* pSart = dynamic_cast<astraCUDA::SART*>(m_pAlgo);
+
+ pSart->setRelaxation(m_fLambda);
+}
+
+
} // namespace astra
diff --git a/src/CudaSirtAlgorithm.cpp b/src/CudaSirtAlgorithm.cpp
index d424915..c8dc677 100644
--- a/src/CudaSirtAlgorithm.cpp
+++ b/src/CudaSirtAlgorithm.cpp
@@ -30,7 +30,6 @@ $Id$
#include "astra/CudaSirtAlgorithm.h"
-#include <boost/lexical_cast.hpp>
#include "astra/AstraObjectManager.h"
#include "../cuda/2d/sirt.h"
@@ -51,6 +50,8 @@ CCudaSirtAlgorithm::CCudaSirtAlgorithm()
m_pMinMask = 0;
m_pMaxMask = 0;
+
+ m_fLambda = 1.0f;
}
//----------------------------------------------------------------------------------------
@@ -77,16 +78,18 @@ bool CCudaSirtAlgorithm::initialize(const Config& _cfg)
// min/max masks
if (_cfg.self.hasOption("MinMaskId")) {
- int id = boost::lexical_cast<int>(_cfg.self.getOption("MinMaskId"));
+ int id = _cfg.self.getOptionInt("MinMaskId");
m_pMinMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
}
CC.markOptionParsed("MinMaskId");
if (_cfg.self.hasOption("MaxMaskId")) {
- int id = boost::lexical_cast<int>(_cfg.self.getOption("MaxMaskId"));
+ int id = _cfg.self.getOptionInt("MaxMaskId");
m_pMaxMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
}
CC.markOptionParsed("MaxMaskId");
+ m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f);
+ CC.markOptionParsed("Relaxation");
m_pAlgo = new astraCUDA::SIRT();
m_bAlgoInit = false;
@@ -98,11 +101,9 @@ bool CCudaSirtAlgorithm::initialize(const Config& _cfg)
// Initialize - C++
bool CCudaSirtAlgorithm::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
- CFloat32VolumeData2D* _pReconstruction,
- int _iGPUindex, int _iDetectorSuperSampling,
- int _iPixelSuperSampling)
+ CFloat32VolumeData2D* _pReconstruction)
{
- m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling);
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction);
if (!m_bIsInitialized)
return false;
@@ -111,41 +112,30 @@ bool CCudaSirtAlgorithm::initialize(CProjector2D* _pProjector,
m_pAlgo = new astraCUDA::SIRT();
m_bAlgoInit = false;
+ m_fLambda = 1.0f;
return true;
}
//----------------------------------------------------------------------------------------
-// Iterate
-void CCudaSirtAlgorithm::run(int _iNrIterations)
+
+void CCudaSirtAlgorithm::initCUDAAlgorithm()
{
- // check initialized
- ASTRA_ASSERT(m_bIsInitialized);
+ CCudaReconstructionAlgorithm2D::initCUDAAlgorithm();
- if (!m_bAlgoInit) {
- // We only override the initialisation step to copy the min/max masks
+ astraCUDA::SIRT* pSirt = dynamic_cast<astraCUDA::SIRT*>(m_pAlgo);
- bool ok = setupGeometry();
+ if (m_pMinMask || m_pMaxMask) {
+ const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
+ const float *pfMinMaskData = 0;
+ const float *pfMaxMaskData = 0;
+ if (m_pMinMask) pfMinMaskData = m_pMinMask->getDataConst();
+ if (m_pMaxMask) pfMaxMaskData = m_pMaxMask->getDataConst();
+ bool ok = pSirt->uploadMinMaxMasks(pfMinMaskData, pfMaxMaskData, volgeom.getGridColCount());
ASTRA_ASSERT(ok);
-
- ok = m_pAlgo->allocateBuffers();
- ASTRA_ASSERT(ok);
-
- if (m_pMinMask || m_pMaxMask) {
- const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
- astraCUDA::SIRT* pSirt = dynamic_cast<astraCUDA::SIRT*>(m_pAlgo);
- const float *pfMinMaskData = 0;
- const float *pfMaxMaskData = 0;
- if (m_pMinMask) pfMinMaskData = m_pMinMask->getDataConst();
- if (m_pMaxMask) pfMaxMaskData = m_pMaxMask->getDataConst();
- ok = pSirt->uploadMinMaxMasks(pfMinMaskData, pfMaxMaskData, volgeom.getGridColCount());
- ASTRA_ASSERT(ok);
- }
-
- m_bAlgoInit = true;
}
- CCudaReconstructionAlgorithm2D::run(_iNrIterations);
+ pSirt->setRelaxation(m_fLambda);
}
diff --git a/src/CudaSirtAlgorithm3D.cpp b/src/CudaSirtAlgorithm3D.cpp
index 5ad131b..c819f8e 100644
--- a/src/CudaSirtAlgorithm3D.cpp
+++ b/src/CudaSirtAlgorithm3D.cpp
@@ -28,14 +28,15 @@ $Id$
#include "astra/CudaSirtAlgorithm3D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/ConeProjectionGeometry3D.h"
#include "astra/ParallelProjectionGeometry3D.h"
#include "astra/ParallelVecProjectionGeometry3D.h"
#include "astra/ConeVecProjectionGeometry3D.h"
+#include "astra/CudaProjector3D.h"
+
+#include "astra/Logging.h"
#include "../cuda/3d/astra3d.h"
@@ -55,6 +56,7 @@ CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D()
m_iGPUIndex = -1;
m_iVoxelSuperSampling = 1;
m_iDetectorSuperSampling = 1;
+ m_fLambda = 1.0f;
}
//----------------------------------------------------------------------------------------
@@ -89,7 +91,27 @@ bool CCudaSirtAlgorithm3D::_check()
return true;
}
-//---------------------------------------------------------------------------------------
+//----------------------------------------------------------------------------------------
+void CCudaSirtAlgorithm3D::initializeFromProjector()
+{
+ m_iVoxelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+ m_iGPUIndex = -1;
+
+ CCudaProjector3D* pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ if (!pCudaProjector) {
+ if (m_pProjector) {
+ ASTRA_WARN("non-CUDA Projector3D passed to SIRT3D_CUDA");
+ }
+ } else {
+ m_iVoxelSuperSampling = pCudaProjector->getVoxelSuperSampling();
+ m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
+ m_iGPUIndex = pCudaProjector->getGPUIndex();
+ }
+
+}
+
+//--------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg)
{
@@ -107,12 +129,23 @@ bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg)
return false;
}
- m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
- CC.markOptionParsed("GPUindex");
- m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", 1);
- CC.markOptionParsed("DetectorSuperSampling");
- m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", 1);
+ m_fLambda = _cfg.self.getOptionNumerical("Relaxation");
+
+ initializeFromProjector();
+
+ // Deprecated options
+ m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", m_iVoxelSuperSampling);
+ m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", m_iDetectorSuperSampling);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", m_iGPUIndex);
+ m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex);
+
CC.markOptionParsed("VoxelSuperSampling");
+ CC.markOptionParsed("DetectorSuperSampling");
+ CC.markOptionParsed("GPUIndex");
+ if (!_cfg.self.hasOption("GPUIndex"))
+ CC.markOptionParsed("GPUindex");
+
+
m_pSirt = new AstraSIRT3d();
@@ -135,6 +168,8 @@ bool CCudaSirtAlgorithm3D::initialize(CProjector3D* _pProjector,
clear();
}
+ m_fLambda = 1.0f;
+
// required classes
m_pProjector = _pProjector;
m_pSinogram = _pSinogram;
@@ -172,10 +207,6 @@ void CCudaSirtAlgorithm3D::run(int _iNrIterations)
ASTRA_ASSERT(m_bIsInitialized);
const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry();
- const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
- const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
- const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
- const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry();
bool ok = true;
@@ -184,39 +215,7 @@ void CCudaSirtAlgorithm3D::run(int _iNrIterations)
ok &= m_pSirt->setGPUIndex(m_iGPUIndex);
- ok &= m_pSirt->setReconstructionGeometry(volgeom.getGridColCount(),
- volgeom.getGridRowCount(),
- volgeom.getGridSliceCount());
-
- if (conegeom) {
- ok &= m_pSirt->setConeGeometry(conegeom->getProjectionCount(),
- conegeom->getDetectorColCount(),
- conegeom->getDetectorRowCount(),
- conegeom->getOriginSourceDistance(),
- conegeom->getOriginDetectorDistance(),
- conegeom->getDetectorSpacingX(),
- conegeom->getDetectorSpacingY(),
- conegeom->getProjectionAngles());
- } else if (par3dgeom) {
- ok &= m_pSirt->setPar3DGeometry(par3dgeom->getProjectionCount(),
- par3dgeom->getDetectorColCount(),
- par3dgeom->getDetectorRowCount(),
- par3dgeom->getDetectorSpacingX(),
- par3dgeom->getDetectorSpacingY(),
- par3dgeom->getProjectionAngles());
- } else if (parvec3dgeom) {
- ok &= m_pSirt->setPar3DGeometry(parvec3dgeom->getProjectionCount(),
- parvec3dgeom->getDetectorColCount(),
- parvec3dgeom->getDetectorRowCount(),
- parvec3dgeom->getProjectionVectors());
- } else if (conevec3dgeom) {
- ok &= m_pSirt->setConeGeometry(conevec3dgeom->getProjectionCount(),
- conevec3dgeom->getDetectorColCount(),
- conevec3dgeom->getDetectorRowCount(),
- conevec3dgeom->getProjectionVectors());
- } else {
- ASTRA_ASSERT(false);
- }
+ ok &= m_pSirt->setGeometry(&volgeom, projgeom);
ok &= m_pSirt->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling);
@@ -231,6 +230,8 @@ void CCudaSirtAlgorithm3D::run(int _iNrIterations)
ASTRA_ASSERT(ok);
+ m_pSirt->setRelaxation(m_fLambda);
+
m_bAstraSIRTInit = true;
}
diff --git a/src/FanFlatBeamLineKernelProjector2D.cpp b/src/FanFlatBeamLineKernelProjector2D.cpp
index 0681715..fd4195b 100644
--- a/src/FanFlatBeamLineKernelProjector2D.cpp
+++ b/src/FanFlatBeamLineKernelProjector2D.cpp
@@ -30,7 +30,6 @@ $Id$
#include <cmath>
#include <cstring>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
diff --git a/src/FanFlatBeamStripKernelProjector2D.cpp b/src/FanFlatBeamStripKernelProjector2D.cpp
index e94d3da..b48beab 100644
--- a/src/FanFlatBeamStripKernelProjector2D.cpp
+++ b/src/FanFlatBeamStripKernelProjector2D.cpp
@@ -29,7 +29,6 @@ $Id$
#include "astra/FanFlatBeamStripKernelProjector2D.h"
#include <cmath>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
diff --git a/src/FanFlatProjectionGeometry2D.cpp b/src/FanFlatProjectionGeometry2D.cpp
index 91b9578..3aab582 100644
--- a/src/FanFlatProjectionGeometry2D.cpp
+++ b/src/FanFlatProjectionGeometry2D.cpp
@@ -30,7 +30,6 @@ $Id$
#include <cstring>
#include <sstream>
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -136,13 +135,13 @@ bool CFanFlatProjectionGeometry2D::initialize(const Config& _cfg)
// Required: DistanceOriginDetector
XMLNode node = _cfg.self.getSingleNode("DistanceOriginDetector");
ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginDetector tag specified.");
- m_fOriginDetectorDistance = boost::lexical_cast<float32>(node.getContent());
+ m_fOriginDetectorDistance = node.getContentNumerical();
CC.markNodeParsed("DistanceOriginDetector");
// Required: DetectorOriginSource
node = _cfg.self.getSingleNode("DistanceOriginSource");
ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginSource tag specified.");
- m_fOriginSourceDistance = boost::lexical_cast<float32>(node.getContent());
+ m_fOriginSourceDistance = node.getContentNumerical();
CC.markNodeParsed("DistanceOriginSource");
// success
diff --git a/src/FanFlatVecProjectionGeometry2D.cpp b/src/FanFlatVecProjectionGeometry2D.cpp
index 4104379..0b76fc5 100644
--- a/src/FanFlatVecProjectionGeometry2D.cpp
+++ b/src/FanFlatVecProjectionGeometry2D.cpp
@@ -30,7 +30,6 @@ $Id$
#include <cstring>
#include <sstream>
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -125,7 +124,7 @@ bool CFanFlatVecProjectionGeometry2D::initialize(const Config& _cfg)
// Required: DetectorCount
node = _cfg.self.getSingleNode("DetectorCount");
ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No DetectorRowCount tag specified.");
- m_iDetectorCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorCount = node.getContentInt();
CC.markNodeParsed("DetectorCount");
// Required: Vectors
@@ -235,12 +234,12 @@ Config* CFanFlatVecProjectionGeometry2D::getConfiguration() const
std::string vectors = "";
for (int i = 0; i < m_iProjectionAngleCount; ++i) {
SFanProjection& p = m_pProjectionAngles[i];
- vectors += boost::lexical_cast<string>(p.fSrcX) + ",";
- vectors += boost::lexical_cast<string>(p.fSrcY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSX + 0.5f * m_iDetectorCount * p.fDetUX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSY + 0.5f * m_iDetectorCount * p.fDetUY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUY);
+ vectors += StringUtil::toString(p.fSrcX) + ",";
+ vectors += StringUtil::toString(p.fSrcY) + ",";
+ vectors += StringUtil::toString(p.fDetSX + 0.5f * m_iDetectorCount * p.fDetUX) + ",";
+ vectors += StringUtil::toString(p.fDetSY + 0.5f * m_iDetectorCount * p.fDetUY) + ",";
+ vectors += StringUtil::toString(p.fDetUX) + ",";
+ vectors += StringUtil::toString(p.fDetUY);
if (i < m_iProjectionAngleCount-1) vectors += ';';
}
cfg->self.addChildNode("Vectors", vectors);
diff --git a/src/FilteredBackProjectionAlgorithm.cpp b/src/FilteredBackProjectionAlgorithm.cpp
index f494d22..70462f7 100644
--- a/src/FilteredBackProjectionAlgorithm.cpp
+++ b/src/FilteredBackProjectionAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/FilteredBackProjectionAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include <iostream>
#include <iomanip>
#include <math.h>
@@ -96,19 +94,19 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
// projector
XMLNode node = _cfg.self.getSingleNode("ProjectorId");
ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectorId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pProjector = CProjector2DManager::getSingleton().get(id);
// sinogram data
node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
// volume data
node = _cfg.self.getSingleNode("ReconstructionDataId");
ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ReconstructionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
node = _cfg.self.getSingleNode("ProjectionIndex");
@@ -119,12 +117,10 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
int angleCount = projectionIndex.size();
int detectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount();
+ // TODO: There is no need to allocate this. Better just
+ // create the CFloat32ProjectionData2D object directly, and use its
+ // memory.
float32 * sinogramData2D = new float32[angleCount* detectorCount];
- float32 ** sinogramData = new float32*[angleCount];
- for (int i = 0; i < angleCount; i++)
- {
- sinogramData[i] = &(sinogramData2D[i * detectorCount]);
- }
float32 * projectionAngles = new float32[angleCount];
float32 detectorWidth = m_pProjector->getProjectionGeometry()->getDetectorWidth();
@@ -132,6 +128,8 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
for (int i = 0; i < angleCount; i ++) {
if (projectionIndex[i] > m_pProjector->getProjectionGeometry()->getProjectionAngleCount() -1 )
{
+ delete[] sinogramData2D;
+ delete[] projectionAngles;
ASTRA_ERROR("Invalid Projection Index");
return false;
} else {
@@ -141,7 +139,6 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
{
sinogramData2D[i*detectorCount+ iDetector] = m_pSinogram->getData2D()[orgIndex][iDetector];
}
-// sinogramData[i] = m_pSinogram->getSingleProjectionData(projectionIndex[i]);
projectionAngles[i] = m_pProjector->getProjectionGeometry()->getProjectionAngle((int)projectionIndex[i] );
}
@@ -150,6 +147,9 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
CParallelProjectionGeometry2D * pg = new CParallelProjectionGeometry2D(angleCount, detectorCount,detectorWidth,projectionAngles);
m_pProjector = new CParallelBeamLineKernelProjector2D(pg,m_pReconstruction->getGeometry());
m_pSinogram = new CFloat32ProjectionData2D(pg, sinogramData2D);
+
+ delete[] sinogramData2D;
+ delete[] projectionAngles;
}
// TODO: check that the angles are linearly spaced between 0 and pi
@@ -274,60 +274,57 @@ void CFilteredBackProjectionAlgorithm::performFiltering(CFloat32ProjectionData2D
filter[iDetector] = (2.0f * (zpDetector - iDetector)) / zpDetector;
- float32* pfRe = new float32[iAngleCount * zpDetector];
- float32* pfIm = new float32[iAngleCount * zpDetector];
+ float32* pf = new float32[2 * iAngleCount * zpDetector];
+ int *ip = new int[int(2+sqrt((float)zpDetector)+1)];
+ ip[0]=0;
+ float32 *w = new float32[zpDetector/2];
// Copy and zero-pad data
for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
- float32* pfReRow = pfRe + iAngle * zpDetector;
- float32* pfImRow = pfIm + iAngle * zpDetector;
+ float32* pfRow = pf + iAngle * 2 * zpDetector;
float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount;
for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector) {
- pfReRow[iDetector] = pfDataRow[iDetector];
- pfImRow[iDetector] = 0.0f;
+ pfRow[2*iDetector] = pfDataRow[iDetector];
+ pfRow[2*iDetector+1] = 0.0f;
}
for (int iDetector = iDetectorCount; iDetector < zpDetector; ++iDetector) {
- pfReRow[iDetector] = 0.0f;
- pfImRow[iDetector] = 0.0f;
+ pfRow[2*iDetector] = 0.0f;
+ pfRow[2*iDetector+1] = 0.0f;
}
}
// in-place FFT
for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
- float32* pfReRow = pfRe + iAngle * zpDetector;
- float32* pfImRow = pfIm + iAngle * zpDetector;
-
- fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, false);
+ float32* pfRow = pf + iAngle * 2 * zpDetector;
+ cdft(2*zpDetector, -1, pfRow, ip, w);
}
// Filter
for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
- float32* pfReRow = pfRe + iAngle * zpDetector;
- float32* pfImRow = pfIm + iAngle * zpDetector;
+ float32* pfRow = pf + iAngle * 2 * zpDetector;
for (int iDetector = 0; iDetector < zpDetector; ++iDetector) {
- pfReRow[iDetector] *= filter[iDetector];
- pfImRow[iDetector] *= filter[iDetector];
+ pfRow[2*iDetector] *= filter[iDetector];
+ pfRow[2*iDetector+1] *= filter[iDetector];
}
}
// in-place inverse FFT
for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
- float32* pfReRow = pfRe + iAngle * zpDetector;
- float32* pfImRow = pfIm + iAngle * zpDetector;
-
- fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, true);
+ float32* pfRow = pf + iAngle * 2 * zpDetector;
+ cdft(2*zpDetector, 1, pfRow, ip, w);
}
// Copy data back
for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
- float32* pfReRow = pfRe + iAngle * zpDetector;
+ float32* pfRow = pf + iAngle * 2 * zpDetector;
float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount;
for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector)
- pfDataRow[iDetector] = pfReRow[iDetector];
+ pfDataRow[iDetector] = pfRow[2*iDetector] / zpDetector;
}
- delete[] pfRe;
- delete[] pfIm;
+ delete[] pf;
+ delete[] w;
+ delete[] ip;
delete[] filter;
}
diff --git a/src/Float32ProjectionData3D.cpp b/src/Float32ProjectionData3D.cpp
index 2bd0447..680ad55 100644
--- a/src/Float32ProjectionData3D.cpp
+++ b/src/Float32ProjectionData3D.cpp
@@ -53,13 +53,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const CFloat32Pro
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
#ifdef _DEBUG
CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
- int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
- int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();
+ int iDataProjectionDetectorCount = pDataGeometry->getDetectorTotCount();
ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
- ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
+ ASTRA_ASSERT(iDetectorCount == iDataProjectionDetectorCount);
#endif
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
@@ -67,7 +67,7 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const CFloat32Pro
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
@@ -91,13 +91,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const CFloat32Pro
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
#ifdef _DEBUG
CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
- int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
- int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();
+ int iDataProjectionDetectorCount = pDataGeometry->getDetectorTotCount();
ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
- ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
+ ASTRA_ASSERT(iDetectorCount == iDataProjectionDetectorCount);
#endif
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
@@ -105,7 +105,7 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const CFloat32Pro
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
@@ -129,13 +129,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const CFloat32Pro
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
#ifdef _DEBUG
CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
- int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
- int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();
+ int iDataProjectionDetectorCount = pDataGeometry->getDetectorTotCount();
ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
- ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
+ ASTRA_ASSERT(iDetectorCount == iDataProjectionDetectorCount);
#endif
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
@@ -143,7 +143,7 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const CFloat32Pro
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
@@ -167,12 +167,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const float32& _f
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
{
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
@@ -194,12 +195,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator/=(const float32& _f
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
{
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
@@ -221,12 +223,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const float32& _f
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
{
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
@@ -248,12 +251,13 @@ CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const float32& _f
CProjectionGeometry3D * pThisGeometry = getGeometry();
int iProjectionCount = pThisGeometry->getProjectionCount();
+ int iDetectorCount = pThisGeometry->getDetectorTotCount();
for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
{
CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
- for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
{
float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
diff --git a/src/Float32VolumeData3DMemory.cpp b/src/Float32VolumeData3DMemory.cpp
index af45cb9..14adb1a 100644
--- a/src/Float32VolumeData3DMemory.cpp
+++ b/src/Float32VolumeData3DMemory.cpp
@@ -136,7 +136,6 @@ CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceZ(int _iSliceIndex)
CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom);
// copy data
- int iSliceCount = m_pGeometry->getGridSliceCount();
float * pfTargetData = res->getData();
for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++)
{
diff --git a/src/ForwardProjectionAlgorithm.cpp b/src/ForwardProjectionAlgorithm.cpp
index f356824..dcf5790 100644
--- a/src/ForwardProjectionAlgorithm.cpp
+++ b/src/ForwardProjectionAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ForwardProjectionAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/DataProjectorPolicies.h"
@@ -128,32 +126,32 @@ bool CForwardProjectionAlgorithm::initialize(const Config& _cfg)
// projector
XMLNode node = _cfg.self.getSingleNode("ProjectorId");
ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectorId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pProjector = CProjector2DManager::getSingleton().get(id);
// sinogram data
node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
// volume data
node = _cfg.self.getSingleNode("VolumeDataId");
ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No VolumeDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
// volume mask
if (_cfg.self.hasOption("VolumeMaskId")) {
m_bUseVolumeMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("VolumeMaskId"));
+ id = _cfg.self.getOptionInt("VolumeMaskId");
m_pVolumeMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
}
// sino mask
if (_cfg.self.hasOption("SinogramMaskId")) {
m_bUseSinogramMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("SinogramMaskId"));
+ id = _cfg.self.getOptionInt("SinogramMaskId");
m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
}
diff --git a/src/Fourier.cpp b/src/Fourier.cpp
index 584b633..c33f7bd 100644
--- a/src/Fourier.cpp
+++ b/src/Fourier.cpp
@@ -27,207 +27,3273 @@ $Id$
*/
#include "astra/Fourier.h"
+#include <cmath>
namespace astra {
+ /*
+Copyright Takuya OOURA, 1996-2001
-void discreteFourierTransform1D(unsigned int iLength,
- const float32* pfRealIn,
- const float32* pfImaginaryIn,
- float32* pfRealOut,
- float32* pfImaginaryOut,
- unsigned int iStrideIn,
- unsigned int iStrideOut,
- bool inverse)
-{
- for (unsigned int w = 0; w < iLength; w++)
- {
- pfRealOut[iStrideOut*w] = pfImaginaryOut[iStrideOut*w] = 0;
- for (unsigned int y = 0; y < iLength; y++)
- {
- float32 a = 2 * PI * w * y / float32(iLength);
- if (!inverse)
- a = -a;
- float32 ca = cos(a);
- float32 sa = sin(a);
- pfRealOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * ca - pfImaginaryIn[iStrideIn*y] * sa;
- pfImaginaryOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * sa + pfImaginaryIn[iStrideIn*y] * ca;
- }
- }
-
- if (inverse) {
- for (unsigned int x = 0; x < iLength; ++x) {
- pfRealOut[iStrideOut*x] /= iLength;
- pfImaginaryOut[iStrideOut*x] /= iLength;
- }
- }
-}
-
-void discreteFourierTransform2D(unsigned int iHeight, unsigned int iWidth,
- const float32* pfRealIn,
- const float32* pfImaginaryIn,
- float32* pfRealOut,
- float32* pfImaginaryOut,
- bool inverse)
-{
- float32* reTemp = new float32[iWidth * iHeight];
- float32* imTemp = new float32[iWidth * iHeight];
-
- //calculate the fourier transform of the columns
- for (unsigned int x = 0; x < iWidth; x++)
- {
- discreteFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x,
- reTemp+x, imTemp+x,
- iWidth, iWidth, inverse);
- }
-
- //calculate the fourier transform of the rows
- for(unsigned int y = 0; y < iHeight; y++)
- {
- discreteFourierTransform1D(iWidth,
- reTemp+y*iWidth,
- imTemp+y*iWidth,
- pfRealOut+y*iWidth,
- pfImaginaryOut+y*iWidth,
- 1, 1, inverse);
- }
-
- delete[] reTemp;
- delete[] imTemp;
-}
-
-/** permute the entries from pfDataIn into pfDataOut to prepare for an
- * in-place FFT. pfDataIn may be equal to pfDataOut.
- */
-static void bitReverse(unsigned int iLength,
- const float32* pfDataIn, float32* pfDataOut,
- unsigned int iStrideShiftIn,
- unsigned int iStrideShiftOut)
-{
- if (pfDataIn == pfDataOut) {
- assert(iStrideShiftIn == iStrideShiftOut);
- float32 t;
- unsigned int j = 0;
- for(unsigned int i = 0; i < iLength - 1; i++) {
- if (i < j) {
- t = pfDataOut[i<<iStrideShiftOut];
- pfDataOut[i<<iStrideShiftOut] = pfDataOut[j<<iStrideShiftOut];
- pfDataOut[j<<iStrideShiftOut] = t;
- }
- unsigned int k = iLength / 2;
- while (k <= j) {
- j -= k;
- k /= 2;
- }
- j += k;
- }
- } else {
- unsigned int j = 0;
- for(unsigned int i = 0; i < iLength - 1; i++) {
- pfDataOut[i<<iStrideShiftOut] = pfDataIn[j<<iStrideShiftIn];
- unsigned int k = iLength / 2;
- while (k <= j) {
- j -= k;
- k /= 2;
- }
- j += k;
- }
- pfDataOut[(iLength-1)<<iStrideShiftOut] = pfDataIn[(iLength-1)<<iStrideShiftOut];
- }
-}
-
-static unsigned int log2(unsigned int n)
-{
- unsigned int l = 0;
- while (n > 1) {
- n /= 2;
- ++l;
- }
- return l;
-}
-
-/** perform 1D FFT. iLength, iStrideIn, iStrideOut must be powers of two. */
-void fastTwoPowerFourierTransform1D(unsigned int iLength,
- const float32* pfRealIn,
- const float32* pfImaginaryIn,
- float32* pfRealOut,
- float32* pfImaginaryOut,
- unsigned int iStrideIn,
- unsigned int iStrideOut,
- bool inverse)
-{
- unsigned int iStrideShiftIn = log2(iStrideIn);
- unsigned int iStrideShiftOut = log2(iStrideOut);
- unsigned int iLogLength = log2(iLength);
-
- bitReverse(iLength, pfRealIn, pfRealOut, iStrideShiftIn, iStrideShiftOut);
- bitReverse(iLength, pfImaginaryIn, pfImaginaryOut, iStrideShiftIn, iStrideShiftOut);
-
- float32 ca = -1.0;
- float32 sa = 0.0;
- unsigned int l1 = 1, l2 = 1;
- for(unsigned int l=0; l < iLogLength; ++l)
- {
- l1 = l2;
- l2 *= 2;
- float32 u1 = 1.0;
- float32 u2 = 0.0;
- for(unsigned int j = 0; j < l1; j++)
- {
- for(unsigned int i = j; i < iLength; i += l2)
- {
- unsigned int i1 = i + l1;
- float32 t1 = u1 * pfRealOut[i1<<iStrideShiftOut] - u2 * pfImaginaryOut[i1<<iStrideShiftOut];
- float32 t2 = u1 * pfImaginaryOut[i1<<iStrideShiftOut] + u2 * pfRealOut[i1<<iStrideShiftOut];
- pfRealOut[i1<<iStrideShiftOut] = pfRealOut[i<<iStrideShiftOut] - t1;
- pfImaginaryOut[i1<<iStrideShiftOut] = pfImaginaryOut[i<<iStrideShiftOut] - t2;
- pfRealOut[i<<iStrideShiftOut] += t1;
- pfImaginaryOut[i<<iStrideShiftOut] += t2;
- }
- float32 z = u1 * ca - u2 * sa;
- u2 = u1 * sa + u2 * ca;
- u1 = z;
- }
- sa = sqrt((1.0 - ca) / 2.0);
- if (!inverse)
- sa = -sa;
- ca = sqrt((1.0 + ca) / 2.0);
- }
-
- if (inverse) {
- for (unsigned int i = 0; i < iLength; ++i) {
- pfRealOut[i<<iStrideShiftOut] /= iLength;
- pfImaginaryOut[i<<iStrideShiftOut] /= iLength;
- }
- }
-}
-
-void fastTwoPowerFourierTransform2D(unsigned int iHeight,
- unsigned int iWidth,
- const float32* pfRealIn,
- const float32* pfImaginaryIn,
- float32* pfRealOut,
- float32* pfImaginaryOut,
- bool inverse)
-{
- //calculate the fourier transform of the columns
- for (unsigned int x = 0; x < iWidth; x++)
- {
- fastTwoPowerFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x,
- pfRealOut+x, pfImaginaryOut+x,
- iWidth, iWidth, inverse);
- }
-
- //calculate the fourier transform of the rows
- for (unsigned int y = 0; y < iHeight; y++)
- {
- fastTwoPowerFourierTransform1D(iWidth,
- pfRealOut+y*iWidth,
- pfImaginaryOut+y*iWidth,
- pfRealOut+y*iWidth,
- pfImaginaryOut+y*iWidth,
- 1, 1, inverse);
- }
+You may use, copy, modify and distribute this code for any purpose (include commercial use) and without fee.
+
+Source: http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
+
+Fast Fourier/Cosine/Sine Transform
+ dimension :one
+ data length :power of 2
+ decimation :frequency
+ radix :split-radix
+ data :inplace
+ table :use
+functions
+ cdft: Complex Discrete Fourier Transform
+ rdft: Real Discrete Fourier Transform
+ ddct: Discrete Cosine Transform
+ ddst: Discrete Sine Transform
+ dfct: Cosine Transform of RDFT (Real Symmetric DFT)
+ dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
+function prototypes
+ void cdft(int, int, float32 *, int *, float32 *);
+ void rdft(int, int, float32 *, int *, float32 *);
+ void ddct(int, int, float32 *, int *, float32 *);
+ void ddst(int, int, float32 *, int *, float32 *);
+ void dfct(int, float32 *, float32 *, int *, float32 *);
+ void dfst(int, float32 *, float32 *, int *, float32 *);
+macro definitions
+ USE_CDFT_PTHREADS : default=not defined
+ CDFT_THREADS_BEGIN_N : must be >= 512, default=8192
+ CDFT_4THREADS_BEGIN_N : must be >= 512, default=65536
+ USE_CDFT_WINTHREADS : default=not defined
+ CDFT_THREADS_BEGIN_N : must be >= 512, default=32768
+ CDFT_4THREADS_BEGIN_N : must be >= 512, default=524288
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+ [definition]
+ <case1>
+ X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
+ <case2>
+ X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
+ (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ cdft(2*n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ cdft(2*n, -1, a, ip, w);
+ [parameters]
+ 2*n :data length (int)
+ n >= 1, n = power of 2
+ a[0...2*n-1] :input/output data (float32 *)
+ input data
+ a[2*j] = Re(x[j]),
+ a[2*j+1] = Im(x[j]), 0<=j<n
+ output data
+ a[2*k] = Re(X[k]),
+ a[2*k+1] = Im(X[k]), 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (float32 *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ cdft(2*n, -1, a, ip, w);
+ is
+ cdft(2*n, 1, a, ip, w);
+ for (j = 0; j <= 2 * n - 1; j++) {
+ a[j] *= 1.0 / n;
+ }
+ .
+
+
+-------- Real DFT / Inverse of Real DFT --------
+ [definition]
+ <case1> RDFT
+ R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
+ I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2
+ <case2> IRDFT (excluding scale)
+ a[k] = (R[0] + R[n/2]*cos(pi*k))/2 +
+ sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) +
+ sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ rdft(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ rdft(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float32 *)
+ <case1>
+ output data
+ a[2*k] = R[k], 0<=k<n/2
+ a[2*k+1] = I[k], 0<k<n/2
+ a[1] = R[n/2]
+ <case2>
+ input data
+ a[2*j] = R[j], 0<=j<n/2
+ a[2*j+1] = I[j], 0<j<n/2
+ a[1] = R[n/2]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (float32 *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ rdft(n, 1, a, ip, w);
+ is
+ rdft(n, -1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
+ [definition]
+ <case1> IDCT (excluding scale)
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DCT
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddct(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddct(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float32 *)
+ output data
+ a[k] = C[k], 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (float32 *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddct(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddct(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DST (Discrete Sine Transform) / Inverse of DST --------
+ [definition]
+ <case1> IDST (excluding scale)
+ S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DST
+ S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddst(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddst(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float32 *)
+ <case1>
+ input data
+ a[j] = A[j], 0<j<n
+ a[0] = A[n]
+ output data
+ a[k] = S[k], 0<=k<n
+ <case2>
+ output data
+ a[k] = S[k], 0<k<n
+ a[0] = S[n]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (float32 *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddst(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddst(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Cosine Transform of RDFT (Real Symmetric DFT) --------
+ [definition]
+ C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
+ [usage]
+ ip[0] = 0; // first time only
+ dfct(n, a, t, ip, w);
+ [parameters]
+ n :data length - 1 (int)
+ n >= 2, n = power of 2
+ a[0...n] :input/output data (float32 *)
+ output data
+ a[k] = C[k], 0<=k<=n
+ t[0...n/2] :work area (float32 *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (float32 *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ is
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ for (j = 0; j <= n; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
+ [definition]
+ S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n
+ [usage]
+ ip[0] = 0; // first time only
+ dfst(n, a, t, ip, w);
+ [parameters]
+ n :data length + 1 (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float32 *)
+ output data
+ a[k] = S[k], 0<k<n
+ (a[0] is used for work area)
+ t[0...n/2-1] :work area (float32 *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (float32 *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ dfst(n, a, t, ip, w);
+ is
+ dfst(n, a, t, ip, w);
+ for (j = 1; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+Appendix :
+ The cos/sin table is recalculated when the larger table required.
+ w[] and ip[] are compatible with all routines.
+*/
+
+
+static int cfttree(int n, int j, int k, float32 *a, int nw, float32 *w);
+static void bitrv208(float32 *a);
+static void bitrv208neg(float32 *a);
+static void bitrv216(float32 *a);
+static void bitrv216neg(float32 *a);
+static void bitrv2conj(int n, int *ip, float32 *a);
+static void bitrv2(int n, int *ip, float32 *a);
+static void cftb040(float32 *a);
+static void cftb1st(int n, float32 *a, float32 *w);
+static void cftbsub(int n, float32 *a, int *ip, int nw, float32 *w);
+static void cftf040(float32 *a);
+static void cftf081(float32 *a, float32 *w);
+static void cftf082(float32 *a, float32 *w);
+static void cftf161(float32 *a, float32 *w);
+static void cftf162(float32 *a, float32 *w);
+static void cftf1st(int n, float32 *a, float32 *w);
+static void cftfsub(int n, float32 *a, int *ip, int nw, float32 *w);
+static void cftfx41(int n, float32 *a, int nw, float32 *w);
+static void cftleaf(int n, int isplt, float32 *a, int nw, float32 *w);
+static void cftmdl1(int n, float32 *a, float32 *w);
+static void cftmdl2(int n, float32 *a, float32 *w);
+static void *cftrec1_th(void *p);
+static void *cftrec2_th(void *p);
+static void cftrec4(int n, float32 *a, int nw, float32 *w);
+static void cftx020(float32 *a);
+static void dctsub(int n, float32 *a, int nc, float32 *c);
+static void dstsub(int n, float32 *a, int nc, float32 *c);
+static void makect(int nc, int *ip, float32 *c);
+static void makeipt(int nw, int *ip);
+static void makewt(int nw, int *ip, float32 *w);
+static void rftbsub(int n, float32 *a, int nc, float32 *c);
+static void rftfsub(int n, float32 *a, int nc, float32 *c);
+#ifdef USE_CDFT_THREADS
+static void cftrec4_th(int n, float32 *a, int nw, float32 *w);
+#endif /* USE_CDFT_THREADS */
+
+
+_AstraExport void cdft(int n, int isgn, float32 *a, int *ip, float32 *w)
+{
+ int nw;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ if (isgn >= 0) {
+ cftfsub(n, a, ip, nw, w);
+ } else {
+ cftbsub(n, a, ip, nw, w);
+ }
+}
+
+
+_AstraExport void rdft(int n, int isgn, float32 *a, int *ip, float32 *w)
+{
+ int nw, nc;
+ float32 xi;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 2)) {
+ nc = n >> 2;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, w);
+ }
+ xi = a[0] - a[1];
+ a[0] += a[1];
+ a[1] = xi;
+ } else {
+ a[1] = 0.5 * (a[0] - a[1]);
+ a[0] -= a[1];
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+}
+
+
+_AstraExport void ddct(int n, int isgn, float32 *a, int *ip, float32 *w)
+{
+ int j, nw, nc;
+ float32 xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = a[j] - a[j - 1];
+ a[j] += a[j - 1];
+ }
+ a[1] = a[0] - xr;
+ a[0] += xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+ dctsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = a[j] - a[j + 1];
+ a[j] += a[j + 1];
+ }
+ a[n - 1] = xr;
+ }
+}
+
+
+_AstraExport void ddst(int n, int isgn, float32 *a, int *ip, float32 *w)
+{
+ int j, nw, nc;
+ float32 xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = -a[j] - a[j - 1];
+ a[j] -= a[j - 1];
+ }
+ a[1] = a[0] + xr;
+ a[0] -= xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+ dstsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = -a[j] - a[j + 1];
+ a[j] -= a[j + 1];
+ }
+ a[n - 1] = -xr;
+ }
+}
+
+
+_AstraExport void dfct(int n, float32 *a, float32 *t, int *ip, float32 *w)
+{
+ int j, k, l, m, mh, nw, nc;
+ float32 xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ m = n >> 1;
+ yi = a[m];
+ xi = a[0] + a[n];
+ a[0] -= a[n];
+ t[0] = xi - yi;
+ t[m] = xi + yi;
+ if (n > 2) {
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] - a[n - j];
+ xi = a[j] + a[n - j];
+ yr = a[k] - a[n - k];
+ yi = a[k] + a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi - yi;
+ t[k] = xi + yi;
+ }
+ t[mh] = a[mh] + a[n - mh];
+ a[mh] -= a[n - mh];
+ dctsub(m, a, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, a, ip, nw, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, ip, nw, w);
+ }
+ a[n - 1] = a[0] - a[1];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] + a[j + 1];
+ a[2 * j - 1] = a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dctsub(m, t, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, t, ip, nw, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, ip, nw, w);
+ }
+ a[n - l] = t[0] - t[1];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = t[j] - t[j + 1];
+ a[k + l] = t[j] + t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 0; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] - t[m + j];
+ t[k] = t[m + k] + t[m + j];
+ }
+ t[mh] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ a[n] = t[2] - t[1];
+ a[0] = t[2] + t[1];
+ } else {
+ a[1] = a[0];
+ a[2] = t[0];
+ a[0] = t[1];
+ }
+}
+
+
+_AstraExport void dfst(int n, float32 *a, float32 *t, int *ip, float32 *w)
+{
+ int j, k, l, m, mh, nw, nc;
+ float32 xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ if (n > 2) {
+ m = n >> 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] + a[n - j];
+ xi = a[j] - a[n - j];
+ yr = a[k] + a[n - k];
+ yi = a[k] - a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi + yi;
+ t[k] = xi - yi;
+ }
+ t[0] = a[mh] - a[n - mh];
+ a[mh] += a[n - mh];
+ a[0] = a[m];
+ dstsub(m, a, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, a, ip, nw, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, ip, nw, w);
+ }
+ a[n - 1] = a[1] - a[0];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] - a[j + 1];
+ a[2 * j - 1] = -a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dstsub(m, t, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, t, ip, nw, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, ip, nw, w);
+ }
+ a[n - l] = t[1] - t[0];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = -t[j] - t[j + 1];
+ a[k + l] = t[j] - t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] + t[m + j];
+ t[k] = t[m + k] - t[m + j];
+ }
+ t[0] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ }
+ a[0] = 0;
+}
+
+
+/* -------- initializing routines -------- */
+
+static void makewt(int nw, int *ip, float32 *w)
+{
+ int j, nwh, nw0, nw1;
+ float32 delta, wn4r, wk1r, wk1i, wk3r, wk3i;
+
+ ip[0] = nw;
+ ip[1] = 1;
+ if (nw > 2) {
+ nwh = nw >> 1;
+ delta = atan(1.0) / nwh;
+ wn4r = cos(delta * nwh);
+ w[0] = 1;
+ w[1] = wn4r;
+ if (nwh == 4) {
+ w[2] = cos(delta * 2);
+ w[3] = sin(delta * 2);
+ } else if (nwh > 4) {
+ makeipt(nw, ip);
+ w[2] = 0.5 / cos(delta * 2);
+ w[3] = 0.5 / cos(delta * 6);
+ for (j = 4; j < nwh; j += 4) {
+ w[j] = cos(delta * j);
+ w[j + 1] = sin(delta * j);
+ w[j + 2] = cos(3 * delta * j);
+ w[j + 3] = -sin(3 * delta * j);
+ }
+ }
+ nw0 = 0;
+ while (nwh > 2) {
+ nw1 = nw0 + nwh;
+ nwh >>= 1;
+ w[nw1] = 1;
+ w[nw1 + 1] = wn4r;
+ if (nwh == 4) {
+ wk1r = w[nw0 + 4];
+ wk1i = w[nw0 + 5];
+ w[nw1 + 2] = wk1r;
+ w[nw1 + 3] = wk1i;
+ } else if (nwh > 4) {
+ wk1r = w[nw0 + 4];
+ wk3r = w[nw0 + 6];
+ w[nw1 + 2] = 0.5 / wk1r;
+ w[nw1 + 3] = 0.5 / wk3r;
+ for (j = 4; j < nwh; j += 4) {
+ wk1r = w[nw0 + 2 * j];
+ wk1i = w[nw0 + 2 * j + 1];
+ wk3r = w[nw0 + 2 * j + 2];
+ wk3i = w[nw0 + 2 * j + 3];
+ w[nw1 + j] = wk1r;
+ w[nw1 + j + 1] = wk1i;
+ w[nw1 + j + 2] = wk3r;
+ w[nw1 + j + 3] = wk3i;
+ }
+ }
+ nw0 = nw1;
+ }
+ }
+}
+
+
+static void makeipt(int nw, int *ip)
+{
+ int j, l, m, m2, p, q;
+
+ ip[2] = 0;
+ ip[3] = 16;
+ m = 2;
+ for (l = nw; l > 32; l >>= 2) {
+ m2 = m << 1;
+ q = m2 << 3;
+ for (j = m; j < m2; j++) {
+ p = ip[j] << 2;
+ ip[m + j] = p;
+ ip[m2 + j] = p + q;
+ }
+ m = m2;
+ }
+}
+
+
+static void makect(int nc, int *ip, float32 *c)
+{
+ int j, nch;
+ float32 delta;
+
+ ip[1] = nc;
+ if (nc > 1) {
+ nch = nc >> 1;
+ delta = atan(1.0) / nch;
+ c[0] = cos(delta * nch);
+ c[nch] = 0.5 * c[0];
+ for (j = 1; j < nch; j++) {
+ c[j] = 0.5 * cos(delta * j);
+ c[nc - j] = 0.5 * sin(delta * j);
+ }
+ }
+}
+
+
+/* -------- child routines -------- */
+
+
+#ifdef USE_CDFT_PTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 8192
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 65536
+#endif
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t pthread_t
+#define cdft_thread_create(thp,func,argp) { \
+ if (pthread_create(thp, NULL, func, (void *) argp) != 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#define cdft_thread_wait(th) { \
+ if (pthread_join(th, NULL) != 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#endif /* USE_CDFT_PTHREADS */
+
+
+#ifdef USE_CDFT_WINTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 32768
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 524288
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t HANDLE
+#define cdft_thread_create(thp,func,argp) { \
+ DWORD thid; \
+ *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, (LPVOID) argp, 0, &thid); \
+ if (*(thp) == 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#define cdft_thread_wait(th) { \
+ WaitForSingleObject(th, INFINITE); \
+ CloseHandle(th); \
+}
+#endif /* USE_CDFT_WINTHREADS */
+
+
+static void cftfsub(int n, float32 *a, int *ip, int nw, float32 *w)
+{
+ if (n > 8) {
+ if (n > 32) {
+ cftf1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+ if (n > CDFT_THREADS_BEGIN_N) {
+ cftrec4_th(n, a, nw, w);
+ } else
+#endif /* USE_CDFT_THREADS */
+ if (n > 512) {
+ cftrec4(n, a, nw, w);
+ } else if (n > 128) {
+ cftleaf(n, 1, a, nw, w);
+ } else {
+ cftfx41(n, a, nw, w);
+ }
+ bitrv2(n, ip, a);
+ } else if (n == 32) {
+ cftf161(a, &w[nw - 8]);
+ bitrv216(a);
+ } else {
+ cftf081(a, w);
+ bitrv208(a);
+ }
+ } else if (n == 8) {
+ cftf040(a);
+ } else if (n == 4) {
+ cftx020(a);
+ }
+}
+
+
+static void cftbsub(int n, float32 *a, int *ip, int nw, float32 *w)
+{
+ if (n > 8) {
+ if (n > 32) {
+ cftb1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+ if (n > CDFT_THREADS_BEGIN_N) {
+ cftrec4_th(n, a, nw, w);
+ } else
+#endif /* USE_CDFT_THREADS */
+ if (n > 512) {
+ cftrec4(n, a, nw, w);
+ } else if (n > 128) {
+ cftleaf(n, 1, a, nw, w);
+ } else {
+ cftfx41(n, a, nw, w);
+ }
+ bitrv2conj(n, ip, a);
+ } else if (n == 32) {
+ cftf161(a, &w[nw - 8]);
+ bitrv216neg(a);
+ } else {
+ cftf081(a, w);
+ bitrv208neg(a);
+ }
+ } else if (n == 8) {
+ cftb040(a);
+ } else if (n == 4) {
+ cftx020(a);
+ }
+}
+
+
+static void bitrv2(int n, int *ip, float32 *a)
+{
+ int j, j1, k, k1, l, m, nh, nm;
+ float32 xr, xi, yr, yi;
+
+ m = 1;
+ for (l = n >> 2; l > 8; l >>= 2) {
+ m <<= 1;
+ }
+ nh = n >> 1;
+ nm = 4 * m;
+ if (l == 8) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + 2 * ip[m + k];
+ k1 = 4 * k + 2 * ip[m + j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + 2 * ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= 2;
+ k1 -= nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh + 2;
+ k1 += nh + 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh - nm;
+ k1 += 2 * nm - 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ } else {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + ip[m + k];
+ k1 = 4 * k + ip[m + j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ }
+}
+
+
+static void bitrv2conj(int n, int *ip, float32 *a)
+{
+ int j, j1, k, k1, l, m, nh, nm;
+ float32 xr, xi, yr, yi;
+
+ m = 1;
+ for (l = n >> 2; l > 8; l >>= 2) {
+ m <<= 1;
+ }
+ nh = n >> 1;
+ nm = 4 * m;
+ if (l == 8) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + 2 * ip[m + k];
+ k1 = 4 * k + 2 * ip[m + j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + 2 * ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= 2;
+ k1 -= nh;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh + 2;
+ k1 += nh + 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh - nm;
+ k1 += 2 * nm - 2;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ }
+ } else {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + ip[m + k];
+ k1 = 4 * k + ip[m + j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ j1 += nm;
+ k1 += nm;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ }
+ }
+}
+
+
+static void bitrv216(float32 *a)
+{
+ float32 x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i,
+ x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x7r = a[14];
+ x7i = a[15];
+ x8r = a[16];
+ x8i = a[17];
+ x10r = a[20];
+ x10i = a[21];
+ x11r = a[22];
+ x11i = a[23];
+ x12r = a[24];
+ x12i = a[25];
+ x13r = a[26];
+ x13i = a[27];
+ x14r = a[28];
+ x14i = a[29];
+ a[2] = x8r;
+ a[3] = x8i;
+ a[4] = x4r;
+ a[5] = x4i;
+ a[6] = x12r;
+ a[7] = x12i;
+ a[8] = x2r;
+ a[9] = x2i;
+ a[10] = x10r;
+ a[11] = x10i;
+ a[14] = x14r;
+ a[15] = x14i;
+ a[16] = x1r;
+ a[17] = x1i;
+ a[20] = x5r;
+ a[21] = x5i;
+ a[22] = x13r;
+ a[23] = x13i;
+ a[24] = x3r;
+ a[25] = x3i;
+ a[26] = x11r;
+ a[27] = x11i;
+ a[28] = x7r;
+ a[29] = x7i;
+}
+
+
+static void bitrv216neg(float32 *a)
+{
+ float32 x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i,
+ x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i,
+ x13r, x13i, x14r, x14i, x15r, x15i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x6r = a[12];
+ x6i = a[13];
+ x7r = a[14];
+ x7i = a[15];
+ x8r = a[16];
+ x8i = a[17];
+ x9r = a[18];
+ x9i = a[19];
+ x10r = a[20];
+ x10i = a[21];
+ x11r = a[22];
+ x11i = a[23];
+ x12r = a[24];
+ x12i = a[25];
+ x13r = a[26];
+ x13i = a[27];
+ x14r = a[28];
+ x14i = a[29];
+ x15r = a[30];
+ x15i = a[31];
+ a[2] = x15r;
+ a[3] = x15i;
+ a[4] = x7r;
+ a[5] = x7i;
+ a[6] = x11r;
+ a[7] = x11i;
+ a[8] = x3r;
+ a[9] = x3i;
+ a[10] = x13r;
+ a[11] = x13i;
+ a[12] = x5r;
+ a[13] = x5i;
+ a[14] = x9r;
+ a[15] = x9i;
+ a[16] = x1r;
+ a[17] = x1i;
+ a[18] = x14r;
+ a[19] = x14i;
+ a[20] = x6r;
+ a[21] = x6i;
+ a[22] = x10r;
+ a[23] = x10i;
+ a[24] = x2r;
+ a[25] = x2i;
+ a[26] = x12r;
+ a[27] = x12i;
+ a[28] = x4r;
+ a[29] = x4i;
+ a[30] = x8r;
+ a[31] = x8i;
+}
+
+
+static void bitrv208(float32 *a)
+{
+ float32 x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x6r = a[12];
+ x6i = a[13];
+ a[2] = x4r;
+ a[3] = x4i;
+ a[6] = x6r;
+ a[7] = x6i;
+ a[8] = x1r;
+ a[9] = x1i;
+ a[12] = x3r;
+ a[13] = x3i;
+}
+
+
+static void bitrv208neg(float32 *a)
+{
+ float32 x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x6r, x6i, x7r, x7i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x6r = a[12];
+ x6i = a[13];
+ x7r = a[14];
+ x7i = a[15];
+ a[2] = x7r;
+ a[3] = x7i;
+ a[4] = x3r;
+ a[5] = x3i;
+ a[6] = x5r;
+ a[7] = x5i;
+ a[8] = x1r;
+ a[9] = x1i;
+ a[10] = x6r;
+ a[11] = x6i;
+ a[12] = x2r;
+ a[13] = x2i;
+ a[14] = x4r;
+ a[15] = x4i;
+}
+
+
+static void cftf1st(int n, float32 *a, float32 *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ float32 wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i,
+ wd1r, wd1i, wd3r, wd3i;
+ float32 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = a[1] + a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = a[1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j2] = x1r - x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ csc1 = w[2];
+ csc3 = w[3];
+ wd1r = 1;
+ wd1i = 0;
+ wd3r = 1;
+ wd3i = 0;
+ k = 0;
+ for (j = 2; j < mh - 2; j += 4) {
+ k += 4;
+ wk1r = csc1 * (wd1r + w[k]);
+ wk1i = csc1 * (wd1i + w[k + 1]);
+ wk3r = csc3 * (wd3r + w[k + 2]);
+ wk3i = csc3 * (wd3i + w[k + 3]);
+ wd1r = w[k];
+ wd1i = w[k + 1];
+ wd3r = w[k + 2];
+ wd3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = a[j + 1] + a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = a[j + 1] - a[j2 + 1];
+ y0r = a[j + 2] + a[j2 + 2];
+ y0i = a[j + 3] + a[j2 + 3];
+ y1r = a[j + 2] - a[j2 + 2];
+ y1i = a[j + 3] - a[j2 + 3];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 + 2] + a[j3 + 2];
+ y2i = a[j1 + 3] + a[j3 + 3];
+ y3r = a[j1 + 2] - a[j3 + 2];
+ y3i = a[j1 + 3] - a[j3 + 3];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j + 2] = y0r + y2r;
+ a[j + 3] = y0i + y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j1 + 2] = y0r - y2r;
+ a[j1 + 3] = y0i - y2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+ a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+ a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ y0r = a[j0 - 2] + a[j2 - 2];
+ y0i = a[j0 - 1] + a[j2 - 1];
+ y1r = a[j0 - 2] - a[j2 - 2];
+ y1i = a[j0 - 1] - a[j2 - 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 - 2] + a[j3 - 2];
+ y2i = a[j1 - 1] + a[j3 - 1];
+ y3r = a[j1 - 2] - a[j3 - 2];
+ y3i = a[j1 - 1] - a[j3 - 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j0 - 2] = y0r + y2r;
+ a[j0 - 1] = y0i + y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j1 - 2] = y0r - y2r;
+ a[j1 - 1] = y0i - y2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+ a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+ a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+ }
+ wk1r = csc1 * (wd1r + wn4r);
+ wk1i = csc1 * (wd1i + wn4r);
+ wk3r = csc3 * (wd3r - wn4r);
+ wk3i = csc3 * (wd3i - wn4r);
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0 - 2] + a[j2 - 2];
+ x0i = a[j0 - 1] + a[j2 - 1];
+ x1r = a[j0 - 2] - a[j2 - 2];
+ x1i = a[j0 - 1] - a[j2 - 1];
+ x2r = a[j1 - 2] + a[j3 - 2];
+ x2i = a[j1 - 1] + a[j3 - 1];
+ x3r = a[j1 - 2] - a[j3 - 2];
+ x3i = a[j1 - 1] - a[j3 - 1];
+ a[j0 - 2] = x0r + x2r;
+ a[j0 - 1] = x0i + x2i;
+ a[j1 - 2] = x0r - x2r;
+ a[j1 - 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+ a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+ a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+ x0r = a[j0 + 2] + a[j2 + 2];
+ x0i = a[j0 + 3] + a[j2 + 3];
+ x1r = a[j0 + 2] - a[j2 + 2];
+ x1i = a[j0 + 3] - a[j2 + 3];
+ x2r = a[j1 + 2] + a[j3 + 2];
+ x2i = a[j1 + 3] + a[j3 + 3];
+ x3r = a[j1 + 2] - a[j3 + 2];
+ x3i = a[j1 + 3] - a[j3 + 3];
+ a[j0 + 2] = x0r + x2r;
+ a[j0 + 3] = x0i + x2i;
+ a[j1 + 2] = x0r - x2r;
+ a[j1 + 3] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+static void cftb1st(int n, float32 *a, float32 *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ float32 wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i,
+ wd1r, wd1i, wd3r, wd3i;
+ float32 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = -a[1] - a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = -a[1] + a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i - x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j2] = x1r + x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r - x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ csc1 = w[2];
+ csc3 = w[3];
+ wd1r = 1;
+ wd1i = 0;
+ wd3r = 1;
+ wd3i = 0;
+ k = 0;
+ for (j = 2; j < mh - 2; j += 4) {
+ k += 4;
+ wk1r = csc1 * (wd1r + w[k]);
+ wk1i = csc1 * (wd1i + w[k + 1]);
+ wk3r = csc3 * (wd3r + w[k + 2]);
+ wk3i = csc3 * (wd3i + w[k + 3]);
+ wd1r = w[k];
+ wd1i = w[k + 1];
+ wd3r = w[k + 2];
+ wd3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = -a[j + 1] - a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = -a[j + 1] + a[j2 + 1];
+ y0r = a[j + 2] + a[j2 + 2];
+ y0i = -a[j + 3] - a[j2 + 3];
+ y1r = a[j + 2] - a[j2 + 2];
+ y1i = -a[j + 3] + a[j2 + 3];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 + 2] + a[j3 + 2];
+ y2i = a[j1 + 3] + a[j3 + 3];
+ y3r = a[j1 + 2] - a[j3 + 2];
+ y3i = a[j1 + 3] - a[j3 + 3];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j + 2] = y0r + y2r;
+ a[j + 3] = y0i - y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j1 + 2] = y0r - y2r;
+ a[j1 + 3] = y0i + y2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i + y3r;
+ a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+ a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i - y3r;
+ a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+ a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = -a[j0 + 1] - a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = -a[j0 + 1] + a[j2 + 1];
+ y0r = a[j0 - 2] + a[j2 - 2];
+ y0i = -a[j0 - 1] - a[j2 - 1];
+ y1r = a[j0 - 2] - a[j2 - 2];
+ y1i = -a[j0 - 1] + a[j2 - 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 - 2] + a[j3 - 2];
+ y2i = a[j1 - 1] + a[j3 - 1];
+ y3r = a[j1 - 2] - a[j3 - 2];
+ y3i = a[j1 - 1] - a[j3 - 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i - x2i;
+ a[j0 - 2] = y0r + y2r;
+ a[j0 - 1] = y0i - y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j1 - 2] = y0r - y2r;
+ a[j1 - 1] = y0i + y2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i + y3r;
+ a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+ a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i - y3r;
+ a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+ a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+ }
+ wk1r = csc1 * (wd1r + wn4r);
+ wk1i = csc1 * (wd1i + wn4r);
+ wk3r = csc3 * (wd3r - wn4r);
+ wk3i = csc3 * (wd3i - wn4r);
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0 - 2] + a[j2 - 2];
+ x0i = -a[j0 - 1] - a[j2 - 1];
+ x1r = a[j0 - 2] - a[j2 - 2];
+ x1i = -a[j0 - 1] + a[j2 - 1];
+ x2r = a[j1 - 2] + a[j3 - 2];
+ x2i = a[j1 - 1] + a[j3 - 1];
+ x3r = a[j1 - 2] - a[j3 - 2];
+ x3i = a[j1 - 1] - a[j3 - 1];
+ a[j0 - 2] = x0r + x2r;
+ a[j0 - 1] = x0i - x2i;
+ a[j1 - 2] = x0r - x2r;
+ a[j1 - 1] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+ a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+ a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+ x0r = a[j0] + a[j2];
+ x0i = -a[j0 + 1] - a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = -a[j0 + 1] + a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i - x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+ x0r = a[j0 + 2] + a[j2 + 2];
+ x0i = -a[j0 + 3] - a[j2 + 3];
+ x1r = a[j0 + 2] - a[j2 + 2];
+ x1i = -a[j0 + 3] + a[j2 + 3];
+ x2r = a[j1 + 2] + a[j3 + 2];
+ x2i = a[j1 + 3] + a[j3 + 3];
+ x3r = a[j1 + 2] - a[j3 + 2];
+ x3i = a[j1 + 3] - a[j3 + 3];
+ a[j0 + 2] = x0r + x2r;
+ a[j0 + 3] = x0i - x2i;
+ a[j1 + 2] = x0r - x2r;
+ a[j1 + 3] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+#ifdef USE_CDFT_THREADS
+struct cdft_arg_st {
+ int n0;
+ int n;
+ float32 *a;
+ int nw;
+ float32 *w;
+};
+typedef struct cdft_arg_st cdft_arg_t;
+
+
+static void cftrec4_th(int n, float32 *a, int nw, float32 *w)
+{
+ int i, idiv4, m, nthread;
+ cdft_thread_t th[4];
+ cdft_arg_t ag[4];
+
+ nthread = 2;
+ idiv4 = 0;
+ m = n >> 1;
+ if (n > CDFT_4THREADS_BEGIN_N) {
+ nthread = 4;
+ idiv4 = 1;
+ m >>= 1;
+ }
+ for (i = 0; i < nthread; i++) {
+ ag[i].n0 = n;
+ ag[i].n = m;
+ ag[i].a = &a[i * m];
+ ag[i].nw = nw;
+ ag[i].w = w;
+ if (i != idiv4) {
+ cdft_thread_create(&th[i], cftrec1_th, &ag[i]);
+ } else {
+ cdft_thread_create(&th[i], cftrec2_th, &ag[i]);
+ }
+ }
+ for (i = 0; i < nthread; i++) {
+ cdft_thread_wait(th[i]);
+ }
+}
+
+
+static void *cftrec1_th(void *p)
+{
+ int isplt, j, k, m, n, n0, nw;
+ float32 *a, *w;
+
+ n0 = ((cdft_arg_t *) p)->n0;
+ n = ((cdft_arg_t *) p)->n;
+ a = ((cdft_arg_t *) p)->a;
+ nw = ((cdft_arg_t *) p)->nw;
+ w = ((cdft_arg_t *) p)->w;
+ m = n0;
+ while (m > 512) {
+ m >>= 2;
+ cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+ }
+ cftleaf(m, 1, &a[n - m], nw, w);
+ k = 0;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+ return (void *) 0;
+}
+
+
+static void *cftrec2_th(void *p)
+{
+ int isplt, j, k, m, n, n0, nw;
+ float32 *a, *w;
+
+ n0 = ((cdft_arg_t *) p)->n0;
+ n = ((cdft_arg_t *) p)->n;
+ a = ((cdft_arg_t *) p)->a;
+ nw = ((cdft_arg_t *) p)->nw;
+ w = ((cdft_arg_t *) p)->w;
+ k = 1;
+ m = n0;
+ while (m > 512) {
+ m >>= 2;
+ k <<= 2;
+ cftmdl2(m, &a[n - m], &w[nw - m]);
+ }
+ cftleaf(m, 0, &a[n - m], nw, w);
+ k >>= 1;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+ return (void *) 0;
+}
+#endif /* USE_CDFT_THREADS */
+
+
+static void cftrec4(int n, float32 *a, int nw, float32 *w)
+{
+ int isplt, j, k, m;
+
+ m = n;
+ while (m > 512) {
+ m >>= 2;
+ cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+ }
+ cftleaf(m, 1, &a[n - m], nw, w);
+ k = 0;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+}
+
+
+int cfttree(int n, int j, int k, float32 *a, int nw, float32 *w)
+{
+ int i, isplt, m;
+
+ if ((k & 3) != 0) {
+ isplt = k & 1;
+ if (isplt != 0) {
+ cftmdl1(n, &a[j - n], &w[nw - (n >> 1)]);
+ } else {
+ cftmdl2(n, &a[j - n], &w[nw - n]);
+ }
+ } else {
+ m = n;
+ for (i = k; (i & 3) == 0; i >>= 2) {
+ m <<= 2;
+ }
+ isplt = i & 1;
+ if (isplt != 0) {
+ while (m > 128) {
+ cftmdl1(m, &a[j - m], &w[nw - (m >> 1)]);
+ m >>= 2;
+ }
+ } else {
+ while (m > 128) {
+ cftmdl2(m, &a[j - m], &w[nw - m]);
+ m >>= 2;
+ }
+ }
+ }
+ return isplt;
+}
+
+
+static void cftleaf(int n, int isplt, float32 *a, int nw, float32 *w)
+{
+ if (n == 512) {
+ cftmdl1(128, a, &w[nw - 64]);
+ cftf161(a, &w[nw - 8]);
+ cftf162(&a[32], &w[nw - 32]);
+ cftf161(&a[64], &w[nw - 8]);
+ cftf161(&a[96], &w[nw - 8]);
+ cftmdl2(128, &a[128], &w[nw - 128]);
+ cftf161(&a[128], &w[nw - 8]);
+ cftf162(&a[160], &w[nw - 32]);
+ cftf161(&a[192], &w[nw - 8]);
+ cftf162(&a[224], &w[nw - 32]);
+ cftmdl1(128, &a[256], &w[nw - 64]);
+ cftf161(&a[256], &w[nw - 8]);
+ cftf162(&a[288], &w[nw - 32]);
+ cftf161(&a[320], &w[nw - 8]);
+ cftf161(&a[352], &w[nw - 8]);
+ if (isplt != 0) {
+ cftmdl1(128, &a[384], &w[nw - 64]);
+ cftf161(&a[480], &w[nw - 8]);
+ } else {
+ cftmdl2(128, &a[384], &w[nw - 128]);
+ cftf162(&a[480], &w[nw - 32]);
+ }
+ cftf161(&a[384], &w[nw - 8]);
+ cftf162(&a[416], &w[nw - 32]);
+ cftf161(&a[448], &w[nw - 8]);
+ } else {
+ cftmdl1(64, a, &w[nw - 32]);
+ cftf081(a, &w[nw - 8]);
+ cftf082(&a[16], &w[nw - 8]);
+ cftf081(&a[32], &w[nw - 8]);
+ cftf081(&a[48], &w[nw - 8]);
+ cftmdl2(64, &a[64], &w[nw - 64]);
+ cftf081(&a[64], &w[nw - 8]);
+ cftf082(&a[80], &w[nw - 8]);
+ cftf081(&a[96], &w[nw - 8]);
+ cftf082(&a[112], &w[nw - 8]);
+ cftmdl1(64, &a[128], &w[nw - 32]);
+ cftf081(&a[128], &w[nw - 8]);
+ cftf082(&a[144], &w[nw - 8]);
+ cftf081(&a[160], &w[nw - 8]);
+ cftf081(&a[176], &w[nw - 8]);
+ if (isplt != 0) {
+ cftmdl1(64, &a[192], &w[nw - 32]);
+ cftf081(&a[240], &w[nw - 8]);
+ } else {
+ cftmdl2(64, &a[192], &w[nw - 64]);
+ cftf082(&a[240], &w[nw - 8]);
+ }
+ cftf081(&a[192], &w[nw - 8]);
+ cftf082(&a[208], &w[nw - 8]);
+ cftf081(&a[224], &w[nw - 8]);
+ }
+}
+
+
+static void cftmdl1(int n, float32 *a, float32 *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ float32 wn4r, wk1r, wk1i, wk3r, wk3i;
+ float32 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = a[1] + a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = a[1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j2] = x1r - x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ k = 0;
+ for (j = 2; j < mh; j += 2) {
+ k += 4;
+ wk1r = w[k];
+ wk1i = w[k + 1];
+ wk3r = w[k + 2];
+ wk3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = a[j + 1] + a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = a[j + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ }
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+}
+
+
+static void cftmdl2(int n, float32 *a, float32 *w)
+{
+ int j, j0, j1, j2, j3, k, kr, m, mh;
+ float32 wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+ float32 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ wn4r = w[1];
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] - a[j2 + 1];
+ x0i = a[1] + a[j2];
+ x1r = a[0] + a[j2 + 1];
+ x1i = a[1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wn4r * (x2r - x2i);
+ y0i = wn4r * (x2i + x2r);
+ a[0] = x0r + y0r;
+ a[1] = x0i + y0i;
+ a[j1] = x0r - y0r;
+ a[j1 + 1] = x0i - y0i;
+ y0r = wn4r * (x3r - x3i);
+ y0i = wn4r * (x3i + x3r);
+ a[j2] = x1r - y0i;
+ a[j2 + 1] = x1i + y0r;
+ a[j3] = x1r + y0i;
+ a[j3 + 1] = x1i - y0r;
+ k = 0;
+ kr = 2 * m;
+ for (j = 2; j < mh; j += 2) {
+ k += 4;
+ wk1r = w[k];
+ wk1i = w[k + 1];
+ wk3r = w[k + 2];
+ wk3i = w[k + 3];
+ kr -= 4;
+ wd1i = w[kr];
+ wd1r = w[kr + 1];
+ wd3i = w[kr + 2];
+ wd3r = w[kr + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] - a[j2 + 1];
+ x0i = a[j + 1] + a[j2];
+ x1r = a[j] + a[j2 + 1];
+ x1i = a[j + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wk1r * x0r - wk1i * x0i;
+ y0i = wk1r * x0i + wk1i * x0r;
+ y2r = wd1r * x2r - wd1i * x2i;
+ y2i = wd1r * x2i + wd1i * x2r;
+ a[j] = y0r + y2r;
+ a[j + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wk3r * x1r + wk3i * x1i;
+ y0i = wk3r * x1i - wk3i * x1r;
+ y2r = wd3r * x3r + wd3i * x3i;
+ y2i = wd3r * x3i - wd3i * x3r;
+ a[j2] = y0r + y2r;
+ a[j2 + 1] = y0i + y2i;
+ a[j3] = y0r - y2r;
+ a[j3 + 1] = y0i - y2i;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] - a[j2 + 1];
+ x0i = a[j0 + 1] + a[j2];
+ x1r = a[j0] + a[j2 + 1];
+ x1i = a[j0 + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wd1i * x0r - wd1r * x0i;
+ y0i = wd1i * x0i + wd1r * x0r;
+ y2r = wk1i * x2r - wk1r * x2i;
+ y2i = wk1i * x2i + wk1r * x2r;
+ a[j0] = y0r + y2r;
+ a[j0 + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wd3i * x1r + wd3r * x1i;
+ y0i = wd3i * x1i - wd3r * x1r;
+ y2r = wk3i * x3r + wk3r * x3i;
+ y2i = wk3i * x3i - wk3r * x3r;
+ a[j2] = y0r + y2r;
+ a[j2 + 1] = y0i + y2i;
+ a[j3] = y0r - y2r;
+ a[j3 + 1] = y0i - y2i;
+ }
+ wk1r = w[m];
+ wk1i = w[m + 1];
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] - a[j2 + 1];
+ x0i = a[j0 + 1] + a[j2];
+ x1r = a[j0] + a[j2 + 1];
+ x1i = a[j0 + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wk1r * x0r - wk1i * x0i;
+ y0i = wk1r * x0i + wk1i * x0r;
+ y2r = wk1i * x2r - wk1r * x2i;
+ y2i = wk1i * x2i + wk1r * x2r;
+ a[j0] = y0r + y2r;
+ a[j0 + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wk1i * x1r - wk1r * x1i;
+ y0i = wk1i * x1i + wk1r * x1r;
+ y2r = wk1r * x3r - wk1i * x3i;
+ y2i = wk1r * x3i + wk1i * x3r;
+ a[j2] = y0r - y2r;
+ a[j2 + 1] = y0i - y2i;
+ a[j3] = y0r + y2r;
+ a[j3 + 1] = y0i + y2i;
+}
+
+
+static void cftfx41(int n, float32 *a, int nw, float32 *w)
+{
+ if (n == 128) {
+ cftf161(a, &w[nw - 8]);
+ cftf162(&a[32], &w[nw - 32]);
+ cftf161(&a[64], &w[nw - 8]);
+ cftf161(&a[96], &w[nw - 8]);
+ } else {
+ cftf081(a, &w[nw - 8]);
+ cftf082(&a[16], &w[nw - 8]);
+ cftf081(&a[32], &w[nw - 8]);
+ cftf081(&a[48], &w[nw - 8]);
+ }
+}
+
+
+static void cftf161(float32 *a, float32 *w)
+{
+ float32 wn4r, wk1r, wk1i,
+ x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i,
+ y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i,
+ y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+ wn4r = w[1];
+ wk1r = w[2];
+ wk1i = w[3];
+ x0r = a[0] + a[16];
+ x0i = a[1] + a[17];
+ x1r = a[0] - a[16];
+ x1i = a[1] - a[17];
+ x2r = a[8] + a[24];
+ x2i = a[9] + a[25];
+ x3r = a[8] - a[24];
+ x3i = a[9] - a[25];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y4r = x0r - x2r;
+ y4i = x0i - x2i;
+ y8r = x1r - x3i;
+ y8i = x1i + x3r;
+ y12r = x1r + x3i;
+ y12i = x1i - x3r;
+ x0r = a[2] + a[18];
+ x0i = a[3] + a[19];
+ x1r = a[2] - a[18];
+ x1i = a[3] - a[19];
+ x2r = a[10] + a[26];
+ x2i = a[11] + a[27];
+ x3r = a[10] - a[26];
+ x3i = a[11] - a[27];
+ y1r = x0r + x2r;
+ y1i = x0i + x2i;
+ y5r = x0r - x2r;
+ y5i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y9r = wk1r * x0r - wk1i * x0i;
+ y9i = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y13r = wk1i * x0r - wk1r * x0i;
+ y13i = wk1i * x0i + wk1r * x0r;
+ x0r = a[4] + a[20];
+ x0i = a[5] + a[21];
+ x1r = a[4] - a[20];
+ x1i = a[5] - a[21];
+ x2r = a[12] + a[28];
+ x2i = a[13] + a[29];
+ x3r = a[12] - a[28];
+ x3i = a[13] - a[29];
+ y2r = x0r + x2r;
+ y2i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y10r = wn4r * (x0r - x0i);
+ y10i = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y14r = wn4r * (x0r + x0i);
+ y14i = wn4r * (x0i - x0r);
+ x0r = a[6] + a[22];
+ x0i = a[7] + a[23];
+ x1r = a[6] - a[22];
+ x1i = a[7] - a[23];
+ x2r = a[14] + a[30];
+ x2i = a[15] + a[31];
+ x3r = a[14] - a[30];
+ x3i = a[15] - a[31];
+ y3r = x0r + x2r;
+ y3i = x0i + x2i;
+ y7r = x0r - x2r;
+ y7i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y11r = wk1i * x0r - wk1r * x0i;
+ y11i = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y15r = wk1r * x0r - wk1i * x0i;
+ y15i = wk1r * x0i + wk1i * x0r;
+ x0r = y12r - y14r;
+ x0i = y12i - y14i;
+ x1r = y12r + y14r;
+ x1i = y12i + y14i;
+ x2r = y13r - y15r;
+ x2i = y13i - y15i;
+ x3r = y13r + y15r;
+ x3i = y13i + y15i;
+ a[24] = x0r + x2r;
+ a[25] = x0i + x2i;
+ a[26] = x0r - x2r;
+ a[27] = x0i - x2i;
+ a[28] = x1r - x3i;
+ a[29] = x1i + x3r;
+ a[30] = x1r + x3i;
+ a[31] = x1i - x3r;
+ x0r = y8r + y10r;
+ x0i = y8i + y10i;
+ x1r = y8r - y10r;
+ x1i = y8i - y10i;
+ x2r = y9r + y11r;
+ x2i = y9i + y11i;
+ x3r = y9r - y11r;
+ x3i = y9i - y11i;
+ a[16] = x0r + x2r;
+ a[17] = x0i + x2i;
+ a[18] = x0r - x2r;
+ a[19] = x0i - x2i;
+ a[20] = x1r - x3i;
+ a[21] = x1i + x3r;
+ a[22] = x1r + x3i;
+ a[23] = x1i - x3r;
+ x0r = y5r - y7i;
+ x0i = y5i + y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ x0r = y5r + y7i;
+ x0i = y5i - y7r;
+ x3r = wn4r * (x0r - x0i);
+ x3i = wn4r * (x0i + x0r);
+ x0r = y4r - y6i;
+ x0i = y4i + y6r;
+ x1r = y4r + y6i;
+ x1i = y4i - y6r;
+ a[8] = x0r + x2r;
+ a[9] = x0i + x2i;
+ a[10] = x0r - x2r;
+ a[11] = x0i - x2i;
+ a[12] = x1r - x3i;
+ a[13] = x1i + x3r;
+ a[14] = x1r + x3i;
+ a[15] = x1i - x3r;
+ x0r = y0r + y2r;
+ x0i = y0i + y2i;
+ x1r = y0r - y2r;
+ x1i = y0i - y2i;
+ x2r = y1r + y3r;
+ x2i = y1i + y3i;
+ x3r = y1r - y3r;
+ x3i = y1i - y3i;
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x0r - x2r;
+ a[3] = x0i - x2i;
+ a[4] = x1r - x3i;
+ a[5] = x1i + x3r;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+}
+
+
+static void cftf162(float32 *a, float32 *w)
+{
+ float32 wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ x0r, x0i, x1r, x1i, x2r, x2i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i,
+ y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i,
+ y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+ wn4r = w[1];
+ wk1r = w[4];
+ wk1i = w[5];
+ wk3r = w[6];
+ wk3i = -w[7];
+ wk2r = w[8];
+ wk2i = w[9];
+ x1r = a[0] - a[17];
+ x1i = a[1] + a[16];
+ x0r = a[8] - a[25];
+ x0i = a[9] + a[24];
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ y0r = x1r + x2r;
+ y0i = x1i + x2i;
+ y4r = x1r - x2r;
+ y4i = x1i - x2i;
+ x1r = a[0] + a[17];
+ x1i = a[1] - a[16];
+ x0r = a[8] + a[25];
+ x0i = a[9] - a[24];
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ y8r = x1r - x2i;
+ y8i = x1i + x2r;
+ y12r = x1r + x2i;
+ y12i = x1i - x2r;
+ x0r = a[2] - a[19];
+ x0i = a[3] + a[18];
+ x1r = wk1r * x0r - wk1i * x0i;
+ x1i = wk1r * x0i + wk1i * x0r;
+ x0r = a[10] - a[27];
+ x0i = a[11] + a[26];
+ x2r = wk3i * x0r - wk3r * x0i;
+ x2i = wk3i * x0i + wk3r * x0r;
+ y1r = x1r + x2r;
+ y1i = x1i + x2i;
+ y5r = x1r - x2r;
+ y5i = x1i - x2i;
+ x0r = a[2] + a[19];
+ x0i = a[3] - a[18];
+ x1r = wk3r * x0r - wk3i * x0i;
+ x1i = wk3r * x0i + wk3i * x0r;
+ x0r = a[10] + a[27];
+ x0i = a[11] - a[26];
+ x2r = wk1r * x0r + wk1i * x0i;
+ x2i = wk1r * x0i - wk1i * x0r;
+ y9r = x1r - x2r;
+ y9i = x1i - x2i;
+ y13r = x1r + x2r;
+ y13i = x1i + x2i;
+ x0r = a[4] - a[21];
+ x0i = a[5] + a[20];
+ x1r = wk2r * x0r - wk2i * x0i;
+ x1i = wk2r * x0i + wk2i * x0r;
+ x0r = a[12] - a[29];
+ x0i = a[13] + a[28];
+ x2r = wk2i * x0r - wk2r * x0i;
+ x2i = wk2i * x0i + wk2r * x0r;
+ y2r = x1r + x2r;
+ y2i = x1i + x2i;
+ y6r = x1r - x2r;
+ y6i = x1i - x2i;
+ x0r = a[4] + a[21];
+ x0i = a[5] - a[20];
+ x1r = wk2i * x0r - wk2r * x0i;
+ x1i = wk2i * x0i + wk2r * x0r;
+ x0r = a[12] + a[29];
+ x0i = a[13] - a[28];
+ x2r = wk2r * x0r - wk2i * x0i;
+ x2i = wk2r * x0i + wk2i * x0r;
+ y10r = x1r - x2r;
+ y10i = x1i - x2i;
+ y14r = x1r + x2r;
+ y14i = x1i + x2i;
+ x0r = a[6] - a[23];
+ x0i = a[7] + a[22];
+ x1r = wk3r * x0r - wk3i * x0i;
+ x1i = wk3r * x0i + wk3i * x0r;
+ x0r = a[14] - a[31];
+ x0i = a[15] + a[30];
+ x2r = wk1i * x0r - wk1r * x0i;
+ x2i = wk1i * x0i + wk1r * x0r;
+ y3r = x1r + x2r;
+ y3i = x1i + x2i;
+ y7r = x1r - x2r;
+ y7i = x1i - x2i;
+ x0r = a[6] + a[23];
+ x0i = a[7] - a[22];
+ x1r = wk1i * x0r + wk1r * x0i;
+ x1i = wk1i * x0i - wk1r * x0r;
+ x0r = a[14] + a[31];
+ x0i = a[15] - a[30];
+ x2r = wk3i * x0r - wk3r * x0i;
+ x2i = wk3i * x0i + wk3r * x0r;
+ y11r = x1r + x2r;
+ y11i = x1i + x2i;
+ y15r = x1r - x2r;
+ y15i = x1i - x2i;
+ x1r = y0r + y2r;
+ x1i = y0i + y2i;
+ x2r = y1r + y3r;
+ x2i = y1i + y3i;
+ a[0] = x1r + x2r;
+ a[1] = x1i + x2i;
+ a[2] = x1r - x2r;
+ a[3] = x1i - x2i;
+ x1r = y0r - y2r;
+ x1i = y0i - y2i;
+ x2r = y1r - y3r;
+ x2i = y1i - y3i;
+ a[4] = x1r - x2i;
+ a[5] = x1i + x2r;
+ a[6] = x1r + x2i;
+ a[7] = x1i - x2r;
+ x1r = y4r - y6i;
+ x1i = y4i + y6r;
+ x0r = y5r - y7i;
+ x0i = y5i + y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[8] = x1r + x2r;
+ a[9] = x1i + x2i;
+ a[10] = x1r - x2r;
+ a[11] = x1i - x2i;
+ x1r = y4r + y6i;
+ x1i = y4i - y6r;
+ x0r = y5r + y7i;
+ x0i = y5i - y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[12] = x1r - x2i;
+ a[13] = x1i + x2r;
+ a[14] = x1r + x2i;
+ a[15] = x1i - x2r;
+ x1r = y8r + y10r;
+ x1i = y8i + y10i;
+ x2r = y9r - y11r;
+ x2i = y9i - y11i;
+ a[16] = x1r + x2r;
+ a[17] = x1i + x2i;
+ a[18] = x1r - x2r;
+ a[19] = x1i - x2i;
+ x1r = y8r - y10r;
+ x1i = y8i - y10i;
+ x2r = y9r + y11r;
+ x2i = y9i + y11i;
+ a[20] = x1r - x2i;
+ a[21] = x1i + x2r;
+ a[22] = x1r + x2i;
+ a[23] = x1i - x2r;
+ x1r = y12r - y14i;
+ x1i = y12i + y14r;
+ x0r = y13r + y15i;
+ x0i = y13i - y15r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[24] = x1r + x2r;
+ a[25] = x1i + x2i;
+ a[26] = x1r - x2r;
+ a[27] = x1i - x2i;
+ x1r = y12r + y14i;
+ x1i = y12i - y14r;
+ x0r = y13r - y15i;
+ x0i = y13i + y15r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[28] = x1r - x2i;
+ a[29] = x1i + x2r;
+ a[30] = x1r + x2i;
+ a[31] = x1i - x2r;
+}
+
+
+static void cftf081(float32 *a, float32 *w)
+{
+ float32 wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[1];
+ x0r = a[0] + a[8];
+ x0i = a[1] + a[9];
+ x1r = a[0] - a[8];
+ x1i = a[1] - a[9];
+ x2r = a[4] + a[12];
+ x2i = a[5] + a[13];
+ x3r = a[4] - a[12];
+ x3i = a[5] - a[13];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[2] + a[10];
+ x0i = a[3] + a[11];
+ x1r = a[2] - a[10];
+ x1i = a[3] - a[11];
+ x2r = a[6] + a[14];
+ x2i = a[7] + a[15];
+ x3r = a[6] - a[14];
+ x3i = a[7] - a[15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[8] = y1r + y5r;
+ a[9] = y1i + y5i;
+ a[10] = y1r - y5r;
+ a[11] = y1i - y5i;
+ a[12] = y3r - y7i;
+ a[13] = y3i + y7r;
+ a[14] = y3r + y7i;
+ a[15] = y3i - y7r;
+ a[0] = y0r + y4r;
+ a[1] = y0i + y4i;
+ a[2] = y0r - y4r;
+ a[3] = y0i - y4i;
+ a[4] = y2r - y6i;
+ a[5] = y2i + y6r;
+ a[6] = y2r + y6i;
+ a[7] = y2i - y6r;
+}
+
+
+static void cftf082(float32 *a, float32 *w)
+{
+ float32 wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[1];
+ wk1r = w[2];
+ wk1i = w[3];
+ y0r = a[0] - a[9];
+ y0i = a[1] + a[8];
+ y1r = a[0] + a[9];
+ y1i = a[1] - a[8];
+ x0r = a[4] - a[13];
+ x0i = a[5] + a[12];
+ y2r = wn4r * (x0r - x0i);
+ y2i = wn4r * (x0i + x0r);
+ x0r = a[4] + a[13];
+ x0i = a[5] - a[12];
+ y3r = wn4r * (x0r - x0i);
+ y3i = wn4r * (x0i + x0r);
+ x0r = a[2] - a[11];
+ x0i = a[3] + a[10];
+ y4r = wk1r * x0r - wk1i * x0i;
+ y4i = wk1r * x0i + wk1i * x0r;
+ x0r = a[2] + a[11];
+ x0i = a[3] - a[10];
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ x0r = a[6] - a[15];
+ x0i = a[7] + a[14];
+ y6r = wk1i * x0r - wk1r * x0i;
+ y6i = wk1i * x0i + wk1r * x0r;
+ x0r = a[6] + a[15];
+ x0i = a[7] - a[14];
+ y7r = wk1r * x0r - wk1i * x0i;
+ y7i = wk1r * x0i + wk1i * x0r;
+ x0r = y0r + y2r;
+ x0i = y0i + y2i;
+ x1r = y4r + y6r;
+ x1i = y4i + y6i;
+ a[0] = x0r + x1r;
+ a[1] = x0i + x1i;
+ a[2] = x0r - x1r;
+ a[3] = x0i - x1i;
+ x0r = y0r - y2r;
+ x0i = y0i - y2i;
+ x1r = y4r - y6r;
+ x1i = y4i - y6i;
+ a[4] = x0r - x1i;
+ a[5] = x0i + x1r;
+ a[6] = x0r + x1i;
+ a[7] = x0i - x1r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ x1r = y5r - y7r;
+ x1i = y5i - y7i;
+ a[8] = x0r + x1r;
+ a[9] = x0i + x1i;
+ a[10] = x0r - x1r;
+ a[11] = x0i - x1i;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ x1r = y5r + y7r;
+ x1i = y5i + y7i;
+ a[12] = x0r - x1i;
+ a[13] = x0i + x1r;
+ a[14] = x0r + x1i;
+ a[15] = x0i - x1r;
+}
+
+
+static void cftf040(float32 *a)
+{
+ float32 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[4];
+ x0i = a[1] + a[5];
+ x1r = a[0] - a[4];
+ x1i = a[1] - a[5];
+ x2r = a[2] + a[6];
+ x2i = a[3] + a[7];
+ x3r = a[2] - a[6];
+ x3i = a[3] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x1r - x3i;
+ a[3] = x1i + x3r;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+}
+
+
+static void cftb040(float32 *a)
+{
+ float32 x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[4];
+ x0i = a[1] + a[5];
+ x1r = a[0] - a[4];
+ x1i = a[1] - a[5];
+ x2r = a[2] + a[6];
+ x2i = a[3] + a[7];
+ x3r = a[2] - a[6];
+ x3i = a[3] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x1r + x3i;
+ a[3] = x1i - x3r;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[6] = x1r - x3i;
+ a[7] = x1i + x3r;
+}
+
+
+static void cftx020(float32 *a)
+{
+ float32 x0r, x0i;
+
+ x0r = a[0] - a[2];
+ x0i = a[1] - a[3];
+ a[0] += a[2];
+ a[1] += a[3];
+ a[2] = x0r;
+ a[3] = x0i;
+}
+
+
+static void rftfsub(int n, float32 *a, int nc, float32 *c)
+{
+ int j, k, kk, ks, m;
+ float32 wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr - wki * xi;
+ yi = wkr * xi + wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+
+static void rftbsub(int n, float32 *a, int nc, float32 *c)
+{
+ int j, k, kk, ks, m;
+ float32 wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr + wki * xi;
+ yi = wkr * xi - wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+
+static void dctsub(int n, float32 *a, int nc, float32 *c)
+{
+ int j, k, kk, ks, m;
+ float32 wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[j] - wkr * a[k];
+ a[j] = wkr * a[j] + wki * a[k];
+ a[k] = xr;
+ }
+ a[m] *= c[0];
+}
+
+
+static void dstsub(int n, float32 *a, int nc, float32 *c)
+{
+ int j, k, kk, ks, m;
+ float32 wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[k] - wkr * a[j];
+ a[k] = wkr * a[k] + wki * a[j];
+ a[j] = xr;
+ }
+ a[m] *= c[0];
}
}
diff --git a/src/GeometryUtil3D.cpp b/src/GeometryUtil3D.cpp
index 52dd5a9..c6bfd8b 100644
--- a/src/GeometryUtil3D.cpp
+++ b/src/GeometryUtil3D.cpp
@@ -28,8 +28,96 @@ $Id$
#include "astra/GeometryUtil3D.h"
+#include <cmath>
+
namespace astra {
+
+SConeProjection* genConeProjections(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ double fOriginSourceDistance,
+ double fOriginDetectorDistance,
+ double fDetUSize,
+ double fDetVSize,
+ const float *pfAngles)
+{
+ SConeProjection base;
+ base.fSrcX = 0.0f;
+ base.fSrcY = -fOriginSourceDistance;
+ base.fSrcZ = 0.0f;
+
+ base.fDetSX = iProjU * fDetUSize * -0.5f;
+ base.fDetSY = fOriginDetectorDistance;
+ base.fDetSZ = iProjV * fDetVSize * -0.5f;
+
+ base.fDetUX = fDetUSize;
+ base.fDetUY = 0.0f;
+ base.fDetUZ = 0.0f;
+
+ base.fDetVX = 0.0f;
+ base.fDetVY = 0.0f;
+ base.fDetVZ = fDetVSize;
+
+ SConeProjection* p = new SConeProjection[iProjAngles];
+
+#define ROTATE0(name,i,alpha) do { p[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); p[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); p[i].f##name##Z = base.f##name##Z; } while(0)
+
+ for (unsigned int i = 0; i < iProjAngles; ++i) {
+ ROTATE0(Src, i, pfAngles[i]);
+ ROTATE0(DetS, i, pfAngles[i]);
+ ROTATE0(DetU, i, pfAngles[i]);
+ ROTATE0(DetV, i, pfAngles[i]);
+ }
+
+#undef ROTATE0
+
+ return p;
+}
+
+SPar3DProjection* genPar3DProjections(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ double fDetUSize,
+ double fDetVSize,
+ const float *pfAngles)
+{
+ SPar3DProjection base;
+ base.fRayX = 0.0f;
+ base.fRayY = 1.0f;
+ base.fRayZ = 0.0f;
+
+ base.fDetSX = iProjU * fDetUSize * -0.5f;
+ base.fDetSY = 0.0f;
+ base.fDetSZ = iProjV * fDetVSize * -0.5f;
+
+ base.fDetUX = fDetUSize;
+ base.fDetUY = 0.0f;
+ base.fDetUZ = 0.0f;
+
+ base.fDetVX = 0.0f;
+ base.fDetVY = 0.0f;
+ base.fDetVZ = fDetVSize;
+
+ SPar3DProjection* p = new SPar3DProjection[iProjAngles];
+
+#define ROTATE0(name,i,alpha) do { p[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); p[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); p[i].f##name##Z = base.f##name##Z; } while(0)
+
+ for (unsigned int i = 0; i < iProjAngles; ++i) {
+ ROTATE0(Ray, i, pfAngles[i]);
+ ROTATE0(DetS, i, pfAngles[i]);
+ ROTATE0(DetU, i, pfAngles[i]);
+ ROTATE0(DetV, i, pfAngles[i]);
+ }
+
+#undef ROTATE0
+
+ return p;
+}
+
+
+
+
// (See declaration in header for (mathematical) description of these functions)
@@ -72,4 +160,88 @@ void computeBP_UV_Coeffs(const SConeProjection& proj, double &fUX, double &fUY,
}
+// TODO: Handle cases of rays parallel to coordinate planes
+
+void backprojectPointX(const SPar3DProjection& proj, double fU, double fV,
+ double fX, double &fY, double &fZ)
+{
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fX - px) / proj.fRayX;
+
+ fY = py + a * proj.fRayY;
+ fZ = pz + a * proj.fRayZ;
+}
+
+void backprojectPointY(const SPar3DProjection& proj, double fU, double fV,
+ double fY, double &fX, double &fZ)
+{
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fY - py) / proj.fRayY;
+
+ fX = px + a * proj.fRayX;
+ fZ = pz + a * proj.fRayZ;
+
+}
+
+void backprojectPointZ(const SPar3DProjection& proj, double fU, double fV,
+ double fZ, double &fX, double &fY)
+{
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fZ - pz) / proj.fRayZ;
+
+ fX = px + a * proj.fRayX;
+ fY = py + a * proj.fRayY;
+}
+
+
+
+void backprojectPointX(const SConeProjection& proj, double fU, double fV,
+ double fX, double &fY, double &fZ)
+{
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fX - proj.fSrcX) / (px - proj.fSrcX);
+
+ fY = proj.fSrcY + a * (py - proj.fSrcY);
+ fZ = proj.fSrcZ + a * (pz - proj.fSrcZ);
+}
+
+void backprojectPointY(const SConeProjection& proj, double fU, double fV,
+ double fY, double &fX, double &fZ)
+{
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fY - proj.fSrcY) / (py - proj.fSrcY);
+
+ fX = proj.fSrcX + a * (px - proj.fSrcX);
+ fZ = proj.fSrcZ + a * (pz - proj.fSrcZ);
+}
+
+void backprojectPointZ(const SConeProjection& proj, double fU, double fV,
+ double fZ, double &fX, double &fY)
+{
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fZ - proj.fSrcZ) / (pz - proj.fSrcZ);
+
+ fX = proj.fSrcX + a * (px - proj.fSrcX);
+ fY = proj.fSrcY + a * (py - proj.fSrcY);
+}
+
+
}
diff --git a/src/Globals.cpp b/src/Globals.cpp
index 813f9c9..904a459 100644
--- a/src/Globals.cpp
+++ b/src/Globals.cpp
@@ -28,5 +28,8 @@ $Id$
#include "astra/Globals.h"
+namespace astra{
+ bool running_in_matlab=false;
+}
// nothing to see here :)
diff --git a/src/Logging.cpp b/src/Logging.cpp
index 8290ca0..cd7e3f0 100644
--- a/src/Logging.cpp
+++ b/src/Logging.cpp
@@ -70,37 +70,65 @@ void CLogger::disable()
void CLogger::debug(const char *sfile, int sline, const char *fmt, ...)
{
_assureIsInitialized();
- va_list ap;
- va_start(ap, fmt);
- if(m_bEnabledScreen) clog_debug(sfile,sline,0,fmt,ap);
- if(m_bEnabledFile && m_bFileProvided) clog_debug(sfile,sline,1,fmt,ap);
+ va_list ap, apf;
+ if(m_bEnabledScreen){
+ va_start(ap, fmt);
+ clog_debug(sfile,sline,0,fmt,ap);
+ va_end(ap);
+ }
+ if(m_bEnabledFile && m_bFileProvided){
+ va_start(apf, fmt);
+ clog_debug(sfile,sline,1,fmt,apf);
+ va_end(apf);
+ }
}
void CLogger::info(const char *sfile, int sline, const char *fmt, ...)
{
_assureIsInitialized();
- va_list ap;
- va_start(ap, fmt);
- if(m_bEnabledScreen) clog_info(sfile,sline,0,fmt,ap);
- if(m_bEnabledFile && m_bFileProvided) clog_info(sfile,sline,1,fmt,ap);
+ va_list ap, apf;
+ if(m_bEnabledScreen){
+ va_start(ap, fmt);
+ clog_info(sfile,sline,0,fmt,ap);
+ va_end(ap);
+ }
+ if(m_bEnabledFile && m_bFileProvided){
+ va_start(apf, fmt);
+ clog_info(sfile,sline,1,fmt,apf);
+ va_end(apf);
+ }
}
void CLogger::warn(const char *sfile, int sline, const char *fmt, ...)
{
_assureIsInitialized();
- va_list ap;
- va_start(ap, fmt);
- if(m_bEnabledScreen) clog_warn(sfile,sline,0,fmt,ap);
- if(m_bEnabledFile && m_bFileProvided) clog_warn(sfile,sline,1,fmt,ap);
+ va_list ap, apf;
+ if(m_bEnabledScreen){
+ va_start(ap, fmt);
+ clog_warn(sfile,sline,0,fmt,ap);
+ va_end(ap);
+ }
+ if(m_bEnabledFile && m_bFileProvided){
+ va_start(apf, fmt);
+ clog_warn(sfile,sline,1,fmt,apf);
+ va_end(apf);
+ }
}
void CLogger::error(const char *sfile, int sline, const char *fmt, ...)
{
_assureIsInitialized();
- va_list ap;
- va_start(ap, fmt);
- if(m_bEnabledScreen) clog_error(sfile,sline,0,fmt,ap);
- if(m_bEnabledFile && m_bFileProvided) clog_error(sfile,sline,1,fmt,ap);
+ va_list ap, apf;
+ if(m_bEnabledScreen){
+ va_start(ap, fmt);
+ clog_error(sfile,sline,0,fmt,ap);
+ va_end(ap);
+ }
+ if(m_bEnabledFile && m_bFileProvided){
+ va_start(apf, fmt);
+ clog_error(sfile,sline,1,fmt,apf);
+ va_end(apf);
+ }
}
void CLogger::_setLevel(int id, log_level m_eLevel)
diff --git a/src/ParallelBeamBlobKernelProjector2D.cpp b/src/ParallelBeamBlobKernelProjector2D.cpp
index 1e6312f..f6741dc 100644
--- a/src/ParallelBeamBlobKernelProjector2D.cpp
+++ b/src/ParallelBeamBlobKernelProjector2D.cpp
@@ -29,7 +29,6 @@ $Id$
#include "astra/ParallelBeamBlobKernelProjector2D.h"
#include <cmath>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
@@ -134,17 +133,17 @@ bool CParallelBeamBlobKernelProjector2D::initialize(const Config& _cfg)
// Required: KernelSize
XMLNode node2 = node.getSingleNode("KernelSize");
ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelSize tag specified.");
- m_fBlobSize = boost::lexical_cast<float32>(node2.getContent());
+ m_fBlobSize = node2.getContentNumerical();
// Required: SampleRate
node2 = node.getSingleNode("SampleRate");
ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleRate tag specified.");
- m_fBlobSampleRate = boost::lexical_cast<float32>(node2.getContent());
+ m_fBlobSampleRate = node2.getContentNumerical();
// Required: SampleCount
node2 = node.getSingleNode("SampleCount");
ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleCount tag specified.");
- m_iBlobSampleCount = boost::lexical_cast<int>(node2.getContent());
+ m_iBlobSampleCount = node2.getContentInt();
// Required: KernelValues
node2 = node.getSingleNode("KernelValues");
diff --git a/src/ParallelBeamLineKernelProjector2D.cpp b/src/ParallelBeamLineKernelProjector2D.cpp
index c94c024..4b5a34f 100644
--- a/src/ParallelBeamLineKernelProjector2D.cpp
+++ b/src/ParallelBeamLineKernelProjector2D.cpp
@@ -29,7 +29,6 @@ $Id$
#include "astra/ParallelBeamLineKernelProjector2D.h"
#include <cmath>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
diff --git a/src/ParallelBeamLinearKernelProjector2D.cpp b/src/ParallelBeamLinearKernelProjector2D.cpp
index 043db71..4090fb6 100644
--- a/src/ParallelBeamLinearKernelProjector2D.cpp
+++ b/src/ParallelBeamLinearKernelProjector2D.cpp
@@ -29,7 +29,6 @@ $Id$
#include "astra/ParallelBeamLinearKernelProjector2D.h"
#include <cmath>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
diff --git a/src/ParallelBeamStripKernelProjector2D.cpp b/src/ParallelBeamStripKernelProjector2D.cpp
index bb693a2..68e4017 100644
--- a/src/ParallelBeamStripKernelProjector2D.cpp
+++ b/src/ParallelBeamStripKernelProjector2D.cpp
@@ -29,7 +29,6 @@ $Id$
#include "astra/ParallelBeamStripKernelProjector2D.h"
#include <cmath>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
diff --git a/src/ParallelProjectionGeometry2D.cpp b/src/ParallelProjectionGeometry2D.cpp
index 8632b17..105e24b 100644
--- a/src/ParallelProjectionGeometry2D.cpp
+++ b/src/ParallelProjectionGeometry2D.cpp
@@ -27,7 +27,6 @@ $Id$
*/
#include "astra/ParallelProjectionGeometry2D.h"
-#include <boost/lexical_cast.hpp>
#include <cstring>
@@ -179,6 +178,11 @@ Config* CParallelProjectionGeometry2D::getConfiguration() const
cfg->self.addChildNode("DetectorCount", getDetectorCount());
cfg->self.addChildNode("DetectorWidth", getDetectorWidth());
cfg->self.addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount);
+ if(m_pfExtraDetectorOffset!=NULL){
+ XMLNode opt = cfg->self.addChildNode("Option");
+ opt.addAttribute("key","ExtraDetectorOffset");
+ opt.setContent(m_pfExtraDetectorOffset, m_iProjectionAngleCount);
+ }
return cfg;
}
diff --git a/src/ParallelProjectionGeometry3D.cpp b/src/ParallelProjectionGeometry3D.cpp
index 1c87157..2f80883 100644
--- a/src/ParallelProjectionGeometry3D.cpp
+++ b/src/ParallelProjectionGeometry3D.cpp
@@ -27,7 +27,8 @@ $Id$
*/
#include "astra/ParallelProjectionGeometry3D.h"
-#include <boost/lexical_cast.hpp>
+
+#include "astra/GeometryUtil3D.h"
#include <cstring>
@@ -185,9 +186,9 @@ CVector3D CParallelProjectionGeometry3D::getProjectionDirection(int _iProjection
return CVector3D(fDirX, fDirY, fDirZ);
}
-void CParallelProjectionGeometry3D::projectPoint(float32 fX, float32 fY, float32 fZ,
+void CParallelProjectionGeometry3D::projectPoint(double fX, double fY, double fZ,
int iAngleIndex,
- float32 &fU, float32 &fV) const
+ double &fU, double &fV) const
{
ASTRA_ASSERT(iAngleIndex >= 0);
ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
@@ -214,6 +215,79 @@ CParallelProjectionGeometry2D * CParallelProjectionGeometry3D::createProjectionG
return pOutput;
}
+void CParallelProjectionGeometry3D::backprojectPointX(int iAngleIndex, double fU, double fV,
+ double fX, double &fY, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SPar3DProjection *projs = genPar3DProjections(1, m_iDetectorColCount, m_iDetectorRowCount,
+ m_fDetectorSpacingX, m_fDetectorSpacingY,
+ &m_pfProjectionAngles[iAngleIndex]);
+
+ SPar3DProjection &proj = projs[0];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fX - px) / proj.fRayX;
+
+ fY = py + a * proj.fRayY;
+ fZ = pz + a * proj.fRayZ;
+
+ delete[] projs;
+}
+
+void CParallelProjectionGeometry3D::backprojectPointY(int iAngleIndex, double fU, double fV,
+ double fY, double &fX, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SPar3DProjection *projs = genPar3DProjections(1, m_iDetectorColCount, m_iDetectorRowCount,
+ m_fDetectorSpacingX, m_fDetectorSpacingY,
+ &m_pfProjectionAngles[iAngleIndex]);
+
+ SPar3DProjection &proj = projs[0];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fY - py) / proj.fRayY;
+
+ fX = px + a * proj.fRayX;
+ fZ = pz + a * proj.fRayZ;
+
+ delete[] projs;
+}
+
+void CParallelProjectionGeometry3D::backprojectPointZ(int iAngleIndex, double fU, double fV,
+ double fZ, double &fX, double &fY) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SPar3DProjection *projs = genPar3DProjections(1, m_iDetectorColCount, m_iDetectorRowCount,
+ m_fDetectorSpacingX, m_fDetectorSpacingY,
+ &m_pfProjectionAngles[iAngleIndex]);
+
+ SPar3DProjection &proj = projs[0];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fZ - pz) / proj.fRayZ;
+
+ fX = px + a * proj.fRayX;
+ fY = py + a * proj.fRayY;
+
+ delete[] projs;
+}
+
+
//----------------------------------------------------------------------------------------
} // end namespace astra
diff --git a/src/ParallelVecProjectionGeometry3D.cpp b/src/ParallelVecProjectionGeometry3D.cpp
index ffad6d0..3172818 100644
--- a/src/ParallelVecProjectionGeometry3D.cpp
+++ b/src/ParallelVecProjectionGeometry3D.cpp
@@ -27,9 +27,9 @@ $Id$
*/
#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/Utilities.h"
#include <cstring>
-#include <boost/lexical_cast.hpp>
using namespace std;
@@ -82,13 +82,13 @@ bool CParallelVecProjectionGeometry3D::initialize(const Config& _cfg)
// Required: DetectorRowCount
node = _cfg.self.getSingleNode("DetectorRowCount");
ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No DetectorRowCount tag specified.");
- m_iDetectorRowCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorRowCount = node.getContentInt();
CC.markNodeParsed("DetectorRowCount");
// Required: DetectorCount
node = _cfg.self.getSingleNode("DetectorColCount");
ASTRA_CONFIG_CHECK(node, "", "No DetectorColCount tag specified.");
- m_iDetectorColCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorColCount = node.getContentInt();
m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount;
CC.markNodeParsed("DetectorColCount");
@@ -212,18 +212,18 @@ Config* CParallelVecProjectionGeometry3D::getConfiguration() const
std::string vectors = "";
for (int i = 0; i < m_iProjectionAngleCount; ++i) {
SPar3DProjection& p = m_pProjectionAngles[i];
- vectors += boost::lexical_cast<string>(p.fRayX) + ",";
- vectors += boost::lexical_cast<string>(p.fRayY) + ",";
- vectors += boost::lexical_cast<string>(p.fRayZ) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSX + 0.5f*m_iDetectorRowCount*p.fDetVX + 0.5f*m_iDetectorColCount*p.fDetUX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSY + 0.5f*m_iDetectorRowCount*p.fDetVY + 0.5f*m_iDetectorColCount*p.fDetUY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetSZ + 0.5f*m_iDetectorRowCount*p.fDetVZ + 0.5f*m_iDetectorColCount*p.fDetUZ) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetUZ) + ",";
- vectors += boost::lexical_cast<string>(p.fDetVX) + ",";
- vectors += boost::lexical_cast<string>(p.fDetVY) + ",";
- vectors += boost::lexical_cast<string>(p.fDetVZ);
+ vectors += StringUtil::toString(p.fRayX) + ",";
+ vectors += StringUtil::toString(p.fRayY) + ",";
+ vectors += StringUtil::toString(p.fRayZ) + ",";
+ vectors += StringUtil::toString(p.fDetSX + 0.5f*m_iDetectorRowCount*p.fDetVX + 0.5f*m_iDetectorColCount*p.fDetUX) + ",";
+ vectors += StringUtil::toString(p.fDetSY + 0.5f*m_iDetectorRowCount*p.fDetVY + 0.5f*m_iDetectorColCount*p.fDetUY) + ",";
+ vectors += StringUtil::toString(p.fDetSZ + 0.5f*m_iDetectorRowCount*p.fDetVZ + 0.5f*m_iDetectorColCount*p.fDetUZ) + ",";
+ vectors += StringUtil::toString(p.fDetUX) + ",";
+ vectors += StringUtil::toString(p.fDetUY) + ",";
+ vectors += StringUtil::toString(p.fDetUZ) + ",";
+ vectors += StringUtil::toString(p.fDetVX) + ",";
+ vectors += StringUtil::toString(p.fDetVY) + ",";
+ vectors += StringUtil::toString(p.fDetVZ);
if (i < m_iProjectionAngleCount-1) vectors += ';';
}
cfg->self.addChildNode("Vectors", vectors);
@@ -239,9 +239,9 @@ CVector3D CParallelVecProjectionGeometry3D::getProjectionDirection(int _iProject
return CVector3D(p.fRayX, p.fRayY, p.fRayZ);
}
-void CParallelVecProjectionGeometry3D::projectPoint(float32 fX, float32 fY, float32 fZ,
- int iAngleIndex,
- float32 &fU, float32 &fV) const
+void CParallelVecProjectionGeometry3D::projectPoint(double fX, double fY, double fZ,
+ int iAngleIndex,
+ double &fU, double &fV) const
{
ASTRA_ASSERT(iAngleIndex >= 0);
ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
@@ -258,6 +258,61 @@ void CParallelVecProjectionGeometry3D::projectPoint(float32 fX, float32 fY, floa
}
+void CParallelVecProjectionGeometry3D::backprojectPointX(int iAngleIndex, double fU, double fV,
+ double fX, double &fY, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SPar3DProjection &proj = m_pProjectionAngles[iAngleIndex];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fX - px) / proj.fRayX;
+
+ fY = py + a * proj.fRayY;
+ fZ = pz + a * proj.fRayZ;
+}
+
+void CParallelVecProjectionGeometry3D::backprojectPointY(int iAngleIndex, double fU, double fV,
+ double fY, double &fX, double &fZ) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SPar3DProjection &proj = m_pProjectionAngles[iAngleIndex];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fY - py) / proj.fRayY;
+
+ fX = px + a * proj.fRayX;
+ fZ = pz + a * proj.fRayZ;
+}
+
+void CParallelVecProjectionGeometry3D::backprojectPointZ(int iAngleIndex, double fU, double fV,
+ double fZ, double &fX, double &fY) const
+{
+ ASTRA_ASSERT(iAngleIndex >= 0);
+ ASTRA_ASSERT(iAngleIndex < m_iProjectionAngleCount);
+
+ SPar3DProjection &proj = m_pProjectionAngles[iAngleIndex];
+
+ double px = proj.fDetSX + fU * proj.fDetUX + fV * proj.fDetVX;
+ double py = proj.fDetSY + fU * proj.fDetUY + fV * proj.fDetVY;
+ double pz = proj.fDetSZ + fU * proj.fDetUZ + fV * proj.fDetVZ;
+
+ double a = (fZ - pz) / proj.fRayZ;
+
+ fX = px + a * proj.fRayX;
+ fY = py + a * proj.fRayY;
+}
+
+
//----------------------------------------------------------------------------------------
bool CParallelVecProjectionGeometry3D::_check()
diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp
new file mode 100644
index 0000000..1bcfbdb
--- /dev/null
+++ b/src/PluginAlgorithm.cpp
@@ -0,0 +1,36 @@
+/*
+-----------------------------------------------------------------------
+Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp
+ 2014-2015, CWI, Amsterdam
+
+Contact: astra@uantwerpen.be
+Website: http://sf.net/projects/astra-toolbox
+
+This file is part of the ASTRA Toolbox.
+
+
+The ASTRA Toolbox is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+The ASTRA Toolbox is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/PluginAlgorithm.h"
+
+namespace astra {
+
+CPluginAlgorithmFactory *CPluginAlgorithmFactory::m_factory = 0;
+
+}
+
diff --git a/src/ProjectionGeometry2D.cpp b/src/ProjectionGeometry2D.cpp
index da93b9c..03fbd22 100644
--- a/src/ProjectionGeometry2D.cpp
+++ b/src/ProjectionGeometry2D.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ProjectionGeometry2D.h"
-#include <boost/lexical_cast.hpp>
-
using namespace std;
namespace astra
@@ -123,13 +121,13 @@ bool CProjectionGeometry2D::initialize(const Config& _cfg)
// Required: DetectorWidth
XMLNode node = _cfg.self.getSingleNode("DetectorWidth");
ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorWidth tag specified.");
- m_fDetectorWidth = boost::lexical_cast<float32>(node.getContent());
+ m_fDetectorWidth = node.getContentNumerical();
CC.markNodeParsed("DetectorWidth");
// Required: DetectorCount
node = _cfg.self.getSingleNode("DetectorCount");
ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorCount tag specified.");
- m_iDetectorCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorCount = node.getContentInt();
CC.markNodeParsed("DetectorCount");
// Required: ProjectionAngles
diff --git a/src/ProjectionGeometry3D.cpp b/src/ProjectionGeometry3D.cpp
index ef0246c..281db7c 100644
--- a/src/ProjectionGeometry3D.cpp
+++ b/src/ProjectionGeometry3D.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ProjectionGeometry3D.h"
-#include <boost/lexical_cast.hpp>
-
using namespace std;
namespace astra
@@ -151,25 +149,25 @@ bool CProjectionGeometry3D::initialize(const Config& _cfg)
// Required: DetectorWidth
XMLNode node = _cfg.self.getSingleNode("DetectorSpacingX");
ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingX tag specified.");
- m_fDetectorSpacingX = boost::lexical_cast<float32>(node.getContent());
+ m_fDetectorSpacingX = node.getContentNumerical();
CC.markNodeParsed("DetectorSpacingX");
// Required: DetectorHeight
node = _cfg.self.getSingleNode("DetectorSpacingY");
ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingY tag specified.");
- m_fDetectorSpacingY = boost::lexical_cast<float32>(node.getContent());
+ m_fDetectorSpacingY = node.getContentNumerical();
CC.markNodeParsed("DetectorSpacingY");
// Required: DetectorRowCount
node = _cfg.self.getSingleNode("DetectorRowCount");
ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorRowCount tag specified.");
- m_iDetectorRowCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorRowCount = node.getContentInt();
CC.markNodeParsed("DetectorRowCount");
// Required: DetectorCount
node = _cfg.self.getSingleNode("DetectorColCount");
ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorColCount tag specified.");
- m_iDetectorColCount = boost::lexical_cast<int>(node.getContent());
+ m_iDetectorColCount = node.getContentInt();
m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount;
CC.markNodeParsed("DetectorColCount");
diff --git a/src/ReconstructionAlgorithm2D.cpp b/src/ReconstructionAlgorithm2D.cpp
index 767efe6..1c6d855 100644
--- a/src/ReconstructionAlgorithm2D.cpp
+++ b/src/ReconstructionAlgorithm2D.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ReconstructionAlgorithm2D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
using namespace std;
@@ -85,29 +83,36 @@ bool CReconstructionAlgorithm2D::initialize(const Config& _cfg)
// projector
XMLNode node = _cfg.self.getSingleNode("ProjectorId");
- ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
- m_pProjector = CProjector2DManager::getSingleton().get(id);
+ if (requiresProjector()) {
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified.");
+ }
+ int id;
+ if (node) {
+ id = node.getContentInt();
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ } else {
+ m_pProjector = 0;
+ }
CC.markNodeParsed("ProjectorId");
// sinogram data
node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("ProjectionDataId");
// reconstruction data
node = _cfg.self.getSingleNode("ReconstructionDataId");
ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
CC.markNodeParsed("ReconstructionDataId");
// fixed mask
if (_cfg.self.hasOption("ReconstructionMaskId")) {
m_bUseReconstructionMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("ReconstructionMaskId"));
+ id = _cfg.self.getOptionInt("ReconstructionMaskId");
m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
ASTRA_CONFIG_CHECK(m_pReconstructionMask, "Reconstruction2D", "Invalid ReconstructionMaskId.");
}
@@ -116,7 +121,7 @@ bool CReconstructionAlgorithm2D::initialize(const Config& _cfg)
// fixed mask
if (_cfg.self.hasOption("SinogramMaskId")) {
m_bUseSinogramMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("SinogramMaskId"));
+ id = _cfg.self.getOptionInt("SinogramMaskId");
m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
ASTRA_CONFIG_CHECK(m_pSinogramMask, "Reconstruction2D", "Invalid SinogramMaskId.");
}
@@ -205,18 +210,22 @@ void CReconstructionAlgorithm2D::setSinogramMask(CFloat32ProjectionData2D* _pMas
bool CReconstructionAlgorithm2D::_check()
{
// check pointers
- ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object.");
+ if (requiresProjector())
+ ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object.");
ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction2D", "Invalid Projection Data Object.");
ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction2D", "Invalid Reconstruction Data Object.");
// check initializations
- ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized.");
+ if (requiresProjector())
+ ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized.");
ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction2D", "Projection Data Object Not Initialized.");
ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction2D", "Reconstruction Data Object Not Initialized.");
// check compatibility between projector and data classes
- ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector.");
- ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector.");
+ if (requiresProjector()) {
+ ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector.");
+ }
// success
return true;
diff --git a/src/ReconstructionAlgorithm3D.cpp b/src/ReconstructionAlgorithm3D.cpp
index 86b8ab2..55f1031 100644
--- a/src/ReconstructionAlgorithm3D.cpp
+++ b/src/ReconstructionAlgorithm3D.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ReconstructionAlgorithm3D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
using namespace std;
@@ -106,33 +104,37 @@ bool CReconstructionAlgorithm3D::initialize(const Config& _cfg)
XMLNode node;
int id;
-#if 0
+
// projector
- node = _cfg.self->getSingleNode("ProjectorId");
- ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectorId tag specified.");
- id = boost::lexical_cast<int>(node->getContent());
- m_pProjector = CProjector3DManager::getSingleton().get(id);
- ASTRA_DELETE(node);
-#endif
+ node = _cfg.self.getSingleNode("ProjectorId");
+ m_pProjector = 0;
+ if (node) {
+ id = node.getContentInt();
+ m_pProjector = CProjector3DManager::getSingleton().get(id);
+ if (!m_pProjector) {
+ // TODO: Report
+ }
+ }
+ CC.markNodeParsed("ProjectorId");
// sinogram data
node = _cfg.self.getSingleNode("ProjectionDataId");
ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pSinogram = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("ProjectionDataId");
// reconstruction data
node = _cfg.self.getSingleNode("ReconstructionDataId");
ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ReconstructionDataId tag specified.");
- id = boost::lexical_cast<int>(node.getContent());
+ id = node.getContentInt();
m_pReconstruction = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id));
CC.markNodeParsed("ReconstructionDataId");
// fixed mask
if (_cfg.self.hasOption("ReconstructionMaskId")) {
m_bUseReconstructionMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("ReconstructionMaskId"));
+ id = _cfg.self.getOptionInt("ReconstructionMaskId");
m_pReconstructionMask = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id));
}
CC.markOptionParsed("ReconstructionMaskId");
@@ -140,9 +142,10 @@ bool CReconstructionAlgorithm3D::initialize(const Config& _cfg)
// fixed mask
if (_cfg.self.hasOption("SinogramMaskId")) {
m_bUseSinogramMask = true;
- id = boost::lexical_cast<int>(_cfg.self.getOption("SinogramMaskId"));
+ id = _cfg.self.getOptionInt("SinogramMaskId");
m_pSinogramMask = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id));
}
+ CC.markOptionParsed("SinogramMaskId");
// Constraints - NEW
if (_cfg.self.hasOption("MinConstraint")) {
diff --git a/src/ReconstructionAlgorithmMultiSlice2D.cpp b/src/ReconstructionAlgorithmMultiSlice2D.cpp
index fe64c86..39c337f 100644
--- a/src/ReconstructionAlgorithmMultiSlice2D.cpp
+++ b/src/ReconstructionAlgorithmMultiSlice2D.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/ReconstructionAlgorithmMultiSlice2D.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
using namespace std;
@@ -96,7 +94,7 @@ bool CReconstructionAlgorithmMultiSlice2D::initialize(const Config& _cfg)
// projector
XMLNode* node = _cfg.self->getSingleNode("ProjectorId");
ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified.");
- int id = boost::lexical_cast<int>(node->getContent());
+ int id = node->getContentInt();
m_pProjector = CProjector2DManager::getSingleton().get(id);
ASTRA_DELETE(node);
CC.markNodeParsed("ProjectorId");
@@ -125,7 +123,7 @@ bool CReconstructionAlgorithmMultiSlice2D::initialize(const Config& _cfg)
// reconstruction masks
if (_cfg.self->hasOption("ReconstructionMaskId")) {
m_bUseReconstructionMask = true;
- id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId"));
+ id = _cfg.self->getOptionInt("ReconstructionMaskId");
m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
}
CC.markOptionParsed("ReconstructionMaskId");
@@ -133,7 +131,7 @@ bool CReconstructionAlgorithmMultiSlice2D::initialize(const Config& _cfg)
// sinogram masks
if (_cfg.self->hasOption("SinogramMaskId")) {
m_bUseSinogramMask = true;
- id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId"));
+ id = _cfg.self->getOptionInt("SinogramMaskId");
m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
}
CC.markOptionParsed("SinogramMaskId");
diff --git a/src/SartAlgorithm.cpp b/src/SartAlgorithm.cpp
index e4dc5c7..8df3342 100644
--- a/src/SartAlgorithm.cpp
+++ b/src/SartAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/SartAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/DataProjectorPolicies.h"
@@ -153,6 +151,9 @@ bool CSartAlgorithm::initialize(const Config& _cfg)
CC.markOptionParsed("ProjectionOrderList");
}
+ m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f);
+ CC.markOptionParsed("Relaxation");
+
// create data objects
m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
@@ -248,6 +249,7 @@ map<string,boost::any> CSartAlgorithm::getInformation()
{
map<string, boost::any> res;
res["ProjectionOrder"] = getInformation("ProjectionOrder");
+ res["Relaxation"] = getInformation("Relaxation");
return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
};
@@ -255,6 +257,8 @@ map<string,boost::any> CSartAlgorithm::getInformation()
// Information - Specific
boost::any CSartAlgorithm::getInformation(std::string _sIdentifier)
{
+ if (_sIdentifier == "Relaxation")
+ return m_fLambda;
if (_sIdentifier == "ProjectionOrder") {
vector<float32> res;
for (int i = 0; i < m_iProjectionCount; i++) {
@@ -274,9 +278,8 @@ void CSartAlgorithm::run(int _iNrIterations)
m_bShouldAbort = false;
- int iIteration = 0;
-
// data projectors
+ CDataProjectorInterface* pFirstForwardProjector;
CDataProjectorInterface* pForwardProjector;
CDataProjectorInterface* pBackProjector;
@@ -288,13 +291,13 @@ void CSartAlgorithm::run(int _iNrIterations)
m_pProjector,
SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
- SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength), // SIRT backprojection
+ SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength, m_fLambda), // SIRT backprojection
m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
);
// first time forward projection data projector,
// also computes total pixel weight and total ray length
- pForwardProjector = dispatchDataProjector(
+ pFirstForwardProjector = dispatchDataProjector(
m_pProjector,
SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
@@ -305,16 +308,30 @@ void CSartAlgorithm::run(int _iNrIterations)
m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
);
+ // forward projection data projector
+ pForwardProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ CombinePolicy<DiffFPPolicy, TotalPixelWeightPolicy>( // 2 basic operations
+ DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation
+ TotalPixelWeightPolicy(m_pTotalPixelWeight)), // calculate the total pixel weights
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
// iteration loop
- for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) {
+ for (int iIteration = 0; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) {
int iProjection = m_piProjectionOrder[m_iIterationCount % m_iProjectionCount];
// forward projection and difference calculation
m_pTotalPixelWeight->setData(0.0f);
- pForwardProjector->projectSingleProjection(iProjection);
+ if (iIteration < m_iProjectionCount)
+ pFirstForwardProjector->projectSingleProjection(iProjection);
+ else
+ pForwardProjector->projectSingleProjection(iProjection);
// backprojection
pBackProjector->projectSingleProjection(iProjection);
// update iteration count
@@ -327,6 +344,7 @@ void CSartAlgorithm::run(int _iNrIterations)
}
+ ASTRA_DELETE(pFirstForwardProjector);
ASTRA_DELETE(pForwardProjector);
ASTRA_DELETE(pBackProjector);
diff --git a/src/SirtAlgorithm.cpp b/src/SirtAlgorithm.cpp
index ae3b3bc..ff25648 100644
--- a/src/SirtAlgorithm.cpp
+++ b/src/SirtAlgorithm.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/SirtAlgorithm.h"
-#include <boost/lexical_cast.hpp>
-
#include "astra/AstraObjectManager.h"
#include "astra/DataProjectorPolicies.h"
@@ -78,6 +76,7 @@ void CSirtAlgorithm::_clear()
m_pDiffSinogram = NULL;
m_pTmpVolume = NULL;
+ m_fLambda = 1.0f;
m_iIterationCount = 0;
}
@@ -93,6 +92,7 @@ void CSirtAlgorithm::clear()
ASTRA_DELETE(m_pDiffSinogram);
ASTRA_DELETE(m_pTmpVolume);
+ m_fLambda = 1.0f;
m_iIterationCount = 0;
}
@@ -130,6 +130,9 @@ bool CSirtAlgorithm::initialize(const Config& _cfg)
return false;
}
+ m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f);
+ CC.markOptionParsed("Relaxation");
+
// init data objects and data projectors
_init();
@@ -154,6 +157,8 @@ bool CSirtAlgorithm::initialize(CProjector2D* _pProjector,
m_pSinogram = _pSinogram;
m_pReconstruction = _pReconstruction;
+ m_fLambda = 1.0f;
+
// init data objects and data projectors
_init();
@@ -250,7 +255,7 @@ void CSirtAlgorithm::run(int _iNrIterations)
x = 1.0f / x;
else
x = 0.0f;
- pfT[i] = x;
+ pfT[i] = m_fLambda * x;
}
pfT = m_pTotalRayLength->getData();
for (int i = 0; i < m_pTotalRayLength->getSize(); ++i) {
@@ -298,7 +303,7 @@ void CSirtAlgorithm::run(int _iNrIterations)
m_pTmpVolume->setData(0.0f);
pBackProjector->project();
- // divide by pixel weights
+ // multiply with relaxation factor divided by pixel weights
(*m_pTmpVolume) *= (*m_pTotalPixelWeight);
(*m_pReconstruction) += (*m_pTmpVolume);
diff --git a/src/SparseMatrixProjectionGeometry2D.cpp b/src/SparseMatrixProjectionGeometry2D.cpp
index 073720f..358c992 100644
--- a/src/SparseMatrixProjectionGeometry2D.cpp
+++ b/src/SparseMatrixProjectionGeometry2D.cpp
@@ -28,7 +28,6 @@ $Id$
#include "astra/SparseMatrixProjectionGeometry2D.h"
-#include <boost/lexical_cast.hpp>
#include "astra/AstraObjectManager.h"
@@ -100,7 +99,7 @@ bool CSparseMatrixProjectionGeometry2D::initialize(const Config& _cfg)
// get matrix
XMLNode node = _cfg.self.getSingleNode("MatrixID");
ASTRA_CONFIG_CHECK(node, "SparseMatrixProjectionGeometry2D", "No MatrixID tag specified.");
- int id = boost::lexical_cast<int>(node.getContent());
+ int id = node.getContentInt();
m_pMatrix = CMatrixManager::getSingleton().get(id);
CC.markNodeParsed("MatrixID");
diff --git a/src/SparseMatrixProjector2D.cpp b/src/SparseMatrixProjector2D.cpp
index bc2e974..be7e069 100644
--- a/src/SparseMatrixProjector2D.cpp
+++ b/src/SparseMatrixProjector2D.cpp
@@ -29,7 +29,6 @@ $Id$
#include "astra/SparseMatrixProjector2D.h"
#include <cmath>
-#include <boost/lexical_cast.hpp>
#include "astra/DataProjectorPolicies.h"
diff --git a/src/Utilities.cpp b/src/Utilities.cpp
index 3f65e9a..c9740bf 100644
--- a/src/Utilities.cpp
+++ b/src/Utilities.cpp
@@ -28,101 +28,99 @@ $Id$
#include "astra/Utilities.h"
-using namespace std;
-using namespace astra;
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
-//-----------------------------------------------------------------------------
-// Trim Whitespace Characters
-void StringUtil::trim(std::string& _sString, bool _bLeft, bool _bRight)
+#include <sstream>
+#include <locale>
+#include <iomanip>
+
+namespace astra {
+
+namespace StringUtil {
+
+int stringToInt(const std::string& s)
{
- // trim right
- if (_bRight)
- _sString.erase(_sString.find_last_not_of(" \t\r") + 1);
+ int i;
+ std::istringstream iss(s);
+ iss.imbue(std::locale::classic());
+ iss >> i;
+ if (iss.fail() || !iss.eof())
+ throw bad_cast();
+ return i;
- // trim left
- if (_bLeft)
- _sString.erase(0, _sString.find_first_not_of(" \t\r"));
}
-//-----------------------------------------------------------------------------
-// Split String
-vector<string> StringUtil::split(const string& _sString, const string& _sDelims)
+
+float stringToFloat(const std::string& s)
{
- std::vector<string> ret;
-
- size_t start, pos;
- start = 0;
- do {
- pos = _sString.find_first_of(_sDelims, start);
- if (pos == start) {
- // Do nothing
- start = pos + 1;
- } else if (pos == string::npos) {
- // Copy the rest of the string
- ret.push_back(_sString.substr(start));
- break;
- } else {
- // Copy up to newt delimiter
- ret.push_back(_sString.substr(start, pos - start));
- start = pos + 1;
- }
-
- // Parse up to next real data (in case there are two delims after each other)
- start = _sString.find_first_not_of(_sDelims, start);
- } while (pos != string::npos);
-
- return ret;
+ return (float)stringToDouble(s);
}
-//-----------------------------------------------------------------------------
-// Cast string to int
-bool StringUtil::toInt(const string& _sString, int& _iValue)
+
+double stringToDouble(const std::string& s)
{
- std::istringstream ss(_sString);
- ss >> _iValue;
- return !ss.fail();
+ double f;
+ std::istringstream iss(s);
+ iss.imbue(std::locale::classic());
+ iss >> f;
+ if (iss.fail() || !iss.eof())
+ throw bad_cast();
+ return f;
}
-//-----------------------------------------------------------------------------
-// Cast string to float
-bool StringUtil::toFloat32(const string& _sString, float32& _fValue)
+
+template<> float stringTo(const std::string& s) { return stringToFloat(s); }
+template<> double stringTo(const std::string& s) { return stringToDouble(s); }
+
+std::vector<float> stringToFloatVector(const std::string &s)
{
- std::istringstream ss(_sString);
- ss >> _fValue;
- return !ss.fail();
+ return stringToVector<float>(s);
}
-//-----------------------------------------------------------------------------
-// Convert string to Lower Case
-void StringUtil::toLowerCase(std::string& _sString)
+
+std::vector<double> stringToDoubleVector(const std::string &s)
{
- std::transform(_sString.begin(),
- _sString.end(),
- _sString.begin(),
- ::tolower);
+ return stringToVector<double>(s);
}
-//-----------------------------------------------------------------------------
-// Convert string to Upper Case
-void StringUtil::toUpperCase(std::string& _sString)
+
+template<typename T>
+std::vector<T> stringToVector(const std::string& s)
{
- std::transform(_sString.begin(),
- _sString.end(),
- _sString.begin(),
- ::toupper);
-}
-//-----------------------------------------------------------------------------
+ // split
+ std::vector<std::string> items;
+ boost::split(items, s, boost::is_any_of(",;"));
+ // init list
+ std::vector<T> out;
+ out.resize(items.size());
+ // loop elements
+ for (unsigned int i = 0; i < items.size(); i++) {
+ out[i] = stringTo<T>(items[i]);
+ }
+ return out;
+}
-//-----------------------------------------------------------------------------
-// Get Extension
-string FileSystemUtil::getExtension(string& _sFilename)
+std::string floatToString(float f)
{
- string sExtension = "";
- for (int i = _sFilename.length() - 1; 0 < i; i--) {
- if (_sFilename[i] == '.') {
- std::transform(sExtension.begin(),sExtension.end(),sExtension.begin(),::tolower);
- return sExtension;
- }
- sExtension = _sFilename[i] + sExtension;
- }
- return "";
+ std::ostringstream s;
+ s.imbue(std::locale::classic());
+ s << std::setprecision(9) << f;
+ return s.str();
+}
+
+std::string doubleToString(double f)
+{
+ std::ostringstream s;
+ s.imbue(std::locale::classic());
+ s << std::setprecision(17) << f;
+ return s.str();
+}
+
+
+template<> std::string toString(float f) { return floatToString(f); }
+template<> std::string toString(double f) { return doubleToString(f); }
+
+
+}
+
}
-//-----------------------------------------------------------------------------
diff --git a/src/VolumeGeometry2D.cpp b/src/VolumeGeometry2D.cpp
index 6eea1b2..9d74e47 100644
--- a/src/VolumeGeometry2D.cpp
+++ b/src/VolumeGeometry2D.cpp
@@ -28,7 +28,6 @@ $Id$
#include "astra/VolumeGeometry2D.h"
-#include <boost/lexical_cast.hpp>
#include <cmath>
namespace astra
@@ -166,13 +165,13 @@ bool CVolumeGeometry2D::initialize(const Config& _cfg)
// Required: GridColCount
XMLNode node = _cfg.self.getSingleNode("GridColCount");
ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified.");
- m_iGridColCount = boost::lexical_cast<int>(node.getContent());
+ m_iGridColCount = node.getContentInt();
CC.markNodeParsed("GridColCount");
// Required: GridRowCount
node = _cfg.self.getSingleNode("GridRowCount");
ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified.");
- m_iGridRowCount = boost::lexical_cast<int>(node.getContent());
+ m_iGridRowCount = node.getContentInt();
CC.markNodeParsed("GridRowCount");
// Optional: Window minima and maxima
diff --git a/src/VolumeGeometry3D.cpp b/src/VolumeGeometry3D.cpp
index a1cf424..5d72c24 100644
--- a/src/VolumeGeometry3D.cpp
+++ b/src/VolumeGeometry3D.cpp
@@ -28,8 +28,6 @@ $Id$
#include "astra/VolumeGeometry3D.h"
-#include <boost/lexical_cast.hpp>
-
namespace astra
{
@@ -45,6 +43,7 @@ bool CVolumeGeometry3D::_check()
ASTRA_CONFIG_CHECK(m_fWindowMinZ < m_fWindowMaxZ, "VolumeGeometry3D", "WindowMinZ should be lower than WindowMaxZ.");
ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error.");
+#if 0
ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry3D", "Internal configuration error.");
ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry3D", "Internal configuration error.");
ASTRA_CONFIG_CHECK(m_fWindowLengthZ == (m_fWindowMaxZ - m_fWindowMinZ), "VolumeGeometry3D", "Internal configuration error.");
@@ -57,6 +56,7 @@ bool CVolumeGeometry3D::_check()
ASTRA_CONFIG_CHECK(m_fDivPixelLengthX == (1.0f / m_fPixelLengthX), "VolumeGeometry3D", "Internal configuration error.");
ASTRA_CONFIG_CHECK(m_fDivPixelLengthY == (1.0f / m_fPixelLengthY), "VolumeGeometry3D", "Internal configuration error.");
ASTRA_CONFIG_CHECK(m_fDivPixelLengthZ == (1.0f / m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error.");
+#endif
return true;
}
@@ -194,19 +194,19 @@ bool CVolumeGeometry3D::initialize(const Config& _cfg)
// Required: GridColCount
XMLNode node = _cfg.self.getSingleNode("GridColCount");
ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified.");
- m_iGridColCount = boost::lexical_cast<int>(node.getContent());
+ m_iGridColCount = node.getContentInt();
CC.markNodeParsed("GridColCount");
// Required: GridRowCount
node = _cfg.self.getSingleNode("GridRowCount");
ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified.");
- m_iGridRowCount = boost::lexical_cast<int>(node.getContent());
+ m_iGridRowCount = node.getContentInt();
CC.markNodeParsed("GridRowCount");
// Required: GridRowCount
node = _cfg.self.getSingleNode("GridSliceCount");
ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridSliceCount tag specified.");
- m_iGridSliceCount = boost::lexical_cast<int>(node.getContent());
+ m_iGridSliceCount = node.getContentInt();
CC.markNodeParsed("GridSliceCount");
// Optional: Window minima and maxima
diff --git a/src/XMLNode.cpp b/src/XMLNode.cpp
index 0ec701f..cf268c2 100644
--- a/src/XMLNode.cpp
+++ b/src/XMLNode.cpp
@@ -31,12 +31,6 @@ $Id$
#include "rapidxml/rapidxml.hpp"
#include "rapidxml/rapidxml_print.hpp"
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/split.hpp>
-#include <boost/algorithm/string/classification.hpp>
-
-
using namespace rapidxml;
using namespace astra;
@@ -138,8 +132,13 @@ string XMLNode::getContent() const
// Get node content - NUMERICAL
float32 XMLNode::getContentNumerical() const
{
- return boost::lexical_cast<float32>(getContent());
+ return StringUtil::stringToFloat(getContent());
}
+int XMLNode::getContentInt() const
+{
+ return StringUtil::stringToInt(getContent());
+}
+
//-----------------------------------------------------------------------------
// Get node content - BOOLEAN
@@ -154,12 +153,12 @@ bool XMLNode::getContentBool() const
vector<string> XMLNode::getContentArray() const
{
// get listsize
- int iSize = boost::lexical_cast<int>(getAttribute("listsize"));
+ int iSize = StringUtil::stringToInt(getAttribute("listsize"));
// create result array
vector<string> res(iSize);
// loop all list item nodes
list<XMLNode> nodes = getNodes("ListItem");
- for (list<XMLNode>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ for (list<XMLNode>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
int iIndex = it->getAttributeNumerical("index");
string sValue = it->getAttribute("value");
ASTRA_ASSERT(iIndex < iSize);
@@ -175,40 +174,12 @@ vector<string> XMLNode::getContentArray() const
// NB: A 2D matrix is returned as a linear list
vector<float32> XMLNode::getContentNumericalArray() const
{
- string input = getContent();
-
- // split
- std::vector<std::string> items;
- boost::split(items, input, boost::is_any_of(",;"));
-
- // init list
- vector<float32> out;
- out.resize(items.size());
-
- // loop elements
- for (unsigned int i = 0; i < items.size(); i++) {
- out[i] = boost::lexical_cast<float32>(items[i]);
- }
- return out;
+ return StringUtil::stringToFloatVector(getContent());
}
vector<double> XMLNode::getContentNumericalArrayDouble() const
{
- string input = getContent();
-
- // split
- std::vector<std::string> items;
- boost::split(items, input, boost::is_any_of(",;"));
-
- // init list
- vector<double> out;
- out.resize(items.size());
-
- // loop elements
- for (unsigned int i = 0; i < items.size(); i++) {
- out[i] = boost::lexical_cast<double>(items[i]);
- }
- return out;
+ return StringUtil::stringToDoubleVector(getContent());
}
//-----------------------------------------------------------------------------
@@ -235,14 +206,20 @@ string XMLNode::getAttribute(string _sName, string _sDefaultValue) const
float32 XMLNode::getAttributeNumerical(string _sName, float32 _fDefaultValue) const
{
if (!hasAttribute(_sName)) return _fDefaultValue;
- return boost::lexical_cast<float32>(getAttribute(_sName));
+ return StringUtil::stringToFloat(getAttribute(_sName));
}
double XMLNode::getAttributeNumericalDouble(string _sName, double _fDefaultValue) const
{
if (!hasAttribute(_sName)) return _fDefaultValue;
- return boost::lexical_cast<double>(getAttribute(_sName));
+ return StringUtil::stringToDouble(getAttribute(_sName));
+}
+int XMLNode::getAttributeInt(string _sName, int _iDefaultValue) const
+{
+ if (!hasAttribute(_sName)) return _iDefaultValue;
+ return StringUtil::stringToInt(getAttribute(_sName));
}
+
//-----------------------------------------------------------------------------
// Get attribute - BOOLEAN
bool XMLNode::getAttributeBool(string _sName, bool _bDefaultValue) const
@@ -287,9 +264,15 @@ string XMLNode::getOption(string _sKey, string _sDefaultValue) const
float32 XMLNode::getOptionNumerical(string _sKey, float32 _fDefaultValue) const
{
if (!hasOption(_sKey)) return _fDefaultValue;
- return boost::lexical_cast<float32>(getOption(_sKey));
+ return StringUtil::stringToFloat(getOption(_sKey));
+}
+int XMLNode::getOptionInt(string _sKey, int _iDefaultValue) const
+{
+ if (!hasOption(_sKey)) return _iDefaultValue;
+ return StringUtil::stringToInt(getOption(_sKey));
}
+
//-----------------------------------------------------------------------------
// Get option - BOOL
bool XMLNode::getOptionBool(string _sKey, bool _bDefaultValue) const
@@ -307,7 +290,7 @@ vector<float32> XMLNode::getOptionNumericalArray(string _sKey) const
if (!hasOption(_sKey)) return vector<float32>();
list<XMLNode> nodes = getNodes("Option");
- for (list<XMLNode>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ for (list<XMLNode>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
if (it->getAttribute("key") == _sKey) {
vector<float32> vals = it->getContentNumericalArray();
return vals;
@@ -386,7 +369,7 @@ void XMLNode::setContent(string _sText)
// Set content - FLOAT
void XMLNode::setContent(float32 _fValue)
{
- setContent(boost::lexical_cast<string>(_fValue));
+ setContent(StringUtil::floatToString(_fValue));
}
//-----------------------------------------------------------------------------
@@ -394,9 +377,9 @@ void XMLNode::setContent(float32 _fValue)
template<typename T>
static std::string setContentList_internal(T* pfList, int _iSize) {
- std::string str = (_iSize > 0) ? boost::lexical_cast<std::string>(pfList[0]) : "";
+ std::string str = (_iSize > 0) ? StringUtil::toString(pfList[0]) : "";
for (int i = 1; i < _iSize; i++) {
- str += "," + boost::lexical_cast<std::string>(pfList[i]);
+ str += "," + StringUtil::toString(pfList[i]);
}
return str;
}
@@ -431,9 +414,9 @@ static std::string setContentMatrix_internal(T* _pfMatrix, int _iWidth, int _iHe
for (int y = 0; y < _iHeight; ++y) {
if (_iWidth > 0)
- str += boost::lexical_cast<std::string>(_pfMatrix[0*s1 + y*s2]);
+ str += StringUtil::toString(_pfMatrix[0*s1 + y*s2]);
for (int x = 1; x < _iWidth; x++)
- str += "," + boost::lexical_cast<std::string>(_pfMatrix[x*s1 + y*s2]);
+ str += "," + StringUtil::toString(_pfMatrix[x*s1 + y*s2]);
if (y != _iHeight-1)
str += ";";
@@ -468,7 +451,7 @@ void XMLNode::addAttribute(string _sName, string _sText)
// Add attribute - FLOAT
void XMLNode::addAttribute(string _sName, float32 _fValue)
{
- addAttribute(_sName, boost::lexical_cast<string>(_fValue));
+ addAttribute(_sName, StringUtil::floatToString(_fValue));
}
//-----------------------------------------------------------------------------