feat(map): add seamless five-band grid LOD
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
import {
|
||||
gridShouldBeVisible,
|
||||
resolveGridMode,
|
||||
selectGridLod,
|
||||
snapGridCenter,
|
||||
} from "../apps/catalog/src/mapGridPolicy.mjs";
|
||||
|
||||
const settings = {
|
||||
gridVisible: true,
|
||||
gridLodEnabled: true,
|
||||
gridLod1MaxHeightKm: 10,
|
||||
gridLod1StepKm: 1,
|
||||
gridLod1Mode: "3d",
|
||||
gridLod2MaxHeightKm: 50,
|
||||
gridLod2StepKm: 5,
|
||||
gridLod2Mode: "3d",
|
||||
gridLod3MaxHeightKm: 180,
|
||||
gridLod3StepKm: 25,
|
||||
gridLod3Mode: "3d",
|
||||
gridLod4MaxHeightKm: 700,
|
||||
gridLod4StepKm: 100,
|
||||
gridLod4Mode: "graticule",
|
||||
gridLod5StepKm: 500,
|
||||
gridLod5Mode: "graticule",
|
||||
grid3dEnabled: true,
|
||||
gridGraticuleEnabled: true,
|
||||
gridMax3dViewAngleDegrees: 30,
|
||||
gridAutoDisableHeightKm: 10_000,
|
||||
gridCenterMode: "camera",
|
||||
gridTileSizeKm: 10,
|
||||
};
|
||||
|
||||
test("five grid LODs preserve the close 3D and distant graticule contract", () => {
|
||||
assert.deepEqual(
|
||||
[5, 40, 120, 500, 2_000].map((height) => {
|
||||
const band = selectGridLod(settings, height);
|
||||
return [band.id, band.stepKm, band.mode];
|
||||
}),
|
||||
[
|
||||
["lod-1", 1, "3d"],
|
||||
["lod-2", 5, "3d"],
|
||||
["lod-3", 25, "3d"],
|
||||
["lod-4", 100, "graticule"],
|
||||
["lod-5", 500, "graticule"],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test("LOD hysteresis holds the previous band around a threshold", () => {
|
||||
assert.equal(selectGridLod(settings, 10.5, 0).id, "lod-1");
|
||||
assert.equal(selectGridLod(settings, 10.9, 0).id, "lod-2");
|
||||
assert.equal(selectGridLod(settings, 9.5, 1).id, "lod-2");
|
||||
assert.equal(selectGridLod(settings, 9.1, 1).id, "lod-1");
|
||||
});
|
||||
|
||||
test("oblique close view falls back to the graticule without dropping the grid", () => {
|
||||
assert.equal(resolveGridMode(settings, "3d", 12), "3d");
|
||||
assert.equal(resolveGridMode(settings, "3d", 48), "graticule");
|
||||
assert.equal(resolveGridMode({ ...settings, gridGraticuleEnabled: false }, "3d", 48), "hidden");
|
||||
});
|
||||
|
||||
test("grid auto-disable and stable camera tile center are deterministic", () => {
|
||||
assert.equal(gridShouldBeVisible(settings, 9_999), true);
|
||||
assert.equal(gridShouldBeVisible(settings, 10_001), false);
|
||||
const first = snapGridCenter({ latitude: 55.7558, longitude: 37.6173 }, settings);
|
||||
const second = snapGridCenter({ latitude: 55.76, longitude: 37.62 }, settings);
|
||||
assert.deepEqual(first, second);
|
||||
});
|
||||
|
||||
test("renderer swaps double-buffered data sources and never clears the live grid first", async () => {
|
||||
const source = await readFile(new URL("../apps/catalog/src/CesiumMapRenderer.tsx", import.meta.url), "utf8");
|
||||
assert.match(source, /class GridLayerController/);
|
||||
assert.match(source, /dataSourceDisplay\.ready/);
|
||||
assert.doesNotMatch(source, /function rebuildElevatedGrid[\s\S]*?entities\.removeAll\(\)/);
|
||||
});
|
||||
Reference in New Issue
Block a user