mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 03:20:05 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			258 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <scwx/qt/map/radar_site_layer.hpp>
 | |
| #include <scwx/qt/config/radar_site.hpp>
 | |
| #include <scwx/qt/gl/draw/geo_lines.hpp>
 | |
| #include <scwx/qt/settings/general_settings.hpp>
 | |
| #include <scwx/qt/settings/text_settings.hpp>
 | |
| #include <scwx/qt/util/maplibre.hpp>
 | |
| #include <scwx/qt/util/tooltip.hpp>
 | |
| #include <scwx/common/geographic.hpp>
 | |
| #include <scwx/util/logger.hpp>
 | |
| 
 | |
| #include <imgui.h>
 | |
| #include <mbgl/util/constants.hpp>
 | |
| 
 | |
| #include <QGuiApplication>
 | |
| 
 | |
| 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<gl::GlContext>& glContext) :
 | |
|        self_ {self}, geoLines_ {std::make_shared<gl::draw::GeoLines>(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<config::RadarSite>& radarSite);
 | |
|    void RenderRadarLine(const std::shared_ptr<MapContext>& mapContext);
 | |
| 
 | |
|    RadarSiteLayer* self_;
 | |
| 
 | |
|    std::vector<std::shared_ptr<config::RadarSite>> 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<gl::draw::GeoLines>                       geoLines_;
 | |
|    std::array<std::shared_ptr<gl::draw::GeoLineDrawItem>, 2> radarSiteLines_ {
 | |
|       nullptr, nullptr};
 | |
| };
 | |
| 
 | |
| RadarSiteLayer::RadarSiteLayer(
 | |
|    const std::shared_ptr<gl::GlContext>& glContext) :
 | |
|     DrawLayer(glContext, "RadarSiteLayer"),
 | |
|     p(std::make_unique<Impl>(this, glContext))
 | |
| {
 | |
| }
 | |
| 
 | |
| RadarSiteLayer::~RadarSiteLayer() = default;
 | |
| 
 | |
| void RadarSiteLayer::Initialize(const std::shared_ptr<MapContext>& 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>&            mapContext,
 | |
|    const QMapLibre::CustomLayerRenderParameters& params)
 | |
| {
 | |
|    p->hoverText_.clear();
 | |
| 
 | |
|    auto mapDistance = util::maplibre::GetMapDistance(params);
 | |
|    auto threshold   = units::length::kilometers<double>(
 | |
|       settings::GeneralSettings::Instance().radar_site_threshold().GetValue());
 | |
| 
 | |
|    if (!(threshold.value() == 0.0 || mapDistance <= threshold ||
 | |
|          (threshold.value() < 0 && mapDistance >= -threshold)))
 | |
|    {
 | |
|       return;
 | |
|    }
 | |
| 
 | |
|    // 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<config::RadarSite>&           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>& 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<float>(mouseCoord.latitude_),
 | |
|                                  static_cast<float>(mouseCoord.longitude_),
 | |
|                                  static_cast<float>(radarLatitude),
 | |
|                                  static_cast<float>(radarLongitude));
 | |
|       geoLines_->SetLineVisible(radarSiteLines_[0], true);
 | |
| 
 | |
|       geoLines_->SetLineLocation(radarSiteLines_[1],
 | |
|                                  static_cast<float>(mouseCoord.latitude_),
 | |
|                                  static_cast<float>(mouseCoord.longitude_),
 | |
|                                  static_cast<float>(radarLatitude),
 | |
|                                  static_cast<float>(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>& /* mapContext */,
 | |
|    const QMapLibre::CustomLayerRenderParameters& /* params */,
 | |
|    const QPointF& /* mouseLocalPos */,
 | |
|    const QPointF& mouseGlobalPos,
 | |
|    const glm::vec2& /* mouseCoords */,
 | |
|    const common::Coordinate& /* mouseGeoCoords */,
 | |
|    std::shared_ptr<types::EventHandler>& /* eventHandler */)
 | |
| {
 | |
|    if (!p->hoverText_.empty())
 | |
|    {
 | |
|       util::tooltip::Show(p->hoverText_, mouseGlobalPos);
 | |
|       return true;
 | |
|    }
 | |
| 
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| } // namespace scwx::qt::map
 | 
