Skip to content

Commit

Permalink
Merge pull request #552 from AndyTWF/glideslop-drift
Browse files Browse the repository at this point in the history
Glideslop deviation
  • Loading branch information
AndyTWF authored Dec 28, 2023
2 parents 4166861 + 8c38c60 commit 07a547d
Show file tree
Hide file tree
Showing 38 changed files with 849 additions and 54 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
1 change: 1 addition & 0 deletions docs/UserGuide/Features/Features.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ dynamically to the plugin.
- [Electronic Prenotes](PrenoteMessages.md)
- [SELCAL Parsing](Selcal.md)
- [Approach Sequencing](ApproachSequencer.md)
- [Glideslope Deviation](GlideslopeDeviation.md)
11 changes: 11 additions & 0 deletions docs/UserGuide/Features/GlideslopeDeviation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Glideslope Deviation

The glideslope deviation TAG item displays the aircrafts current deviation from the glideslope. It does this by looking at the aircraft current position
along the localiser (by taking a perpendicular line from the aircraft to the localiser) and then calculating the difference between the aircrafts altitude
and the altitude of the glideslope at that point.

## TAG Item

The "Glideslope Deviation" TAG item displays the current deviation from the glideslope in the format of `+/-XXX` where `XXX` is the deviation in feet. It will display in
green when the aircraft is within a few hundred feet of or below the glideslope, and red when the aircraft is above the glideslope. If the aircraft is massively above or below the
glideslope, the deviation will be displayed as `>/<1k`.
12 changes: 10 additions & 2 deletions src/plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ set(src__approach
approach/ApproachSequencerDisplayOptions.cpp approach/ApproachSequencerDisplayOptions.h
approach/ApproachSequencerDisplayAsrLoader.cpp approach/ApproachSequencerDisplayAsrLoader.h
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/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/GlideslopeDeviationEstimator.h
approach/GlideslopeDeviationEstimator.cpp
approach/GlideslopeDeviationTagItem.cpp
approach/GlideslopeDeviationTagItem.h)
source_group("src\\approach" FILES ${src__approach})

set(src__bootstrap
Expand Down Expand Up @@ -282,7 +286,11 @@ set(src__flightrule
source_group("src\\flightrule" FILES ${src__flightrule})

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/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})

