opengeos--geolibre
7df9ebf22c
Sync labels / sync (push) Failing after 1m9s
Publish Container Image / Build and publish container image (push) Has been cancelled
Deploy Website / Deploy to GitHub Pages (push) Has been cancelled
Deploy Website / Build website and demo (push) Has been cancelled
Deploy viewer / Deploy viewer proxy to Cloudflare Workers (push) Has been cancelled
Deploy tiles / Deploy planetary tile proxy to Cloudflare Workers (push) Has been cancelled
Deploy collab / Deploy collaboration relay to Cloudflare Workers (push) Has been cancelled
CI / Dependency audit (push) Has been cancelled
CI / E2E smoke (Playwright) (push) Has been cancelled
CI / Validate CITATION.cff (push) Has been cancelled
CI / Build and test (push) Has been cancelled
115 行
3.7 KiB
TypeScript
115 行
3.7 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { describe, it } from "node:test";
|
|
import {
|
|
DEFAULT_SUN_SETTINGS,
|
|
advanceSunClock,
|
|
getSunSettings,
|
|
normalizeSunSettings,
|
|
setSunSettings,
|
|
SUN_SHADE_MAX,
|
|
SUN_SPEED_MAX,
|
|
SUN_SPEED_MIN,
|
|
subsolarPoint,
|
|
sunEquatorialPosition,
|
|
sunPositionAt,
|
|
} from "../packages/plugins/src/plugins/maplibre-sun";
|
|
|
|
describe("normalizeSunSettings", () => {
|
|
it("fills defaults for missing/invalid fields", () => {
|
|
const s = normalizeSunSettings({});
|
|
assert.deepEqual(s, DEFAULT_SUN_SETTINGS);
|
|
});
|
|
|
|
it("clamps speed and shade into range and coerces types", () => {
|
|
const s = normalizeSunSettings({
|
|
speed: 100000,
|
|
shadeOpacity: 5,
|
|
playing: "yes" as unknown as boolean,
|
|
dateMs: Number.NaN,
|
|
});
|
|
assert.equal(s.speed, SUN_SPEED_MAX);
|
|
assert.equal(s.shadeOpacity, SUN_SHADE_MAX);
|
|
// Non-boolean playing falls back to the default, NaN date to the default.
|
|
assert.equal(s.playing, DEFAULT_SUN_SETTINGS.playing);
|
|
assert.equal(s.dateMs, DEFAULT_SUN_SETTINGS.dateMs);
|
|
});
|
|
|
|
it("keeps a valid low speed and floors are respected", () => {
|
|
assert.equal(normalizeSunSettings({ speed: -10 }).speed, SUN_SPEED_MIN);
|
|
});
|
|
});
|
|
|
|
describe("solar declination", () => {
|
|
it("is near +23.4° at the June solstice and near -23.4° at December", () => {
|
|
const june = sunEquatorialPosition(Date.UTC(2024, 5, 20, 20, 51));
|
|
assert.ok(
|
|
Math.abs(june.delta - 23.44) < 0.4,
|
|
`June declination ${june.delta} not near +23.44`,
|
|
);
|
|
const dec = sunEquatorialPosition(Date.UTC(2024, 11, 21, 9, 21));
|
|
assert.ok(
|
|
Math.abs(dec.delta + 23.44) < 0.4,
|
|
`December declination ${dec.delta} not near -23.44`,
|
|
);
|
|
});
|
|
|
|
it("is near 0° at the equinoxes", () => {
|
|
const mar = sunEquatorialPosition(Date.UTC(2024, 2, 20, 3, 6));
|
|
assert.ok(Math.abs(mar.delta) < 0.7, `March declination ${mar.delta}`);
|
|
});
|
|
});
|
|
|
|
describe("subsolarPoint / sunPositionAt round trip", () => {
|
|
// Sampling several instants across a year is the strongest end-to-end check:
|
|
// the sun must sit ~overhead at its own subsolar point and ~underfoot at the
|
|
// antipode, which only holds if declination, sidereal time, and the hour
|
|
// angle all agree.
|
|
const instants = [
|
|
Date.UTC(2024, 0, 5, 3, 0),
|
|
Date.UTC(2024, 3, 15, 12, 30),
|
|
Date.UTC(2024, 6, 21, 18, 45),
|
|
Date.UTC(2024, 9, 2, 6, 15),
|
|
Date.UTC(2025, 1, 11, 21, 0),
|
|
];
|
|
|
|
for (const dateMs of instants) {
|
|
it(`sun is overhead at its subsolar point (${new Date(dateMs).toISOString()})`, () => {
|
|
const { lat, lng } = subsolarPoint(dateMs);
|
|
const here = sunPositionAt(dateMs, lat, lng);
|
|
assert.ok(
|
|
here.altitude > 89,
|
|
`altitude ${here.altitude} at subsolar point should be ~90`,
|
|
);
|
|
const anti = sunPositionAt(dateMs, -lat, lng + 180);
|
|
assert.ok(
|
|
anti.altitude < -89,
|
|
`altitude ${anti.altitude} at antipode should be ~-90`,
|
|
);
|
|
});
|
|
}
|
|
|
|
it("declination equals the subsolar latitude", () => {
|
|
const dateMs = Date.UTC(2024, 7, 1, 9, 0);
|
|
const { lat } = subsolarPoint(dateMs);
|
|
const { delta } = sunEquatorialPosition(dateMs);
|
|
assert.ok(Math.abs(lat - delta) < 1e-9);
|
|
});
|
|
});
|
|
|
|
describe("advanceSunClock", () => {
|
|
it("loops within the displayed local day", () => {
|
|
const start = new Date(2024, 0, 15, 23, 59, 0).getTime();
|
|
setSunSettings({ ...DEFAULT_SUN_SETTINGS, dateMs: start, loop: true });
|
|
advanceSunClock(2 * 60 * 1000);
|
|
|
|
const next = new Date(getSunSettings().dateMs);
|
|
assert.equal(next.getFullYear(), 2024);
|
|
assert.equal(next.getMonth(), 0);
|
|
assert.equal(next.getDate(), 15);
|
|
assert.equal(next.getHours(), 0);
|
|
assert.equal(next.getMinutes(), 1);
|
|
|
|
setSunSettings(DEFAULT_SUN_SETTINGS);
|
|
});
|
|
});
|