/* ----------------------------------------------------------------------- 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 . ----------------------------------------------------------------------- */ #define policy_weight(p,rayindex,volindex,weight) do { if (p.pixelPrior(volindex)) { p.addWeight(rayindex, volindex, weight); p.pixelPosterior(volindex); } } while (false) template void CFanFlatBeamLineKernelProjector2D::project(Policy& p) { projectBlock_internal(0, m_pProjectionGeometry->getProjectionAngleCount(), 0, m_pProjectionGeometry->getDetectorCount(), p); } template void CFanFlatBeamLineKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) { projectBlock_internal(_iProjection, _iProjection + 1, 0, m_pProjectionGeometry->getDetectorCount(), p); } template void CFanFlatBeamLineKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) { projectBlock_internal(_iProjection, _iProjection + 1, _iDetector, _iDetector + 1, p); } //---------------------------------------------------------------------------------------- // PROJECT BLOCK - vector projection geometry template void CFanFlatBeamLineKernelProjector2D::projectBlock_internal(int _iProjFrom, int _iProjTo, int _iDetFrom, int _iDetTo, Policy& p) { // get vector geometry const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry; if (dynamic_cast(m_pProjectionGeometry)) { pVecProjectionGeometry = dynamic_cast(m_pProjectionGeometry)->toVectorGeometry(); } else { pVecProjectionGeometry = dynamic_cast(m_pProjectionGeometry); } // precomputations const float32 pixelLengthX = m_pVolumeGeometry->getPixelLengthX(); const float32 pixelLengthY = m_pVolumeGeometry->getPixelLengthY(); const float32 inv_pixelLengthX = 1.0f / pixelLengthX; const float32 inv_pixelLengthY = 1.0f / pixelLengthY; const int colCount = m_pVolumeGeometry->getGridColCount(); const int rowCount = m_pVolumeGeometry->getGridRowCount(); const int detCount = pVecProjectionGeometry->getDetectorCount(); const float32 Ex = m_pVolumeGeometry->getWindowMinX() + pixelLengthX*0.5f; const float32 Ey = m_pVolumeGeometry->getWindowMaxY() - pixelLengthY*0.5f; // loop angles for (int iAngle = _iProjFrom; iAngle < _iProjTo; ++iAngle) { // variables float32 Dx, Dy, Rx, Ry, S, T, weight, c, r, deltac, deltar, offset, RxOverRy, RyOverRx; float32 lengthPerRow, lengthPerCol, invTminSTimesLengthPerRow, invTminSTimesLengthPerCol; int iVolumeIndex, iRayIndex, row, col, iDetector; const SFanProjection * proj = &pVecProjectionGeometry->getProjectionVectors()[iAngle]; // loop detectors for (iDetector = _iDetFrom; iDetector < _iDetTo; ++iDetector) { iRayIndex = iAngle * detCount + iDetector; // POLICY: RAY PRIOR if (!p.rayPrior(iRayIndex)) continue; Dx = proj->fDetSX + (iDetector+0.5f) * proj->fDetUX; Dy = proj->fDetSY + (iDetector+0.5f) * proj->fDetUY; Rx = proj->fSrcX - Dx; Ry = proj->fSrcY - Dy; bool vertical = fabs(Rx) < fabs(Ry); bool isin = false; // vertically if (vertical) { RxOverRy = Rx/Ry; lengthPerRow = pixelLengthX * sqrt(Rx*Rx + Ry*Ry) / abs(Ry); deltac = -pixelLengthY * RxOverRy * inv_pixelLengthX; S = 0.5f - 0.5f*fabs(RxOverRy); T = 0.5f + 0.5f*fabs(RxOverRy); invTminSTimesLengthPerRow = lengthPerRow / (T - S); // calculate c for row 0 c = (Dx + (Ey - Dy)*RxOverRy - Ex) * inv_pixelLengthX; // for each row for (row = 0; row < rowCount; ++row, c += deltac) { col = int(floor(c+0.5f)); if (col < -1 || col > colCount) { if (!isin) continue; else break; } offset = c - float32(col); // left if (offset < -S) { weight = (offset + T) * invTminSTimesLengthPerRow; iVolumeIndex = row * colCount + col - 1; if (col > 0) { policy_weight(p, iRayIndex, iVolumeIndex, lengthPerRow-weight); } iVolumeIndex++; if (col >= 0 && col < colCount) { policy_weight(p, iRayIndex, iVolumeIndex, weight); } } // right else if (S < offset) { weight = (offset - S) * invTminSTimesLengthPerRow; iVolumeIndex = row * colCount + col; if (col >= 0 && col < colCount) { policy_weight(p, iRayIndex, iVolumeIndex, lengthPerRow-weight); } iVolumeIndex++; if (col + 1 < colCount) { policy_weight(p, iRayIndex, iVolumeIndex, weight); } } // centre else if (col >= 0 && col < colCount) { iVolumeIndex = row * colCount + col; policy_weight(p, iRayIndex, iVolumeIndex, lengthPerRow); } isin = true; } } // horizontally else { RyOverRx = Ry/Rx; lengthPerCol = pixelLengthY * sqrt(Rx*Rx + Ry*Ry) / abs(Rx); deltar = -pixelLengthX * RyOverRx * inv_pixelLengthY; S = 0.5f - 0.5f*fabs(RyOverRx); T = 0.5f + 0.5f*fabs(RyOverRx); invTminSTimesLengthPerCol = lengthPerCol / (T - S); // calculate r for col 0 r = -(Dy + (Ex - Dx)*RyOverRx - Ey) * inv_pixelLengthY; // for each col for (col = 0; col < colCount; ++col, r += deltar) { row = int(floor(r+0.5f)); if (row < -1 || row > rowCount) { if (!isin) continue; else break; } offset = r - float32(row); // up if (offset < -S) { weight = (offset + T) * invTminSTimesLengthPerCol; iVolumeIndex = (row-1) * colCount + col; if (row > 0) { policy_weight(p, iRayIndex, iVolumeIndex, lengthPerCol-weight); } iVolumeIndex += colCount; if (row >= 0 && row < rowCount) { policy_weight(p, iRayIndex, iVolumeIndex, weight); } } // down else if (S < offset) { weight = (offset - S) * invTminSTimesLengthPerCol; iVolumeIndex = row * colCount + col; if (row >= 0 && row < rowCount) { policy_weight(p, iRayIndex, iVolumeIndex, lengthPerCol-weight); } iVolumeIndex += colCount; if (row + 1 < rowCount) { policy_weight(p, iRayIndex, iVolumeIndex, weight); } } // centre else if (row >= 0 && row < rowCount) { iVolumeIndex = row * colCount + col; policy_weight(p, iRayIndex, iVolumeIndex, lengthPerCol); } isin = true; } } // POLICY: RAY POSTERIOR p.rayPosterior(iRayIndex); } // end loop detector } // end loop angles // Delete created vec geometry if required if (dynamic_cast(m_pProjectionGeometry)) delete pVecProjectionGeometry; }