CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const float32& _fScalar)
{
	CVolumeGeometry3D * pThisGeometry = getGeometry();

	int iSliceCount = pThisGeometry->getGridSliceCount();

	for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
	{
		CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);

		for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
		{
			float32 fThisValue = pThisProjection->getData()[iDetectorIndex];

			fThisValue -= _fScalar;

			pThisProjection->getData()[iDetectorIndex] = fThisValue;
		}

		returnSliceZ(iSliceIndex, pThisProjection);

		delete pThisProjection;
	}

	return *this;
}
CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const float32& _fScalar)
{
	CProjectionGeometry3D * pThisGeometry = getGeometry();

	int iProjectionCount = pThisGeometry->getProjectionCount();

	for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
	{
		CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);

		for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
		{
			float32 fThisValue = pThisProjection->getData()[iDetectorIndex];

			fThisValue += _fScalar;

			pThisProjection->getData()[iDetectorIndex] = fThisValue;
		}

		returnProjection(iProjectionIndex, pThisProjection);

		delete pThisProjection;
	}

	return *this;
}
//----------------------------------------------------------------------------------------
// Fetch a projection
CFloat32VolumeData2D* CFloat32ProjectionData3DMemory::fetchProjection(int _iProjectionNr) const
{
	// fetch slice of the geometry
	CVolumeGeometry2D volGeom(m_pGeometry->getDetectorColCount(), m_pGeometry->getDetectorRowCount());
	// create new volume data
	CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom);
	// copy data
	int row, col;
	for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) {
		for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) {
			res->getData()[row*m_pGeometry->getDetectorColCount() + col] = 
				m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col];
		}
	}
	// return
	return res;
}
CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const CFloat32VolumeData3D& _data)
{
	CVolumeGeometry3D * pThisGeometry = getGeometry();

	int iSliceCount = pThisGeometry->getGridSliceCount();
#ifdef _DEBUG
	CVolumeGeometry3D * pDataGeometry = _data.getGeometry();
	int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount();
	int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount();

	ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount());
	ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount);
#endif

	for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
	{
		CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
		CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex);

		for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
		{
			float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
			float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];

			fThisValue -= fDataValue;

			pThisProjection->getData()[iDetectorIndex] = fThisValue;
		}

		returnSliceZ(iSliceIndex, pThisProjection);

		delete pThisProjection;
		delete pDataProjection;
	}

	return *this;
}
CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const CFloat32ProjectionData3D& _data)
{
	CProjectionGeometry3D * pThisGeometry = getGeometry();

	int iProjectionCount = pThisGeometry->getProjectionCount();
#ifdef _DEBUG
	CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
	int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
	int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();

	ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
	ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
#endif

	for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
	{
		CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
		CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);

		for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
		{
			float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
			float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];

			fThisValue -= fDataValue;

			pThisProjection->getData()[iDetectorIndex] = fThisValue;
		}

		returnProjection(iProjectionIndex, pThisProjection);

		delete pThisProjection;
		delete pDataProjection;
	}

	return *this;
}
/** astra_mex_data2d('change_geometry', id, geom);
 *
 * Change the associated geometry of a 2d data object (volume or sinogram)
 * id: identifier of the 2d data object as stored in the astra-library.
 * geom: the new geometry struct, as created by astra_create_vol/proj_geom
 */
void astra_mex_data2d_change_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{ 
	// step1: check input
	if (nrhs < 3) {
		mexErrMsgTxt("Not enough arguments.  See the help document for a detailed argument list. \n");
		return;
	}
	if (!mxIsDouble(prhs[1])) {
		mexErrMsgTxt("Identifier should be a scalar value. \n");
		return;
	}

	// step2: get data object
	int iDataID = (int)(mxGetScalar(prhs[1]));
	CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID);
	if (!pDataObject || !pDataObject->isInitialized()) {
		mexErrMsgTxt("Data object not found or not initialized properly.\n");
		return;
	}

	CFloat32ProjectionData2D* pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(pDataObject);

	if (pSinogram) {
		// Projection data

		// Read geometry
		if (!mxIsStruct(prhs[2])) {
			mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
		}
		XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]);
		Config cfg;
		cfg.self = xml->getRootNode();
		// FIXME: Change how the base class is created. (This is duplicated
		// in 'create' and Projector2D.cpp.)
		std::string type = cfg.self->getAttribute("type");
		CProjectionGeometry2D* pGeometry;
		if (type == "sparse_matrix") {
			pGeometry = new CSparseMatrixProjectionGeometry2D();
		} else if (type == "fanflat") {
			//CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D();
			//pFanFlatProjectionGeometry->initialize(Config(node));
			//m_pProjectionGeometry = pFanFlatProjectionGeometry;
			pGeometry = new CFanFlatProjectionGeometry2D();	
		} else if (type == "fanflat_vec") {
			pGeometry = new CFanFlatVecProjectionGeometry2D();	
		} else {
			pGeometry = new CParallelProjectionGeometry2D();	
		}
		if (!pGeometry->initialize(cfg)) {
			mexErrMsgTxt("Geometry class not initialized. \n");
			delete pGeometry;
			delete xml;
			return;
		}
		// If data is specified, check dimensions
		if (pGeometry->getDetectorCount() != pSinogram->getDetectorCount() || pGeometry->getProjectionAngleCount() != pSinogram->getAngleCount()) {
			mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
			delete pGeometry;
			delete xml;
			return;
		}

		// If ok, change geometry
		pSinogram->changeGeometry(pGeometry);
		delete pGeometry;
		delete xml;

		return;
	}

	CFloat32VolumeData2D* pVolume = dynamic_cast<CFloat32VolumeData2D*>(pDataObject);

	if (pVolume) {
		// Volume data

		// Read geometry
		if (!mxIsStruct(prhs[2])) {
			mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
		}
		XMLDocument* xml = struct2XML(string("VolumeGeometry"), prhs[2]);
		Config cfg;
		cfg.self = xml->getRootNode();
		CVolumeGeometry2D* pGeometry = new CVolumeGeometry2D();
		if (!pGeometry->initialize(cfg)) {
			mexErrMsgTxt("Geometry class not initialized. \n");
			delete xml;
			delete pGeometry;
			return;
		}
		// If data is specified, check dimensions
		if (pGeometry->getGridColCount() != pVolume->getWidth() || pGeometry->getGridRowCount() != pVolume->getHeight()) {
			mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
			delete xml;
			delete pGeometry;
			return;
		}

		// If ok, change geometry
		pVolume->changeGeometry(pGeometry);
		delete xml;
		delete pGeometry;

	}

	mexErrMsgTxt("Data object not found or not initialized properly.\n");
	return;
}