LCOV - code coverage report
Current view: top level - elsa/generators - LimitedAngleTrajectoryGenerator.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 42 44 95.5 %
Date: 2024-05-16 04:22:26 Functions: 2 2 100.0 %

          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             :     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           4 :     {
      16             :         // pull in geometry namespace, to reduce cluttering
      17           4 :         using namespace geometry;
      18             : 
      19             :         // sanity check
      20           4 :         const auto dim = volumeDescriptor.getNumberOfDimensions();
      21           4 :         if (dim != 2) {
      22           0 :             throw InvalidArgumentError("LimitedAngleTrajectoryGenerator: can only handle 2D");
      23           0 :         }
      24             : 
      25           4 :         Logger::get("LimitedAngleTrajectoryGenerator")
      26           4 :             ->info("creating 2D trajectory with {} poses in an {} degree arc", numberOfPoses,
      27           4 :                    arcDegrees);
      28             : 
      29           4 :         const auto [coeffs, spacing] =
      30           4 :             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           4 :         std::vector<Geometry> geometryList;
      35           4 :         geometryList.reserve(static_cast<std::size_t>(numberOfPoses));
      36             : 
      37           4 :         real_t wedgeArc = mirrored ? 2 * (missingWedgeAngles.second - missingWedgeAngles.first)
      38           4 :                                    : missingWedgeAngles.second - missingWedgeAngles.first;
      39             : 
      40           4 :         const real_t angleIncrement =
      41           4 :             (static_cast<real_t>(arcDegrees) - wedgeArc) / (static_cast<real_t>(numberOfPoses));
      42             : 
      43        1679 :         for (index_t i = 0;; ++i) {
      44        1679 :             Radian angle = Degree{static_cast<real_t>(i) * angleIncrement};
      45             : 
      46        1679 :             if (angle.to_degree() >= static_cast<real_t>(arcDegrees)) {
      47           4 :                 break;
      48           4 :             }
      49             : 
      50        1675 :             if (notInMissingWedge(angle, missingWedgeAngles, mirrored)) {
      51             :                 // use emplace_back, then no copy is created
      52        1281 :                 geometryList.emplace_back(SourceToCenterOfRotation{sourceToCenter},
      53        1281 :                                           CenterOfRotationToDetector{centerToDetector},
      54        1281 :                                           Radian{angle},
      55        1281 :                                           VolumeData2D{volumeDescriptor.getSpacingPerDimension(),
      56        1281 :                                                        volumeDescriptor.getLocationOfOrigin()},
      57        1281 :                                           SinogramData2D{Size2D{coeffs}, Spacing2D{spacing}});
      58        1281 :             }
      59        1675 :         }
      60             : 
      61           4 :         return std::make_unique<PlanarDetectorDescriptor>(coeffs, spacing, geometryList);
      62           4 :     }
      63             : 
      64             :     bool LimitedAngleTrajectoryGenerator::notInMissingWedge(
      65             :         elsa::geometry::Radian angle,
      66             :         std::pair<elsa::geometry::Degree, elsa::geometry::Degree> missingWedgeAngles, bool mirrored)
      67        1675 :     {
      68        1675 :         if (!mirrored) {
      69         577 :             return !(angle.to_degree() >= missingWedgeAngles.first
      70         577 :                      && angle.to_degree() <= missingWedgeAngles.second);
      71        1098 :         } else {
      72        1098 :             return !((angle.to_degree() >= missingWedgeAngles.first
      73        1098 :                       && angle.to_degree() <= missingWedgeAngles.second)
      74        1098 :                      || (angle.to_degree() >= (missingWedgeAngles.first + 180)
      75         805 :                          && angle.to_degree() <= (missingWedgeAngles.second + 180)));
      76        1098 :         }
      77        1675 :     }
      78             : } // namespace elsa

Generated by: LCOV version 1.14