mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-09 04:44:01 +00:00
fix(cockpit): the sensor strip follows the view through a zoom step; the pre-load level test checks a worked number; the boundary gate's dependency-asset exemption is tested
This commit is contained in:
1 parent
1453794573
commit
63aa45c520
4 files changed
+84
-14
No files matched your search
@@ -1658,14 +1658,16 @@ the satellite's live altitude and the window's shape is still at least as
|
||||
wide as that swath (`orbitalMaxZoom` in `src/cockpitOrbital.js`); when the
|
||||
cap falls below the zoom shown, the view steps back to it. Unconfirmed
|
||||
swaths add no steps, but are still drawn, read out and offered to SENSOR.
|
||||
The sensor's swath is drawn to scale as a strip along the ground track with
|
||||
The sensor's swath is drawn to scale as a strip along the ground track (its
|
||||
width follows the view through a zoom step, not ahead of it) with
|
||||
a SENSOR SWATH readout, and a SENSOR button zooms to exactly that width when
|
||||
it lies between 1× and the cap. No strip is drawn for a geostationary view
|
||||
(no ground track; its sensors image areas, not strips) or a SAR (it images
|
||||
to one side of nadir, not under it); the readout stays. Tilted off nadir
|
||||
the strip stays (view and swath widen alike), the readout scales as the swath
|
||||
readout does (`SENSOR SWATH ≈ 191 KM`), and SENSOR, a nadir framing, is
|
||||
hidden; tilted past the Earth's limb neither the sensor nor the swath reads. A swath is confirmed only on the operator's, an agency's (ESA's
|
||||
hidden; tilted past the Earth's limb neither the sensor nor the swath
|
||||
reads. A swath is confirmed only on the operator's, an agency's (ESA's
|
||||
eoPortal included) or an academic page for its platform. From
|
||||
16×, with flat imagery on the globe (not Google 3D tiles) and the view at
|
||||
nadir, every 2 s the view asks the base imagery layer for the tiles it will
|
||||
|
||||
@@ -126,3 +126,49 @@ test('a lifecycle owner cannot acquire a layer panel even through an unused impo
|
||||
);
|
||||
await assert.rejects(checkPackageBoundaries(root), /unowned module.*panel/);
|
||||
});
|
||||
|
||||
test('a declared dependency owns the asset files it ships, and only those', async (t) => {
|
||||
const asset = (pkg) =>
|
||||
`import url from './node_modules/${pkg}/flags/aa.svg?url&no-inline'; export const value = url;`;
|
||||
const root = await fixture(t, asset('flags'));
|
||||
for (const pkg of ['flags', 'flags-extra', 'stray']) {
|
||||
await mkdir(path.join(root, 'node_modules', pkg, 'flags'), {
|
||||
recursive: true,
|
||||
});
|
||||
await writeFile(
|
||||
path.join(root, 'node_modules', pkg, 'flags/aa.svg'),
|
||||
'<svg xmlns="http://www.w3.org/2000/svg"/>',
|
||||
);
|
||||
}
|
||||
await writeFile(
|
||||
path.join(root, 'package.json'),
|
||||
JSON.stringify({
|
||||
name: 'boundary-fixture',
|
||||
type: 'module',
|
||||
exports: { './feature': './entry.js' },
|
||||
dependencies: { flags: '1.0.0' },
|
||||
}),
|
||||
);
|
||||
await writeFile(
|
||||
path.join(root, 'scripts/package-boundaries.json'),
|
||||
JSON.stringify({
|
||||
feature: {
|
||||
exports: ['./feature'],
|
||||
modules: ['entry.js'],
|
||||
external: ['flags'],
|
||||
},
|
||||
}),
|
||||
);
|
||||
// The entry and the flag it ships.
|
||||
assert.deepEqual(await checkPackageBoundaries(root), [
|
||||
{ name: 'feature', exports: 1, modules: 2 },
|
||||
]);
|
||||
// An undeclared package's file, and one whose name only starts the same.
|
||||
for (const pkg of ['stray', 'flags-extra']) {
|
||||
await writeFile(path.join(root, 'entry.js'), asset(pkg));
|
||||
await assert.rejects(
|
||||
checkPackageBoundaries(root),
|
||||
new RegExp(`unowned module.*node_modules/${pkg}/`),
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -631,6 +631,11 @@ export function publishOrbitalView(info, transition = IDLE_TRANSITION) {
|
||||
: canvasAspect(this.viewer);
|
||||
const settledFov = fovForZoom(orbitalBaseFovRad(info.altitudeM), state.zoom);
|
||||
const footprintKm = footprintWidthKm(info.altitudeM, settledFov, aspect);
|
||||
// The strip is drawn over the picture, so it follows the view as a step
|
||||
// zooms (republished every frame then), not the step it is heading for.
|
||||
const shownKm = Number.isFinite(state.verticalFov)
|
||||
? footprintWidthKm(info.altitudeM, state.verticalFov, aspect)
|
||||
: footprintKm;
|
||||
const maxZoom = orbitalMaxZoomFor.call(this, info);
|
||||
const swathKm = sensorSwathKm(info);
|
||||
const trackUp = Number.isFinite(info.groundTrackDeg);
|
||||
@@ -687,7 +692,7 @@ export function publishOrbitalView(info, transition = IDLE_TRANSITION) {
|
||||
// along, and a SAR images to one side of nadir, not under it.
|
||||
stripFraction:
|
||||
trackUp && info.sensor?.type !== 'SAR'
|
||||
? sensorStripFraction(swathKm, footprintKm)
|
||||
? sensorStripFraction(swathKm, shownKm)
|
||||
: null,
|
||||
zoom: sensorSwathZoom(info.altitudeM, swathKm, aspect, maxZoom),
|
||||
},
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
} from '../cockpitOrbital.js';
|
||||
import { vesselCockpitInfo } from '../layers/vessels/cockpitSubject.js';
|
||||
import { prefetchImageryAhead } from './cockpitOrbitalView.js';
|
||||
import { imageryLevelForView } from '../cockpitOrbital.js';
|
||||
import { claimPointer, releasePointer } from '../data/inputOwnership.js';
|
||||
|
||||
const ISS = Object.freeze({
|
||||
@@ -1161,6 +1160,27 @@ function imageryGlobe(viewer, { requestImage } = {}) {
|
||||
|
||||
const WORLDVIEW_ON_TRACK = Object.freeze({ ...WORLDVIEW, groundTrackDeg: 52 });
|
||||
|
||||
test('the sensor strip follows the view through a zoom step, not ahead of it', async (t) => {
|
||||
const { cockpit, store, clock } = await orbitAt(t, {
|
||||
satellite: WORLDVIEW,
|
||||
reducedMotion: false,
|
||||
});
|
||||
const strip = () => store.orbital.sensor.stripFraction;
|
||||
const atOne = strip();
|
||||
assert.ok(atOne > 0 && atOne < 1);
|
||||
press(cockpit, '+');
|
||||
cockpit.update();
|
||||
near(strip(), atOne, 'the step starts at 1x, and so does the strip');
|
||||
clock.advance(ORBITAL_ZOOM_TRANSITION_MS / 2);
|
||||
cockpit.update();
|
||||
const midway = strip();
|
||||
clock.advance(ORBITAL_ZOOM_TRANSITION_MS + 1000);
|
||||
cockpit.update();
|
||||
const atTwo = strip();
|
||||
assert.ok(atTwo > atOne * 1.5, 'twice the zoom, about twice the share');
|
||||
assert.ok(midway > atOne && midway < atTwo, 'part-way through the step');
|
||||
});
|
||||
|
||||
test('from 16x the imagery ahead of the ground track is pre-loaded', async (t) => {
|
||||
const { cockpit, viewer, store, clock } = await orbitAt(t, {
|
||||
satellite: WORLDVIEW_ON_TRACK,
|
||||
@@ -1444,16 +1464,13 @@ test('the pre-load is throttled, at the level Cesium draws, and waits out a tilt
|
||||
);
|
||||
assert.equal(request.type, Cesium.RequestType.IMAGERY);
|
||||
}
|
||||
// The level Cesium's own selection takes for this view.
|
||||
const fov = fovForZoom(orbitalBaseFovRad(WORLDVIEW.altitudeM), 16);
|
||||
const metresPerPixel =
|
||||
(WORLDVIEW.altitudeM * 2 * Math.tan(fov / 2)) /
|
||||
viewer.scene.canvas.clientHeight;
|
||||
const expected = imageryLevelForView(new Cesium.WebMercatorTilingScheme(), {
|
||||
metresPerPixel,
|
||||
latitudeDeg: WORLDVIEW.latitude,
|
||||
});
|
||||
assert.equal(Number(requests[0].split('/')[0]), expected);
|
||||
// The level Cesium's own selection takes for this view, worked by hand:
|
||||
// at 16x from 617 km the 900 px canvas is ~49.5 m a pixel. The ellipsoid
|
||||
// terrain's level-zero error is 6378137 · 2π / 4 / 130 ≈ 77,067 m; it first
|
||||
// meets Cesium's screen-space error of 2 px (≤ 99 m) at level 10, 75.3 m.
|
||||
// A Web Mercator level-zero texel at 30° is 6378137 · 2π · cos 30° / 256
|
||||
// ≈ 135,566 m, so the imagery level is round(log2(135,566 / 75.3)) = 11.
|
||||
assert.equal(Number(requests[0].split('/')[0]), 11);
|
||||
});
|
||||
|
||||
test('the TLE age is measured from the time the satellite is shown at', async (t) => {
|
||||
|
||||
Reference in new issue
Block a user