Merge pull request #250 from AdenKoperczak/audio_location_methods

Radar Site Audio Location Method and Radius
This commit is contained in:
Dan Paulat 2024-07-29 22:32:30 -05:00 committed by GitHub
commit 7b41184fbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 802 additions and 120 deletions

View file

@ -1466,6 +1466,7 @@ void MainWindowImpl::UpdateRadarSite()
timelineManager_->SetRadarSite("?");
}
alertManager_->SetRadarSite(radarSite);
placefileManager_->SetRadarSite(radarSite);
}

View file

@ -6,6 +6,8 @@
#include <scwx/qt/types/location_types.hpp>
#include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/util/logger.hpp>
#include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/settings/general_settings.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
@ -74,6 +76,8 @@ public:
PositionManager::Instance()};
std::shared_ptr<TextEventManager> textEventManager_ {
TextEventManager::Instance()};
std::shared_ptr<config::RadarSite> radarSite_ {};
};
AlertManager::AlertManager() : p(std::make_unique<Impl>(this)) {}
@ -100,6 +104,33 @@ common::Coordinate AlertManager::Impl::CurrentCoordinate(
coordinate.longitude_ = trackedCoordinate.longitude();
}
}
else if (locationMethod == types::LocationMethod::RadarSite)
{
std::string radarSiteSelection =
audioSettings.alert_radar_site().GetValue();
std::shared_ptr<config::RadarSite> radarSite;
if (radarSiteSelection == "default")
{
std::string siteId = settings::GeneralSettings::Instance()
.default_radar_site()
.GetValue();
radarSite = config::RadarSite::Get(siteId);
}
else if (radarSiteSelection == "follow")
{
radarSite = radarSite_;
}
else
{
radarSite = config::RadarSite::Get(radarSiteSelection);
}
if (radarSite != nullptr)
{
coordinate.latitude_ = radarSite->latitude();
coordinate.longitude_ = radarSite->longitude();
}
}
return coordinate;
}
@ -118,6 +149,8 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
audioSettings.alert_location_method().GetValue());
common::Coordinate currentCoordinate = CurrentCoordinate(locationMethod);
std::string alertCounty = audioSettings.alert_county().GetValue();
auto alertRadius = units::length::kilometers<double>(
audioSettings.alert_radius().GetValue());
auto message = textEventManager_->message_list(key).at(messageIndex);
@ -145,13 +178,16 @@ void AlertManager::Impl::HandleAlert(const types::TextEventKey& key,
bool activeAtLocation = (locationMethod == types::LocationMethod::All);
if (locationMethod == types::LocationMethod::Fixed ||
locationMethod == types::LocationMethod::Track)
locationMethod == types::LocationMethod::Track ||
locationMethod == types::LocationMethod::RadarSite)
{
// Determine if the alert is active at the current coordinte
auto alertCoordinates = segment->codedLocation_->coordinates();
activeAtLocation = util::GeographicLib::AreaContainsPoint(
alertCoordinates, currentCoordinate);
activeAtLocation = util::GeographicLib::AreaInRangeOfPoint(
alertCoordinates,
currentCoordinate,
alertRadius);
}
else if (locationMethod == types::LocationMethod::County)
{
@ -183,6 +219,27 @@ void AlertManager::Impl::UpdateLocationTracking(
positionManager_->EnablePositionUpdates(uuid_, locationEnabled);
}
void AlertManager::SetRadarSite(
const std::shared_ptr<config::RadarSite>& radarSite)
{
if (p->radarSite_ == radarSite)
{
// No action needed
return;
}
if (radarSite == nullptr)
{
logger_->debug("SetRadarSite: ?");
}
else
{
logger_->debug("SetRadarSite: {}", radarSite->id());
}
p->radarSite_ = radarSite;
}
std::shared_ptr<AlertManager> AlertManager::Instance()
{
static std::weak_ptr<AlertManager> alertManagerReference_ {};

View file

@ -1,5 +1,7 @@
#pragma once
#include <scwx/qt/config/radar_site.hpp>
#include <memory>
#include <QObject>
@ -20,6 +22,7 @@ public:
explicit AlertManager();
~AlertManager();
void SetRadarSite(const std::shared_ptr<config::RadarSite>& radarSite);
static std::shared_ptr<AlertManager> Instance();
private:

View file

@ -1,13 +1,16 @@
#include <scwx/qt/model/alert_model.hpp>
#include <scwx/qt/config/county_database.hpp>
#include <scwx/qt/manager/text_event_manager.hpp>
#include <scwx/qt/settings/unit_settings.hpp>
#include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/types/unit_types.hpp>
#include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/common/geographic.hpp>
#include <scwx/util/logger.hpp>
#include <scwx/util/strings.hpp>
#include <scwx/util/time.hpp>
#include <format>
#include <QApplication>
@ -73,7 +76,6 @@ public:
double,
types::TextEventHash<types::TextEventKey>>
distanceMap_;
scwx::common::DistanceType distanceDisplay_;
scwx::common::Coordinate previousPosition_;
};
@ -182,18 +184,19 @@ QVariant AlertModel::data(const QModelIndex& index, int role) const
case static_cast<int>(Column::Distance):
if (role == Qt::DisplayRole)
{
if (p->distanceDisplay_ == scwx::common::DistanceType::Miles)
{
return QString("%1 mi").arg(
static_cast<uint32_t>(p->distanceMap_.at(textEventKey) *
scwx::common::kMilesPerMeter));
}
else
{
return QString("%1 km").arg(
static_cast<uint32_t>(p->distanceMap_.at(textEventKey) *
scwx::common::kKilometersPerMeter));
}
const std::string distanceUnitName =
settings::UnitSettings::Instance().distance_units().GetValue();
types::DistanceUnits distanceUnits =
types::GetDistanceUnitsFromName(distanceUnitName);
double distanceScale = types::GetDistanceUnitsScale(distanceUnits);
std::string abbreviation =
types::GetDistanceUnitsAbbreviation(distanceUnits);
return QString("%1 %2")
.arg(static_cast<uint32_t>(p->distanceMap_.at(textEventKey) *
scwx::common::kKilometersPerMeter *
distanceScale))
.arg(QString::fromStdString(abbreviation));
}
else
{
@ -419,7 +422,6 @@ AlertModelImpl::AlertModelImpl() :
textEventKeys_ {},
geodesic_(util::GeographicLib::DefaultGeodesic()),
distanceMap_ {},
distanceDisplay_ {scwx::common::DistanceType::Miles},
previousPosition_ {}
{
}

View file

@ -1,6 +1,8 @@
#include <scwx/qt/model/radar_site_model.hpp>
#include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/settings/unit_settings.hpp>
#include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/types/unit_types.hpp>
#include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/common/geographic.hpp>
@ -36,7 +38,6 @@ public:
radarSites_ {},
geodesic_(util::GeographicLib::DefaultGeodesic()),
distanceMap_ {},
distanceDisplay_ {scwx::common::DistanceType::Miles},
previousPosition_ {}
{
// Get all loaded radar sites
@ -64,7 +65,6 @@ public:
const GeographicLib::Geodesic& geodesic_;
std::unordered_map<std::string, double> distanceMap_;
scwx::common::DistanceType distanceDisplay_;
scwx::common::Coordinate previousPosition_;
QIcon starIcon_ {":/res/icons/font-awesome-6/star-solid.svg"};
@ -213,18 +213,19 @@ QVariant RadarSiteModel::data(const QModelIndex& index, int role) const
case static_cast<int>(Column::Distance):
if (role == Qt::DisplayRole)
{
if (p->distanceDisplay_ == scwx::common::DistanceType::Miles)
{
return QString("%1 mi").arg(
static_cast<uint32_t>(p->distanceMap_.at(site->id()) *
scwx::common::kMilesPerMeter));
}
else
{
return QString("%1 km").arg(
static_cast<uint32_t>(p->distanceMap_.at(site->id()) *
scwx::common::kKilometersPerMeter));
}
const std::string distanceUnitName =
settings::UnitSettings::Instance().distance_units().GetValue();
types::DistanceUnits distanceUnits =
types::GetDistanceUnitsFromName(distanceUnitName);
double distanceScale = types::GetDistanceUnitsScale(distanceUnits);
std::string abbreviation =
types::GetDistanceUnitsAbbreviation(distanceUnits);
return QString("%1 %2")
.arg(static_cast<uint32_t>(p->distanceMap_.at(site->id()) *
scwx::common::kKilometersPerMeter *
distanceScale))
.arg(QString::fromStdString(abbreviation));
}
else
{

View file

@ -37,12 +37,17 @@ public:
alertLocationMethod_.SetDefault(defaultAlertLocationMethodValue);
alertLatitude_.SetDefault(0.0);
alertLongitude_.SetDefault(0.0);
alertRadius_.SetDefault(0.0);
alertRadarSite_.SetDefault("default");
ignoreMissingCodecs_.SetDefault(false);
alertLatitude_.SetMinimum(-90.0);
alertLatitude_.SetMaximum(90.0);
alertLongitude_.SetMinimum(-180.0);
alertLongitude_.SetMaximum(180.0);
alertRadius_.SetMinimum(0.0);
alertRadius_.SetMaximum(9999999999);
alertLocationMethod_.SetValidator(
SCWX_SETTINGS_ENUM_VALIDATOR(types::LocationMethod,
@ -86,6 +91,8 @@ public:
SettingsVariable<std::string> alertLocationMethod_ {"alert_location_method"};
SettingsVariable<double> alertLatitude_ {"alert_latitude"};
SettingsVariable<double> alertLongitude_ {"alert_longitude"};
SettingsVariable<std::string> alertRadarSite_ {"alert_radar_site"};
SettingsVariable<double> alertRadius_ {"alert_radius"};
SettingsVariable<std::string> alertCounty_ {"alert_county"};
SettingsVariable<bool> ignoreMissingCodecs_ {"ignore_missing_codecs"};
@ -101,6 +108,8 @@ AudioSettings::AudioSettings() :
&p->alertLocationMethod_,
&p->alertLatitude_,
&p->alertLongitude_,
&p->alertRadarSite_,
&p->alertRadius_,
&p->alertCounty_,
&p->ignoreMissingCodecs_});
RegisterVariables(p->variables_);
@ -133,6 +142,16 @@ SettingsVariable<double>& AudioSettings::alert_longitude() const
return p->alertLongitude_;
}
SettingsVariable<std::string>& AudioSettings::alert_radar_site() const
{
return p->alertRadarSite_;
}
SettingsVariable<double>& AudioSettings::alert_radius() const
{
return p->alertRadius_;
}
SettingsVariable<std::string>& AudioSettings::alert_county() const
{
return p->alertCounty_;
@ -166,6 +185,8 @@ bool operator==(const AudioSettings& lhs, const AudioSettings& rhs)
lhs.p->alertLocationMethod_ == rhs.p->alertLocationMethod_ &&
lhs.p->alertLatitude_ == rhs.p->alertLatitude_ &&
lhs.p->alertLongitude_ == rhs.p->alertLongitude_ &&
lhs.p->alertRadarSite_ == rhs.p->alertRadarSite_ &&
lhs.p->alertRadius_ == rhs.p->alertRadius_ &&
lhs.p->alertCounty_ == rhs.p->alertCounty_ &&
lhs.p->alertEnabled_ == rhs.p->alertEnabled_);
}

View file

@ -30,6 +30,8 @@ public:
SettingsVariable<std::string>& alert_location_method() const;
SettingsVariable<double>& alert_latitude() const;
SettingsVariable<double>& alert_longitude() const;
SettingsVariable<double>& alert_radius() const;
SettingsVariable<std::string>& alert_radar_site() const;
SettingsVariable<std::string>& alert_county() const;
SettingsVariable<bool>& alert_enabled(awips::Phenomenon phenomenon) const;
SettingsVariable<bool>& ignore_missing_codecs() const;

View file

@ -40,6 +40,7 @@ public:
void UpdateEditWidget();
void UpdateResetButton();
void UpdateUnitLabel();
SettingsInterface<T>* self_;
@ -49,9 +50,14 @@ public:
std::unique_ptr<QObject> context_ {std::make_unique<QObject>()};
QWidget* editWidget_ {nullptr};
QAbstractButton* resetButton_ {nullptr};
QLabel* unitLabel_ {nullptr};
std::function<std::string(const T&)> mapFromValue_ {nullptr};
std::function<T(const std::string&)> mapToValue_ {nullptr};
double unitScale_ {1};
std::optional<std::string> unitAbbreviation_ {};
bool unitEnabled_ {false};
};
template<class T>
@ -381,6 +387,11 @@ void SettingsInterface<T>::SetEditWidget(QWidget* widget)
p->context_.get(),
[this](double d)
{
if (p->unitEnabled_)
{
d = d / p->unitScale_;
}
const T value = p->variable_->GetValue();
const std::optional<T> staged = p->variable_->GetStaged();
@ -448,6 +459,11 @@ void SettingsInterface<T>::SetResetButton(QAbstractButton* button)
p->UpdateResetButton();
}
}
template<class T>
void SettingsInterface<T>::SetUnitLabel(QLabel* label)
{
p->unitLabel_ = label;
}
template<class T>
void SettingsInterface<T>::SetMapFromValueFunction(
@ -463,6 +479,17 @@ void SettingsInterface<T>::SetMapToValueFunction(
p->mapToValue_ = function;
}
template<class T>
void SettingsInterface<T>::SetUnit(const double& scale,
const std::string& abbreviation)
{
p->unitScale_ = scale;
p->unitAbbreviation_ = abbreviation;
p->unitEnabled_ = true;
p->UpdateEditWidget();
p->UpdateUnitLabel();
}
template<class T>
template<class U>
void SettingsInterface<T>::Impl::SetWidgetText(U* widget, const T& currentValue)
@ -559,11 +586,27 @@ void SettingsInterface<T>::Impl::UpdateEditWidget()
{
if constexpr (std::is_floating_point_v<T>)
{
doubleSpinBox->setValue(static_cast<double>(currentValue));
double doubleValue = static_cast<double>(currentValue);
if (unitEnabled_)
{
doubleValue = doubleValue * unitScale_;
}
doubleSpinBox->setValue(doubleValue);
}
}
}
template<class T>
void SettingsInterface<T>::Impl::UpdateUnitLabel()
{
if (unitLabel_ == nullptr || !unitEnabled_)
{
return;
}
unitLabel_->setText(QString::fromStdString(unitAbbreviation_.value_or("")));
}
template<class T>
void SettingsInterface<T>::Impl::UpdateResetButton()
{

View file

@ -7,6 +7,8 @@
#include <string>
#include <vector>
class QLabel;
namespace scwx
{
namespace qt
@ -91,6 +93,13 @@ public:
*/
void SetResetButton(QAbstractButton* button) override;
/**
* Sets the label for units from the settings dialog.
*
* @param label Unit label
*/
void SetUnitLabel(QLabel* label);
/**
* If the edit widget displays a different value than what is stored in the
* settings variable, a mapping function must be provided in order to convert
@ -109,6 +118,14 @@ public:
*/
void SetMapToValueFunction(std::function<T(const std::string&)> function);
/**
* Sets the unit to be used by this setting.
*
* @param scale The radio of the current unit to the base unit
* @param abbreviation The abreviation to be displayed
*/
void SetUnit(const double& scale, const std::string& abbreviation);
private:
class Impl;
std::unique_ptr<Impl> p;

View file

@ -26,16 +26,20 @@ public:
types::GetOtherUnitsName(types::OtherUnits::Default);
std::string defaultSpeedUnitsValue =
types::GetSpeedUnitsName(types::SpeedUnits::Knots);
std::string defaultDistanceUnitsValue =
types::GetDistanceUnitsName(types::DistanceUnits::Miles);
boost::to_lower(defaultAccumulationUnitsValue);
boost::to_lower(defaultEchoTopsUnitsValue);
boost::to_lower(defaultOtherUnitsValue);
boost::to_lower(defaultSpeedUnitsValue);
boost::to_lower(defaultDistanceUnitsValue);
accumulationUnits_.SetDefault(defaultAccumulationUnitsValue);
echoTopsUnits_.SetDefault(defaultEchoTopsUnitsValue);
otherUnits_.SetDefault(defaultOtherUnitsValue);
speedUnits_.SetDefault(defaultSpeedUnitsValue);
distanceUnits_.SetDefault(defaultDistanceUnitsValue);
accumulationUnits_.SetValidator(
SCWX_SETTINGS_ENUM_VALIDATOR(types::AccumulationUnits,
@ -53,6 +57,10 @@ public:
SCWX_SETTINGS_ENUM_VALIDATOR(types::SpeedUnits,
types::SpeedUnitsIterator(),
types::GetSpeedUnitsName));
distanceUnits_.SetValidator(
SCWX_SETTINGS_ENUM_VALIDATOR(types::DistanceUnits,
types::DistanceUnitsIterator(),
types::GetDistanceUnitsName));
}
~Impl() {}
@ -61,6 +69,7 @@ public:
SettingsVariable<std::string> echoTopsUnits_ {"echo_tops_units"};
SettingsVariable<std::string> otherUnits_ {"other_units"};
SettingsVariable<std::string> speedUnits_ {"speed_units"};
SettingsVariable<std::string> distanceUnits_ {"distance_units"};
};
UnitSettings::UnitSettings() :
@ -69,7 +78,8 @@ UnitSettings::UnitSettings() :
RegisterVariables({&p->accumulationUnits_,
&p->echoTopsUnits_,
&p->otherUnits_,
&p->speedUnits_});
&p->speedUnits_,
&p->distanceUnits_});
SetDefaults();
}
UnitSettings::~UnitSettings() = default;
@ -97,6 +107,11 @@ SettingsVariable<std::string>& UnitSettings::speed_units() const
return p->speedUnits_;
}
SettingsVariable<std::string>& UnitSettings::distance_units() const
{
return p->distanceUnits_;
}
UnitSettings& UnitSettings::Instance()
{
static UnitSettings generalSettings_;
@ -108,7 +123,8 @@ bool operator==(const UnitSettings& lhs, const UnitSettings& rhs)
return (lhs.p->accumulationUnits_ == rhs.p->accumulationUnits_ &&
lhs.p->echoTopsUnits_ == rhs.p->echoTopsUnits_ &&
lhs.p->otherUnits_ == rhs.p->otherUnits_ &&
lhs.p->speedUnits_ == rhs.p->speedUnits_);
lhs.p->speedUnits_ == rhs.p->speedUnits_ &&
lhs.p->distanceUnits_ == rhs.p->distanceUnits_);
}
} // namespace settings

