From 4a31cf6d3e5a7ec891b712a18048a4116990bc4c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 19 Feb 2023 13:01:19 -0600 Subject: [PATCH] Find nearest radar site --- scwx-qt/source/scwx/qt/config/radar_site.cpp | 42 +++++++++++++++++++ scwx-qt/source/scwx/qt/config/radar_site.hpp | 15 +++++++ .../source/scwx/qt/config/radar_site.test.cpp | 38 +++++++++++++++-- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/scwx-qt/source/scwx/qt/config/radar_site.cpp b/scwx-qt/source/scwx/qt/config/radar_site.cpp index 74a44290..5d2851f8 100644 --- a/scwx-qt/source/scwx/qt/config/radar_site.cpp +++ b/scwx-qt/source/scwx/qt/config/radar_site.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace scwx { @@ -30,6 +31,9 @@ static std::unordered_map> static std::unordered_map siteIdMap_; static std::shared_mutex siteMutex_; +static GeographicLib::Geodesic geodesic_ {GeographicLib::Constants::WGS84_a(), + GeographicLib::Constants::WGS84_f()}; + static bool ValidateJsonEntry(const boost::json::object& o); class RadarSiteImpl @@ -162,6 +166,44 @@ std::vector> RadarSite::GetAll() return radarSites; } +std::shared_ptr RadarSite::FindNearest( + double latitude, double longitude, std::optional type) +{ + std::shared_lock lock(siteMutex_); + + double distanceInMeters; + + std::shared_ptr nearestRadarSite = nullptr; + double nearestDistance = 0.0; + + for (const auto& site : radarSiteMap_) + { + auto& radarSite = site.second; + + // If the type filter doesn't match, skip + if (type.has_value() && radarSite->type() != type) + { + continue; + } + + // Calculate distance to radar site + geodesic_.Inverse(latitude, + longitude, + radarSite->latitude(), + radarSite->longitude(), + distanceInMeters); + + // If the radar site is the closer, record it as the closest + if (nearestRadarSite == nullptr || distanceInMeters < nearestDistance) + { + nearestRadarSite = radarSite; + nearestDistance = distanceInMeters; + } + } + + return nearestRadarSite; +} + std::string GetRadarIdFromSiteId(const std::string& siteId) { std::shared_lock lock(siteMutex_); diff --git a/scwx-qt/source/scwx/qt/config/radar_site.hpp b/scwx-qt/source/scwx/qt/config/radar_site.hpp index 279e8c13..953659f5 100644 --- a/scwx-qt/source/scwx/qt/config/radar_site.hpp +++ b/scwx-qt/source/scwx/qt/config/radar_site.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -38,6 +39,20 @@ public: static std::shared_ptr Get(const std::string& id); static std::vector> GetAll(); + /** + * Find the nearest radar site to the supplied location. + * + * @param latitude Latitude in degrees + * @param longitude Longitude in degrees + * @param type Restrict results to optional radar type + * + * @return Nearest radar site + */ + static std::shared_ptr + FindNearest(double latitude, + double longitude, + std::optional type = std::nullopt); + static void Initialize(); static size_t ReadConfig(const std::string& path); diff --git a/test/source/scwx/qt/config/radar_site.test.cpp b/test/source/scwx/qt/config/radar_site.test.cpp index f69381d1..7c1dde91 100644 --- a/test/source/scwx/qt/config/radar_site.test.cpp +++ b/test/source/scwx/qt/config/radar_site.test.cpp @@ -12,12 +12,23 @@ namespace config static const std::string DEFAULT_RADAR_SITE_FILE = ":/res/config/radar_sites.json"; -TEST(RadarSite, DefaultConfig) +class RadarSiteTest : public testing::Test { - size_t numSites = RadarSite::ReadConfig(DEFAULT_RADAR_SITE_FILE); +protected: + static size_t numSites_; - ASSERT_GT(numSites, 0); - EXPECT_EQ(numSites, 204); + static void SetUpTestSuite() + { + numSites_ = RadarSite::ReadConfig(DEFAULT_RADAR_SITE_FILE); + } +}; + +size_t RadarSiteTest::numSites_ {0u}; + +TEST_F(RadarSiteTest, DefaultConfig) +{ + ASSERT_GT(numSites_, 0); + EXPECT_EQ(numSites_, 204); std::shared_ptr radarSite = RadarSite::Get("KLSX"); @@ -31,6 +42,25 @@ TEST(RadarSite, DefaultConfig) EXPECT_DOUBLE_EQ(radarSite->longitude(), -90.682877); } +TEST_F(RadarSiteTest, FindNearest) +{ + ASSERT_GT(numSites_, 0); + + std::shared_ptr nearest1 = + RadarSite::FindNearest(46.591111, -112.020278); // Helena, MT + std::shared_ptr nearest2 = + RadarSite::FindNearest(28.54, -81.38); // Orlando, FL + std::shared_ptr nearest3 = + RadarSite::FindNearest(38.627222, -90.197778, "wsr88d"); // St Louis, MO + std::shared_ptr nearest4 = + RadarSite::FindNearest(38.627222, -90.197778, "tdwr"); // St Louis, MO + + EXPECT_EQ(nearest1->id(), "KTFX"); + EXPECT_EQ(nearest2->id(), "TMCO"); + EXPECT_EQ(nearest3->id(), "KLSX"); + EXPECT_EQ(nearest4->id(), "TSTL"); +} + } // namespace config } // namespace qt } // namespace scwx