set(src__graphics
Expand Down
10 changes: 10 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 "GlideslopeDeviationEstimator.h"
#include "GlideslopeDeviationTagItem.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,13 @@ namespace UKControllerPlugin::Approach {

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

// Add the deviation tag item
const auto deviationEstimator = std::make_shared<GlideslopeDeviationEstimator>();

container.tagHandler->RegisterTagItem(
GLIDESLOPE_DEVIATION_TAG_ITEM_ID,
std::make_shared<GlideslopeDeviationTagItem>(deviationEstimator, 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 GLIDESLOPE_DEVIATION_TAG_ITEM_ID = 132;
};
} // namespace UKControllerPlugin::Approach
30 changes: 30 additions & 0 deletions src/plugin/approach/GlideslopeDeviationEstimator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "GlideslopeDeviationEstimator.h"
#include "euroscope/EuroScopeCRadarTargetInterface.h"
#include "runway/Runway.h"

namespace UKControllerPlugin::Approach {

auto GlideslopeDeviationEstimator::CalculateGlideslopeDeviation(
const Euroscope::EuroScopeCRadarTargetInterface& radarTarget, const Runway::Runway& runway) const
-> GlideslopeDeviation
{
// Calculate the slope of each line
const auto runwaySlope = runway.RunwayHeadingLineSlope();
const auto runwayPerpendicularSlope = runway.RunwayPerpendicularHeadingLineSlope();

// Calculate the distance between the intersection and the threshold
EuroScopePlugIn::CPosition intersection;
intersection.m_Latitude = (runwaySlope * runway.Threshold().m_Latitude -
runwayPerpendicularSlope * radarTarget.GetPosition().m_Latitude +
radarTarget.GetPosition().m_Longitude - runway.Threshold().m_Longitude) /
(runwaySlope - runwayPerpendicularSlope);
intersection.m_Longitude =
runwaySlope * (intersection.m_Latitude - runway.Threshold().m_Latitude) + runway.Threshold().m_Longitude;
const auto distance = runway.Threshold().DistanceTo(intersection);

return {
.deviation = radarTarget.GetAltitude() - runway.GlideslopeAltitudeAtDistance(distance),
.perpendicularDistanceFromLocaliser = radarTarget.GetPosition().DistanceTo(intersection),
.localiserRange = distance};
}
} // namespace UKControllerPlugin::Approach
28 changes: 28 additions & 0 deletions src/plugin/approach/GlideslopeDeviationEstimator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

namespace UKControllerPlugin {
namespace Euroscope {
class EuroScopeCRadarTargetInterface;
} // namespace Euroscope
namespace Runway {
class Runway;
} // namespace Runway
} // namespace UKControllerPlugin

namespace UKControllerPlugin::Approach {
// Struct representing glideslope deviation
struct GlideslopeDeviation
{
int deviation;
double perpendicularDistanceFromLocaliser;
double localiserRange;
};

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

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

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

void GlideslopeDeviationTagItem::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 deviation and make sure we're somewhat close
const auto deviation =
glideslopeDeviationEstimator->CalculateGlideslopeDeviation(tagData.GetRadarTarget(), *runway);
if (deviation.perpendicularDistanceFromLocaliser > 15) {
return;
}

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

// Set the tag colour to red if we're massively out
if (deviation.deviation > 300) {
tagData.SetTagColour(RGB(255, 87, 51));
}

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

// Set the tag item string
const auto deviationSign = deviation.deviation >= 0 ? "+" : "";
tagData.SetItemString(deviationSign + std::to_string(deviation.deviation));
}
} // namespace UKControllerPlugin::Approach
31 changes: 31 additions & 0 deletions src/plugin/approach/GlideslopeDeviationTagItem.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 GlideslopeDeviationEstimator;

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

private:
// The glideslope deviation estimator
std::shared_ptr<const GlideslopeDeviationEstimator> glideslopeDeviationEstimator;

// 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
21 changes: 21 additions & 0 deletions src/plugin/geometry/Angle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "Angle.h"

namespace UKControllerPlugin::Geometry {

const double pi = 3.14159265358979323846;

auto DegreesToRadians(const double degrees) -> double
{
return degrees * pi / 180;
}

auto RadiansToDegrees(const double radians) -> double
{
return radians * 180 / pi;
}

auto Slope(const double radians) -> double
{
return std::tan(radians);
}
} // namespace UKControllerPlugin::Geometry
8 changes: 8 additions & 0 deletions src/plugin/geometry/Angle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

namespace UKControllerPlugin::Geometry {
[[nodiscard]] auto DegreesToRadians(const double degrees) -> double;
[[nodiscard]] auto RadiansToDegrees(const double radians) -> double;
[[nodiscard]] auto Slope(const double radians) -> double;

} // namespace UKControllerPlugin::Geometry
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
10 changes: 10 additions & 0 deletions src/plugin/headings/Heading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,14 @@ namespace UKControllerPlugin::Headings {
{
return first == static_cast<unsigned int>(second);
}

[[nodiscard]] auto TruncateHeading(unsigned int heading) -> unsigned int
{
return heading % 360;
}

[[nodiscard]] auto PerpendicularHeading(unsigned int heading) -> unsigned int
{
return TruncateHeading(heading + 90);
}
} // namespace UKControllerPlugin::Headings
3 changes: 3 additions & 0 deletions src/plugin/headings/Heading.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ namespace UKControllerPlugin::Headings {
auto operator<(double first, Heading second) -> bool;
auto operator>=(double first, Heading second) -> bool;
auto operator==(unsigned int first, Heading second) -> bool;

[[nodiscard]] auto TruncateHeading(unsigned int heading) -> unsigned int;
[[nodiscard]] auto PerpendicularHeading(unsigned int heading) -> unsigned int;
} // namespace UKControllerPlugin::Headings
Loading

0 comments on commit 07a547d

Please sign in to comment.