View file

@ -29,6 +29,7 @@ public:
SettingsVariable<std::string>& echo_tops_units() const;
SettingsVariable<std::string>& other_units() const;
SettingsVariable<std::string>& speed_units() const;
SettingsVariable<std::string>& distance_units() const;
static UnitSettings& Instance();

View file

@ -15,6 +15,7 @@ namespace types
static const std::unordered_map<LocationMethod, std::string>
locationMethodName_ {{LocationMethod::Fixed, "Fixed"},
{LocationMethod::Track, "Track"},
{LocationMethod::RadarSite, "Radar Site"},
{LocationMethod::County, "County"},
{LocationMethod::All, "All"},
{LocationMethod::Unknown, "?"}};

View file

@ -15,6 +15,7 @@ enum class LocationMethod
{
Fixed,
Track,
RadarSite,
County,
All,
Unknown

View file

@ -89,12 +89,35 @@ static const std::unordered_map<SpeedUnits, float> speedUnitsScale_ {
{SpeedUnits::User, 1.0f},
{SpeedUnits::Unknown, 1.0f}};
static const std::unordered_map<DistanceUnits, std::string>
distanceUnitsAbbreviation_ {{DistanceUnits::Kilometers, "km"},
{DistanceUnits::Miles, "mi"},
{DistanceUnits::User, ""},
{DistanceUnits::Unknown, ""}};
static const std::unordered_map<DistanceUnits, std::string> distanceUnitsName_ {
{DistanceUnits::Kilometers, "Kilometers"},
{DistanceUnits::Miles, "Miles"},
{DistanceUnits::User, "User-defined"},
{DistanceUnits::Unknown, "?"}};
static constexpr auto distanceUnitsBase_ = units::kilometers<double> {1.0f};
static const std::unordered_map<DistanceUnits, double> distanceUnitsScale_ {
{DistanceUnits::Kilometers,
(distanceUnitsBase_ / units::kilometers<double> {1.0f})},
{DistanceUnits::Miles,
(distanceUnitsBase_ / units::miles<double> {1.0f})},
{DistanceUnits::User, 1.0f},
{DistanceUnits::Unknown, 1.0f}};
SCWX_GET_ENUM(AccumulationUnits,
GetAccumulationUnitsFromName,
accumulationUnitsName_)
SCWX_GET_ENUM(EchoTopsUnits, GetEchoTopsUnitsFromName, echoTopsUnitsName_)
SCWX_GET_ENUM(OtherUnits, GetOtherUnitsFromName, otherUnitsName_)
SCWX_GET_ENUM(SpeedUnits, GetSpeedUnitsFromName, speedUnitsName_)
SCWX_GET_ENUM(DistanceUnits, GetDistanceUnitsFromName, distanceUnitsName_)
const std::string& GetAccumulationUnitsAbbreviation(AccumulationUnits units)
{
@ -146,6 +169,21 @@ float GetSpeedUnitsScale(SpeedUnits units)
return speedUnitsScale_.at(units);
}
const std::string& GetDistanceUnitsAbbreviation(DistanceUnits units)
{
return distanceUnitsAbbreviation_.at(units);
}
const std::string& GetDistanceUnitsName(DistanceUnits units)
{
return distanceUnitsName_.at(units);
}
double GetDistanceUnitsScale(DistanceUnits units)
{
return distanceUnitsScale_.at(units);
}
} // namespace types
} // namespace qt
} // namespace scwx

