Skip to content

Commit

Permalink
feat: glideslope drift tag item
Browse files Browse the repository at this point in the history
  • Loading branch information
AndyTWF committed Dec 28, 2023
1 parent 1db137a commit 3b5f774
Show file tree
Hide file tree
Showing 26 changed files with 446 additions and 25 deletions.
3 changes: 2 additions & 1 deletion docs/TAG_ITEMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@
128 - SELCAL Code
129 - SELCAL Code With Separator
130 - Missed Approach Indicator
131 - Relevant ECFMP Flow Measures
131 - Relevant ECFMP Flow Measures
132 - Glideslope Deviation
5 changes: 4 additions & 1 deletion src/plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ set(src__approach
approach/ToggleApproachSequencerDisplay.cpp approach/ToggleApproachSequencerDisplay.h
approach/SequencerAirfieldSelector.cpp approach/SequencerAirfieldSelector.h approach/AircraftSelectionProvider.cpp approach/AircraftSelectionProvider.h approach/TargetSelectorList.cpp approach/TargetSelectorList.h approach/ApproachSpacingCalculator.cpp approach/ApproachSpacingCalculator.h approach/ApproachSequencerOptions.cpp approach/ApproachSequencerOptions.h approach/AirfieldApproachOptions.h approach/ApproachSequencerOptionsLoader.cpp approach/ApproachSequencerOptionsLoader.h approach/AirfieldTargetSelectorList.cpp approach/AirfieldTargetSelectorList.h approach/ApproachSequencerDistanceOptions.cpp approach/ApproachSequencerDistanceOptions.h approach/RemoveLandedAircraft.cpp approach/RemoveLandedAircraft.h approach/ApproachFlightplanEventHandler.cpp approach/ApproachFlightplanEventHandler.h
approach/GlideslopeDriftEstimator.h
approach/GlideslopeDriftEstimator.cpp)
approach/GlideslopeDriftEstimator.cpp
approach/GlideslopeDriftTagItem.cpp
approach/GlideslopeDriftTagItem.h)
source_group("src\\approach" FILES ${src__approach})

set(src__bootstrap
Expand Down Expand Up @@ -287,6 +289,7 @@ set(src__geometry
geometry/Line.cpp geometry/Line.h geometry/DistanceRadiusToScreenRadius.cpp geometry/DistanceRadiusToScreenRadius.h geometry/MeasurementUnitType.h geometry/MeasurementUnitFactory.cpp geometry/MeasurementUnitFactory.h geometry/Measurement.cpp geometry/Measurement.h geometry/MeasurementUnit.cpp geometry/MeasurementUnit.h
geometry/Angle.cpp
geometry/Angle.h
geometry/Length.h
)
source_group("src\\geometry" FILES ${src__geometry})

Expand Down
9 changes: 9 additions & 0 deletions src/plugin/approach/ApproachBootstrapProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "ApproachSequencerDisplayOptions.h"
#include "ApproachSequencerOptionsLoader.h"
#include "ApproachSpacingRingRenderer.h"
#include "GlideslopeDriftEstimator.h"
#include "GlideslopeDriftTagItem.h"
#include "RemoveLandedAircraft.h"
#include "SequencerAirfieldSelector.h"
#include "TargetSelectorList.h"
Expand All @@ -22,6 +24,7 @@
#include "list/PopupListFactory.h"
#include "radarscreen/MenuToggleableDisplayFactory.h"
#include "radarscreen/RadarRenderableCollection.h"
#include "tag/TagItemCollection.h"
#include "timedevent/TimedEventCollection.h"

namespace UKControllerPlugin::Approach {
Expand All @@ -38,6 +41,12 @@ namespace UKControllerPlugin::Approach {

container.flightplanHandler->RegisterHandler(
std::make_shared<ApproachFlightplanEventHandler>(container.moduleFactories->Approach().Sequencer()));

// Add the drift tag item
const auto driftEstimator = std::make_shared<GlideslopeDriftEstimator>();

container.tagHandler->RegisterTagItem(
DRIFT_TAG_ITEM_ID, std::make_shared<GlideslopeDriftTagItem>(driftEstimator, container.runwayCollection));
}

void ApproachBootstrapProvider::BootstrapRadarScreen(
Expand Down
3 changes: 3 additions & 0 deletions src/plugin/approach/ApproachBootstrapProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ namespace UKControllerPlugin::Approach {
RadarScreen::ConfigurableDisplayCollection& configurables,
Euroscope::AsrEventHandlerCollection& asrHandlers,
const RadarScreen::MenuToggleableDisplayFactory& toggleableDisplayFactory) override;

private:
const int DRIFT_TAG_ITEM_ID = 132;
};
} // namespace UKControllerPlugin::Approach
9 changes: 6 additions & 3 deletions src/plugin/approach/GlideslopeDriftEstimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
namespace UKControllerPlugin::Approach {

auto GlideslopeDriftEstimator::CalculateGlideslopeDrift(
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget, const Runway::Runway& runway) -> int
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget, const Runway::Runway& runway) const
-> GlideslopeDrift
{
// Calculate the slope of each line
const auto runwaySlope = runway.RunwayHeadingLineSlope();
Expand All @@ -21,7 +22,9 @@ namespace UKControllerPlugin::Approach {
runwaySlope * (intersection.m_Latitude - runway.Threshold().m_Latitude) + runway.Threshold().m_Longitude;
const auto distance = runway.Threshold().DistanceTo(intersection);

// Calculate the difference between the glideslope altitude and the aircraft altitude
return runway.GlideslopeAltitudeAtDistance(distance) - radarTarget.GetAltitude();
return {
.drift = radarTarget.GetAltitude() - runway.GlideslopeAltitudeAtDistance(distance),
.perpendicularDistanceFromLocaliser = radarTarget.GetPosition().DistanceTo(intersection),
.localiserRange = distance};
}
} // namespace UKControllerPlugin::Approach
9 changes: 8 additions & 1 deletion src/plugin/approach/GlideslopeDriftEstimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ namespace UKControllerPlugin {
} // namespace UKControllerPlugin

namespace UKControllerPlugin::Approach {
struct GlideslopeDrift
{
int drift;
double perpendicularDistanceFromLocaliser;
double localiserRange;
};

class GlideslopeDriftEstimator
{
public:
[nodiscard] auto CalculateGlideslopeDrift(
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget, const Runway::Runway& runway) -> int;
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget, const Runway::Runway& runway) const
-> GlideslopeDrift;
};
} // namespace UKControllerPlugin::Approach
76 changes: 76 additions & 0 deletions src/plugin/approach/GlideslopeDriftTagItem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "GlideslopeDriftEstimator.h"
#include "GlideslopeDriftTagItem.h"
#include "euroscope/EuroScopeCFlightPlanInterface.h"
#include "euroscope/EuroScopeCRadarTargetInterface.h"
#include "runway/Runway.h"
#include "runway/RunwayCollection.h"
#include "tag/TagData.h"

