Line data Source code
1 : #include "LimitedAngleTrajectoryGenerator.h" 2 : #include "VolumeDescriptor.h" 3 : #include "PlanarDetectorDescriptor.h" 4 : #include "Logger.h" 5 : 6 : #include <stdexcept> 7 : 8 : namespace elsa 9 : { 10 0 : std::unique_ptr<DetectorDescriptor> LimitedAngleTrajectoryGenerator::createTrajectory( 11 : index_t numberOfPoses, 12 : std::pair<elsa::geometry::Degree, elsa::geometry::Degree> missingWedgeAngles, 13 : const DataDescriptor& volumeDescriptor, index_t arcDegrees, real_t sourceToCenter, 14 : real_t centerToDetector, bool mirrored) 15 : { 16 : // pull in geometry namespace, to reduce cluttering 17 : using namespace geometry; 18 : 19 : // sanity check 20 0 : const auto dim = volumeDescriptor.getNumberOfDimensions(); 21 0 : if (dim != 2) { 22 0 : throw InvalidArgumentError("LimitedAngleTrajectoryGenerator: can only handle 2D"); 23 : } 24 : 25 0 : Logger::get("LimitedAngleTrajectoryGenerator") 26 0 : ->info("creating 2D trajectory with {} poses in an {} degree arc", numberOfPoses, 27 : arcDegrees); 28 : 29 0 : const auto [coeffs, spacing] = 30 0 : calculateSizeAndSpacingPerGeometry(volumeDescriptor, numberOfPoses); 31 : 32 : // create vector and reserve the necessary size, minor optimization such that no new 33 : // allocations are necessary in the loop 34 0 : std::vector<Geometry> geometryList; 35 0 : geometryList.reserve(static_cast<std::size_t>(numberOfPoses)); 36 : 37 0 : real_t wedgeArc = mirrored ? 2 * (missingWedgeAngles.second - missingWedgeAngles.first) 38 0 : : missingWedgeAngles.second - missingWedgeAngles.first; 39 : 40 0 : const real_t angleIncrement = 41 0 : (static_cast<real_t>(arcDegrees) - wedgeArc) / (static_cast<real_t>(numberOfPoses)); 42 : 43 0 : for (index_t i = 0;; ++i) { 44 0 : Radian angle = Degree{static_cast<real_t>(i) * angleIncrement}; 45 : 46 0 : if (angle.to_degree() >= static_cast<real_t>(arcDegrees)) { 47 0 : break; 48 : } 49 : 50 0 : if (notInMissingWedge(angle, missingWedgeAngles, mirrored)) { 51 : // use emplace_back, then no copy is created 52 0 : geometryList.emplace_back(SourceToCenterOfRotation{sourceToCenter}, 53 0 : CenterOfRotationToDetector{centerToDetector}, 54 0 : Radian{angle}, 55 0 : VolumeData2D{volumeDescriptor.getSpacingPerDimension(), 56 0 : volumeDescriptor.getLocationOfOrigin()}, 57 0 : SinogramData2D{Size2D{coeffs}, Spacing2D{spacing}}); 58 : } 59 0 : } 60 : 61 0 : return std::make_unique<PlanarDetectorDescriptor>(coeffs, spacing, geometryList); 62 0 : } 63 : 64 0 : bool LimitedAngleTrajectoryGenerator::notInMissingWedge( 65 : elsa::geometry::Radian angle, 66 : std::pair<elsa::geometry::Degree, elsa::geometry::Degree> missingWedgeAngles, bool mirrored) 67 : { 68 0 : if (!mirrored) { 69 0 : return !(angle.to_degree() >= missingWedgeAngles.first 70 0 : && angle.to_degree() <= missingWedgeAngles.second); 71 : } else { 72 0 : return !((angle.to_degree() >= missingWedgeAngles.first 73 0 : && angle.to_degree() <= missingWedgeAngles.second) 74 0 : || (angle.to_degree() >= (missingWedgeAngles.first + 180) 75 0 : && angle.to_degree() <= (missingWedgeAngles.second + 180))); 76 : } 77 : } 78 : } // namespace elsa