Skip to content

Commit

Permalink
feat: mapping flightplans to flow measures
Browse files Browse the repository at this point in the history
  • Loading branch information
AndyTWF committed Aug 11, 2023
1 parent 00aae91 commit 90b0e73
Show file tree
Hide file tree
Showing 6 changed files with 452 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/plugin/CMakeLists.txt
Expand Up @@ -179,7 +179,7 @@ source_group("src\\dependency" FILES ${src__dependency})

set(src__ecfmp

ecfmp/ECFMPModuleFactory.cpp ecfmp/ECFMPModuleFactory.h ecfmp/Logger.cpp ecfmp/Logger.h ecfmp/HttpClient.cpp ecfmp/HttpClient.h ecfmp/ECFMPBootstrapProvider.cpp ecfmp/ECFMPBootstrapProvider.h ecfmp/TriggerEcfmpEventLoop.cpp ecfmp/TriggerEcfmpEventLoop.h)
ecfmp/ECFMPModuleFactory.cpp ecfmp/ECFMPModuleFactory.h ecfmp/Logger.cpp ecfmp/Logger.h ecfmp/HttpClient.cpp ecfmp/HttpClient.h ecfmp/ECFMPBootstrapProvider.cpp ecfmp/ECFMPBootstrapProvider.h ecfmp/TriggerEcfmpEventLoop.cpp ecfmp/TriggerEcfmpEventLoop.h ecfmp/AircraftFlowMeasureMap.cpp ecfmp/AircraftFlowMeasureMap.h ecfmp/AircraftFlowMeasureMapInterface.h)