namespace UKControllerPlugin::Approach {
GlideslopeDriftTagItem::GlideslopeDriftTagItem(
std::shared_ptr<const GlideslopeDriftEstimator> glideslopeDriftEstimator,
std::shared_ptr<const Runway::RunwayCollection> runways)
: glideslopeDriftEstimator(glideslopeDriftEstimator), runways(runways)
{
assert(this->glideslopeDriftEstimator != nullptr && "Glideslope drift estimator cannot be null");
assert(this->runways != nullptr && "Runways cannot be null");
}

std::string GlideslopeDriftTagItem::GetTagItemDescription(int tagItemId) const
{
switch (tagItemId) {
case 132:
return "Glideslope Deviation";
default:
throw std::invalid_argument("Invalid tag item ID");
}
}

void GlideslopeDriftTagItem::SetTagItemData(Tag::TagData& tagData)
{
const auto& flightplan = tagData.GetFlightplan();

// Get the runway
const auto runway =
runways->GetByAirfieldAndIdentifier(flightplan.GetDestination(), flightplan.GetArrivalRunway());
if (runway == nullptr) {
return;
}

// Make sure we're upwind of the runway
if (std::abs(tagData.GetRadarTarget().GetPosition().DirectionTo(runway->Threshold()) - runway->Heading()) >
90) {
return;
}

// Calculate the drift and make sure we're somewhat close
const auto drift = glideslopeDriftEstimator->CalculateGlideslopeDrift(tagData.GetRadarTarget(), *runway);
if (drift.perpendicularDistanceFromLocaliser > 15) {
return;
}

if (drift.localiserRange > 25) {
return;
}

// Set the tag colour based on the drift
if (std::abs(drift.drift) < 300) {
tagData.SetTagColour(RGB(2, 48, 32));
} else {
tagData.SetTagColour(RGB(255, 0, 0));
}

// If we're massively out, abbreviate the string
if (drift.drift > 999) {
tagData.SetItemString(">1k");
return;
} else if (drift.drift < -999) {
tagData.SetItemString("<1k");
return;
}

// Set the tag item string
const auto driftSign = drift.drift >= 0 ? "+" : "";
tagData.SetItemString(driftSign + std::to_string(drift.drift));
}
} // namespace UKControllerPlugin::Approach
31 changes: 31 additions & 0 deletions src/plugin/approach/GlideslopeDriftTagItem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once
#include "tag/TagItemInterface.h"

namespace UKControllerPlugin {
namespace Runway {
class RunwayCollection;
} // namespace Runway
} // namespace UKControllerPlugin

