diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index f5d6a489..129d3f14 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -59,11 +59,13 @@ set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp source/scwx/qt/gl/draw/geo_line.hpp source/scwx/qt/gl/draw/placefile_icons.hpp source/scwx/qt/gl/draw/placefile_polygons.hpp + source/scwx/qt/gl/draw/placefile_text.hpp source/scwx/qt/gl/draw/rectangle.hpp) set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp source/scwx/qt/gl/draw/geo_line.cpp source/scwx/qt/gl/draw/placefile_icons.cpp source/scwx/qt/gl/draw/placefile_polygons.cpp + source/scwx/qt/gl/draw/placefile_text.cpp source/scwx/qt/gl/draw/rectangle.cpp) set(HDR_MANAGER source/scwx/qt/manager/placefile_manager.hpp source/scwx/qt/manager/radar_product_manager.hpp diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp new file mode 100644 index 00000000..ee28800a --- /dev/null +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace gl +{ +namespace draw +{ + +static const std::string logPrefix_ = "scwx::qt::gl::draw::placefile_text"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class PlacefileText::Impl +{ +public: + explicit Impl(std::shared_ptr context, + const std::string& placefileName) : + context_ {context}, placefileName_ {placefileName} + { + } + + ~Impl() {} + + void RenderTextDrawItem( + const QMapLibreGL::CustomLayerRenderParameters& params, + const std::shared_ptr& di); + void RenderText(const QMapLibreGL::CustomLayerRenderParameters& params, + const std::string& text, + const std::string& hoverText, + boost::gil::rgba8_pixel_t color, + float x, + float y); + + std::shared_ptr context_; + + std::string placefileName_; + + bool dirty_ {false}; + bool thresholded_ {false}; + + std::uint32_t textId_ {}; + glm::vec2 mapScreenCoordLocation_ {}; + float mapScale_ {1.0f}; + float mapBearingCos_ {1.0f}; + float mapBearingSin_ {0.0f}; + float halfWidth_ {}; + float halfHeight_ {}; + ImFont* monospaceFont_ {}; + + units::length::nautical_miles mapDistance_ {}; + + std::vector> textList_ {}; + + void Update(); +}; + +PlacefileText::PlacefileText(std::shared_ptr context, + const std::string& placefileName) : + DrawItem(context->gl()), p(std::make_unique(context, placefileName)) +{ +} +PlacefileText::~PlacefileText() = default; + +PlacefileText::PlacefileText(PlacefileText&&) noexcept = default; +PlacefileText& PlacefileText::operator=(PlacefileText&&) noexcept = default; + +void PlacefileText::set_placefile_name(const std::string& placefileName) +{ + p->placefileName_ = placefileName; +} + +void PlacefileText::set_thresholded(bool thresholded) +{ + p->thresholded_ = thresholded; +} + +void PlacefileText::Initialize() +{ + p->dirty_ = true; +} + +void PlacefileText::Render( + const QMapLibreGL::CustomLayerRenderParameters& params) +{ + if (!p->textList_.empty()) + { + p->Update(); + + // Reset text ID per frame + p->textId_ = 0; + + // Update map screen coordinate and scale information + p->mapScreenCoordLocation_ = util::maplibre::LatLongToScreenCoordinate( + {params.latitude, params.longitude}); + p->mapScale_ = std::pow(2.0, params.zoom) * mbgl::util::tileSize_D / + mbgl::util::DEGREES_MAX; + p->mapBearingCos_ = cosf(params.bearing * common::kDegreesToRadians); + p->mapBearingSin_ = sinf(params.bearing * common::kDegreesToRadians); + p->halfWidth_ = params.width * 0.5f; + p->halfHeight_ = params.height * 0.5f; + p->mapDistance_ = util::maplibre::GetMapDistance(params); + + // Get monospace font pointer + std::size_t fontSize = 16; + auto fontSizes = + manager::SettingsManager::general_settings().font_sizes().GetValue(); + if (fontSizes.size() > 1) + { + fontSize = fontSizes[1]; + } + else if (fontSizes.size() > 0) + { + fontSize = fontSizes[0]; + } + auto monospace = + manager::ResourceManager::Font(types::Font::Inconsolata_Regular); + p->monospaceFont_ = monospace->ImGuiFont(fontSize); + + for (auto& di : p->textList_) + { + p->RenderTextDrawItem(params, di); + } + } +} + +void PlacefileText::Impl::RenderTextDrawItem( + const QMapLibreGL::CustomLayerRenderParameters& params, + const std::shared_ptr& di) +{ + if (!thresholded_ || mapDistance_ <= di->threshold_) + { + const auto screenCoordinates = (util::maplibre::LatLongToScreenCoordinate( + {di->latitude_, di->longitude_}) - + mapScreenCoordLocation_) * + mapScale_; + + // Rotate text according to map rotation + float rotatedX = screenCoordinates.x; + float rotatedY = screenCoordinates.y; + if (params.bearing != 0.0) + { + rotatedX = screenCoordinates.x * mapBearingCos_ - + screenCoordinates.y * mapBearingSin_; + rotatedY = screenCoordinates.x * mapBearingSin_ + + screenCoordinates.y * mapBearingCos_; + } + + RenderText(params, + di->text_, + di->hoverText_, + di->color_, + rotatedX + di->x_ + halfWidth_, + rotatedY + di->y_ + halfHeight_); + } +} + +void PlacefileText::Impl::RenderText( + const QMapLibreGL::CustomLayerRenderParameters& params, + const std::string& text, + const std::string& hoverText, + boost::gil::rgba8_pixel_t color, + float x, + float y) +{ + const std::string windowName { + fmt::format("PlacefileText-{}-{}", placefileName_, ++textId_)}; + + // Convert screen to ImGui coordinates + y = params.height - y; + + // Setup "window" to hold text + ImGui::SetNextWindowPos( + ImVec2 {x, y}, ImGuiCond_Always, ImVec2 {0.5f, 0.5f}); + ImGui::Begin(windowName.c_str(), + nullptr, + ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_NoBackground); + + // Render text + ImGui::PushStyleColor(ImGuiCol_Text, + IM_COL32(color[0], color[1], color[2], color[3])); + ImGui::TextUnformatted(text.c_str()); + ImGui::PopStyleColor(); + + // Create tooltip for hover text + if (!hoverText.empty() && ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushFont(monospaceFont_); + ImGui::TextUnformatted(hoverText.c_str()); + ImGui::PopFont(); + ImGui::EndTooltip(); + } + + // End window + ImGui::End(); +} + +void PlacefileText::Deinitialize() +{ + Reset(); +} + +void PlacefileText::AddText( + const std::shared_ptr& di) +{ + if (di != nullptr) + { + p->textList_.emplace_back(di); + p->dirty_ = true; + } +} + +void PlacefileText::Reset() +{ + // Clear the icon list, and mark the draw item dirty + p->textList_.clear(); + p->dirty_ = true; +} + +void PlacefileText::Impl::Update() +{ + dirty_ = false; +} + +} // namespace draw +} // namespace gl +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp new file mode 100644 index 00000000..04d78844 --- /dev/null +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace gl +{ +namespace draw +{ + +class PlacefileText : public DrawItem +{ +public: + explicit PlacefileText(std::shared_ptr context, + const std::string& placefileName); + ~PlacefileText(); + + PlacefileText(const PlacefileText&) = delete; + PlacefileText& operator=(const PlacefileText&) = delete; + + PlacefileText(PlacefileText&&) noexcept; + PlacefileText& operator=(PlacefileText&&) noexcept; + + void set_placefile_name(const std::string& placefileName); + void set_thresholded(bool thresholded); + + void Initialize() override; + void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Deinitialize() override; + + /** + * Adds placefile text to the internal draw list. + * + * @param [in] di Placefile icon + */ + void AddText(const std::shared_ptr& di); + + /** + * Resets the list of text in preparation for rendering a new frame. + */ + void Reset(); + +private: + class Impl; + + std::unique_ptr p; +}; + +} // namespace draw +} // namespace gl +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/map/placefile_layer.cpp b/scwx-qt/source/scwx/qt/map/placefile_layer.cpp index ca98bdfa..e287be40 100644 --- a/scwx-qt/source/scwx/qt/map/placefile_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/placefile_layer.cpp @@ -1,16 +1,10 @@ #include #include #include +#include #include -#include -#include -#include -#include #include -#include -#include -#include namespace scwx { @@ -32,7 +26,9 @@ public: placefileName_ {placefileName}, placefileIcons_ {std::make_shared(context)}, placefilePolygons_ { - std::make_shared(context)} + std::make_shared(context)}, + placefileText_ { + std::make_shared(context, placefileName)} { ConnectSignals(); } @@ -42,36 +38,17 @@ public: void AddIcon(const std::shared_ptr& di); void AddPolygon(const std::shared_ptr& di); - void - RenderTextDrawItem(const QMapLibreGL::CustomLayerRenderParameters& params, - const std::shared_ptr& di); + void AddText(const std::shared_ptr& di); - void RenderText(const QMapLibreGL::CustomLayerRenderParameters& params, - const std::string& text, - const std::string& hoverText, - boost::gil::rgba8_pixel_t color, - float x, - float y); PlacefileLayer* self_; std::string placefileName_; bool dirty_ {true}; - std::uint32_t textId_ {}; - glm::vec2 mapScreenCoordLocation_ {}; - float mapScale_ {1.0f}; - float mapBearingCos_ {1.0f}; - float mapBearingSin_ {0.0f}; - float halfWidth_ {}; - float halfHeight_ {}; - bool thresholded_ {true}; - ImFont* monospaceFont_ {}; - - units::length::nautical_miles mapDistance_ {}; - std::shared_ptr placefileIcons_; std::shared_ptr placefilePolygons_; + std::shared_ptr placefileText_; }; PlacefileLayer::PlacefileLayer(std::shared_ptr context, @@ -81,6 +58,7 @@ PlacefileLayer::PlacefileLayer(std::shared_ptr context, { AddDrawItem(p->placefileIcons_); AddDrawItem(p->placefilePolygons_); + AddDrawItem(p->placefileText_); } PlacefileLayer::~PlacefileLayer() = default; @@ -110,6 +88,8 @@ void PlacefileLayer::set_placefile_name(const std::string& placefileName) { p->placefileName_ = placefileName; p->dirty_ = true; + + p->placefileText_->set_placefile_name(placefileName); } void PlacefileLayer::Initialize() @@ -141,78 +121,15 @@ void PlacefileLayer::Impl::AddPolygon( placefilePolygons_->AddPolygon(di); } -void PlacefileLayer::Impl::RenderTextDrawItem( - const QMapLibreGL::CustomLayerRenderParameters& params, +void PlacefileLayer::Impl::AddText( const std::shared_ptr& di) { - if (!thresholded_ || mapDistance_ <= di->threshold_) + if (!dirty_) { - const auto screenCoordinates = (util::maplibre::LatLongToScreenCoordinate( - {di->latitude_, di->longitude_}) - - mapScreenCoordLocation_) * - mapScale_; + return; + }; - // Rotate text according to map rotation - float rotatedX = screenCoordinates.x; - float rotatedY = screenCoordinates.y; - if (params.bearing != 0.0) - { - rotatedX = screenCoordinates.x * mapBearingCos_ - - screenCoordinates.y * mapBearingSin_; - rotatedY = screenCoordinates.x * mapBearingSin_ + - screenCoordinates.y * mapBearingCos_; - } - - RenderText(params, - di->text_, - di->hoverText_, - di->color_, - rotatedX + di->x_ + halfWidth_, - rotatedY + di->y_ + halfHeight_); - } -} - -void PlacefileLayer::Impl::RenderText( - const QMapLibreGL::CustomLayerRenderParameters& params, - const std::string& text, - const std::string& hoverText, - boost::gil::rgba8_pixel_t color, - float x, - float y) -{ - const std::string windowName { - fmt::format("PlacefileText-{}-{}", placefileName_, ++textId_)}; - - // Convert screen to ImGui coordinates - y = params.height - y; - - // Setup "window" to hold text - ImGui::SetNextWindowPos( - ImVec2 {x, y}, ImGuiCond_Always, ImVec2 {0.5f, 0.5f}); - ImGui::Begin(windowName.c_str(), - nullptr, - ImGuiWindowFlags_AlwaysAutoResize | - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | - ImGuiWindowFlags_NoBackground); - - // Render text - ImGui::PushStyleColor(ImGuiCol_Text, - IM_COL32(color[0], color[1], color[2], color[3])); - ImGui::TextUnformatted(text.c_str()); - ImGui::PopStyleColor(); - - // Create tooltip for hover text - if (!hoverText.empty() && ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::PushFont(monospaceFont_); - ImGui::TextUnformatted(hoverText.c_str()); - ImGui::PopFont(); - ImGui::EndTooltip(); - } - - // End window - ImGui::End(); + placefileText_->AddText(di); } void PlacefileLayer::Render( @@ -223,36 +140,6 @@ void PlacefileLayer::Render( // Set OpenGL blend mode for transparency gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Reset text ID per frame - p->textId_ = 0; - - // Update map screen coordinate and scale information - p->mapScreenCoordLocation_ = util::maplibre::LatLongToScreenCoordinate( - {params.latitude, params.longitude}); - p->mapScale_ = std::pow(2.0, params.zoom) * mbgl::util::tileSize_D / - mbgl::util::DEGREES_MAX; - p->mapBearingCos_ = cosf(params.bearing * common::kDegreesToRadians); - p->mapBearingSin_ = sinf(params.bearing * common::kDegreesToRadians); - p->halfWidth_ = params.width * 0.5f; - p->halfHeight_ = params.height * 0.5f; - p->mapDistance_ = util::maplibre::GetMapDistance(params); - - // Get monospace font pointer - std::size_t fontSize = 16; - auto fontSizes = - manager::SettingsManager::general_settings().font_sizes().GetValue(); - if (fontSizes.size() > 1) - { - fontSize = fontSizes[1]; - } - else if (fontSizes.size() > 0) - { - fontSize = fontSizes[0]; - } - auto monospace = - manager::ResourceManager::Font(types::Font::Inconsolata_Regular); - p->monospaceFont_ = monospace->ImGuiFont(fontSize); - std::shared_ptr placefileManager = manager::PlacefileManager::Instance(); @@ -261,10 +148,11 @@ void PlacefileLayer::Render( // Render placefile if (placefile != nullptr) { - p->thresholded_ = + bool thresholded = placefileManager->placefile_thresholded(placefile->name()); - p->placefileIcons_->set_thresholded(p->thresholded_); - p->placefilePolygons_->set_thresholded(p->thresholded_); + p->placefileIcons_->set_thresholded(thresholded); + p->placefilePolygons_->set_thresholded(thresholded); + p->placefileText_->set_thresholded(thresholded); if (p->dirty_) { @@ -275,6 +163,9 @@ void PlacefileLayer::Render( // Reset Placefile Polygons p->placefilePolygons_->StartPolygons(); + + // Reset Placefile Text + p->placefileText_->Reset(); } for (auto& drawItem : placefile->GetDrawItems()) @@ -282,8 +173,7 @@ void PlacefileLayer::Render( switch (drawItem->itemType_) { case gr::Placefile::ItemType::Text: - p->RenderTextDrawItem( - params, + p->AddText( std::static_pointer_cast(drawItem)); break;