mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-12 06:12:18 +00:00
Cut duplicated and dead code across the engines, the layers and the QA scripts
- src/geo drops the ported debug argument checks and the tests that bitExact already covers; package boundaries accept a directory entry, so src/geo/ is listed once per group. - Cesium no longer carries movers and lines nobody draws with: they are optional engine capabilities. The fake engine and the Cesium camera use the shared cameraMath; unused contract tables, clock.ticked, the 'finest' surface detail and Navara click statistics are gone. - ALPR keeps one overlay core and one presentation model for both engines, bikeshare one station bookkeeping, the Navara ground effects one definition helper; image atlases, view centres, mover banks and colours are shared. - The legacy switch route, the clock offset and rate controls and other unused exports are removed. - The acceptance runs the Navara draw, geo import and scope checks; scenarios use the harness switch and page helpers; the main chunk check keeps the size budget only and runs once in CI.
This commit is contained in:
1 parent
c502404e1d
commit
7abf74518f
272 files changed
+4828
-10213
No files matched your search
@@ -1,23 +1,5 @@
|
||||
import * as geo from '../../../geo/index.js';
|
||||
import {
|
||||
MAX_CANVAS_FRUSTUMS,
|
||||
MARKER_ICON_SIZE,
|
||||
SELECTED_MARKER_ICON_SIZE,
|
||||
MARKER_FLOOR_LIFT_M,
|
||||
ANCHOR_SAMPLES_PER_PAINT,
|
||||
SURFACE_BELOW_FLOOR_M,
|
||||
SURFACE_ABOVE_FLOOR_M,
|
||||
SURFACE_SAMPLES_PER_PAINT,
|
||||
} from '../policy.js';
|
||||
import {
|
||||
MARKER_IMAGE,
|
||||
SELECTED_IMAGE,
|
||||
BRACKETS_IMAGE,
|
||||
directionWedgePositions,
|
||||
markerScale,
|
||||
paintDirectionWedge,
|
||||
validAlprGroundHeight,
|
||||
} from '../visuals.js';
|
||||
import { createAlprOverlayCore } from '../overlay.js';
|
||||
|
||||
/** Canvas artwork over Navara pick sprites, with bounded surface refinement. */
|
||||
export function createAlprNavaraOverlay({
|
||||
@@ -29,396 +11,73 @@ export function createAlprNavaraOverlay({
|
||||
services,
|
||||
onSurfaceChange = () => {},
|
||||
}) {
|
||||
let lane,
|
||||
removeMapListener,
|
||||
retryTimer,
|
||||
retryUntil = 0;
|
||||
let records = [],
|
||||
hits = [],
|
||||
images = [],
|
||||
destroyed = false,
|
||||
lastCamera = null;
|
||||
const requestPaint = () => {
|
||||
if (!destroyed && state.enabled) lane?.requestPaint();
|
||||
};
|
||||
|
||||
function nativeVisible(entity, visible) {
|
||||
if (!entity) return;
|
||||
canvasOwned(entity, !visible);
|
||||
setShown(entity, visible);
|
||||
}
|
||||
|
||||
function canvasOwned(marker, owned) {
|
||||
if (marker.canvasOwned === owned) return;
|
||||
marker.canvasOwned = owned;
|
||||
syncMarker(marker);
|
||||
}
|
||||
|
||||
function setShown(marker, visible) {
|
||||
if (marker.shown === visible) return;
|
||||
marker.shown = visible;
|
||||
syncMarker(marker);
|
||||
}
|
||||
|
||||
function resetAnchors() {
|
||||
for (const entity of markers.values()) {
|
||||
entity.gevAlprCanvasPosition = null;
|
||||
entity.gevAlprWedge = null;
|
||||
entity.displayPosition = null;
|
||||
nativeVisible(entity, true);
|
||||
}
|
||||
state.lastAnchorSampleAt = 0;
|
||||
retryUntil = Date.now() + 15000;
|
||||
requestPaint();
|
||||
}
|
||||
|
||||
function anchorFor(record, entity, budget) {
|
||||
if (entity.gevAlprCanvasPosition) return entity.gevAlprCanvasPosition;
|
||||
const location = geo.cartographic.fromDegrees(
|
||||
record.longitude,
|
||||
record.latitude,
|
||||
);
|
||||
// A floor-placed marker anchors where its native badge sits; only a
|
||||
// marker still waiting for its floor samples the rendered surface, and
|
||||
// each paint samples a few at most (Navara raycasts the loaded surface).
|
||||
let height;
|
||||
const floor = services.groundFloor.cachedGroundFloor(
|
||||
record.latitude,
|
||||
record.longitude,
|
||||
);
|
||||
if (validAlprGroundHeight(floor)) height = floor + MARKER_FLOOR_LIFT_M;
|
||||
else if (engine.surface.supported) {
|
||||
if (budget.samples <= 0) return null;
|
||||
budget.samples -= 1;
|
||||
try {
|
||||
height = sampleHeight(location);
|
||||
} catch {
|
||||
/* streaming tiles */
|
||||
}
|
||||
}
|
||||
if (!validAlprGroundHeight(height) && engine.surface.terrainHeightSupported)
|
||||
height = engine.surface.terrainHeight(location);
|
||||
if (!validAlprGroundHeight(height)) return null;
|
||||
setAnchor(record, entity, height);
|
||||
return entity.gevAlprCanvasPosition;
|
||||
}
|
||||
|
||||
function floorHeightAt(latitude, longitude) {
|
||||
const floor = services.groundFloor.cachedGroundFloor(latitude, longitude);
|
||||
return validAlprGroundHeight(floor) ? floor + MARKER_FLOOR_LIFT_M : null;
|
||||
}
|
||||
|
||||
function setAnchor(record, entity, height) {
|
||||
entity.gevAlprCanvasPosition = geo.cartesian3.fromDegrees(
|
||||
record.longitude,
|
||||
record.latitude,
|
||||
height,
|
||||
);
|
||||
entity.resolved = true;
|
||||
syncMarker(entity);
|
||||
entity.gevAlprWedge = directionWedgePositions(
|
||||
record,
|
||||
height,
|
||||
floorHeightAt,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace floor anchors with the rendered surface under each overlay camera.
|
||||
* Floors come from ~111 m cells, so on a slope a badge could float or sink
|
||||
* by tens of metres. Runs only while the camera is still and tiles have
|
||||
* settled, a few surface samples per paint, and each anchor at most once;
|
||||
* samples far outside the floor prior (a roof or a streaming tile) are
|
||||
* rejected. Returns whether anchors remain to check.
|
||||
*/
|
||||
function refineAnchors(budget) {
|
||||
const camera = engine.camera.pose();
|
||||
const still =
|
||||
lastCamera &&
|
||||
camera.position &&
|
||||
geo.cartesian3.equalsEpsilon(
|
||||
camera.position,
|
||||
lastCamera.position,
|
||||
0,
|
||||
0.05,
|
||||
) &&
|
||||
geo.cartesian3.equalsEpsilon(
|
||||
camera.direction,
|
||||
lastCamera.direction,
|
||||
0,
|
||||
1e-6,
|
||||
);
|
||||
if (camera.position && camera.direction)
|
||||
lastCamera = {
|
||||
position: geo.cartesian3.clone(camera.position),
|
||||
direction: geo.cartesian3.clone(camera.direction),
|
||||
};
|
||||
if (!engine.surface.supported) return false;
|
||||
let pending = false;
|
||||
for (const record of records) {
|
||||
const entity = markers.get(record.id);
|
||||
const anchor = entity?.gevAlprCanvasPosition;
|
||||
if (!anchor || entity.gevAlprSurfaceCheckedFor === anchor) continue;
|
||||
if (!still || !engine.surface.tilesLoaded() || budget.samples <= 0) {
|
||||
pending = true;
|
||||
continue;
|
||||
}
|
||||
budget.samples -= 1;
|
||||
let sample;
|
||||
try {
|
||||
sample = sampleHeight(
|
||||
geo.cartographic.fromDegrees(record.longitude, record.latitude),
|
||||
const location = (record) =>
|
||||
geo.cartographic.fromDegrees(record.longitude, record.latitude);
|
||||
return createAlprOverlayCore({
|
||||
state,
|
||||
services,
|
||||
onSurfaceChange,
|
||||
engine: {
|
||||
marker: (id) => markers.get(id),
|
||||
markers: () => markers.values(),
|
||||
canvasOwned(marker, owned) {
|
||||
if (marker.canvasOwned === owned) return;
|
||||
marker.canvasOwned = owned;
|
||||
syncMarker(marker);
|
||||
},
|
||||
setShown(marker, visible) {
|
||||
if (marker.shown === visible) return;
|
||||
marker.shown = visible;
|
||||
syncMarker(marker);
|
||||
},
|
||||
setDisplayPosition(marker, position) {
|
||||
marker.displayPosition = position;
|
||||
},
|
||||
placeAnchor(marker, record, height) {
|
||||
marker.gevAlprCanvasPosition = geo.cartesian3.fromDegrees(
|
||||
record.longitude,
|
||||
record.latitude,
|
||||
height,
|
||||
);
|
||||
} catch {
|
||||
/* streaming tiles */
|
||||
}
|
||||
const current = geo.cartographic.fromCartesian(anchor).height;
|
||||
const floor = services.groundFloor.cachedGroundFloor(
|
||||
record.latitude,
|
||||
record.longitude,
|
||||
);
|
||||
const accepted =
|
||||
validAlprGroundHeight(sample) &&
|
||||
(!validAlprGroundHeight(floor) ||
|
||||
(sample >= floor - SURFACE_BELOW_FLOOR_M &&
|
||||
sample <= floor + SURFACE_ABOVE_FLOOR_M));
|
||||
if (accepted && Math.abs(sample + MARKER_FLOOR_LIFT_M - current) > 1)
|
||||
setAnchor(record, entity, sample + MARKER_FLOOR_LIFT_M);
|
||||
entity.gevAlprSurfaceCheckedFor = entity.gevAlprCanvasPosition;
|
||||
if (entity.id === state.selectedId)
|
||||
entity.displayPosition = entity.gevAlprCanvasPosition;
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
function paint({
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
keyhole,
|
||||
viewProjectionMatrix: matrix,
|
||||
}) {
|
||||
hits = [];
|
||||
if (!state.enabled || destroyed) return;
|
||||
// The host already captured the camera and CSS viewport for this frame.
|
||||
// Reuse it for every wedge vertex instead of rereading DOM geometry.
|
||||
const project = ({ x, y, z }) => {
|
||||
const w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
|
||||
if (!(w > 0)) return null;
|
||||
return {
|
||||
x:
|
||||
(((matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12]) / w +
|
||||
1) *
|
||||
width) /
|
||||
2,
|
||||
y:
|
||||
((1 -
|
||||
(matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13]) / w) *
|
||||
height) /
|
||||
2,
|
||||
};
|
||||
};
|
||||
let unresolved = false;
|
||||
const painted = [];
|
||||
const budget = { samples: ANCHOR_SAMPLES_PER_PAINT };
|
||||
for (const record of records) {
|
||||
const entity = markers.get(record.id);
|
||||
if (!entity) continue;
|
||||
const selected = record.id === state.selectedId;
|
||||
const image = images[selected ? 1 : 0];
|
||||
if (
|
||||
!image?.complete ||
|
||||
!image.naturalWidth ||
|
||||
(selected && !images[2]?.naturalWidth)
|
||||
) {
|
||||
nativeVisible(entity, true);
|
||||
continue;
|
||||
}
|
||||
const anchor = anchorFor(record, entity, budget);
|
||||
if (!anchor) {
|
||||
nativeVisible(entity, true);
|
||||
unresolved = true;
|
||||
continue;
|
||||
}
|
||||
canvasOwned(entity, true);
|
||||
if (!engine.projector.horizonVisible(anchor)) {
|
||||
setShown(entity, false);
|
||||
continue;
|
||||
}
|
||||
const origin = project(anchor);
|
||||
if (!origin) {
|
||||
setShown(entity, false);
|
||||
continue;
|
||||
}
|
||||
const alpha =
|
||||
services.overlays.keyholeAlpha?.(origin.x, origin.y, keyhole) ?? 1;
|
||||
if (!(alpha > 0)) {
|
||||
setShown(entity, false);
|
||||
continue;
|
||||
}
|
||||
const wedge = entity.gevAlprWedge;
|
||||
if (wedge) {
|
||||
const left = project(wedge[1]);
|
||||
const right = project(wedge[2]);
|
||||
if (
|
||||
left &&
|
||||
right &&
|
||||
Math.max(origin.x, left.x, right.x) >= -3 &&
|
||||
Math.min(origin.x, left.x, right.x) <= width + 3 &&
|
||||
Math.max(origin.y, left.y, right.y) >= -3 &&
|
||||
Math.min(origin.y, left.y, right.y) <= height + 3
|
||||
) {
|
||||
ctx.save();
|
||||
ctx.globalAlpha *= alpha;
|
||||
paintDirectionWedge(ctx, origin, left, right, selected);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
if (
|
||||
origin.x < -60 ||
|
||||
origin.x > width + 60 ||
|
||||
origin.y < -60 ||
|
||||
origin.y > height + 60
|
||||
) {
|
||||
setShown(entity, false);
|
||||
continue;
|
||||
}
|
||||
setShown(entity, true);
|
||||
painted.push({
|
||||
record,
|
||||
origin,
|
||||
selected,
|
||||
image,
|
||||
alpha,
|
||||
scale: markerScale(
|
||||
geo.cartesian3.distance(engine.camera.livePosition, anchor),
|
||||
),
|
||||
});
|
||||
if (selected) entity.displayPosition = anchor;
|
||||
}
|
||||
// Paint all glyphs after the wedges so one camera's cone cannot wash out another.
|
||||
for (const { record, origin, selected, image, alpha, scale } of painted) {
|
||||
const size =
|
||||
(selected ? SELECTED_MARKER_ICON_SIZE : MARKER_ICON_SIZE) * scale;
|
||||
ctx.save();
|
||||
ctx.globalAlpha *= alpha;
|
||||
ctx.drawImage(
|
||||
image,
|
||||
origin.x - size / 2,
|
||||
origin.y - size / 2,
|
||||
size,
|
||||
size,
|
||||
);
|
||||
if (selected)
|
||||
ctx.drawImage(
|
||||
images[2],
|
||||
origin.x - size / 2,
|
||||
origin.y - size / 2,
|
||||
size,
|
||||
size,
|
||||
);
|
||||
ctx.restore();
|
||||
hits.push({ id: record.id, x: origin.x, y: origin.y, radius: size / 2 });
|
||||
}
|
||||
const refining = refineAnchors({
|
||||
samples: Math.min(budget.samples, SURFACE_SAMPLES_PER_PAINT),
|
||||
});
|
||||
if ((unresolved || refining) && !retryTimer && Date.now() < retryUntil) {
|
||||
retryTimer = setTimeout(() => {
|
||||
retryTimer = null;
|
||||
requestPaint();
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init() {
|
||||
destroyed = false;
|
||||
removeMapListener = services.overlays?.subscribeMapStack?.((event) => {
|
||||
if (event.detail?.status !== 'ready' || !state.enabled) return;
|
||||
// Same-regime provider changes also invalidate absolute placements.
|
||||
onSurfaceChange();
|
||||
resetAnchors();
|
||||
});
|
||||
if (!services.overlays?.registerPaintLane || typeof Image === 'undefined')
|
||||
return;
|
||||
lane = services.overlays.registerPaintLane('selected', paint, {
|
||||
id: `alpr-${crypto.randomUUID()}`,
|
||||
active: false,
|
||||
});
|
||||
images = [MARKER_IMAGE, SELECTED_IMAGE, BRACKETS_IMAGE].map((src) => {
|
||||
const image = new Image();
|
||||
image.onload = requestPaint;
|
||||
image.onerror = requestPaint;
|
||||
image.src = src;
|
||||
return image;
|
||||
});
|
||||
marker.resolved = true;
|
||||
syncMarker(marker);
|
||||
},
|
||||
surfaceSupported: () => engine.surface.supported,
|
||||
// Navara raycasts the loaded surface.
|
||||
sampleHeight: (record) => sampleHeight(location(record)),
|
||||
terrainHeight: (record) =>
|
||||
engine.surface.terrainHeightSupported
|
||||
? engine.surface.terrainHeight(location(record))
|
||||
: undefined,
|
||||
surfaceSettled: () => engine.surface.tilesLoaded(),
|
||||
cameraPose: () => engine.camera.pose(),
|
||||
cameraPosition: () => engine.camera.livePosition,
|
||||
projector: ({ width, height, viewProjectionMatrix: matrix }) => ({
|
||||
horizonVisible: (point) => engine.projector.horizonVisible(point),
|
||||
// The host already captured the camera and CSS viewport for this
|
||||
// frame; reuse it for every wedge vertex instead of rereading DOM
|
||||
// geometry.
|
||||
project({ x, y, z }) {
|
||||
const w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
|
||||
if (!(w > 0)) return null;
|
||||
return {
|
||||
x:
|
||||
(((matrix[0] * x + matrix[4] * y + matrix[8] * z + matrix[12]) /
|
||||
w +
|
||||
1) *
|
||||
width) /
|
||||
2,
|
||||
y:
|
||||
((1 -
|
||||
(matrix[1] * x + matrix[5] * y + matrix[9] * z + matrix[13]) /
|
||||
w) *
|
||||
height) /
|
||||
2,
|
||||
};
|
||||
},
|
||||
}),
|
||||
cullOffscreenWedges: true,
|
||||
createId: () => crypto.randomUUID(),
|
||||
},
|
||||
sync(visible) {
|
||||
if (!lane) return;
|
||||
for (const record of records) nativeVisible(markers.get(record.id), true);
|
||||
const position = engine.camera.livePosition;
|
||||
records = visible
|
||||
.filter(
|
||||
(record) =>
|
||||
Number.isFinite(record.directionDeg) &&
|
||||
record.id !== state.selectedId,
|
||||
)
|
||||
.map((record) => ({
|
||||
record,
|
||||
distance: position
|
||||
? geo.cartesian3.distanceSquared(
|
||||
position,
|
||||
geo.cartesian3.fromDegrees(record.longitude, record.latitude),
|
||||
)
|
||||
: 0,
|
||||
}))
|
||||
.sort((a, b) => a.distance - b.distance)
|
||||
.slice(0, MAX_CANVAS_FRUSTUMS)
|
||||
.map((item) => item.record);
|
||||
const selected = visible.find((record) => record.id === state.selectedId);
|
||||
if (selected) {
|
||||
if (records.length >= MAX_CANVAS_FRUSTUMS) records.pop();
|
||||
records.push(selected);
|
||||
}
|
||||
hits = [];
|
||||
retryUntil = Date.now() + 15000;
|
||||
lane.setActive(state.enabled && records.length > 0);
|
||||
requestPaint();
|
||||
},
|
||||
pick(position) {
|
||||
if (!state.enabled || !position) return null;
|
||||
let closest,
|
||||
distance = Infinity;
|
||||
for (const hit of hits) {
|
||||
const next = (hit.x - position.x) ** 2 + (hit.y - position.y) ** 2;
|
||||
if (next <= hit.radius ** 2 && next <= distance) {
|
||||
closest = hit.id;
|
||||
distance = next;
|
||||
}
|
||||
}
|
||||
return closest || null;
|
||||
},
|
||||
clear() {
|
||||
clearTimeout(retryTimer);
|
||||
retryTimer = null;
|
||||
for (const record of records) nativeVisible(markers.get(record.id), true);
|
||||
records = [];
|
||||
hits = [];
|
||||
lane?.setActive(false);
|
||||
},
|
||||
destroy() {
|
||||
this.clear();
|
||||
destroyed = true;
|
||||
removeMapListener?.();
|
||||
removeMapListener = null;
|
||||
lane?.unregister();
|
||||
lane = null;
|
||||
for (const image of images) {
|
||||
image.onload = null;
|
||||
image.onerror = null;
|
||||
}
|
||||
images = [];
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user