Skip to content

Commit 1d15fc7

Browse files
authored
Add time rules for airspaces (#352)
1 parent 6ce9fb4 commit 1d15fc7

File tree

10 files changed

+544
-11
lines changed

10 files changed

+544
-11
lines changed

apps/fxc-front/src/app/components/2d/airspace-element.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,16 @@ export class AirspaceElement extends connect(store)(LitElement) {
7070
if (
7171
changedProperties.has('maxAltitude') ||
7272
changedProperties.has('showClasses') ||
73-
changedProperties.has('showTypes')
73+
changedProperties.has('showTypes') ||
74+
changedProperties.has('track')
7475
) {
7576
this.removeOverlays();
7677
this.addOverlays();
7778
}
7879
if (this.track && changedProperties.has('timeSec') && !this.isMapClick) {
7980
const point = sel.getTrackLatLonAlt(store.getState())(this.timeSec) as common.LatLonAlt;
8081
const gndAlt = sel.getGndAlt(store.getState())(this.timeSec);
81-
this.showAirspaceInfo(point, gndAlt);
82+
this.showAirspaceInfo(point, { gndAlt, date: new Date(this.timeSec * 1000) });
8283
}
8384
}
8485
if (changedProperties.has('show')) {
@@ -100,10 +101,12 @@ export class AirspaceElement extends connect(store)(LitElement) {
100101

101102
private async handleMapClick(latLng: google.maps.LatLng): Promise<void> {
102103
this.isMapClick = true;
103-
this.showAirspaceInfo({ lat: latLng.lat(), lon: latLng.lng(), alt: this.maxAltitude });
104+
// Use the track time or the current time
105+
const date = this.track ? new Date(this.timeSec * 1000) : new Date();
106+
this.showAirspaceInfo({ lat: latLng.lat(), lon: latLng.lng(), alt: this.maxAltitude }, { date });
104107
}
105108

106-
private async showAirspaceInfo(point: common.LatLonAlt, gndAlt = 0) {
109+
private async showAirspaceInfo(point: common.LatLonAlt, { gndAlt = 0, date = new Date() } = {}) {
107110
if (this.show) {
108111
const html = await getAirspaceList(
109112
Math.round(this.map.getZoom() ?? 10),
@@ -112,6 +115,7 @@ export class AirspaceElement extends connect(store)(LitElement) {
112115
gndAlt,
113116
this.showClasses,
114117
this.showTypes,
118+
date,
115119
);
116120
if (html !== '') {
117121
this.info?.setContent(html);
@@ -129,6 +133,9 @@ export class AirspaceElement extends connect(store)(LitElement) {
129133
o.setAltitude(this.maxAltitude);
130134
o.showClasses(this.showClasses);
131135
o.showTypes(this.showTypes);
136+
// Use the track time or the current time
137+
const date = this.track ? new Date(this.timeSec * 1000) : new Date();
138+
o.setDate(date);
132139
this.map.overlayMapTypes.push(o as any);
133140
}
134141
});

apps/fxc-front/src/app/components/3d/airspace3d-element.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ export class Airspace3dElement extends connect(store)(LitElement) {
6969
0,
7070
this.showClasses,
7171
this.showTypes,
72+
// TODO: use track time when there is a track
73+
new Date(),
7274
);
7375
if (html) {
7476
view.popup?.open({

apps/fxc-front/src/app/logic/airspaces.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { AirspaceString, AirspaceTyped, Class, LatLon, Point, Type } from '@flyxc/common';
22
import {
33
AIRSPACE_TILE_SIZE,
4+
applyTimeRule,
45
getAirspaceCategory,
56
getAirspaceColor,
67
getAirspaceTileUrl,
@@ -37,6 +38,7 @@ export async function getAirspaceList(
3738
gndAltitude: number,
3839
showClasses: Class[],
3940
showTypes: Type[],
41+
date: Date,
4042
): Promise<string> {
4143
const tileZoom = Math.min(zoom, MAX_AIRSPACE_TILE_ZOOM);
4244
const { tile: tileCoords, px } = pixelCoordinates(latLon, tileZoom, AIRSPACE_TILE_SIZE);
@@ -62,7 +64,7 @@ export async function getAirspaceList(
6264
const info: string[] = [];
6365
for (let i = 0; i < layer.length; i++) {
6466
const f = layer.feature(i);
65-
const airspace = toTypedAirspace(f.properties as AirspaceString);
67+
const airspace = applyTimeRule(toTypedAirspace(f.properties as AirspaceString), date);
6668
const floor = airspace.floorM + (airspace.floorRefGnd ? gndAltitude : 0);
6769
const top = airspace.topM + (airspace.topRefGnd ? gndAltitude : 0);
6870
const onlyConsiderFloor = gndAltitude == 0;
@@ -99,6 +101,8 @@ export class AspMapType {
99101
classes: Class[] = [];
100102
types: Type[] = [];
101103
active_ = true;
104+
date = new Date();
105+
102106
// FetchInfo indexed by fetch key.
103107
fetchInfoMap: Map<number, FetchInfo> = new Map();
104108

@@ -126,7 +130,18 @@ export class AspMapType {
126130
}
127131

128132
getTile(coord: google.maps.Point, zoom: number, doc: Document): HTMLElement {
129-
return getTile(coord, zoom, zoom, doc, this.altitude, this.classes, this.types, this.active, this.fetchInfoMap);
133+
return getTile(
134+
coord,
135+
zoom,
136+
zoom,
137+
doc,
138+
this.altitude,
139+
this.classes,
140+
this.types,
141+
this.active,
142+
this.fetchInfoMap,
143+
this.date,
144+
);
130145
}
131146

132147
// @ts-ignore
@@ -168,6 +183,10 @@ export class AspMapType {
168183
this.types = types;
169184
}
170185

186+
setDate(date: Date): void {
187+
this.date = date;
188+
}
189+
171190
// minZoom and maxZoom are not taken into account by the Google Maps API for overlay map types.
172191
// We need to manually activate the layers for the current zoom level.
173192
setCurrentZoom(zoom: number): void {
@@ -204,6 +223,7 @@ export class AspZoomMapType extends AspMapType {
204223
this.types,
205224
this.active,
206225
this.fetchInfoMap,
226+
this.date,
207227
);
208228
}
209229
}
@@ -220,6 +240,7 @@ function getTile(
220240
showTypes: Type[],
221241
active: boolean,
222242
fetchInfoMap: Map<number, FetchInfo>,
243+
date: Date,
223244
): HTMLElement {
224245
if (!active) {
225246
return doc.createElement('div');
@@ -262,7 +283,7 @@ function getTile(
262283
return;
263284
}
264285
const vectorTile = new VectorTile(new Uint8Array(buffer));
265-
renderTiles(fetchKey, fetchInfoMap, vectorTile, altitude, showClasses, showTypes, mapZoom, tileZoom);
286+
renderTiles(fetchKey, fetchInfoMap, vectorTile, altitude, showClasses, showTypes, mapZoom, tileZoom, date);
266287
})
267288
.catch((e) => {
268289
// AbortError are expected when aborting a request.
@@ -288,6 +309,7 @@ function renderTiles(
288309
showTypes: Type[],
289310
mapZoom: number,
290311
tileZoom: number,
312+
date: Date,
291313
) {
292314
const fetchInfo = fetchInfoMap.get(fetchKey);
293315
if (fetchInfo == null) {
@@ -320,7 +342,7 @@ function renderTiles(
320342

321343
for (let i = 0; i < vectorTile.layers.asp.length; i++) {
322344
const f = vectorTile.layers.asp.feature(i);
323-
const airspace = toTypedAirspace(f.properties as any);
345+
const airspace = applyTimeRule(toTypedAirspace(f.properties as any), date);
324346
const ratio = renderSize / f.extent;
325347
if (
326348
f.type === 3 &&

apps/run/src/app/airspace.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { AirspaceString, AirspaceTyped, Point } from '@flyxc/common';
22
import {
33
AIRSPACE_TILE_SIZE,
44
AirspaceColorCategory,
5+
applyTimeRule,
56
fetchResponse,
67
Flags,
78
getAirspaceColorCategory,
@@ -100,9 +101,11 @@ export async function fetchAirspaces(track: protos.Track, altitude: protos.Groun
100101
}
101102
const aspLayer = new VectorTile(new Uint8Array(buffer)).layers.asp;
102103

104+
const startDate = track.timeSec[0] ? new Date(track.timeSec[0] * 1000) : new Date();
105+
103106
for (let i = 0; i < aspLayer.length; i++) {
104107
const feature = aspLayer.feature(i);
105-
const airspace = toTypedAirspace(feature.properties as AirspaceString);
108+
const airspace = applyTimeRule(toTypedAirspace(feature.properties as AirspaceString), startDate);
106109
const airspaceId = getAirspaceFeatureId(airspace);
107110
for (const fixIdx of indexes) {
108111
// Do not check airspaces above the track.

libs/common/jest.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export default {
22
displayName: 'common',
33
preset: '../../jest.preset.js',
44
globals: {},
5+
testEnvironment: 'node',
56
transform: {
67
'^.+\\.[tj]s$': [
78
'ts-jest',

0 commit comments

Comments
 (0)