bool CCudaForwardProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, 
                                  CFloat32ProjectionData3DMemory* _pProjections, 
                                  CFloat32VolumeData3DMemory* _pVolume,
                                  int _iGPUindex, int _iDetectorSuperSampling)
{
	m_pProjector = _pProjector;
	
	// required classes
	m_pProjections = _pProjections;
	m_pVolume = _pVolume;

	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();

	if (!m_bIsInitialized)
		return false;

	return true;
}
//---------------------------------------------------------------------------------------
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 CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg)
{
	ASTRA_ASSERT(_cfg.self);
	ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm3D", this, _cfg);	

	// if already initialized, clear first
	if (m_bIsInitialized) {
		clear();
	}

	// initialization of parent class
	if (!CReconstructionAlgorithm3D::initialize(_cfg)) {
		return false;
	}

	CCudaProjector3D* pCudaProjector = 0;
	pCudaProjector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
	if (!pCudaProjector) {
		// TODO: Report
	}

	m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", -1);
	CC.markOptionParsed("GPUindex");


	m_iVoxelSuperSampling = 1;
	if (pCudaProjector)
		m_iVoxelSuperSampling = pCudaProjector->getVoxelSuperSampling();
	m_iVoxelSuperSampling = (int)_cfg.self.getOptionNumerical("VoxelSuperSampling", m_iVoxelSuperSampling);
	CC.markOptionParsed("VoxelSuperSampling");

	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");
	}

	// success
	m_bIsInitialized = _check();
	return m_bIsInitialized;
}
//----------------------------------------------------------------------------------------
// Run
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 CVolumeGeometry3D& volgeom = *m_pVolume->getGeometry();

	Cuda3DProjectionKernel projKernel = ker3d_default;
	if (m_pProjector) {
		CCudaProjector3D* projector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
		projKernel = projector->getProjectionKernel();
	}

#if 0
	// Debugging code that gives the coordinates of the corners of the volume
	// projected on the detector.
	{
		float fX[] = { volgeom.getWindowMinX(), volgeom.getWindowMaxX() };
		float fY[] = { volgeom.getWindowMinY(), volgeom.getWindowMaxY() };
		float fZ[] = { volgeom.getWindowMinZ(), volgeom.getWindowMaxZ() };

		for (int a = 0; a < projgeom->getProjectionCount(); ++a)
		for (int i = 0; i < 2; ++i)
		for (int j = 0; j < 2; ++j)
		for (int k = 0; k < 2; ++k) {
			float fU, fV;
			projgeom->projectPoint(fX[i], fY[j], fZ[k], a, fU, fV);
			ASTRA_DEBUG("%3d %c1,%c1,%c1 -> %12f %12f", a, i ? ' ' : '-', j ? ' ' : '-', k ? ' ' : '-', fU, fV);
		}
	}
#endif

	astraCudaFP(m_pVolume->getDataConst(), m_pProjections->getData(),
	            &volgeom, projgeom,
	            m_iGPUIndex, m_iDetectorSuperSampling, projKernel);
#endif
}