LCOV - code coverage report
Current view: top level - elsa/projectors - TraverseAABBJosephsMethod.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 142 149 95.3 %
Date: 2022-08-25 03:05:39 Functions: 13 14 92.9 %

          Line data    Source code
       1             : #include "TraverseAABBJosephsMethod.h"
       2             : 
       3             : namespace elsa
       4             : {
       5             : 
       6             :     TraverseAABBJosephsMethod::TraverseAABBJosephsMethod(const BoundingBox& aabb,
       7             :                                                          const RealRay_t& r)
       8             :         : _aabb{aabb}
       9       16135 :     {
      10       16135 :         initStepDirection(r.direction());
      11             : 
      12       16135 :         RealRay_t rt(r.origin(), r.direction());
      13             : 
      14             :         // determinge length of entire intersection with AABB
      15       16135 :         real_t intersectionLength = calculateAABBIntersections(rt);
      16             : 
      17       16135 :         if (!isInBoundingBox())
      18        1258 :             return;
      19             : 
      20       14877 :         selectClosestVoxel(_entryPoint);
      21             : 
      22             :         // exit direction stored in _exitDirection
      23       14877 :         (_exitPoint - (_exitPoint.array().floor() + static_cast<real_t>(0.5)).matrix())
      24       14877 :             .cwiseAbs()
      25       14877 :             .maxCoeff(&_exitDirection);
      26             : 
      27       14877 :         moveToFirstSamplingPoint(r.direction(), intersectionLength);
      28             : 
      29             :         // last pixel/voxel handled separately, reduce box dimensionality for easy detection
      30       14877 :         int mainDir;
      31       14877 :         rt.direction().cwiseAbs().maxCoeff(&mainDir);
      32       14877 :         real_t prevBorder = std::floor(_exitPoint(mainDir));
      33       14877 :         if (prevBorder == _exitPoint(mainDir) && rt.direction()[mainDir] > 0) {
      34        6904 :             prevBorder--;
      35        6904 :         }
      36       14877 :         if (rt.direction()[mainDir] < 0) {
      37        4096 :             _aabb._min[mainDir] = prevBorder + 1;
      38       10781 :         } else {
      39       10781 :             _aabb._max[mainDir] = prevBorder;
      40       10781 :         }
      41       14877 :     }
      42             : 
      43             :     void TraverseAABBJosephsMethod::updateTraverse()
      44      172052 :     {
      45      172052 :         _fractionals += _nextStep;
      46      483484 :         for (int i = 0; i < _aabb._dim; i++) {
      47             :             //*0.5 because a change of 1 spacing corresponds to a change of
      48             :             // fractionals from -0.5 to 0.5  0.5 or -0.5 = voxel border is still
      49             :             // ok
      50      311432 :             if (std::abs(_fractionals(i)) > 0.5) {
      51      221796 :                 _fractionals(i) -= _stepDirection(i);
      52      221796 :                 _currentPos(i) += _stepDirection(i);
      53             :                 // --> is the traverse algorithm still in the bounding box?
      54      221796 :                 _isInAABB = _isInAABB && isCurrentPositionInAABB(i);
      55      221796 :             }
      56      311432 :         }
      57      172052 :         switch (_stage) {
      58       14562 :             case FIRST:
      59       14562 :                 _nextStep.cwiseAbs().maxCoeff(&_ignoreDirection);
      60       14562 :                 if (_isInAABB) {
      61             :                     // now ignore main direction
      62       14038 :                     _nextStep /= std::abs(_nextStep(_ignoreDirection));
      63       14038 :                     _fractionals(_ignoreDirection) = 0;
      64       14038 :                     _intersectionLength = _nextStep.norm();
      65       14038 :                     _stage = INTERIOR;
      66       14038 :                 }
      67       14562 :                 [[fallthrough]];
      68      153248 :             case INTERIOR:
      69      153248 :                 if (!_isInAABB) {
      70             :                     // revert to exit position and adjust values
      71       14636 :                     real_t prevBorder = _nextStep(_ignoreDirection) < 0
      72       14636 :                                             ? _aabb._min[_ignoreDirection]
      73       14636 :                                             : _aabb._max[_ignoreDirection];
      74       14636 :                     _nextStep.normalize();
      75       14636 :                     _intersectionLength =
      76       14636 :                         (_exitPoint[_ignoreDirection] - prevBorder) / (_nextStep[_ignoreDirection]);
      77             :                     // determine exit direction (the exit coordinate furthest from the center of the
      78             :                     // volume)
      79       14636 :                     _ignoreDirection = _exitDirection;
      80             :                     // move to last sampling point
      81       14636 :                     RealVector_t currentPosition = _exitPoint - _intersectionLength * _nextStep / 2;
      82       14636 :                     selectClosestVoxel(currentPosition);
      83       14636 :                     initFractionals(currentPosition);
      84       14636 :                     _isInAABB = true;
      85       14636 :                     _stage = LAST;
      86       14636 :                 }
      87      153248 :                 break;
      88       15044 :             case LAST:
      89       15044 :                 _isInAABB = false;
      90       15044 :                 break;
      91       14562 :             default:
      92           0 :                 break;
      93      172052 :         }
      94      172052 :     }
      95             : 
      96      171888 :     const RealVector_t& TraverseAABBJosephsMethod::getFractionals() const { return _fractionals; }
      97      173302 :     int TraverseAABBJosephsMethod::getIgnoreDirection() const { return _ignoreDirection; }
      98             : 
      99             :     void TraverseAABBJosephsMethod::initFractionals(const RealVector_t& currentPosition)
     100       29675 :     {
     101       88389 :         for (int i = 0; i < _aabb._dim; i++)
     102       58714 :             _fractionals(i) =
     103       58714 :                 static_cast<real_t>(std::abs(currentPosition(i)) - _currentPos(i) - 0.5);
     104       29675 :     }
     105             : 
     106             :     void TraverseAABBJosephsMethod::moveToFirstSamplingPoint(const RealVector_t& rd,
     107             :                                                              real_t intersectionLength)
     108       14876 :     {
     109             :         // determine main direction
     110       14876 :         rd.cwiseAbs().maxCoeff(&_ignoreDirection);
     111             : 
     112             :         // initialize _nextStep as the step for interior pixels
     113       14876 :         _nextStep(_ignoreDirection) = _stepDirection(_ignoreDirection);
     114       44455 :         for (int i = 0; i < _aabb._dim; ++i) {
     115       29579 :             if (i != _ignoreDirection) {
     116             :                 // tDelta(i) is given in relation to tDelta(_ignoreDirection)
     117       14883 :                 _nextStep(i) = _nextStep(_ignoreDirection) * rd(i) / rd(_ignoreDirection);
     118       14883 :             }
     119       29579 :         }
     120             : 
     121       14876 :         RealVector_t currentPosition = _entryPoint;
     122             :         // move to first sampling point
     123       14876 :         if (std::abs(_entryPoint[_ignoreDirection] - _exitPoint[_ignoreDirection])
     124       14876 :             <= static_cast<real_t>(1.)) {
     125         397 :             _stage = LAST;
     126             :             // use midpoint of intersection as the interpolation value
     127         397 :             currentPosition += rd * intersectionLength / 2;
     128         397 :             _intersectionLength = intersectionLength;
     129       14479 :         } else {
     130             :             // find distance to next plane orthogonal to main direction
     131       14479 :             real_t nextBoundary = std::trunc(_currentPos(_ignoreDirection));
     132       14479 :             if (_stepDirection(_ignoreDirection) > 0)
     133       10566 :                 nextBoundary += static_cast<real_t>(1.);
     134             : 
     135       14479 :             real_t distToBoundary =
     136       14479 :                 (nextBoundary - _entryPoint[_ignoreDirection]) / rd[_ignoreDirection];
     137             : 
     138       14479 :             currentPosition += rd * distToBoundary / 2;
     139       14479 :             _nextStep = _nextStep / 2 + _nextStep * (distToBoundary / (2 * _nextStep.norm()));
     140       14479 :             _intersectionLength = distToBoundary;
     141             : 
     142             :             // determine entry direction (the entry coordinate furthest from the center of the
     143             :             // volume)
     144       14479 :             (_entryPoint - (_entryPoint.array().floor() + static_cast<real_t>(0.5)).matrix())
     145       14479 :                 .cwiseAbs()
     146       14479 :                 .maxCoeff(&_ignoreDirection);
     147       14479 :         }
     148       14876 :         selectClosestVoxel(currentPosition);
     149             : 
     150             :         // init fractionals
     151       14876 :         initFractionals(currentPosition);
     152       14876 :     }
     153             : 
     154             :     inline bool TraverseAABBJosephsMethod::isCurrentPositionInAABB(index_t index) const
     155      216058 :     {
     156      216058 :         return _currentPos(index) < _aabb._max(index) && _currentPos(index) >= _aabb._min(index);
     157      216058 :     }
     158             : 
     159             :     void TraverseAABBJosephsMethod::selectClosestVoxel(const RealVector_t& currentPosition)
     160       44220 :     {
     161       44220 :         RealVector_t lowerCorner = currentPosition.array().floor();
     162       44220 :         lowerCorner =
     163       44220 :             (((lowerCorner.array() == currentPosition.array()) && (_stepDirection.array() < 0.0))
     164       44220 :              || currentPosition.array() == _aabb._max.array())
     165       44220 :                 .select(lowerCorner.array() - 1, lowerCorner);
     166             : 
     167             :         // --> If ray is parallel and we are close, choose the next previous/next voxel
     168       44220 :         _currentPos = lowerCorner;
     169             : 
     170             :         // check if we are still inside the aabb
     171       44220 :         if ((_currentPos.array() >= _aabb._max.array()).any()
     172       44220 :             || (_currentPos.array() < _aabb._min.array()).any())
     173       14672 :             _isInAABB = false;
     174       44220 :     }
     175             : 
     176             :     RealVector_t floorFallback(const RealVector_t& v)
     177           0 :     {
     178           0 :         RealVector_t ret(v.rows());
     179           0 :         for (int i = 0; i < v.rows(); i++)
     180           0 :             ret(i) = std::floor(v(i));
     181           0 :         return ret;
     182           0 :     }
     183             : 
     184             :     void TraverseAABBJosephsMethod::initStepDirection(const RealVector_t& rd)
     185       16129 :     {
     186       16129 :         _stepDirection = rd.array().sign();
     187       16129 :     }
     188             : 
     189             :     real_t TraverseAABBJosephsMethod::calculateAABBIntersections(const RealRay_t& ray)
     190       16138 :     {
     191       16138 :         real_t tmin;
     192             : 
     193             :         // --> calculate intersection parameter and if the volume is hit
     194       16138 :         auto opt = Intersection::withRay(_aabb, ray);
     195             : 
     196       16138 :         if (opt) {
     197       14971 :             _isInAABB = true;
     198       14971 :             tmin = opt->_tmin;
     199             : 
     200             :             // --> get points at which they intersect
     201       14971 :             _entryPoint = ray.pointAt(tmin);
     202             : 
     203             :             // --> because of floating point error it can happen, that values are out of
     204             :             // the bounding box, this can lead to errors
     205       14971 :             _entryPoint =
     206       14971 :                 (_entryPoint.array() < _aabb._min.array()).select(_aabb._min, _entryPoint);
     207       14971 :             _entryPoint =
     208       14971 :                 (_entryPoint.array() > _aabb._max.array()).select(_aabb._max, _entryPoint);
     209             : 
     210             :             // exit point stored in _exitPoint
     211       14971 :             _exitPoint = ray.pointAt(opt->_tmax);
     212       14971 :             _exitPoint = (_exitPoint.array() < _aabb._min.array()).select(_aabb._min, _exitPoint);
     213       14971 :             _exitPoint = (_exitPoint.array() > _aabb._max.array()).select(_aabb._max, _exitPoint);
     214             : 
     215       14971 :             return opt->_tmax - opt->_tmin;
     216       14971 :         } else {
     217        1167 :             return 0;
     218        1167 :         }
     219       16138 :     }
     220             : 
     221      205078 :     bool TraverseAABBJosephsMethod::isInBoundingBox() const { return _isInAABB; }
     222             : 
     223      169679 :     real_t TraverseAABBJosephsMethod::getIntersectionLength() const { return _intersectionLength; }
     224             : 
     225             :     IndexVector_t TraverseAABBJosephsMethod::getCurrentVoxel() const
     226      173340 :     {
     227      173340 :         return _currentPos.template cast<index_t>();
     228      173340 :     }
     229             : 
     230             : } // namespace elsa

Generated by: LCOV version 1.14