View file

@ -56,6 +56,17 @@ typedef scwx::util::
Iterator<SpeedUnits, SpeedUnits::KilometersPerHour, SpeedUnits::User>
SpeedUnitsIterator;
enum class DistanceUnits
{
Kilometers,
Miles,
User,
Unknown
};
typedef scwx::util::
Iterator<DistanceUnits, DistanceUnits::Kilometers, DistanceUnits::User>
DistanceUnitsIterator;
const std::string& GetAccumulationUnitsAbbreviation(AccumulationUnits units);
const std::string& GetAccumulationUnitsName(AccumulationUnits units);
AccumulationUnits GetAccumulationUnitsFromName(const std::string& name);
@ -74,6 +85,11 @@ const std::string& GetSpeedUnitsName(SpeedUnits units);
SpeedUnits GetSpeedUnitsFromName(const std::string& name);
float GetSpeedUnitsScale(SpeedUnits units);
const std::string& GetDistanceUnitsAbbreviation(DistanceUnits units);
const std::string& GetDistanceUnitsName(DistanceUnits units);
DistanceUnits GetDistanceUnitsFromName(const std::string& name);
double GetDistanceUnitsScale(DistanceUnits units);
} // namespace types
} // namespace qt
} // namespace scwx

View file

@ -102,6 +102,16 @@ public:
types::GetSpeedUnitsName);
AddRow(speedUnits_, "Speed", speedComboBox);
QComboBox* distanceComboBox = new QComboBox(self);
distanceComboBox->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Preferred);
distanceUnits_.SetSettingsVariable(unitSettings.distance_units());
SCWX_SETTINGS_COMBO_BOX(distanceUnits_,
distanceComboBox,
types::DistanceUnitsIterator(),
types::GetDistanceUnitsName);
AddRow(distanceUnits_, "Distance", distanceComboBox);
QComboBox* otherComboBox = new QComboBox(self);
otherComboBox->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Preferred);
@ -127,6 +137,7 @@ public:
settings::SettingsInterface<std::string> echoTopsUnits_ {};
settings::SettingsInterface<std::string> otherUnits_ {};
settings::SettingsInterface<std::string> speedUnits_ {};
settings::SettingsInterface<std::string> distanceUnits_ {};
};
UnitSettingsWidget::UnitSettingsWidget(QWidget* parent) :

