LCOV - code coverage report
Current view: top level - core - StrongTypes.h (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 0 115 0.0 %
Date: 2022-08-04 03:43:28 Functions: 0 181 0.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "elsaDefines.h"
       4             : #include "DataDescriptor.h"
       5             : #include "Error.h"
       6             : 
       7             : #include <utility>
       8             : #include <cassert>
       9             : #include <array>
      10             : 
      11             : namespace elsa
      12             : {
      13             :     namespace geometry
      14             :     {
      15             :         class Degree;
      16             : 
      17             :         /**
      18             :          * @brief Class describing angles in Radians. Mostly used for parameter passing.
      19             :          * Has an implicit constructor from Degree, and converts to real_t implicitly as well
      20             :          */
      21             :         class Radian
      22             :         {
      23             :         public:
      24             :             /// Default constructor (sets 0 radians)
      25             :             constexpr Radian() : _radian(0) {}
      26             : 
      27             :             /// Constructor from real_t
      28           0 :             constexpr explicit Radian(real_t radian) : _radian(radian) {}
      29             : 
      30             :             /// Constructor (implicit) from Degree
      31             :             constexpr Radian(Degree d);
      32             : 
      33             :             /// Conversion to degree (as real_t)
      34           0 :             constexpr real_t to_degree() const { return _radian * 180 / pi_t; }
      35             : 
      36             :             /// Conversion (implicit) to real_t
      37           0 :             constexpr operator real_t() const { return _radian; }
      38             : 
      39             :         private:
      40             :             real_t _radian;
      41             :         };
      42             : 
      43             :         /**
      44             :          * @brief Class describing angles in Degree. Mostly used for parameter passing.
      45             :          * Has an implicit constructor from Radians, and converts to real_t implicitly as well
      46             :          */
      47             :         class Degree
      48             :         {
      49             :         public:
      50             :             /// Default constructor (sets 0 degrees)
      51             :             constexpr Degree() : _degree(0) {}
      52             : 
      53             :             /// Constructor from real_t
      54           0 :             constexpr explicit Degree(real_t degree) : _degree(degree) {}
      55             : 
      56             :             /// Constructor (implicit) from Radian
      57             :             constexpr Degree(Radian r);
      58             : 
      59             :             /// Conversion to radian (as real_t)
      60           0 :             constexpr real_t to_radian() const { return _degree * pi_t / 180; }
      61             : 
      62             :             /// Conversion (implicit) to real_t
      63           0 :             constexpr operator real_t() const { return _degree; }
      64             : 
      65             :         private:
      66             :             real_t _degree;
      67             :         };
      68             : 
      69             :         // Defined out of class, to access the to_... functions
      70           0 :         constexpr Radian::Radian(Degree d) : _radian(d.to_radian()) {}
      71             :         constexpr Degree::Degree(Radian r) : _degree(r.to_degree()) {}
      72             : 
      73             :         /// Strong type class to a specific angle alpha
      74             :         class Alpha : Radian
      75             :         {
      76             :         public:
      77             :             using Base = Radian;
      78             : 
      79             :             using Base::Base;
      80             :             using Base::to_degree;
      81             :             using Base::operator real_t;
      82             :         };
      83             : 
      84             :         /// Strong type class to a specific angle beta
      85             :         class Beta : Radian
      86             :         {
      87             :         public:
      88             :             using Base = Radian;
      89             : 
      90             :             using Base::Base;
      91             :             using Base::to_degree;
      92             :             using Base::operator real_t;
      93             :         };
      94             : 
      95             :         /// Strong type class to a specific angle gamma
      96             :         class Gamma : Radian
      97             :         {
      98             :         public:
      99             :             using Base = Radian;
     100             : 
     101             :             using Base::Base;
     102             :             using Base::to_degree;
     103             :             using Base::operator real_t;
     104             :         };
     105             : 
     106             :         namespace detail
     107             :         {
     108             :             /**
     109             :              * @brief Class to store a fixed length array of Radians. Ensures, that all entries are
     110             :              * convertible to radians
     111             :              */
     112             :             template <index_t Size>
     113             :             class RotationAngles
     114             :             {
     115             :             public:
     116             :                 // Alias for Radian
     117             :                 using Type = Radian;
     118             : 
     119             :             private:
     120             :                 /// Alias for, enable if, all (the conjunction of) Ts... are convertible to Radian
     121             :                 template <typename... Ts>
     122             :                 using AllRadian = typename std::enable_if_t<
     123             :                     std::conjunction<std::is_convertible<Ts, Type>...>::value>;
     124             : 
     125             :             public:
     126             :                 RotationAngles(const RotationAngles&) = default;
     127             :                 RotationAngles& operator=(const RotationAngles&) = default;
     128             :                 RotationAngles(RotationAngles&&) = default;
     129             :                 RotationAngles& operator=(RotationAngles&&) = default;
     130             : 
     131             :                 /// Construct array (expect it to be all convertible to Radians and number of
     132             :                 /// arguments, equal to size)
     133             :                 template <typename... Ts, typename = AllRadian<Ts...>,
     134             :                           typename = std::enable_if_t<(Size > 0) && (Size == (sizeof...(Ts)))>>
     135           0 :                 constexpr RotationAngles(Ts&&... ts)
     136           0 :                     : RotationAngles(std::index_sequence_for<Ts...>{}, std::forward<Ts>(ts)...)
     137             :                 {
     138           0 :                 }
     139             : 
     140             :                 /// Access operator
     141           0 :                 constexpr Type operator[](index_t i) const
     142             :                 {
     143           0 :                     return _angles[static_cast<size_t>(i)];
     144             :                 }
     145             : 
     146             :                 /// get function (non-const reference) to enable structured bindings
     147             :                 template <size_t I>
     148             :                 Type& get() &
     149             :                 {
     150             :                     return (std::get<I>(_angles));
     151             :                 }
     152             : 
     153             :                 /// get function (const reference) to enable structured bindings
     154             :                 template <size_t I>
     155             :                 const Type& get() const&
     156             :                 {
     157             :                     return (std::get<I>(_angles));
     158             :                 }
     159             : 
     160             :                 /// get function (r-value reference) to enable structured bindings
     161             :                 template <size_t I>
     162           0 :                 Type&& get() &&
     163             :                 {
     164           0 :                     return std::move(std::get<I>(_angles));
     165             :                 }
     166             : 
     167             :             private:
     168             :                 /// Helper constructor to init array
     169             :                 template <std::size_t... Is, typename... Ts, typename = AllRadian<Ts...>>
     170           0 :                 constexpr RotationAngles(std::index_sequence<Is...>, Ts&&... vals)
     171           0 :                 {
     172             :                     // Fold expression expands to _angles[0] = vals0, _angles[1] = vals1, ...,
     173             :                     // _angles[k] = valsk;
     174           0 :                     (static_cast<void>(_angles[Is] = vals), ...);
     175           0 :                 }
     176             : 
     177             :                 std::array<Type, Size> _angles;
     178             :             };
     179             :         } // namespace detail
     180             : 
     181             :         /**
     182             :          * @brief Strong type class for 3D geometry, which expects 3 angles (alpha, beta, gamma).
     183             :          * Class is constructible from the previously defined Alpha, Beta, Gamma and only subsets of
     184             :          * it (i.e. only with Beta and Alpha)
     185             :          *
     186             :          */
     187             :         class RotationAngles3D : public detail::RotationAngles<3>
     188             :         {
     189             :         public:
     190             :             using Base = detail::RotationAngles<3>;
     191             : 
     192             :         private:
     193             :             using Base::Base;
     194             : 
     195             :         public:
     196             :             /// Construction from Gamma
     197           0 :             constexpr RotationAngles3D(Gamma gamma)
     198           0 :                 : Base(Radian{static_cast<real_t>(gamma)}, Radian{0}, Radian{0})
     199             :             {
     200           0 :             }
     201             : 
     202             :             /// Construction from Beta
     203             :             constexpr RotationAngles3D(Beta beta)
     204             :                 : Base(Radian{0}, Radian{static_cast<real_t>(beta)}, Radian{0})
     205             :             {
     206             :             }
     207             : 
     208             :             /// Construction from Alpha
     209             :             constexpr RotationAngles3D(Alpha alpha)
     210             :                 : Base(Radian{0}, Radian{0}, Radian{static_cast<real_t>(alpha)})
     211             :             {
     212             :             }
     213             : 
     214             :             /// Construction from Gamma and Beta
     215           0 :             constexpr RotationAngles3D(Gamma gamma, Beta beta)
     216           0 :                 : Base(Radian{static_cast<real_t>(gamma)}, Radian{static_cast<real_t>(beta)},
     217           0 :                        Radian{0})
     218             :             {
     219           0 :             }
     220             : 
     221             :             /// Construction from Gamma and Alpha
     222             :             constexpr RotationAngles3D(Gamma gamma, Alpha alpha)
     223             :                 : Base(Radian{static_cast<real_t>(gamma)}, Radian{0},
     224             :                        Radian{static_cast<real_t>(alpha)})
     225             :             {
     226             :             }
     227             : 
     228             :             /// Construction from Beta and Gamma
     229             :             constexpr RotationAngles3D(Beta beta, Gamma gamma) : RotationAngles3D(gamma, beta) {}
     230             : 
     231             :             /// Construction from Beta and Alpha
     232             :             constexpr RotationAngles3D(Beta beta, Alpha alpha)
     233             :                 : Base(Radian{0}, Radian{static_cast<real_t>(beta)},
     234             :                        Radian{static_cast<real_t>(alpha)})
     235             :             {
     236             :             }
     237             : 
     238             :             /// Construction from Alpha and Beta
     239             :             constexpr RotationAngles3D(Alpha alpha, Gamma gamma) : RotationAngles3D(gamma, alpha) {}
     240             : 
     241             :             /// Construction from Alpha and Gamma
     242             :             constexpr RotationAngles3D(Alpha alpha, Beta beta) : RotationAngles3D(beta, alpha) {}
     243             : 
     244             :             /// Construction from Gamma, Beta and Alpha
     245           0 :             constexpr RotationAngles3D(Gamma gamma, Beta beta, Alpha alpha)
     246           0 :                 : Base(Radian{static_cast<real_t>(gamma)}, Radian{static_cast<real_t>(beta)},
     247           0 :                        Radian{static_cast<real_t>(alpha)})
     248             :             {
     249           0 :             }
     250             : 
     251             :             /// Access to gamma
     252           0 :             constexpr Radian gamma() const { return operator[](0u); }
     253             :             /// Access to beta
     254           0 :             constexpr Radian beta() const { return operator[](1u); }
     255             :             /// Access to alpha
     256           0 :             constexpr Radian alpha() const { return operator[](2); }
     257             :         };
     258             : 
     259             :         namespace detail
     260             :         {
     261             :             /**
     262             :              * @brief Wrapper for real_t, used as base class for strong typing
     263             :              */
     264             :             class RealWrapper
     265             :             {
     266             :             public:
     267           0 :                 constexpr RealWrapper() : _x(0) {}
     268             : 
     269           0 :                 constexpr explicit RealWrapper(real_t x) : _x(x) {}
     270             : 
     271           0 :                 constexpr operator real_t() { return _x; }
     272             : 
     273             :             private:
     274             :                 real_t _x;
     275             :             };
     276             : 
     277             :             /**
     278             :              * @brief Class wrapping RealVector_t for strong typing, with a fixed size
     279             :              */
     280             :             template <index_t Size, typename Vector>
     281             :             class StaticVectorTemplate
     282             :             {
     283             :             private:
     284             :                 using Scalar = typename Vector::Scalar;
     285             : 
     286             :                 /// Alias for, enable if, all (the conjunction of) Ts... are convertible to Scalar
     287             :                 template <typename... Ts>
     288             :                 using AllScalar = typename std::enable_if_t<
     289             :                     std::conjunction<std::is_convertible<Ts, Scalar>...>::value>;
     290             : 
     291             :             public:
     292             :                 /// Default constructor
     293           0 :                 StaticVectorTemplate() : _vec(Size) {}
     294             : 
     295             :                 StaticVectorTemplate(const StaticVectorTemplate&) = default;
     296             :                 StaticVectorTemplate& operator=(const StaticVectorTemplate&) = default;
     297           0 :                 StaticVectorTemplate(StaticVectorTemplate&&) = default;
     298             :                 StaticVectorTemplate& operator=(StaticVectorTemplate&&) = default;
     299             : 
     300             :                 /// Construct array (expect it to be all convertible to Scalar and number of
     301             :                 /// arguments, equal to size)
     302             :                 template <typename... Ts, typename = AllScalar<Ts...>,
     303             :                           typename = std::enable_if_t<(Size > 0) && (Size == (sizeof...(Ts) + 1))>>
     304           0 :                 StaticVectorTemplate(Scalar x, Ts&&... ts) : _vec(Size)
     305             :                 {
     306             :                     // Fold expression, which expands to _vec << x, t1, t2, t3, ..., tn;
     307           0 :                     ((_vec << x), ..., static_cast<Scalar>(ts));
     308           0 :                 }
     309             : 
     310             :                 /// Constructor from Vector
     311           0 :                 StaticVectorTemplate(Vector vec) : _vec(vec)
     312             :                 {
     313           0 :                     if (_vec.size() != Size)
     314           0 :                         throw InvalidArgumentError(
     315             :                             "StaticVectorTemplate::Given argument vector is of the wrong size");
     316           0 :                 }
     317             : 
     318             :                 /// Access operator
     319           0 :                 Scalar operator[](index_t i) const { return _vec[i]; }
     320             : 
     321             :                 /// Access operator
     322           0 :                 Scalar& operator[](index_t i) { return _vec[i]; }
     323             : 
     324             :                 /// Conversion operator to Vector
     325           0 :                 operator Vector() const { return _vec; }
     326             : 
     327             :                 /// Conversion operator to Vector&& (rvalue reference)
     328           0 :                 operator Vector&&() { return std::move(_vec); }
     329             : 
     330             :                 /// Access to vector (const reference)
     331           0 :                 const Vector& get() & { return _vec; }
     332             : 
     333             :                 /// Access to vector (r-value reference)
     334           0 :                 Vector&& get() && { return std::move(_vec); }
     335             : 
     336             :             private:
     337             :                 Vector _vec;
     338             :             };
     339             : 
     340             :             template <index_t Size>
     341             :             using StaticRealVector = StaticVectorTemplate<Size, RealVector_t>;
     342             : 
     343             :             template <index_t Size>
     344             :             using StaticIndexVector = StaticVectorTemplate<Size, IndexVector_t>;
     345             :         } // namespace detail
     346             : 
     347             :         /// Strong Type for Geometry construction (Distance Source to Center of Rotation)
     348             :         class SourceToCenterOfRotation : detail::RealWrapper
     349             :         {
     350             :         public:
     351             :             using Base = detail::RealWrapper;
     352             : 
     353             :             using Base::Base;
     354             :             using Base::operator real_t;
     355             :         };
     356             : 
     357             :         /// Strong Type for Geometry construction (Distance Center of Rotation to Principal point)
     358             :         class CenterOfRotationToDetector : detail::RealWrapper
     359             :         {
     360             :         public:
     361             :             using Base = detail::RealWrapper;
     362             : 
     363             :             using Base::Base;
     364             :             using Base::operator real_t;
     365             :         };
     366             : 
     367             :         /// Strong Type for Geometry construction (1D Principal point offset)
     368             :         class PrincipalPointOffset : detail::RealWrapper
     369             :         {
     370             :         public:
     371             :             using Base = detail::RealWrapper;
     372             : 
     373             :             using Base::Base;
     374             :             using Base::operator real_t;
     375             :         };
     376             : 
     377             :         /// Strong Type for Geometry construction (2D Principal point offset)
     378             :         class PrincipalPointOffset2D : detail::StaticRealVector<2>
     379             :         {
     380             :         public:
     381             :             using Base = detail::StaticRealVector<2>;
     382             : 
     383             :             using Base::Base;
     384             :             using Base::operator[];
     385             :             using Base::operator=;
     386             :             // using Base::operator RealVector_t;
     387             :             using Base::get;
     388             :         };
     389             : 
     390             :         /// Strong Type for Geometry construction (nD Offset of Rotation axis)
     391             :         template <index_t Size>
     392             :         class RotationOffset : detail::StaticRealVector<Size>
     393             :         {
     394             :         public:
     395             :             using Base = detail::StaticRealVector<Size>;
     396             : 
     397             :             using Base::Base;
     398             :             using Base::operator[];
     399             :             using Base::operator=;
     400             :             // using Base::operator RealVector_t;
     401             :             using Base::get;
     402             :         };
     403             : 
     404             :         using RotationOffset1D = RotationOffset<1>; ///< Alias for 1D
     405             :         using RotationOffset2D = RotationOffset<2>; ///< Alias for 2D
     406             :         using RotationOffset3D = RotationOffset<3>; ///< Alias for 3D
     407             : 
     408             :         /// Strong Type for Geometry construction (nD Spacing)
     409             :         template <index_t Size>
     410             :         class Spacing : detail::StaticRealVector<Size>
     411             :         {
     412             :         public:
     413             :             using Base = detail::StaticRealVector<Size>;
     414             : 
     415             :             using Base::Base;
     416             :             using Base::operator[];
     417             :             using Base::operator=;
     418             :             // using Base::operator RealVector_t;
     419             :             using Base::get;
     420             :         };
     421             : 
     422             :         using Spacing1D = Spacing<1>; ///< Alias for 1D
     423             :         using Spacing2D = Spacing<2>; ///< Alias for 2D
     424             :         using Spacing3D = Spacing<3>; ///< Alias for 3D
     425             : 
     426             :         /// Strong type for Geometry construction (nD shift of origin)
     427             :         template <index_t Size>
     428             :         class OriginShift : detail::StaticRealVector<Size>
     429             :         {
     430             :         public:
     431             :             using Base = detail::StaticRealVector<Size>;
     432             : 
     433             :             using Base::Base;
     434             :             using Base::operator[];
     435             :             using Base::operator=;
     436             :             // using Base::operator RealVector_t;
     437             :             using Base::get;
     438             :         };
     439             : 
     440             :         using OriginShift1D = OriginShift<1>; ///< Alias for 1D
     441             :         using OriginShift2D = OriginShift<2>; ///< Alias for 2D
     442             :         using OriginShift3D = OriginShift<3>; ///< Alias for 3D
     443             : 
     444             :         /// Strong type for Geometry construction (nD coefficients)
     445             :         template <index_t Size>
     446             :         class Coefficients : detail::StaticIndexVector<Size>
     447             :         {
     448             :         public:
     449             :             using Base = detail::StaticIndexVector<Size>;
     450             : 
     451             :             using Base::Base;
     452             :             using Base::operator[];
     453             :             using Base::operator=;
     454             :             // using Base::operator IndexVector_t;
     455             :             using Base::get;
     456             :         };
     457             : 
     458             :         using Size1D = Coefficients<1>; ///< Alias for 1D
     459             :         using Size2D = Coefficients<2>; ///< Alias for 2D
     460             :         using Size3D = Coefficients<3>; ///< Alias for 3D
     461             : 
     462             :         namespace detail
     463             :         {
     464             :             /**
     465             :              * @brief Base type for strong typing volume and sinogram data
     466             :              *
     467             :              * @tparam Size Dimension of problem
     468             :              */
     469             :             template <index_t Size>
     470             :             class GeometryData
     471             :             {
     472             :                 template <typename... Ts>
     473             :                 using AllReal = typename std::enable_if_t<
     474             :                     std::conjunction<std::is_convertible<Ts, real_t>...>::value>;
     475             : 
     476             :             public:
     477             :                 /// Alias for RealVector_t
     478             :                 using Vector = RealVector_t;
     479             : 
     480             :                 /// Default Constructor
     481           0 :                 GeometryData() : _spacing(Size), _locationOfOrigin(Size) {}
     482             : 
     483             :                 GeometryData(const GeometryData&) = default;
     484             :                 GeometryData& operator=(const GeometryData&) = default;
     485           0 :                 GeometryData(GeometryData&&) = default;
     486             :                 GeometryData& operator=(GeometryData&&) = default;
     487             : 
     488             :                 /// Constructor from Strong type Spacing and OriginShift
     489           0 :                 GeometryData(Coefficients<Size> size)
     490           0 :                     : _spacing(Vector::Ones(Size)), _locationOfOrigin(Size)
     491             :                 {
     492           0 :                     IndexVector_t coeffs = size.get();
     493           0 :                     _locationOfOrigin = static_cast<real_t>(0.5)
     494           0 :                                         * (coeffs.cast<real_t>().array() * _spacing.array());
     495           0 :                 }
     496             : 
     497             :                 /// Constructor from Strong type Spacing and OriginShift
     498           0 :                 GeometryData(Coefficients<Size> size, Spacing<Size> spacing)
     499           0 :                     : _spacing(std::move(spacing.get())), _locationOfOrigin(Size)
     500             :                 {
     501           0 :                     IndexVector_t coeffs = size.get();
     502           0 :                     _locationOfOrigin = static_cast<real_t>(0.5)
     503           0 :                                         * (coeffs.cast<real_t>().array() * _spacing.array());
     504           0 :                 }
     505             : 
     506             :                 /// Constructor from Strong type Spacing and OriginShift
     507           0 :                 GeometryData(Spacing<Size> spacing, OriginShift<Size> origin)
     508           0 :                     : _spacing(std::move(spacing.get())), _locationOfOrigin(std::move(origin.get()))
     509             :                 {
     510           0 :                 }
     511             : 
     512             :                 /// Constructor from RealVector_t for Spacing and Strong type OriginShift
     513           0 :                 GeometryData(RealVector_t spacing, OriginShift<Size> origin)
     514           0 :                     : _spacing(std::move(spacing)), _locationOfOrigin(std::move(origin.get()))
     515             :                 {
     516           0 :                     if (_spacing.size() != Size || _locationOfOrigin.size() != Size
     517           0 :                         || _spacing.size() != _locationOfOrigin.size())
     518           0 :                         throw InvalidArgumentError(
     519             :                             "Spacing and Origin must have the same dimension");
     520           0 :                 }
     521             : 
     522             :                 /// Constructor from RealVector_t for origin shift and Strong type Spacing
     523           0 :                 GeometryData(Spacing<Size> spacing, RealVector_t origin)
     524           0 :                     : _spacing(std::move(spacing.get())), _locationOfOrigin(std::move(origin))
     525             :                 {
     526           0 :                     if (_spacing.size() != Size || _locationOfOrigin.size() != Size
     527           0 :                         || _spacing.size() != _locationOfOrigin.size())
     528           0 :                         throw InvalidArgumentError(
     529             :                             "Spacing and Origin must have the same dimension");
     530           0 :                 }
     531             : 
     532             :                 /// Constructor from RealVector_t for spacing and origin shift
     533           0 :                 GeometryData(RealVector_t spacing, RealVector_t origin)
     534           0 :                     : _spacing(std::move(spacing)), _locationOfOrigin(std::move(origin))
     535             :                 {
     536           0 :                     if (_spacing.size() != Size || _locationOfOrigin.size() != Size
     537           0 :                         || _spacing.size() != _locationOfOrigin.size())
     538           0 :                         throw InvalidArgumentError(
     539             :                             "Spacing and Origin must have the same dimension");
     540           0 :                 }
     541             : 
     542             :                 /// Getter for spacing (const reference)
     543           0 :                 Vector getSpacing() const& { return _spacing; }
     544             : 
     545             :                 /// Getter for spacing (r-value reference)
     546           0 :                 Vector&& getSpacing() && { return std::move(_spacing); }
     547             : 
     548             :                 /// Getter for origin shift/location of origin (const reference)
     549           0 :                 Vector getLocationOfOrigin() const& { return _locationOfOrigin; }
     550             : 
     551             :                 /// Getter for origin shift/location of origin (r-value reference)
     552           0 :                 Vector&& getLocationOfOrigin() && { return std::move(_locationOfOrigin); }
     553             : 
     554             :                 /// Get function (const reference overload) for structured bindings
     555             :                 template <std::size_t N>
     556             :                 decltype(auto) get() const&
     557             :                 {
     558             :                     if constexpr (N == 0)
     559             :                         return (_spacing);
     560             :                     else if constexpr (N == 1)
     561             :                         return (_locationOfOrigin);
     562             :                 }
     563             : 
     564             :                 /// Get function (r-value reference overload) for structured bindings
     565             :                 template <std::size_t N>
     566           0 :                 decltype(auto) get() &&
     567             :                 {
     568             :                     if constexpr (N == 0)
     569           0 :                         return std::move(_spacing);
     570             :                     else if constexpr (N == 1)
     571           0 :                         return std::move(_locationOfOrigin);
     572             :                 }
     573             : 
     574             :             private:
     575             :                 Vector _spacing = Vector::Zero(Size);
     576             :                 Vector _locationOfOrigin = Vector::Zero(Size);
     577             :             };
     578             :         } // namespace detail
     579             : 
     580             :         /**
     581             :          * @brief Strong type for geometry data, describing volume/domain spacing and location of
     582             :          * origin.
     583             :          *
     584             :          * @tparam Size Dimension of problem
     585             :          *
     586             :          * This used to be private inheritance, changed to public because of NVCC bug involving
     587             :          * structured bindings and overloaded get() functions lifted with a using statement
     588             :          */
     589             :         template <index_t Size>
     590             :         class VolumeData : public detail::GeometryData<Size>
     591             :         {
     592             :         public:
     593             :             using Base = detail::GeometryData<Size>;
     594             : 
     595             :             using Base::Base;
     596             :         };
     597             : 
     598             :         using VolumeData2D = VolumeData<2>; ///< 2D volume data alias for 2D geometry
     599             :         using VolumeData3D = VolumeData<3>; ///< 3D volume data alias for 3D geometry
     600             : 
     601             :         /**
     602             :          * @brief Strong type for geometry data, describing sinogram/range spacing and location of
     603             :          * origin. Note sinogram data is expected to be 1 dimension less, than the actual problem!
     604             :          *
     605             :          * @tparam Size Dimension of problem
     606             :          *
     607             :          * This used to be private inheritance, changed to public because of NVCC bug involving
     608             :          * structured bindings and overloaded get() functions lifted with a using statement
     609             :          */
     610             :         template <index_t Size>
     611             :         class SinogramData : public detail::GeometryData<Size>
     612             :         {
     613             :         public:
     614             :             using Base = detail::GeometryData<Size>;
     615             : 
     616             :             using Base::Base;
     617             :         };
     618             : 
     619             :         using SinogramData2D = SinogramData<2>; ///< 2D sinogram data alias for 2D geometry
     620             :         using SinogramData3D = SinogramData<3>; ///< 3D sinogram data alias for 3D geometry
     621             : 
     622             :         /**
     623             :          * @brief Strong type for a single value of type data_t used in proximity operators.
     624             :          * Comparison, addition, subtraction are overridden by utilizing the private member
     625             :          * _threshold.
     626             :          * N.B. The threshold value is expected to be strictly greater than 0, otherwise an
     627             :          * exception is thrown
     628             :          *
     629             :          * @tparam data_t data type of the threshold
     630             :          */
     631             :         template <typename data_t = real_t>
     632             :         class Threshold
     633             :         {
     634             :         public:
     635           0 :             explicit Threshold(data_t threshold) : _threshold(threshold)
     636             :             {
     637           0 :                 if (threshold <= 0) {
     638           0 :                     throw InvalidArgumentError("threshold must be strictly greater than 0");
     639             :                 }
     640           0 :             }
     641             : 
     642             :             /// explicit casting operator
     643           0 :             explicit operator data_t() const { return _threshold; }
     644             : 
     645             :             /// return -Threshold
     646           0 :             auto operator-() -> const data_t { return static_cast<data_t>(-_threshold); }
     647             : 
     648             :             /// return computed subtraction
     649           0 :             auto operator-(const data_t t) const -> data_t
     650             :             {
     651           0 :                 return static_cast<data_t>(_threshold - t);
     652             :             }
     653             : 
     654             :             /// return computed addition
     655           0 :             auto operator+(const data_t t) const -> data_t
     656             :             {
     657           0 :                 return static_cast<data_t>(_threshold + t);
     658             :             }
     659             : 
     660             :             /// return computed less-than comparison
     661           0 :             auto operator<(const data_t t) const -> bool { return _threshold < t; }
     662             : 
     663             :             /// return computed less-than-equals comparison
     664           0 :             auto operator<=(const data_t t) const -> bool { return !(*this > t); }
     665             : 
     666             :             /// return computed greater-than comparison
     667           0 :             auto operator>(const data_t t) const -> bool { return _threshold > t; }
     668             : 
     669             :             /// return computed greater-than-equals comparison
     670             :             auto operator>=(const data_t t) const -> bool { return !(*this < t); }
     671             : 
     672             :             /// return computed equality comparison
     673           0 :             auto operator==(const data_t t) const -> bool { return this->_threshold == t; }
     674             : 
     675             :             /// return computed equality-negation comparison
     676           0 :             auto operator!=(const data_t t) const -> bool { return !(*this == t); }
     677             : 
     678             :         private:
     679             :             data_t _threshold;
     680             :         };
     681             : 
     682             :         /// return computed subtraction of data_t with Threshold<data_t>
     683             :         template <typename data_t = real_t>
     684           0 :         auto operator-(const data_t a, const Threshold<data_t>& b) -> data_t
     685             :         {
     686           0 :             return static_cast<data_t>(-(b - a));
     687             :         }
     688             : 
     689             :         /// return computed addition of data_t with Threshold<data_t>
     690             :         template <typename data_t = real_t>
     691           0 :         auto operator+(const data_t a, const Threshold<data_t>& b) -> data_t
     692             :         {
     693           0 :             return static_cast<data_t>(b + a);
     694             :         }
     695             : 
     696             :         /// return computed greater-than comparison of data_t with Threshold<data_t>
     697             :         template <typename data_t = real_t>
     698           0 :         auto operator>(const data_t& a, const Threshold<data_t>& b) -> bool
     699             :         {
     700           0 :             return b < a;
     701             :         }
     702             : 
     703             :         /// return computed greater-than-equals comparison of data_t with Threshold<data_t>
     704             :         template <typename data_t = real_t>
     705           0 :         auto operator>=(const data_t& a, const Threshold<data_t>& b) -> bool
     706             :         {
     707           0 :             return b <= a;
     708             :         }
     709             : 
     710             :         /// return computed less-than comparison of data_t with Threshold<data_t>
     711             :         template <typename data_t = real_t>
     712             :         auto operator<(const data_t& a, const Threshold<data_t>& b) -> bool
     713             :         {
     714             :             return b > a;
     715             :         }
     716             : 
     717             :         /// return computed less-than-equals comparison of data_t with Threshold<data_t>
     718             :         template <typename data_t = real_t>
     719             :         auto operator<=(const data_t& a, const Threshold<data_t>& b) -> bool
     720             :         {
     721             :             return b >= a;
     722             :         }
     723             : 
     724             :         /// return computed equality comparison of data_t with Threshold<data_t>
     725             :         template <typename data_t = real_t>
     726             :         auto operator==(const data_t& a, const Threshold<data_t>& b) -> bool
     727             :         {
     728             :             return b == a;
     729             :         }
     730             : 
     731             :         /// return computed equality-negation comparison of data_t with Threshold<data_t>
     732             :         template <typename data_t = real_t>
     733             :         auto operator!=(const data_t& a, const Threshold<data_t>& b) -> bool
     734             :         {
     735             :             return b != a;
     736             :         }
     737             :     } // namespace geometry
     738             : } // namespace elsa
     739             : 
     740             : /*
     741             : #davidfrank 2020-05-09
     742             : All of these functions are needed to enable structured bindings for SinogramData, VolumeData and
     743             : RotationAngles I didn't find a way to do it generally for all sizes (at least not with explicit
     744             : instantiation). This should be fine for now
     745             : */
     746             : 
     747             : /// template specialization for class SinogramData (2D and 3D)
     748             : namespace std
     749             : {
     750             :     template <>
     751             :     struct tuple_size<elsa::geometry::SinogramData2D> : std::integral_constant<std::size_t, 2> {
     752             :     };
     753             : 
     754             :     template <std::size_t N>
     755             :     struct tuple_element<N, elsa::geometry::SinogramData2D> {
     756             :         using type = decltype(std::declval<elsa::geometry::SinogramData2D>().get<N>());
     757             :     };
     758             : 
     759             :     template <>
     760             :     struct tuple_size<elsa::geometry::SinogramData3D> : std::integral_constant<std::size_t, 2> {
     761             :     };
     762             : 
     763             :     template <std::size_t N>
     764             :     struct tuple_element<N, elsa::geometry::SinogramData3D> {
     765             :         using type = decltype(std::declval<elsa::geometry::SinogramData3D>().get<N>());
     766             :     };
     767             : } // namespace std
     768             : 
     769             : /// template specialization for class VolumeData (2D and 3D)
     770             : namespace std
     771             : {
     772             :     template <>
     773             :     struct tuple_size<elsa::geometry::VolumeData2D> : std::integral_constant<std::size_t, 2> {
     774             :     };
     775             : 
     776             :     template <std::size_t N>
     777             :     struct tuple_element<N, elsa::geometry::VolumeData2D> {
     778             :         using type = decltype(std::declval<elsa::geometry::VolumeData2D>().get<N>());
     779             :     };
     780             : 
     781             :     template <>
     782             :     struct tuple_size<elsa::geometry::VolumeData3D> : std::integral_constant<std::size_t, 2> {
     783             :     };
     784             : 
     785             :     template <std::size_t N>
     786             :     struct tuple_element<N, elsa::geometry::VolumeData3D> {
     787             :         using type = decltype(std::declval<elsa::geometry::VolumeData3D>().get<N>());
     788             :     };
     789             : } // namespace std
     790             : 
     791             : /// template specialization for class RotationAngles3D (2D and 3D)
     792             : namespace std
     793             : {
     794             :     template <>
     795             :     struct tuple_size<elsa::geometry::RotationAngles3D> : std::integral_constant<std::size_t, 3> {
     796             :     };
     797             : 
     798             :     template <std::size_t N>
     799             :     struct tuple_element<N, elsa::geometry::RotationAngles3D> {
     800             :         using type = decltype(std::declval<elsa::geometry::RotationAngles3D>().get<N>());
     801             :     };
     802             : } // namespace std

Generated by: LCOV version 1.14