viewer: download/upload ROIs to the broker

Add Download and "Upload to server" buttons to the ROI panel. The HTTP
reader gains GetROIDefinitions (GET /config/roi) and UploadROIDefinitions
(PUT /config/roi), converting between ROIDefinition and the generated
Roi_definitions model (including the optional azimuthal phi sector), the
same shapes OpenAPIConvert uses on the server. Download applies the
fetched ROIs through SetROIDefinition; upload pushes the current ones.
Both are no-ops unless the viewer is connected to a broker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 14:47:10 +02:00
co-authored by Claude Opus 4.8
parent 142cb88aa8
commit b2c60dfbd0
9 changed files with 136 additions and 0 deletions
+89
View File
@@ -9,6 +9,8 @@
#include "../broker/gen/model/Image_buffer_status.h"
#include "../broker/gen/model/Plots.h"
#include "../broker/gen/model/Broker_status.h"
#include "../broker/gen/model/Roi_definitions.h"
#include "../common/JFJochMath.h"
#include "../image_analysis/bragg_integration/CalcISigma.h"
void JFJochHttpReader::Close() {
@@ -402,6 +404,93 @@ void JFJochHttpReader::UploadUserMask(const std::vector<uint32_t>& mask) {
"Server rejected user mask upload");
}
ROIDefinition JFJochHttpReader::GetROIDefinitions() const {
std::unique_lock ul(http_mutex);
if (addr.empty())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "HTTP address not set");
httplib::Client cli_cmd(addr);
auto res = cli_cmd.Get("/config/roi");
if (!res || res->status != httplib::StatusCode::OK_200)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Could not get ROI definitions");
org::openapitools::server::model::Roi_definitions input = nlohmann::json::parse(res->body);
ROIDefinition out;
for (const auto &i : input.getBox().getRois())
out.boxes.emplace_back(i.getName(), i.getMinXPxl(), i.getMaxXPxl(), i.getMinYPxl(), i.getMaxYPxl());
for (const auto &i : input.getCircle().getRois())
out.circles.emplace_back(i.getName(), i.getCenterXPxl(), i.getCenterYPxl(), i.getRadiusPxl());
for (const auto &i : input.getAzim().getRois()) {
float phi_min = 0, phi_max = 0;
if (i.phiMinDegIsSet() && i.phiMaxDegIsSet()) {
phi_min = i.getPhiMinDeg();
phi_max = i.getPhiMaxDeg();
}
const float d_min = (i.getQMaxRecipA() == 0.0f) ? 0.0f : 2.0f * static_cast<float>(PI) / i.getQMaxRecipA();
const float d_max = (i.getQMinRecipA() == 0.0f) ? 0.0f : 2.0f * static_cast<float>(PI) / i.getQMinRecipA();
out.azimuthal.emplace_back(i.getName(), d_min, d_max, phi_min, phi_max);
}
return out;
}
void JFJochHttpReader::UploadROIDefinitions(const ROIDefinition &rois) const {
std::unique_lock ul(http_mutex);
if (addr.empty())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "HTTP address not set");
namespace model = org::openapitools::server::model;
model::Roi_definitions out;
model::Roi_box_list bl;
std::vector<model::Roi_box> boxes;
for (const auto &b : rois.boxes) {
model::Roi_box e;
e.setName(b.GetName());
e.setMinXPxl(b.GetXMin()); e.setMaxXPxl(b.GetXMax());
e.setMinYPxl(b.GetYMin()); e.setMaxYPxl(b.GetYMax());
boxes.push_back(e);
}
bl.setRois(boxes);
out.setBox(bl);
model::Roi_circle_list cl;
std::vector<model::Roi_circle> circles;
for (const auto &c : rois.circles) {
model::Roi_circle e;
e.setName(c.GetName());
e.setCenterXPxl(c.GetX()); e.setCenterYPxl(c.GetY());
e.setRadiusPxl(c.GetRadius_pxl());
circles.push_back(e);
}
cl.setRois(circles);
out.setCircle(cl);
model::Roi_azim_list al;
std::vector<model::Roi_azimuthal> azim;
for (const auto &a : rois.azimuthal) {
model::Roi_azimuthal e;
e.setName(a.GetName());
e.setQMinRecipA(a.GetQMin_recipA());
e.setQMaxRecipA(a.GetQMax_recipA());
if (a.HasPhi()) {
e.setPhiMinDeg(a.GetPhiMin_deg());
e.setPhiMaxDeg(a.GetPhiMax_deg());
}
azim.push_back(e);
}
al.setRois(azim);
out.setAzim(al);
nlohmann::json j = out;
httplib::Client cli_cmd(addr);
auto res = cli_cmd.Put("/config/roi", j.dump(), "application/json");
if (!res)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Failed to connect to server to upload ROIs");
if (res->status != httplib::StatusCode::OK_200)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Server rejected ROI upload");
}
std::vector<SpotToSave> JFJochHttpReader::ReadSpots(int64_t image) const {
std::unique_lock ul(http_mutex);