Three changes to what is on the picture, and both drawings got all three.
The line from an information box to its aircraft was drawn in the
aircraft's own colour, which made it the same colour as that aircraft's
trail: a straight solid line running out of an aeroplane, in the colour of
the path behind the aeroplane, reads as more path, and on a busy picture
that is a heading nobody flew. It has its own colour now, and is dashed.
Qt measures a dash pattern in multiples of the pen's width, so each pass of
the glow divides the pattern by its own width; without that the halo's
dashes are three times the core's and the line comes out as beads.
The animation had no such line at all, which only came out when the two
were held up against each other: a label pushed into one of the outward
rings by a crowd had nothing tying it to the aeroplane it was about. It has
one now, walked along the line's own length rather than along whichever axis
is longer, so that a nearly horizontal leader and a nearly vertical one get
dashes of the same length and neither runs past the aircraft it points at.
A red flag stands where the receiver was told it is standing, from the
coordinates in the settings. The foot of the pole is the position and the
pennant flies up and to the right, so nothing the flag is made of covers the
place it points at. It is pure red in every theme: that is the one mark on
the picture whose meaning must not change with the colours, and pure red is
both the brightest red there is and the one furthest from every altitude
colour -- a softer one sat close enough to a low aeroplane on the default
map, and to a mid-altitude one on the red theme, to be taken for one. It is
drawn only where a position was actually given, since a middle worked out
from whatever flew past is not a place anybody is standing.
And the range rings: faint discs at a quarter, a half and three quarters of
the radius, concentric on the receiver and labelled with the distance. They
are translucent and they stack, so the ground inside the innermost is lifted
three times and the outer once, which gives a sense of how far away a thing
is without measuring anything. An indexed picture cannot blend, so
translucent there means moving the ground under the disc a step or two up
its own ramp of shades, which keeps the coastline and the roads visible
through it. Separate settings for the two, because a picture is studied and
a window is glanced at.
Two bugs found by the tests rather than by looking. The rings were built
across the whole canvas instead of the part of it the map is drawn on, so
they came out stretched by the height of the title bar -- four per cent,
which is invisible and wrong. And a radius of zero killed the window: the
projection collapses, every pixel maps to one point, and the graticule asks
for lines across a span of nothing until Qt aborts. The program never
passes a zero, but a caller could, and a crash is not an answer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
The aerodromes were never on the window at all: only the animation drew
them, and the window's map had whatever airport glyphs the tiles happened to
carry. They are drawn there now, in the same colour and the same square.
The first attempt at that had a bug worth naming, because it would have
looked like the feature simply not working. They were fetched inside the
same pass of the fetching loop as a piece of map, so they queued behind a
hundred and twenty tiles coming off a network -- and once the map was in
hand there were no more passes, so they were never fetched again. They are
their own question now, asked on the same thread but not behind the tiles,
and they arrive whether the tiles do or not. An area that has been asked
about and has none in it is remembered as none, rather than asked about
again five times a second for the rest of the night. And the thread now
starts if either the map or the aerodromes are wanted, so --no-basemap no
longer quietly takes the airports with it.
Then the themes, which change the window and the animated pictures together
because both read their colours out of the same palette. night is what this
program has always drawn and is untouched. digital, phosphor, amber and red
are the screens the phrase "air defence display" actually calls to mind: a
black tube, one phosphor, and thin bright vector lines with a halo round
them.
Three things follow from having one colour to spend, and they are
constraints rather than decoration. Height becomes brightness, since hue is
no longer free -- low is dim and high burns, which is the trade those
displays made. The map underneath drops to about a quarter of the
brightness asked for, because a tinted photograph of a county behind the
vectors is the one thing that stops a vector display looking like one. And
a country is named in two letters rather than drawn as a flag, a flag being
half a dozen colours.
The glow is done twice, differently, because the two are different kinds of
picture. The window lays each line down two or three times, wider and
fainter each pass, with the core last: trails, symbols, leader lines, box
borders and the aerodrome squares. The animation cannot blend at all, a GIF
being indexed colour, so it dilates what it has drawn and fills the halo
with the dimmed copy of the colour underneath -- and the aircraft colours
already had dimmed copies, since those are the trail shades, so an aeroplane
glows into the colour its own trail is drawn in, which is the colour a
phosphor would have spread into. The fixed colours get two rings each in
the palette for the purpose. The halo goes over the map, the grid and the
background and over nothing else that was drawn, since a halo is what light
does to the dark around a line; where two rings meet the nearer wins. It
costs about 55 ms a frame at 1400 by 1258 and the default theme skips the
pass entirely.
The palette is written over in place rather than replaced, because both
drawings and every one of their helpers hold a reference to that array and a
new one would leave half the program painting in the colours of the theme
before. There is a test that every theme keeps the aerodrome colour more
than forty units of CIELAB from every altitude colour, stated as the
distance rather than as the colour, so that a new theme cannot quietly walk
an aircraft back into the airports.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
Four things about the animated pictures, and the window kept in step with
them.
The aerodromes were amber, and so is an aeroplane at twelve thousand feet.
Sixteen units of CIELAB apart is not two colours, it is one: an aircraft low
over a field was drawn in the field's own colour and neither could be picked
out from the other. They are magenta now, fifty-six units from the nearest
altitude colour, which is what the ramp leaves free once red, amber, green,
cyan and violet have gone on height -- and what an aeronautical chart marks
an aerodrome in anyway. The test states that as the distance rather than as
the colour, so that changing the ramp cannot quietly walk an aircraft back
into the airports.
The height beside an aircraft was the flight level, which is shorter and is
what an aviator reads, but "376" is only a height to somebody who already
knows it is one. It is feet with the unit on it now, rounded to the
twenty-five feet Mode S reports altitude in: a real reading is a multiple of
that and comes through untouched, while a moment interpolated between two
reports stops claiming to know the height to the foot.
The flag of the country of registration now comes off the address block
where no register answered. Taking it from the register's answer alone left
the flag off exactly the aircraft that had nothing else beside them either.
Mexico was missing from the address table while we were in there, which a
receiver in the American southwest notices; two registers independently give
XA- registrations for that block.
And what sort of aircraft it is, which is two facts and not one. What it is
comes off the air: every identification message carries three bits under its
type code saying whether it is light, large, heavy, a rotorcraft, a glider,
a drone or a van on the apron, and that is the only word about what an
aircraft *is* that needs no register. They were being decoded and thrown
away. They are inside the identification frame the log already writes down
in full, so every log this program has ever written has them, including the
ones written before anything here knew to look.
Whether it is military comes off no air at all -- a tanker calls itself
heavy exactly as an airliner does -- and is read from the address block
instead. On one evening here AE07D3 broadcast "heavy" and sat in the United
States military block; the register, asked separately, came back with a
C-17A Globemaster III, tail 90-0534, United States Air Force.
Labels in an animation now behave as the boxes in the window do. One keeps
its place for as long as that place still works and is moved only when
something takes it, which on a real log is about half as many moves as
deciding afresh every frame; the moves that are left are eased over half a
second of playback; and what the next label is laid out against is where a
moving one is going rather than where it has reached. A still has no frame
before it and places its labels exactly as it always did.
The fading was only half done. A label's name faded, because it is drawn in
the aircraft's own colour, but its rows and its flag were fixed colours and
stayed at full brightness -- so the brightest thing on that part of the
picture was the one aeroplane nothing had been heard from. An indexed
picture cannot blend, so the row grey and all twelve flag colours now have
dimmed copies at each of the four fade steps, and the whole box goes
together. A crowded frame, which drops back to the short label, drops the
class and the flag with it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
A callsign is a flight number rather than a leg, and the free registers hold
one route per number, so an aircraft over Arizona kept being handed a hop
between two airports in Texas. Nothing on the air settles it: ADS-B carries
no origin or destination. A commercial schedule service does know, because
it holds the day's actual movements.
Four are wired up and all four are optional: FlightAware AeroAPI,
Flightradar24, OAG and Cirium. Each is asked before the free databases and
each answers for the moment the aircraft was overhead rather than for the
flight number in general, so the leg chosen is the one that was in the air.
With no keys set nothing changes at all: a source with no key is skipped
rather than asked and refused, and the free databases answer as before.
Keys come from the environment and are never written to the settings file,
because a settings file is meant to be copied between machines and pasted
into a message asking for help, and an API key is not. There is a test that
holds that line.
None of the four has been run against its live service, since each wants a
paid account. They were written from the published response shapes and are
tested against those shapes, so each reader finds what it recognises and
returns nothing otherwise: a service that has changed since costs a route
rather than a scan. Cirium's plain departureTime is local and carries no
offset, so the UTC field is preferred where it is there -- reading the local
one as UTC is up to half a day out, which is exactly far enough to pick the
wrong leg of the same number. Reading now happens inside the same guard as
asking, as an answer shaped differently from the documented one is the
failure most likely to actually happen.
And the map. The zoom is now chosen from how wide the picture is rather
than from the area alone, with half again over the width fetched and
averaged down, since a downscaled tile is sharp and an upscaled one is not.
The window fetches a little more world than it shows so panning does not
leave the ground blank, and now fetches that bigger piece at the bigger
piece's own size: rendering it into the window's own pixels and stretching
it back was a fifth of an upscale over the whole map, which is what a sharp
map looks like when it looks blurred. The comment in the fetcher said the
opposite of what the code did, which is how it stayed hidden.
At 1920 by 1080 over a hundred miles the tiles now hold about 1.6 times the
pixels the window wants. At 3840 by 2160 the tile budget is reached, the
zoom stops climbing and the map is enlarged after all; a smaller radius buys
the detail back, and somebody else's tile server is not a thing to fetch a
thousand tiles from for one picture. The README says so rather than
implying otherwise.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
Three things asked for, and a fourth found while doing them.
The map looked like a photograph of a map, and did so twice over. The
window fetched at its own pixel size but for a box a third larger in each
direction -- the margin added to stop the ground blinking -- and then cut
the middle out, so every pixel was enlarged by two thirds. It now asks
for enough pixels to cover the bigger box at the window's own detail.
Underneath that, both the window and the animation took the nearest source
pixel: the tile mosaic is commonly half again the size of the picture, so
most of every tile was thrown away and what survived was the aliasing.
Both now average the source pixels that fall in each output cell, done as
the difference of a running total rather than a loop.
An aircraft that goes quiet now fades instead of vanishing. Taking it off
between one frame and the next says it stopped existing; fading says it
stopped talking, which is what happened. It fades where it was last
actually seen and never along a reckoned track, because the reason for
giving up on it is that where it would be by now is a guess. --fade sets
how long, and it is in the menu. The window has alpha and fades smoothly;
an indexed picture cannot blend, so the animation gained a fourth ramp at
a seventh of full and fades in four steps, which at a second apart reads
as a fade. A trail fades with the aircraft it belongs to, and the box
goes before the symbol does.
The aircraft's country of registration carries a flag now as well as the
two ends of its route, from the register where one answered and from the
address block otherwise.
And the fourth: the window's header counted an aircraft that had gone
quiet as overhead, which was saying more than had been heard.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
The terminal board says what is overhead. This says where: a real map
with the aircraft moving on it as the frames arrive, and beside each one a
box carrying everything known about the flight -- type and registration,
who operates it, where it came from and where it is going, height with a
rate of climb, speed and heading, how far away and on what bearing, its
position, how many frames it has sent and how long since the last one.
Qt is asked for and not required. Four bindings are tried, the module
imports on a machine with none of them, and asking for the window without
one gets the instructions rather than a traceback -- before the receiver
is opened, since nothing is gained by taking the dongle for a window that
cannot be drawn.
In the menu, "listen now" is now "passive capture" with a realtime
display beside it. Closing the window leaves exactly the files pressing
control-C leaves, because listen and watch share one read loop and one
finishing step; the receiver runs on its own thread, so a slow repaint
cannot cost a frame and a slow tile fetch cannot stall the picture.
The animation's labels grew to match: flight level and speed, type and
registration, and both ends of the route, each with a small flag of the
country its airport is in. The flags are a table rather than a network --
twelve pixels by eight, where a flag is the arrangement that makes one
recognisable rather than a rendering of the real thing -- and a country
not in the table is named by its two letters, since a flag that is nearly
another country's is worse than none. Where a route arrives as bare
codes the country comes from the ICAO prefix.
Four things found on the way. The window ignored --seconds, so "listen
for ten minutes" meant something different with a window open; it closes
itself now. The register was being asked twice per aircraft, once for
labels and once for airport positions. Cached routes had no country in
them, so the first real redraw drew no flags at all -- routes are
versioned now. And past fourteen aircraft on one frame the labels go
back to the callsign, the height and the speed, because five lines beside
each of three hundred aircraft is a page of overlapping text with a map
somewhere behind it.
Long names are folded rather than allowed to stretch a box, breaking at
the arrow of a route so the two ends stay whole; and the animation's
label placement gained the same ring search the window uses, having only
ever tried four spots.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg