From 2bd276ae1b2347022b5cb93e285065a5cec14aed Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Fri, 19 Jun 2026 09:44:57 +0200 Subject: [PATCH] preview: draw azimuthal ROIs AddROI now renders azimuthal ROIs in addition to box and circle ROIs: inner/outer arcs at the Q (d) bounds and, for a sector, the two radial edges at the phi bounds. The per-pixel phi comes from the same DiffractionGeometry::Phi_rad used to assign ROIs, so the overlay matches the ROI footprint exactly (including wrap-around sectors). Full-ring azimuthal ROIs draw as two concentric arcs. Co-Authored-By: Claude Opus 4.8 --- preview/PreviewImage.cpp | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/preview/PreviewImage.cpp b/preview/PreviewImage.cpp index 9d820bb7..37076154 100644 --- a/preview/PreviewImage.cpp +++ b/preview/PreviewImage.cpp @@ -36,6 +36,20 @@ constexpr const static rgb plotly[] = {{0x1f, 0x77, 0xb4}, constexpr const static rgb gray = {.r = 0xbe, .g = 0xbe, .b = 0xbe}; +// Smallest difference between two angles in degrees, accounting for wrap-around. +static float AngularDistance_deg(float a, float b) { + float d = std::fabs(a - b); + if (d > 180.0f) + d = 360.0f - d; + return d; +} + +static bool InPhiSector(float phi_deg, float phi_min, float phi_max) { + if (phi_min <= phi_max) + return phi_deg >= phi_min && phi_deg <= phi_max; + return phi_deg >= phi_min || phi_deg <= phi_max; // sector wraps across 0 +} + void PreviewImage::color_pixel(std::vector &ret, int64_t in_xpixel, int64_t in_ypixel,const rgb &color) const { if ((in_xpixel >= 0) && (in_xpixel < xpixel) && (in_ypixel >= 0) && (in_ypixel < ypixel)) ret[(in_ypixel * xpixel + in_xpixel)] = color; @@ -198,6 +212,36 @@ void PreviewImage::AddROI(std::vector &rgb_image) const { } roi_counter++; } + + DiffractionGeometry geom = experiment.GetDiffractionGeometry(); + for (const auto &az: experiment.ROI().GetROIDefinition().azimuthal) { + const int width = 5; + const float r_inner = geom.ResToPxl(az.GetDMax_A()); // larger d -> smaller radius + const float r_outer = geom.ResToPxl(az.GetDMin_A()); + const bool has_phi = az.HasPhi(); + + for (int64_t y = 0; y <= ypixel; y++) { + for (int64_t x = 0; x <= xpixel; x++) { + const float dx = x - beam_x; + const float dy = y - beam_y; + const float dist = sqrtf(dx * dx + dy * dy); + const float phi_deg = geom.Phi_rad(x, y) * 180.0f / static_cast(PI); + + const bool in_sector = !has_phi || InPhiSector(phi_deg, az.GetPhiMin_deg(), az.GetPhiMax_deg()); + const bool on_arc = (std::fabs(dist - r_inner) < width) || (std::fabs(dist - r_outer) < width); + + // Radial edges of a sector: angular tolerance scaled to keep ~constant pixel width. + const float tol_deg = (dist > 1.0f) ? width / dist * 180.0f / static_cast(PI) : 180.0f; + const bool on_edge = has_phi && (dist >= r_inner) && (dist <= r_outer) + && (AngularDistance_deg(phi_deg, az.GetPhiMin_deg()) < tol_deg + || AngularDistance_deg(phi_deg, az.GetPhiMax_deg()) < tol_deg); + + if ((on_arc && in_sector) || on_edge) + roi(rgb_image, x, y, roi_counter); + } + } + roi_counter++; + } } void PreviewImage::AddResolutionRing(std::vector &rgb_image, float d) const {