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 <noreply@anthropic.com>
This commit is contained in:
@@ -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<rgb> &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> &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<float>(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<float>(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> &rgb_image, float d) const {
|
||||
|
||||
Reference in New Issue
Block a user