Skip to content

Commit 7d8e13b

Browse files
authored
Merge pull request #10 from AI4REALNET/900-multiple-airplanes-context
900 multiple airplanes context
2 parents 8d09bc1 + edd67b1 commit 7d8e13b

File tree

8 files changed

+182
-78
lines changed

8 files changed

+182
-78
lines changed

backend/context-service/resources/ATM/schemas.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,35 @@
22

33
from api.schemas import MetadataSchema
44
from apiflask.fields import Dict, String, Float, List, Integer
5-
class MetadataSchemaATM(MetadataSchema):
5+
from apiflask import Schema, fields
6+
from marshmallow import pre_load
7+
class PlaneMetadataSchemaATM(MetadataSchema):
8+
id_plane = String()
69
ApDest = Dict()
710
Current_airspeed = Float()
811
Latitude = Float()
912
Longitude = Float()
1013
wpList = List(Dict())
11-
id_plane = Integer()
14+
15+
class MetadataSchemaATM(MetadataSchema):
16+
airplanes = List(fields.Nested(PlaneMetadataSchemaATM), required=True)
17+
18+
# Backward compatibility: optional fields for the single airplane case
19+
ApDest = Dict(required=False)
20+
Current_airspeed = Float(required=False)
21+
Latitude = Float(required=False)
22+
Longitude = Float(required=False)
23+
wpList = List(Dict(), required=False)
24+
25+
@pre_load
26+
def handle_backward_compatibility(self, data, **kwargs):
27+
# If the new 'airplanes' field is not provided, assume the old format.
28+
if 'airplanes' not in data:
29+
airplane = {}
30+
for field in ['ApDest', 'Current_airspeed', 'Latitude', 'Longitude', 'wpList']:
31+
if field in data:
32+
airplane[field] = data[field]
33+
# Provide a default id_plane if not present.
34+
airplane.setdefault('id_plane', "X")
35+
data['airplanes'] = [airplane]
36+
return data

backend/recommendation-service/resources/Railway/manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# backend/recommendation-service/resources/RTE/manager.py
1+
# backend/recommendation-service/resources/Railway/manager.py
22

33
from api.manager.base_manager import BaseRecommendationManager
44

