mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(hud): carry rounded DMS seconds into the minutes (#1339)
Carry rounded HUD coordinate seconds into minutes and degrees. Contribution by @rudycelekli.
This commit is contained in:
1 parent
2a17491c8b
commit
a15fdd3134
5 files changed
+123
-6
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
- Carry HUD LAT/LON seconds that round up to 60.00" into the minutes and
|
||||||
|
degrees, so longitude -122.35 reads `122°21'00.00"W` instead of
|
||||||
|
`122°20'60.00"W` (rudycelekli, #1339).
|
||||||
@@ -4,6 +4,12 @@ Docker Compose mounts the checkout with the shared SELinux `:z` label so
|
|||||||
containers can read it on enforcing SELinux hosts. The separate image-owned
|
containers can read it on enforcing SELinux hosts. The separate image-owned
|
||||||
`node_modules` volume and loopback-only port publishing remain unchanged.
|
`node_modules` volume and loopback-only port publishing remain unchanged.
|
||||||
|
|
||||||
|
The HUD's LAT/LON degrees-minutes-seconds readout rounds the coordinate once, to
|
||||||
|
hundredths of a second, and then splits it. A value within 0.005" of the next
|
||||||
|
whole minute carries into the minutes and degrees, so `-122.35` reads
|
||||||
|
`122°21'00.00"W` rather than `122°20'60.00"W`. The field widths and hemisphere
|
||||||
|
letters are unchanged.
|
||||||
|
|
||||||
Aircraft detection candidates reuse normalized display text until callsign or
|
Aircraft detection candidates reuse normalized display text until callsign or
|
||||||
registration changes, including in-place enrichment. Each candidate resolves its
|
registration changes, including in-place enrichment. Each candidate resolves its
|
||||||
fleet model once per collection. Positions, model ownership and tracked-aircraft
|
fleet model once per collection. Positions, model ownership and tracked-aircraft
|
||||||
|
|||||||
@@ -1087,5 +1087,6 @@
|
|||||||
"scripts/qa-status-badges.mjs",
|
"scripts/qa-status-badges.mjs",
|
||||||
"src/dockerTrustedPeers.test.mjs",
|
"src/dockerTrustedPeers.test.mjs",
|
||||||
"src/cameraGlobeRotation.test.mjs",
|
"src/cameraGlobeRotation.test.mjs",
|
||||||
"src/voice/globeResetConfirmation.test.mjs"
|
"src/voice/globeResetConfirmation.test.mjs",
|
||||||
|
"src/hudDms.test.mjs"
|
||||||
]
|
]
|
||||||
+6
-5
@@ -574,11 +574,12 @@ export class IntelHUD {
|
|||||||
* @returns {string} Formatted DMS string, e.g. `"38°53'23.10"N"`.
|
* @returns {string} Formatted DMS string, e.g. `"38°53'23.10"N"`.
|
||||||
*/
|
*/
|
||||||
_toDMS(decimal, type) {
|
_toDMS(decimal, type) {
|
||||||
const abs = Math.abs(decimal);
|
// Round once, in hundredths of a second, so a value that rounds up to
|
||||||
const deg = Math.floor(abs);
|
// 60.00" carries into the minutes and degrees instead of printing 60.
|
||||||
const minFloat = (abs - deg) * 60;
|
const hundredths = Math.round(Math.abs(decimal) * 360000);
|
||||||
const min = Math.floor(minFloat);
|
const deg = Math.floor(hundredths / 360000);
|
||||||
const sec = ((minFloat - min) * 60).toFixed(2);
|
const min = Math.floor(hundredths / 6000) % 60;
|
||||||
|
const sec = ((hundredths % 6000) / 100).toFixed(2);
|
||||||
|
|
||||||
let dir;
|
let dir;
|
||||||
if (type === 'lat') dir = decimal >= 0 ? 'N' : 'S';
|
if (type === 'lat') dir = decimal >= 0 ? 'N' : 'S';
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
// The HUD's LAT/LON readout in degrees-minutes-seconds. Seconds are printed to
|
||||||
|
// two decimals, so a value within 0.005" of the next whole minute rounds up.
|
||||||
|
// That carry must reach the minutes (and degrees): `122°20'60.00"W` is not a
|
||||||
|
// coordinate. Ordinary decimal inputs land there through binary floating
|
||||||
|
// point: 122.35 - 122 is 0.34999999999999432, so -122.35 read 20'60.00".
|
||||||
|
//
|
||||||
|
// hud.js imports `mgrs`, a CommonJS package whose named exports Node's ESM
|
||||||
|
// loader cannot see, so this installs the same one-specifier stub as
|
||||||
|
// hudAltitudeDatum.test.mjs before importing it.
|
||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { registerHooks } from 'node:module';
|
||||||
|
|
||||||
|
const MGRS_STUB_URL = 'gev-test-stub:mgrs';
|
||||||
|
registerHooks({
|
||||||
|
resolve(specifier, context, next) {
|
||||||
|
if (specifier === 'mgrs') return { url: MGRS_STUB_URL, shortCircuit: true };
|
||||||
|
return next(specifier, context);
|
||||||
|
},
|
||||||
|
load(url, context, next) {
|
||||||
|
if (url === MGRS_STUB_URL) {
|
||||||
|
return {
|
||||||
|
format: 'module',
|
||||||
|
shortCircuit: true,
|
||||||
|
source:
|
||||||
|
'export function forward() { return "10SEG55776339"; }\nexport default { forward };\n',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return next(url, context);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { IntelHUD } = await import('./hud.js');
|
||||||
|
|
||||||
|
const toDMS = (decimal, type) => IntelHUD.prototype._toDMS(decimal, type);
|
||||||
|
|
||||||
|
test('a rounded-up second carries into the minutes', () => {
|
||||||
|
assert.equal(toDMS(-122.35, 'lon'), `122°21'00.00"W`);
|
||||||
|
assert.equal(toDMS(139.7, 'lon'), `139°42'00.00"E`);
|
||||||
|
assert.equal(toDMS(37.0166666, 'lat'), `37°01'00.00"N`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a carry through 59 minutes reaches the degrees', () => {
|
||||||
|
assert.equal(toDMS(38.999999, 'lat'), `39°00'00.00"N`);
|
||||||
|
assert.equal(toDMS(-0.999999, 'lat'), `01°00'00.00"S`);
|
||||||
|
assert.equal(toDMS(179.999999, 'lon'), `180°00'00.00"E`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ordinary values keep their existing format', () => {
|
||||||
|
assert.equal(toDMS(38.889722, 'lat'), `38°53'23.00"N`);
|
||||||
|
assert.equal(toDMS(-77.035278, 'lon'), `077°02'07.00"W`);
|
||||||
|
assert.equal(toDMS(51.5, 'lat'), `51°30'00.00"N`);
|
||||||
|
assert.equal(toDMS(-33.8568, 'lat'), `33°51'24.48"S`);
|
||||||
|
assert.equal(toDMS(0, 'lon'), `000°00'00.00"E`);
|
||||||
|
assert.equal(toDMS(90, 'lat'), `90°00'00.00"N`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the telemetry tick paints the carried value into both readouts', () => {
|
||||||
|
const elements = new Map(
|
||||||
|
[
|
||||||
|
'hud-alt',
|
||||||
|
'hud-summary',
|
||||||
|
'hud-mgrs',
|
||||||
|
'hud-latlon',
|
||||||
|
'hud-bottom-line',
|
||||||
|
'hud-gsd',
|
||||||
|
'hud-coll',
|
||||||
|
'hud-ona',
|
||||||
|
'hud-mode',
|
||||||
|
].map((id) => [id, { textContent: '' }]),
|
||||||
|
);
|
||||||
|
const previousDocument = globalThis.document;
|
||||||
|
globalThis.document = {
|
||||||
|
getElementById: (id) => elements.get(id) ?? null,
|
||||||
|
querySelectorAll: () => [],
|
||||||
|
addEventListener() {},
|
||||||
|
removeEventListener() {},
|
||||||
|
};
|
||||||
|
const viewer = {
|
||||||
|
camera: {
|
||||||
|
pitch: -Math.PI / 2,
|
||||||
|
positionCartographic: {
|
||||||
|
latitude: (37.75 * Math.PI) / 180,
|
||||||
|
longitude: (-122.35 * Math.PI) / 180,
|
||||||
|
height: 1500,
|
||||||
|
},
|
||||||
|
computeViewRectangle: () => undefined,
|
||||||
|
moveStart: { addEventListener() {}, removeEventListener() {} },
|
||||||
|
moveEnd: { addEventListener() {}, removeEventListener() {} },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let hud;
|
||||||
|
try {
|
||||||
|
hud = new IntelHUD(viewer);
|
||||||
|
hud._updateCameraData();
|
||||||
|
const latlon = elements.get('hud-latlon').textContent;
|
||||||
|
const bottom = elements.get('hud-bottom-line').textContent;
|
||||||
|
assert.equal(latlon, `37°45'00.00"N 122°21'00.00"W`);
|
||||||
|
assert.match(bottom, /LON: 122°21'00\.00"W/);
|
||||||
|
assert.doesNotMatch(`${latlon} ${bottom}`, /60\.00"/);
|
||||||
|
} finally {
|
||||||
|
hud?.destroy();
|
||||||
|
if (previousDocument === undefined) delete globalThis.document;
|
||||||
|
else globalThis.document = previousDocument;
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in new issue
Block a user