namespace UKControllerPlugin::Approach {

class GlideslopeDriftEstimator;

class GlideslopeDriftTagItem : public Tag::TagItemInterface
{
public:
GlideslopeDriftTagItem(
std::shared_ptr<const GlideslopeDriftEstimator> glideslopeDriftEstimator,
std::shared_ptr<const Runway::RunwayCollection> runways);
auto GetTagItemDescription(int tagItemId) const -> std::string override;
void SetTagItemData(Tag::TagData& tagData) override;

private:
// The glideslope drift estimator
std::shared_ptr<const GlideslopeDriftEstimator> glideslopeDriftEstimator;

// The runways
std::shared_ptr<const Runway::RunwayCollection> runways;
};

} // namespace UKControllerPlugin::Approach
2 changes: 1 addition & 1 deletion src/plugin/bootstrap/PersistenceContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ namespace UKControllerPlugin::Bootstrap {
std::unique_ptr<UKControllerPlugin::Wake::WakeCategoryMapperCollection> wakeCategoryMappers;
std::shared_ptr<UKControllerPlugin::Hold::PublishedHoldCollection> publishedHolds;
std::unique_ptr<UKControllerPlugin::FlightRules::FlightRuleCollection> flightRules;
std::unique_ptr<UKControllerPlugin::Runway::RunwayCollection> runwayCollection;
std::shared_ptr<UKControllerPlugin::Runway::RunwayCollection> runwayCollection;

// Push events
std::shared_ptr<Push::PushEventProcessorCollection> pushEventProcessors;
Expand Down
1 change: 1 addition & 0 deletions src/plugin/euroscope/EuroScopeCFlightPlanInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ namespace UKControllerPlugin::Euroscope {
[[nodiscard]] virtual EuroScopePlugIn::CFlightPlan& GetEuroScopeObject() const = 0;
[[nodiscard]] virtual auto GetRemarks() const -> std::string = 0;
[[nodiscard]] virtual auto GetDepartureRunway() const -> std::string = 0;
[[nodiscard]] virtual auto GetArrivalRunway() const -> std::string = 0;
};
} // namespace UKControllerPlugin::Euroscope
5 changes: 5 additions & 0 deletions src/plugin/euroscope/EuroScopeCFlightPlanWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,9 @@ namespace UKControllerPlugin::Euroscope {
{
return this->originalData.GetFlightPlanData().GetDepartureRwy();
}

std::string EuroScopeCFlightPlanWrapper::GetArrivalRunway() const
{
return this->originalData.GetFlightPlanData().GetArrivalRwy();
}
} // namespace UKControllerPlugin::Euroscope
1 change: 1 addition & 0 deletions src/plugin/euroscope/EuroScopeCFlightPlanWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace UKControllerPlugin::Euroscope {
std::string GetRawRouteString() const override;
std::string GetSidName() const override;
std::string GetDepartureRunway() const override;
std::string GetArrivalRunway() const override;
bool HasAssignedSquawk() const override;
bool HasControllerClearedAltitude() const override;
bool HasControllerAssignedHeading() const override;
Expand Down
13 changes: 13 additions & 0 deletions src/plugin/geometry/Length.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

namespace UKControllerPlugin::Geometry {
[[nodiscard]] inline auto NauticalMilesToFeet(double nauticalMiles) -> double
{
return nauticalMiles * 6076.115;
}

[[nodiscard]] inline auto FeetToNauticalMiles(double feet) -> double
{
return feet / 6076.115;
}
} // namespace UKControllerPlugin::Geometry
16 changes: 12 additions & 4 deletions src/plugin/runway/Runway.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
#include "Runway.h"
#include "geometry/Angle.h"
#include "geometry/Length.h"
#include "headings/Heading.h"

namespace UKControllerPlugin::Runway {

Runway::Runway(int id, int airfieldId, std::string identifier, int heading, EuroScopePlugIn::CPosition threshold)
// TODO: Remove hard-coded threshold elevation and glideslope angle
: id(id), airfieldId(airfieldId), identifier(std::move(identifier)), heading(heading),
headingRadians(Geometry::DegreesToRadians(heading)),
// TODO: Remove hard-coded threshold elevation
// TODO: remove hard-coded glideslope angle
// TODO: Remove hard-coded airfield identifier
: id(id), airfieldId(airfieldId), airfieldIdentifier("EGKK"), identifier(std::move(identifier)),
heading(heading), headingRadians(Geometry::DegreesToRadians(heading)),
perpendicularHeading(Headings::PerpendicularHeading(heading)),
perpendicularHeadingRadians(Geometry::DegreesToRadians(perpendicularHeading)),
runwayHeadingLineSlope(Geometry::Slope(headingRadians)),
Expand All @@ -26,6 +29,11 @@ namespace UKControllerPlugin::Runway {
return airfieldId;
}

auto Runway::AirfieldIdentifier() const -> const std::string&
{
return airfieldIdentifier;
}

auto Runway::Identifier() const -> const std::string&
{
return identifier;
Expand All @@ -43,7 +51,7 @@ namespace UKControllerPlugin::Runway {

auto Runway::GlideslopeAltitudeAtDistance(const double distanceInNauticalMiles) const -> int
{
return (glideslopeAngleRadians * (distanceInNauticalMiles * 6076.12)) + thresholdElevation;
return (glideslopeAngleRadians * Geometry::NauticalMilesToFeet(distanceInNauticalMiles)) + thresholdElevation;
}

auto Runway::RunwayHeadingLineSlope() const -> double
Expand Down
4 changes: 4 additions & 0 deletions src/plugin/runway/Runway.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace UKControllerPlugin::Runway {
Runway(int id, int airfieldId, std::string identifier, int heading, EuroScopePlugIn::CPosition threshold);
[[nodiscard]] auto Id() const -> int;
[[nodiscard]] auto AirfieldId() const -> int;
[[nodiscard]] auto AirfieldIdentifier() const -> const std::string&;
[[nodiscard]] auto Identifier() const -> const std::string&;
[[nodiscard]] auto Heading() const -> int;
[[nodiscard]] auto Threshold() const -> const EuroScopePlugIn::CPosition&;
Expand All @@ -27,6 +28,9 @@ namespace UKControllerPlugin::Runway {
// The id of the airfield that this runway is at
int airfieldId;

// The identifier of the airfield that this runway is at
std::string airfieldIdentifier;

// The identifier of the runway - e.g 27L
std::string identifier;

Expand Down
32 changes: 25 additions & 7 deletions src/plugin/runway/RunwayCollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace UKControllerPlugin::Runway {
}

runways[runway->Id()] = runway;
runwaysByAirfieldIdAndIdentifier[runway->AirfieldId()][runway->Identifier()] = runway;
runwaysByAirfieldAndIdentifier[runway->AirfieldIdentifier()][runway->Identifier()] = runway;
}

auto RunwayCollection::Count() const -> size_t
Expand All @@ -26,12 +28,28 @@ namespace UKControllerPlugin::Runway {
auto RunwayCollection::GetByAirfieldAndIdentifier(int airfieldId, const std::string& identifier) const
-> std::shared_ptr<class Runway>
{
auto runway = std::find_if(
runways.begin(),
runways.end(),
[&airfieldId, &identifier](std::pair<int, const std::shared_ptr<class Runway>&> runway) -> bool {
return runway.second->AirfieldId() == airfieldId && runway.second->Identifier() == identifier;
});
return runway != runways.cend() ? runway->second : nullptr;
if (runwaysByAirfieldIdAndIdentifier.count(airfieldId) == 0) {
return nullptr;
}

if (runwaysByAirfieldIdAndIdentifier.at(airfieldId).count(identifier) == 0) {
return nullptr;
}

return runwaysByAirfieldIdAndIdentifier.at(airfieldId).at(identifier);
}

auto RunwayCollection::GetByAirfieldAndIdentifier(const std::string& airfield, const std::string& identifier) const
-> std::shared_ptr<class Runway>
{
if (runwaysByAirfieldAndIdentifier.count(airfield) == 0) {
return nullptr;
}

if (runwaysByAirfieldAndIdentifier.at(airfield).count(identifier) == 0) {
return nullptr;
}

return runwaysByAirfieldAndIdentifier.at(airfield).at(identifier);
}
} // namespace UKControllerPlugin::Runway
7 changes: 6 additions & 1 deletion src/plugin/runway/RunwayCollection.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#pragma once

#include "RunwayCollectionFactory.h"

namespace UKControllerPlugin::Runway {
Expand All @@ -16,9 +15,15 @@ namespace UKControllerPlugin::Runway {
[[nodiscard]] auto GetById(int id) const -> std::shared_ptr<class Runway>;
[[nodiscard]] auto GetByAirfieldAndIdentifier(int airfieldId, const std::string& identifier) const
-> std::shared_ptr<class Runway>;
[[nodiscard]] auto GetByAirfieldAndIdentifier(const std::string& airfield, const std::string& identifier) const
-> std::shared_ptr<class Runway>;

private:
// All the runways
std::map<int, std::shared_ptr<class Runway>> runways;
std::unordered_map<int, std::unordered_map<std::string, std::shared_ptr<class Runway>>>
runwaysByAirfieldIdAndIdentifier;
std::unordered_map<std::string, std::unordered_map<std::string, std::shared_ptr<class Runway>>>
runwaysByAirfieldAndIdentifier;
};
} // namespace UKControllerPlugin::Runway
Loading

0 comments on commit 3b5f774

Please sign in to comment.