set(src__euroscope
"euroscope/AsrEventHandlerCollection.cpp"
Expand Down
143 changes: 143 additions & 0 deletions src/plugin/ecfmp/AircraftFlowMeasureMap.cpp
@@ -0,0 +1,143 @@
#include "AircraftFlowMeasureMap.h"
#include "ECFMP/flowmeasure/FlowMeasure.h"
#include "euroscope/EuroScopeCFlightPlanInterface.h"
#include "euroscope/EuroScopeCRadarTargetInterface.h"
#include "euroscope/EuroscopePluginLoopbackInterface.h"

namespace UKControllerPlugin::ECFMP {

struct AircraftFlowMeasureMap::Impl
{
Impl(Euroscope::EuroscopePluginLoopbackInterface& plugin) : plugin(plugin)
{
}

void RemoveFlightplanFromCollection(Euroscope::EuroScopeCFlightPlanInterface& flightplan)
{
// No flow measures are relevant to this flight plan
if (!callsignFlowMeasureMap.contains(flightplan.GetCallsign())) {
return;
}

// Remove the flight plan from the flow measure's callsign map
for (const auto& flowMeasure : callsignFlowMeasureMap.at(flightplan.GetCallsign())) {
flowMeasureCallsignMap.at(flowMeasure).erase(flightplan.GetCallsign());
}

// Remove the callsign from the callsign map
callsignFlowMeasureMap.erase(flightplan.GetCallsign());
}

void RemoveFlowMeasureFromCollection(const ::ECFMP::FlowMeasure::FlowMeasure& measure)
{
// Measure never became active
if (!flowMeasureIdMap.contains(measure.Id())) {
return;
}

const auto collectionMeasure = flowMeasureIdMap.at(measure.Id());

// Remove from the callsign map
for (const auto& callsign : flowMeasureCallsignMap.at(collectionMeasure)) {
callsignFlowMeasureMap.at(callsign).erase(collectionMeasure);
}

// Remove from the map by measure and id
flowMeasureCallsignMap.erase(collectionMeasure);
flowMeasureIdMap.erase(measure.Id());
}

void FlowMeasureActivated(const std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>& measure)
{
if (flowMeasureIdMap.contains(measure->Id())) {
LogWarning("Flow measure with id " + std::to_string(measure->Id()) + " already exists in the map");
return;
}

// Add the flow measure to the map by id
flowMeasureIdMap.emplace(measure->Id(), measure);

// Check each of the flightplans and see if it applies to them
plugin.ApplyFunctionToAllFlightplans([&measure, this](
const Euroscope::EuroScopeCFlightPlanInterface& flightplan,
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget) {
if (measure->ApplicableToAircraft(flightplan.GetEuroScopeObject(), radarTarget.GetEuroScopeObject())) {
callsignFlowMeasureMap[flightplan.GetCallsign()].insert(measure);
flowMeasureCallsignMap[measure].insert(flightplan.GetCallsign());
}
});
}

void MapFlightplanToActiveFlowMeasures(
Euroscope::EuroScopeCFlightPlanInterface& flightPlan,
Euroscope::EuroScopeCRadarTargetInterface& radarTarget)
{
for (const auto& [id, measure] : flowMeasureIdMap) {
if (measure->ApplicableToAircraft(flightPlan.GetEuroScopeObject(), radarTarget.GetEuroScopeObject())) {
callsignFlowMeasureMap[flightPlan.GetCallsign()].insert(measure);
flowMeasureCallsignMap[measure].insert(flightPlan.GetCallsign());
}
}
}

// The plugin, used to map over flightplans
Euroscope::EuroscopePluginLoopbackInterface& plugin;

// Map of callsigns to flow measures and vice versa
std::map<int, std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>> flowMeasureIdMap;
std::map<std::string, std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>>>
callsignFlowMeasureMap;
std::map<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>, std::unordered_set<std::string>>
flowMeasureCallsignMap;

// An empty set for use when we dont have a callsign
std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>> emptyFlowMeasureSet;
};

AircraftFlowMeasureMap::AircraftFlowMeasureMap(Euroscope::EuroscopePluginLoopbackInterface& plugin)
: impl(std::make_unique<Impl>(plugin))
{
}

AircraftFlowMeasureMap::~AircraftFlowMeasureMap() = default;

void AircraftFlowMeasureMap::OnEvent(const ::ECFMP::Plugin::FlowMeasureActivatedEvent& event)
{
impl->FlowMeasureActivated(event.flowMeasure);
}

void AircraftFlowMeasureMap::OnEvent(const ::ECFMP::Plugin::FlowMeasureExpiredEvent& event)
{
impl->RemoveFlowMeasureFromCollection(*event.flowMeasure);
}

void AircraftFlowMeasureMap::OnEvent(const ::ECFMP::Plugin::FlowMeasureWithdrawnEvent& event)
{
impl->RemoveFlowMeasureFromCollection(*event.flowMeasure);
}

void AircraftFlowMeasureMap::FlightPlanEvent(
Euroscope::EuroScopeCFlightPlanInterface& flightPlan, Euroscope::EuroScopeCRadarTargetInterface& radarTarget)
{
impl->RemoveFlightplanFromCollection(flightPlan);
impl->MapFlightplanToActiveFlowMeasures(flightPlan, radarTarget);
}

void AircraftFlowMeasureMap::FlightPlanDisconnectEvent(Euroscope::EuroScopeCFlightPlanInterface& flightPlan)
{
impl->RemoveFlightplanFromCollection(flightPlan);
}

const std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>>&
AircraftFlowMeasureMap::GetFlowMeasuresForCallsign(const std::string& callsign)
{
return impl->callsignFlowMeasureMap.contains(callsign) ? impl->callsignFlowMeasureMap.at(callsign)
: impl->emptyFlowMeasureSet;
}

void AircraftFlowMeasureMap::ControllerFlightPlanDataEvent(
Euroscope::EuroScopeCFlightPlanInterface& flightPlan, int dataType)
{
// No-op
}
} // namespace UKControllerPlugin::ECFMP
40 changes: 40 additions & 0 deletions src/plugin/ecfmp/AircraftFlowMeasureMap.h
@@ -0,0 +1,40 @@
#pragma once
#include <string>
#include <unordered_set>
#include "ECFMP/SdkEvents.h"
#include "ECFMP/flowmeasure/FlowMeasure.h"
#include "AircraftFlowMeasureMapInterface.h"
#include "euroscope/EuroscopePluginLoopbackInterface.h"
#include "flightplan/FlightPlanEventHandlerInterface.h"

namespace UKControllerPlugin::Euroscope {
class EuroscopePluginLoopbackInterface;
} // namespace UKControllerPlugin::Euroscope

namespace UKControllerPlugin::ECFMP {
class AircraftFlowMeasureMap : public ::ECFMP::EventBus::EventListener<::ECFMP::Plugin::FlowMeasureActivatedEvent>,
public ::ECFMP::EventBus::EventListener<::ECFMP::Plugin::FlowMeasureExpiredEvent>,
public ::ECFMP::EventBus::EventListener<::ECFMP::Plugin::FlowMeasureWithdrawnEvent>,
public Flightplan::FlightPlanEventHandlerInterface,
public AircraftFlowMeasureMapInterface
{
public:
AircraftFlowMeasureMap(Euroscope::EuroscopePluginLoopbackInterface& plugin);
~AircraftFlowMeasureMap() override;
void FlightPlanEvent(
UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightPlan,
UKControllerPlugin::Euroscope::EuroScopeCRadarTargetInterface& radarTarget) override;
void
FlightPlanDisconnectEvent(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightPlan) override;
void ControllerFlightPlanDataEvent(Euroscope::EuroScopeCFlightPlanInterface& flightPlan, int dataType) override;
void OnEvent(const ::ECFMP::Plugin::FlowMeasureActivatedEvent& event) override;
void OnEvent(const ::ECFMP::Plugin::FlowMeasureExpiredEvent& event) override;
void OnEvent(const ::ECFMP::Plugin::FlowMeasureWithdrawnEvent& event) override;
auto GetFlowMeasuresForCallsign(const std::string& callsign)
-> const std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>>& override;

private:
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace UKControllerPlugin::ECFMP
11 changes: 11 additions & 0 deletions src/plugin/ecfmp/AircraftFlowMeasureMapInterface.h
@@ -0,0 +1,11 @@
#pragma once

namespace UKControllerPlugin::ECFMP {
class AircraftFlowMeasureMapInterface
{
public:
virtual ~AircraftFlowMeasureMapInterface() = default;
[[nodiscard]] virtual auto GetFlowMeasuresForCallsign(const std::string& callsign)
-> const std::unordered_set<std::shared_ptr<const ::ECFMP::FlowMeasure::FlowMeasure>>& = 0;
};
} // namespace UKControllerPlugin::ECFMP
2 changes: 1 addition & 1 deletion test/plugin/CMakeLists.txt
Expand Up @@ -109,7 +109,7 @@ set(test__dependency
)
source_group("test\\dependency" FILES ${test__dependency})

set(test__ecfmp ecfmp/HttpClientTest.cpp ecfmp/TriggerEcfmpEventLoopTest.cpp ecfmp/ECFMPModuleFactoryTest.cpp ecfmp/ECFMPBootstrapProviderTest.cpp)
set(test__ecfmp ecfmp/HttpClientTest.cpp ecfmp/TriggerEcfmpEventLoopTest.cpp ecfmp/ECFMPModuleFactoryTest.cpp ecfmp/ECFMPBootstrapProviderTest.cpp ecfmp/AircraftFlowMeasureMapTest.cpp)
source_group("test\\ecfmp" FILES ${test__ecfmp})

set(test__euroscope
Expand Down

0 comments on commit 90b0e73

Please sign in to comment.