LCOV - code coverage report
Current view: top level - elsa/projectors - SliceTraversal.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 128 146 87.7 %
Date: 2022-08-25 03:05:39 Functions: 26 32 81.2 %

          Line data    Source code
       1             : #include "SliceTraversal.h"
       2             : #include "Error.h"
       3             : #include "elsaDefines.h"
       4             : #include "spdlog/fmt/fmt.h"
       5             : #include "spdlog/fmt/ostr.h"
       6             : 
       7             : namespace elsa
       8             : {
       9             :     RealMatrix_t TransformToTraversal::create2DRotation(const real_t leadingCoeff,
      10             :                                                         const index_t leadingAxisIndex)
      11        1510 :     {
      12        1514 :         auto createRotationMatrix = [](real_t radian) {
      13        1514 :             real_t c = std::cos(radian);
      14        1514 :             real_t s = std::sin(radian);
      15        1514 :             return RealMatrix_t({{c, -s}, {s, c}});
      16        1514 :         };
      17             : 
      18             :         // TODO: Does a closed form solution exist?
      19             :         // Use conversion to polar coordinates
      20        1510 :         if (leadingAxisIndex == 0 && leadingCoeff >= 0) {
      21             :             // Already identity, so do nothing
      22         402 :             return createRotationMatrix(0);
      23        1108 :         } else if (leadingAxisIndex == 0 && leadingCoeff < 0) {
      24             :             // create a 2D 180° rotation matrix
      25         380 :             return createRotationMatrix(pi_t);
      26         731 :         } else if (leadingAxisIndex == 1 && leadingCoeff >= 0) {
      27             :             // create a 2D 270° rotation matrix counter clockwise
      28         361 :             return createRotationMatrix(3 * pi_t / 2);
      29         371 :         } else if (leadingAxisIndex == 1 && leadingCoeff <= 0) {
      30             :             // create a 2D 90° rotation matrix counter clockwise
      31         371 :             return createRotationMatrix(pi_t / 2);
      32         371 :         }
      33 >1844*10^16 :         return createRotationMatrix(0);
      34 >1844*10^16 :     }
      35             : 
      36             :     RealMatrix_t TransformToTraversal::create3DRotation(const real_t leadingCoeff,
      37             :                                                         const index_t leadingAxisIndex)
      38         245 :     {
      39         245 :         auto identity = []() { return RealMatrix_t({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}); };
      40             : 
      41         245 :         auto rotationX = [](real_t radian) {
      42         245 :             real_t c = std::cos(radian);
      43         245 :             real_t s = std::sin(radian);
      44         245 :             return RealMatrix_t({{1, 0, 0}, {0, c, -s}, {0, s, c}});
      45         245 :         };
      46             : 
      47         245 :         auto rotationY = [](real_t radian) {
      48         158 :             real_t c = std::cos(radian);
      49         158 :             real_t s = std::sin(radian);
      50         158 :             return RealMatrix_t({{c, 0, s}, {0, 1, 0}, {-s, 0, c}});
      51         158 :         };
      52             : 
      53         245 :         auto rotationZ = [](real_t radian) {
      54           8 :             real_t c = std::cos(radian);
      55           8 :             real_t s = std::sin(radian);
      56           8 :             return RealMatrix_t({{c, -s, 0}, {s, c, 0}, {0, 0, 1}});
      57           8 :         };
      58             : 
      59             :         // TODO: Does a closed form solution exist?
      60             :         // Use conversion to polar coordinates
      61         245 :         if (leadingAxisIndex == 0 && leadingCoeff >= 0) {
      62             :             // Already identity, so do nothing
      63          79 :             return identity();
      64         166 :         } else if (leadingAxisIndex == 0 && leadingCoeff < 0) {
      65          60 :             return rotationY(pi_t);
      66         106 :         } else if (leadingAxisIndex == 1 && leadingCoeff >= 0) {
      67           4 :             return rotationZ(-0.5 * pi_t);
      68         102 :         } else if (leadingAxisIndex == 1 && leadingCoeff <= 0) {
      69           4 :             return rotationZ(0.5 * pi_t);
      70          98 :         } else if (leadingAxisIndex == 2 && leadingCoeff >= 0) {
      71          54 :             return rotationY(0.5 * pi_t);
      72          54 :         } else if (leadingAxisIndex == 2 && leadingCoeff <= 0) {
      73          44 :             return rotationY(-0.5 * pi_t);
      74          44 :         }
      75             : 
      76           0 :         return identity();
      77           0 :     }
      78             : 
      79             :     RealMatrix_t TransformToTraversal::createRotation(RealRay_t ray)
      80        1778 :     {
      81             :         // Get the leading axis, by absolute value
      82        1778 :         index_t leadingAxisIndex = 0;
      83        1778 :         ray.direction().array().abs().maxCoeff(&leadingAxisIndex);
      84             : 
      85             :         // Get the signed leading coefficient
      86        1778 :         const auto leadingCoeff = ray.direction()(leadingAxisIndex);
      87             : 
      88        1778 :         if (ray.dim() == 2) {
      89        1506 :             return create2DRotation(leadingCoeff, leadingAxisIndex);
      90        1506 :         } else if (ray.dim() == 3) {
      91         245 :             return create3DRotation(leadingCoeff, leadingAxisIndex);
      92         245 :         }
      93          27 :         throw Error("Can not create a {}-dimensional transformation for the slice traversal",
      94          27 :                     ray.dim());
      95          27 :     }
      96             : 
      97             :     RealMatrix_t TransformToTraversal::createTransformation(const RealRay_t& ray,
      98             :                                                             const RealVector_t& centerOfRotation)
      99        1749 :     {
     100        1749 :         const auto dim = ray.dim();
     101             : 
     102             :         // Setup translation
     103        1749 :         RealMatrix_t translation(dim + 1, dim + 1);
     104        1749 :         translation.setIdentity();
     105        1749 :         translation.block(0, dim, dim, 1) = -centerOfRotation;
     106             : 
     107             :         // Setup rotation
     108        1749 :         RealMatrix_t rotation(dim + 1, dim + 1);
     109        1749 :         rotation.setIdentity();
     110        1749 :         rotation.block(0, 0, dim, dim) = createRotation(ray);
     111             : 
     112        1749 :         return rotation * translation;
     113        1749 :     }
     114             : 
     115             :     TransformToTraversal::TransformToTraversal(const RealRay_t& ray,
     116             :                                                const RealVector_t& centerOfRotation)
     117             :         : transformation_(createTransformation(ray, centerOfRotation)),
     118             :           translation_(-centerOfRotation)
     119        1746 :     {
     120        1746 :     }
     121             : 
     122             :     RealRay_t TransformToTraversal::toTraversalCoordinates(RealRay_t ray) const
     123        1667 :     {
     124        1667 :         ray.origin() = *this * Point(ray.origin());
     125        1667 :         ray.direction() = *this * Vec(ray.direction());
     126        1667 :         return ray;
     127        1667 :     }
     128             : 
     129             :     BoundingBox TransformToTraversal::toTraversalCoordinates(BoundingBox aabb) const
     130        1675 :     {
     131             :         // Only translate, as the rotations are always 90, 180, 270 degrees,
     132             :         // TODO: this might be wrong, idk, what about non square things
     133        1675 :         aabb._min = *this * Point(aabb._min);
     134        1675 :         aabb._max = *this * Point(aabb._max);
     135        1675 :         aabb.recomputeBounds();
     136        1675 :         return aabb;
     137        1675 :     }
     138             : 
     139        5042 :     RealMatrix_t TransformToTraversal::transformation() const { return transformation_; }
     140             : 
     141             :     RealMatrix_t TransformToTraversal::invTransformation() const
     142           0 :     {
     143           0 :         return transformation().inverse();
     144           0 :     }
     145             : 
     146             :     RealMatrix_t TransformToTraversal::rotation() const
     147        1762 :     {
     148        1762 :         const auto dim = transformation_.rows();
     149        1762 :         return transformation_.block(0, 0, dim - 1, dim - 1);
     150        1762 :     }
     151             : 
     152           0 :     RealMatrix_t TransformToTraversal::invRotation() const { return rotation().transpose(); }
     153             : 
     154           0 :     RealVector_t TransformToTraversal::translation() const { return translation_; }
     155             : 
     156        1713 :     RealMatrix_t TransformToTraversal::linear() const { return rotation(); }
     157             : 
     158             :     RealVector_t TransformToTraversal::operator*(const Point<real_t>& point) const
     159        5041 :     {
     160        5041 :         return (transformation() * point.point_.homogeneous()).hnormalized();
     161        5041 :     }
     162             : 
     163             :     RealVector_t TransformToTraversal::operator*(const Vec<real_t>& vec) const
     164        1688 :     {
     165        1688 :         return linear() * vec.vec_;
     166        1688 :     }
     167             : 
     168             :     SliceTraversal::SliceTraversal(BoundingBox aabb, RealRay_t ray)
     169             :         : transformation_(ray, aabb._max.array() / 2), ray_(ray)
     170        1660 :     {
     171             :         // Transform ray and aabb to traversal coordinate space
     172        1660 :         ray = transformation_.toTraversalCoordinates(ray);
     173        1660 :         aabb = transformation_.toTraversalCoordinates(aabb);
     174             : 
     175             :         // TODO: We only want to shift in x direction by 0.5, not in y
     176        1660 :         auto hit = Intersection::xPlanesWithRay(aabb, ray);
     177             : 
     178             :         // Default init is sufficient if we don't hit,  TODO: test that!
     179        1663 :         if (hit) {
     180        1663 :             const auto firstVoxel = ray.pointAt(hit->_tmin);
     181        1663 :             const auto lastVoxel = ray.pointAt(hit->_tmax);
     182             : 
     183        1663 :             endIndex_ = std::max<index_t>(
     184        1663 :                 1, static_cast<index_t>(std::ceil(lastVoxel[0] - firstVoxel[0] + 0.5f)));
     185             : 
     186        1663 :             tDelta_ = 1 / ray.direction()[0];
     187             : 
     188        1663 :             t_ = hit->_tmin;
     189        1663 :         }
     190        1660 :     }
     191             : 
     192             :     index_t SliceTraversal::leadingDirection() const
     193           0 :     {
     194           0 :         index_t idx = 0;
     195           0 :         ray_.direction().array().cwiseAbs().maxCoeff(&idx);
     196           0 :         return idx;
     197           0 :     }
     198             : 
     199          43 :     real_t SliceTraversal::t() const { return t_; }
     200             : 
     201          43 :     real_t SliceTraversal::tDelta() const { return tDelta_; }
     202             : 
     203             :     SliceTraversal::Iter SliceTraversal::begin() const
     204        1670 :     {
     205        1670 :         return {startIndex_, ray_.pointAt(t_), ray_.direction() * tDelta_};
     206        1670 :     }
     207             : 
     208        1768 :     SliceTraversal::Iter SliceTraversal::end() const { return {endIndex_}; }
     209             : 
     210           0 :     index_t SliceTraversal::startIndex() const { return startIndex_; }
     211             : 
     212          43 :     index_t SliceTraversal::endIndex() const { return endIndex_; }
     213             : 
     214             :     SliceTraversal::Iter::value_type SliceTraversal::Iter::operator*() const
     215        8042 :     {
     216        8042 :         return cur_.template cast<index_t>();
     217        8042 :     }
     218             : 
     219             :     SliceTraversal::Iter& SliceTraversal::Iter::operator++()
     220        8060 :     {
     221        8060 :         ++pos_;
     222        8060 :         cur_ += dir_;
     223        8060 :         return *this;
     224        8060 :     }
     225             : 
     226             :     SliceTraversal::Iter SliceTraversal::Iter::operator++(int)
     227           0 :     {
     228           0 :         auto copy = *this;
     229           0 :         ++(*this);
     230           0 :         return copy;
     231           0 :     }
     232             : 
     233             :     bool operator==(const SliceTraversal::Iter& lhs, const SliceTraversal::Iter& rhs)
     234        9711 :     {
     235        9711 :         return lhs.pos_ == rhs.pos_;
     236        9711 :     }
     237             : 
     238             :     bool operator!=(const SliceTraversal::Iter& lhs, const SliceTraversal::Iter& rhs)
     239        9709 :     {
     240        9709 :         return !(lhs == rhs);
     241        9709 :     }
     242             : 
     243             : } // namespace elsa

Generated by: LCOV version 1.14