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

          Line data    Source code
       1             : #include "BaseCircleTrajectoryGenerator.h"
       2             : #include "Logger.h"
       3             : #include "TypeCasts.hpp"
       4             : #include "VolumeDescriptor.h"
       5             : 
       6             : #include <algorithm>
       7             : #include <optional>
       8             : #include <stdexcept>
       9             : 
      10             : namespace elsa
      11             : {
      12             :     std::tuple<IndexVector_t, RealVector_t, std::vector<Geometry>>
      13             :         BaseCircleTrajectoryGenerator::createTrajectoryData(
      14             :             const std::vector<real_t>& thetas, const DataDescriptor& volumeDescriptor,
      15             :             real_t sourceToCenter, real_t centerToDetector,
      16             :             std::optional<RealVector_t> principalPointOffset,
      17             :             std::optional<RealVector_t> centerOfRotOffset,
      18             :             std::optional<IndexVector_t> detectorSize, std::optional<RealVector_t> detectorSpacing)
      19          20 :     {
      20             :         // pull in geometry namespace, to reduce cluttering
      21          20 :         using namespace geometry;
      22             : 
      23             :         // sanity check
      24          20 :         const auto dim = volumeDescriptor.getNumberOfDimensions();
      25             : 
      26          20 :         if (dim < 2 || dim > 3)
      27           0 :             throw InvalidArgumentError("CircleTrajectoryGenerator: can only handle 2d/3d");
      28             : 
      29          20 :         const auto numberOfPoses = asSigned(thetas.size());
      30          20 :         const auto arc = *std::max_element(thetas.begin(), thetas.end());
      31          20 :         Logger::get("CircleTrajectoryGenerator")
      32          20 :             ->info("creating {}D trajectory with {} poses in an {} degree arc", dim, numberOfPoses,
      33          20 :                    arc);
      34             : 
      35             :         // Calculate size and spacing for each geometry pose using a IIFE
      36          20 :         const auto [coeffs, spacing] = calculateSizeAndSpacingPerGeometry(
      37          20 :             volumeDescriptor, numberOfPoses, detectorSize, detectorSpacing);
      38             : 
      39             :         // Create vector and reserve the necessary size, minor optimization such that no new
      40             :         // allocations are necessary in the loop
      41          20 :         std::vector<Geometry> geometryList;
      42          20 :         geometryList.reserve(asUnsigned(numberOfPoses));
      43             : 
      44        1620 :         for (auto degree : thetas) {
      45        1620 :             const auto angle = Degree{degree}.to_radian();
      46        1620 :             if (dim == 2) {
      47             :                 // Use emplace_back, then no copy is created
      48        1108 :                 geometryList.emplace_back(
      49        1108 :                     SourceToCenterOfRotation{sourceToCenter},
      50        1108 :                     CenterOfRotationToDetector{centerToDetector}, Radian{angle},
      51        1108 :                     VolumeData2D{volumeDescriptor.getSpacingPerDimension(),
      52        1108 :                                  volumeDescriptor.getLocationOfOrigin()},
      53        1108 :                     SinogramData2D{Size2D{coeffs}, Spacing2D{spacing}},
      54        1108 :                     principalPointOffset ? PrincipalPointOffset{principalPointOffset.value()[0]}
      55        1108 :                                          : PrincipalPointOffset{0},
      56        1108 :                     centerOfRotOffset ? RotationOffset2D{centerOfRotOffset.value()}
      57        1108 :                                       : RotationOffset2D{0, 0});
      58        1108 :             } else {
      59         512 :                 geometryList.emplace_back(
      60         512 :                     SourceToCenterOfRotation{sourceToCenter},
      61         512 :                     CenterOfRotationToDetector{centerToDetector},
      62         512 :                     VolumeData3D{volumeDescriptor.getSpacingPerDimension(),
      63         512 :                                  volumeDescriptor.getLocationOfOrigin()},
      64         512 :                     SinogramData3D{Size3D{coeffs}, Spacing3D{spacing}},
      65         512 :                     RotationAngles3D{Radian{angle}, Radian{0}, Radian{0}},
      66         512 :                     principalPointOffset ? PrincipalPointOffset2D{principalPointOffset.value()}
      67         512 :                                          : PrincipalPointOffset2D{0, 0},
      68         512 :                     centerOfRotOffset ? RotationOffset3D{centerOfRotOffset.value()}
      69         512 :                                       : RotationOffset3D{0, 0, 0});
      70         512 :             }
      71        1620 :         }
      72             : 
      73          20 :         return std::make_tuple(std::move(coeffs), std::move(spacing), std::move(geometryList));
      74          20 :     }
      75             : } // namespace elsa

Generated by: LCOV version 1.14