Find nearest radar site

This commit is contained in:
Dan Paulat 2023-02-19 13:01:19 -06:00
parent b739aad4bb
commit 4a31cf6d3e
3 changed files with 91 additions and 4 deletions

View file

@ -8,6 +8,7 @@
#include <unordered_map> #include <unordered_map>
#include <boost/json.hpp> #include <boost/json.hpp>
#include <GeographicLib/Geodesic.hpp>
namespace scwx namespace scwx
{ {
@ -30,6 +31,9 @@ static std::unordered_map<std::string, std::shared_ptr<RadarSite>>
static std::unordered_map<std::string, std::string> siteIdMap_; static std::unordered_map<std::string, std::string> siteIdMap_;
static std::shared_mutex siteMutex_; 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); static bool ValidateJsonEntry(const boost::json::object& o);
class RadarSiteImpl class RadarSiteImpl
@ -162,6 +166,44 @@ std::vector<std::shared_ptr<RadarSite>> RadarSite::GetAll()
return radarSites; return radarSites;
} }
std::shared_ptr<RadarSite> RadarSite::FindNearest(
double latitude, double longitude, std::optional<std::string> type)
{
std::shared_lock lock(siteMutex_);
double distanceInMeters;
std::shared_ptr<RadarSite> 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::string GetRadarIdFromSiteId(const std::string& siteId)
{ {
std::shared_lock lock(siteMutex_); std::shared_lock lock(siteMutex_);

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -38,6 +39,20 @@ public:
static std::shared_ptr<RadarSite> Get(const std::string& id); static std::shared_ptr<RadarSite> Get(const std::string& id);
static std::vector<std::shared_ptr<RadarSite>> GetAll(); static std::vector<std::shared_ptr<RadarSite>> 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<RadarSite>
FindNearest(double latitude,
double longitude,
std::optional<std::string> type = std::nullopt);
static void Initialize(); static void Initialize();
static size_t ReadConfig(const std::string& path); static size_t ReadConfig(const std::string& path);

View file

@ -12,12 +12,23 @@ namespace config
static const std::string DEFAULT_RADAR_SITE_FILE = static const std::string DEFAULT_RADAR_SITE_FILE =
":/res/config/radar_sites.json"; ":/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); static void SetUpTestSuite()
EXPECT_EQ(numSites, 204); {
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 = RadarSite::Get("KLSX"); std::shared_ptr<RadarSite> radarSite = RadarSite::Get("KLSX");
@ -31,6 +42,25 @@ TEST(RadarSite, DefaultConfig)
EXPECT_DOUBLE_EQ(radarSite->longitude(), -90.682877); EXPECT_DOUBLE_EQ(radarSite->longitude(), -90.682877);
} }
TEST_F(RadarSiteTest, FindNearest)
{
ASSERT_GT(numSites_, 0);
std::shared_ptr<RadarSite> nearest1 =
RadarSite::FindNearest(46.591111, -112.020278); // Helena, MT
std::shared_ptr<RadarSite> nearest2 =
RadarSite::FindNearest(28.54, -81.38); // Orlando, FL
std::shared_ptr<RadarSite> nearest3 =
RadarSite::FindNearest(38.627222, -90.197778, "wsr88d"); // St Louis, MO
std::shared_ptr<RadarSite> 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 config
} // namespace qt } // namespace qt
} // namespace scwx } // namespace scwx