View file

@ -14,12 +14,14 @@
#include <scwx/qt/settings/palette_settings.hpp>
#include <scwx/qt/settings/settings_interface.hpp>
#include <scwx/qt/settings/text_settings.hpp>
#include <scwx/qt/settings/unit_settings.hpp>
#include <scwx/qt/types/alert_types.hpp>
#include <scwx/qt/types/font_types.hpp>
#include <scwx/qt/types/location_types.hpp>
#include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/types/text_types.hpp>
#include <scwx/qt/types/time_types.hpp>
#include <scwx/qt/types/unit_types.hpp>
#include <scwx/qt/ui/county_dialog.hpp>
#include <scwx/qt/ui/radar_site_dialog.hpp>
#include <scwx/qt/ui/serial_port_dialog.hpp>
@ -103,6 +105,7 @@ public:
explicit SettingsDialogImpl(SettingsDialog* self) :
self_ {self},
radarSiteDialog_ {new RadarSiteDialog(self)},
alertAudioRadarSiteDialog_ {new RadarSiteDialog(self)},
gpsSourceDialog_ {new SerialPortDialog(self)},
countyDialog_ {new CountyDialog(self)},
fontDialog_ {new QFontDialog(self)},
@ -134,6 +137,8 @@ public:
&alertAudioLocationMethod_,
&alertAudioLatitude_,
&alertAudioLongitude_,
&alertAudioRadarSite_,
&alertAudioRadius_,
&alertAudioCounty_,
&hoverTextWrap_,
&tooltipMethod_,
@ -175,6 +180,7 @@ public:
void ShowColorDialog(QLineEdit* lineEdit, QFrame* frame = nullptr);
void UpdateRadarDialogLocation(const std::string& id);
void UpdateAlertRadarDialogLocation(const std::string& id);
QFont GetSelectedFont();
void SelectFontCategory(types::FontCategory fontCategory);
@ -199,6 +205,7 @@ public:
SettingsDialog* self_;
RadarSiteDialog* radarSiteDialog_;
RadarSiteDialog* alertAudioRadarSiteDialog_;
SerialPortDialog* gpsSourceDialog_;
CountyDialog* countyDialog_;
QFontDialog* fontDialog_;
@ -252,6 +259,8 @@ public:
settings::SettingsInterface<std::string> alertAudioLocationMethod_ {};
settings::SettingsInterface<double> alertAudioLatitude_ {};
settings::SettingsInterface<double> alertAudioLongitude_ {};
settings::SettingsInterface<std::string> alertAudioRadarSite_ {};
settings::SettingsInterface<double> alertAudioRadius_ {};
settings::SettingsInterface<std::string> alertAudioCounty_ {};
std::unordered_map<awips::Phenomenon, settings::SettingsInterface<bool>>
@ -339,6 +348,30 @@ void SettingsDialogImpl::ConnectSignals()
}
});
QObject::connect(self_->ui->alertAudioRadarSiteSelectButton,
&QAbstractButton::clicked,
self_,
[this]() { alertAudioRadarSiteDialog_->show(); });
QObject::connect(alertAudioRadarSiteDialog_,
&RadarSiteDialog::accepted,
self_,
[this]()
{
std::string id =
alertAudioRadarSiteDialog_->radar_site();
std::shared_ptr<config::RadarSite> radarSite =
config::RadarSite::Get(id);
if (radarSite != nullptr)
{
self_->ui->alertAudioRadarSiteComboBox
->setCurrentText(QString::fromStdString(
RadarSiteLabel(radarSite)));
}
});
QObject::connect(self_->ui->gpsSourceSelectButton,
&QAbstractButton::clicked,
self_,
@ -504,11 +537,18 @@ void SettingsDialogImpl::SetupGeneralTab()
const std::shared_ptr<config::RadarSite>& b)
{ return a->id() < b->id(); });
// Add default and follow options to radar sites
self_->ui->alertAudioRadarSiteComboBox->addItem(
QString::fromStdString("default"));
self_->ui->alertAudioRadarSiteComboBox->addItem(
QString::fromStdString("follow"));
// Add sorted radar sites
for (std::shared_ptr<config::RadarSite>& radarSite : radarSites)
{
QString text = QString::fromStdString(RadarSiteLabel(radarSite));
self_->ui->radarSiteComboBox->addItem(text);
self_->ui->alertAudioRadarSiteComboBox->addItem(text);
}
defaultRadarSite_.SetSettingsVariable(generalSettings.default_radar_site());
@ -900,6 +940,12 @@ void SettingsDialogImpl::SetupAudioTab()
bool coordinateEntryEnabled =
locationMethod == types::LocationMethod::Fixed;
bool radarSiteEntryEnable =
locationMethod == types::LocationMethod::RadarSite;
bool radiusEntryEnable =
locationMethod == types::LocationMethod::Fixed ||
locationMethod == types::LocationMethod::Track ||
locationMethod == types::LocationMethod::RadarSite;
bool countyEntryEnabled =
locationMethod == types::LocationMethod::County;
@ -912,6 +958,18 @@ void SettingsDialogImpl::SetupAudioTab()
self_->ui->resetAlertAudioLongitudeButton->setEnabled(
coordinateEntryEnabled);
self_->ui->alertAudioRadarSiteComboBox->setEnabled(
radarSiteEntryEnable);
self_->ui->alertAudioRadarSiteSelectButton->setEnabled(
radarSiteEntryEnable);
self_->ui->resetAlertAudioRadarSiteButton->setEnabled(
radarSiteEntryEnable);
self_->ui->alertAudioRadiusSpinBox->setEnabled(
radiusEntryEnable);
self_->ui->resetAlertAudioRadiusButton->setEnabled(
radiusEntryEnable);
self_->ui->alertAudioCountyLineEdit->setEnabled(countyEntryEnabled);
self_->ui->alertAudioCountySelectButton->setEnabled(
countyEntryEnabled);
@ -983,6 +1041,64 @@ void SettingsDialogImpl::SetupAudioTab()
alertAudioLongitude_.SetResetButton(
self_->ui->resetAlertAudioLongitudeButton);
alertAudioRadarSite_.SetSettingsVariable(audioSettings.alert_radar_site());
alertAudioRadarSite_.SetMapFromValueFunction(
[](const std::string& id) -> std::string
{
// Get the radar site associated with the ID
std::shared_ptr<config::RadarSite> radarSite =
config::RadarSite::Get(id);
if (radarSite == nullptr)
{
// No radar site found, just return the ID
return id;
}
// Add location details to the radar site
return RadarSiteLabel(radarSite);
});
alertAudioRadarSite_.SetMapToValueFunction(
[](const std::string& text) -> std::string
{
// Find the position of location details
size_t pos = text.rfind(" (");
if (pos == std::string::npos)
{
// No location details found, just return the text
return text;
}
// Remove location details from the radar site
return text.substr(0, pos);
});
alertAudioRadarSite_.SetEditWidget(self_->ui->alertAudioRadarSiteComboBox);
alertAudioRadarSite_.SetResetButton(
self_->ui->resetAlertAudioRadarSiteButton);
UpdateAlertRadarDialogLocation(audioSettings.alert_radar_site().GetValue());
alertAudioRadius_.SetSettingsVariable(audioSettings.alert_radius());
alertAudioRadius_.SetEditWidget(self_->ui->alertAudioRadiusSpinBox);
alertAudioRadius_.SetResetButton(
self_->ui->resetAlertAudioRadiusButton);
alertAudioRadius_.SetUnitLabel(self_->ui->alertAudioRadiusUnitsLabel);
auto alertAudioRadiusUpdateUnits = [this](const std::string& newValue)
{
types::DistanceUnits radiusUnits =
types::GetDistanceUnitsFromName(newValue);
double radiusScale = types::GetDistanceUnitsScale(radiusUnits);
std::string abbreviation =
types::GetDistanceUnitsAbbreviation(radiusUnits);
alertAudioRadius_.SetUnit(radiusScale, abbreviation);
};
settings::UnitSettings::Instance()
.distance_units()
.RegisterValueStagedCallback(alertAudioRadiusUpdateUnits);
alertAudioRadiusUpdateUnits(
settings::UnitSettings::Instance().distance_units().GetValue());
auto& alertAudioPhenomena = types::GetAlertAudioPhenomena();
auto alertAudioLayout =
static_cast<QGridLayout*>(self_->ui->alertAudioGroupBox->layout());
@ -1268,6 +1384,19 @@ void SettingsDialogImpl::UpdateRadarDialogLocation(const std::string& id)
}
}
void SettingsDialogImpl::UpdateAlertRadarDialogLocation(const std::string& id)
{
std::shared_ptr<config::RadarSite> radarSite = config::RadarSite::Get(id);
if (radarSite != nullptr)
{
alertAudioRadarSiteDialog_->HandleMapUpdate(radarSite->latitude(),
radarSite->longitude());
}
}
QFont SettingsDialogImpl::GetSelectedFont()
{
std::string fontFamily = fontFamilies_.at(selectedFontCategory_)

View file

@ -122,7 +122,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
<number>3</number>
</property>
<widget class="QWidget" name="general">
<layout class="QVBoxLayout" name="verticalLayout_2">
@ -135,9 +135,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-113</y>
<y>0</y>
<width>511</width>
<height>669</height>
<height>647</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -610,8 +610,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>66</width>
<height>18</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
@ -691,45 +691,6 @@
<string>Alerts</string>
</property>
<layout class="QGridLayout" name="gridLayout_10">
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Latitude</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QToolButton" name="resetAlertAudioLocationMethodButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="alertAudioSoundSelectButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Location Method</string>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QToolButton" name="resetAlertAudioLongitudeButton">
<property name="text">
@ -741,11 +702,19 @@
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QToolButton" name="alertAudioSoundStopButton">
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/stop-solid.svg</normaloff>:/res/icons/font-awesome-6/stop-solid.svg</iconset>
<item row="5" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="alertAudioRadiusSpinBox">
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>9999999999999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
@ -760,6 +729,23 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="alertAudioLocationMethodComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>County</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QToolButton" name="resetAlertAudioSoundButton">
<property name="text">
@ -771,25 +757,10 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QToolButton" name="alertAudioSoundTestButton">
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/play-solid.svg</normaloff>:/res/icons/font-awesome-6/play-solid.svg</iconset>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<item row="5" column="3">
<widget class="QLabel" name="alertAudioRadiusUnitsLabel">
<property name="text">
<string>Sound</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>County</string>
<string/>
</property>
</widget>
</item>
@ -809,6 +780,34 @@
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QToolButton" name="resetAlertAudioLocationMethodButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="alertAudioSoundSelectButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QToolButton" name="alertAudioCountySelectButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="alertAudioSoundLineEdit"/>
</item>
<item row="2" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="alertAudioLatitudeSpinBox">
<property name="decimals">
@ -825,21 +824,16 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="alertAudioLocationMethodComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="0" column="5">
<widget class="QToolButton" name="alertAudioSoundStopButton">
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/stop-solid.svg</normaloff>:/res/icons/font-awesome-6/stop-solid.svg</iconset>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="alertAudioSoundLineEdit"/>
</item>
<item row="4" column="6">
<widget class="QToolButton" name="resetAlertAudioCountyButton">
<item row="5" column="6">
<widget class="QToolButton" name="resetAlertAudioRadiusButton">
<property name="text">
<string>...</string>
</property>
@ -849,14 +843,21 @@
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QToolButton" name="alertAudioCountySelectButton">
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>...</string>
<string>Latitude</string>
</property>
</widget>
</item>
<item row="4" column="2">
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Sound</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="alertAudioCountyLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
@ -869,7 +870,15 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="0" column="4">
<widget class="QToolButton" name="alertAudioSoundTestButton">
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/play-solid.svg</normaloff>:/res/icons/font-awesome-6/play-solid.svg</iconset>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="alertAudioCountyLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -882,6 +891,66 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Location Method</string>
</property>
</widget>
</item>
<item row="7" column="6">
<widget class="QToolButton" name="resetAlertAudioCountyButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="alertAudioRadiusLabel">
<property name="text">
<string>Radius</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>Radar Site</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QToolButton" name="alertAudioRadarSiteSelectButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QToolButton" name="resetAlertAudioRadarSiteButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="alertAudioRadarSiteComboBox"/>
</item>
</layout>
</widget>
</item>

View file

@ -5,7 +5,9 @@
#include <GeographicLib/Gnomonic.hpp>
#include <geos/algorithm/PointLocation.h>
#include <geos/operation/distance/DistanceOp.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/GeometryFactory.h>
namespace scwx
{
@ -28,6 +30,40 @@ const ::GeographicLib::Geodesic& DefaultGeodesic()
return geodesic_;
}
bool GnomonicAreaContainsCenter(geos::geom::CoordinateSequence sequence)
{
// Cannot have an area with just two points
if (sequence.size() <= 2 ||
(sequence.size() == 3 && sequence.front() == sequence.back()))
{
return false;
}
bool areaContainsPoint = false;
geos::geom::CoordinateXY zero {};
// If the sequence is not a ring, add the first point again for closure
if (!sequence.isRing())
{
sequence.add(sequence.front(), false);
}
// The sequence should be a ring at this point, but make sure
if (sequence.isRing())
{
try
{
areaContainsPoint =
geos::algorithm::PointLocation::isInRing(zero, &sequence);
}
catch (const std::exception& ex)
{
logger_->warn("Invalid area sequence. {}", ex.what());
}
}
return areaContainsPoint;
}
bool AreaContainsPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point)
{
@ -82,6 +118,12 @@ bool AreaContainsPoint(const std::vector<common::Coordinate>& area,
return areaContainsPoint;
}
units::angle::degrees<double>
GetAngle(double lat1, double lon1, double lat2, double lon2)
{
@ -137,6 +179,116 @@ GetDistance(double lat1, double lon1, double lat2, double lon2)
return units::length::meters<double> {distance};
}
/*
* Uses the gnomonic projection to determine if the area is in the radius.
*
* The basic algorithm is as follows:
* - Get a gnomonic projection centered on the point of the area
* - Find the point on the area which is closest to the center
* - Convert the closest point back to latitude and longitude.
* - Find the distance form the closest point to the point.
*
* The first property needed to make this work is that great circles become
* lines in the projection, which allows the area to be converted to strait
* lines. This is generally true for gnomic projections.
*
* The second property needed to make this work is that a point further away
* on the geodesic must be further away on the projection. This means that
* the closes point on the projection is also the closest point on the geodesic.
* This holds for spherical geodesics and is an approximation non spherical
* geodesics.
*
* This algorithm only works if the area is fully on the hemisphere centered
* on the point. Otherwise, this falls back to centroid based distances.
*
* If the point is inside the area, 0 is always returned.
*/
units::length::meters<double>
GetDistanceAreaPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point)
{
// Ensure that the same geodesic is used here as is for the distance
// calculation
::GeographicLib::Gnomonic gnomonic =
::GeographicLib::Gnomonic(DefaultGeodesic());
geos::geom::CoordinateSequence sequence {};
double x;
double y;
bool useCentroid = false;
// Using a gnomonic projection with the test point as the center
// latitude/longitude, the projected test point will be at (0, 0)
geos::geom::CoordinateXY zero {};
// Create the area coordinate sequence using a gnomonic projection
for (auto& areaCoordinate : area)
{
gnomonic.Forward(point.latitude_,
point.longitude_,
areaCoordinate.latitude_,
areaCoordinate.longitude_,
x,
y);
// Check if the current point is in the hemisphere centered on the point
// if not, fall back to using centroid.
if (std::isnan(x) || std::isnan(y))
{
useCentroid = true;
}
sequence.add(x, y);
}
units::length::meters<double> distance;
if (useCentroid)
{
common::Coordinate centroid = common::GetCentroid(area);
distance = GetDistance(point.latitude_,
point.longitude_,
centroid.latitude_,
centroid.longitude_);
}
else if (GnomonicAreaContainsCenter(sequence))
{
distance = units::length::meters<double>(0);
}
else
{
// Get the closes point on the geometry
auto geometryFactory = geos::geom::GeometryFactory::getDefaultInstance();
auto lineString = geometryFactory->createLineString(sequence);
auto zeroPoint = geometryFactory->createPoint(zero);
std::unique_ptr<geos::geom::CoordinateSequence> closestPoints =
geos::operation::distance::DistanceOp::nearestPoints(lineString.get(),
zeroPoint.get());
double closestLat;
double closestLon;
gnomonic.Reverse(point.latitude_,
point.longitude_,
closestPoints->getX(0),
closestPoints->getY(0),
closestLat,
closestLon);
distance = GetDistance(point.latitude_,
point.longitude_,
closestLat,
closestLon);
}
return distance;
}
bool AreaInRangeOfPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point,
const units::length::meters<double> distance)
{
return GetDistanceAreaPoint(area, point) <= distance;
}
} // namespace GeographicLib
} // namespace util
} // namespace qt