frontend/src/components/organisms/Map.vue

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@ import { useMapStore } from '@/stores/components/map'
8383
import type { Waypoint } from '@/types/components/map'
8484
import { criticalityToColor, maxCriticality } from '@/utils/utils'
8585
86-
withDefaults(
86+
const props = withDefaults(
8787
defineProps<{
8888
tileLayers?: string[]
8989
contextClick?: (waypoint: Waypoint) => void
9090
waypointClick?: (waypoint: Waypoint) => void
91+
autoFit?: boolean
9192
}>(),
9293
{
9394
tileLayers: () => ['http://{s}.tile.osm.org/{z}/{x}/{y}.png'],
@@ -103,9 +104,17 @@ const lockView = ref(true)
103104
const zoom = ref(6)
104105
const map = ref()
105106
106-
watch(mapStore.contextWaypoints, () => {
107-
toggleLockView()
108-
})
107+
watch(
108+
() => mapStore.contextWaypoints,
109+
() => {
110+
if (props.autoFit) {
111+
toggleLockView()
112+
}
113+
114+
}
115+
)
116+
117+
109118
watch(appStore.panels, () => {
110119
map.value.leafletObject.invalidateSize()
111120
})

frontend/src/entities/ATM/CAB/Context.vue

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,17 @@
33
<Map v-if="appStore.tab.context === 0" />
44
</Context>
55
</template>
6+
67
<script setup lang="ts">
7-
import { onBeforeMount, onUnmounted, ref, watch } from 'vue'
8+
import { onBeforeMount, onUnmounted, ref } from 'vue'
89
import { useI18n } from 'vue-i18n'
9-
1010
import Context from '@/components/organisms/CAB/Context.vue'
1111
import Map from '@/components/organisms/Map.vue'
12-
import type { System } from '@/entities/ATM/types'
12+
import type { AirplaneContext, LegacyContext, ContextType } from '@/entities/ATM/types'
1313
import { useAppStore } from '@/stores/app'
1414
import { useMapStore } from '@/stores/components/map'
1515
import { useServicesStore } from '@/stores/services'
1616
17-
1817
const { t, locale } = useI18n()
1918
const servicesStore = useServicesStore()
2019
const mapStore = useMapStore()
@@ -23,40 +22,86 @@ const appStore = useAppStore()
2322
const contextPID = ref(0)
2423
const faulty = ref(false)
2524
26-
2725
onBeforeMount(async () => {
2826
locale.value = `en-ATM`
29-
contextPID.value = await servicesStore.getContext('ATM', (context) => {
30-
mapStore.addContextWaypoint({
31-
lat: context.data.Latitude,
32-
lng: context.data.Longitude,
33-
id: t('map.context')
34-
})
35-
const waypoints = [
36-
...(context.data.wpList
37-
? context.data.wpList.map(({ wplat, wplon, wpid }) => ({
38-
id: wpid,
39-
lat: wplat,
40-
lng: wplon
41-
}))
42-
: []),
43-
...(context.data.ApDest
44-
? [
45-
{
46-
id: context.data.ApDest.apid,
47-
lat: context.data.ApDest.aplat,
48-
lng: context.data.ApDest.aplon,
49-
permanentTooltip: true
50-
}
51-
]
52-
: [])
53-
]
54-
mapStore.addPolyline({
55-
id: 'current_route',
56-
waypoints
57-
})
27+
contextPID.value = await servicesStore.getContext('ATM', (context: { data: ContextType }) => {
28+
// New context data: iterate over the airplanes array
29+
// 1- Clear last tick's markers and ROUTE waypoints
5830
mapStore.removeCategoryWaypoint('ROUTE')
59-
for (const waypoint of waypoints) mapStore.addWaypoint({ ...waypoint, category: 'ROUTE' })
31+
// 2- add new markers and ROUTE waypoints
32+
if ('airplanes' in context.data) {
33+
context.data.airplanes.forEach((airplane: AirplaneContext) => {
34+
mapStore.addContextWaypoint({
35+
lat: airplane.Latitude,
36+
lng: airplane.Longitude,
37+
id: `plane-${airplane.id_plane}`
38+
})
39+
// build the route waypoints
40+
const waypoints = [
41+
...(airplane.wpList
42+
? airplane.wpList.map(({ wplat, wplon, wpid }) => ({
43+
id: wpid,
44+
lat: wplat,
45+
lng: wplon
46+
}))
47+
: []),
48+
...(airplane.ApDest
49+
? [
50+
{
51+
id: airplane.ApDest.apid,
52+
lat: airplane.ApDest.aplat,
53+
lng: airplane.ApDest.aplon,
54+
permanentTooltip: true
55+
}
56+
]
57+
: [])
58+
]
59+
// draw polyline for the plane
60+
mapStore.addPolyline({
61+
id: `current_route_plane-${airplane.id_plane}`,
62+
waypoints
63+
})
64+
// add each wp a ROUTE waypoint
65+
for (const waypoint of waypoints) {
66+
mapStore.addWaypoint({ ...waypoint, category: 'ROUTE' })
67+
}
68+
})
69+
} else {
70+
// Legacy context data handling
71+
const legacy = context.data as LegacyContext
72+
mapStore.addContextWaypoint({
73+
lat: legacy.Latitude,
74+
lng: legacy.Longitude,
75+
id: t('map.context')
76+
})
77+
const waypoints = [
78+
...(legacy.wpList
79+
? legacy.wpList.map(({ wplat, wplon, wpid }) => ({
80+
id: wpid,
81+
lat: wplat,
82+
lng: wplon
83+
}))
84+
: []),
85+
...(legacy.ApDest
86+
? [
87+
{
88+
id: legacy.ApDest.apid,
89+
lat: legacy.ApDest.aplat,
90+
lng: legacy.ApDest.aplon,
91+
permanentTooltip: true
92+
}
93+
]
94+
: [])
95+
]
96+
mapStore.addPolyline({
97+
id: 'current_route',
98+
waypoints
99+
})
100+
//mapStore.removeCategoryWaypoint('ROUTE')
101+
for (const waypoint of waypoints) {
102+
mapStore.addWaypoint({ ...waypoint, category: 'ROUTE' })
103+
}
104+
}
60105
})
61106
})
62107

frontend/src/entities/ATM/types.ts

Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,68 @@
1+
export type AirplaneContext = {
2+
id_plane: number;
3+
Current_airspeed: number;
4+
Latitude: number;
5+
Longitude: number;
6+
ApDest?: {
7+
apcity: string;
8+
apid: Uppercase<string>;
9+
aplat: number;
10+
aplon: number;
11+
apname: string;
12+
};
13+
wpList?: {
14+
wpid: Uppercase<string>;
15+
wpidx: number;
16+
wplat: number;
17+
wplon: number;
18+
}[];
19+
};
20+
21+
export type LegacyContext = {
22+
Current_airspeed: number;
23+
Latitude: number;
24+
Longitude: number;
25+
ApDest?: {
26+
apcity: string;
27+
apid: Uppercase<string>;
28+
aplat: number;
29+
aplon: number;
30+
apname: string;
31+
};
32+
wpList?: {
33+
wpid: Uppercase<string>;
34+
wpidx: number;
35+
wplat: number;
36+
wplon: number;
37+
}[];
38+
};
39+
40+
export type ContextType = { airplanes: AirplaneContext[] } | LegacyContext;
41+
142
export type ATM = {
2-
Context: {
3-
'Current airspeed': number
4-
Latitude: number
5-
Longitude: number
6-
ApDest?: {
7-
apcity: string
8-
apid: Uppercase<string>
9-
aplat: number
10-
aplon: number
11-
apname: string
12-
}
13-
wpList?: {
14-
wpid: Uppercase<string>
15-
wpidx: number
16-
wplat: number
17-
wplon: number
18-
}[]
19-
}
20-
Metadata: { event_type: string; system: string }
43+
Context: ContextType;
44+
Metadata: { event_type: string; system: string };
2145
Action: {
2246
airport_destination: {
23-
apcity: string
24-
apid: Uppercase<string>
25-
apname: Uppercase<string>
26-
latitude: number
27-
longitude: number
28-
}
47+
apcity: string;
48+
apid: Uppercase<string>;
49+
apname: Uppercase<string>;
50+
latitude: number;
51+
longitude: number;
52+
};
2953
waypoints: {
30-
wplat: number
31-
wplon: number
32-
wpidx: number
33-
wpid: Uppercase<string>
34-
}[]
35-
}
36-
}
54+
wplat: number;
55+
wplon: number;
56+
wpidx: number;
57+
wpid: Uppercase<string>;
58+
}[];
59+
};
60+
};
61+
3762

3863
export const SYSTEMS = [
3964
'ENGINE',
4065
'ELECTRIC',
41-
] as const
42-
Object.freeze(SYSTEMS)
43-
export type System = (typeof SYSTEMS)[number]
66+
] as const;
67+
Object.freeze(SYSTEMS);
68+
export type System = (typeof SYSTEMS)[number];

frontend/src/entities/Railway/locales/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"card.event_type.INFRASTRUCTURE": "Infrastructure",
66
"card.event_type.PASSENGER": "Passenger",
77
"card.event_type.RAIL": "Rail",
8-
"event.button.primary": "Recalculate transport plans",
8+
"event.button.primary": "Get recommendation from maze",
99
"event.button.primary.passenger": "Show procedure",
1010
"event.button.secondary": "Continue the procedure follow-up",
1111
"event.button.secondary.passenger": "Put on hold",

0 commit comments

Comments
 (0)