#include #include #include #include #include #include #include #include #include #include #include #include namespace scwx::qt::map { static const std::string logPrefix_ = "scwx::qt::map::radar_site_layer"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class RadarSiteLayer::Impl { public: explicit Impl(RadarSiteLayer* self, const std::shared_ptr& glContext) : self_ {self}, geoLines_ {std::make_shared(glContext)} { } ~Impl() = default; Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; Impl(const Impl&&) = delete; Impl& operator=(const Impl&&) = delete; void RenderRadarSite(const QMapLibre::CustomLayerRenderParameters& params, std::shared_ptr& radarSite); void RenderRadarLine(const std::shared_ptr& mapContext); RadarSiteLayer* self_; std::vector> radarSites_ {}; glm::vec2 mapScreenCoordLocation_ {}; float mapScale_ {1.0f}; float mapBearingCos_ {1.0f}; float mapBearingSin_ {0.0f}; float halfWidth_ {}; float halfHeight_ {}; std::string hoverText_ {}; std::shared_ptr geoLines_; std::array, 2> radarSiteLines_ { nullptr, nullptr}; }; RadarSiteLayer::RadarSiteLayer( const std::shared_ptr& glContext) : DrawLayer(glContext, "RadarSiteLayer"), p(std::make_unique(this, glContext)) { } RadarSiteLayer::~RadarSiteLayer() = default; void RadarSiteLayer::Initialize(const std::shared_ptr& mapContext) { logger_->debug("Initialize()"); p->radarSites_ = config::RadarSite::GetAll(); p->geoLines_->StartLines(); p->radarSiteLines_[0] = p->geoLines_->AddLine(); p->radarSiteLines_[1] = p->geoLines_->AddLine(); p->geoLines_->FinishLines(); static const boost::gil::rgba32f_pixel_t color0 {0.0f, 0.0f, 0.0f, 1.0f}; static const boost::gil::rgba32f_pixel_t color1 {1.0f, 1.0f, 1.0f, 1.0f}; static const float width = 1; p->geoLines_->SetLineModulate(p->radarSiteLines_[0], color0); p->geoLines_->SetLineWidth(p->radarSiteLines_[0], width + 2); p->geoLines_->SetLineModulate(p->radarSiteLines_[1], color1); p->geoLines_->SetLineWidth(p->radarSiteLines_[1], width); AddDrawItem(p->geoLines_); p->geoLines_->set_thresholded(false); DrawLayer::Initialize(mapContext); } void RadarSiteLayer::Render( const std::shared_ptr& mapContext, const QMapLibre::CustomLayerRenderParameters& params) { p->hoverText_.clear(); auto mapDistance = util::maplibre::GetMapDistance(params); auto threshold = units::length::kilometers( settings::GeneralSettings::Instance().radar_site_threshold().GetValue()); if (!(threshold.value() == 0.0 || mapDistance <= threshold || (threshold.value() < 0 && mapDistance >= -threshold))) { return; } gl::OpenGLFunctions& gl = gl_context()->gl(); // 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; ImGuiFrameStart(mapContext); // Radar site ImGui windows shouldn't have padding ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2 {0.0f, 0.0f}); for (auto& radarSite : p->radarSites_) { p->RenderRadarSite(params, radarSite); } ImGui::PopStyleVar(); p->RenderRadarLine(mapContext); DrawLayer::RenderWithoutImGui(params); ImGuiFrameEnd(); SCWX_GL_CHECK_ERROR(); } void RadarSiteLayer::Impl::RenderRadarSite( const QMapLibre::CustomLayerRenderParameters& params, std::shared_ptr& radarSite) { const std::string windowName = fmt::format("radar-site-{}", radarSite->id()); const auto screenCoordinates = (util::maplibre::LatLongToScreenCoordinate( {radarSite->latitude(), radarSite->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_; } // Convert screen to ImGui coordinates float x = rotatedX + halfWidth_; float y = params.height - (rotatedY + halfHeight_); // Setup window to hold text ImGui::SetNextWindowPos( ImVec2 {x, y}, ImGuiCond_Always, ImVec2 {0.5f, 0.5f}); if (ImGui::Begin(windowName.c_str(), nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) { // Render text if (ImGui::Button(radarSite->id().c_str())) { Q_EMIT self_->RadarSiteSelected(radarSite->id()); self_->ImGuiSelectContext(); } // Store hover text for mouse picking pass if (settings::TextSettings::Instance() .radar_site_hover_text_enabled() .GetValue() && ImGui::IsItemHovered()) { hoverText_ = fmt::format("{} ({})\n{}\n{}, {}", radarSite->id(), radarSite->type_name(), radarSite->location_name(), common::GetLatitudeString(radarSite->latitude()), common::GetLongitudeString(radarSite->longitude())); } // End window ImGui::End(); } } void RadarSiteLayer::Impl::RenderRadarLine( const std::shared_ptr& mapContext) { if ((QGuiApplication::keyboardModifiers() & Qt::KeyboardModifier::ShiftModifier) && mapContext->radar_site() != nullptr) { const auto& mouseCoord = mapContext->mouse_coordinate(); const double radarLatitude = mapContext->radar_site()->latitude(); const double radarLongitude = mapContext->radar_site()->longitude(); geoLines_->SetLineLocation(radarSiteLines_[0], static_cast(mouseCoord.latitude_), static_cast(mouseCoord.longitude_), static_cast(radarLatitude), static_cast(radarLongitude)); geoLines_->SetLineVisible(radarSiteLines_[0], true); geoLines_->SetLineLocation(radarSiteLines_[1], static_cast(mouseCoord.latitude_), static_cast(mouseCoord.longitude_), static_cast(radarLatitude), static_cast(radarLongitude)); geoLines_->SetLineVisible(radarSiteLines_[1], true); } else { geoLines_->SetLineVisible(radarSiteLines_[0], false); geoLines_->SetLineVisible(radarSiteLines_[1], false); } } void RadarSiteLayer::Deinitialize() { logger_->debug("Deinitialize()"); p->radarSites_.clear(); } bool RadarSiteLayer::RunMousePicking( const std::shared_ptr& /* mapContext */, const QMapLibre::CustomLayerRenderParameters& /* params */, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& /* mouseCoords */, const common::Coordinate& /* mouseGeoCoords */, std::shared_ptr& /* eventHandler */) { if (!p->hoverText_.empty()) { util::tooltip::Show(p->hoverText_, mouseGlobalPos); return true; } return false; } } // namespace scwx::qt::map