Traffic Picture
traffic.TrafficPicture is one picture of all traffic around a centre of the world (#366): our controlled aircraft, MSFS AI and the user, with where each one is and what it is doing, and the airports inside the radius. The centre is fixed — an airport or a position — or follows the user’s aircraft; the library never assumes which.
picture := traffic.NewTrafficPicture(traffic.PictureOptions{
Centre: traffic.Centre{FollowUser: true}, // or {ICAO: "LKPR"}, or {Position: ...}
RadiusNM: 250, // default DefaultPictureRadiusNM
})
lister := traffic.NewAirportLister(client, 0)
lister.Request()
for msg := range client.Stream() {
if airports, ok := lister.Handle(msg); ok {
picture.SetAirports(airports)
}
// … your aircraft scan (RequestDataOnSimObjectType) → []traffic.Observation
picture.Observe(time.Now(), scan)
}
Feeding it
The picture is fed, not self-driving:
Observe(now, scan)with each aircraft scan. SimConnect’sRequestDataOnSimObjectTypereaches at mostMaxScanRadiusMeters(200 km): MSFS AI farther away is not seen. Aircraft outside the radius, or not seen forPictureStaleAfter, leave the picture.SetAirportswith the airports around, e.g. fromAirportLister(SimConnect’s facilities list: the airports the simulator has loaded around the user, about 180 NM in MSFS 2024).AddAirportadds one it does not reach, such as a flight’s destination.SetOwn(objectID, phase, icao)for the aircraft our controllers drive — they know their phase best;ForgetOwnwhen a controller lets go.
Centre
A fixed centre stays put; SetCentre moves it, SetRadius changes the radius. A centre following the user moves only once the user is RecentreNM (25 NM) from it, so the picture does not churn with every scan.
What it knows
Aircraft() — nearest to the centre first — gives each aircraft’s scan data with its phase and airport:
| Phase | For aircraft not ours |
|---|---|
parked |
on the ground, not moving |
taxiing |
on the ground, up to 40 kt |
runway |
on the ground, faster (take-off or landing roll) |
departing / arriving |
airborne within AirportTerminalNM of an airport below 10 000 ft, climbing / descending |
enroute |
anything else airborne |
An aircraft on the ground belongs to the airport within AirportNearNM. Airports() are the airports inside the radius with their distance from the centre. Events() reports aircraft and airports entering and leaving, and recentring (dropped when the channel is full; the picture itself stays current).
Feeding the controllers
Ground(icao)is theGroundPictureof an airport, shared by its controllers (TaxiWithGroundPicture,ArrivalWithGroundPicture; see Ground traffic).Observereports the aircraft on the ground there that are not ours; ours report themselves.Allocate(icao, allocator)feeds aStandAllocator(Stand allocation) from the picture’s scans, so it needs no scan of its own.ManagerOptions.Picturegives it to the Traffic Manager, which counts the aircraft that are not ours as other traffic and follows its own airborne flights in it.
On the airport map
The Map section has the Traffic picture: the centre (follow my aircraft, this airport, or the map centre), the radius, the airports and aircraft in range by phase, and the load of the aircraft we drive. The 🌐 button (bottom left) is the world view (#371): the map zooms out to the picture’s circle and shows the airports in range and every aircraft, coloured by phase and labelled with call sign, level, phase and destination. Other traffic appears there only when its layer is on. Press 🌐 again to go back to the airport. The airports in range fill the ICAO fields (Load, flight plan) as a dropdown. GET /api/world returns the picture; POST /api/world sets the centre ({"follow":true}, {"icao":"LKPR"}, {"lat":…,"lon":…}) and the radius ({"radiusNM":250}).