Placefile line hover in-work

This commit is contained in:
Dan Paulat 2023-08-28 00:15:57 -05:00
parent 37d751774d
commit 8dfb9f1105
14 changed files with 243 additions and 36 deletions

View file

@ -54,7 +54,8 @@ void DrawItem::Render(const QMapLibreGL::CustomLayerRenderParameters& params,
} }
bool DrawItem::RunMousePicking( bool DrawItem::RunMousePicking(
const QMapLibreGL::CustomLayerRenderParameters& /* params */) const QMapLibreGL::CustomLayerRenderParameters& /* params */,
const glm::vec2& /* mousePos */)
{ {
// By default, the draw item is not picked // By default, the draw item is not picked
return false; return false;
@ -97,17 +98,7 @@ void DrawItem::UseMapProjection(
{ {
OpenGLFunctions& gl = p->gl_; OpenGLFunctions& gl = p->gl_;
// TODO: Refactor to utility class const glm::mat4 uMVPMatrix = util::maplibre::GetMapMatrix(params);
const float scale = std::pow(2.0, params.zoom) * 2.0f *
mbgl::util::tileSize_D / mbgl::util::DEGREES_MAX;
const float xScale = scale / params.width;
const float yScale = scale / params.height;
glm::mat4 uMVPMatrix(1.0f);
uMVPMatrix = glm::scale(uMVPMatrix, glm::vec3(xScale, yScale, 1.0f));
uMVPMatrix = glm::rotate(uMVPMatrix,
glm::radians<float>(params.bearing),
glm::vec3(0.0f, 0.0f, 1.0f));
gl.glUniform2fv(uMapScreenCoordLocation, gl.glUniform2fv(uMapScreenCoordLocation,
1, 1,

View file

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include <QMapLibreGL/QMapLibreGL> #include <QMapLibreGL/QMapLibreGL>
#include <glm/gtc/type_ptr.hpp>
namespace scwx namespace scwx
{ {
@ -37,11 +38,13 @@ public:
* @brief Run mouse picking on the draw item. * @brief Run mouse picking on the draw item.
* *
* @param [in] params Custom layer render parameters * @param [in] params Custom layer render parameters
* @param [in] mousePos Mouse cursor location in map screen coordinates
* *
* @return true if the draw item was picked, otherwise false * @return true if the draw item was picked, otherwise false
*/ */
virtual bool virtual bool
RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params); RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params,
const glm::vec2& mousePos);
protected: protected:
void void

View file

@ -1,8 +1,12 @@
#include <scwx/qt/gl/draw/placefile_lines.hpp> #include <scwx/qt/gl/draw/placefile_lines.hpp>
#include <scwx/qt/manager/resource_manager.hpp>
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/util/geographic_lib.hpp> #include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/qt/util/maplibre.hpp> #include <scwx/qt/util/maplibre.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <imgui.h>
namespace scwx namespace scwx
{ {
namespace qt namespace qt
@ -28,6 +32,15 @@ static const boost::gil::rgba8_pixel_t kBlack_ {0, 0, 0, 255};
class PlacefileLines::Impl class PlacefileLines::Impl
{ {
public: public:
struct LineHoverEntry
{
std::string hoverText_;
glm::vec2 p1_;
glm::vec2 p2_;
glm::mat2 rotate_;
float width_;
};
explicit Impl(const std::shared_ptr<GlContext>& context) : explicit Impl(const std::shared_ptr<GlContext>& context) :
context_ {context}, context_ {context},
shaderProgram_ {nullptr}, shaderProgram_ {nullptr},
@ -46,9 +59,10 @@ public:
void BufferLine(const gr::Placefile::LineDrawItem::Element& e1, void BufferLine(const gr::Placefile::LineDrawItem::Element& e1,
const gr::Placefile::LineDrawItem::Element& e2, const gr::Placefile::LineDrawItem::Element& e2,
const float width, const float width,
const float angle, const units::angle::degrees<double> angle,
const boost::gil::rgba8_pixel_t color, const boost::gil::rgba8_pixel_t color,
const GLint threshold); const GLint threshold,
const std::string& hoverText = {});
void void
UpdateBuffers(const std::shared_ptr<const gr::Placefile::LineDrawItem>& di); UpdateBuffers(const std::shared_ptr<const gr::Placefile::LineDrawItem>& di);
void Update(); void Update();
@ -68,6 +82,9 @@ public:
std::vector<float> newLinesBuffer_ {}; std::vector<float> newLinesBuffer_ {};
std::vector<GLint> newThresholdBuffer_ {}; std::vector<GLint> newThresholdBuffer_ {};
std::vector<LineHoverEntry> currentHoverLines_ {};
std::vector<LineHoverEntry> newHoverLines_ {};
std::shared_ptr<ShaderProgram> shaderProgram_; std::shared_ptr<ShaderProgram> shaderProgram_;
GLint uMVPMatrixLocation_; GLint uMVPMatrixLocation_;
GLint uMapMatrixLocation_; GLint uMapMatrixLocation_;
@ -213,6 +230,125 @@ void PlacefileLines::Deinitialize()
p->currentLinesBuffer_.clear(); p->currentLinesBuffer_.clear();
p->currentThresholdBuffer_.clear(); p->currentThresholdBuffer_.clear();
p->currentHoverLines_.clear();
}
void DrawTooltip(const std::string& hoverText)
{
// 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);
auto monospaceFont = monospace->ImGuiFont(fontSize);
ImGui::BeginTooltip();
ImGui::PushFont(monospaceFont);
ImGui::TextUnformatted(hoverText.c_str());
ImGui::PopFont();
ImGui::EndTooltip();
}
bool IsPointInPolygon(const std::vector<glm::vec2> vertices,
const glm::vec2& point)
{
bool inPolygon = true;
// For each vertex, assume counterclockwise order
for (std::size_t i = 0; i < vertices.size(); ++i)
{
const auto& p1 = vertices[i];
const auto& p2 =
(i == vertices.size() - 1) ? vertices[0] : vertices[i + 1];
// Test which side of edge point lies on
const float a = -(p2.y - p1.y);
const float b = p2.x - p1.x;
const float c = -(a * p1.x + b * p1.y);
const float d = a * point.x + b * point.y + c;
// If d < 0, the point is on the right-hand side, and outside of the
// polygon
if (d < 0)
{
inPolygon = false;
break;
}
}
return inPolygon;
}
bool PlacefileLines::RunMousePicking(
const QMapLibreGL::CustomLayerRenderParameters& params,
const glm::vec2& mousePos)
{
std::unique_lock lock {p->lineMutex_};
bool itemPicked = false;
// Calculate map scale, remove width and height from original calculation
glm::vec2 scale = util::maplibre::GetMapScale(params);
scale = 1.0f / glm::vec2 {scale.x * params.width, scale.y * params.height};
// Scale and rotate the identity matrix to create the map matrix
glm::mat4 mapMatrix {1.0f};
mapMatrix = glm::scale(mapMatrix, glm::vec3 {scale, 1.0f});
mapMatrix = glm::rotate(mapMatrix,
glm::radians<float>(params.bearing),
glm::vec3(0.0f, 0.0f, 1.0f));
// For each pickable line
for (auto& line : p->currentHoverLines_)
{
// Initialize vertices
glm::vec2 bl = line.p1_;
glm::vec2 br = bl;
glm::vec2 tl = line.p2_;
glm::vec2 tr = tl;
// Calculate offsets
// - Offset is half the line width (pixels) in each direction
// - Rotate the offset at each vertex
// - Multiply the offset by the map matrix
const float hw = line.width_ * 0.5f;
const glm::vec2 otl =
mapMatrix *
glm::vec4 {line.rotate_ * glm::vec2 {-hw, -hw}, 0.0f, 1.0f};
const glm::vec2 obl =
mapMatrix * glm::vec4 {line.rotate_ * glm::vec2 {-hw, hw}, 0.0f, 1.0f};
const glm::vec2 obr =
mapMatrix * glm::vec4 {line.rotate_ * glm::vec2 {hw, hw}, 0.0f, 1.0f};
const glm::vec2 otr =
mapMatrix * glm::vec4 {line.rotate_ * glm::vec2 {hw, -hw}, 0.0f, 1.0f};
// Offset vertices
tl += otl;
bl += obl;
br += obr;
tr += otr;
// TODO: X/Y offsets
// Test point against polygon bounds
if (IsPointInPolygon({tl, bl, br, tr}, mousePos))
{
itemPicked = true;
DrawTooltip(line.hoverText_);
break;
}
}
return itemPicked;
} }
void PlacefileLines::StartLines() void PlacefileLines::StartLines()
@ -220,6 +356,7 @@ void PlacefileLines::StartLines()
// Clear the new buffers // Clear the new buffers
p->newLinesBuffer_.clear(); p->newLinesBuffer_.clear();
p->newThresholdBuffer_.clear(); p->newThresholdBuffer_.clear();
p->newHoverLines_.clear();
p->newNumLines_ = 0u; p->newNumLines_ = 0u;
} }
@ -241,10 +378,12 @@ void PlacefileLines::FinishLines()
// Swap buffers // Swap buffers
p->currentLinesBuffer_.swap(p->newLinesBuffer_); p->currentLinesBuffer_.swap(p->newLinesBuffer_);
p->currentThresholdBuffer_.swap(p->newThresholdBuffer_); p->currentThresholdBuffer_.swap(p->newThresholdBuffer_);
p->currentHoverLines_.swap(p->newHoverLines_);
// Clear the new buffers // Clear the new buffers
p->newLinesBuffer_.clear(); p->newLinesBuffer_.clear();
p->newThresholdBuffer_.clear(); p->newThresholdBuffer_.clear();
p->newHoverLines_.clear();
// Update the number of lines // Update the number of lines
p->currentNumLines_ = p->newNumLines_; p->currentNumLines_ = p->newNumLines_;
@ -262,7 +401,7 @@ void PlacefileLines::Impl::UpdateBuffers(
units::length::nautical_miles<double> threshold = di->threshold_; units::length::nautical_miles<double> threshold = di->threshold_;
GLint thresholdValue = static_cast<GLint>(std::round(threshold.value())); GLint thresholdValue = static_cast<GLint>(std::round(threshold.value()));
std::vector<float> angles {}; std::vector<units::angle::degrees<double>> angles {};
angles.reserve(di->elements_.size() - 1); angles.reserve(di->elements_.size() - 1);
// For each element pair inside a Line statement, render a black line // For each element pair inside a Line statement, render a black line
@ -277,26 +416,27 @@ void PlacefileLines::Impl::UpdateBuffers(
// Calculate angle // Calculate angle
const units::angle::degrees<double> angle = const units::angle::degrees<double> angle =
util::GeographicLib::GetAngle(lat1, lon1, lat2, lon2); util::GeographicLib::GetAngle(lat1, lon1, lat2, lon2);
float angleValue = angle.value(); angles.push_back(angle);
angles.push_back(angleValue);
// Buffer line with hover text
BufferLine(di->elements_[i], BufferLine(di->elements_[i],
di->elements_[i + 1], di->elements_[i + 1],
di->width_ + 2, di->width_ + 2,
static_cast<float>(angleValue), angle,
kBlack_, kBlack_,
thresholdValue); thresholdValue,
di->hoverText_);
} }
// For each element pair inside a Line statement, render a colored line // For each element pair inside a Line statement, render a colored line
for (std::size_t i = 0; i < di->elements_.size() - 1; ++i) for (std::size_t i = 0; i < di->elements_.size() - 1; ++i)
{ {
float angleValue = angles[i]; auto angle = angles[i];
BufferLine(di->elements_[i], BufferLine(di->elements_[i],
di->elements_[i + 1], di->elements_[i + 1],
di->width_, di->width_,
static_cast<float>(angleValue), angle,
di->color_, di->color_,
thresholdValue); thresholdValue);
} }
@ -306,9 +446,10 @@ void PlacefileLines::Impl::BufferLine(
const gr::Placefile::LineDrawItem::Element& e1, const gr::Placefile::LineDrawItem::Element& e1,
const gr::Placefile::LineDrawItem::Element& e2, const gr::Placefile::LineDrawItem::Element& e2,
const float width, const float width,
const float angle, const units::angle::degrees<double> angle,
const boost::gil::rgba8_pixel_t color, const boost::gil::rgba8_pixel_t color,
const GLint threshold) const GLint threshold,
const std::string& hoverText)
{ {
// Latitude and longitude coordinates in degrees // Latitude and longitude coordinates in degrees
const float lat1 = static_cast<float>(e1.latitude_); const float lat1 = static_cast<float>(e1.latitude_);
@ -323,7 +464,7 @@ void PlacefileLines::Impl::BufferLine(
// const float y2 = static_cast<float>(e2.y_); // const float y2 = static_cast<float>(e2.y_);
// Angle // Angle
const float a = angle; const float a = static_cast<float>(angle.value());
// Final X/Y offsets in pixels // Final X/Y offsets in pixels
const float hw = width * 0.5f; const float hw = width * 0.5f;
@ -352,6 +493,22 @@ void PlacefileLines::Impl::BufferLine(
newThresholdBuffer_.insert( newThresholdBuffer_.insert(
newThresholdBuffer_.end(), newThresholdBuffer_.end(),
{threshold, threshold, threshold, threshold, threshold, threshold}); {threshold, threshold, threshold, threshold, threshold, threshold});
if (!hoverText.empty())
{
const units::angle::radians<double> radians = angle;
const auto sc1 = util::maplibre::LatLongToScreenCoordinate({lat1, lon1});
const auto sc2 = util::maplibre::LatLongToScreenCoordinate({lat2, lon2});
const float cosAngle = cosf(static_cast<float>(radians.value()));
const float sinAngle = sinf(static_cast<float>(radians.value()));
const glm::mat2 rotate {cosAngle, -sinAngle, sinAngle, cosAngle};
newHoverLines_.emplace_back(
LineHoverEntry {hoverText, sc1, sc2, rotate, width});
}
} }
void PlacefileLines::Impl::Update() void PlacefileLines::Impl::Update()

View file

@ -31,6 +31,9 @@ public:
void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override;
void Deinitialize() override; void Deinitialize() override;
bool RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params,
const glm::vec2& mousePos) override;
/** /**
* Resets and prepares the draw item for adding a new set of lines. * Resets and prepares the draw item for adding a new set of lines.
*/ */

View file

@ -210,7 +210,8 @@ void PlacefileText::Deinitialize()
} }
bool PlacefileText::RunMousePicking( bool PlacefileText::RunMousePicking(
const QMapLibreGL::CustomLayerRenderParameters& /* params */) const QMapLibreGL::CustomLayerRenderParameters& /* params */,
const glm::vec2& /* mousePos */)
{ {
bool itemPicked = false; bool itemPicked = false;

View file

@ -33,8 +33,8 @@ public:
void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override;
void Deinitialize() override; void Deinitialize() override;
bool RunMousePicking( bool RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params,
const QMapLibreGL::CustomLayerRenderParameters& params) override; const glm::vec2& mousePos) override;
/** /**
* Resets and prepares the draw item for adding a new set of text. * Resets and prepares the draw item for adding a new set of text.

View file

@ -77,7 +77,8 @@ void DrawLayer::Deinitialize()
} }
bool DrawLayer::RunMousePicking( bool DrawLayer::RunMousePicking(
const QMapLibreGL::CustomLayerRenderParameters& params) const QMapLibreGL::CustomLayerRenderParameters& params,
const glm::vec2& mousePos)
{ {
bool itemPicked = false; bool itemPicked = false;
@ -85,7 +86,7 @@ bool DrawLayer::RunMousePicking(
for (auto it = p->drawList_.rbegin(); it != p->drawList_.rend(); ++it) for (auto it = p->drawList_.rbegin(); it != p->drawList_.rend(); ++it)
{ {
// Run mouse picking on each draw item // Run mouse picking on each draw item
if ((*it)->RunMousePicking(params)) if ((*it)->RunMousePicking(params, mousePos))
{ {
// If a draw item was picked, don't process additional items // If a draw item was picked, don't process additional items
itemPicked = true; itemPicked = true;

View file

@ -23,8 +23,9 @@ public:
Render(const QMapLibreGL::CustomLayerRenderParameters&) override; Render(const QMapLibreGL::CustomLayerRenderParameters&) override;
virtual void Deinitialize() override; virtual void Deinitialize() override;
virtual bool RunMousePicking( virtual bool
const QMapLibreGL::CustomLayerRenderParameters& params) override; RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params,
const glm::vec2& mousePos) override;
protected: protected:
void AddDrawItem(const std::shared_ptr<gl::draw::DrawItem>& drawItem); void AddDrawItem(const std::shared_ptr<gl::draw::DrawItem>& drawItem);

View file

@ -27,7 +27,8 @@ GenericLayer::GenericLayer(std::shared_ptr<MapContext> context) :
GenericLayer::~GenericLayer() = default; GenericLayer::~GenericLayer() = default;
bool GenericLayer::RunMousePicking( bool GenericLayer::RunMousePicking(
const QMapLibreGL::CustomLayerRenderParameters& /* params */) const QMapLibreGL::CustomLayerRenderParameters& /* params */,
const glm::vec2& /* mousePos */)
{ {
// By default, the layer has nothing to pick // By default, the layer has nothing to pick
return false; return false;

View file

@ -6,6 +6,7 @@
#include <QObject> #include <QObject>
#include <QMapLibreGL/QMapLibreGL> #include <QMapLibreGL/QMapLibreGL>
#include <glm/gtc/type_ptr.hpp>
namespace scwx namespace scwx
{ {
@ -32,11 +33,13 @@ public:
* @brief Run mouse picking on the layer. * @brief Run mouse picking on the layer.
* *
* @param [in] params Custom layer render parameters * @param [in] params Custom layer render parameters
* @param [in] mousePos Mouse cursor location in map screen coordinates
* *
* @return true if a draw item was picked, otherwise false * @return true if a draw item was picked, otherwise false
*/ */
virtual bool virtual bool
RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params); RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params,
const glm::vec2& mousePos);
protected: protected:
std::shared_ptr<MapContext> context() const; std::shared_ptr<MapContext> context() const;

View file

@ -13,6 +13,7 @@
#include <scwx/qt/map/radar_range_layer.hpp> #include <scwx/qt/map/radar_range_layer.hpp>
#include <scwx/qt/model/imgui_context_model.hpp> #include <scwx/qt/model/imgui_context_model.hpp>
#include <scwx/qt/util/file.hpp> #include <scwx/qt/util/file.hpp>
#include <scwx/qt/util/maplibre.hpp>
#include <scwx/qt/view/radar_product_view_factory.hpp> #include <scwx/qt/view/radar_product_view_factory.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <scwx/util/time.hpp> #include <scwx/util/time.hpp>
@ -172,6 +173,7 @@ public:
common::Level2Product selectedLevel2Product_; common::Level2Product selectedLevel2Product_;
bool hasMouse_ {false};
QPointF lastPos_; QPointF lastPos_;
std::size_t currentStyleIndex_; std::size_t currentStyleIndex_;
const MapStyle* currentStyle_; const MapStyle* currentStyle_;
@ -862,6 +864,16 @@ void MapWidgetImpl::AddLayer(const std::string& id,
layerList_.push_back(id); layerList_.push_back(id);
} }
void MapWidget::enterEvent(QEnterEvent* /* ev */)
{
p->hasMouse_ = true;
}
void MapWidget::leaveEvent(QEvent* /* ev */)
{
p->hasMouse_ = false;
}
void MapWidget::keyPressEvent(QKeyEvent* ev) void MapWidget::keyPressEvent(QKeyEvent* ev)
{ {
switch (ev->key()) switch (ev->key())
@ -1024,7 +1036,10 @@ void MapWidget::paintGL()
p->map_->render(); p->map_->render();
// Perform mouse picking // Perform mouse picking
p->RunMousePicking(); if (p->hasMouse_)
{
p->RunMousePicking();
}
// Render ImGui Frame // Render ImGui Frame
ImGui::Render(); ImGui::Render();
@ -1039,13 +1054,17 @@ void MapWidgetImpl::RunMousePicking()
const QMapLibreGL::CustomLayerRenderParameters params = const QMapLibreGL::CustomLayerRenderParameters params =
context_->render_parameters(); context_->render_parameters();
auto coordinate = map_->coordinateForPixel(lastPos_);
auto mouseScreenCoordinate =
util::maplibre::LatLongToScreenCoordinate(coordinate);
// For each layer in reverse // For each layer in reverse
// TODO: All Generic Layers, not just Placefile Layers // TODO: All Generic Layers, not just Placefile Layers
for (auto it = placefileLayers_.rbegin(); it != placefileLayers_.rend(); for (auto it = placefileLayers_.rbegin(); it != placefileLayers_.rend();
++it) ++it)
{ {
// Run mouse picking for each layer // Run mouse picking for each layer
if ((*it)->RunMousePicking(params)) if ((*it)->RunMousePicking(params, mouseScreenCoordinate))
{ {
// If a draw item was picked, don't process additional layers // If a draw item was picked, don't process additional layers
break; break;

View file

@ -119,7 +119,9 @@ private:
qreal pixelRatio(); qreal pixelRatio();
// QWidget implementation. // QWidget implementation.
void enterEvent(QEnterEvent* ev) override final;
void keyPressEvent(QKeyEvent* ev) override final; void keyPressEvent(QKeyEvent* ev) override final;
void leaveEvent(QEvent* ev) override final;
void mousePressEvent(QMouseEvent* ev) override final; void mousePressEvent(QMouseEvent* ev) override final;
void mouseMoveEvent(QMouseEvent* ev) override final; void mouseMoveEvent(QMouseEvent* ev) override final;
void wheelEvent(QWheelEvent* ev) override final; void wheelEvent(QWheelEvent* ev) override final;

View file

@ -20,6 +20,29 @@ GetMapDistance(const QMapLibreGL::CustomLayerRenderParameters& params)
(params.width + params.height) / 2.0); (params.width + params.height) / 2.0);
} }
glm::mat4 GetMapMatrix(const QMapLibreGL::CustomLayerRenderParameters& params)
{
glm::vec2 scale = GetMapScale(params);
glm::mat4 mapMatrix(1.0f);
mapMatrix = glm::scale(mapMatrix, glm::vec3(scale, 1.0f));
mapMatrix = glm::rotate(mapMatrix,
glm::radians<float>(params.bearing),
glm::vec3(0.0f, 0.0f, 1.0f));
return mapMatrix;
}
glm::vec2 GetMapScale(const QMapLibreGL::CustomLayerRenderParameters& params)
{
const float scale = std::pow(2.0, params.zoom) * 2.0f *
mbgl::util::tileSize_D / mbgl::util::DEGREES_MAX;
const float xScale = scale / params.width;
const float yScale = scale / params.height;
return glm::vec2 {xScale, yScale};
}
glm::vec2 LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate) glm::vec2 LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate)
{ {
static constexpr double RAD2DEG_D = 180.0 / M_PI; static constexpr double RAD2DEG_D = 180.0 / M_PI;

View file

@ -15,6 +15,8 @@ namespace maplibre
units::length::meters<double> units::length::meters<double>
GetMapDistance(const QMapLibreGL::CustomLayerRenderParameters& params); GetMapDistance(const QMapLibreGL::CustomLayerRenderParameters& params);
glm::mat4 GetMapMatrix(const QMapLibreGL::CustomLayerRenderParameters& params);
glm::vec2 GetMapScale(const QMapLibreGL::CustomLayerRenderParameters& params);
glm::vec2 LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate); glm::vec2 LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate);
} // namespace maplibre } // namespace maplibre