feat: SFO, LAX, both bridges, a road that reads as a road, and aeroplanes that move
**The aeroplanes were stuck because the wire could not describe motion.** `WireAircraft` carried position, altitude and heading and nothing else, so the client could only interpolate between the last two observations: every aircraft replayed a segment it had already flown, arrived at the newest known point, and sat still until the next poll landed five to fifteen seconds later. The feed had the missing numbers the whole time and the server threw them away. Sampled live from `api.adsb.lol/v2/point` while writing this — `gs` ground speed, `track`, `baro_rate`, plus `r` registration and `t` type designator. They are on the wire now in SI, aircraft dead-reckon along their own track and correct toward the truth when a fix lands, and the click card an anonymous visitor gets says "B739 · N68834". That last part is the enrichment FR24 was wanted for, obtained from an ODbL feed we may actually republish. **SFO and LAX exist.** A new `engine/airports.ts` composes an airport from runways, taxiways, aprons and terminal masses, with markings drawn on a canvas rather than modelled; the pattern of the runways is what the eye recognises from altitude, long before any building does. SFO is the two crossing pairs on the bay fill; LAX is the four parallels either side of the terminal horseshoe, plus the Southland fields under the traffic that actually flies there. **The Golden Gate and the Bay Bridge are those bridges.** One kit in `engine/bridges.ts`, because a suspension bridge is a repeated tower, a catenary main cable, a series of hangers and a deck — so both are configurations rather than two private implementations. The Bay Bridge carries the real 2013 topology: two suspension towers west of Yerba Buena, one east, then the piered causeway. The freeway stopped being a wireframe overlay and became a road, with shoulders, a median, and lane markings as texture. **And the board got faster while all of that landed.** California went from 728,744 triangles and 562 draw calls to 391,169 and 371 — headroom from 2.8% to 47.8%. The Bay Area board is 506,550 triangles lighter than before this work. Two things paid for it: - `transmission: 0.08` on the aircraft cockpit glass. three.js runs a full transmission backdrop pass whenever any rendered material has transmission above zero, re-drawing the entire opaque scene into a second target every frame — so the city was rendering terrain, every block and every freeway piece TWICE. Measured by patching only that number in a copy of the built bundle: 703,267 tris / 562 draws with it, 398,608 / 371 without. The material was already `transparent: true, opacity: 0.86`, so it was buying nothing. - Flatness-adaptive terrain LOD, which collapses runs of lattice cells wherever the height and colour agree with the quad replacing them. The coastline is provably untouched — a patch collapses only when every point is on land and agrees about `park` — and a test asserts the drawn footprint matches the cell-by-cell area to 1e-6. `createTerrain` got *faster*: the vertices it stops emitting cost more than the flatness scan costs to run. **The budget now watches the boards this was built on.** There was no `bay-area` or `socal` cell — so SFO, LAX and both bridges all landed in frames nothing measured, which is how a cap you do not have looks from the inside. Both are in the matrix now with caps set from measurement, and the rationale lives in the harness because JSON cannot hold a comment. Two known defects ship with this, both recorded in TODO.md rather than hidden: - `bay-area.desktop` drops about one frame in twenty (p50 16.7, p95 33.3). It is desktop-only and not fill rate — mobile runs the same 2.26 M triangles at a comparable pixel count and holds 16.7 flat — which points at the 2048 shadow map desktop uses against handheld's 1024. Measured at the commit before this work with the same harness: identical p95 33.3. Pre-existing, and invisible until the cell existed. - The aeroplane glyph is still about 1.5x the Golden Gate's main span at chapter zoom, down from 2.5x. `GLYPH_MAX_SCALE` is 52 because the raw scale at the far end of the California orbit is 51.0 at a 60-degree field of view, and 26 — tried first — put the glyph at 0.0123 of the frame against the 0.012 where the wings stop resolving. The real fix is to clamp against the camera's focus distance rather than the aircraft's, which is a signature change. Tests 1020 -> 1137. Typecheck, build, eight budget cells, no-binaries, provenance, zero-config boot, dependency licences, arena source hashes and the UI smoke across two viewports and two access tiers all pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+290
-40
@@ -44,6 +44,7 @@
|
||||
* nothing there but water and the flanks of two mountain ranges.
|
||||
*/
|
||||
|
||||
import type { Airport } from "../engine/airports.ts";
|
||||
import type { Bridge, City, District, Hill, Landmark, LatLng } from "../engine/types.ts";
|
||||
|
||||
/**
|
||||
@@ -1222,43 +1223,265 @@ export const MARIN_101: LatLng[] = [
|
||||
[38.012, -122.538],
|
||||
];
|
||||
|
||||
/**
|
||||
* Runways, drawn as roads because that is exactly what they are at this scale:
|
||||
* a pale straight strip laid on flat ground.
|
||||
*
|
||||
* Worth the eight lines. SFO's crossing pairs on their square of fill are the
|
||||
* one shape on the Peninsula's bay edge you can name from ten thousand feet,
|
||||
* and the reason San Jose's downtown is short is standing on the other one.
|
||||
*/
|
||||
export const SFO_RUNWAYS: LatLng[][] = [
|
||||
[
|
||||
[37.6151, -122.36],
|
||||
[37.6229, -122.3948],
|
||||
],
|
||||
[
|
||||
[37.6171, -122.3594],
|
||||
[37.6249, -122.3942],
|
||||
],
|
||||
[
|
||||
[37.633, -122.3709],
|
||||
[37.605, -122.3791],
|
||||
],
|
||||
[
|
||||
[37.6335, -122.3735],
|
||||
[37.6055, -122.3817],
|
||||
],
|
||||
];
|
||||
// ---- Airports -------------------------------------------------------------
|
||||
|
||||
export const SJC_RUNWAYS: LatLng[][] = [
|
||||
[
|
||||
[37.3705, -121.9385],
|
||||
[37.3555, -121.9195],
|
||||
/**
|
||||
* San Francisco International, on the fill at the bay edge below the city.
|
||||
*
|
||||
* The board has had real aircraft over it since the ADS-B layer landed, and
|
||||
* every one of them was descending onto nothing. This is the ground they were
|
||||
* descending onto.
|
||||
*
|
||||
* ## The headings are the whole of it
|
||||
*
|
||||
* SFO is two crossing pairs, and that pattern is its signature from any
|
||||
* altitude a board camera sits at: long before a terminal is a terminal, the
|
||||
* eye reads four bars making an X on a square of fill. So the numbers below
|
||||
* that matter most are the two bearings, and they are **true**, not the
|
||||
* magnetic ones the runways are named after.
|
||||
*
|
||||
* A runway designator is magnetic and rounded to the nearest ten degrees. San
|
||||
* Francisco's declination is about 13.5° east, so "28R" is a runway pointing
|
||||
* **298.6° true** and "1L" one pointing **26.5°**. Building from the painted
|
||||
* numbers instead would lay the whole airport thirteen degrees out and put the
|
||||
* 28s on a heading that misses the city they point at. The two check against
|
||||
* each other and against history: at the ~17° east declination of the years the
|
||||
* designators were assigned, 118.6° true is 101.6° magnetic — "10" — and 26.5°
|
||||
* true is 9.5° magnetic — "01".
|
||||
*
|
||||
* The two pairs are **92.1° apart**, which is the other thing worth being exact
|
||||
* about. SFO crosses at very nearly a right angle; an airfield whose runways
|
||||
* cross at seventy degrees is a different airport, and reads as a generic one.
|
||||
*
|
||||
* ## The relative geometry
|
||||
*
|
||||
* Everything is placed from the airport reference point at 37.6189, −122.3750,
|
||||
* which is what makes the four runways consistent with each other rather than
|
||||
* four independent guesses:
|
||||
*
|
||||
* - **10L/28R** is 11,870 ft (3,618 m). **10R/28L** is 11,381 ft (3,469 m),
|
||||
* 229 m — 750 ft — to its south-south-west. That separation is the famous
|
||||
* one: the closest parallel pair in the United States used for simultaneous
|
||||
* approaches, and the reason every SFO arrival in low cloud is a single-file
|
||||
* arrival. The 28 thresholds sit abeam each other at the shoreline, so the
|
||||
* 149 m 10R/28L gives away comes off its western end.
|
||||
* - **1L/19R** is 7,650 ft (2,332 m). **1R/19L** is 8,650 ft (2,637 m), 213 m
|
||||
* — 700 ft — to its east-south-east. The 01 thresholds sit abeam at the
|
||||
* south end and the extra length runs north.
|
||||
*
|
||||
* The 28 thresholds land ~70 m inside the bay edge traced in `PENINSULA`, which
|
||||
* is not luck: that outline was drawn with "SFO's bay edge — the runways are
|
||||
* built out onto the mud" written on the vertex, and now they are.
|
||||
*
|
||||
* Terminals are **massed rather than surveyed**. The horseshoe is right — the
|
||||
* International Terminal across the west end, Terminals 1 and 3 as the arms
|
||||
* reaching east, Terminal 2 and the garages in the court, the tower in the
|
||||
* middle of it — and it sits in the wedge between the west ends of the 28s and
|
||||
* the south ends of the 01s, which is where SFO's terminals are. Individual
|
||||
* boarding-area fingers are not modelled: at 94 m per scene unit a boarding
|
||||
* area is two pixels, and the aircraft parked against it are not.
|
||||
*/
|
||||
export const SFO: Airport = {
|
||||
id: "KSFO",
|
||||
name: "San Francisco International",
|
||||
lat: 37.6189,
|
||||
lng: -122.375,
|
||||
// 13 ft. Carried because it is a fact about the place; the kit grades the
|
||||
// field onto the terrain rather than lifting it to this, which on a board
|
||||
// exaggerating relief 3.6× would stand SFO fourteen metres above its own
|
||||
// shoreline. See `engine/airports.ts`.
|
||||
elevation: 4,
|
||||
|
||||
/**
|
||||
* The fill, traced to meet `PENINSULA`'s bay edge without crossing it.
|
||||
*
|
||||
* The eastern four lie a few tens of metres inside coastline vertices this
|
||||
* pack already had — the airport is on made ground and its eastern boundary
|
||||
* *is* the shore. The western edge runs a few hundred metres east of US-101,
|
||||
* which is where the fence actually is.
|
||||
*/
|
||||
field: [
|
||||
[37.6425, -122.3782],
|
||||
[37.6398, -122.3592],
|
||||
[37.6232, -122.3548],
|
||||
[37.6072, -122.3576],
|
||||
[37.6048, -122.381],
|
||||
[37.6105, -122.3935],
|
||||
[37.6262, -122.3968],
|
||||
[37.6355, -122.3905],
|
||||
],
|
||||
[
|
||||
[37.3685, -121.9405],
|
||||
[37.3535, -121.9215],
|
||||
|
||||
runways: [
|
||||
// 10L [37.62861, -122.39335] -> 28R [37.61305, -122.35733]
|
||||
{ id: "10L/28R", lat: 37.62083, lng: -122.37534, heading: 118.6, length: 3618, width: 61, designators: ["10L", "28R"] },
|
||||
// 10R [37.62616, -122.39311] -> 28L [37.61124, -122.35857]
|
||||
{ id: "10R/28L", lat: 37.6187, lng: -122.37584, heading: 118.6, length: 3469, width: 61, designators: ["10R", "28L"] },
|
||||
// 1L [37.60783, -122.38525] -> 19R [37.62657, -122.37345]
|
||||
{ id: "1L/19R", lat: 37.6172, lng: -122.37935, heading: 26.5, length: 2332, width: 61, designators: ["1L", "19R"] },
|
||||
// 1R [37.60697, -122.38309] -> 19L [37.62817, -122.36975]
|
||||
{ id: "1R/19L", lat: 37.61757, lng: -122.37642, heading: 26.5, length: 2637, width: 61, designators: ["1R", "19L"] },
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The four outer parallels — A and B outside the 10s, F and Z outside the 01s.
|
||||
*
|
||||
* Typed as coordinates rather than computed here, because a city pack is data
|
||||
* and `airports.ts` imports three.js. `parallelTaxiway()` produced them and
|
||||
* `sfoAirport.test.ts` asserts they still match what it produces, so the
|
||||
* derivation is checked without the pack having to run it.
|
||||
*/
|
||||
taxiways: [
|
||||
{ id: "A", path: [[37.62939, -122.39126], [37.61487, -122.35763]] },
|
||||
{ id: "B", path: [[37.62434, -122.39281], [37.61046, -122.36066]] },
|
||||
{ id: "F", path: [[37.60907, -122.38586], [37.62621, -122.37507]] },
|
||||
{ id: "Z", path: [[37.60711, -122.38091], [37.6267, -122.36858]] },
|
||||
],
|
||||
|
||||
aprons: [
|
||||
// The terminal court and the stands around it, square to the 01s the way
|
||||
// the whole complex is.
|
||||
{
|
||||
id: "terminal",
|
||||
polygon: [
|
||||
[37.61834, -122.37961],
|
||||
[37.62211, -122.38915],
|
||||
[37.61407, -122.39421],
|
||||
[37.6103, -122.38467],
|
||||
],
|
||||
},
|
||||
// The north field: cargo and the maintenance base, and the reason there is
|
||||
// a kilometre and a half of airport north of the 19 thresholds.
|
||||
{
|
||||
id: "north-field",
|
||||
polygon: [
|
||||
[37.6314, -122.3738],
|
||||
[37.63381, -122.37989],
|
||||
[37.62706, -122.38414],
|
||||
[37.62465, -122.37805],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* The horseshoe, and where the aeroplanes go.
|
||||
*
|
||||
* Terminals 1 and 3 are the two arms and they run out to meet the
|
||||
* International Terminal at the closed end, so the complex reads as a U at
|
||||
* the scale it is seen from rather than as five separate slabs. `gates` puts
|
||||
* the stands on the **outside** of the U on all three, which is where SFO's
|
||||
* are: the court inside holds Terminal 2, the garages and the roadway, and
|
||||
* nothing that needs a wingspan.
|
||||
*/
|
||||
terminals: [
|
||||
// Heights are the real ones — a terminal is two or three storeys over a very
|
||||
// large footprint — and they are the numbers to keep even though the board
|
||||
// exaggerates its vertical 3.6× and makes a 26 m building stand ninety
|
||||
// metres tall. Trimming them to compensate would put SFO on a different
|
||||
// vertical scale from every house in San Bruno behind it, and the eye
|
||||
// notices that far sooner than it notices a tall terminal.
|
||||
{ id: "international", lat: 37.61749, lng: -122.39016, length: 600, width: 120, height: 28, heading: 26.5, gates: { count: 6, side: -1 } },
|
||||
{ id: "t3", lat: 37.6187, lng: -122.38559, length: 500, width: 100, height: 17, heading: 116.5, gates: { count: 6, side: -1 } },
|
||||
{ id: "t1", lat: 37.61387, lng: -122.38863, length: 500, width: 100, height: 17, heading: 116.5, gates: { count: 6, side: 1 } },
|
||||
{ id: "t2", lat: 37.61596, lng: -122.3863, length: 300, width: 80, height: 15, heading: 26.5 },
|
||||
{ id: "garages", lat: 37.61516, lng: -122.38427, length: 340, width: 90, height: 21, heading: 26.5 },
|
||||
// The north field, square to the 10s rather than to the terminals, which is
|
||||
// what stops the maintenance base reading as more of the same building. A
|
||||
// widebody hangar is genuinely as tall as a six-storey block.
|
||||
{ id: "maintenance", lat: 37.62806, lng: -122.38135, length: 260, width: 120, height: 25, heading: 118.6 },
|
||||
{ id: "cargo", lat: 37.63013, lng: -122.37715, length: 220, width: 100, height: 14, heading: 118.6, gates: { count: 3, side: 1 } },
|
||||
],
|
||||
|
||||
// No `tower`: this pack draws SFO's as a labelled `Landmark`, because that is
|
||||
// what the minimap reads. See `LANDMARKS` above.
|
||||
};
|
||||
|
||||
/**
|
||||
* Mineta San José, two parallels at the head of the valley.
|
||||
*
|
||||
* Here because it was already on this board as a pair of pale strips and the
|
||||
* kit is what those strips wanted to be — not because the South Bay needs an
|
||||
* airport modelled. Two 11,000 ft runways 700 ft apart on 131.5° true (which
|
||||
* is "12" once the same 13.4° of easterly declination comes off it), the
|
||||
* terminal frontage on the north-east side where Highway 87 runs, and nothing
|
||||
* else: from a camera that can see San Jose at all, SJC is its runways.
|
||||
*
|
||||
* The plate is kept east of −121.946 and between 37.348 and 37.377 on purpose.
|
||||
* That is the gap this pack's districts already leave — `santa-clara` stops at
|
||||
* the airport's west fence, `san-jose-north` above it and `san-jose-downtown`
|
||||
* below — and a field plate that crossed into one of them would have houses
|
||||
* scattered over it.
|
||||
*/
|
||||
export const SJC: Airport = {
|
||||
id: "KSJC",
|
||||
name: "Norman Y. Mineta San José International",
|
||||
lat: 37.3626,
|
||||
lng: -121.9291,
|
||||
elevation: 19,
|
||||
/**
|
||||
* The plate is **asymmetric about the runways** on purpose: it runs 430 m
|
||||
* south-west of the centreline and only 230 m north-east, because this pack's
|
||||
* `BAYSHORE_101` passes about 240 m north-east of runway 12L and a field that
|
||||
* reached past it would have a freeway drawn across the middle of the airport.
|
||||
*
|
||||
* It is also kept east of −121.946 and between 37.348 and 37.377, which is the
|
||||
* gap this pack's districts already leave — `santa-clara` stops at the west
|
||||
* fence, `san-jose-north` above and `san-jose-downtown` below — and a plate
|
||||
* that crossed into one would have houses scattered over it.
|
||||
*/
|
||||
field: [
|
||||
[37.35343, -121.91214],
|
||||
[37.34899, -121.91708],
|
||||
[37.37042, -121.94756],
|
||||
[37.37486, -121.94261],
|
||||
],
|
||||
runways: [
|
||||
// 12L [37.3733, -121.94249] -> 30R [37.35334, -121.91411]
|
||||
{ id: "12L/30R", lat: 37.36332, lng: -121.9283, heading: 131.5, length: 3353, width: 46, designators: ["12L", "30R"] },
|
||||
// 12R [37.37186, -121.94409] -> 30L [37.3519, -121.91571]
|
||||
{ id: "12R/30L", lat: 37.36188, lng: -121.9299, heading: 131.5, length: 3353, width: 46, designators: ["12R", "30L"] },
|
||||
],
|
||||
taxiways: [{ id: "A", path: [[37.37377, -121.94061], [37.35489, -121.91375]] }],
|
||||
aprons: [
|
||||
{
|
||||
id: "terminal",
|
||||
polygon: [
|
||||
[37.36036, -121.92315],
|
||||
[37.3615, -121.92187],
|
||||
[37.36817, -121.93136],
|
||||
[37.36702, -121.93263],
|
||||
],
|
||||
},
|
||||
],
|
||||
// Terminals A and B as one frontage on the north-east side, where Highway 87
|
||||
// and Airport Boulevard run, with the stands facing back at the runways.
|
||||
terminals: [
|
||||
{ id: "ab", lat: 37.3644, lng: -121.9271, length: 620, width: 90, height: 16, heading: 131.5, gates: { count: 7, side: 1 } },
|
||||
],
|
||||
};
|
||||
|
||||
/** Every airport on this board, in the order a pack would list them. */
|
||||
export const AIRPORTS: Airport[] = [SFO, SJC];
|
||||
|
||||
/**
|
||||
* ## Runways are no longer roads
|
||||
*
|
||||
* They were, until this pack got an airport: four hand-typed two-point paths on
|
||||
* *magnetic* headings — thirteen degrees out of true, with the 01/19 pair nearly
|
||||
* nine hundred metres too long — handed to `createRoads` as `kind: "street"`,
|
||||
* because a pale strip on flat ground was as close as the road builder could
|
||||
* get. The kit draws the same centrelines properly, with paint on them, the
|
||||
* fill under them and the terminals beside them, so those entries are gone from
|
||||
* `ROADS` above.
|
||||
*
|
||||
* **The two cannot both be present.** A road ribbon drapes 0.14 units — thirteen
|
||||
* metres at this board's scale — above the terrain and a runway quad sits flush
|
||||
* on it, so a board carrying both floats a dark forty-seven-metre stripe over
|
||||
* every runway on the Peninsula. It was photographed before it was deleted.
|
||||
*
|
||||
* `runwayCentreline()` in `engine/airports.ts` reproduces those paths from the
|
||||
* `SFO` and `SJC` declarations above, if anything ever wants a runway as a line
|
||||
* again.
|
||||
*/
|
||||
|
||||
export const ROADS: City["roads"] = [
|
||||
{ path: MARKET_STREET, width: 0.34, kind: "street" },
|
||||
@@ -1284,8 +1507,6 @@ export const ROADS: City["roads"] = [
|
||||
{ path: COAST_HIGHWAY, width: 0.2, kind: "street" },
|
||||
{ path: HIGHWAY_92, width: 0.2, kind: "street" },
|
||||
{ path: HIGHWAY_84, width: 0.2, kind: "street" },
|
||||
...SFO_RUNWAYS.map((path) => ({ path, width: 0.5, kind: "street" as const })),
|
||||
...SJC_RUNWAYS.map((path) => ({ path, width: 0.45, kind: "street" as const })),
|
||||
];
|
||||
|
||||
// ---- Bridges --------------------------------------------------------------
|
||||
@@ -1513,9 +1734,24 @@ export const LANDMARKS: Landmark[] = [
|
||||
// campus — a building named for a company would put a trademark on the map,
|
||||
// and ARCHITECTURE.md §3.1 is the reason there is not one in this repo.
|
||||
{
|
||||
/**
|
||||
* The airport's tower, and the one piece of SFO that is **not** in `SFO`
|
||||
* below.
|
||||
*
|
||||
* `Airport` has a `tower` field and the kit draws a much better one — a
|
||||
* tapered shaft with a cab on it, in the airport's own palette. It is
|
||||
* deliberately not used here, because this landmark was already on the board
|
||||
* and a landmark is more than a mesh: `label: true` is what puts SFO on the
|
||||
* **minimap**, and `minimap.ts` reads `city.landmarks`, not the airport. Two
|
||||
* towers four hundred metres apart is what you get if you forget that, and
|
||||
* it was photographed before it was noticed.
|
||||
*
|
||||
* Moved to sit in the terminal court with the rest of the complex, which is
|
||||
* where SFO's tower actually stands.
|
||||
*/
|
||||
name: "SFO Control Tower",
|
||||
lat: 37.618,
|
||||
lng: -122.3838,
|
||||
lat: 37.6174,
|
||||
lng: -122.3883,
|
||||
height: 67,
|
||||
footprint: 0.00014,
|
||||
shape: "tower",
|
||||
@@ -2203,10 +2439,15 @@ export const DISTRICTS: District[] = [
|
||||
{
|
||||
id: "santa-clara",
|
||||
name: "Santa Clara",
|
||||
// The east edge stops at Mineta's west fence rather than at the freeway.
|
||||
// Both eastern vertices were 0.004° further east and the corner reached over
|
||||
// the airport's graded plate, which put a wedge of scattered houses across
|
||||
// the north-west end of 12L/30R. Same argument, and same fix, as
|
||||
// `millbrae-burlingame` up at SFO.
|
||||
polygon: [
|
||||
[37.372, -122.0],
|
||||
[37.369, -121.942],
|
||||
[37.34, -121.95],
|
||||
[37.369, -121.946],
|
||||
[37.34, -121.954],
|
||||
[37.343, -122.008],
|
||||
],
|
||||
minHeight: 7,
|
||||
@@ -2693,6 +2934,15 @@ export const SAN_FRANCISCO_CITY: City = {
|
||||
bridges: BRIDGES,
|
||||
roads: ROADS,
|
||||
chapters: CHAPTERS,
|
||||
|
||||
/**
|
||||
* SFO and SJC, drawn by `engine/airports.ts` as graded plates with the real
|
||||
* runway headings on them. The four runways that used to be pale `Road`
|
||||
* strips are gone from `ROADS` above and must stay gone: a road ribbon drapes
|
||||
* thirteen metres over the terrain at this scale, so a board carrying both
|
||||
* would float a dark stripe across every runway the kit lays flush.
|
||||
*/
|
||||
airports: AIRPORTS,
|
||||
};
|
||||
|
||||
export default SAN_FRANCISCO_CITY;
|
||||
|
||||
+579
-39
@@ -30,6 +30,7 @@
|
||||
* show.
|
||||
*/
|
||||
|
||||
import type { Airport } from "../engine/airports.ts";
|
||||
import type {
|
||||
Bridge,
|
||||
City,
|
||||
@@ -834,11 +835,21 @@ export const HILLS: Hill[] = [
|
||||
radius: 0.048,
|
||||
},
|
||||
{
|
||||
// Moved north-east, from 34.205/-118.33 with a 0.04 radius, when Burbank
|
||||
// Airport went onto the board and stood on a hillside. A 700 m peak whose
|
||||
// falloff is 4.4 km across, sited half a kilometre north of runway 08/26,
|
||||
// put 478 m of mountain on the 26 threshold and 191 m on the 08 threshold —
|
||||
// a nine-degree slope across a field that is, in life, flat. It also had
|
||||
// downtown Burbank sitting 165 m up a ramp. The ridge crest above Burbank
|
||||
// really is at about 34.22, and this is where it belongs; the change reads
|
||||
// as the Verdugos ending in the right place rather than leaning on the
|
||||
// Valley floor. `socalAirports.test.ts` holds every field to the relief it
|
||||
// may stand on, so this cannot quietly come back.
|
||||
name: "Mount Thom",
|
||||
lat: 34.205,
|
||||
lng: -118.33,
|
||||
elevation: 700,
|
||||
radius: 0.04,
|
||||
lat: 34.221,
|
||||
lng: -118.318,
|
||||
elevation: 720,
|
||||
radius: 0.036,
|
||||
},
|
||||
{
|
||||
name: "San Rafael Hills",
|
||||
@@ -1235,7 +1246,10 @@ export const I405: LatLng[] = [
|
||||
[34.04, -118.43],
|
||||
[34.01, -118.403],
|
||||
[33.98, -118.39],
|
||||
[33.945, -118.386], // past LAX
|
||||
// Moved east from -118.386 when LAX went onto the board: at that longitude the
|
||||
// freeway ran across the 25R touchdown zone, and the real 405 passes about
|
||||
// three kilometres east of the airport, not through it.
|
||||
[33.945, -118.3765], // past LAX
|
||||
[33.91, -118.372],
|
||||
[33.875, -118.35],
|
||||
[33.85, -118.315],
|
||||
@@ -1247,6 +1261,10 @@ export const I405: LatLng[] = [
|
||||
[33.745, -118.01],
|
||||
[33.72, -117.955],
|
||||
[33.69, -117.9],
|
||||
// Added when John Wayne went onto the board: without it this leg cut the
|
||||
// corner and drew a freeway straight across runway 02L/20R. The real 405
|
||||
// passes about a kilometre north-west of the field and meets the 55 beyond it.
|
||||
[33.6885, -117.87],
|
||||
[33.678, -117.845],
|
||||
[33.66, -117.78],
|
||||
[33.63, -117.7],
|
||||
@@ -1257,7 +1275,13 @@ export const I5: LatLng[] = [
|
||||
[34.32, -118.46],
|
||||
[34.27, -118.42],
|
||||
[34.23, -118.39],
|
||||
[34.19, -118.36],
|
||||
// These two replace a single vertex at 34.19/-118.36, which ran the Golden
|
||||
// State diagonally across Burbank's runway 08/26. The real 5 comes down the
|
||||
// far side of Hollywood Way, north-east of the field — which is why the
|
||||
// airport's north-east corner is cut off the way it is, and why `BUR`'s 08/26
|
||||
// stops 700 m short of the freeway.
|
||||
[34.222, -118.368],
|
||||
[34.196, -118.338],
|
||||
[34.16, -118.335],
|
||||
[34.13, -118.28],
|
||||
[34.105, -118.25],
|
||||
@@ -1561,22 +1585,26 @@ export const KATELLA: LatLng[] = [
|
||||
];
|
||||
|
||||
/**
|
||||
* LAX's two runway complexes, north and south of the terminals.
|
||||
* ## The runways are no longer roads
|
||||
*
|
||||
* Drawn as roads because that is what they are: a fifty-metre-wide paved strip
|
||||
* lying on the ground. Two parallel bars pointing due west at the ocean is the
|
||||
* single most recognisable piece of ground plan on the coastal plain, and it is
|
||||
* three points of data.
|
||||
* `LAX_RUNWAYS_NORTH` and `LAX_RUNWAYS_SOUTH` used to live here: two hand-typed
|
||||
* two-point paths lying on **33.9535 and 33.9405 due east–west**, handed to
|
||||
* `createRoads` as `kind: "street"`, because a pale strip on flat ground was as
|
||||
* close as the road builder could get to an airport. Both numbers were wrong in
|
||||
* the same way. LAX's runways are not due east–west — they run **82.9° true**,
|
||||
* which over three and a half kilometres is four hundred metres of drift the
|
||||
* pair did not have — and there are four of them, not two. `AIRPORTS` below
|
||||
* draws the real ones, with the paint on them, the fill under them and the
|
||||
* horseshoe between them.
|
||||
*
|
||||
* **The two cannot both be present.** A road ribbon drapes 0.14 units above the
|
||||
* terrain — fifty-five metres at this board's scale — while a runway quad sits
|
||||
* flush on it, so a board carrying both floats a dark stripe over every runway
|
||||
* in Westchester. The Bay Area pack hit this first and photographed it.
|
||||
*
|
||||
* `runwayCentreline()` in `engine/airports.ts` reproduces a runway as a
|
||||
* two-point path, if anything ever wants one as a line again.
|
||||
*/
|
||||
export const LAX_RUNWAYS_NORTH: LatLng[] = [
|
||||
[33.9535, -118.434],
|
||||
[33.9535, -118.402],
|
||||
];
|
||||
|
||||
export const LAX_RUNWAYS_SOUTH: LatLng[] = [
|
||||
[33.9405, -118.434],
|
||||
[33.9405, -118.402],
|
||||
];
|
||||
|
||||
export const ROADS: City["roads"] = [
|
||||
{ path: I405, width: 0.14, kind: "freeway" },
|
||||
@@ -1597,8 +1625,6 @@ export const ROADS: City["roads"] = [
|
||||
{ path: VENTURA_BLVD, width: 0.08, kind: "street" },
|
||||
{ path: COLORADO_BLVD, width: 0.08, kind: "street" },
|
||||
{ path: KATELLA, width: 0.08, kind: "street" },
|
||||
{ path: LAX_RUNWAYS_NORTH, width: 0.16, kind: "street" },
|
||||
{ path: LAX_RUNWAYS_SOUTH, width: 0.16, kind: "street" },
|
||||
];
|
||||
|
||||
// ---- Bridges --------------------------------------------------------------
|
||||
@@ -1608,13 +1634,13 @@ export const ROADS: City["roads"] = [
|
||||
* worth the geometry — nothing else in the metro spans water rather than
|
||||
* freeway.
|
||||
*
|
||||
* A caveat for whoever renders these: `structures.ts` sizes bridge members in
|
||||
* scene units — a 0.25-unit deck radius, 0.34-unit towers — and those constants
|
||||
* were tuned at San Francisco's 94 m per unit. At 391 they come out about four
|
||||
* times too heavy, so both of these render chunkier than life. They are kept
|
||||
* because the port is one of the three or four silhouettes that say Southern
|
||||
* California from above, and a heavy bridge still reads as a bridge. Making the
|
||||
* members scale-relative belongs in `structures.ts`, not here.
|
||||
* A caveat for whoever renders these. `bridges.ts` now sizes members in metres
|
||||
* over metres-per-unit rather than in the fixed scene-unit constants that were
|
||||
* tuned at San Francisco's 94 m per unit, so these are no longer four times too
|
||||
* heavy — but the legibility floor under that arithmetic still is a floor, and
|
||||
* at 391 m per unit it is what makes this pair read a little chunkier than life.
|
||||
* They are kept because the port is one of the three or four silhouettes that
|
||||
* say Southern California from above.
|
||||
*/
|
||||
|
||||
/** The Vincent Thomas, over the main channel. Green, and suspension. */
|
||||
@@ -1661,6 +1687,439 @@ export const LONG_BEACH_GATEWAY: Bridge = {
|
||||
|
||||
export const BRIDGES = [VINCENT_THOMAS, LONG_BEACH_GATEWAY];
|
||||
|
||||
// ---- Airports -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The Southland fields, and why these six.
|
||||
*
|
||||
* ## The headings, first, because they are the whole of the recognition
|
||||
*
|
||||
* A runway designator is **magnetic** and rounded to the nearest ten degrees.
|
||||
* Los Angeles's declination is about 11.8° east, so a runway painted "25" is
|
||||
* pointing somewhere near 262° true and one painted "16" near 172°. Building
|
||||
* from the painted numbers lays a whole airport twelve degrees out of true —
|
||||
* over LAX's longest runway that is seven hundred metres of drift — so every
|
||||
* `heading` below is a **true** bearing and every one of them is checked against
|
||||
* its designator in `socalAirports.test.ts`.
|
||||
*
|
||||
* Only LAX gets its bearing from a surveyed figure. The other five are
|
||||
* `designator × 10 + 11.8°`, which is accurate to about half of the five degrees
|
||||
* the rounding already allows and is invisible at 391 m to the scene unit. That
|
||||
* is stated rather than hidden: it is the difference between a number that was
|
||||
* looked up and a number that was derived, and the next person deserves to know
|
||||
* which is which.
|
||||
*
|
||||
* ## Six, and the ones that were left out
|
||||
*
|
||||
* The live ADS-B layer over this board carries a hundred and sixty-odd aircraft
|
||||
* in the middle of a weekday. Sampled at 02:40 Pacific — which is what the feed
|
||||
* would give me while this was written, and is therefore a thin sample rather
|
||||
* than a survey — twenty-two aircraft were airborne over the basin and six of
|
||||
* the eleven flying below eight thousand feet near any field were in LAX's
|
||||
* pattern, with Van Nuys and Burbank next. That ordering matches the annual
|
||||
* operations counts, which is what actually decided the list: LAX at ~700,000
|
||||
* movements, Van Nuys at ~220,000 (the busiest general-aviation field in the
|
||||
* world), John Wayne and Long Beach around ~300,000 each with their flight
|
||||
* schools, Burbank ~130,000, Ontario ~70,000 but the region's freight door.
|
||||
*
|
||||
* Deliberately absent, and all of them real airports: **Santa Monica**, whose
|
||||
* single 3,500 ft strip disappears into the Westside grid at this scale;
|
||||
* **Chino**, nine kilometres from Ontario, which would read as a smudge beside
|
||||
* it; **Torrance**, **Hawthorne**, **Fullerton**, **El Monte** and **Whiteman**,
|
||||
* which are one short runway each; and **March Air Reserve Base**, whose
|
||||
* 13,300 ft runway is the second longest in Southern California but sits three
|
||||
* kilometres from the eastern edge of the board with thirty thousand movements a
|
||||
* year. An airport nobody flies into is scenery, and scenery costs triangles.
|
||||
*
|
||||
* ## Every one of them is a hole cut in a district
|
||||
*
|
||||
* `blocks.ts` has never heard of an airport. It scatters lots across a district
|
||||
* polygon and the only thing that keeps houses off a runway is the polygon
|
||||
* stopping short. Four of these — LAX, Van Nuys, John Wayne and the western half
|
||||
* of Burbank — sit on a district edge and are cut out with a notch. Long Beach
|
||||
* and Ontario sit in the middle of continuously built ground, so each is a hole
|
||||
* reached by a **narrow corridor** to the nearest district edge: Cherry Avenue
|
||||
* north out of Long Beach, Haven Avenue south out of Ontario. The corridor
|
||||
* costs one column of lots, which at 164 m to the lot reads as the six-lane
|
||||
* arterial that is genuinely there. `socalAirports.test.ts` sweeps the whole of
|
||||
* every field against every district and every park, because checking the
|
||||
* corners is what lets a runway keep a housing tract in the middle of it.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Los Angeles International: four parallels in two pairs, either side of the
|
||||
* horseshoe.
|
||||
*
|
||||
* From the altitude this board is looked at, LAX **is** that pattern — two long
|
||||
* bars, a gap with buildings in it, two more long bars — and it is as
|
||||
* recognisable as the Hollywood sign. Everything below is placed as a metre
|
||||
* offset from the airport reference point at 33.9425, −118.4081 and converted,
|
||||
* rather than typed as four independent thresholds, because four hand-typed
|
||||
* pairs of coordinates will not be consistent with each other and the
|
||||
* consistency is the shape.
|
||||
*
|
||||
* ### The bearing, and how the numbers check out
|
||||
*
|
||||
* All four runways are on **82.9° true**. That single number is why the whole
|
||||
* field is drawn from one frame, and it survives two independent checks.
|
||||
* Subtract the 11.8° east declination and it is 71.1° magnetic, which rounds to
|
||||
* **07** — and the south pair is 07L/25R and 07R/25L. The FAA does not allow
|
||||
* four parallels to share a number, so the north pair takes the next one down
|
||||
* and is 06L/24R and 06R/24L, which is why LAX has runways called both 24 and
|
||||
* 25 lying exactly parallel to each other. Any reading that makes the 24s a
|
||||
* different bearing from the 25s is wrong about LAX.
|
||||
*
|
||||
* ### The relative geometry
|
||||
*
|
||||
* Lateral offsets are from the reference point, positive to the south:
|
||||
*
|
||||
* - **06L/24R** at −853 m, 8,926 ft (2,721 m) long. **06R/24L** 213 m — 700 ft
|
||||
* — south of it, 10,285 ft (3,135 m).
|
||||
* - **07L/25R** at +610 m, 12,091 ft (3,685 m) and the longest on the field.
|
||||
* **07R/25L** 244 m — 800 ft — south of it, 11,095 ft (3,382 m).
|
||||
*
|
||||
* That leaves 1,250 m of airport between 24L and 25R, and the horseshoe is what
|
||||
* fills it: the Tom Bradley International Terminal closing the west end across
|
||||
* the axis, Terminals 1–3 as the north arm and 4–8 as the south arm, the parking
|
||||
* structures in the court. `gates` puts the stands on the **outside** of both
|
||||
* arms, which is where LAX's are — the court holds roadway and cars and nothing
|
||||
* that needs a wingspan.
|
||||
*
|
||||
* Terminal heights are the real ones. The board exaggerates its vertical 3.4×
|
||||
* and makes a 17 m concourse stand fifty-eight metres tall; trimming that would
|
||||
* put the airport on a different vertical scale from every house in Westchester
|
||||
* behind it, and the eye notices the mismatch long before it notices a tall
|
||||
* terminal.
|
||||
*
|
||||
* No `tower` is declared: this pack draws LAX's as a labelled `Landmark`,
|
||||
* because `label: true` is what puts the airport on the minimap and
|
||||
* `minimap.ts` reads `city.landmarks` rather than `city.airports`.
|
||||
*/
|
||||
export const LAX: Airport = {
|
||||
id: "KLAX",
|
||||
name: "Los Angeles International",
|
||||
lat: 33.9425,
|
||||
lng: -118.4081,
|
||||
// 125 ft. Carried because it is a fact about the place; the kit grades the
|
||||
// field onto the terrain rather than lifting it to this. See
|
||||
// `engine/airports.ts`.
|
||||
elevation: 38,
|
||||
|
||||
/**
|
||||
* The property, and it is **square to Westchester rather than to the
|
||||
* runways**, which is the detail that makes LAX look like LAX from above: a
|
||||
* cardinal rectangle with a pattern seven degrees off it inside. Westchester
|
||||
* Parkway is the north fence, Imperial Highway the south, Aviation Boulevard
|
||||
* the east, and the dunes above Dockweiler the west.
|
||||
*/
|
||||
field: [
|
||||
[33.9545, -118.433],
|
||||
[33.9545, -118.382],
|
||||
[33.931, -118.382],
|
||||
[33.931, -118.433],
|
||||
],
|
||||
|
||||
runways: [
|
||||
// 06L [33.94845, -118.42526] -> 24R [33.95147, -118.39602]
|
||||
{ id: "06L/24R", lat: 33.94996, lng: -118.41064, heading: 82.9, length: 2721, width: 46, designators: ["06L", "24R"] },
|
||||
// 06R [33.94636, -118.42685] -> 24L [33.94984, -118.39317]
|
||||
{ id: "06R/24L", lat: 33.9481, lng: -118.41001, heading: 82.9, length: 3135, width: 46, designators: ["06R", "24L"] },
|
||||
// 07L [33.93515, -118.42571] -> 25R [33.93925, -118.38611]
|
||||
{ id: "07L/25R", lat: 33.9372, lng: -118.40591, heading: 82.9, length: 3685, width: 61, designators: ["07L", "25R"] },
|
||||
// 07R [33.93311, -118.42417] -> 25L [33.93687, -118.38783]
|
||||
{ id: "07R/25L", lat: 33.93499, lng: -118.406, heading: 82.9, length: 3382, width: 61, designators: ["07R", "25L"] },
|
||||
],
|
||||
|
||||
/**
|
||||
* The four outer parallels, B and C on the north complex and D and E on the
|
||||
* south.
|
||||
*
|
||||
* Typed as coordinates rather than computed here, because a city pack is data
|
||||
* and `airports.ts` imports three.js. `parallelTaxiway()` produced them and
|
||||
* `socalAirports.test.ts` asserts they are still what it produces, so the
|
||||
* derivation is checked without the pack having to run it.
|
||||
*/
|
||||
taxiways: [
|
||||
{ id: "B", path: [[33.94989, -118.42449], [33.95271, -118.39719]] },
|
||||
{ id: "C", path: [[33.94521, -118.4257], [33.94849, -118.39395]] },
|
||||
{ id: "D", path: [[33.9365, -118.42493], [33.94039, -118.38727]] },
|
||||
{ id: "E", path: [[33.93188, -118.423], [33.93543, -118.3886]] },
|
||||
],
|
||||
|
||||
aprons: [
|
||||
{ id: "terminal", polygon: [[33.94524, -118.41833], [33.94709, -118.4005], [33.9396, -118.39937], [33.93776, -118.41721]] },
|
||||
// The Imperial Cargo Complex, on the south side under the 25L approach.
|
||||
{ id: "cargo", polygon: [[33.93628, -118.39298], [33.937, -118.386], [33.9337, -118.3855], [33.93298, -118.39248]] },
|
||||
{ id: "maintenance", polygon: [[33.94571, -118.43051], [33.94631, -118.42471], [33.94354, -118.4243], [33.94294, -118.4301]] },
|
||||
],
|
||||
|
||||
terminals: [
|
||||
{ id: "tbit", lat: 33.94192, lng: -118.41369, length: 560, width: 130, height: 30, heading: 352.9, gates: { count: 8, side: -1 } },
|
||||
{ id: "north-arm", lat: 33.94517, lng: -118.4085, length: 850, width: 85, height: 17, heading: 82.9, gates: { count: 8, side: -1 } },
|
||||
{ id: "south-arm", lat: 33.93989, lng: -118.40705, length: 950, width: 85, height: 17, heading: 82.9, gates: { count: 9, side: 1 } },
|
||||
// The central terminal area's parking structures, as three blocks rather
|
||||
// than one. A single 700 m mass filled the court, and a filled court is not
|
||||
// a horseshoe — the U only reads because there is a gap with something
|
||||
// smaller in it.
|
||||
{ id: "parking-west", lat: 33.94221, lng: -118.41089, length: 230, width: 120, height: 20, heading: 82.9 },
|
||||
{ id: "parking-centre", lat: 33.94246, lng: -118.40853, length: 230, width: 120, height: 20, heading: 82.9 },
|
||||
{ id: "parking-east", lat: 33.9427, lng: -118.40617, length: 230, width: 120, height: 20, heading: 82.9 },
|
||||
// The west maintenance base, square to the runways rather than to the
|
||||
// horseshoe, which is what stops it reading as more of the same building.
|
||||
{ id: "maintenance", lat: 33.94456, lng: -118.42761, length: 280, width: 130, height: 26, heading: 82.9 },
|
||||
{ id: "cargo", lat: 33.93492, lng: -118.3895, length: 400, width: 110, height: 14, heading: 82.9, gates: { count: 4, side: -1 } },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Hollywood Burbank, in the gap between the Verdugos and the Valley floor.
|
||||
*
|
||||
* Two runways crossing at seventy degrees, which is the shape here: 15/33 is the
|
||||
* long one running down out of the Verdugo gap, 08/26 is the short one along the
|
||||
* north fence, and they cross west of the terminal. Everything at Burbank is
|
||||
* small — 6,886 ft and 5,802 ft, a terminal that is genuinely two storeys — and
|
||||
* that is the point of drawing it beside LAX rather than instead of it.
|
||||
*
|
||||
* The bearings are the designators plus the 11.8° east declination: 161.8° and
|
||||
* 91.8° true. See the section comment.
|
||||
*/
|
||||
export const BUR: Airport = {
|
||||
id: "KBUR",
|
||||
name: "Hollywood Burbank",
|
||||
lat: 34.2007,
|
||||
lng: -118.3585,
|
||||
elevation: 237,
|
||||
/**
|
||||
* Held inside 34.190–34.2115 and −118.3735 to −118.349 on purpose: that is the
|
||||
* gap `van-nuys` and `burbank` were reshaped to leave, and a field that
|
||||
* crossed into either would have tract houses on the runway.
|
||||
*/
|
||||
/**
|
||||
* Both diagonals are the fence, not tidiness. The **north-east** cut is
|
||||
* Hollywood Way and the Golden State beyond it: I-5 passes about 700 m
|
||||
* north-east of the 26 threshold, and a square corner there put a freeway
|
||||
* ribbon across the runway. The **south-west** cut is the Burbank industrial
|
||||
* quarter, which is city and not airport, and every square metre of field that
|
||||
* is not holding a runway up is a square metre of plate standing proud of the
|
||||
* ground at the low end — see `Mount Thom` in `HILLS` for what that cost here.
|
||||
*/
|
||||
field: [
|
||||
[34.2108, -118.3715],
|
||||
[34.2108, -118.361],
|
||||
[34.205, -118.3505],
|
||||
[34.1915, -118.3505],
|
||||
[34.1915, -118.36],
|
||||
[34.2, -118.3715],
|
||||
],
|
||||
runways: [
|
||||
// 15 [34.20993, -118.3638] -> 33 [34.19201, -118.35668]
|
||||
{ id: "15/33", lat: 34.20097, lng: -118.36024, heading: 161.8, length: 2099, width: 46, designators: ["15", "33"] },
|
||||
// 08 [34.20526, -118.37082] -> 26 [34.20476, -118.35162]
|
||||
{ id: "08/26", lat: 34.20501, lng: -118.36122, heading: 91.8, length: 1769, width: 46, designators: ["08", "26"] },
|
||||
],
|
||||
taxiways: [
|
||||
{ id: "A", path: [[34.20955, -118.36205], [34.19317, -118.35554]] },
|
||||
{ id: "C", path: [[34.20407, -118.37], [34.20362, -118.35253]] },
|
||||
],
|
||||
aprons: [{ id: "terminal", polygon: [[34.20032, -118.35469], [34.19716, -118.35343], [34.19643, -118.35612], [34.19959, -118.35737]] }],
|
||||
// Terminals A and B as one frontage east of 15/33, where Hollywood Way runs,
|
||||
// with the stands facing back at the runway.
|
||||
terminals: [
|
||||
{ id: "ab", lat: 34.1985, lng: -118.35524, length: 340, width: 70, height: 12, heading: 161.8, gates: { count: 6, side: 1 } },
|
||||
{ id: "cargo", lat: 34.20366, lng: -118.35383, length: 260, width: 80, height: 13, heading: 91.8 },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Van Nuys: two parallels down the middle of the Valley, and no airline at all.
|
||||
*
|
||||
* It is on this board because it is the busiest general-aviation airport in the
|
||||
* world and because the aircraft over the Valley are largely its — not because
|
||||
* anything about it is famous. So it is drawn as what it is: a long thin field
|
||||
* with an 8,000 ft runway, a 4,000 ft one beside it, and hangar rows down the
|
||||
* east side instead of a terminal. No `gates` anywhere on it, because the kit
|
||||
* parks airliners and nothing that lives here is one.
|
||||
*
|
||||
* The north fence is pulled in to 34.227 — Van Nuys really reaches Roscoe at
|
||||
* 34.232 — because `north-valley` starts at 34.2316 at this longitude and a
|
||||
* field that crossed it would have houses on runway 16R.
|
||||
*/
|
||||
export const VNY: Airport = {
|
||||
id: "KVNY",
|
||||
name: "Van Nuys",
|
||||
lat: 34.2098,
|
||||
lng: -118.4899,
|
||||
elevation: 244,
|
||||
// Trimmed in at the north and west from 34.227/-118.499 — Van Nuys really does
|
||||
// reach Roscoe — because the Valley floor rises about a metre in a hundred
|
||||
// across this field and the kit grades a plate to the highest ground it
|
||||
// covers. Every metre of field that is not holding a runway up is a metre of
|
||||
// lip standing proud at the low end. What is left spans 33 m.
|
||||
field: [
|
||||
[34.2235, -118.4955],
|
||||
[34.2235, -118.481],
|
||||
[34.1975, -118.481],
|
||||
[34.1975, -118.4955],
|
||||
],
|
||||
runways: [
|
||||
// 16R [34.22064, -118.49298] -> 34L [34.19896, -118.4892]
|
||||
{ id: "16R/34L", lat: 34.2098, lng: -118.49109, heading: 171.8, length: 2439, width: 46, designators: ["16R", "34L"] },
|
||||
// 16L [34.2121, -118.48971] -> 34R [34.20122, -118.48781]
|
||||
{ id: "16L/34R", lat: 34.20666, lng: -118.48876, heading: 171.8, length: 1223, width: 23, designators: ["16L", "34R"] },
|
||||
],
|
||||
taxiways: [{ id: "A", path: [[34.22011, -118.49135], [34.19985, -118.48782]] }],
|
||||
/**
|
||||
* The east ramp runs the whole length of the field, Saticoy to Sherman Way,
|
||||
* which is what Van Nuys's east side is. It is drawn that long for a second
|
||||
* reason as well: `airports.ts` grades the field to the highest of the
|
||||
* airport's own authored coordinates, and an apron corner is one of them. The
|
||||
* Valley floor's high point inside this fence is under the middle of this
|
||||
* ramp, so a short ramp graded the plate to ground lower than the ground it
|
||||
* covers. See the note on `FIELD_LIFT` in the section comment.
|
||||
*/
|
||||
aprons: [{ id: "east-ramp", polygon: [[34.21511, -118.48797], [34.19991, -118.48532], [34.2004, -118.48124], [34.2156, -118.48389]] }],
|
||||
terminals: [
|
||||
{ id: "east-hangars", lat: 34.20872, lng: -118.48523, length: 780, width: 90, height: 14, heading: 171.8 },
|
||||
{ id: "west-hangars", lat: 34.21411, lng: -118.49446, length: 420, width: 80, height: 13, heading: 171.8 },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Long Beach, and the one field on this board that is a genuine X.
|
||||
*
|
||||
* 12/30 runs 10,003 ft south-east across the whole property and the 08s cross
|
||||
* it near their western ends, which is what gives Long Beach the crossed-strip
|
||||
* plan that reads from any altitude. The terminal is the small 1941 one on the
|
||||
* south-west side; the very large building on the north fence is the old
|
||||
* Douglas plant, which is a real 420 m shed and the largest single mass on the
|
||||
* field.
|
||||
*
|
||||
* Bearings are the designators plus declination: 131.8° and 91.8° true.
|
||||
*/
|
||||
export const LGB: Airport = {
|
||||
id: "KLGB",
|
||||
name: "Long Beach",
|
||||
lat: 33.8177,
|
||||
lng: -118.1516,
|
||||
elevation: 18,
|
||||
/**
|
||||
* The south-west corner is cut off, and that is not tidiness: **Signal Hill**
|
||||
* is 111 m of real oil-field hill 1.9 km south-west of the airport, and a
|
||||
* rectangle reaching -118.169 at 33.8055 put its flank inside the field. The
|
||||
* kit grades a field to the highest ground it covers, so that one corner
|
||||
* lifted the whole plate a hundred metres and stood Long Beach Airport on a
|
||||
* table. Cut back, the field spans 21 m of relief and lies flat.
|
||||
*/
|
||||
field: [
|
||||
[33.8305, -118.1665],
|
||||
[33.8305, -118.1375],
|
||||
[33.8065, -118.1375],
|
||||
[33.8065, -118.148],
|
||||
[33.816, -118.1665],
|
||||
],
|
||||
runways: [
|
||||
// 12 [33.82683, -118.16389] -> 30 [33.80857, -118.13931]
|
||||
{ id: "12/30", lat: 33.8177, lng: -118.1516, heading: 131.8, length: 3049, width: 61, designators: ["12", "30"] },
|
||||
// 08L [33.823, -118.16018] -> 26R [33.82246, -118.13978]
|
||||
{ id: "08L/26R", lat: 33.82273, lng: -118.14998, heading: 91.8, length: 1887, width: 46, designators: ["08L", "26R"] },
|
||||
// 08R [33.82089, -118.15891] -> 26L [33.82043, -118.14105]
|
||||
{ id: "08R/26L", lat: 33.82066, lng: -118.14998, heading: 91.8, length: 1653, width: 46, designators: ["08R", "26L"] },
|
||||
],
|
||||
taxiways: [
|
||||
{ id: "D", path: [[33.82529, -118.16409], [33.80823, -118.14113]] },
|
||||
{ id: "B", path: [[33.82414, -118.15927], [33.82365, -118.1406]] },
|
||||
],
|
||||
aprons: [{ id: "terminal", polygon: [[33.81745, -118.15694], [33.81356, -118.1517], [33.81041, -118.15509], [33.8143, -118.16033]] }],
|
||||
terminals: [
|
||||
{ id: "terminal", lat: 33.81303, lng: -118.15722, length: 260, width: 60, height: 12, heading: 131.8, gates: { count: 5, side: -1 } },
|
||||
{ id: "douglas", lat: 33.82803, lng: -118.14836, length: 420, width: 160, height: 20, heading: 91.8 },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* John Wayne, pointing north-east at the hills, which is the whole reason
|
||||
* anyone in Newport Beach has an opinion about it.
|
||||
*
|
||||
* 02L/20R is 5,701 ft with the short 02R/20L general-aviation strip beside it,
|
||||
* and the Riley terminal on the south-east side along MacArthur with the stands
|
||||
* facing back across at the runway. On 31.8° true — the designators plus
|
||||
* declination.
|
||||
*/
|
||||
export const SNA: Airport = {
|
||||
id: "KSNA",
|
||||
name: "John Wayne",
|
||||
lat: 33.6757,
|
||||
lng: -117.8682,
|
||||
elevation: 17,
|
||||
/**
|
||||
* Square to the runways rather than to the compass, which is the one field on
|
||||
* this board that is: John Wayne is a diagonal parcel wedged between MacArthur
|
||||
* Boulevard and the 405, and a cardinal rectangle around it left two-thirds of
|
||||
* the plate as empty green with the runways pushed into one corner.
|
||||
*/
|
||||
field: [
|
||||
[33.66833, -117.87686],
|
||||
[33.68513, -117.86435],
|
||||
[33.68073, -117.85582],
|
||||
[33.66393, -117.86833],
|
||||
],
|
||||
runways: [
|
||||
// 02L [33.66907, -117.87379] -> 20R [33.68233, -117.86391]
|
||||
{ id: "02L/20R", lat: 33.6757, lng: -117.86885, heading: 31.8, length: 1738, width: 46, designators: ["02L", "20R"] },
|
||||
// 02R [33.67081, -117.8687] -> 20L [33.67753, -117.8637]
|
||||
{ id: "02R/20L", lat: 33.67417, lng: -117.8662, heading: 31.8, length: 880, width: 23, designators: ["02R", "20L"] },
|
||||
],
|
||||
taxiways: [{ id: "A", path: [[33.66901, -117.87205], [33.68106, -117.86308]] }],
|
||||
aprons: [{ id: "terminal", polygon: [[33.6756, -117.86637], [33.67988, -117.86318], [33.67855, -117.86061], [33.67428, -117.8638]] }],
|
||||
terminals: [
|
||||
{ id: "riley", lat: 33.67866, lng: -117.86356, length: 420, width: 85, height: 16, heading: 31.8, gates: { count: 6, side: -1 } },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Ontario, the freight door, out where the basin runs into the Inland Empire.
|
||||
*
|
||||
* Two long parallels 560 m apart with the passenger terminals and the cargo
|
||||
* ramp between them — which is the layout, and the reason Ontario looks like a
|
||||
* much bigger airport than its passenger numbers suggest. 12,198 ft and
|
||||
* 10,200 ft on 91.8° true.
|
||||
*
|
||||
* It is the only field on this board that had to be reached by a corridor cut
|
||||
* south to the district edge rather than notched from one; see the section
|
||||
* comment.
|
||||
*/
|
||||
export const ONT: Airport = {
|
||||
id: "KONT",
|
||||
name: "Ontario International",
|
||||
lat: 34.056,
|
||||
lng: -117.6012,
|
||||
elevation: 288,
|
||||
field: [
|
||||
[34.063, -117.625],
|
||||
[34.063, -117.577],
|
||||
[34.049, -117.577],
|
||||
[34.049, -117.625],
|
||||
],
|
||||
runways: [
|
||||
// 08L [34.05904, -117.62135] -> 26R [34.058, -117.58105]
|
||||
{ id: "08L/26R", lat: 34.05852, lng: -117.6012, heading: 91.8, length: 3718, width: 61, designators: ["08L", "26R"] },
|
||||
// 08R [34.05392, -117.61642] -> 26L [34.05304, -117.58272]
|
||||
{ id: "08R/26L", lat: 34.05348, lng: -117.59957, heading: 91.8, length: 3109, width: 46, designators: ["08R", "26L"] },
|
||||
],
|
||||
taxiways: [
|
||||
{ id: "A", path: [[34.05776, -117.62031], [34.05677, -117.58218]] },
|
||||
{ id: "B", path: [[34.05515, -117.61528], [34.05433, -117.58376]] },
|
||||
],
|
||||
aprons: [{ id: "terminal", polygon: [[34.05779, -117.60764], [34.05748, -117.59572], [34.05406, -117.59585], [34.05437, -117.60777]] }],
|
||||
terminals: [
|
||||
{ id: "t2-t4", lat: 34.056, lng: -117.60228, length: 700, width: 110, height: 16, heading: 91.8, gates: { count: 8, side: -1 } },
|
||||
{ id: "cargo", lat: 34.05474, lng: -117.5871, length: 500, width: 130, height: 16, heading: 91.8, gates: { count: 5, side: 1 } },
|
||||
],
|
||||
};
|
||||
|
||||
/** Every airport on this board, biggest first. */
|
||||
export const AIRPORTS: Airport[] = [LAX, BUR, VNY, LGB, SNA, ONT];
|
||||
|
||||
// ---- Landmarks ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -1872,16 +2331,24 @@ export const LANDMARKS: Landmark[] = [
|
||||
},
|
||||
|
||||
// ---- LAX ----
|
||||
// Not a building: a two-kilometre pad of apron and terminal, which with the
|
||||
// two runway strips beside it is what actually reads as an airport.
|
||||
// This used to be a flat two-kilometre pad of a landmark standing in for an
|
||||
// airport, beside two runway-shaped roads. `LAX` in `AIRPORTS` draws the real
|
||||
// thing now and the pad would sit on top of its own field, so what is left
|
||||
// here is the one piece of LAX the kit does not draw: the tower, at its real
|
||||
// 277 ft.
|
||||
//
|
||||
// It is a landmark rather than the airport's own `tower` because `label: true`
|
||||
// is what puts LAX on the minimap — `minimap.ts` reads `city.landmarks` and
|
||||
// has never heard of `city.airports`. Declaring both would stand two towers
|
||||
// four hundred metres apart, which is how the Bay Area pack found this out.
|
||||
{
|
||||
name: "LAX",
|
||||
lat: 33.9445,
|
||||
lng: -118.4045,
|
||||
height: 12,
|
||||
footprint: 0.0095,
|
||||
shape: "box",
|
||||
color: 0x76736c,
|
||||
name: "LAX Control Tower",
|
||||
lat: 33.9421,
|
||||
lng: -118.4022,
|
||||
height: 84,
|
||||
footprint: 0.00028,
|
||||
shape: "cylinder",
|
||||
color: 0xc9ccce,
|
||||
label: true,
|
||||
},
|
||||
{
|
||||
@@ -2391,12 +2858,25 @@ export const DISTRICTS: District[] = [
|
||||
},
|
||||
{
|
||||
id: "van-nuys",
|
||||
// Two airports come out of this one polygon. Vertices 3-6 are the notch for
|
||||
// Burbank, cut in from the east boundary; vertices 9-12 are the notch for
|
||||
// Van Nuys, cut in from the west, where the ground it also gives up is the
|
||||
// Sepulveda Basin and already open. `burbank` picks up the eastern strip
|
||||
// that the first notch removes, so nothing is left unbuilt but the fields.
|
||||
name: "Van Nuys & North Hollywood",
|
||||
polygon: [
|
||||
[34.24, -118.5],
|
||||
[34.235, -118.34],
|
||||
[34.2125, -118.3423],
|
||||
[34.2125, -118.3745],
|
||||
[34.189, -118.3745],
|
||||
[34.189, -118.3447],
|
||||
[34.176, -118.346],
|
||||
[34.181, -118.506],
|
||||
[34.194, -118.5047],
|
||||
[34.194, -118.48],
|
||||
[34.229, -118.48],
|
||||
[34.229, -118.5011],
|
||||
],
|
||||
minHeight: 12,
|
||||
maxHeight: 48,
|
||||
@@ -2439,12 +2919,18 @@ export const DISTRICTS: District[] = [
|
||||
},
|
||||
{
|
||||
id: "burbank",
|
||||
// The north-west corner is cut back from -118.368 to -118.348, which is
|
||||
// Hollywood Way and the east fence of the airport. What that leaves out is
|
||||
// the eastern half of Burbank's field; `van-nuys` gives up the western
|
||||
// half, and between them the two polygons leave one clean hole.
|
||||
name: "Burbank",
|
||||
polygon: [
|
||||
[34.212, -118.368],
|
||||
[34.2125, -118.348],
|
||||
[34.206, -118.282],
|
||||
[34.15, -118.29],
|
||||
[34.157, -118.375],
|
||||
[34.189, -118.3709],
|
||||
[34.189, -118.348],
|
||||
],
|
||||
minHeight: 13,
|
||||
maxHeight: 62,
|
||||
@@ -2521,11 +3007,24 @@ export const DISTRICTS: District[] = [
|
||||
},
|
||||
{
|
||||
id: "ontario",
|
||||
// Ontario International, cut out the same way Long Beach is: a hole with a
|
||||
// corridor, here running south to the boundary along Haven Avenue. Nothing
|
||||
// on the eastern half of this board is close enough to a district edge to
|
||||
// notch, and a warehouse district with a runway drawn through it is worse
|
||||
// than one arterial's worth of missing lots.
|
||||
name: "Ontario & Rancho Cucamonga",
|
||||
polygon: [
|
||||
[34.125, -117.69],
|
||||
[34.12, -117.48],
|
||||
[34.015, -117.492],
|
||||
[34.0181, -117.601],
|
||||
[34.0475, -117.601],
|
||||
[34.0475, -117.5755],
|
||||
[34.0645, -117.5755],
|
||||
[34.0645, -117.6265],
|
||||
[34.0475, -117.6265],
|
||||
[34.0475, -117.606],
|
||||
[34.0182, -117.606],
|
||||
[34.021, -117.702],
|
||||
],
|
||||
minHeight: 11,
|
||||
@@ -2571,12 +3070,23 @@ export const DISTRICTS: District[] = [
|
||||
},
|
||||
{
|
||||
id: "inglewood",
|
||||
// The last four vertices are the LAX notch: the polygon runs up the west
|
||||
// boundary, turns in along the airport's south fence, round the east and
|
||||
// north fences, and back out to the boundary. `blocks.ts` has never heard
|
||||
// of an airport, so this notch is the only thing keeping tract houses off
|
||||
// the 25R touchdown zone. The strip it also gives up — between the fence at
|
||||
// -118.433 and the boundary — is the Dockweiler dunes, which are genuinely
|
||||
// unbuilt, and that is why the notch opens west rather than east.
|
||||
name: "Inglewood & Hawthorne",
|
||||
polygon: [
|
||||
[33.985, -118.43],
|
||||
[33.98, -118.32],
|
||||
[33.915, -118.33],
|
||||
[33.92, -118.438],
|
||||
[33.929, -118.4369],
|
||||
[33.929, -118.38],
|
||||
[33.9565, -118.38],
|
||||
[33.9565, -118.4335],
|
||||
],
|
||||
minHeight: 11,
|
||||
maxHeight: 50,
|
||||
@@ -2651,9 +3161,24 @@ export const DISTRICTS: District[] = [
|
||||
},
|
||||
{
|
||||
id: "long-beach",
|
||||
// Long Beach Airport sits three and a half kilometres inside this polygon in
|
||||
// every direction, so it cannot be notched from an edge — it is a hole
|
||||
// reached by a corridor running north to the boundary along Cherry Avenue.
|
||||
// The corridor is 460 m wide and takes about one column of lots with it,
|
||||
// which at 164 m to the lot is what a six-lane arterial looks like here in
|
||||
// any case. Vertices 2-9 walk down the corridor, round the field, and back
|
||||
// up it.
|
||||
name: "Long Beach",
|
||||
polygon: [
|
||||
[33.868, -118.23],
|
||||
[33.8653, -118.166],
|
||||
[33.832, -118.166],
|
||||
[33.832, -118.169],
|
||||
[33.8055, -118.169],
|
||||
[33.8055, -118.136],
|
||||
[33.832, -118.136],
|
||||
[33.832, -118.161],
|
||||
[33.865, -118.161],
|
||||
[33.862, -118.09],
|
||||
[33.752, -118.102],
|
||||
[33.758, -118.24],
|
||||
@@ -2797,12 +3322,20 @@ export const DISTRICTS: District[] = [
|
||||
},
|
||||
{
|
||||
id: "irvine",
|
||||
// John Wayne straddles this polygon's west boundary, so the last four
|
||||
// vertices notch it out from that edge. `newport-beach` stops at about
|
||||
// 33.662 under the field and `santa-ana` starts at 33.705 above it, so this
|
||||
// is the only district the airport touches.
|
||||
name: "Irvine",
|
||||
polygon: [
|
||||
[33.735, -117.865],
|
||||
[33.73, -117.71],
|
||||
[33.63, -117.722],
|
||||
[33.636, -117.877],
|
||||
[33.662, -117.8739],
|
||||
[33.662, -117.854],
|
||||
[33.6935, -117.854],
|
||||
[33.6935, -117.87],
|
||||
],
|
||||
minHeight: 12,
|
||||
maxHeight: 84,
|
||||
@@ -3136,6 +3669,13 @@ export const SOCAL_CITY: City = {
|
||||
inlandWater: INLAND_WATER,
|
||||
hills: HILLS,
|
||||
districts: DISTRICTS,
|
||||
|
||||
/**
|
||||
* The basin's six fields, drawn by `engine/airports.ts`. LAX's runways-as-
|
||||
* roads are gone from `ROADS` above and must stay gone: a board carrying both
|
||||
* floats a dark stripe over every runway the kit lays flush.
|
||||
*/
|
||||
airports: AIRPORTS,
|
||||
landmarks: LANDMARKS,
|
||||
bridges: BRIDGES,
|
||||
roads: ROADS,
|
||||
|
||||
Reference in New Issue
Block a user