/*
-----------------------------------------------------------------------
Copyright: 2010-2021, imec Vision Lab, University of Antwerp
2014-2021, CWI, Amsterdam
Contact: astra@astra-toolbox.com
Website: http://www.astra-toolbox.com/
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 .
-----------------------------------------------------------------------
*/
#ifndef _INC_ASTRA_PROJECTIONGEOMETRY3D
#define _INC_ASTRA_PROJECTIONGEOMETRY3D
#include "Globals.h"
#include "Config.h"
#include "Vector3D.h"
#include
#include
#include
namespace astra
{
class XMLNode;
/**
* This class defines the interface for each 3D projection geometry.
* It has a number of data fields, such as width and height of detector
* pixels, projection angles and number of rows and columns of detector pixels.
*
* \par XML Configuration
* \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.}
* \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.}
* \astra_xml_item{DetectorWidth, float, Width of each detector.}
* \astra_xml_item{DetectorHeight, float, Width of each detector.}
* \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.}
*/
class _AstraExport CProjectionGeometry3D
{
protected:
/** Has the object been intialized with acceptable values?
*/
bool m_bInitialized;
/** Number of projection angles.
*/
int m_iProjectionAngleCount;
/** Number of rows of detectors.
*/
int m_iDetectorRowCount;
/** Number of columns of detectors.
*/
int m_iDetectorColCount;
/** Total number of detectors.
*/
int m_iDetectorTotCount;
/** The x-distance between projected rays on the detector plate (or width of projected strips).
*/
float32 m_fDetectorSpacingX;
/** The y-distance between projected rays on the detector plate (or height of projected strips).
*/
float32 m_fDetectorSpacingY;
/** Dynamically allocated array of projection angles. All angles are represented in radians and lie in
* the [0,2pi[ interval.
*/
float32* m_pfProjectionAngles;
/** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
*
* If an object is constructed using this default constructor, it must always be followed by a call
* to one of the initialize() methods before the object can be used. Any use before calling initialize()
* is not allowed, except calling the member function isInitialized().
*
*/
CProjectionGeometry3D();
/** Constructor. Create an instance of the CProjectionGeometry3D class.
*
* @param _iProjectionAngleCount Number of projection angles.
* @param _iDetectorRowCount Number of rows of detectors.
* @param _iDetectorColCount Number of columns detectors.
* @param _fDetectorSpacingX Spacing between the detector points on the X-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
* @param _fDetectorSpacingY Spacing between the detector points on the Y-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
* @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
* are represented in radians and lie in the [0,2pi[ interval.
*/
CProjectionGeometry3D(int _iProjectionAngleCount,
int _iDetectorRowCount,
int _iDetectorColCount,
float32 _fDetectorSpacingX,
float32 _fDetectorSpacingY,
const float32* _pfProjectionAngles);
/** Copy constructor.
*/
CProjectionGeometry3D(const CProjectionGeometry3D& _projGeom);
/** Check the values of this object. If everything is ok, the object can be set to the initialized state.
* The following statements are then guaranteed to hold:
* - number of rows and columns is larger than zero
* - detector spacing is larger than zero
* - number of angles is larger than zero
* - (autofix) each angle lies in [0,2pi[
*/
bool _check();
/** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
* Should only be used by constructors. Otherwise use the clear() function.
*/
void _clear();
/** Initialize the geometry. If the object has been initialized before, the object is reinitialized
* and memory is freed and reallocated if necessary.
*
* @param _iProjectionAngleCount Number of projection angles.
* @param _iDetectorRowCount Number of rows of detectors.
* @param _iDetectorColCount Number of columns detectors.
* @param _fDetectorSpacingX Spacing between the detector points on the X-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
* @param _fDetectorSpacingY Spacing between the detector points on the Y-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
* @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
* are represented in radians and lie in the [0,2pi[ interval.
*/
bool _initialize(int _iProjectionAngleCount,
int _iDetectorRowCount,
int _iDetectorColCount,
float32 _fDetectorSpacingX,
float32 _fDetectorSpacingY,
const float32* _pfProjectionAngles);
public:
/** Destructor
*/
virtual ~CProjectionGeometry3D();
/** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
*/
virtual void clear();
/** Create a hard copy.
*/
virtual CProjectionGeometry3D* clone() const = 0;
/** Initialize the geometry with a config object.
*
* @param _cfg Configuration Object
* @return initialization successful?
*/
virtual bool initialize(const Config& _cfg);
/** Get the initialization state of the object.
*
* @return true iff the object has been initialized
*/
bool isInitialized() const;
/** Return true if this geometry instance is the same as the one specified.
*
* @return true if this geometry instance is the same as the one specified.
*/
virtual bool isEqual(const CProjectionGeometry3D *) const = 0;
/** Get all settings in a Config object.
*
* @return Configuration Object.
*/
virtual Config* getConfiguration() const = 0;
/** Get the number of projections.
*
* @return Number of projections
*/
int getProjectionCount() const;
/** Get the number of rows of detectors.
*
* @return Number of rows of detectors.
*/
int getDetectorRowCount() const;
/** Get the number of columns of detectors.
*
* @return Number of columns of detectors.
*/
int getDetectorColCount() const;
/** Get the total number of detectors.
*
* @return Total number of detectors.
*/
int getDetectorTotCount() const;
/** Get the width of a detector.
*
* @return Width of a detector, in unit lengths
*/
float32 getDetectorSpacingX() const;
/** Get the height of a detector.
*
* @return Height of a detector, in unit lengths
*/
float32 getDetectorSpacingY() const;
/** Get a projection angle, given by its index. The angle is represented in Radians.
*
* @return Projection angle with index _iProjectionIndex
*/
float32 getProjectionAngle(int _iProjectionIndex) const;
/** Get a projection angle, given by its index. The angle is represented in degrees.
*
* @return Projection angle with index _iProjectionIndex
*/
// float32 getProjectionAngleDegrees(int _iProjectionIndex) const;
/** Returns a buffer containing all projection angles. The element count of the buffer is equal
* to the number given by getProjectionAngleCount.
*
* The angles are in radians.
*
* @return Pointer to buffer containing the angles.
*/
const float32* getProjectionAngles() const;
/** Get the column index coordinate of a point on a detector array.
*
* @param _fOffsetX Distance between the center of the detector array and a certain point (both on the X-axis).
* @return The location of the point in index X-coordinates (still float, not rounded)
*/
virtual float32 detectorOffsetXToColIndexFloat(float32 _fOffsetX) const;
/** Get the row index coordinate of a point on a detector array.
*
* @param _fOffsetY Distance between the center of the detector array and a certain point (both on the Y-axis).
* @return The location of the point in index Y-coordinates (still float, not rounded)
*/
virtual float32 detectorOffsetYToRowIndexFloat(float32 _fOffsetY) const;
/** Get the offset of a detector on the X-axis based on its index coordinate.
*
* @param _iIndex the index of the detector.
* @return the offset from the center of the detector array on the X-axis.
*/
virtual float32 indexToDetectorOffsetX(int _iIndex) const;
/** Get the offset of a detector on the Y-axis based on its index coordinate.
*
* @param _iIndex the index of the detector.
* @return the offset from the center of the detector array on the Y-axis.
*/
virtual float32 indexToDetectorOffsetY(int _iIndex) const;
/** Get the offset of a detector on the X-axis based on its column index coordinate.
*
* @param _iIndex the index of the detector.
* @return the offset from the center of the detector array on the X-axis.
*/
virtual float32 colIndexToDetectorOffsetX(int _iIndex) const;
/** Get the offset of a detector on the Y-axis based on its row index coordinate.
*
* @param _iIndex the index of the detector.
* @return the offset from the center of the detector array on the Y-axis.
*/
virtual float32 rowIndexToDetectorOffsetY(int _iIndex) const;
/** Get the row and column index of a detector based on its index.
*
* @param _iDetectorIndex in: the index of the detector.
* @param _iDetectorRow out: the row index of the detector.
* @param _iDetectorCol out: the column index of the detector.
*/
virtual void detectorIndexToRowCol(int _iDetectorIndex, int& _iDetectorRow, int& _iDetectorCol) const;
/** Get the angle and detector index of a detector
*
* @param _iIndex the index of the detector.
* @param _iAngleIndex output: index of angle
* @param _iDetectorIndex output: index of detector
*/
virtual void indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const;
/** Project a point onto the detector. The 3D point coordinates
* are in units. The output fU,fV are the (unrounded) indices of the
* detector column and row.
* This may fall outside of the actual detector.
*
* @param fX,fY,fZ coordinates of the point to project
* @param iAngleIndex the index of the angle to use
* @param fU,fV the projected point.
*/
virtual void projectPoint(double fX, double fY, double fZ,
int iAngleIndex,
double &fU, double &fV) const = 0;
/** Returns true if the type of geometry defined in this class is the one specified in _sType.
*
* @param _sType geometry type to compare to.
* @return true if the type of geometry defined in this class is the one specified in _sType.
*/
virtual bool isOfType(const std::string& _sType) const = 0;
/**
* Returns a vector giving the projection direction for a projection and detector index
*/
virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const = 0;
//< For Config unused argument checking
ConfigCheckData* configCheckData;
friend class ConfigStackCheck;
protected:
virtual bool initializeAngles(const Config& _cfg);
};
//----------------------------------------------------------------------------------------
// Inline member functions
//----------------------------------------------------------------------------------------
// Get the initialization state.
inline bool CProjectionGeometry3D::isInitialized() const
{
return m_bInitialized;
}
//----------------------------------------------------------------------------------------
// Get the number of detectors.
inline int CProjectionGeometry3D::getDetectorRowCount() const
{
ASTRA_ASSERT(m_bInitialized);
return m_iDetectorRowCount;
}
//----------------------------------------------------------------------------------------
// Get the number of detectors.
inline int CProjectionGeometry3D::getDetectorColCount() const
{
ASTRA_ASSERT(m_bInitialized);
return m_iDetectorColCount;
}
//----------------------------------------------------------------------------------------
// Get the number of detectors.
inline int CProjectionGeometry3D::getDetectorTotCount() const
{
ASTRA_ASSERT(m_bInitialized);
return m_iDetectorTotCount;
}
//----------------------------------------------------------------------------------------
// Get the width of a single detector (in unit lengths).
inline float32 CProjectionGeometry3D::getDetectorSpacingX() const
{
ASTRA_ASSERT(m_bInitialized);
return m_fDetectorSpacingX;
}
//----------------------------------------------------------------------------------------
// Get the width of a single detector (in unit lengths).
inline float32 CProjectionGeometry3D::getDetectorSpacingY() const
{
ASTRA_ASSERT(m_bInitialized);
return m_fDetectorSpacingY;
}
//----------------------------------------------------------------------------------------
// Get the number of projection angles.
inline int CProjectionGeometry3D::getProjectionCount() const
{
ASTRA_ASSERT(m_bInitialized);
return m_iProjectionAngleCount;
}
//----------------------------------------------------------------------------------------
// Get a projection angle, represented in Radians.
inline float32 CProjectionGeometry3D::getProjectionAngle(int _iProjectionIndex) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iProjectionIndex >= 0);
ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount);
return m_pfProjectionAngles[_iProjectionIndex];
}
/*
//----------------------------------------------------------------------------------------
// Get a projection angle, represented in degrees.
inline float32 CProjectionGeometry3D::getProjectionAngleDegrees(int _iProjectionIndex) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iProjectionIndex >= 0);
ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount);
return (m_pfProjectionAngles[_iProjectionIndex] * 180.0f / PI32);
}
*/
//----------------------------------------------------------------------------------------
// Get pointer to buffer used to store projection angles.
inline const float32* CProjectionGeometry3D::getProjectionAngles() const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
return m_pfProjectionAngles;
}
//----------------------------------------------------------------------------------------
// detector offset X -> detector column index (float)
inline float32 CProjectionGeometry3D::detectorOffsetXToColIndexFloat(float32 _fOffsetX) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
return (_fOffsetX / m_fDetectorSpacingX) + ((m_iDetectorColCount-1.0f) / 2.0f);
}
//----------------------------------------------------------------------------------------
// detector offset Y -> detector row index (float)
inline float32 CProjectionGeometry3D::detectorOffsetYToRowIndexFloat(float32 _fOffsetY) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
return (_fOffsetY / m_fDetectorSpacingY) + ((m_iDetectorRowCount-1.0f) / 2.0f);
}
//----------------------------------------------------------------------------------------
// detector index -> detector offset X
inline float32 CProjectionGeometry3D::indexToDetectorOffsetX(int _iIndex) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iIndex >= 0);
ASTRA_ASSERT(_iIndex < m_iDetectorTotCount);
_iIndex = _iIndex % m_iDetectorColCount;
return (_iIndex - (m_iDetectorColCount-1.0f) / 2.0f) * m_fDetectorSpacingX;
}
//----------------------------------------------------------------------------------------
// detector index -> detector offset Y
inline float32 CProjectionGeometry3D::indexToDetectorOffsetY(int _iIndex) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iIndex >= 0);
ASTRA_ASSERT(_iIndex < m_iDetectorTotCount);
_iIndex = _iIndex / m_iDetectorColCount;
return -(_iIndex - (m_iDetectorRowCount-1.0f) / 2.0f) * m_fDetectorSpacingY;
}
//----------------------------------------------------------------------------------------
// detector index -> detector offset X
inline float32 CProjectionGeometry3D::colIndexToDetectorOffsetX(int _iIndex) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iIndex >= 0);
ASTRA_ASSERT(_iIndex < m_iDetectorColCount);
return (_iIndex - (m_iDetectorColCount-1.0f) / 2.0f) * m_fDetectorSpacingX;
}
//----------------------------------------------------------------------------------------
// detector index -> detector offset Y
inline float32 CProjectionGeometry3D::rowIndexToDetectorOffsetY(int _iIndex) const
{
// basic checks
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iIndex >= 0);
ASTRA_ASSERT(_iIndex < m_iDetectorRowCount);
return (_iIndex - (m_iDetectorRowCount-1.0f) / 2.0f) * m_fDetectorSpacingY;
}
//----------------------------------------------------------------------------------------
// detector index -> row index & column index
inline void CProjectionGeometry3D::detectorIndexToRowCol(int _iDetectorIndex, int& _iDetectorRow, int& _iDetectorCol) const
{
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iDetectorIndex >= 0);
ASTRA_ASSERT(_iDetectorIndex < m_iDetectorTotCount);
_iDetectorRow = _iDetectorIndex / m_iDetectorColCount;
_iDetectorCol = _iDetectorIndex % m_iDetectorColCount;
}
//----------------------------------------------------------------------------------------
inline void CProjectionGeometry3D::indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const
{
ASTRA_ASSERT(m_bInitialized);
ASTRA_ASSERT(_iIndex >= 0);
ASTRA_ASSERT(_iIndex < m_iDetectorTotCount * m_iProjectionAngleCount);
// int det_row = _iIndex / (m_iDetectorColCount*m_iProjectionAngleCount);
// int det_col = _iIndex % m_iDetectorColCount;
//
// _iAngleIndex = _iIndex % (m_iDetectorColCount*m_iProjectionAngleCount) / m_iDetectorColCount;
// _iDetectorIndex = det_row * m_iDetectorColCount + det_col;
_iAngleIndex = (_iIndex % (m_iDetectorColCount*m_iProjectionAngleCount)) / m_iDetectorColCount;
_iDetectorIndex = _iIndex / m_iProjectionAngleCount + (_iIndex % m_iDetectorColCount);
}
//----------------------------------------------------------------------------------------
} // end namespace astra
#endif /* _INC_ASTRA_PROJECTIONGEOMETRY2D */