Skip to content

Commit cee53a6

Browse files
committed
Included route validation changes
Courtesy of @FreshDave29
1 parent fbe1c88 commit cee53a6

File tree

9 files changed

+480
-2
lines changed

9 files changed

+480
-2
lines changed

DelHel/CDelHel.cpp

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ CDelHel::CDelHel() : EuroScopePlugIn::CPlugIn(
3131
this->LoadSettings();
3232

3333
this->ReadAirportConfig();
34+
this->ReadRoutingConfig();
3435

3536
if (this->updateCheck) {
3637
this->latestVersion = std::async(FetchLatestVersion);
@@ -114,6 +115,7 @@ bool CDelHel::OnCompileCommand(const char* sCommandLine)
114115

115116
this->airports.clear();
116117
this->ReadAirportConfig();
118+
this->ReadRoutingConfig();
117119

118120
return true;
119121
}
@@ -248,6 +250,66 @@ void CDelHel::SaveSettings()
248250
this->SaveDataToSettings(PLUGIN_NAME, "DelHel settings", ss.str().c_str());
249251
}
250252

253+
void CDelHel::ReadRoutingConfig()
254+
{
255+
json j;
256+
257+
try {
258+
std::filesystem::path base2(GetPluginDirectory());
259+
base2.append("routing.json");
260+
261+
std::ifstream ifs(base2.c_str());
262+
263+
j = json::parse(ifs);
264+
}
265+
catch (std::exception e)
266+
{
267+
this->LogMessage("Failed to read routing config. Error: " + std::string(e.what()), "Config");
268+
return;
269+
}
270+
271+
for (auto itair = this->airports.begin(); itair != this->airports.end(); itair++) {
272+
273+
for (auto& obj : j.items()) { //iterator on outer json object -> key = departure icao
274+
if (obj.key() == itair->second.icao) { //if departure icao has already been read in by AirportConfig
275+
276+
try {
277+
for (auto& el : obj.value()["entry"].items()) { //iterator on routes items
278+
279+
for (auto& in_el : el.value()["routes"].items()) {
280+
281+
routing ro{
282+
obj.key(),
283+
in_el.value()["icao"],
284+
in_el.value()["maxlvl"],
285+
in_el.value()["minlvl"],
286+
{}
287+
};
288+
289+
ro.waypts.push_back(el.value()["name"]); // add entry-point = SID exit as first waypoint of route
290+
291+
for (auto& inner_el : in_el.value()["waypoints"].items()) { // add route waypoints
292+
ro.waypts.push_back(inner_el.value());
293+
}
294+
295+
itair->second.validroutes.push_back(ro); //add routing to airports
296+
297+
std::string check = "ADEP:" + ro.adep + "-ADEST:" + ro.adest + "-MAX:" + std::to_string(ro.maxlvl) + "-MIN:" + std::to_string(ro.minlvl) + "-#wpts:" + std::to_string(ro.waypts.size());
298+
this->LogDebugMessage("New Routing added: " + check, "Config");
299+
}
300+
}
301+
}
302+
catch (std::exception e) {
303+
this->LogMessage("Failed to read routing config for " + itair->second.icao + "| Error: " + std::string(e.what()), "Config");
304+
return;
305+
}
306+
this->LogDebugMessage("Routing for departure Airport " + itair->second.icao + " has been added.", "Config");
307+
}
308+
309+
}
310+
}
311+
}
312+
251313
void CDelHel::ReadAirportConfig()
252314
{
253315
json j;
@@ -322,6 +384,7 @@ void CDelHel::ReadAirportConfig()
322384
}
323385
}
324386

