mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
619 lines
28 KiB
C++
619 lines
28 KiB
C++
#include "viewer.h"
|
|
#include "common/map/map_drawer.h"
|
|
#include "common/projection/reprojector.h"
|
|
#include "logger.h"
|
|
#include "resources.h"
|
|
#include "core/style.h"
|
|
#include "main_ui.h"
|
|
#include "common/image/image_utils.h"
|
|
#include "common/widgets/switch.h"
|
|
#include "libs/tiny-regex-c/re.h"
|
|
#include "imgui/pfd/pfd_utils.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
namespace satdump
|
|
{
|
|
re_t osm_url_regex = re_compile("https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)\\/\\{([xyz])\\}\\/\\{((?!\\3)[xyz])\\}\\/\\{((?!\\3)(?!\\4)[xyz])\\}(\\.png|\\.jpg|\\.jpeg|\\.j2k|)");
|
|
int osm_url_regex_len = 0;
|
|
|
|
void ViewerApplication::drawProjectionPanel()
|
|
{
|
|
if (ImGui::CollapsingHeader("Projection", ImGuiTreeNodeFlags_DefaultOpen))
|
|
{
|
|
ImGui::Text("Output image : ");
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.40f);
|
|
ImGui::InputInt("##width", &projections_image_width, 0);
|
|
ImGui::SameLine();
|
|
ImGui::Text(u8"\uea76");
|
|
ImGui::SameLine();
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.40f);
|
|
ImGui::InputInt("##height", &projections_image_height, 0);
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.96f);
|
|
ImGui::Combo("##targetproj", &projections_current_selected_proj, "Equirectangular\0"
|
|
"Mercator\0"
|
|
"Stereo\0"
|
|
"Satellite (TPERS)\0"
|
|
"Azimuthal Equidistant\0");
|
|
|
|
if (projections_current_selected_proj == 0)
|
|
{
|
|
ImGui::Text("Top Left Coordinates :");
|
|
ImGui::InputFloat("Lat##tl", &projections_equirectangular_tl_lat);
|
|
ImGui::InputFloat("Lon##tl", &projections_equirectangular_tl_lon);
|
|
ImGui::Spacing();
|
|
ImGui::Text("Bottom Right Coordinates :");
|
|
ImGui::InputFloat("Lat##br", &projections_equirectangular_br_lat);
|
|
ImGui::InputFloat("Lon##br", &projections_equirectangular_br_lon);
|
|
}
|
|
else if (projections_current_selected_proj == 1)
|
|
{
|
|
}
|
|
else if (projections_current_selected_proj == 2)
|
|
{
|
|
ImGui::Text("Center Coordinates :");
|
|
ImGui::InputFloat("Lat##stereo", &projections_stereo_center_lat);
|
|
ImGui::InputFloat("Lon##stereo", &projections_stereo_center_lon);
|
|
ImGui::Spacing();
|
|
ImGui::InputFloat("Scale##stereo", &projections_stereo_scale);
|
|
}
|
|
else if (projections_current_selected_proj == 3)
|
|
{
|
|
ImGui::Text("Center Coordinates :");
|
|
ImGui::InputFloat("Lat##tpers", &projections_tpers_lat);
|
|
ImGui::InputFloat("Lon##tpers", &projections_tpers_lon);
|
|
ImGui::Spacing();
|
|
ImGui::InputFloat("Altitude (km)##tpers", &projections_tpers_alt);
|
|
ImGui::InputFloat("Angle##tpers", &projections_tpers_ang);
|
|
ImGui::InputFloat("Azimuth##tpers", &projections_tpers_azi);
|
|
}
|
|
else if (projections_current_selected_proj == 4)
|
|
{
|
|
ImGui::Text("Center Coordinates :");
|
|
ImGui::InputFloat("Lat##eqaz", &projections_azeq_lat);
|
|
ImGui::InputFloat("Lon##eqaz", &projections_azeq_lon);
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
bool beginGenHide = projections_are_generating;
|
|
if (projections_are_generating || projection_layers.size() == 0)
|
|
style::beginDisabled();
|
|
if (ImGui::Button("Generate Projection"))
|
|
{
|
|
ui_thread_pool.push([this](int)
|
|
{
|
|
logger->info("Update projection...");
|
|
generateProjectionImage();
|
|
logger->info("Done"); });
|
|
|
|
config::main_cfg["user"]["viewer_state"]["projections"] = serialize_projections_config();
|
|
config::saveUserConfig();
|
|
}
|
|
if ((projections_are_generating || projection_layers.size() == 0) && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
|
|
ImGui::SetTooltip("No layers loaded!");
|
|
if ((projections_are_generating && beginGenHide) || projection_layers.size() == 0)
|
|
style::endDisabled();
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (ImGui::Button("Save Projected Image"))
|
|
{
|
|
std::string default_ext = satdump::config::main_cfg["satdump_general"]["image_format"]["value"].get<std::string>();
|
|
std::string default_path = config::main_cfg["satdump_directories"]["default_projection_output_directory"]["value"].get<std::string>();
|
|
#ifdef _MSC_VER
|
|
if (default_path == ".")
|
|
{
|
|
char* cwd;
|
|
cwd = _getcwd(NULL, 0);
|
|
if (cwd != 0)
|
|
default_path = cwd;
|
|
}
|
|
default_path += "\\";
|
|
#else
|
|
default_path += "/";
|
|
#endif
|
|
std::string default_name = default_path + "projection." + default_ext;
|
|
|
|
#ifndef __ANDROID__
|
|
auto result = pfd::save_file("Save Image", default_name, get_file_formats(default_ext));
|
|
while (!result.ready(1000))
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
|
if (result.result().size() > 0)
|
|
{
|
|
std::string path = result.result();
|
|
logger->info("Saving current projection at %s", path.c_str());
|
|
projected_image_result.save_img(path);
|
|
}
|
|
#else
|
|
std::string path = "/storage/emulated/0/" + default_name;
|
|
logger->info("Saving current projection at %s", path.c_str());
|
|
projected_image_result.save_img("" + path);
|
|
#endif
|
|
}
|
|
}
|
|
if (ImGui::CollapsingHeader("Layers"))
|
|
{
|
|
ImGui::BeginGroup();
|
|
ImGui::Text("Mode : ");
|
|
ImGui::SameLine();
|
|
ImGui::Text("Blend");
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SetNextItemWidth(50);
|
|
ToggleButton("##projtog", &projections_mode_radio);
|
|
ImGui::SameLine();
|
|
ImGui::Text("Overlay");
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::Separator(); //////////////////////////////////////////////////////
|
|
|
|
ImGui::Text("Layers :");
|
|
|
|
ImGui::SameLine(ImGui::GetWindowWidth() - 85 * ui_scale);
|
|
|
|
if (is_opening_layer)
|
|
style::beginDisabled();
|
|
|
|
if (ImGui::Button("Add Layer##button"))
|
|
{
|
|
ImGui::OpenPopup("Add Layer##popup", ImGuiPopupFlags_None);
|
|
}
|
|
|
|
if (is_opening_layer)
|
|
style::endDisabled();
|
|
|
|
{
|
|
if (ImGui::BeginPopupModal("Add Layer##popup", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize))
|
|
{
|
|
ImGui::RadioButton("Equirectangular", &selected_external_type, 0);
|
|
ImGui::RadioButton("Tile Map (OSM)", &selected_external_type, 2);
|
|
ImGui::RadioButton("Other", &selected_external_type, 1);
|
|
|
|
if (selected_external_type == 2)
|
|
{
|
|
ImGui::SliderInt("Zoom##osmsliderzoom", &projection_osm_zoom, 0, 6);
|
|
if (!urlgood)
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 0, 0, 255));
|
|
|
|
ImGui::InputText("Tile URL", &mapurl, ImGuiInputTextFlags_None);
|
|
|
|
if (!urlgood)
|
|
{
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("Invalid URL! must be https://server/{z}/{x}/{y}.ext");
|
|
ImGui::PopStyleColor();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ImGui::InputText("Name", &projection_new_layer_name);
|
|
projection_new_layer_file.draw("Input Image");
|
|
if (selected_external_type == 1)
|
|
projection_new_layer_cfg.draw("Projection Config File");
|
|
}
|
|
|
|
if (ImGui::Button("Add layer") && (selected_external_type == 2 || (projection_new_layer_file.isValid() &&
|
|
(selected_external_type == 0 ? 1 : projection_new_layer_cfg.isValid()))))
|
|
{
|
|
if (re_matchp(osm_url_regex, mapurl.c_str(), &osm_url_regex_len) || selected_external_type != 2)
|
|
{
|
|
urlgood = true;
|
|
auto genfun = [this](int)
|
|
{
|
|
is_opening_layer = true;
|
|
|
|
std::shared_ptr<ExternalProjSource> new_layer_cfg = std::make_shared<ExternalProjSource>();
|
|
if (selected_external_type == 2)
|
|
new_layer_cfg->name = "Tile Map";
|
|
else
|
|
new_layer_cfg->name = projection_new_layer_name;
|
|
|
|
if (selected_external_type == 1)
|
|
new_layer_cfg->path = projection_new_layer_cfg.getPath();
|
|
else if (selected_external_type == 2)
|
|
new_layer_cfg->cfg = nlohmann::json::parse("{\"type\":\"mercator\"}");
|
|
else
|
|
new_layer_cfg->cfg = nlohmann::json::parse("{\"type\":\"equirectangular\",\"tl_lon\":-180,\"tl_lat\":90,\"br_lon\":180,\"br_lat\":-90}");
|
|
|
|
int i = -1;
|
|
bool contains = false;
|
|
do
|
|
{
|
|
contains = false;
|
|
std::string curr_name = ((i + 1) == 0 ? new_layer_cfg->name : (new_layer_cfg->name + " #" + std::to_string(i + 1)));
|
|
for (int i = 0; i < (int)projection_layers.size(); i++)
|
|
if (projection_layers[i].name == curr_name)
|
|
contains = true;
|
|
i++;
|
|
} while (contains);
|
|
new_layer_cfg->name = (i == 0 ? new_layer_cfg->name : (new_layer_cfg->name + " #" + std::to_string(i)));
|
|
|
|
if (selected_external_type == 2)
|
|
{
|
|
std::stringstream test(mapurl);
|
|
std::string segment;
|
|
std::vector<std::string> seglist;
|
|
|
|
while (std::getline(test, segment, '/'))
|
|
{
|
|
seglist.push_back(segment);
|
|
}
|
|
logger->info("Generating tile map");
|
|
tileMap tile_map(mapurl, satdump::user_path + "/osm_tiles/" + seglist[2] + "/");
|
|
new_layer_cfg->img = tile_map.getMapImage({-85.06, -180}, {85.06, 180}, projection_osm_zoom).to16bits();
|
|
}
|
|
else
|
|
new_layer_cfg->img.load_img(projection_new_layer_file.getPath());
|
|
|
|
projections_external_sources.push_back(new_layer_cfg);
|
|
|
|
if (selected_external_type == 2)
|
|
selected_external_type = 0;
|
|
|
|
projections_should_refresh = true;
|
|
is_opening_layer = false;
|
|
};
|
|
ui_thread_pool.push(genfun);
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
else
|
|
{
|
|
urlgood = false;
|
|
}
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("Cancel"))
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
ImGui::EndPopup();
|
|
}
|
|
}
|
|
|
|
if (ImGui::BeginListBox("##projectionslistbox", ImVec2(ImGui::GetWindowWidth(), 300 * ui_scale)))
|
|
{
|
|
for (int i = 0; i < (int)projection_layers.size(); i++)
|
|
{
|
|
ImGui::PushID(i);
|
|
ImGui::BeginGroup();
|
|
ProjectionLayer &layer = projection_layers[i];
|
|
std::string label;
|
|
if (layer.type == 0)
|
|
{
|
|
label = layer.viewer_prods->products->instrument_name;
|
|
if (layer.viewer_prods->handler->instrument_cfg.contains("name"))
|
|
label = layer.viewer_prods->handler->instrument_cfg["name"].get<std::string>();
|
|
}
|
|
else
|
|
label = layer.name;
|
|
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x, ImGui::GetCursorPos().y + 4 * ui_scale));
|
|
ImGui::Text("%s", label.c_str());
|
|
if (ImGui::IsItemHovered() && layer.type == 0)
|
|
{
|
|
ImGui::SetTooltip("%s", layer.viewer_prods->dataset_name.c_str());
|
|
}
|
|
ImGui::SameLine(ImGui::GetWindowWidth() - 70 * ui_scale);
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPos().y - 2 * ui_scale);
|
|
ImGui::Checkbox(std::string("##enablelayer" + layer.name + std::to_string(i)).c_str(), &layer.enabled);
|
|
// if (layer.type == 1)
|
|
{
|
|
// Closing button
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosY(ImGui::GetCursorPos().y - 2 * ui_scale);
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 0, 0, 255));
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
|
if (ImGui::Button(std::string(u8"\uf00d##layerdelete" + layer.name + std::to_string(i)).c_str()))
|
|
{
|
|
if (layer.type == 1 || layer.type == 2)
|
|
{
|
|
projection_layers.erase(projection_layers.begin() + i);
|
|
for (int f = 0; f < (int)projections_external_sources.size(); f++)
|
|
if (projections_external_sources[f]->name == projection_layers[i].name)
|
|
projections_external_sources.erase(projections_external_sources.begin() + f);
|
|
}
|
|
else if (layer.type == 0)
|
|
{
|
|
layer.viewer_prods->handler->setShouldProject(false);
|
|
}
|
|
refreshProjectionLayers();
|
|
ImGui::EndGroup();
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopID();
|
|
break;
|
|
}
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopStyleColor();
|
|
}
|
|
if (layer.enabled)
|
|
{
|
|
// ImGui::DragFloat(std::string("Opacity##opacitylayer" + layer.name + std::to_string(i)).c_str(), &layer.opacity, 1.0, 0, 100);
|
|
ImGui::Image((void *)(intptr_t)layer.getPreview(), {50 * ui_scale, 50 * ui_scale});
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginGroup();
|
|
FancySlider(std::string("##opacitylayer" + layer.name + std::to_string(i)).c_str(), "Opacity", &layer.opacity, ImGui::GetWindowWidth() - 76 * ui_scale);
|
|
ImGui::ProgressBar(layer.progress, ImVec2(ImGui::GetWindowWidth() - 76 * ui_scale, ImGui::GetFrameHeight()));
|
|
ImGui::EndGroup();
|
|
}
|
|
ImGui::EndGroup();
|
|
|
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
|
{
|
|
// Set payload to carry the index of our item (could be anything)
|
|
ImGui::SetDragDropPayload("LAYER_PROJECTION", &i, sizeof(int));
|
|
|
|
ImGui::Text("%s", label.c_str());
|
|
ImGui::EndDragDropSource();
|
|
}
|
|
if (ImGui::BeginDragDropTarget())
|
|
{
|
|
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("LAYER_PROJECTION"))
|
|
{
|
|
IM_ASSERT(payload->DataSize == sizeof(int));
|
|
int payload_n = *(const int *)payload->Data;
|
|
ProjectionLayer pr = projection_layers[payload_n];
|
|
projection_layers.erase(projection_layers.begin() + payload_n);
|
|
auto it = projection_layers.begin();
|
|
projection_layers.insert(it + i, pr);
|
|
}
|
|
ImGui::EndDragDropTarget();
|
|
}
|
|
ImGui::PopID();
|
|
ImGui::Separator();
|
|
}
|
|
ImGui::EndListBox();
|
|
}
|
|
|
|
if (projections_are_generating || projection_layers.size() == 0)
|
|
style::beginDisabled();
|
|
if (ImGui::Button("Generate Projection##layers"))
|
|
{
|
|
ui_thread_pool.push([this](int)
|
|
{
|
|
logger->info("Update projection...");
|
|
generateProjectionImage();
|
|
logger->info("Done"); });
|
|
}
|
|
if (projections_are_generating || projection_layers.size() == 0)
|
|
style::endDisabled();
|
|
}
|
|
if (ImGui::CollapsingHeader("Overlay##viewerpojoverlay"))
|
|
{
|
|
ImGui::Checkbox("Map Overlay##Projs", &projections_draw_map_overlay);
|
|
ImGui::SameLine();
|
|
ImGui::ColorEdit3("##borders", (float *)&color_borders, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
|
|
ImGui::Checkbox("Cities Overlay##Projs", &projections_draw_cities_overlay);
|
|
ImGui::SameLine();
|
|
ImGui::ColorEdit3("##cities", (float *)&color_cities, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
|
|
ImGui::SliderInt("Cities Font Size##Projs", &projections_cities_scale, 10, 500);
|
|
}
|
|
|
|
if (projections_should_refresh) // Refresh in the UI thread!
|
|
{
|
|
refreshProjectionLayers();
|
|
projections_should_refresh = false;
|
|
}
|
|
}
|
|
|
|
void ViewerApplication::generateProjectionImage()
|
|
{
|
|
projections_are_generating = true;
|
|
|
|
nlohmann::json cfg; //= nlohmann::json::parse("{\"type\":\"equirectangular\",\"tl_lon\":-180,\"tl_lat\":90,\"br_lon\":180,\"br_lat\":-90}");
|
|
|
|
if (projections_current_selected_proj == 0)
|
|
{
|
|
cfg["type"] = "equirectangular";
|
|
cfg["tl_lon"] = projections_equirectangular_tl_lon;
|
|
cfg["tl_lat"] = projections_equirectangular_tl_lat;
|
|
cfg["br_lon"] = projections_equirectangular_br_lon;
|
|
cfg["br_lat"] = projections_equirectangular_br_lat;
|
|
}
|
|
else if (projections_current_selected_proj == 1)
|
|
{
|
|
cfg["type"] = "mercator";
|
|
// cfg["tl_lon"] = projections_equirectangular_tl_lon;
|
|
// cfg["tl_lat"] = projections_equirectangular_tl_lat;
|
|
// cfg["br_lon"] = projections_equirectangular_br_lon;
|
|
// cfg["br_lat"] = projections_equirectangular_br_lat;
|
|
}
|
|
else if (projections_current_selected_proj == 2)
|
|
{
|
|
cfg["type"] = "stereo";
|
|
cfg["center_lon"] = projections_stereo_center_lon;
|
|
cfg["center_lat"] = projections_stereo_center_lat;
|
|
cfg["scale"] = projections_stereo_scale;
|
|
}
|
|
else if (projections_current_selected_proj == 3)
|
|
{
|
|
cfg["type"] = "tpers";
|
|
cfg["lon"] = projections_tpers_lon;
|
|
cfg["lat"] = projections_tpers_lat;
|
|
cfg["alt"] = projections_tpers_alt;
|
|
cfg["ang"] = projections_tpers_ang;
|
|
cfg["azi"] = projections_tpers_azi;
|
|
}
|
|
else if (projections_current_selected_proj == 4)
|
|
{
|
|
cfg["type"] = "azeq";
|
|
cfg["lon"] = projections_azeq_lon;
|
|
cfg["lat"] = projections_azeq_lat;
|
|
}
|
|
|
|
// Setup final image
|
|
projected_image_result.init(projections_image_width, projections_image_height, 3);
|
|
projected_image_result.init_font(resources::getResourcePath("fonts/font.ttf"));
|
|
|
|
// Generate all layers
|
|
std::vector<image::Image<uint16_t>> layers_images;
|
|
|
|
for (int i = projection_layers.size() - 1; i >= 0; i--)
|
|
{
|
|
ProjectionLayer &layer = projection_layers[i];
|
|
if (!layer.enabled)
|
|
continue;
|
|
|
|
if (layer.type == 0)
|
|
{
|
|
layer.viewer_prods->handler->updateProjection(projections_image_width, projections_image_height, cfg, &layer.progress);
|
|
layers_images.push_back(layer.viewer_prods->handler->getProjection());
|
|
}
|
|
else
|
|
{
|
|
auto img = projectExternal(projections_image_width, projections_image_height, cfg, layer.external, &layer.progress);
|
|
// img.to_rgb();
|
|
layers_images.push_back(img);
|
|
}
|
|
}
|
|
|
|
logger->info("Combining images...");
|
|
if (projections_mode_radio == 0) // Blend
|
|
{
|
|
projected_image_result = layers_images[0];
|
|
for (int i = 1; i < (int)layers_images.size(); i++)
|
|
projected_image_result = image::blend_images(projected_image_result, layers_images[i]);
|
|
}
|
|
else if (projections_mode_radio == 1)
|
|
{
|
|
projected_image_result = layers_images[0];
|
|
for (int i = 1; i < (int)layers_images.size(); i++)
|
|
{
|
|
projected_image_result = image::merge_images_opacity(projected_image_result,
|
|
layers_images[i],
|
|
projection_layers[(projection_layers.size() - 1) - i].opacity / 100.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This sucks but temporary
|
|
for (auto &img : layers_images)
|
|
projected_image_result.draw_image(0, img);
|
|
}
|
|
|
|
// Free up memory
|
|
layers_images.clear();
|
|
|
|
// Setup projection to draw stuff on top
|
|
auto proj_func = satdump::reprojection::setupProjectionFunction(projections_image_width, projections_image_height, cfg, {});
|
|
|
|
// Draw map borders
|
|
if (projections_draw_map_overlay)
|
|
{
|
|
logger->info("Drawing map overlay...");
|
|
unsigned short color[4] = {(unsigned short)(color_borders.x * 65535.0f), (unsigned short)(color_borders.y * 65535.0f), (unsigned short)(color_borders.z * 65535.0f), 65535};
|
|
map::drawProjectedMapShapefile({resources::getResourcePath("maps/ne_10m_admin_0_countries.shp")},
|
|
projected_image_result,
|
|
color,
|
|
proj_func);
|
|
}
|
|
|
|
// Draw cities points
|
|
if (projections_draw_cities_overlay)
|
|
{
|
|
logger->info("Drawing map overlay...");
|
|
unsigned short color[4] = {(unsigned short)(color_cities.x * 65535.0f), (unsigned short)(color_cities.y * 65535.0f), (unsigned short)(color_cities.z * 65535.0f), 65535};
|
|
map::drawProjectedCapitalsGeoJson({resources::getResourcePath("maps/ne_10m_populated_places_simple.json")},
|
|
projected_image_result,
|
|
color,
|
|
proj_func,
|
|
projections_cities_scale);
|
|
}
|
|
|
|
// Update ImageView
|
|
projection_image_widget.update(projected_image_result);
|
|
|
|
projections_are_generating = false;
|
|
}
|
|
|
|
image::Image<uint16_t> ViewerApplication::projectExternal(int width, int height, nlohmann::json tcfg, std::shared_ptr<ExternalProjSource> ep, float *progress)
|
|
{
|
|
reprojection::ReprojectionOperation op;
|
|
|
|
if (ep->path.size() > 0)
|
|
op.source_prj_info = loadJsonFile(ep->path);
|
|
else
|
|
op.source_prj_info = ep->cfg;
|
|
|
|
if (!op.source_prj_info.contains("type")) // Just in case...
|
|
return image::Image<uint16_t>(width, height, 4);
|
|
|
|
op.target_prj_info = tcfg;
|
|
op.img = ep->img;
|
|
op.output_width = width;
|
|
op.output_height = height;
|
|
reprojection::ProjectionResult res = reprojection::reproject(op, progress);
|
|
return res.img;
|
|
}
|
|
|
|
void ViewerApplication::refreshProjectionLayers()
|
|
{
|
|
// Check for *new* ext layers
|
|
for (int i = 0; i < (int)projections_external_sources.size(); i++)
|
|
{
|
|
bool contains = false;
|
|
|
|
for (ProjectionLayer &lay : projection_layers)
|
|
if (projections_external_sources[i]->name == lay.name)
|
|
contains = true;
|
|
|
|
if (!contains)
|
|
projection_layers.push_back({projections_external_sources[i]->name, 1, nullptr, projections_external_sources[i]});
|
|
}
|
|
|
|
// Check for *new* products layers
|
|
for (int i = 0; i < (int)products_and_handlers.size(); i++)
|
|
{
|
|
if (products_and_handlers[i]->handler->canBeProjected() && products_and_handlers[i]->handler->shouldProject())
|
|
{
|
|
std::string label = products_and_handlers[i]->products->instrument_name;
|
|
|
|
bool contains = false;
|
|
for (ProjectionLayer &lay : projection_layers)
|
|
{
|
|
if (lay.type != 0)
|
|
continue;
|
|
|
|
if (label == lay.name && products_and_handlers[i].get() == lay.viewer_prods.get())
|
|
contains = true;
|
|
}
|
|
|
|
if (!contains)
|
|
projection_layers.push_back({label, 0, products_and_handlers[i], nullptr});
|
|
}
|
|
}
|
|
|
|
recheck:
|
|
// Check for products layers to delete
|
|
for (int i = 0; i < (int)projection_layers.size(); i++)
|
|
{
|
|
ProjectionLayer &lay = projection_layers[i];
|
|
|
|
if (lay.type != 0)
|
|
continue;
|
|
|
|
bool contains = false;
|
|
for (int i = 0; i < (int)products_and_handlers.size(); i++)
|
|
if (products_and_handlers[i]->handler->canBeProjected() && products_and_handlers[i]->handler->shouldProject())
|
|
if (products_and_handlers[i]->products->instrument_name == lay.name && products_and_handlers[i].get() == lay.viewer_prods.get())
|
|
contains = true;
|
|
|
|
if (!contains)
|
|
{
|
|
projection_layers.erase(projection_layers.begin() + i);
|
|
goto recheck;
|
|
}
|
|
}
|
|
}
|
|
}
|