add a menu to force set runways

This commit is contained in:
Sven Czarnian
2021-12-19 12:23:23 +01:00
parent c14698bc39
commit c3a75bb900
2 changed files with 123 additions and 24 deletions

View File

@@ -13,6 +13,7 @@
#include <algorithm>
#include <cctype>
#include <regex>
#include <gsl/gsl>
#include <Shlwapi.h>
@@ -71,6 +72,7 @@ PlugIn::PlugIn() :
this->RegisterTagItemType("Delta time", static_cast<int>(PlugIn::TagItemElement::DeltaTime));
this->RegisterTagItemType("Fixed plan indicator", static_cast<int>(PlugIn::TagItemElement::FixedPlanIndicator));
this->RegisterTagItemFunction("Force planning", static_cast<int>(PlugIn::TagItemFunction::ForceToBackendMenu));
this->RegisterTagItemFunction("Runway selection", static_cast<int>(PlugIn::TagItemFunction::RunwaySelectMenu));
this->DisplayUserMessage(PLUGIN_NAME, "INFO", (std::string("Loaded ") + PLUGIN_NAME + " " + PLUGIN_VERSION).c_str(), true, true, false, false, false);
@@ -207,6 +209,8 @@ EuroScopePlugIn::CRadarScreen* PlugIn::OnRadarScreenCreated(const char* displayN
if (nullptr == this->m_screen)
this->m_screen = std::make_shared<RadarScreen>();
this->OnAirportRunwayActivityChanged();
return this->m_screen.get();
}
@@ -454,6 +458,10 @@ void PlugIn::generateAircraftReportMessage(EuroScopePlugIn::CRadarTarget& radarT
report->set_allocated_dynamics(dynamics);
report->set_allocated_position(coordinate);
auto selectedRwyIt = this->m_selectedRunway.find(radarTarget.GetCallsign());
if (this->m_selectedRunway.cend() != selectedRwyIt)
report->set_requestedrunway(selectedRwyIt->second);
/* set the report time */
std::stringstream stream;
const auto reportTime = std::chrono::utc_clock::now();
@@ -476,8 +484,6 @@ bool PlugIn::OnCompileCommand(const char* cmdline) {
if (std::string::npos != message.find("RELOAD")) {
this->validateBackendData();
this->m_sweatboxValid = false;
this->m_playbackValid = false;
retval = true;
}
else if (std::string::npos != message.find("SWEATBOX")) {
@@ -603,9 +609,9 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE
this->OpenPopupList(area, "AMAN", 1);
bool inList = this->m_forcedToBackendCallsigns.cend() != std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), callsign);
this->AddPopupListElement("Add to AMAN", "", static_cast<int>(PlugIn::TagItemFunction::ForceToBackendSelect),
false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, true == inList);
false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, true == inList);
this->AddPopupListElement("Remove from AMAN", "", static_cast<int>(PlugIn::TagItemFunction::ForceToBackendSelect),
false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList);
false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList);
break;
}
case PlugIn::TagItemFunction::ForceToBackendSelect:
@@ -633,6 +639,45 @@ void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RE
break;
}
case PlugIn::TagItemFunction::RunwaySelectMenu:
{
std::string destination(radarTarget.GetCorrelatedFlightPlan().GetFlightPlanData().GetDestination());
std::transform(destination.begin(), destination.end(), destination.begin(), ::toupper);
std::lock_guard guard(this->m_updateQueueLock);
auto it = this->m_updateQueue.find(destination);
if (this->m_updateQueue.cend() != it) {
this->OpenPopupList(area, "Select runway", 1);
bool inList = this->m_selectedRunway.find(callsign) != this->m_selectedRunway.cend();
this->AddPopupListElement("Remove", "", static_cast<int>(PlugIn::TagItemFunction::RunwaySelect),
false, EuroScopePlugIn::POPUP_ELEMENT_NO_CHECKBOX, false == inList);
for (const auto& rwy : std::as_const(it->second.arrivalRunways))
this->AddPopupListElement(rwy.c_str(), "", static_cast<int>(PlugIn::TagItemFunction::RunwaySelect));
}
break;
}
case PlugIn::TagItemFunction::RunwaySelect:
{
std::lock_guard guard(this->m_updateQueueLock);
if (0 == std::strcmp(itemString, "Remove")) {
auto it = this->m_selectedRunway.find(callsign);
if (this->m_selectedRunway.end() != it)
this->m_selectedRunway.erase(it);
}
else {
auto it = this->m_selectedRunway.find(callsign);
if (this->m_selectedRunway.end() != it)
it->second = itemString;
else
this->m_selectedRunway.insert({ callsign, itemString });
}
break;
}
default:
break;
}
@@ -651,8 +696,17 @@ void PlugIn::addUpdateQueue(EuroScopePlugIn::CRadarTarget& radarTarget) {
#pragma warning(default: 4244)
auto it = this->m_updateQueue.find(destination);
if (this->m_updateQueue.end() != it)
it->second.push_back(radarTarget.GetCallsign());
if (this->m_updateQueue.end() != it) {
/* check that an active arrival runway is selected */
auto selectedIt = this->m_selectedRunway.find(radarTarget.GetCallsign());
if (this->m_selectedRunway.end() != selectedIt) {
auto activeRwyIt = std::find(it->second.arrivalRunways.cbegin(), it->second.arrivalRunways.cend(), selectedIt->second);
if (it->second.arrivalRunways.cend() == activeRwyIt)
this->m_selectedRunway.erase(selectedIt);
}
it->second.inboundUpdates.push_back(radarTarget.GetCallsign());
}
}
void PlugIn::updateInbound(EuroScopePlugIn::CRadarTarget& radarTarget) {
@@ -726,8 +780,15 @@ void PlugIn::updateSequence(std::shared_ptr<aman::AircraftSequence>& sequence) {
}
}
if (false == found)
if (false == found) {
/* delete the forced runway selection */
std::lock_guard guard(this->m_updateQueueLock);
auto selected = this->m_selectedRunway.find(it->first);
if (this->m_selectedRunway.end() != selected)
this->m_selectedRunway.erase(selected);
it = this->m_inbounds.erase(it);
}
else
++it;
}
@@ -764,7 +825,7 @@ void PlugIn::OnTimer(int counter) {
if (true == this->m_connectedToNetwork) {
std::lock_guard guardUpdate(this->m_updateQueueLock);
for (auto& airport : this->m_updateQueue)
airport.second.clear();
airport.second.inboundUpdates.clear();
std::lock_guard guardInbound(this->m_inboundsQueueLock);
this->m_inbounds.clear();
@@ -785,10 +846,10 @@ void PlugIn::OnTimer(int counter) {
aman::AircraftUpdate update;
update.set_airport(airport.first);
if (0 != airport.second.size()) {
if (0 != airport.second.inboundUpdates.size()) {
for (auto target = this->RadarTargetSelectFirst(); true == target.IsValid(); target = this->RadarTargetSelectNext(target)) {
auto it = std::find(airport.second.begin(), airport.second.end(), target.GetCallsign());
if (airport.second.end() != it) {
auto it = std::find(airport.second.inboundUpdates.begin(), airport.second.inboundUpdates.end(), target.GetCallsign());
if (airport.second.inboundUpdates.end() != it) {
auto report = update.add_reports();
this->generateAircraftReportMessage(target, report);
}
@@ -802,8 +863,34 @@ void PlugIn::OnTimer(int counter) {
else
this->updateSequence(sequence);
airport.second.clear();
airport.second.inboundUpdates.clear();
}
this->m_updateQueueLock.unlock();
}
void PlugIn::OnAirportRunwayActivityChanged() {
std::lock_guard guard(this->m_updateQueueLock);
/* cleanup the arrival airports */
for (auto& airport : this->m_updateQueue)
airport.second.arrivalRunways.clear();
EuroScopePlugIn::CSectorElement rwy;
for (rwy = this->SectorFileElementSelectFirst(EuroScopePlugIn::SECTOR_ELEMENT_RUNWAY); true == rwy.IsValid();
rwy = this->SectorFileElementSelectNext(rwy, EuroScopePlugIn::SECTOR_ELEMENT_RUNWAY)) {
/* remove leading and trailing whitespaces */
std::string airport(rwy.GetAirportName());
airport = std::regex_replace(airport, std::regex("^ +| +$|( ) +"), "$1");
if (true == rwy.IsElementActive(false, 0) || true == rwy.IsElementActive(false, 1)) {
auto airportData = this->m_updateQueue.find(airport);
if (this->m_updateQueue.end() != airportData) {
if (true == rwy.IsElementActive(false, 0))
airportData->second.arrivalRunways.push_back(rwy.GetRunwayName(0));
if (true == rwy.IsElementActive(false, 1))
airportData->second.arrivalRunways.push_back(rwy.GetRunwayName(1));
}
}
}
}

View File

@@ -37,10 +37,17 @@ namespace aman {
*/
enum class TagItemFunction {
ForceToBackendMenu = 0, /**< Opens the menu to force tracks */
ForceToBackendSelect = 1 /**< Reacts on controller selection */
ForceToBackendSelect = 1, /**< Reacts on controller selection */
RunwaySelectMenu = 2, /**< Opens the runway selection menu */
RunwaySelect = 3 /**< Selects the runway */
};
private:
struct AirportData {
std::vector<std::string> arrivalRunways;
std::list<std::string> inboundUpdates;
};
enum class TagItemElement {
EstimatedTimeOfArrival = 0,
PlannedTimeOfArrival = 1,
@@ -58,17 +65,18 @@ namespace aman {
static void distanceToPredictedIaf(const EuroScopePlugIn::CRadarTarget& radarTarget, const EuroScopePlugIn::CFlightPlan& flightPlan,
const EuroScopePlugIn::CPosition& iafPosition, aman::AircraftReport* report);
Communication m_configuration;
std::shared_ptr<RadarScreen> m_screen;
std::mutex m_updateQueueLock;
std::map<std::string, std::list<std::string>> m_updateQueue;
std::mutex m_inboundsQueueLock;
std::map<std::string, Inbound> m_inbounds;
std::list<std::string> m_forcedToBackendCallsigns;
bool m_compatible;
bool m_connectedToNetwork;
bool m_sweatboxValid;
bool m_playbackValid;
Communication m_configuration;
std::shared_ptr<RadarScreen> m_screen;
std::mutex m_updateQueueLock;
std::map<std::string, AirportData> m_updateQueue;
std::mutex m_inboundsQueueLock;
std::map<std::string, Inbound> m_inbounds;
std::map<std::string, std::string> m_selectedRunway;
std::list<std::string> m_forcedToBackendCallsigns;
bool m_compatible;
bool m_connectedToNetwork;
bool m_sweatboxValid;
bool m_playbackValid;
public:
/**
@@ -145,5 +153,9 @@ namespace aman {
* @param[in] flightPlan The disconnected flight plan
*/
void OnFlightPlanDisconnect(EuroScopePlugIn::CFlightPlan flightPlan) override;
/**
* @brief Called as soon as a runway configuration changed
*/
void OnAirportRunwayActivityChanged() override;
};
}