diff --git a/src/StrixelPixelRemapAlgorithm.cpp b/src/StrixelPixelRemapAlgorithm.cpp index 45de50fc..0dd4c0d5 100644 --- a/src/StrixelPixelRemapAlgorithm.cpp +++ b/src/StrixelPixelRemapAlgorithm.cpp @@ -13,10 +13,10 @@ namespace aare::remap::algo { * The order is intentional because bond shifts are defined in the * sensor's native coordinate system. */ -inline InclusiveROI shift_rotate_roi(InclusiveROI roi, - defs::SensorPixelGeometry const &pixel, - defs::BondShift bond_shift, - defs::Rotation rot) { +inline InclusiveROI +update_pixel_group_placement(InclusiveROI roi, + defs::SensorPixelGeometry const &pixel, + defs::BondShift bond_shift, defs::Rotation rot) { // If there is a bond shift, translate the roi if (bond_shift.x != 0 || bond_shift.y != 0) roi = aare::inclusiveroi::geom::translate(roi, bond_shift.x, @@ -72,6 +72,7 @@ inline InclusiveROI shift_rotate_roi(InclusiveROI roi, * - the generated strixel-to-user-pixel order map; * - the effective pixel ROI covered by the map. * + * @throws std::logic_error For negative or zero strixel multiplicity. * @throws std::logic_error If the group ROI width is not divisible by * the strixel multiplicity. */ @@ -83,6 +84,10 @@ strixel_to_pixel_map(defs::GroupConfig const &group_config, const int multiplicity = group_config.strixel.multiplicity; + // Defensive check to be sure misconfiguration is avoided + if (multiplicity <= 0) + throw std::logic_error("Strixel multiplicity must be positive"); + // The group must contain an integer number of strixel columns. const auto group_width = group_config.placement_on_sensor.width(); @@ -102,25 +107,22 @@ strixel_to_pixel_map(defs::GroupConfig const &group_config, // -- 1) Rebase the user ROI (rx_roi) into sensor-local coordinates const InclusiveROI roi_user_local = inclusiveroi::geom::rebaseROI(roi_user, placement.placement_on_module); - // LOG(logDEBUG) - std::cout + LOG(logDEBUG) << "aare::remap::algo::strixel_to_pixel_map: Transformed user ROI: " << roi_user_local << std::endl; - // LOG(logDEBUG) - std::cout << "aare::remap::algo::strixel_to_pixel_map: Group ROI " - "before transformation (as in global config)" - << group_config.placement_on_sensor << '\n'; + LOG(logDEBUG) << "aare::remap::algo::strixel_to_pixel_map: Group ROI " + "before transformation (as in global config)" + << group_config.placement_on_sensor << '\n'; // -- 2) Apply the physical bond shift first, sensor rotation second. const InclusiveROI roi_group = - shift_rotate_roi(group_config.placement_on_sensor, pixel, bond_shift, - placement.rotation); + update_pixel_group_placement(group_config.placement_on_sensor, pixel, + bond_shift, placement.rotation); - // LOG(logDEBUG) - std::cout << "aare::remap::algo::strixel_to_pixel_map: Group ROI after " - "transformation (as in local transformation) " - << roi_group << '\n'; + LOG(logDEBUG) << "aare::remap::algo::strixel_to_pixel_map: Group ROI after " + "transformation (as in local transformation) " + << roi_group << '\n'; // -- 3) Compute effective ROI = intersection( roi_user, roi_group ) // Only pixels covered by both the user ROI and the transformed group @@ -131,13 +133,15 @@ strixel_to_pixel_map(defs::GroupConfig const &group_config, // If ROIs don't intersect, return empty if (effective_roi.xmax < effective_roi.xmin || effective_roi.ymax < effective_roi.ymin) { + LOG(logDEBUG) + << "Warning: User-supplied ROI does not intersect with configured " + "strixel ROI, returned map is empty!\n"; return {{}, InclusiveROI::emptyROI()}; } - // LOG(logDEBUG) - std::cout << "aare::remap::algo::strixel_to_pixel_map: Result of " - "intersecting ROIs " - << effective_roi << '\n'; + LOG(logDEBUG) << "aare::remap::algo::strixel_to_pixel_map: Result of " + "intersecting ROIs " + << effective_roi << '\n'; /****************************** * Core of the algorithm @@ -160,29 +164,24 @@ strixel_to_pixel_map(defs::GroupConfig const &group_config, //-- 4) Determine the range of strixel coordinates touched by the effective // ROI. - int min_row = std::numeric_limits::max(); - int max_row = std::numeric_limits::min(); - int min_col = std::numeric_limits::max(); - int max_col = std::numeric_limits::min(); + // + // Since effective_roi is contained in roi_group: + // dx = x - roi_group.xmin >= 0 + // dy = y - roi_group.ymin >= 0 + // + // The strixel column is dx / multiplicity. + // Each pixel row maps onto a complete block of `multiplicity` + // strixel rows, regardless of the modulo ordering. + const int min_col = (effective_roi.xmin - roi_group.xmin) / multiplicity; - for (int y = effective_roi.ymin; y <= effective_roi.ymax; ++y) { - for (int x = effective_roi.xmin; x <= effective_roi.xmax; ++x) { + const int max_col = (effective_roi.xmax - roi_group.xmin) / multiplicity; - auto [row, col] = pixel_to_strixel(x, y); + const int min_row = (effective_roi.ymin - roi_group.ymin) * multiplicity; - if (col >= total_strixel_columns) - continue; - - min_row = std::min(min_row, row); - max_row = std::max(max_row, row); - min_col = std::min(min_col, col); - max_col = std::max(max_col, col); - } - } - - if (min_row > max_row) { - return {{}, effective_roi}; // nothing mapped - } + // Catch the first row that is out of bounds (next multiplicity group) and + // calculate -1 + const int max_row = + (effective_roi.ymax - roi_group.ymin + 1) * multiplicity - 1; // Now from the found bounds of the strixel grid, we define the space to // allocate for the order map @@ -192,8 +191,7 @@ strixel_to_pixel_map(defs::GroupConfig const &group_config, // And allocate aare::NDArray map({nrows, ncols}, -1); - // LOG(logDEBUG) - std::cout + LOG(logDEBUG) << "aare::remap::algo::strixel_to_pixel_map: Resulting strixel grid: (" << map.shape(0) << ", " << map.shape(1) << ")" << '\n'; @@ -206,8 +204,7 @@ strixel_to_pixel_map(defs::GroupConfig const &group_config, const int map_col = col - min_col; const int map_row = row - min_row; - // index into !!!ORIGINAL USER ROI GRID!!! (use local - // coordinates) + // index into !!!ORIGINAL USER ROI GRID!!! const ssize_t user_pixel = static_cast(y - roi_user_local.ymin) * roi_user_local.width() +