+ double* pdThetaValuesForT = new double [pProjNew->nView()];
+ double* pdRaysumsForT = new double [pProjNew->nView()];
+
+ // interpolate to evenly spaced theta (views)
+ double dDetPos = pProjNew->m_detStart;
+ for (int iD = 0; iD < pProjNew->nDet(); iD++, dDetPos += pProjNew->m_detInc) {
+ parallel.getThetaAndRaysumsForT (iD, pdThetaValuesForT, pdRaysumsForT);
+
+ double dViewAngle = m_rotStart;
+ int iLastFloor = -1;
+ for (int iV = 0; iV < pProjNew->nView(); iV++, dViewAngle += pProjNew->m_rotInc) {
+ DetectorValue* detValues = pProjNew->getDetectorArray (iV).detValues();
+
+ detValues[iD] = parallel.interpolate (pdThetaValuesForT, pdRaysumsForT, pProjNew->nView(), dViewAngle, &iLastFloor);
+ }
+ }
+ delete pdThetaValuesForT;
+ delete pdRaysumsForT;
+
+ // interpolate to evenly space t (detectors)
+ double* pdOriginalDetPositions = new double [pProjNew->nDet()];
+ parallel.getDetPositions (pdOriginalDetPositions);
+
+ double* pdDetValueCopy = new double [pProjNew->nDet()];
+ double dViewAngle = m_rotStart;
+ for (int iV = 0; iV < pProjNew->nView(); iV++, dViewAngle += pProjNew->m_rotInc) {
+ DetectorArray& detArray = pProjNew->getDetectorArray (iV);
+ DetectorValue* detValues = detArray.detValues();
+ detArray.setViewAngle (dViewAngle);
+
+ for (int i = 0; i < pProjNew->nDet(); i++)
+ pdDetValueCopy[i] = detValues[i];
+
+ double dDetPos = pProjNew->m_detStart;
+ int iLastFloor = -1;
+ for (int iD = 0; iD < pProjNew->nDet(); iD++, dDetPos += pProjNew->m_detInc) {
+ detValues[iD] = parallel.interpolate (pdOriginalDetPositions, pdDetValueCopy, pProjNew->nDet(), dDetPos, &iLastFloor);
+ }
+ }
+ delete pdDetValueCopy;
+ delete pdOriginalDetPositions;
+
+ return pProjNew;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Class ParallelRaysums
+//
+// Used for converting divergent beam raysums into Parallel raysums
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ParallelRaysums::ParallelRaysums (const Projections* pProjections, int iThetaRange)
+: m_iNumCoordinates(0), m_iNumView(pProjections->nView()), m_iNumDet(pProjections->nDet()),
+ m_iThetaRange (iThetaRange), m_pCoordinates(NULL)
+{
+ int iGeometry = pProjections->geometry();
+ double dDetInc = pProjections->detInc();
+ double dDetStart = pProjections->detStart();
+ double dFocalLength = pProjections->focalLength();
+
+ m_iNumCoordinates = m_iNumView * m_iNumDet;
+ m_pCoordinates = new ParallelRaysumCoordinate [m_iNumCoordinates];
+ m_vecpCoordinates.reserve (m_iNumCoordinates);
+ for (int i = 0; i < m_iNumCoordinates; i++)
+ m_vecpCoordinates[i] = m_pCoordinates + i;
+
+ int iCoordinate = 0;
+ for (int iV = 0; iV < m_iNumView; iV++) {
+ double dViewAngle = pProjections->getDetectorArray(iV).viewAngle();
+ const DetectorValue* detValues = pProjections->getDetectorArray(iV).detValues();
+
+ double dDetPos = dDetStart;
+ for (int iD = 0; iD < m_iNumDet; iD++) {
+ ParallelRaysumCoordinate* pC = m_vecpCoordinates[iCoordinate++];
+
+ if (iGeometry == Scanner::GEOMETRY_PARALLEL) {
+ pC->m_dTheta = dViewAngle;
+ pC->m_dT = dDetPos;
+ } else if (iGeometry == Scanner::GEOMETRY_EQUILINEAR) {
+ double dFanAngle = atan (dDetPos / pProjections->sourceDetectorLength());
+ pC->m_dTheta = dViewAngle + dFanAngle;
+ pC->m_dT = dFocalLength * sin(dFanAngle);
+
+ } else if (iGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
+ // fan angle is same as dDetPos
+ pC->m_dTheta = dViewAngle + dDetPos;
+ pC->m_dT = dFocalLength * sin (dDetPos);
+ }
+ if (m_iThetaRange != THETA_RANGE_UNCONSTRAINED) {
+ pC->m_dTheta = normalizeAngle (pC->m_dTheta);
+ if (m_iThetaRange == THETA_RANGE_FOLD_TO_PI && pC->m_dTheta >= PI) {
+ pC->m_dTheta -= PI;
+ pC->m_dT = -pC->m_dT;
+ }
+ }
+ pC->m_dRaysum = detValues[iD];
+ dDetPos += dDetInc;
+ }
+ }
+}
+
+ParallelRaysums::~ParallelRaysums()
+{
+ delete m_pCoordinates;
+}
+
+ParallelRaysums::CoordinateContainer&
+ParallelRaysums::getSortedByTheta()
+{
+ if (m_vecpSortedByTheta.size() == 0) {
+ m_vecpSortedByTheta.resize (m_iNumCoordinates);
+ for (int i = 0; i < m_iNumCoordinates; i++)
+ m_vecpSortedByTheta[i] = m_vecpCoordinates[i];
+ std::sort (m_vecpSortedByTheta.begin(), m_vecpSortedByTheta.end(), ParallelRaysumCoordinate::compareByTheta);
+ }
+
+ return m_vecpSortedByTheta;
+}
+
+ParallelRaysums::CoordinateContainer&
+ParallelRaysums::getSortedByT()
+{
+ if (m_vecpSortedByT.size() == 0) {
+ m_vecpSortedByT.resize (m_iNumCoordinates);
+ for (int i = 0; i < m_iNumCoordinates; i++)
+ m_vecpSortedByT[i] = m_vecpCoordinates[i];
+ std::sort (m_vecpSortedByT.begin(), m_vecpSortedByT.end(), ParallelRaysumCoordinate::compareByT);
+ }
+
+ return m_vecpSortedByT;
+}
+
+
+void
+ParallelRaysums::getLimits (double* dMinT, double* dMaxT, double* dMinTheta, double* dMaxTheta) const
+{
+ if (m_iNumCoordinates <= 0)
+ return;
+
+ *dMinT = *dMaxT = m_vecpCoordinates[0]->m_dT;
+ *dMinTheta = *dMaxTheta = m_vecpCoordinates[0]->m_dTheta;
+
+ for (int i = 0; i < m_iNumCoordinates; i++) {
+ double dT = m_vecpCoordinates[i]->m_dT;
+ double dTheta = m_vecpCoordinates[i]->m_dTheta;
+
+ if (dT < *dMinT)
+ *dMinT = dT;
+ else if (dT > *dMaxT)
+ *dMaxT = dT;
+
+ if (dTheta < *dMinTheta)
+ *dMinTheta = dTheta;
+ else if (dTheta > *dMaxTheta)
+ *dMaxTheta = dTheta;
+ }