+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;
+ }
+}
+
+void
+ParallelRaysums::getThetaAndRaysumsForT (int iTheta, double* pTheta, double* pRaysum)
+{
+ const CoordinateContainer& coordsT = getSortedByT();
+
+ int iBase = iTheta * m_iNumView;
+ for (int i = 0; i < m_iNumView; i++) {
+ int iPos = iBase + i;
+ pTheta[i] = coordsT[iPos]->m_dTheta;
+ pRaysum[i] = coordsT[iPos]->m_dRaysum;
+ }
+}
+
+void
+ParallelRaysums::getDetPositions (double* pdDetPos)
+{
+ const CoordinateContainer& coordsT = getSortedByT();
+
+ int iPos = 0;
+ for (int i = 0; i < m_iNumDet; i++) {
+ pdDetPos[i] = coordsT[iPos]->m_dT;
+ iPos += m_iNumView;
+ }
+}
+
+// locate by bisection, O(log2(n))
+// iLastFloor is used when sequential calls to interpolate have monotonically increasing dX
+double
+ParallelRaysums::interpolate (double* pdX, double* pdY, int n, double dX, int* iLastFloor)
+{
+ int iLower = -1;
+ int iUpper = n;
+ if (iLastFloor && *iLastFloor >= 0 && pdX[*iLastFloor] < dX)
+ iLower = *iLastFloor;
+
+ while (iUpper - iLower > 1) {
+ int iMiddle = (iUpper + iLower) >> 1;
+ if (dX >= pdX[iMiddle])
+ iLower = iMiddle;
+ else
+ iUpper = iMiddle;
+ }
+ if (dX <= pdX[0])
+ return pdY[0];
+ else if (dX >= pdX[n-1])
+ return pdY[1];
+
+ if (iLower < 0 || iLower >= n) {
+ sys_error (ERR_SEVERE, "Coordinate out of range [locateThetaBase]");
+ return 0;
+ }
+
+ if (iLastFloor)
+ *iLastFloor = iLower;
+ return pdY[iLower] + (pdY[iUpper] - pdY[iLower]) * ((dX - pdX[iLower]) / (pdX[iUpper] - pdX[iLower]));