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 20133 : constexpr Radian() : _radian(0) {}
26 :
27 : /// Constructor from real_t
28 24127 : 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 10792 : constexpr real_t to_degree() const { return _radian * 180 / pi_t; }
35 :
36 : /// Conversion (implicit) to real_t
37 39960 : 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 0 : constexpr Degree() : _degree(0) {}
52 :
53 : /// Constructor from real_t
54 12990 : 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 12982 : constexpr real_t to_radian() const { return _degree * pi_t / 180; }
61 :
62 : /// Conversion (implicit) to real_t
63 7450 : 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 7776 : 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 : constexpr RotationAngles(Ts&&... ts)
136 : : RotationAngles(std::index_sequence_for<Ts...>{}, std::forward<Ts>(ts)...)
137 6712 : {
138 6712 : }
139 :
140 : /// Access operator
141 : constexpr Type operator[](index_t i) const
142 20136 : {
143 20136 : return _angles[static_cast<size_t>(i)];
144 20136 : }
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 : Type&& get() &&
163 3 : {
164 3 : return std::move(std::get<I>(_angles));
165 3 : }
166 :
167 : private:
168 : /// Helper constructor to init array
169 : template <std::size_t... Is, typename... Ts, typename = AllRadian<Ts...>>
170 : constexpr RotationAngles(std::index_sequence<Is...>, Ts&&... vals)
171 6712 : {
172 : // Fold expression expands to _angles[0] = vals0, _angles[1] = vals1, ...,
173 : // _angles[k] = valsk;
174 6712 : (static_cast<void>(_angles[Is] = vals), ...);
175 6712 : }
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 : constexpr RotationAngles3D(Gamma gamma)
198 : : Base(Radian{static_cast<real_t>(gamma)}, Radian{0}, Radian{0})
199 1915 : {
200 1915 : }
201 :
202 : /// Construction from Beta
203 : constexpr RotationAngles3D(Beta beta)
204 : : Base(Radian{0}, Radian{static_cast<real_t>(beta)}, Radian{0})
205 100 : {
206 100 : }
207 :
208 : /// Construction from Alpha
209 : constexpr RotationAngles3D(Alpha alpha)
210 : : Base(Radian{0}, Radian{0}, Radian{static_cast<real_t>(alpha)})
211 100 : {
212 100 : }
213 :
214 : /// Construction from Gamma and Beta
215 : constexpr RotationAngles3D(Gamma gamma, Beta beta)
216 : : Base(Radian{static_cast<real_t>(gamma)}, Radian{static_cast<real_t>(beta)},
217 : Radian{0})
218 22 : {
219 22 : }
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 0 : {
226 0 : }
227 :
228 : /// Construction from Beta and Gamma
229 0 : 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 0 : {
236 0 : }
237 :
238 : /// Construction from Alpha and Beta
239 0 : constexpr RotationAngles3D(Alpha alpha, Gamma gamma) : RotationAngles3D(gamma, alpha) {}
240 :
241 : /// Construction from Alpha and Gamma
242 0 : constexpr RotationAngles3D(Alpha alpha, Beta beta) : RotationAngles3D(beta, alpha) {}
243 :
244 : /// Construction from Gamma, Beta and Alpha
245 : constexpr RotationAngles3D(Gamma gamma, Beta beta, Alpha alpha)
246 : : Base(Radian{static_cast<real_t>(gamma)}, Radian{static_cast<real_t>(beta)},
247 : Radian{static_cast<real_t>(alpha)})
248 3 : {
249 3 : }
250 :
251 : /// Access to gamma
252 6709 : constexpr Radian gamma() const { return operator[](0u); }
253 : /// Access to beta
254 6709 : constexpr Radian beta() const { return operator[](1u); }
255 : /// Access to alpha
256 6709 : 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 12 : constexpr RealWrapper() : _x(0) {}
268 :
269 46010 : constexpr explicit RealWrapper(real_t x) : _x(x) {}
270 :
271 99762 : 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 1 : StaticVectorTemplate() : _vec(Size) {}
294 :
295 : StaticVectorTemplate(const StaticVectorTemplate&) = default;
296 : StaticVectorTemplate& operator=(const StaticVectorTemplate&) = default;
297 9366 : 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 : StaticVectorTemplate(Scalar x, Ts&&... ts) : _vec(Size)
305 22210 : {
306 : // Fold expression, which expands to _vec << x, t1, t2, t3, ..., tn;
307 22210 : ((_vec << x), ..., static_cast<Scalar>(ts));
308 22210 : }
309 :
310 : /// Constructor from Vector
311 : StaticVectorTemplate(Vector vec) : _vec(vec)
312 45349 : {
313 45349 : if (_vec.size() != Size)
314 1 : throw InvalidArgumentError(
315 1 : "StaticVectorTemplate::Given argument vector is of the wrong size");
316 45349 : }
317 :
318 : /// Access operator
319 : Scalar operator[](index_t i) const { return _vec[i]; }
320 :
321 : /// Access operator
322 13426 : Scalar& operator[](index_t i) { return _vec[i]; }
323 :
324 : /// Conversion operator to Vector
325 : operator Vector() const { return _vec; }
326 :
327 : /// Conversion operator to Vector&& (rvalue reference)
328 : operator Vector&&() { return std::move(_vec); }
329 :
330 : /// Access to vector (const reference)
331 60850 : const Vector& get() & { return _vec; }
332 :
333 : /// Access to vector (r-value reference)
334 : 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 1 : GeometryData() : _spacing(Size), _locationOfOrigin(Size) {}
482 :
483 124 : GeometryData(const GeometryData&) = default;
484 : GeometryData& operator=(const GeometryData&) = default;
485 30995 : GeometryData(GeometryData&&) = default;
486 : GeometryData& operator=(GeometryData&&) = default;
487 :
488 : /// Constructor from Strong type Spacing and OriginShift
489 : GeometryData(Coefficients<Size> size)
490 : : _spacing(Vector::Ones(Size)), _locationOfOrigin(Size)
491 27136 : {
492 27136 : IndexVector_t coeffs = size.get();
493 27136 : _locationOfOrigin = static_cast<real_t>(0.5)
494 27136 : * (coeffs.cast<real_t>().array() * _spacing.array());
495 27136 : }
496 :
497 : /// Constructor from Strong type Spacing and OriginShift
498 : GeometryData(Coefficients<Size> size, Spacing<Size> spacing)
499 : : _spacing(std::move(spacing.get())), _locationOfOrigin(Size)
500 9099 : {
501 9099 : IndexVector_t coeffs = size.get();
502 9099 : _locationOfOrigin = static_cast<real_t>(0.5)
503 9099 : * (coeffs.cast<real_t>().array() * _spacing.array());
504 9099 : }
505 :
506 : /// Constructor from Strong type Spacing and OriginShift
507 : GeometryData(Spacing<Size> spacing, OriginShift<Size> origin)
508 : : _spacing(std::move(spacing.get())), _locationOfOrigin(std::move(origin.get()))
509 6 : {
510 6 : }
511 :
512 : /// Constructor from RealVector_t for Spacing and Strong type OriginShift
513 : GeometryData(RealVector_t spacing, OriginShift<Size> origin)
514 : : _spacing(std::move(spacing)), _locationOfOrigin(std::move(origin.get()))
515 2 : {
516 2 : if (_spacing.size() != Size || _locationOfOrigin.size() != Size
517 2 : || _spacing.size() != _locationOfOrigin.size())
518 2 : throw InvalidArgumentError(
519 2 : "Spacing and Origin must have the same dimension");
520 2 : }
521 :
522 : /// Constructor from RealVector_t for origin shift and Strong type Spacing
523 : GeometryData(Spacing<Size> spacing, RealVector_t origin)
524 : : _spacing(std::move(spacing.get())), _locationOfOrigin(std::move(origin))
525 2 : {
526 2 : if (_spacing.size() != Size || _locationOfOrigin.size() != Size
527 2 : || _spacing.size() != _locationOfOrigin.size())
528 2 : throw InvalidArgumentError(
529 2 : "Spacing and Origin must have the same dimension");
530 2 : }
531 :
532 : /// Constructor from RealVector_t for spacing and origin shift
533 : GeometryData(RealVector_t spacing, RealVector_t origin)
534 : : _spacing(std::move(spacing)), _locationOfOrigin(std::move(origin))
535 9240 : {
536 9240 : if (_spacing.size() != Size || _locationOfOrigin.size() != Size
537 9240 : || _spacing.size() != _locationOfOrigin.size())
538 2 : throw InvalidArgumentError(
539 2 : "Spacing and Origin must have the same dimension");
540 9240 : }
541 :
542 : /// Getter for spacing (const reference)
543 44 : Vector getSpacing() const& { return _spacing; }
544 :
545 : /// Getter for spacing (r-value reference)
546 : Vector&& getSpacing() && { return std::move(_spacing); }
547 :
548 : /// Getter for origin shift/location of origin (const reference)
549 39 : Vector getLocationOfOrigin() const& { return _locationOfOrigin; }
550 :
551 : /// Getter for origin shift/location of origin (r-value reference)
552 : 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 : decltype(auto) get() &&
567 61996 : {
568 61996 : if constexpr (N == 0)
569 30998 : return std::move(_spacing);
570 30998 : else if constexpr (N == 1)
571 30998 : return std::move(_locationOfOrigin);
572 61996 : }
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 proximal 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 : explicit Threshold(data_t threshold) : _threshold(threshold)
636 5 : {
637 5 : if (threshold <= 0) {
638 2 : throw InvalidArgumentError("threshold must be strictly greater than 0");
639 2 : }
640 5 : }
641 :
642 : /// explicit casting operator
643 : explicit operator data_t() const { return _threshold; }
644 :
645 : /// return -Threshold
646 : auto operator-() -> const data_t { return static_cast<data_t>(-_threshold); }
647 :
648 : /// return computed subtraction
649 : auto operator-(const data_t t) const -> data_t
650 1 : {
651 1 : return static_cast<data_t>(_threshold - t);
652 1 : }
653 :
654 : /// return computed addition
655 : auto operator+(const data_t t) const -> data_t
656 3 : {
657 3 : return static_cast<data_t>(_threshold + t);
658 3 : }
659 :
660 : /// return computed less-than comparison
661 2 : auto operator<(const data_t t) const -> bool { return _threshold < t; }
662 :
663 : /// return computed less-than-equals comparison
664 1 : auto operator<=(const data_t t) const -> bool { return !(*this > t); }
665 :
666 : /// return computed greater-than comparison
667 1 : 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 2 : auto operator==(const data_t t) const -> bool { return this->_threshold == t; }
674 :
675 : /// return computed equality-negation comparison
676 1 : 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 : auto operator-(const data_t a, const Threshold<data_t>& b) -> data_t
685 1 : {
686 1 : return static_cast<data_t>(-(b - a));
687 1 : }
688 :
689 : /// return computed addition of data_t with Threshold<data_t>
690 : template <typename data_t = real_t>
691 : auto operator+(const data_t a, const Threshold<data_t>& b) -> data_t
692 2 : {
693 2 : return static_cast<data_t>(b + a);
694 2 : }
695 :
696 : /// return computed greater-than comparison of data_t with Threshold<data_t>
697 : template <typename data_t = real_t>
698 : auto operator>(const data_t& a, const Threshold<data_t>& b) -> bool
699 1 : {
700 1 : return b < a;
701 1 : }
702 :
703 : /// return computed greater-than-equals comparison of data_t with Threshold<data_t>
704 : template <typename data_t = real_t>
705 : auto operator>=(const data_t& a, const Threshold<data_t>& b) -> bool
706 1 : {
707 1 : return b <= a;
708 1 : }
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
|