2022-09-29 00:46:17 +02:00
|
|
|
#include "scatterometer_handler.h"
|
|
|
|
|
#include "resources.h"
|
|
|
|
|
#include "common/projection/reprojector.h"
|
|
|
|
|
#include "core/style.h"
|
|
|
|
|
#include "common/map/map_drawer.h"
|
2023-10-20 23:33:32 -04:00
|
|
|
#include "common/widgets/stepped_slider.h"
|
2023-09-25 23:36:38 -04:00
|
|
|
#include "imgui/pfd/pfd_utils.h"
|
2023-10-16 11:14:21 -04:00
|
|
|
#include "main_ui.h"
|
2022-09-29 00:46:17 +02:00
|
|
|
|
|
|
|
|
namespace satdump
|
|
|
|
|
{
|
|
|
|
|
void ScatterometerViewerHandler::init()
|
|
|
|
|
{
|
|
|
|
|
products = (ScatterometerProducts *)ViewerHandler::products;
|
|
|
|
|
|
|
|
|
|
if (products->get_scatterometer_type() == products->SCAT_TYPE_ASCAT)
|
|
|
|
|
current_scat_type = SCAT_ASCAT;
|
|
|
|
|
|
|
|
|
|
if (current_scat_type == SCAT_ASCAT)
|
|
|
|
|
{
|
|
|
|
|
select_channel_image_str += std::string("Channel 1 (Back Right)") + '\0';
|
|
|
|
|
select_channel_image_str += std::string("Channel 2 (Down Left)") + '\0';
|
|
|
|
|
select_channel_image_str += std::string("Channel 3 (Back Left)") + '\0';
|
|
|
|
|
select_channel_image_str += std::string("Channel 4 (Front Right)") + '\0';
|
|
|
|
|
select_channel_image_str += std::string("Channel 5 (Back Left)") + '\0';
|
|
|
|
|
select_channel_image_str += std::string("Channel 6 (Front Left)") + '\0';
|
|
|
|
|
|
|
|
|
|
ascat_select_channel_image_str += std::string("Back") + '\0';
|
|
|
|
|
ascat_select_channel_image_str += std::string("Down") + '\0';
|
|
|
|
|
ascat_select_channel_image_str += std::string("Front") + '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (int c = 0; c < (int)products->get_channel_cnt(); c++)
|
|
|
|
|
select_channel_image_str += "Channel " + std::to_string(c + 1) + '\0';
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-01 18:10:00 +01:00
|
|
|
try
|
|
|
|
|
{
|
2023-11-10 18:13:06 +01:00
|
|
|
overlay_handler.set_config(config::main_cfg["user"]["viewer_state"]["products_handler"][products->instrument_name]["overlay_cfg"], false);
|
2023-11-01 18:10:00 +01:00
|
|
|
}
|
2023-11-29 21:30:55 -05:00
|
|
|
catch (std::exception &)
|
2023-11-01 18:10:00 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 15:08:20 -04:00
|
|
|
current_img.init_font(resources::getResourcePath("fonts/font.ttf"));
|
2022-09-29 00:46:17 +02:00
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-22 14:52:06 -04:00
|
|
|
ScatterometerViewerHandler::~ScatterometerViewerHandler()
|
|
|
|
|
{
|
|
|
|
|
handler_thread_pool.stop();
|
|
|
|
|
for (int i = 0; i < handler_thread_pool.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (handler_thread_pool.get_thread(i).joinable())
|
|
|
|
|
handler_thread_pool.get_thread(i).join();
|
|
|
|
|
}
|
2023-11-01 18:10:00 +01:00
|
|
|
|
2023-11-10 18:13:06 +01:00
|
|
|
config::main_cfg["user"]["viewer_state"]["products_handler"][products->instrument_name]["overlay_cfg"] = overlay_handler.get_config();
|
2023-11-01 18:10:00 +01:00
|
|
|
config::saveUserConfig();
|
2023-10-22 14:52:06 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-29 00:46:17 +02:00
|
|
|
void ScatterometerViewerHandler::update()
|
|
|
|
|
{
|
|
|
|
|
if (selected_visualization_id == 0)
|
|
|
|
|
{
|
|
|
|
|
GrayScaleScatCfg cfg;
|
|
|
|
|
cfg.channel = select_channel_image_id;
|
|
|
|
|
cfg.min = scat_grayscale_min;
|
|
|
|
|
cfg.max = scat_grayscale_max;
|
2023-10-19 15:42:54 -04:00
|
|
|
current_img = make_scatterometer_grayscale(*products, cfg);
|
|
|
|
|
image_view.update(current_img);
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
|
|
|
|
else if (selected_visualization_id == 1)
|
|
|
|
|
{
|
|
|
|
|
GrayScaleScatCfg cfg;
|
|
|
|
|
if (current_scat_type == SCAT_ASCAT)
|
|
|
|
|
cfg.channel = ascat_select_channel_id;
|
|
|
|
|
else
|
|
|
|
|
cfg.channel = select_channel_image_id;
|
|
|
|
|
cfg.min = scat_grayscale_min;
|
|
|
|
|
cfg.max = scat_grayscale_max;
|
|
|
|
|
current_image_proj.clear();
|
|
|
|
|
current_img = make_scatterometer_grayscale_projs(*products, cfg, nullptr, ¤t_image_proj);
|
|
|
|
|
|
2023-11-01 18:10:00 +01:00
|
|
|
if (overlay_handler.enabled())
|
2022-09-29 00:46:17 +02:00
|
|
|
{
|
2022-12-15 21:43:39 +01:00
|
|
|
auto proj_func = satdump::reprojection::setupProjectionFunction(current_img.width(), current_img.height(), current_image_proj, {});
|
2023-11-01 18:10:00 +01:00
|
|
|
overlay_handler.apply(current_img, proj_func);
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image_view.update(current_img);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 15:08:20 -04:00
|
|
|
void ScatterometerViewerHandler::asyncUpdate()
|
|
|
|
|
{
|
2023-10-22 14:52:06 -04:00
|
|
|
handler_thread_pool.clear_queue();
|
|
|
|
|
handler_thread_pool.push([this](int)
|
2023-11-01 18:10:00 +01:00
|
|
|
{ async_image_mutex.lock();
|
2023-10-16 21:18:01 -04:00
|
|
|
is_updating = true;
|
2023-10-16 15:08:20 -04:00
|
|
|
logger->info("Update image...");
|
|
|
|
|
update();
|
|
|
|
|
logger->info("Done");
|
2023-10-16 21:18:01 -04:00
|
|
|
is_updating = false;
|
2023-10-16 15:08:20 -04:00
|
|
|
async_image_mutex.unlock(); });
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 00:46:17 +02:00
|
|
|
void ScatterometerViewerHandler::drawMenu()
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::CollapsingHeader("Images"))
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::RadioButton(u8"Raw Image", &selected_visualization_id, 0))
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
2022-09-29 00:46:17 +02:00
|
|
|
if (ImGui::RadioButton(u8"Projected", &selected_visualization_id, 1))
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
2022-09-29 00:46:17 +02:00
|
|
|
|
|
|
|
|
if (selected_visualization_id == 0 || selected_visualization_id == 1)
|
|
|
|
|
{
|
|
|
|
|
if (current_scat_type == SCAT_ASCAT && selected_visualization_id == 1)
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::Combo("###scatchannelcomboid", &ascat_select_channel_id, ascat_select_channel_image_str.c_str()))
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::Combo("###scatchannelcomboid", &select_channel_image_id, select_channel_image_str.c_str()))
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() / 2);
|
|
|
|
|
if (ImGui::SliderInt("##MinScat", &scat_grayscale_min, 0, 1e7, "Min: %d", ImGuiSliderFlags_AlwaysClamp))
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
2022-09-29 00:46:17 +02:00
|
|
|
ImGui::SameLine();
|
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() / 2);
|
|
|
|
|
if (ImGui::SliderInt("##MaxScat", &scat_grayscale_max, 0, 1e7, "Max: %d", ImGuiSliderFlags_AlwaysClamp))
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-16 21:18:01 -04:00
|
|
|
bool save_disabled = is_updating;
|
|
|
|
|
if (save_disabled)
|
|
|
|
|
style::beginDisabled();
|
2022-09-29 00:46:17 +02:00
|
|
|
if (ImGui::Button("Save"))
|
|
|
|
|
{
|
2023-10-22 14:52:06 -04:00
|
|
|
handler_thread_pool.push([this](int)
|
2023-11-01 18:10:00 +01:00
|
|
|
{ async_image_mutex.lock();
|
2023-10-19 15:42:54 -04:00
|
|
|
is_updating = true;
|
|
|
|
|
logger->info("Saving Image...");
|
2023-10-26 18:26:57 -04:00
|
|
|
std::string default_path = config::main_cfg["satdump_directories"]["default_image_output_directory"]["value"].get<std::string>();
|
2023-10-19 15:42:54 -04:00
|
|
|
std::string saved_at = save_image_dialog(products->instrument_name + "_" +
|
|
|
|
|
((selected_visualization_id == 1 && current_scat_type == SCAT_ASCAT) ? std::to_string(ascat_select_channel_id) :
|
2023-10-26 18:26:57 -04:00
|
|
|
std::to_string(select_channel_image_id)), default_path, "Save Image", ¤t_img, &viewer_app->save_type);
|
2023-10-19 15:42:54 -04:00
|
|
|
|
|
|
|
|
if (saved_at == "")
|
|
|
|
|
logger->info("Save cancelled");
|
|
|
|
|
else
|
|
|
|
|
logger->info("Saved current image at %s", saved_at.c_str());
|
|
|
|
|
is_updating = false;
|
|
|
|
|
async_image_mutex.unlock(); });
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
2023-10-16 21:18:01 -04:00
|
|
|
if (save_disabled)
|
|
|
|
|
{
|
|
|
|
|
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
|
|
|
|
|
ImGui::SetTooltip("Updating, please wait...");
|
|
|
|
|
style::endDisabled();
|
|
|
|
|
}
|
2022-09-29 00:46:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::CollapsingHeader("Map Overlay"))
|
|
|
|
|
{
|
|
|
|
|
if (selected_visualization_id != 1)
|
|
|
|
|
style::beginDisabled();
|
2023-10-16 15:08:20 -04:00
|
|
|
|
2023-11-01 18:10:00 +01:00
|
|
|
if (overlay_handler.drawUI())
|
2023-10-16 15:08:20 -04:00
|
|
|
asyncUpdate();
|
|
|
|
|
|
2022-09-29 00:46:17 +02:00
|
|
|
if (selected_visualization_id != 1)
|
|
|
|
|
style::endDisabled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::CollapsingHeader("Projection"))
|
|
|
|
|
{
|
|
|
|
|
ImGui::BeginGroup();
|
|
|
|
|
if (!canBeProjected())
|
|
|
|
|
style::beginDisabled();
|
|
|
|
|
ImGui::Checkbox("Project", &should_project);
|
|
|
|
|
if (!canBeProjected())
|
|
|
|
|
style::endDisabled();
|
|
|
|
|
ImGui::EndGroup();
|
|
|
|
|
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
|
|
|
|
|
{
|
|
|
|
|
ImGui::BeginTooltip();
|
|
|
|
|
if (selected_visualization_id != 1)
|
2024-01-21 14:57:41 -05:00
|
|
|
ImGui::TextColored(style::theme.red, "Select projection view first!");
|
2022-09-29 00:46:17 +02:00
|
|
|
ImGui::EndTooltip();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScatterometerViewerHandler::drawContents(ImVec2 win_size)
|
|
|
|
|
{
|
|
|
|
|
if (selected_visualization_id == 0 || selected_visualization_id == 1)
|
|
|
|
|
{
|
|
|
|
|
image_view.draw(win_size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float ScatterometerViewerHandler::drawTreeMenu()
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScatterometerViewerHandler::canBeProjected()
|
|
|
|
|
{
|
|
|
|
|
return products->has_proj_cfg() &&
|
|
|
|
|
products->has_tle() &&
|
|
|
|
|
products->has_proj_cfg() &&
|
|
|
|
|
products->has_timestamps &&
|
|
|
|
|
selected_visualization_id == 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScatterometerViewerHandler::hasProjection()
|
|
|
|
|
{
|
|
|
|
|
return projection_ready && should_project;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScatterometerViewerHandler::shouldProject()
|
|
|
|
|
{
|
|
|
|
|
return should_project;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ScatterometerViewerHandler::updateProjection(int width, int height, nlohmann::json settings, float *progess)
|
|
|
|
|
{
|
|
|
|
|
if (canBeProjected())
|
|
|
|
|
{
|
|
|
|
|
reprojection::ReprojectionOperation op;
|
|
|
|
|
op.source_prj_info = current_image_proj;
|
|
|
|
|
op.target_prj_info = settings;
|
|
|
|
|
op.img = current_img;
|
|
|
|
|
op.output_width = width;
|
|
|
|
|
op.output_height = height;
|
|
|
|
|
// op.use_draw_algorithm = use_draw_proj_algo;
|
|
|
|
|
// op.img_tle = products->get_tle();
|
|
|
|
|
// op.img_tim = current_timestamps;
|
|
|
|
|
reprojection::ProjectionResult res = reprojection::reproject(op, progess);
|
|
|
|
|
projected_img = res.img;
|
|
|
|
|
projection_ready = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
logger->error("Current image can't be projected!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image::Image<uint16_t> &ScatterometerViewerHandler::getProjection()
|
|
|
|
|
{
|
|
|
|
|
return projected_img;
|
|
|
|
|
}
|
2023-09-26 00:02:27 -04:00
|
|
|
}
|