Files
gods-eye-view/src/layers/flights/evidence.js
T

171 lines
5.5 KiB
JavaScript

import * as Cesium from 'cesium';
import { aircraftIcon } from '../../data/aircraftIcons.js';
import { FOCUS_EVIDENCE_DEV } from './policy.js';
export function createEvidence({
flightState,
services,
parts,
layer,
resolveAsset,
}) {
/** Resolve a JSON-safe evidence position into ECEF. DEV-only caller. */
function _focusEvidencePosition(record) {
const cartesian = record?.cartesian;
if (
Array.isArray(cartesian) &&
cartesian.length >= 3 &&
cartesian.slice(0, 3).every(Number.isFinite)
) {
return Cesium.Cartesian3.fromElements(
cartesian[0],
cartesian[1],
cartesian[2],
);
}
if (
!Number.isFinite(record?.longitude) ||
!Number.isFinite(record?.latitude)
)
return null;
return Cesium.Cartesian3.fromDegrees(
record.longitude,
record.latitude,
Number.isFinite(record.altitudeM) ? record.altitudeM : 3_000,
);
}
/** Replace the real fleet with deterministic explicit-position contacts. */
function _setFocusEvidenceAircraft(records = []) {
if (
!FOCUS_EVIDENCE_DEV ||
!flightState._billboardCollection ||
!flightState._viewer
)
return { ok: false, count: 0 };
if (flightState._trackedIcao) parts.tracking._clearTracking();
parts.rendering._releaseModels();
for (const bb of flightState._billboards.values())
flightState._billboardCollection.remove(bb);
flightState._billboards.clear();
flightState.records.data.clear();
flightState._positionHistory.clear();
flightState._displayCourse.clear();
flightState.records.missingPolls.clear();
flightState._focusEvidenceIds.clear();
for (const record of Array.isArray(records) ? records : []) {
const id = String(record?.id || '')
.trim()
.toLowerCase();
const position = _focusEvidencePosition(record);
if (!id || !position) continue;
const klass = record.klass || 'airliner';
const altitudeM = Number.isFinite(record.altitudeM)
? record.altitudeM
: Cesium.Cartographic.fromCartesian(position)?.height || 3_000;
const meta = {
callsign: String(record.callsign || id).toUpperCase(),
altitude: altitudeM,
renderAltitudeM: altitudeM,
velocity: Number.isFinite(record.velocityMps) ? record.velocityMps : 0,
true_track: Number.isFinite(record.trackDeg) ? record.trackDeg : 90,
klass,
onGround: false,
wasAirborne: true,
turnRateDps: 0,
lastContactEpochMs: Date.now(),
rawLat: record.latitude ?? null,
rawLon: record.longitude ?? null,
};
flightState.records.data.set(id, meta);
flightState._cullPositions.delete(id);
flightState._focusEvidenceIds.add(id);
const bb = flightState._billboardCollection.add({
position,
image: aircraftIcon(parts.rendering._iconKind(id, klass)),
width: 20,
height: 20,
scale: parts.rendering._fleetBillboardScale(id, klass),
rotation: 0,
alignedAxis: Cesium.Cartesian3.ZERO,
color: parts.rendering._fleetBillboardColor(id),
sizeInMeters: false,
scaleByDistance: parts.rendering._normalBillboardScaleByDistance(),
disableDepthTestDistance: parts.rendering._groundDepthDistance(),
id,
show: true,
});
flightState._billboards.set(id, bb);
}
flightState.feed._count = flightState._billboards.size;
flightState._lastFleetTickMs = 0;
flightState._viewer.scene.requestRender?.();
return { ok: true, count: flightState.feed._count };
}
/** Update explicit evidence positions without rebuilding billboards. */
function _moveFocusEvidenceAircraft(records = []) {
if (!FOCUS_EVIDENCE_DEV) return { ok: false, moved: 0 };
let moved = 0;
for (const record of Array.isArray(records) ? records : []) {
const id = String(record?.id || '')
.trim()
.toLowerCase();
if (!flightState._focusEvidenceIds.has(id)) continue;
const position = _focusEvidencePosition(record);
const bb = flightState._billboards.get(id);
if (!position || !bb) continue;
bb.position = position;
const meta = flightState.records.data.get(id);
if (meta) {
if (Number.isFinite(record.trackDeg)) meta.true_track = record.trackDeg;
if (Number.isFinite(record.velocityMps))
meta.velocity = record.velocityMps;
}
moved += 1;
}
flightState._lastFleetTickMs = 0;
flightState._viewer?.scene?.requestRender?.();
return { ok: true, moved };
}
/** JSON-safe visual snapshot for the evidence report. */
function _focusEvidenceSnapshot() {
if (!FOCUS_EVIDENCE_DEV || !flightState._viewer) return [];
return [...flightState._focusEvidenceIds].map((id) => {
const bb = flightState._billboards.get(id);
const screen = bb?.position
? Cesium.SceneTransforms.worldToWindowCoordinates(
flightState._viewer.scene,
bb.position,
)
: null;
return {
id,
show: bb?.show === true,
scale: bb?.scale ?? null,
alpha: bb?.color?.alpha ?? null,
x: screen?.x ?? null,
y: screen?.y ?? null,
cameraDistanceM: bb?.position
? Cesium.Cartesian3.distance(
flightState._viewer.camera.positionWC,
bb.position,
)
: null,
};
});
}
return {
_focusEvidencePosition,
_setFocusEvidenceAircraft,
_moveFocusEvidenceAircraft,
_focusEvidenceSnapshot,
};
}