diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp index 7f05aaaf..bcf6214b 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp @@ -1,11 +1,12 @@ #include #include -#include -#include +#include +#include #include -#include -#include +#include + +#include namespace scwx { @@ -23,29 +24,53 @@ static constexpr size_t kNumRectangles = 1; static constexpr size_t kNumTriangles = kNumRectangles * 2; static constexpr size_t kVerticesPerTriangle = 3; static constexpr size_t kVerticesPerRectangle = kVerticesPerTriangle * 2; -static constexpr size_t kPointsPerVertex = 11; +static constexpr size_t kPointsPerVertex = 9; static constexpr size_t kBufferLength = kNumTriangles * kVerticesPerTriangle * kPointsPerVertex; -static const std::string kTextureName = "lines/default-1x7"; +// Threshold, start time, end time +static constexpr std::size_t kIntegersPerVertex_ = 3; + +struct GeoLineDrawItem +{ + bool visible_ {true}; + units::length::nautical_miles threshold_ {}; + std::chrono::sys_time startTime_ {}; + std::chrono::sys_time endTime_ {}; + + boost::gil::rgba32f_pixel_t modulate_ {1.0f, 1.0f, 1.0f, 1.0f}; + float latitude1_ {}; + float longitude1_ {}; + float latitude2_ {}; + float longitude2_ {}; + float width_ {5.0}; + units::angle::degrees angle_ {}; + std::string hoverText_ {}; +}; class GeoLines::Impl { public: + struct LineHoverEntry + { + std::shared_ptr di_; + + glm::vec2 p1_; + glm::vec2 p2_; + glm::vec2 otl_; + glm::vec2 otr_; + glm::vec2 obl_; + glm::vec2 obr_; + }; + explicit Impl(std::shared_ptr context) : context_ {context}, - geodesic_ {util::GeographicLib::DefaultGeodesic()}, - dirty_ {false}, - visible_ {true}, - points_ {}, - angle_ {}, - width_ {7.0f}, - modulateColor_ {std::nullopt}, shaderProgram_ {nullptr}, uMVPMatrixLocation_(GL_INVALID_INDEX), uMapMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), - texture_ {}, + uMapDistanceLocation_(GL_INVALID_INDEX), + uSelectedTimeLocation_(GL_INVALID_INDEX), vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} { @@ -53,30 +78,40 @@ public: ~Impl() {} + void BufferLine(const std::shared_ptr& di); + void Update(); + void UpdateBuffers(); + std::shared_ptr context_; - const GeographicLib::Geodesic& geodesic_; + bool visible_ {true}; + bool dirty_ {false}; + bool thresholded_ {false}; - bool dirty_; + std::chrono::system_clock::time_point selectedTime_ {}; - bool visible_; - std::array points_; - float angle_; - float width_; + std::mutex lineMutex_ {}; - std::optional modulateColor_; + std::vector> currentLineList_ {}; + std::vector> newLineList_ {}; + + std::vector currentLinesBuffer_ {}; + std::vector currentIntegerBuffer_ {}; + std::vector newLinesBuffer_ {}; + std::vector newIntegerBuffer_ {}; + + std::vector currentHoverLines_ {}; + std::vector newHoverLines_ {}; std::shared_ptr shaderProgram_; GLint uMVPMatrixLocation_; GLint uMapMatrixLocation_; GLint uMapScreenCoordLocation_; + GLint uMapDistanceLocation_; + GLint uSelectedTimeLocation_; - util::TextureAttributes texture_; - - GLuint vao_; - GLuint vbo_; - - void Update(); + GLuint vao_; + std::array vbo_; }; GeoLines::GeoLines(std::shared_ptr context) : @@ -93,37 +128,24 @@ void GeoLines::Initialize() gl::OpenGLFunctions& gl = p->context_->gl(); p->shaderProgram_ = p->context_->GetShaderProgram( - ":/gl/geo_line.vert", ":/gl/texture2d_array.frag"); - - p->uMVPMatrixLocation_ = - gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); - if (p->uMVPMatrixLocation_ == -1) - { - logger_->warn("Could not find uMVPMatrix"); - } - - p->uMapMatrixLocation_ = - gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapMatrix"); - if (p->uMapMatrixLocation_ == -1) - { - logger_->warn("Could not find uMapMatrix"); - } + {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, + {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, + {GL_FRAGMENT_SHADER, ":/gl/color.frag"}}); + p->uMVPMatrixLocation_ = p->shaderProgram_->GetUniformLocation("uMVPMatrix"); + p->uMapMatrixLocation_ = p->shaderProgram_->GetUniformLocation("uMapMatrix"); p->uMapScreenCoordLocation_ = - gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapScreenCoord"); - if (p->uMapScreenCoordLocation_ == -1) - { - logger_->warn("Could not find uMapScreenCoord"); - } - - p->texture_ = - util::TextureAtlas::Instance().GetTextureAttributes(kTextureName); + p->shaderProgram_->GetUniformLocation("uMapScreenCoord"); + p->uMapDistanceLocation_ = + p->shaderProgram_->GetUniformLocation("uMapDistance"); + p->uSelectedTimeLocation_ = + p->shaderProgram_->GetUniformLocation("uSelectedTime"); gl.glGenVertexArrays(1, &p->vao_); - gl.glGenBuffers(1, &p->vbo_); + gl.glGenBuffers(static_cast(p->vbo_.size()), p->vbo_.data()); gl.glBindVertexArray(p->vao_); - gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); + gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBufferData( GL_ARRAY_BUFFER, sizeof(float) * kBufferLength, nullptr, GL_DYNAMIC_DRAW); @@ -145,44 +167,96 @@ void GeoLines::Initialize() reinterpret_cast(2 * sizeof(float))); gl.glEnableVertexAttribArray(1); - // aTexCoord - gl.glVertexAttribPointer(2, - 3, - GL_FLOAT, - GL_FALSE, - kPointsPerVertex * sizeof(float), - reinterpret_cast(4 * sizeof(float))); - gl.glEnableVertexAttribArray(2); - // aModulate gl.glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, kPointsPerVertex * sizeof(float), - reinterpret_cast(7 * sizeof(float))); + reinterpret_cast(4 * sizeof(float))); gl.glEnableVertexAttribArray(3); + // aAngle + gl.glVertexAttribPointer(4, + 1, + GL_FLOAT, + GL_FALSE, + kPointsPerVertex * sizeof(float), + reinterpret_cast(8 * sizeof(float))); + gl.glEnableVertexAttribArray(4); + + gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); + gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); + + // aThreshold + gl.glVertexAttribIPointer(5, // + 1, + GL_INT, + kIntegersPerVertex_ * sizeof(GLint), + static_cast(0)); + gl.glEnableVertexAttribArray(5); + + // aTimeRange + gl.glVertexAttribIPointer(6, // + 2, + GL_INT, + kIntegersPerVertex_ * sizeof(GLint), + reinterpret_cast(1 * sizeof(GLint))); + gl.glEnableVertexAttribArray(6); + p->dirty_ = true; } void GeoLines::Render(const QMapLibreGL::CustomLayerRenderParameters& params) { - if (p->visible_) + if (!p->visible_) + { + return; + } + + std::unique_lock lock {p->lineMutex_}; + + if (p->currentLineList_.size() > 0) { gl::OpenGLFunctions& gl = p->context_->gl(); gl.glBindVertexArray(p->vao_); - gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); p->Update(); p->shaderProgram_->Use(); - UseDefaultProjection(params, p->uMVPMatrixLocation_); + UseRotationProjection(params, p->uMVPMatrixLocation_); UseMapProjection( params, p->uMapMatrixLocation_, p->uMapScreenCoordLocation_); - // Draw line - gl.glDrawArrays(GL_TRIANGLES, 0, 6); + if (p->thresholded_) + { + // If thresholding is enabled, set the map distance + units::length::nautical_miles mapDistance = + util::maplibre::GetMapDistance(params); + gl.glUniform1f(p->uMapDistanceLocation_, mapDistance.value()); + } + else + { + // If thresholding is disabled, set the map distance to 0 + gl.glUniform1f(p->uMapDistanceLocation_, 0.0f); + } + + // Selected time + std::chrono::system_clock::time_point selectedTime = + (p->selectedTime_ == std::chrono::system_clock::time_point {}) ? + std::chrono::system_clock::now() : + p->selectedTime_; + gl.glUniform1i( + p->uSelectedTimeLocation_, + static_cast(std::chrono::duration_cast( + selectedTime.time_since_epoch()) + .count())); + + // Draw icons + gl.glDrawArrays(GL_TRIANGLES, + 0, + static_cast(p->currentLineList_.size() * + kVerticesPerRectangle)); } } @@ -191,52 +265,13 @@ void GeoLines::Deinitialize() gl::OpenGLFunctions& gl = p->context_->gl(); gl.glDeleteVertexArrays(1, &p->vao_); - gl.glDeleteBuffers(1, &p->vbo_); -} + gl.glDeleteBuffers(2, p->vbo_.data()); -void GeoLines::SetPoints(float latitude1, - float longitude1, - float latitude2, - float longitude2) -{ - if (p->points_[0].latitude_ != latitude1 || - p->points_[0].longitude_ != longitude1 || - p->points_[1].latitude_ != latitude2 || - p->points_[1].longitude_ != longitude2) - { - p->points_[0] = {latitude1, longitude1}; - p->points_[1] = {latitude2, longitude2}; + std::unique_lock lock {p->lineMutex_}; - double azi1; // Azimuth at point 1 (degrees) - double azi2; // (Forward) azimuth at point 2 (degrees) - p->geodesic_.Inverse(p->points_[0].latitude_, - p->points_[0].longitude_, - p->points_[1].latitude_, - p->points_[1].longitude_, - azi1, - azi2); - p->angle_ = -azi1 * std::numbers::pi / 180.0; - - p->dirty_ = true; - } -} - -void GeoLines::SetModulateColor(boost::gil::rgba8_pixel_t color) -{ - if (p->modulateColor_ != color) - { - p->modulateColor_ = color; - p->dirty_ = true; - } -} - -void GeoLines::SetWidth(float width) -{ - if (p->width_ != width) - { - p->width_ = width; - p->dirty_ = true; - } + p->currentLinesBuffer_.clear(); + p->currentIntegerBuffer_.clear(); + p->currentHoverLines_.clear(); } void GeoLines::SetVisible(bool visible) @@ -244,68 +279,328 @@ void GeoLines::SetVisible(bool visible) p->visible_ = visible; } +void GeoLines::StartLines() +{ + // Clear the new buffers + p->newLineList_.clear(); + p->newLinesBuffer_.clear(); + p->newIntegerBuffer_.clear(); + p->newHoverLines_.clear(); +} + +std::shared_ptr GeoLines::AddLine() +{ + return p->newLineList_.emplace_back(std::make_shared()); +} + +void GeoLines::SetLineLocation(const std::shared_ptr& di, + float latitude1, + float longitude1, + float latitude2, + float longitude2) +{ + di->latitude1_ = latitude1; + di->longitude1_ = longitude1; + di->latitude2_ = latitude2; + di->longitude2_ = longitude2; +} + +void GeoLines::SetLineModulate(const std::shared_ptr& di, + boost::gil::rgba8_pixel_t modulate) +{ + di->modulate_ = {modulate[0] / 255.0f, + modulate[1] / 255.0f, + modulate[2] / 255.0f, + modulate[3] / 255.0f}; +} + +void GeoLines::SetLineModulate(const std::shared_ptr& di, + boost::gil::rgba32f_pixel_t modulate) +{ + di->modulate_ = modulate; +} + +void GeoLines::SetLineWidth(const std::shared_ptr& di, + float width) +{ + di->width_ = width; +} + +void GeoLines::SetLineVisible(const std::shared_ptr& di, + bool visible) +{ + di->visible_ = visible; +} + +void GeoLines::SetLineHoverText(const std::shared_ptr& di, + const std::string& text) +{ + di->hoverText_ = text; +} + +void GeoLines::FinishLines() +{ + // Update buffers + p->UpdateBuffers(); + + std::unique_lock lock {p->lineMutex_}; + + // Swap buffers + p->currentLineList_.swap(p->newLineList_); + p->currentLinesBuffer_.swap(p->newLinesBuffer_); + p->currentIntegerBuffer_.swap(p->newIntegerBuffer_); + p->currentHoverLines_.swap(p->newHoverLines_); + + // Clear the new buffers, except the full line list (used to update buffers + // without re-adding lines) + p->newLinesBuffer_.clear(); + p->newIntegerBuffer_.clear(); + p->newHoverLines_.clear(); + + // Mark the draw item dirty + p->dirty_ = true; +} + +void GeoLines::Impl::UpdateBuffers() +{ + newLinesBuffer_.clear(); + newLinesBuffer_.reserve(newLineList_.size() * kBufferLength); + newIntegerBuffer_.clear(); + newIntegerBuffer_.reserve(newLineList_.size() * kVerticesPerRectangle * + kIntegersPerVertex_); + newHoverLines_.clear(); + + for (auto& di : newLineList_) + { + BufferLine(di); + } +} + +void GeoLines::Impl::BufferLine( + const std::shared_ptr& di) +{ + // Threshold value + units::length::nautical_miles threshold = di->threshold_; + GLint thresholdValue = static_cast(std::round(threshold.value())); + + // Start and end time + GLint startTime = + static_cast(std::chrono::duration_cast( + di->startTime_.time_since_epoch()) + .count()); + GLint endTime = + static_cast(std::chrono::duration_cast( + di->endTime_.time_since_epoch()) + .count()); + + // Latitude and longitude coordinates in degrees + const float lat1 = di->latitude1_; + const float lon1 = di->longitude1_; + const float lat2 = di->latitude2_; + const float lon2 = di->longitude2_; + + // TODO: Base X/Y offsets in pixels + // const float x1 = static_cast(di->x1_); + // const float y1 = static_cast(di->y1_); + // const float x2 = static_cast(di->x2_); + // const float y2 = static_cast(di->y2_); + + // Angle + const units::angle::degrees angle = + util::GeographicLib::GetAngle(lat1, lon1, lat2, lon2); + const float a = static_cast(angle.value()); + + // Final X/Y offsets in pixels + const float hw = di->width_ * 0.5f; + const float lx = -hw; + const float rx = +hw; + const float ty = +hw; + const float by = -hw; + + // Modulate color + const float mc0 = di->modulate_[0]; + const float mc1 = di->modulate_[1]; + const float mc2 = di->modulate_[2]; + const float mc3 = di->modulate_[3]; + + // Update buffers + newLinesBuffer_.insert(newLinesBuffer_.end(), + { + // Line + lat1, lon1, lx, by, mc0, mc1, mc2, mc3, a, // BL + lat2, lon2, lx, ty, mc0, mc1, mc2, mc3, a, // TL + lat1, lon1, rx, by, mc0, mc1, mc2, mc3, a, // BR + lat1, lon1, rx, by, mc0, mc1, mc2, mc3, a, // BR + lat2, lon2, rx, ty, mc0, mc1, mc2, mc3, a, // TR + lat2, lon2, lx, ty, mc0, mc1, mc2, mc3, a // TL + }); + newIntegerBuffer_.insert(newIntegerBuffer_.end(), + {thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime}); + + if (!di->hoverText_.empty()) + { + const units::angle::radians radians = angle; + + const auto sc1 = util::maplibre::LatLongToScreenCoordinate({lat1, lon1}); + const auto sc2 = util::maplibre::LatLongToScreenCoordinate({lat2, lon2}); + + const float cosAngle = cosf(static_cast(radians.value())); + const float sinAngle = sinf(static_cast(radians.value())); + + const glm::mat2 rotate {cosAngle, -sinAngle, sinAngle, cosAngle}; + + const glm::vec2 otl = rotate * glm::vec2 {-hw, +hw}; + const glm::vec2 otr = rotate * glm::vec2 {+hw, +hw}; + const glm::vec2 obl = rotate * glm::vec2 {-hw, -hw}; + const glm::vec2 obr = rotate * glm::vec2 {+hw, -hw}; + + newHoverLines_.emplace_back( + LineHoverEntry {di, sc1, sc2, otl, otr, obl, obr}); + } +} + void GeoLines::Impl::Update() { + // If the lines have been updated if (dirty_) { gl::OpenGLFunctions& gl = context_->gl(); - texture_ = - util::TextureAtlas::Instance().GetTextureAttributes(kTextureName); - - // Latitude and longitude coordinates in degrees - const float lx = points_[0].latitude_; - const float rx = points_[1].latitude_; - const float by = points_[0].longitude_; - const float ty = points_[1].longitude_; - - // Offset x/y in pixels - const float ox = width_ * 0.5f * cosf(angle_); - const float oy = width_ * 0.5f * sinf(angle_); - - // Texture coordinates - static constexpr float r = 0.0f; - - const float ls = texture_.sLeft_; - const float rs = texture_.sRight_; - const float tt = texture_.tTop_; - const float bt = texture_.tBottom_; - - float mc0 = 1.0f; - float mc1 = 1.0f; - float mc2 = 1.0f; - float mc3 = 1.0f; - - if (modulateColor_.has_value()) - { - boost::gil::rgba8_pixel_t& mc = modulateColor_.value(); - - mc0 = mc[0] / 255.0f; - mc1 = mc[1] / 255.0f; - mc2 = mc[2] / 255.0f; - mc3 = mc[3] / 255.0f; - } - - const float buffer[kNumRectangles][kVerticesPerRectangle] - [kPointsPerVertex] = // - { // - // Line - { - {lx, by, -ox, -oy, ls, bt, r, mc0, mc1, mc2, mc3}, // BL - {lx, by, +ox, +oy, ls, tt, r, mc0, mc1, mc2, mc3}, // TL - {rx, ty, -ox, -oy, rs, bt, r, mc0, mc1, mc2, mc3}, // BR - {rx, ty, -ox, -oy, rs, bt, r, mc0, mc1, mc2, mc3}, // BR - {rx, ty, +ox, +oy, rs, tt, r, mc0, mc1, mc2, mc3}, // TR - {lx, by, +ox, +oy, ls, tt, r, mc0, mc1, mc2, mc3} // TL - }}; - + // Buffer lines data + gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBufferData(GL_ARRAY_BUFFER, - sizeof(float) * kBufferLength, - buffer, + sizeof(float) * currentLinesBuffer_.size(), + currentLinesBuffer_.data(), GL_DYNAMIC_DRAW); - dirty_ = false; + // Buffer threshold data + gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); + gl.glBufferData(GL_ARRAY_BUFFER, + sizeof(GLint) * currentIntegerBuffer_.size(), + currentIntegerBuffer_.data(), + GL_DYNAMIC_DRAW); } + + dirty_ = false; +} + +bool GeoLines::RunMousePicking( + const QMapLibreGL::CustomLayerRenderParameters& params, + const QPointF& /* mouseLocalPos */, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& /* mouseGeoCoords */, + std::shared_ptr& /* eventHandler */) +{ + 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 = 2.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(params.bearing), + glm::vec3(0.0f, 0.0f, 1.0f)); + + units::length::meters mapDistance = + (p->thresholded_) ? util::maplibre::GetMapDistance(params) : + units::length::meters {0.0}; + + // If no time has been selected, use the current time + std::chrono::system_clock::time_point selectedTime = + (p->selectedTime_ == std::chrono::system_clock::time_point {}) ? + std::chrono::system_clock::now() : + p->selectedTime_; + + // For each pickable line + auto it = std::find_if( + std::execution::par_unseq, + p->currentHoverLines_.crbegin(), + p->currentHoverLines_.crend(), + [&mapDistance, &selectedTime, &mapMatrix, &mouseCoords](const auto& line) + { + if (( + // Placefile is thresholded + mapDistance > units::length::meters {0.0} && + + // Placefile threshold is < 999 nmi + static_cast(std::round( + units::length::nautical_miles {line.di_->threshold_} + .value())) < 999 && + + // Map distance is beyond the threshold + line.di_->threshold_ < mapDistance) || + + ( + // Line has a start time + line.di_->startTime_ != + std::chrono::system_clock::time_point {} && + + // The time range has not yet started + (selectedTime < line.di_->startTime_ || + + // The time range has ended + line.di_->endTime_ <= selectedTime))) + { + // Line is not pickable + return false; + } + + // Initialize vertices + glm::vec2 bl = line.p1_; + glm::vec2 br = bl; + glm::vec2 tl = line.p2_; + glm::vec2 tr = tl; + + // Calculate offsets + // - Rotated offset is half the line width (pixels) in each direction + // - Multiply the offset by the scaled and rotated map matrix + const glm::vec2 otl = mapMatrix * glm::vec4 {line.otl_, 0.0f, 1.0f}; + const glm::vec2 obl = mapMatrix * glm::vec4 {line.obl_, 0.0f, 1.0f}; + const glm::vec2 obr = mapMatrix * glm::vec4 {line.obr_, 0.0f, 1.0f}; + const glm::vec2 otr = mapMatrix * glm::vec4 {line.otr_, 0.0f, 1.0f}; + + // Offset vertices + tl += otl; + bl += obl; + br += obr; + tr += otr; + + // TODO: X/Y offsets + + // Test point against polygon bounds + return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mouseCoords); + }); + + if (it != p->currentHoverLines_.crend()) + { + itemPicked = true; + util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos); + } + + return itemPicked; } } // namespace draw diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp index 42b04447..e7564698 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp @@ -14,6 +14,8 @@ namespace gl namespace draw { +struct GeoLineDrawItem; + class GeoLines : public DrawItem { public: @@ -26,48 +28,109 @@ public: GeoLines(GeoLines&&) noexcept; GeoLines& operator=(GeoLines&&) noexcept; + void set_selected_time(std::chrono::system_clock::time_point selectedTime); + void set_thresholded(bool thresholded); + void Initialize() override; void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; void Deinitialize() override; - /** - * Sets the geographic coordinate endpoints associated with the line. - * - * @param latitude1 Latitude of the first endpoint in degrees - * @param longitude1 Longitude of the first endpoint in degrees - * @param latitude2 Latitude of the second endpoint in degrees - * @param longitude2 Longitude of the second endpoint in degrees - */ - void SetPoints(float latitude1, - float longitude1, - float latitude2, - float longitude2); + bool + RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler) override; /** - * Sets the modulate color of the line. If specified, the texture color will - * be multiplied by the modulate color to produce the result. + * Sets the visibility of the geo lines. * - * @param color Modulate color (RGBA) - */ - void SetModulateColor(boost::gil::rgba8_pixel_t color); - - /** - * Sets the width of the line. - * - * @param width Width in pixels - */ - void SetWidth(float width); - - /** - * Sets the visibility of the line. - * - * @param visible + * @param [in] visible Line visibility */ void SetVisible(bool visible); + /** + * Resets and prepares the draw item for adding a new set of lines. + */ + void StartLines(); + + /** + * Adds a geo line to the internal draw list. + * + * @return Geo line draw item + */ + std::shared_ptr AddLine(); + + /** + * Sets the location of a geo line. + * + * @param [in] di Geo line draw item + * @param [in] latitude1 The latitude of the first endpoint of the geo line + * in degrees. + * @param [in] longitude1 The longitude of the first endpoint of the geo line + * in degrees. + * @param [in] latitude2 The latitude of the second endpoint of the geo line + * in degrees. + * @param [in] longitude2 The longitude of the second endpoint of the geo + * line in degrees. + */ + static void SetLineLocation(const std::shared_ptr& di, + float latitude1, + float longitude1, + float latitude2, + float longitude2); + + /** + * Sets the modulate color of a geo line. + * + * @param [in] di Geo line draw item + * @param [in] modulate Modulate color + */ + static void SetLineModulate(const std::shared_ptr& di, + boost::gil::rgba8_pixel_t color); + + /** + * Sets the modulate color of a geo line. + * + * @param [in] di Geo line draw item + * @param [in] modulate Modulate color + */ + static void SetLineModulate(const std::shared_ptr& di, + boost::gil::rgba32f_pixel_t modulate); + + /** + * Sets the width of the geo line. + * + * @param [in] width Width in pixels + */ + static void SetLineWidth(const std::shared_ptr& di, + float width); + + /** + * Sets the visibility of the geo line. + * + * @param [in] visible + */ + static void SetLineVisible(const std::shared_ptr& di, + bool visible); + + /** + * Sets the hover text of a geo line. + * + * @param [in] di Geo line draw item + * @param [in] text Hover text + */ + static void SetLineHoverText(const std::shared_ptr& di, + const std::string& text); + + /** + * Finalizes the draw item after adding new lines. + */ + void FinishLines(); + private: class Impl; - std::unique_ptr p; };