mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-11-04 14:00: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
 |