387+
325388
validation CDelHel::ProcessFlightPlan(const EuroScopePlugIn::CFlightPlan& fp, bool nap, bool validateOnly)
326389
{
327390
validation res{
@@ -514,13 +577,129 @@ validation CDelHel::ProcessFlightPlan(const EuroScopePlugIn::CFlightPlan& fp, bo
514577
this->IsFlightPlanProcessed(fp);
515578
}
516579

580+
581+
if (ap.validroutes.size() != 0) {
582+
583+
flightplan fpl = flightplan(fp.GetCallsign(), fp.GetExtractedRoute(), fpd.GetRoute()); // create fp for route validation
584+
585+
bool routecheck = false;
586+
for (auto vait = ap.validroutes.begin(); vait != ap.validroutes.end(); ++vait) {
587+
588+
routecheck = false;
589+
auto selsidit = vait->waypts.begin();
590+
591+
if (*selsidit == sid.wp) {
592+
if (vait->waypts.size() > 1) {
593+
try {
594+
595+
auto wyprouit = vait->waypts.begin();
596+
597+
for (auto wypfpl = fpl.route.begin(); wypfpl != fpl.route.end(); ++wypfpl) {
598+
599+
if (wypfpl->name == *wyprouit) {
600+
routecheck = true;
601+
602+
if (wyprouit == vait->waypts.end() - 1) {
603+
break;
604+
}
605+
else {
606+
++wyprouit;
607+
}
608+
}
609+
else {
610+
routecheck = false;
611+
}
612+
}
613+
614+
}
615+
catch (std::exception e) {
616+
this->LogDebugMessage("Error, No Routing", cs);
617+
}
618+
}
619+
else {
620+
routecheck = true;
621+
}
622+
if (routecheck && vait->adest == arr) { //check specified destinations like LOWI, LOWS, etc.
623+
624+
if ((cad.GetFinalAltitude() == 0 && fpd.GetFinalAltitude() > vait->maxlvl * 100) || cad.GetFinalAltitude() > vait->maxlvl * 100) {
625+
626+
res.valid = false;
627+
res.tag = "MAX";
628+
res.color = TAG_COLOR_ORANGE;
629+
return res;
630+
}
631+
if ((cad.GetFinalAltitude() == 0 && fpd.GetFinalAltitude() < vait->minlvl * 100) || (cad.GetFinalAltitude() != 0 && cad.GetFinalAltitude() < vait->minlvl * 100)) {
632+
633+
res.valid = false;
634+
res.tag = "MIN";
635+
res.color = TAG_COLOR_ORANGE;
636+
return res;
637+
}
638+
639+
//case all correct
640+
res.valid = true;
641+
res.tag = "";
642+
res.color = TAG_COLOR_NONE;
643+
644+
return res;
645+
646+
}
647+
else if (routecheck && vait->adest != arr && vait->adest == "") { // check for non specified destinations
648+
if ((cad.GetFinalAltitude() == 0 && fpd.GetFinalAltitude() > vait->maxlvl * 100) || cad.GetFinalAltitude() > vait->maxlvl * 100) {
649+
650+
res.valid = false;
651+
res.tag = "MAX";
652+
res.color = TAG_COLOR_ORANGE;
653+
break;
654+
}
655+
if ((cad.GetFinalAltitude() == 0 && fpd.GetFinalAltitude() < vait->minlvl * 100) || (cad.GetFinalAltitude() != 0 && cad.GetFinalAltitude() < vait->minlvl * 100)) {
656+
657+
res.valid = false;
658+
res.tag = "MIN";
659+
res.color = TAG_COLOR_ORANGE;
660+
break;
661+
}
662+
663+
//case all correct
664+
res.valid = true;
665+
res.tag = "";
666+
res.color = TAG_COLOR_NONE;
667+
668+
return res;
669+
670+
}
671+
else if (this->CheckFlightPlanProcessed(fp)) {
672+
res.valid = false;
673+
res.tag = "INV";
674+
res.color = TAG_COLOR_ORANGE;
675+
continue;
676+
}
677+
else {
678+
res.valid = false;
679+
res.tag = "";
680+
res.color = TAG_COLOR_NONE;
681+
continue;
682+
}
683+
}
684+
}
685+
}
517686
return res;
518687
}
519688

689+
bool CDelHel::CheckFlightPlanProcessed(const EuroScopePlugIn::CFlightPlan& fp)
690+
{
691+
std::string cs = fp.GetCallsign();
692+
693+
if (std::find(this->processed.begin(), this->processed.end(), cs) != this->processed.end()) {
694+
return true;
695+
}
696+
return false;
697+
}
698+
520699
bool CDelHel::IsFlightPlanProcessed(const EuroScopePlugIn::CFlightPlan& fp)
521700
{
522701
std::string cs = fp.GetCallsign();
523-
702+
524703
if (std::find(this->processed.begin(), this->processed.end(), cs) != this->processed.end()) {
525704
return true;
526705
}

DelHel/CDelHel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "airport.h"
1919
#include "validation.h"
2020
#include "flightplan.h"
21+
#include "sid.h"
2122

2223
using json = nlohmann::json;
2324
using namespace std::chrono_literals;
@@ -45,9 +46,11 @@ class CDelHel : public EuroScopePlugIn::CPlugIn
4546

4647
void LoadSettings();
4748
void SaveSettings();
49+
void ReadRoutingConfig();
4850
void ReadAirportConfig();
4951

5052
validation ProcessFlightPlan(const EuroScopePlugIn::CFlightPlan& fp, bool nap, bool validateOnly = false);
53+
bool CDelHel::CheckFlightPlanProcessed(const EuroScopePlugIn::CFlightPlan& fp);
5154
bool IsFlightPlanProcessed(const EuroScopePlugIn::CFlightPlan& fp);
5255
void AutoProcessFlightPlans();
5356

DelHel/DelHel.vcxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@
218218
<CopyFileToFolders Include="..\airports.json">
219219
<FileType>Document</FileType>
220220
</CopyFileToFolders>
221+
<CopyFileToFolders Include="..\routing.json">
222+
<FileType>Document</FileType>
223+
</CopyFileToFolders>
221224
<None Include="DelHel.def" />
222225
<None Include="res\DelHel.rc2" />
223226
</ItemGroup>
@@ -231,6 +234,7 @@
231234
<ClInclude Include="pch.h" />
232235
<ClInclude Include="Resource.h" />
233236
<ClInclude Include="route_entry.h" />
237+
<ClInclude Include="routing.h" />
234238
<ClInclude Include="sid.h" />
235239
<ClInclude Include="targetver.h" />
236240
<ClInclude Include="helpers.h" />

DelHel/DelHel.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@
8282
<ClInclude Include="route_entry.h">
8383
<Filter>Header Files</Filter>
8484
</ClInclude>
85+
<ClInclude Include="routing.h">
86+
<Filter>Header Files</Filter>
87+
</ClInclude>
8588
</ItemGroup>
8689
<ItemGroup>
8790
<ResourceCompile Include="DelHel.rc">
@@ -97,5 +100,8 @@
97100
<CopyFileToFolders Include="..\airports.json">
98101
<Filter>Resource Files</Filter>
99102
</CopyFileToFolders>
103+
<CopyFileToFolders Include="..\routing.json">
104+
<Filter>Resource Files</Filter>
105+
</CopyFileToFolders>
100106
</ItemGroup>
101107
</Project>

DelHel/airport.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
#include <regex>
77

88
#include "sid.h"
9+
#include "routing.h"
910

1011
struct airport {
1112
std::string icao;
1213
int elevation;
1314
std::map<std::string, sid> sids;
1415
std::set<std::string> rwys;
16+
std::vector<routing> validroutes;
1517
std::regex rwy_regex;
1618
};

DelHel/routing.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <vector>
5+
#include "route_entry.h"
6+
7+
struct routing {
8+
std::string adep;
9+
std::string adest;
10+
int maxlvl{};
11+
int minlvl{};
12+
std::vector<std::string> waypts;
13+
};

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ At the moment, `DelHel` supports the following validations and processing:
5454
- CFL (**c**leared **f**light **l**evel) validation: verifies correct CFL is set for selected SID. Processing a FPL automatically sets the correct CFL for the calculated SID.
5555
- RWY (**r**un**w**a**y**) validation: displays a warning if a runway assignment has been found in the flightplan as this might influence SID selection.
5656
- Flightplan cleanup: when processing a flightplan, some cleanup will be performed, removing any additional information the pilot might have included before the SID fix (e.g. a SID filed by the pilot), only leaving a valid speed/level group or a runway designation included. This prevents SID assignments filed by pilots from selecting an incorrect runway or procedure by accident.
57+
- INV (**Inv**alid routing): verifies that the filed flightplan contains a valid routing according to the maintained routing.json file. Those routes can e.g. be the SAXFRA compulsory routings or special Vatsim Event routings. Each route contains at least an entry point (= last waypoint of the SID) and optional waypoints. If waypoints are maintained, the flightplan has to contain those waypoints in identical sequence in order to pass the routing validation. "DCT"/"DIRECT"/Speed-Altitude-Blocks in the FP are omitted.
5758

5859
Flightplans can be processed manually using the [`Process FPL`](#process-fpl) [tag function](#tag-functions) or automatically by toggling the [automatic processing](#toggle-automatic-processing) setting on.
5960

@@ -103,6 +104,25 @@ Indicates pilot filed a VFR flightplan, so little to no validations can be perfo
103104
Info, green color.
104105
Indicates pilot filed a processed VFR flightplan, so little to no validations can be performed. This just serves as an additional reminder about VFR flights.
105106

107+
##### `MIN`
108+
109+
Caution, orange color.
110+
Indicates, that the Requested Flight Level RFL is below the minima for the filed route.
111+
The altitudes are maintained in the routing.json and can be disregarded by the controller if necessary (e.g. depeding on active/inactive military areas along the route).
112+
113+
##### `MAX`
114+
115+
Caution, orange color.
116+
Indicates, that the Requested Flight Level RFL is above the maxima for the filed route.
117+
The altitudes are maintained in the routing.json and can be disregarded by the controller if necessary (e.g. depeding on active/inactive military areas along the route).
118+
119+
120+
##### `INV`
121+
122+
Caution, orange color.
123+
Indicates, that the filed route is not valid according to the maintained routings (routing.json). Those routings are e.g. the compulsory SAXRFRA routings for LOWW-departures or in case of a Vatsim Event.
124+
Indication becomes active as soon as the flightplan has been processed (SID is set and a valid SID exit point is in the FP).
125+
106126
##### `OK`
107127

108128
Info, green color.

airports.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@
460460
}
461461
},
462462
"LOWL": {
463-
"elevation": 980,
463+
"elevation": 980,
464464
"sids": {
465465
"LIDSI": {
466466
"cfl": 6000,

0 commit comments

Comments
 (0)