Skip to content

Commit

Permalink
Added flyOver and finish properties
Browse files Browse the repository at this point in the history
  • Loading branch information
fboes committed Oct 19, 2024
1 parent 84f92c1 commit 9a11bf4
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

- Added `flyOver` property to waypoints
- Added `finish` property to missions
- Added new cloud layers
- Improved handling of Garmin `fpl` files
- Prioritizing waypoints in GeoJson
Expand Down
11 changes: 9 additions & 2 deletions dist/Aerofly/Mission.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class Mission {
* True heading of aircraft in Degrees on exit
*/
this.destination_dir = 0;
this.finish = null;
this.conditions = new MissionConditions();
this.checkpoints = [];
/**
Expand Down Expand Up @@ -303,6 +304,7 @@ export class Mission {
break;
}
this.conditions.fromMainMcf(mainMcf);
this.finish = null;
let lastPosition = null;
this.checkpoints = mainMcf.navigation.Route.Ways.filter((w) => {
// Please not that procedure waypoints cannot be restored as of now
Expand Down Expand Up @@ -373,6 +375,7 @@ export class Mission {
}
// Assuming non AFS4 flight plans to start on the ground ;)
this.flight_setting = Mission.FLIGHT_SETTING_TAXI;
this.finish = null;
this.checkpoints = gpl.waypoints.map((w, i) => {
var _a;
let cp = new MissionCheckpoint();
Expand Down Expand Up @@ -787,6 +790,8 @@ export class Mission {
this.calculateCheckpoints();
}
toString() {
var _a, _b;
const finish = (_b = (_a = this.finish) === null || _a === void 0 ? void 0 : _a.toStringTargetPlane('finish')) !== null && _b !== void 0 ? _b : '';
let string = ` // Exported by Aerofly Missionsgerät
<[tmmission_definition][mission][]
<[string8][title][${Quote.tmc(this.title)}]>
Expand All @@ -804,7 +809,7 @@ export class Mission {
<[float64] [destination_dir] [${this.destination_dir}]>
//<[float64] [cruise_altitude] [${this.cruise_altitude}]>
//<[float64] [cruise_speed] [${this.cruise_speed}]>
${this.conditions} <[list_tmmission_checkpoint][checkpoints][]
${this.conditions + finish} <[list_tmmission_checkpoint][checkpoints][]
`;
this.checkpoints.forEach((c, i) => {
string += c.toString(i);
Expand All @@ -816,7 +821,7 @@ ${this.conditions} <[list_tmmission_checkpoint][checkpoints][]
return string;
}
hydrate(json) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
this._title = (_a = json._title) !== null && _a !== void 0 ? _a : this._title;
this._description = (_b = json._description) !== null && _b !== void 0 ? _b : this._description;
this.flight_setting = (_c = json.flight_setting) !== null && _c !== void 0 ? _c : this.flight_setting;
Expand All @@ -842,6 +847,7 @@ ${this.conditions} <[list_tmmission_checkpoint][checkpoints][]
this.cruise_altitude = (_w = json.cruise_altitude) !== null && _w !== void 0 ? _w : this.cruise_altitude;
this.turn_time = (_x = json.turn_time) !== null && _x !== void 0 ? _x : this.turn_time;
this.conditions.hydrate(json.conditions);
this.finish = (_y = json.finish) !== null && _y !== void 0 ? _y : this.finish;
this.checkpoints = json.checkpoints.map((c) => {
const cx = new MissionCheckpoint();
cx.hydrate(c);
Expand Down Expand Up @@ -892,6 +898,7 @@ export class MissionFactory extends FileParser {
mission.conditions.visibility = this.getNumber(tmmission_conditions, "visibility");
mission.conditions.cloud.cover = this.getNumber(tmmission_conditions, "cloud_cover");
mission.conditions.cloud.height = this.getNumber(tmmission_conditions, "cloud_base");
mission.finish = null;
mission.checkpoints = list_tmmission_checkpoint
.split("<[tmmission_checkpoint")
.slice(1)
Expand Down
18 changes: 17 additions & 1 deletion dist/Aerofly/MissionCheckpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export class MissionCheckpoint {
* @see MissionCheckpoint.rawFreqency
*/
this.frequency = 0;
/**
* If waypoint is meant to be flown over. Else turn anticipation will be used.
*/
this.flyOver = false;
/**
* Not official: In kts TAS
*/
Expand Down Expand Up @@ -189,6 +193,11 @@ export class MissionCheckpoint {
this.slope = altDifference / this.distance_m;
}
toString(index) {
let flyOver = "";
if (this.type === MissionCheckpoint.TYPE_WAYPOINT) {
flyOver = ` <[bool][FlyOver][${this.flyOver ? "true" : "false"}]>
`;
}
return ` <[tmmission_checkpoint][element][${index}]
<[string8u][type][${Quote.tmc(this.type)}]>
<[string8u][name][${Quote.tmc(this.name)}]>
Expand All @@ -199,7 +208,14 @@ export class MissionCheckpoint {
<[float64][slope][${this.slope}]> // ${this.slope_deg.toFixed(1)} deg
<[float64][length][${this.length}]>
<[float64][frequency][${this.frequency.toFixed()}]>
>
${flyOver} >
`;
}
toStringTargetPlane(name = "finish") {
return ` <[tmmission_target_plane][${name}][]
<[vector2_float64][lon_lat][${this.lon_lat.lon} ${this.lon_lat.lat}]>
<[float64][direction][${this.direction}]>
>
`;
}
hydrate(cp) {
Expand Down
11 changes: 8 additions & 3 deletions dist/Export/GeoJson.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class GeoJson {
altitude: c.lon_lat.altitude_m,
direction: c.direction,
frequency: c.frequency_string,
"marker-symbol": this.getGeoJsonIcon(c),
"marker-symbol": this.getGeoJsonIcon(c, mission.finish),
"marker-color": c.type === MissionCheckpoint.TYPE_ORIGIN || c.type === MissionCheckpoint.TYPE_DESTINATION
? "#5e6eba"
: "#555555",
Expand Down Expand Up @@ -199,7 +199,8 @@ export class GeoJson {
turnDegrees += 360;
}
const turnAnticipationDistance = Math.tan(((Math.abs(turnDegrees) / 180) * Math.PI) / 2) * turnRadius;
if (Math.abs(turnDegrees) < 150 &&
if (!c.flyOver &&
Math.abs(turnDegrees) < 150 &&
turnAnticipationDistance <= Math.min(c.distance / 2, nextCheckpoint.distance / 2)) {
// Fly-by
const segments = Math.ceil(Math.abs(turnDegrees) / (360 / segmentsPerCircle));
Expand All @@ -215,6 +216,7 @@ export class GeoJson {
//lineCoordinates.push(this.getGeoJsonPosition(entry));
}
else {
console.log("Fly-over");
// Fly-over
// @see https://en.wikipedia.org/wiki/Circular_segment
turnDegrees *= 2;
Expand Down Expand Up @@ -259,7 +261,10 @@ export class GeoJson {
getGeoJsonPosition(entry) {
return entry.altitude_m ? [entry.lon, entry.lat, entry.altitude_m] : [entry.lon, entry.lat];
}
getGeoJsonIcon(cp) {
getGeoJsonIcon(cp, finishCp) {
if (finishCp && finishCp === cp) {
return "af-large_airbase";
}
switch (cp.type_extended) {
case MissionCheckpoint.TYPE_DESTINATION:
return "af-large_airport";
Expand Down
9 changes: 9 additions & 0 deletions dist/Web/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export class App {
this.showFlightplan(App.SHOW_CHECKPOINTS);
}
handleEventClickWaypointEdit(target) {
var _a;
const type = target.getAttribute("data-type");
const waypointId = Number(target.closest("dialog").getAttribute("data-cp-id"));
switch (type) {
Expand All @@ -138,6 +139,14 @@ export class App {
case "add-after":
this.mission.addCheckpointAfter(waypointId, 3, 1000);
break;
case "make-finish":
const currentWaypoint = this.mission.checkpoints[waypointId];
this.mission.finish =
currentWaypoint === this.mission.finish ? null : (_a = this.mission.checkpoints[waypointId]) !== null && _a !== void 0 ? _a : null;
break;
case "toggle-flyover":
this.mission.checkpoints[waypointId].flyOver = !this.mission.checkpoints[waypointId].flyOver;
break;
}
this.handleEventClickModalClose(target);
this.mission.calculateCheckpoints();
Expand Down
2 changes: 2 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ <h4>Edit waypoint</h4>
<button data-handler="waypoint-edit" data-type="delete">Delete waypoint</button>
<button data-handler="waypoint-edit" data-type="add-before">Add waypoint before</button>
<button data-handler="waypoint-edit" data-type="add-after">Add waypoint after</button>
<button data-handler="waypoint-edit" data-type="make-finish">Set as finish (BETA)</button>
<button data-handler="waypoint-edit" data-type="toggle-flyover">Toggle fly-over (BETA)</button>
<button data-handler="modal-close" class="icon" title="Close waypoint editor"><span>Close waypoint editor</span></button>
</dialog>
</main>
Expand Down
8 changes: 7 additions & 1 deletion src/Aerofly/Mission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class Mission {
* True heading of aircraft in Degrees on exit
*/
destination_dir: number = 0;
finish: MissionCheckpoint | null = null;
conditions: MissionConditions = new MissionConditions();
checkpoints: MissionCheckpoint[] = [];
/**
Expand Down Expand Up @@ -347,6 +348,7 @@ export class Mission {
}
this.conditions.fromMainMcf(mainMcf);

this.finish = null;
let lastPosition: LonLat | null = null;
this.checkpoints = mainMcf.navigation.Route.Ways.filter((w) => {
// Please not that procedure waypoints cannot be restored as of now
Expand Down Expand Up @@ -440,6 +442,7 @@ export class Mission {
// Assuming non AFS4 flight plans to start on the ground ;)
this.flight_setting = Mission.FLIGHT_SETTING_TAXI;

this.finish = null;
this.checkpoints = gpl.waypoints.map((w, i) => {
let cp = new MissionCheckpoint();
cp.lon_lat.lat = w.lat;
Expand Down Expand Up @@ -899,6 +902,7 @@ export class Mission {
}

toString(): string {
const finish = this.finish?.toStringTargetPlane("finish") ?? "";
let string = ` // Exported by Aerofly Missionsgerät
<[tmmission_definition][mission][]
<[string8][title][${Quote.tmc(this.title)}]>
Expand All @@ -916,7 +920,7 @@ export class Mission {
<[float64] [destination_dir] [${this.destination_dir}]>
//<[float64] [cruise_altitude] [${this.cruise_altitude}]>
//<[float64] [cruise_speed] [${this.cruise_speed}]>
${this.conditions} <[list_tmmission_checkpoint][checkpoints][]
${this.conditions + finish} <[list_tmmission_checkpoint][checkpoints][]
`;
this.checkpoints.forEach((c, i) => {
string += c.toString(i);
Expand Down Expand Up @@ -956,6 +960,7 @@ ${this.conditions} <[list_tmmission_checkpoint][checkpoints][]

this.conditions.hydrate(json.conditions);

this.finish = json.finish ?? this.finish;
this.checkpoints = json.checkpoints.map((c) => {
const cx = new MissionCheckpoint();
cx.hydrate(c);
Expand Down Expand Up @@ -1005,6 +1010,7 @@ export class MissionFactory extends FileParser {
mission.conditions.cloud.cover = this.getNumber(tmmission_conditions, "cloud_cover");
mission.conditions.cloud.height = this.getNumber(tmmission_conditions, "cloud_base");

mission.finish = null;
mission.checkpoints = list_tmmission_checkpoint
.split("<[tmmission_checkpoint")
.slice(1)
Expand Down
19 changes: 18 additions & 1 deletion src/Aerofly/MissionCheckpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export class MissionCheckpoint {
* @see MissionCheckpoint.rawFreqency
*/
frequency: number = 0;
/**
* If waypoint is meant to be flown over. Else turn anticipation will be used.
*/
flyOver: boolean = false;
/**
* Not official: In kts TAS
*/
Expand Down Expand Up @@ -234,6 +238,11 @@ export class MissionCheckpoint {
}

toString(index: number): string {
let flyOver = "";
if (this.type === MissionCheckpoint.TYPE_WAYPOINT) {
flyOver = ` <[bool][FlyOver][${this.flyOver ? "true" : "false"}]>
`;
}
return ` <[tmmission_checkpoint][element][${index}]
<[string8u][type][${Quote.tmc(this.type)}]>
<[string8u][name][${Quote.tmc(this.name)}]>
Expand All @@ -244,7 +253,15 @@ export class MissionCheckpoint {
<[float64][slope][${this.slope}]> // ${this.slope_deg.toFixed(1)} deg
<[float64][length][${this.length}]>
<[float64][frequency][${this.frequency.toFixed()}]>
>
${flyOver} >
`;
}

toStringTargetPlane(name: string = "finish"): string {
return ` <[tmmission_target_plane][${name}][]
<[vector2_float64][lon_lat][${this.lon_lat.lon} ${this.lon_lat.lat}]>
<[float64][direction][${this.direction}]>
>
`;
}

Expand Down
9 changes: 7 additions & 2 deletions src/Export/GeoJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class GeoJson implements GeoJSON.FeatureCollection {
altitude: c.lon_lat.altitude_m,
direction: c.direction,
frequency: c.frequency_string,
"marker-symbol": this.getGeoJsonIcon(c),
"marker-symbol": this.getGeoJsonIcon(c, mission.finish),
"marker-color":
c.type === MissionCheckpoint.TYPE_ORIGIN || c.type === MissionCheckpoint.TYPE_DESTINATION
? "#5e6eba"
Expand Down Expand Up @@ -235,6 +235,7 @@ export class GeoJson implements GeoJSON.FeatureCollection {
const turnAnticipationDistance = Math.tan(((Math.abs(turnDegrees) / 180) * Math.PI) / 2) * turnRadius;

if (
!c.flyOver &&
Math.abs(turnDegrees) < 150 &&
turnAnticipationDistance <= Math.min(c.distance / 2, nextCheckpoint.distance / 2)
) {
Expand All @@ -253,6 +254,7 @@ export class GeoJson implements GeoJSON.FeatureCollection {
//entry = c.lon_lat.getRelativeCoordinates(turnAnticipationDistance, nextCheckpoint.direction);
//lineCoordinates.push(this.getGeoJsonPosition(entry));
} else {
console.log("Fly-over");
// Fly-over
// @see https://en.wikipedia.org/wiki/Circular_segment
turnDegrees *= 2;
Expand Down Expand Up @@ -308,7 +310,10 @@ export class GeoJson implements GeoJSON.FeatureCollection {
return entry.altitude_m ? [entry.lon, entry.lat, entry.altitude_m] : [entry.lon, entry.lat];
}

protected getGeoJsonIcon(cp: MissionCheckpoint): string {
protected getGeoJsonIcon(cp: MissionCheckpoint, finishCp: MissionCheckpoint | null): string {
if (finishCp && finishCp === cp) {
return "af-large_airbase";
}
switch (cp.type_extended) {
case MissionCheckpoint.TYPE_DESTINATION:
return "af-large_airport";
Expand Down
8 changes: 8 additions & 0 deletions src/Web/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@ export class App {
case "add-after":
this.mission.addCheckpointAfter(waypointId, 3, 1000);
break;
case "make-finish":
const currentWaypoint = this.mission.checkpoints[waypointId];
this.mission.finish =
currentWaypoint === this.mission.finish ? null : this.mission.checkpoints[waypointId] ?? null;
break;
case "toggle-flyover":
this.mission.checkpoints[waypointId].flyOver = !this.mission.checkpoints[waypointId].flyOver;
break;
}
this.handleEventClickModalClose(target);

Expand Down

0 comments on commit 9a11bf4

Please sign in to comment.