View file

@ -90,6 +90,37 @@ common::Coordinate GetCoordinate(const common::Coordinate& center,
units::length::meters<double>
GetDistance(double lat1, double lon1, double lat2, double lon2);
/**
* Get the distance from an area to a point. If the area is less than a quarter
* radius of the Earth away, this is the closest distance between the area and
* the point. Otherwise it is the distance from the centroid of the area to the
* point. Finally, if the point is in the area, it is always 0.
*
* @param [in] area A vector of Coordinates representing the area
* @param [in] point The point to check against the area
*
* @return true if area is inside the radius of the point
*/
units::length::meters<double>
GetDistanceAreaPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point);
/**
* Determine if an area/ring, oriented in either direction, is within a
* distance of a point. A point lying on the area boundary is considered to be
* inside the area, and thus always in range. Any part of the area being inside
* the radius counts as inside. Uses GetDistanceAreaPoint to get the distance.
*
* @param [in] area A vector of Coordinates representing the area
* @param [in] point The point to check against the area
* @param [in] distance The max distance in meters
*
* @return true if area is inside the radius of the point
*/
bool AreaInRangeOfPoint(const std::vector<common::Coordinate>& area,
const common::Coordinate& point,
const units::length::meters<double> distance);
} // namespace GeographicLib
} // namespace util
} // namespace qt

