Refactor placefile text into its own draw item

This commit is contained in:
Dan Paulat 2023-08-19 10:05:26 -05:00
parent d6f8a339fc
commit a4027ba120
4 changed files with 321 additions and 132 deletions

View file

@ -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/geo_line.hpp
source/scwx/qt/gl/draw/placefile_icons.hpp source/scwx/qt/gl/draw/placefile_icons.hpp
source/scwx/qt/gl/draw/placefile_polygons.hpp source/scwx/qt/gl/draw/placefile_polygons.hpp
source/scwx/qt/gl/draw/placefile_text.hpp
source/scwx/qt/gl/draw/rectangle.hpp) source/scwx/qt/gl/draw/rectangle.hpp)
set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp 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/geo_line.cpp
source/scwx/qt/gl/draw/placefile_icons.cpp source/scwx/qt/gl/draw/placefile_icons.cpp
source/scwx/qt/gl/draw/placefile_polygons.cpp source/scwx/qt/gl/draw/placefile_polygons.cpp
source/scwx/qt/gl/draw/placefile_text.cpp
source/scwx/qt/gl/draw/rectangle.cpp) source/scwx/qt/gl/draw/rectangle.cpp)
set(HDR_MANAGER source/scwx/qt/manager/placefile_manager.hpp set(HDR_MANAGER source/scwx/qt/manager/placefile_manager.hpp
source/scwx/qt/manager/radar_product_manager.hpp source/scwx/qt/manager/radar_product_manager.hpp

View file

@ -0,0 +1,240 @@
#include <scwx/qt/gl/draw/placefile_text.hpp>
#include <scwx/qt/manager/resource_manager.hpp>
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/util/maplibre.hpp>
#include <scwx/util/logger.hpp>
#include <fmt/format.h>
#include <imgui.h>
#include <mbgl/util/constants.hpp>
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<GlContext> context,
const std::string& placefileName) :
context_ {context}, placefileName_ {placefileName}
{
}
~Impl() {}
void RenderTextDrawItem(
const QMapLibreGL::CustomLayerRenderParameters& params,
const std::shared_ptr<const gr::Placefile::TextDrawItem>& 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<GlContext> 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<double> mapDistance_ {};
std::vector<std::shared_ptr<const gr::Placefile::TextDrawItem>> textList_ {};
void Update();
};
PlacefileText::PlacefileText(std::shared_ptr<GlContext> context,
const std::string& placefileName) :
DrawItem(context->gl()), p(std::make_unique<Impl>(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<const gr::Placefile::TextDrawItem>& 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<gr::Placefile::TextDrawItem>& 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

View file

@ -0,0 +1,57 @@
#pragma once
#include <scwx/qt/gl/gl_context.hpp>
#include <scwx/qt/gl/draw/draw_item.hpp>
#include <scwx/gr/placefile.hpp>
namespace scwx
{
namespace qt
{
namespace gl
{
namespace draw
{
class PlacefileText : public DrawItem
{
public:
explicit PlacefileText(std::shared_ptr<GlContext> 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<gr::Placefile::TextDrawItem>& di);
/**
* Resets the list of text in preparation for rendering a new frame.
*/
void Reset();
private:
class Impl;
std::unique_ptr<Impl> p;
};
} // namespace draw
} // namespace gl
} // namespace qt
} // namespace scwx

View file

@ -1,16 +1,10 @@
#include <scwx/qt/map/placefile_layer.hpp> #include <scwx/qt/map/placefile_layer.hpp>
#include <scwx/qt/gl/draw/placefile_icons.hpp> #include <scwx/qt/gl/draw/placefile_icons.hpp>
#include <scwx/qt/gl/draw/placefile_polygons.hpp> #include <scwx/qt/gl/draw/placefile_polygons.hpp>
#include <scwx/qt/gl/draw/placefile_text.hpp>
#include <scwx/qt/manager/placefile_manager.hpp> #include <scwx/qt/manager/placefile_manager.hpp>
#include <scwx/qt/manager/resource_manager.hpp>
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/util/maplibre.hpp>
#include <scwx/common/geographic.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <fmt/format.h>
#include <imgui.h>
#include <mbgl/util/constants.hpp>
namespace scwx namespace scwx
{ {
@ -32,7 +26,9 @@ public:
placefileName_ {placefileName}, placefileName_ {placefileName},
placefileIcons_ {std::make_shared<gl::draw::PlacefileIcons>(context)}, placefileIcons_ {std::make_shared<gl::draw::PlacefileIcons>(context)},
placefilePolygons_ { placefilePolygons_ {
std::make_shared<gl::draw::PlacefilePolygons>(context)} std::make_shared<gl::draw::PlacefilePolygons>(context)},
placefileText_ {
std::make_shared<gl::draw::PlacefileText>(context, placefileName)}
{ {
ConnectSignals(); ConnectSignals();
} }
@ -42,36 +38,17 @@ public:
void AddIcon(const std::shared_ptr<gr::Placefile::IconDrawItem>& di); void AddIcon(const std::shared_ptr<gr::Placefile::IconDrawItem>& di);
void AddPolygon(const std::shared_ptr<gr::Placefile::PolygonDrawItem>& di); void AddPolygon(const std::shared_ptr<gr::Placefile::PolygonDrawItem>& di);
void void AddText(const std::shared_ptr<gr::Placefile::TextDrawItem>& di);
RenderTextDrawItem(const QMapLibreGL::CustomLayerRenderParameters& params,
const std::shared_ptr<gr::Placefile::TextDrawItem>& 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_; PlacefileLayer* self_;
std::string placefileName_; std::string placefileName_;
bool dirty_ {true}; 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<double> mapDistance_ {};
std::shared_ptr<gl::draw::PlacefileIcons> placefileIcons_; std::shared_ptr<gl::draw::PlacefileIcons> placefileIcons_;
std::shared_ptr<gl::draw::PlacefilePolygons> placefilePolygons_; std::shared_ptr<gl::draw::PlacefilePolygons> placefilePolygons_;
std::shared_ptr<gl::draw::PlacefileText> placefileText_;
}; };
PlacefileLayer::PlacefileLayer(std::shared_ptr<MapContext> context, PlacefileLayer::PlacefileLayer(std::shared_ptr<MapContext> context,
@ -81,6 +58,7 @@ PlacefileLayer::PlacefileLayer(std::shared_ptr<MapContext> context,
{ {
AddDrawItem(p->placefileIcons_); AddDrawItem(p->placefileIcons_);
AddDrawItem(p->placefilePolygons_); AddDrawItem(p->placefilePolygons_);
AddDrawItem(p->placefileText_);
} }
PlacefileLayer::~PlacefileLayer() = default; PlacefileLayer::~PlacefileLayer() = default;
@ -110,6 +88,8 @@ void PlacefileLayer::set_placefile_name(const std::string& placefileName)
{ {
p->placefileName_ = placefileName; p->placefileName_ = placefileName;
p->dirty_ = true; p->dirty_ = true;
p->placefileText_->set_placefile_name(placefileName);
} }
void PlacefileLayer::Initialize() void PlacefileLayer::Initialize()
@ -141,78 +121,15 @@ void PlacefileLayer::Impl::AddPolygon(
placefilePolygons_->AddPolygon(di); placefilePolygons_->AddPolygon(di);
} }
void PlacefileLayer::Impl::RenderTextDrawItem( void PlacefileLayer::Impl::AddText(
const QMapLibreGL::CustomLayerRenderParameters& params,
const std::shared_ptr<gr::Placefile::TextDrawItem>& di) const std::shared_ptr<gr::Placefile::TextDrawItem>& di)
{ {
if (!thresholded_ || mapDistance_ <= di->threshold_) if (!dirty_)
{ {
const auto screenCoordinates = (util::maplibre::LatLongToScreenCoordinate( return;
{di->latitude_, di->longitude_}) - };
mapScreenCoordLocation_) *
mapScale_;
// Rotate text according to map rotation placefileText_->AddText(di);
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();
} }
void PlacefileLayer::Render( void PlacefileLayer::Render(
@ -223,36 +140,6 @@ void PlacefileLayer::Render(
// Set OpenGL blend mode for transparency // Set OpenGL blend mode for transparency
gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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<manager::PlacefileManager> placefileManager = std::shared_ptr<manager::PlacefileManager> placefileManager =
manager::PlacefileManager::Instance(); manager::PlacefileManager::Instance();
@ -261,10 +148,11 @@ void PlacefileLayer::Render(
// Render placefile // Render placefile
if (placefile != nullptr) if (placefile != nullptr)
{ {
p->thresholded_ = bool thresholded =
placefileManager->placefile_thresholded(placefile->name()); placefileManager->placefile_thresholded(placefile->name());
p->placefileIcons_->set_thresholded(p->thresholded_); p->placefileIcons_->set_thresholded(thresholded);
p->placefilePolygons_->set_thresholded(p->thresholded_); p->placefilePolygons_->set_thresholded(thresholded);
p->placefileText_->set_thresholded(thresholded);
if (p->dirty_) if (p->dirty_)
{ {
@ -275,6 +163,9 @@ void PlacefileLayer::Render(
// Reset Placefile Polygons // Reset Placefile Polygons
p->placefilePolygons_->StartPolygons(); p->placefilePolygons_->StartPolygons();
// Reset Placefile Text
p->placefileText_->Reset();
} }
for (auto& drawItem : placefile->GetDrawItems()) for (auto& drawItem : placefile->GetDrawItems())
@ -282,8 +173,7 @@ void PlacefileLayer::Render(
switch (drawItem->itemType_) switch (drawItem->itemType_)
{ {
case gr::Placefile::ItemType::Text: case gr::Placefile::ItemType::Text:
p->RenderTextDrawItem( p->AddText(
params,
std::static_pointer_cast<gr::Placefile::TextDrawItem>(drawItem)); std::static_pointer_cast<gr::Placefile::TextDrawItem>(drawItem));
break; break;