ROIAzimuthal can now be restricted to an azimuthal-angle sector in addition to its Q/d range, enabling STXM-style directional ROIs. phi bounds are optional (both-or-neither); absent means a full 360 ring, so existing Q-only azimuthal ROIs are unchanged. - ROIElement::CheckROI gains a phi_deg argument; box/circle ignore it. - MarkROI gains an optional phi_map; ROIMap builds it from Phi_rad alongside the resolution map only when azimuthal ROIs are present. - phi bounds are normalized to [0,360) and wrap-around sectors are supported (phi_min > phi_max). - ROIConfigAzim carries phi_min/phi_max (kept trivially copyable for the union; phi_min == phi_max means full ring). No phi crosses the wire yet (CBOR/API wiring follows separately). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
88 lines
2.5 KiB
C++
88 lines
2.5 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <cmath>
|
|
#include "JFJochMath.h"
|
|
#include "ROIAzimuthal.h"
|
|
#include "JFJochException.h"
|
|
|
|
static float NormalizePhi_deg(float phi) {
|
|
phi = std::fmod(phi, 360.0f);
|
|
if (phi < 0)
|
|
phi += 360.0f;
|
|
return phi;
|
|
}
|
|
|
|
ROIAzimuthal::ROIAzimuthal(const std::string &in_name, float in_d_min_A, float in_d_max_A,
|
|
std::optional<float> in_phi_min_deg, std::optional<float> in_phi_max_deg)
|
|
: ROIElement(in_name) {
|
|
if ((in_d_min_A <= 0) || (in_d_max_A <= 0))
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Resolution cannot be zero or negative");
|
|
if (in_d_min_A > in_d_max_A) {
|
|
d_max_A = in_d_min_A;
|
|
d_min_A = in_d_max_A;
|
|
} else {
|
|
d_max_A = in_d_max_A;
|
|
d_min_A = in_d_min_A;
|
|
}
|
|
|
|
if (in_phi_min_deg && in_phi_max_deg) {
|
|
has_phi = true;
|
|
phi_min_deg = NormalizePhi_deg(in_phi_min_deg.value());
|
|
phi_max_deg = NormalizePhi_deg(in_phi_max_deg.value());
|
|
}
|
|
}
|
|
|
|
float ROIAzimuthal::GetDMin_A() const {
|
|
return d_min_A;
|
|
}
|
|
|
|
float ROIAzimuthal::GetDMax_A() const {
|
|
return d_max_A;
|
|
}
|
|
|
|
bool ROIAzimuthal::HasPhi() const {
|
|
return has_phi;
|
|
}
|
|
|
|
float ROIAzimuthal::GetPhiMin_deg() const {
|
|
return phi_min_deg;
|
|
}
|
|
|
|
float ROIAzimuthal::GetPhiMax_deg() const {
|
|
return phi_max_deg;
|
|
}
|
|
|
|
bool ROIAzimuthal::CheckROI(int64_t x, int64_t y, float resolution, float phi_deg) const {
|
|
if (resolution < d_min_A || resolution > d_max_A)
|
|
return false;
|
|
if (!has_phi)
|
|
return true;
|
|
// A sector with phi_min > phi_max wraps across 0 degrees.
|
|
if (phi_min_deg <= phi_max_deg)
|
|
return (phi_deg >= phi_min_deg) && (phi_deg <= phi_max_deg);
|
|
else
|
|
return (phi_deg >= phi_min_deg) || (phi_deg <= phi_max_deg);
|
|
}
|
|
|
|
float ROIAzimuthal::GetQMax_recipA() const {
|
|
return 2.0f * PI / d_min_A;
|
|
}
|
|
|
|
float ROIAzimuthal::GetQMin_recipA() const {
|
|
return 2.0f * PI / d_max_A;
|
|
}
|
|
|
|
ROIConfig ROIAzimuthal::ExportMetadata() const {
|
|
double qmin = GetQMin_recipA();
|
|
double qmax = GetQMax_recipA();
|
|
return ROIConfig{
|
|
.type = ROIConfig::ROIType::Azim,
|
|
.name = name,
|
|
.azim = ROIConfigAzim{.qmin = qmin, .qmax = qmax,
|
|
.phi_min = has_phi ? phi_min_deg : 0.0f,
|
|
.phi_max = has_phi ? phi_max_deg : 0.0f}
|
|
};
|
|
}
|