diff --git a/include/aare/InclusiveROI.hpp b/include/aare/InclusiveROI.hpp index 8c6f5e7..4f67101 100644 --- a/include/aare/InclusiveROI.hpp +++ b/include/aare/InclusiveROI.hpp @@ -42,8 +42,8 @@ inline InclusiveROI toInclusiveROI(ROI const &r) { return {r.xmin, r.xmax - 1, r.ymin, r.ymax - 1}; }; -inline ROI toHalfopenROI(InclusiveROI const& r) { - return {r.xmin, r.xmax + 1, r.ymin, r.ymax + 1}; +inline ROI toHalfopenROI(InclusiveROI const &r) { + return {r.xmin, r.xmax + 1, r.ymin, r.ymax + 1}; } /*********************** @@ -122,4 +122,14 @@ static inline InclusiveROI unite(InclusiveROI const &a, InclusiveROI const &b) { throw std::runtime_error("ROIs cannot be united contiguously"); } +static inline InclusiveROI alignROIs(InclusiveROI const &roi_user, + InclusiveROI const &roi_base) { + const int dx = roi_base.xmin; + const int dy = roi_base.ymin; // + bond_shift_y; + + return {roi_user.xmin - dx, roi_user.xmax - dx, roi_user.ymin - dy, + roi_user.ymax - dy}; + // return translate(roi_user, roi_base.xmin, roi_base.ymin); +} + } // namespace aare::inclusiveroi::geom \ No newline at end of file diff --git a/include/aare/RemapAlgorithm.hpp b/include/aare/RemapAlgorithm.hpp index 63670ac..6a29bc1 100644 --- a/include/aare/RemapAlgorithm.hpp +++ b/include/aare/RemapAlgorithm.hpp @@ -4,8 +4,9 @@ namespace aare::remap::algo { defs::StrixelGroupToPixelMap - generate_strixel_to_pixel_map(defs::SensorGroupConfig, - defs::SensorPlacement); +generate_strixel_to_pixel_map(defs::SensorGroupConfig, defs::SensorPlacement, + InclusiveROI user_roi); std::vector - generate_strixel_to_pixel_maps(defs::SensorConfig, defs::SensorPlacement); +generate_strixel_to_pixel_maps(defs::SensorConfig, defs::SensorPlacement, + InclusiveROI user_roi); } // namespace aare::remap::algo \ No newline at end of file diff --git a/src/RemapAlgorithm.cpp b/src/RemapAlgorithm.cpp new file mode 100644 index 0000000..6dc8861 --- /dev/null +++ b/src/RemapAlgorithm.cpp @@ -0,0 +1,135 @@ +#include "aare/RemapAlgorithm.hpp" + +#include + +namespace aare::remap::algo { + +defs::StrixelGroupToPixelMap +generate_strixel_to_pixel_map(defs::SensorGroupConfig group_config, + defs::SensorPlacement placement, + InclusiveROI roi_user) { + + int multiplicity = group_config.strixel.multiplicity; + double pitch = group_config.strixel.pitch_um; + defs::Rotation rot = placement.rotation; + InclusiveROI roi_group = group_config.placement_on_sensor; + + // Helper to make sure that we work with a correct number of strixel columns + // (i.e. that we do not map pixel columns if the ncols in ASIC pixel + // coordinates is not a multiple of strixel ncols) + if (group_config.placement_on_sensor.width() % multiplicity != 0) + throw std::logic_error("Group ROI width not divisible by multiplicity"); + + const int tot_ncols_strx = + group_config.placement_on_sensor.width() / multiplicity; + + // Define mod ordering (Normal or Inverse) + std::vector mods(multiplicity); + for (int i = 0; i < multiplicity; i++) + mods[i] = i; + if (rot == defs::Rotation::Inverse) + std::reverse(mods.begin(), mods.end()); + + // -- 1) Transform user roi (rx_roi) into sensor-local coordinates + InclusiveROI roi_user_local = + inclusiveroi::geom::alignROIs(roi_user, placement.placement_on_module); + std::cout << "Transformed user ROI: " << roi_user_local << std::endl; + + // -- 2) Compute effective ROI = intersection( roi_user, roi_group ) + InclusiveROI eff = inclusiveroi::geom::intersect(roi_user_local, roi_group); + if (eff.xmax < eff.xmin || eff.ymax < eff.ymin) { + return {-1, 0.0, InclusiveROI::emptyROI(), {}}; // empty + } + + // DEBUG + std::cout << "Result of intersecting ROIs " << eff << '\n'; + + //-- 3) Determine min/max row/col of strixel grid before allocating + // (This may vary from the native grid of the group because of ROI + // intersection.) + int min_row_strx = std::numeric_limits::max(); + int max_row_strx = std::numeric_limits::min(); + int min_col_strx = std::numeric_limits::max(); + int max_col_strx = std::numeric_limits::min(); + + for (int y = eff.ymin; y <= eff.ymax; ++y) { + for (int x = eff.xmin; x <= eff.xmax; ++x) { + + const int dx = x - roi_group.xmin; + const int dy = (y - roi_group.ymin); + + const int m = dx % multiplicity; + const int col_strx = dx / multiplicity; + const int row_strx = dy * multiplicity + mods[m]; + + if (col_strx < 0 || row_strx < 0) + continue; + if (col_strx >= tot_ncols_strx) + continue; + + min_row_strx = std::min(min_row_strx, row_strx); + max_row_strx = std::max(max_row_strx, row_strx); + min_col_strx = std::min(min_col_strx, col_strx); + max_col_strx = std::max(max_col_strx, col_strx); + } + } + + if (min_row_strx > max_row_strx) { + // nothing mapped + return {multiplicity, pitch, eff, {}}; + } + + const int nrows_strx = max_row_strx - min_row_strx + 1; + const int ncols_strx = max_col_strx - min_col_strx + 1; + + // Allocate strixel grid order map + aare::NDArray map({nrows_strx, ncols_strx}, -1); + + // -- 4) For each ASIC pixel in eff ROI, compute remapped (row,col) in group + // local coordinates + for (int y = eff.ymin; y <= eff.ymax; ++y) { + for (int x = eff.xmin; x <= eff.xmax; ++x) { + + const int dx = x - roi_group.xmin; + const int dy = (y - roi_group.ymin); + + const int m = dx % multiplicity; // since eff is intersected with + // roi_group, dx >= 0, so no issue + const int col_strx = dx / multiplicity; + const int row_strx = dy * multiplicity + mods[m]; + + if (col_strx < min_col_strx || row_strx < min_row_strx) + continue; + + const int cstrx = col_strx - min_col_strx; + const int rstrx = row_strx - min_row_strx; + + if (rstrx >= 0 && rstrx < nrows_strx && cstrx >= 0 && + cstrx < ncols_strx) { + // index into !!!ORIGINAL USER ROI GRID!!! (use local + // coordinates) + const int user_pixel = + (y - roi_user_local.ymin) * roi_user_local.width() + + (x - roi_user_local.xmin); + + map(rstrx, cstrx) = user_pixel; + } + } + } + + return {multiplicity, pitch, eff, map}; +}; + +std::vector +generate_strixel_to_pixel_maps(defs::SensorConfig sensor_config, + defs::SensorPlacement placement, + InclusiveROI roi_user) { + std::vector maps; + for (auto &group_config : sensor_config.group_configs) { + maps.emplace_back( + generate_strixel_to_pixel_map(group_config, placement, roi_user)); + } + return maps; +} + +} // namespace aare::remap::algo \ No newline at end of file