mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
fix(awareness): wrap north-bound bearings (#1390)
Wrap awareness bearing and course labels at north and register the formatting helper in package boundaries. Contribution by @rudycelekli.
This commit is contained in:
6 files changed
+30
-2
No files matched your search
@@ -0,0 +1,2 @@
|
||||
- Render awareness-overlay bearings and courses that round through north as
|
||||
`000°`, rather than `360°` (Rudy Celekli, #1390).
|
||||
@@ -4684,6 +4684,7 @@ silently demoting every later lookup for the session.
|
||||
- Selected AIS vessels use their layer-owned full-detail presentation model in the shared world-overlay host; mapped installations promote their own entry to a selected card. Both remain crisp above post-processing without duplicate selected labels; non-selected AIS cards retain their source-owned grid/visibility selection and are host-batched with other world cards.
|
||||
- Space Mission ascent replay uses the compact rocket/thrust overlay only through orbit insertion. Once the replay enters its orbit phase, that vehicle glyph is replaced by a fixed-size cyan dot following the same orbit path and callout.
|
||||
- While a subject is selected, an inner keyhole compass rotates against camera heading and up to three cyan shafted bearing arrows lock to its single faint tick-marked rim, with their labels inset just inside the circle. Labels explicitly separate the geographic bearing (`BRG`) from the contact's reported course (`CRS`) so the pointer direction is not confused with aircraft heading. They point toward the nearest observed/mapped examples; each cohort displays up to ten examples while retaining the complete locally loaded in-range cohort for navigation, with three visible at a time and a ten-second page rotation shared by the panel and arrows. This distinct neutral-context color avoids implying that all context indicators are military-flight symbols. `PREVIOUS`, `FOCUS`, and `NEXT` controls navigate selection history or the next nearby cohort example through the existing tracker. NEXT uses a cycle-scoped visited set and starts a deterministic new walk after exhausting the current candidates instead of re-admitting the nearest visited contact.
|
||||
- Awareness `BRG` and `CRS` labels wrap after rounding to whole degrees, so a direction of 359.5° displays as `000°` rather than `360°`.
|
||||
- Installations are viewport-bounded OSM map features (`military=airfield|naval_base|range|barracks|base` and `landuse=military`), capped to a 10° non-dateline request and 700 upstream features. The proxy caches five minutes and serves a one-hour stale fallback. Empty, stale, unavailable, and zoom-too-wide states remain visibly distinct.
|
||||
- With a selected subject, Contacts hands the installation layer the subject position every refresh. The layer loads a window around the subject (see Installations and map-source guidance), because a follow or Cockpit camera never fires `moveEnd` and often looks at the horizon: a first load from a globe view used to leave the row at "?" for the whole track. The row and the Cockpit scope read `WITHIN 100 KM` instead of `CURRENT VIEWPORT ONLY`, and an empty window reads "none mapped within 100 km; not a complete 250 km survey". `scripts/qa-context-arrivals.mjs` flies synthetic aircraft over Camp Mabry and Fort Cavazos from a wide start, presses CONTACTS, Cockpit and SEARCH NEARBY SITES, and records a clip.
|
||||
- The selected-only visual is one static, unfilled blue circle. It marks the 250 km proximity context window only; it is not coverage or a radar/weapon envelope. Missing broadcasts and unmapped sites are explicitly not evidence of absence.
|
||||
|
||||
@@ -1287,6 +1287,7 @@
|
||||
"src/layers/awareness/navigation.js",
|
||||
"src/layers/awareness/panel.js",
|
||||
"src/layers/awareness/policy.js",
|
||||
"src/layers/awareness/presentation.js",
|
||||
"src/layers/awareness/queries.js",
|
||||
"src/layers/awareness/rendering.js",
|
||||
"src/layers/awareness/state.js",
|
||||
@@ -1944,6 +1945,7 @@
|
||||
"src/layers/awareness/navigation.js",
|
||||
"src/layers/awareness/panel.js",
|
||||
"src/layers/awareness/policy.js",
|
||||
"src/layers/awareness/presentation.js",
|
||||
"src/layers/awareness/queries.js",
|
||||
"src/layers/awareness/rendering.js",
|
||||
"src/layers/awareness/state.js",
|
||||
@@ -2736,6 +2738,7 @@
|
||||
"src/layers/awareness/navigation.js",
|
||||
"src/layers/awareness/panel.js",
|
||||
"src/layers/awareness/policy.js",
|
||||
"src/layers/awareness/presentation.js",
|
||||
"src/layers/awareness/queries.js",
|
||||
"src/layers/awareness/rendering.js",
|
||||
"src/layers/awareness/state.js",
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Format a compass direction for the awareness overlay.
|
||||
* @param {number} degrees
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatAwarenessDirection(degrees) {
|
||||
if (!Number.isFinite(degrees)) return '—';
|
||||
const normalized = ((degrees % 360) + 360) % 360;
|
||||
return String(Math.round(normalized) % 360).padStart(3, '0');
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { formatAwarenessDirection } from './presentation.js';
|
||||
|
||||
test('awareness bearings that round through north read 000, not 360', () => {
|
||||
assert.equal(formatAwarenessDirection(359.4), '359');
|
||||
assert.equal(formatAwarenessDirection(359.6), '000');
|
||||
assert.equal(formatAwarenessDirection(0), '000');
|
||||
assert.equal(formatAwarenessDirection(-0.4), '000');
|
||||
assert.equal(formatAwarenessDirection(Number.NaN), '—');
|
||||
});
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '../../data/militaryAwarenessEngine.js';
|
||||
import { bearingBetweenCoordinates } from '../../cockpitMath.js';
|
||||
import { AWARENESS_PAGE_SIZE, CONTEXT_RIM_HEIGHT_M } from './policy.js';
|
||||
import { formatAwarenessDirection } from './presentation.js';
|
||||
|
||||
export function createRendering({
|
||||
state: layerState,
|
||||
@@ -225,12 +226,12 @@ export function createRendering({
|
||||
: null;
|
||||
const bearingText = Number.isFinite(bearing)
|
||||
? t('BRG {value}°', {
|
||||
value: String(Math.round(bearing)).padStart(3, '0'),
|
||||
value: formatAwarenessDirection(bearing),
|
||||
})
|
||||
: t('BRG —');
|
||||
const courseText = Number.isFinite(item.track)
|
||||
? ` · ${t('CRS {value}°', {
|
||||
value: String(Math.round(item.track)).padStart(3, '0'),
|
||||
value: formatAwarenessDirection(item.track),
|
||||
})}`
|
||||
: '';
|
||||
marker._label.textContent = `${label} · ${formatAwarenessDistance(item.distanceM)}\n${bearingText}${courseText}`;
|
||||
|
||||
Reference in new issue
Block a user