//----------------------------------------------------------------------------------------
// 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
}
//----------------------------------------------------------------------------------------
// Run
void CCudaForwardProjectionAlgorithm::run(int)
{
	// check initialized
	assert(m_bIsInitialized);

	CVolumeGeometry2D* pVolGeom = m_pVolume->getGeometry();
	const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry());
	const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry());
	const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry());

	bool ok = false;
	if (parProjGeom) {

		float *offsets, *angles, detSize, outputScale;
		ok = convertAstraGeometry(pVolGeom, parProjGeom, offsets, angles, detSize, outputScale);

		ASTRA_ASSERT(ok); // FIXME

		// FIXME: Output scaling

		ok = astraCudaFP(m_pVolume->getDataConst(), m_pSinogram->getData(),
		                 pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(),
		                 parProjGeom->getProjectionAngleCount(),
		                 parProjGeom->getDetectorCount(),
		                 angles, offsets, detSize,
		                 m_iDetectorSuperSampling, 1.0f * outputScale, m_iGPUIndex);

		delete[] offsets;
		delete[] angles;

	} else if (fanProjGeom || fanVecProjGeom) {

		astraCUDA::SFanProjection* projs;
		float outputScale;

		if (fanProjGeom) {
			ok = convertAstraGeometry(pVolGeom, fanProjGeom, projs, outputScale);
		} else {
			ok = convertAstraGeometry(pVolGeom, fanVecProjGeom, projs, outputScale);
		}

		ASTRA_ASSERT(ok);

		ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(),
		                    pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(),
		                    m_pSinogram->getGeometry()->getProjectionAngleCount(),
		                    m_pSinogram->getGeometry()->getDetectorCount(),
		                    projs,
		                    m_iDetectorSuperSampling, outputScale, m_iGPUIndex);

		delete[] projs;

	} else {

		ASTRA_ASSERT(false);

	}

	ASTRA_ASSERT(ok);

}