@ -1 +1 @@
Subproject commit 0ea32947d6a6e39a69d931b2827056e7bc58cbba
Subproject commit 5115993596cfe6528b7a07c0b16dbd1ae16ce4df

View file

@ -0,0 +1,69 @@
#include <scwx/qt/util/geographic_lib.hpp>
#include <gtest/gtest.h>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
namespace scwx
{
namespace util
{
std::vector<common::Coordinate> area = {
common::Coordinate(37.0193692, -91.8778413),
common::Coordinate(36.9719180, -91.3006973),
common::Coordinate(36.7270831, -91.6815753),
};
TEST(geographic_lib, area_in_range_inside)
{
auto inside = common::Coordinate(36.9241584, -91.6425933);
bool value;
// inside is always true
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, inside, units::length::meters<double>(0));
EXPECT_EQ(value, true);
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, inside, units::length::meters<double>(1e6));
EXPECT_EQ(value, true);
}
TEST(geographic_lib, area_in_range_near)
{
auto near = common::Coordinate(36.8009181, -91.3922700);
bool value;
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, near, units::length::meters<double>(9000));
EXPECT_EQ(value, false);
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, near, units::length::meters<double>(10100));
EXPECT_EQ(value, true);
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, near, units::length::meters<double>(1e6));
EXPECT_EQ(value, true);
}
TEST(geographic_lib, area_in_range_far)
{
auto far = common::Coordinate(37.6481966, -94.2163834);
bool value;
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, far, units::length::meters<double>(9000));
EXPECT_EQ(value, false);
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, far, units::length::meters<double>(10100));
EXPECT_EQ(value, false);
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, far, units::length::meters<double>(100e3));
EXPECT_EQ(value, false);
value = scwx::qt::util::GeographicLib::AreaInRangeOfPoint(
area, far, units::length::meters<double>(300e3));
EXPECT_EQ(value, true);
}
} // namespace util
} // namespace scwx

View file

@ -28,7 +28,8 @@ set(SRC_QT_MAP_TESTS source/scwx/qt/map/map_provider.test.cpp)
set(SRC_QT_MODEL_TESTS source/scwx/qt/model/imgui_context_model.test.cpp)
set(SRC_QT_SETTINGS_TESTS source/scwx/qt/settings/settings_container.test.cpp
source/scwx/qt/settings/settings_variable.test.cpp)
set(SRC_QT_UTIL_TESTS source/scwx/qt/util/q_file_input_stream.test.cpp)
set(SRC_QT_UTIL_TESTS source/scwx/qt/util/q_file_input_stream.test.cpp
source/scwx/qt/util/geographic_lib.test.cpp)
set(SRC_UTIL_TESTS source/scwx/util/float.test.cpp
source/scwx/util/rangebuf.test.cpp
source/scwx/util/streams.test.cpp