LCOV - code coverage report
Current view: top level - elsa/generators - EllipCylinder.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 84 84 100.0 %
Date: 2024-12-21 07:37:52 Functions: 7 9 77.8 %

          Line data    Source code
       1             : #include "EllipCylinder.h"
       2             : 
       3             : namespace elsa::phantoms
       4             : {
       5             : 
       6             :     template <typename data_t>
       7             :     EllipCylinder<data_t>::EllipCylinder(Orientation o, data_t amplit, elsa::phantoms::Vec3i center,
       8             :                                          Vec2X<data_t> halfAxis, data_t length)
       9             :         : _orientation{o}, _amplit{amplit}, _center{center}, _halfAxis{halfAxis}, _length{length}
      10          61 :     {
      11             : 
      12          61 :         aSqr = _halfAxis[INDEX_A] * _halfAxis[INDEX_A];
      13          61 :         bSqr = _halfAxis[INDEX_B] * _halfAxis[INDEX_B];
      14          61 :         aSqrbSqr = aSqr * bSqr;
      15          61 :     };
      16             : 
      17             :     template <typename data_t>
      18             :     bool EllipCylinder<data_t>::isInEllipCylinder(const Vec3i& idx) const
      19        1584 :     {
      20             :         // Depending on the orientation only one part is compiled
      21        1584 :         if (_orientation == Orientation::X_AXIS) {
      22          46 :             return (double(idx[INDEX_Y] * idx[INDEX_Y]) * bSqr
      23          46 :                     + double(idx[INDEX_Z] * idx[INDEX_Z]) * aSqr)
      24          46 :                    <= aSqrbSqr;
      25        1538 :         } else if (_orientation == Orientation::Y_AXIS) {
      26          32 :             return (double(idx[INDEX_X] * idx[INDEX_X]) * bSqr
      27          32 :                     + double(idx[INDEX_Z] * idx[INDEX_Z]) * aSqr)
      28          32 :                    <= aSqrbSqr;
      29        1506 :         } else {
      30        1506 :             return (double(idx[INDEX_X] * idx[INDEX_X]) * bSqr
      31        1506 :                     + double(idx[INDEX_Y] * idx[INDEX_Y]) * aSqr)
      32        1506 :                    <= aSqrbSqr;
      33        1506 :         }
      34        1584 :     };
      35             : 
      36             :     /**
      37             :      * @brief returns the min and max value of the axis to allow length bigger than the dimension of
      38             :      * the datacontainer. If the length is inside the container, there is no clipping. Return value
      39             :      * are final voxel indices
      40             :      *
      41             :      */
      42             :     std::pair<index_t, index_t> checkBounds(index_t halfLength, index_t center,
      43             :                                             index_t maxDataContainer)
      44          61 :     {
      45          61 :         index_t min, max;
      46          61 :         if (halfLength + center < maxDataContainer) {
      47          55 :             max = halfLength + center;
      48          55 :         } else {
      49           6 :             max = maxDataContainer;
      50           6 :         }
      51             : 
      52          61 :         if (center - halfLength > 0) {
      53          57 :             min = center - halfLength;
      54          57 :         } else {
      55           4 :             min = 0;
      56           4 :         }
      57             : 
      58          61 :         return {min, max};
      59          61 :     }
      60             : 
      61             :     template <Blending b, typename data_t>
      62             :     void rasterize(EllipCylinder<data_t>& el, VolumeDescriptor& dd, DataContainer<data_t>& dc)
      63          61 :     {
      64             :         // check ellipse in origin, mirror 4 points, draw line in the orthogonal directions with
      65             :         // length
      66             : 
      67          61 :         Vec3i idx(3);
      68          61 :         idx << 0, 0, 0;
      69             : 
      70          61 :         auto strides = dd.getProductOfCoefficientsPerDimension();
      71             : 
      72             :         // global offests for a fast memory reuse in the for loops
      73          61 :         index_t aOffset = 0;
      74          61 :         index_t aOffsetNeg = 0;
      75             : 
      76          61 :         index_t bOffset = 0;
      77          61 :         index_t bOffsetNeg = 0;
      78             : 
      79          61 :         index_t cOffset = 0;
      80             : 
      81          61 :         Vec3i _center = el.getCenter();
      82          61 :         data_t _amplit = el.getAmplitude();
      83             : 
      84          61 :         int TEMP_A = INDEX_X;
      85          61 :         int TEMP_B = INDEX_Y;
      86          61 :         int TEMP_C = INDEX_Z;
      87             : 
      88          61 :         if (el.getOrientation() == Orientation::X_AXIS) {
      89           4 :             TEMP_A = INDEX_Y;
      90           4 :             TEMP_B = INDEX_Z;
      91           4 :             TEMP_C = INDEX_X;
      92             : 
      93          57 :         } else if (el.getOrientation() == Orientation::Y_AXIS) {
      94           4 :             TEMP_A = INDEX_X;
      95           4 :             TEMP_B = INDEX_Z;
      96           4 :             TEMP_C = INDEX_Y;
      97           4 :         }
      98             : 
      99          61 :         index_t halfLength = std::lround(el.getLength() / 2);
     100             : 
     101          61 :         auto [minC, maxC] = checkBounds(halfLength, _center[INDEX_C],
     102          61 :                                         dd.getNumberOfCoefficientsPerDimension()[INDEX_C] - 1);
     103             : 
     104             :         // check ellipse on AxB Plane, draw ellipse along the C axis from minC to maxC
     105         264 :         for (; el.isInEllipCylinder(idx); idx[TEMP_A]++) {
     106         203 :             aOffset = (idx[TEMP_A] + _center[TEMP_A]) * strides[TEMP_A];
     107         203 :             aOffsetNeg = (-idx[TEMP_A] + _center[TEMP_A]) * strides[TEMP_A];
     108             : 
     109        1320 :             for (; el.isInEllipCylinder(idx); idx[TEMP_B]++) {
     110        1117 :                 bOffset = (idx[TEMP_B] + _center[TEMP_B]) * strides[TEMP_B];
     111        1117 :                 bOffsetNeg = (-idx[TEMP_B] + _center[TEMP_B]) * strides[TEMP_B];
     112             : 
     113       53674 :                 for (index_t line = minC; line <= maxC; line++) {
     114       52557 :                     cOffset = line * strides[TEMP_C];
     115             : 
     116       52557 :                     blend<b>(dc, aOffset + bOffset + cOffset, _amplit);
     117             : 
     118       52557 :                     if (idx[TEMP_A] != 0) {
     119       49246 :                         blend<b>(dc, aOffsetNeg + bOffset + cOffset, _amplit);
     120       49246 :                     }
     121             : 
     122       52557 :                     if (idx[TEMP_B] != 0) {
     123       47556 :                         blend<b>(dc, aOffset + bOffsetNeg + cOffset, _amplit);
     124       47556 :                     }
     125             : 
     126       52557 :                     if (idx[TEMP_A] != 0 && idx[TEMP_B] != 0) {
     127       44786 :                         blend<b>(dc, aOffsetNeg + bOffsetNeg + cOffset, _amplit);
     128       44786 :                     }
     129       52557 :                 };
     130        1117 :                 idx[TEMP_C] = 0;
     131        1117 :             }
     132         203 :             idx[TEMP_B] = 0;
     133         203 :         }
     134          61 :     };
     135             : 
     136             :     // ------------------------------------------
     137             :     // explicit template instantiation
     138             :     template class EllipCylinder<float>;
     139             :     template class EllipCylinder<double>;
     140             : 
     141             :     template void rasterize<Blending::ADDITION, float>(EllipCylinder<float>& el,
     142             :                                                        VolumeDescriptor& dd,
     143             :                                                        DataContainer<float>& dc);
     144             :     template void rasterize<Blending::ADDITION, double>(EllipCylinder<double>& el,
     145             :                                                         VolumeDescriptor& dd,
     146             :                                                         DataContainer<double>& dc);
     147             : 
     148             :     template void rasterize<Blending::OVERWRITE, float>(EllipCylinder<float>& el,
     149             :                                                         VolumeDescriptor& dd,
     150             :                                                         DataContainer<float>& dc);
     151             :     template void rasterize<Blending::OVERWRITE, double>(EllipCylinder<double>& el,
     152             :                                                          VolumeDescriptor& dd,
     153             :                                                          DataContainer<double>& dc);
     154             : 
     155             : } // namespace elsa::phantoms

Generated by: LCOV version 1.14