mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-14 07:12:21 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6c241a68e | ||
|
|
f42980a04d |
No files matched your search
@@ -0,0 +1,3 @@
|
||||
- Shorten the freeze when Submarine cables is switched on from about 1.4 s to
|
||||
about 0.2 s. Landing markers are now shown a few dozen per frame instead of
|
||||
all at once (mazy1998, #1707).
|
||||
@@ -8158,6 +8158,12 @@ Cesium's multipart suffixes. Each segment gets its own feature's styling, click
|
||||
destination and horizon-culling reference, and each source feature has one
|
||||
reference stem. The source collections are not modified.
|
||||
|
||||
Landing markers are ground-clamped billboards, and Cesium reads the terrain
|
||||
height as it creates each one. They start hidden and the horizon sweep shows
|
||||
the visible ones 48 per rendered frame (`CABLE_LANDING_REVEALS_PER_FRAME`),
|
||||
so switching the layer on does not do every read in one task; hiding is still
|
||||
immediate.
|
||||
|
||||
Natural Earth regions and neighborhood polygon lookup are package exports.
|
||||
Their existing lazy loaders, retry behavior, bundled datasets and attribution
|
||||
are unchanged. The cable dataset remains CC BY-NC-SA 3.0 and is not covered by
|
||||
|
||||
@@ -3,6 +3,7 @@ import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import * as Cesium from 'cesium';
|
||||
import { MAP_STACKS } from '../mapStackController.js';
|
||||
import { CABLE_LANDING_REVEALS_PER_FRAME } from '../layers/submarineCables/policy.js';
|
||||
import {
|
||||
CABLE_LABEL_DEPTH_DECISION,
|
||||
CABLE_OVERLAY_COLLISION_CAPACITY,
|
||||
@@ -2003,3 +2004,62 @@ test('every bundled cable segment is associated with its source feature', async
|
||||
env.layer.destroy(env.viewer);
|
||||
}
|
||||
});
|
||||
|
||||
test('landing markers are revealed a few per frame, never all in one', async () => {
|
||||
// Node has no canvas for GeoJSON point pins, so short lines stand in for
|
||||
// the markers (see createRealCableLayerHarness); the staging is the same.
|
||||
const count = CABLE_LANDING_REVEALS_PER_FRAME * 2 + 10;
|
||||
const landingPoints = Array.from({ length: count }, (_, i) => {
|
||||
const lon = -45 + (i % 20) * 0.5;
|
||||
const lat = 30 + Math.floor(i / 20);
|
||||
return {
|
||||
type: 'Feature',
|
||||
id: `landing-${i}`,
|
||||
properties: { id: `landing-${i}`, name: `Landing ${i}` },
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[lon, lat],
|
||||
[lon + 0.01, lat + 0.01],
|
||||
],
|
||||
},
|
||||
};
|
||||
});
|
||||
const env = await createRealCableLayerHarness({
|
||||
source: geometrySource([], landingPoints),
|
||||
});
|
||||
try {
|
||||
let renderRequests = 0;
|
||||
env.viewer.scene.requestRender = () => {
|
||||
renderRequests++;
|
||||
};
|
||||
const entities = env.dataSources[1].entities.values;
|
||||
const shown = () => entities.filter((entity) => entity.show).length;
|
||||
assert.equal(entities.length, count);
|
||||
assert.equal(shown(), 0, 'nothing is shown before the first sweep');
|
||||
|
||||
env.raiseSweep();
|
||||
assert.equal(shown(), CABLE_LANDING_REVEALS_PER_FRAME);
|
||||
assert.ok(renderRequests > 0, 'another frame is asked for');
|
||||
env.raiseSweep();
|
||||
assert.equal(shown(), CABLE_LANDING_REVEALS_PER_FRAME * 2);
|
||||
env.raiseSweep();
|
||||
assert.equal(shown(), count, 'every visible marker ends up shown');
|
||||
|
||||
renderRequests = 0;
|
||||
env.raiseSweep();
|
||||
assert.equal(renderRequests, 0, 'a finished reveal asks for no frames');
|
||||
|
||||
// Markers over the horizon are hidden at once and are not revealed.
|
||||
env.viewer.camera.positionWC = Cesium.Cartesian3.fromDegrees(
|
||||
140,
|
||||
-35,
|
||||
4_500_000,
|
||||
);
|
||||
for (const fn of env.listeners.moveEnd) fn();
|
||||
env.raiseSweep();
|
||||
assert.equal(shown(), 0);
|
||||
} finally {
|
||||
env.layer.destroy(env.viewer);
|
||||
}
|
||||
});
|
||||
@@ -185,6 +185,10 @@ export function createIngestion({ state, parts, source }) {
|
||||
if (!reference) return;
|
||||
|
||||
parts.rendering.styleLandingEntity(entity, feature);
|
||||
// Hidden until the sweep reveals it: a shown landing marker reads the
|
||||
// terrain height as Cesium creates it, and all of them at once froze
|
||||
// the page (see CABLE_LANDING_REVEALS_PER_FRAME).
|
||||
entity.show = false;
|
||||
parts.interaction.registerPickEntity(entity, {
|
||||
kind: 'landing-point',
|
||||
reference,
|
||||
@@ -193,6 +197,7 @@ export function createIngestion({ state, parts, source }) {
|
||||
state._surfaceRecords.push({
|
||||
entity,
|
||||
base: Cesium.Cartesian3.fromDegrees(reference.lon, reference.lat, 0),
|
||||
staged: true,
|
||||
});
|
||||
if (landingReferences.has(index)) return;
|
||||
landingReferences.add(index);
|
||||
|
||||
@@ -38,12 +38,10 @@ export function createLifecycle({ state, parts, source, mapStackEventTarget }) {
|
||||
// never emit moveEnd — reach the motion fallback. No render is
|
||||
// requested for a fallback sweep: it only fires while the camera is
|
||||
// already moving, so frames are flowing by construction.
|
||||
if (
|
||||
!state._enabled ||
|
||||
!state._loaded ||
|
||||
!state._referenceSweepGate.shouldRun(viewer.camera)
|
||||
)
|
||||
return;
|
||||
if (!state._enabled || !state._loaded) return;
|
||||
// Landing markers left over from the last sweep, a few per frame.
|
||||
parts.rendering.revealLandingMarkers();
|
||||
if (!state._referenceSweepGate.shouldRun(viewer.camera)) return;
|
||||
parts.rendering.updateReferenceVisibility();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -66,6 +66,16 @@ export const CABLE_LABEL_DEPTH_DECISION = Object.freeze({
|
||||
depthTested: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* Landing markers shown per rendered frame. Each one is a ground-clamped
|
||||
* billboard, and Cesium reads the terrain height when it creates one.
|
||||
* Showing all 1,917 in the frame after the layer was switched on did those
|
||||
* reads in a single task (measured 1.2 s on a loaded globe); a few dozen per
|
||||
* frame keeps each frame short and the markers still fill in within a second.
|
||||
*/
|
||||
|
||||
export const CABLE_LANDING_REVEALS_PER_FRAME = 48;
|
||||
|
||||
/**
|
||||
* `MAP_STACKS` ids that render imagery on the SHOWN Cesium globe (the ion
|
||||
* Bing stacks + OSM). Deliberately an explicit allowlist, not "anything that
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
probeTranslucentMarkerBlend,
|
||||
commitTranslucentMarkerBlend,
|
||||
} from './surface.js';
|
||||
import { CABLE_LANDING_REVEALS_PER_FRAME } from './policy.js';
|
||||
import {
|
||||
clampLabel,
|
||||
createCableOverlayEntry,
|
||||
@@ -40,6 +41,7 @@ export function createRendering({ state }) {
|
||||
state._referenceDataSource = null;
|
||||
state._referenceRecords = [];
|
||||
state._surfaceRecords = [];
|
||||
state._pendingLandingReveals.length = 0;
|
||||
state._pickByEntity = new WeakMap();
|
||||
state._referenceLabelCount = 0;
|
||||
state._publishScratch.length = 0;
|
||||
@@ -201,6 +203,26 @@ export function createRendering({ state }) {
|
||||
state._referenceRecords.push(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the next few landing markers the last sweep found visible, and ask
|
||||
* for another frame while any are left. Called from the sweep and then once
|
||||
* per rendered frame, so a parked camera costs nothing once the list is
|
||||
* empty.
|
||||
*/
|
||||
|
||||
function revealLandingMarkers() {
|
||||
const pending = state._pendingLandingReveals;
|
||||
if (!pending.length) return;
|
||||
let budget = CABLE_LANDING_REVEALS_PER_FRAME;
|
||||
while (pending.length && budget > 0) {
|
||||
const record = pending.pop();
|
||||
if (!record.visible || record.entity.show) continue;
|
||||
record.entity.show = true;
|
||||
budget--;
|
||||
}
|
||||
if (pending.length) state._viewer?.scene?.requestRender?.();
|
||||
}
|
||||
|
||||
function updateReferenceVisibility() {
|
||||
if (!state._enabled || !state._viewer?.camera) return;
|
||||
const cameraPos = state._viewer.camera.positionWC;
|
||||
@@ -224,12 +246,16 @@ export function createRendering({ state }) {
|
||||
if (visible)
|
||||
updateCableReferenceStem(record, cameraPos, canvasHeight, fov);
|
||||
}
|
||||
state._pendingLandingReveals.length = 0;
|
||||
for (const record of state._surfaceRecords) {
|
||||
const visible = occluder.isPointVisible(record.base);
|
||||
if (record.entity.show !== visible) {
|
||||
record.entity.show = visible;
|
||||
}
|
||||
record.visible = visible;
|
||||
if (record.entity.show === visible) continue;
|
||||
// Landing markers are shown a few per frame; hiding is immediate.
|
||||
if (visible && record.staged) state._pendingLandingReveals.push(record);
|
||||
else record.entity.show = visible;
|
||||
}
|
||||
revealLandingMarkers();
|
||||
const winners = selectCableReferenceLabelWinners(state._referenceRecords);
|
||||
let changed = winners.length !== state._lastPublishedCount;
|
||||
for (let i = 0; i < winners.length; i++) {
|
||||
@@ -269,6 +295,7 @@ export function createRendering({ state }) {
|
||||
applyCableClassification,
|
||||
styleLandingEntity,
|
||||
addReferenceStem,
|
||||
revealLandingMarkers,
|
||||
updateReferenceVisibility,
|
||||
};
|
||||
}
|
||||
@@ -51,6 +51,11 @@ export function createState({ sweepClock, overlayHost }) {
|
||||
|
||||
state._surfaceRecords = [];
|
||||
|
||||
/** Landing records the last sweep found visible but not shown yet; drained
|
||||
* a few per frame (CABLE_LANDING_REVEALS_PER_FRAME). */
|
||||
|
||||
state._pendingLandingReveals = [];
|
||||
|
||||
state._clickHandler = null;
|
||||
|
||||
state._preRenderRemover = null;
|
||||
|
||||
Reference in new issue
Block a user