Revert hiding vessel detection callouts under ambient cards

The vessels layer hid the detection callout for every vessel whose card
it published to the world overlay. The overlay paints only part of the
published cards (shared budget, collisions, UI chrome), so vessels whose
card was dropped lost all their text: with 60 vessels and Detection on,
21 showed only an arrow. Back to main's behaviour: the callout always
draws. Hiding it only under a painted card is HAL-628.

The translated speed unit in the callout stays.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-16 17:37:58 +04:00
1 parent 3adce33cc6
commit a2463ca2d2
7 files changed
+433 -250

No files matched your search

+1 -17
View File
@@ -1,6 +1,4 @@
// C6: a vessel with an ambient card gets no detection callout under it (the
// card already shows name, speed and course); the speed unit of a callout
// follows the UI language.
// The speed unit of a vessel's detection callout follows the UI language.
import test from 'node:test';
import assert from 'node:assert/strict';
import * as Cesium from 'cesium';
@@ -61,20 +59,6 @@ function detectable(cameraZ) {
}
}
test('a vessel with a card on screen draws no detection label', () => {
const objects = detectable(2_500);
const hidden = Object.values(objects).filter((object) => object.hideLabel);
assert.equal(hidden.length, 1, 'exactly the carded vessel hides its label');
const shown = Object.values(objects).filter((object) => !object.hideLabel);
assert.equal(shown.length, 1, 'the vessel without a card keeps its label');
assert.equal(hidden[0].skipLabel, false, 'not treated as the tracked vessel');
});
test('past the card fade the detection label comes back', () => {
const objects = detectable(4_000_000);
assert.ok(Object.values(objects).every((object) => !object.hideLabel));
});
test('ru: the callout speed unit is translated', () => {
setLocale('ru');
try {
-1
View File
@@ -129,7 +129,6 @@ export function createLifecycle({
state.lastFocusUpdate = 0;
state.activeFocusCount = 0;
state.activeLabelCount = 0;
state.cardedRecords = new Set();
state.selectedRecord = null;
state.trail = null;
state.trailPositions = [];
+1 -5
View File
@@ -471,7 +471,7 @@ export function createQueries({
* @param {Object} [options={}] - Options from the detection system.
* @param {number} [options.maxCount] - Maximum objects to return (defaults to all).
* @param {number} [options.seed] - Seed offset for stride sampling.
* @returns {Array<{position: Cesium.Cartesian3, id: string, type: string, skipLabel: boolean, hideLabel: boolean}>}
* @returns {Array<{position: Cesium.Cartesian3, id: string, type: string, skipLabel: boolean}>}
*/
getDetectableObjects(options = {}) {
if (
@@ -492,7 +492,6 @@ export function createQueries({
const start = seed % stride;
const selected = state.selectedRecord;
const carded = state.cardedRecords;
const result = [];
for (let idx = 0; idx < records.length; idx += 1) {
if ((idx - start) % stride !== 0) continue;
@@ -507,9 +506,6 @@ export function createQueries({
id: record.name || record.mmsi || 'VESSEL',
type: 'SEA',
skipLabel: record === selected,
// An open ambient card already names the vessel with its speed and
// course; a detection label under it would only cover them.
hideLabel: carded?.has(record) === true,
klass: record.type
? String(record.type).toUpperCase().slice(0, 14)
: undefined,
-23
View File
@@ -6,7 +6,6 @@ import {
VESSEL_OVERLAY_SOURCE_ID,
applyVesselOverlayPolicy,
VESSEL_CARD_FADE_DISTANCE_M,
VESSEL_CARD_FADE_START_RATIO,
} from '../../data/vesselLabels.js';
import {
cameraPoseSignature,
@@ -367,7 +366,6 @@ export function createRendering({
if (!scene || !records.length || maxLabels <= 0) {
state.activeLabelCount = entries.length;
state.cardedRecords = new Set();
publishVesselOverlayEntries(entries);
return;
}
@@ -405,9 +403,6 @@ export function createRendering({
if (screen) accepted.push({ x: screen.x, y: screen.y });
}
const ranked = [...cells.values()].sort((a, b) => b.score - a.score);
// Vessels with an ambient card: the card already shows name, speed and
// course, so the detection overlay draws no label of its own under it.
const carded = new Set();
for (const candidate of ranked) {
if (entries.length >= maxLabels) break;
if (
@@ -420,10 +415,8 @@ export function createRendering({
continue;
accepted.push({ x: candidate.x, y: candidate.y });
entries.push(components.cards.buildVesselCard(candidate.record));
if (cardFullyShown(scene, candidate.record)) carded.add(candidate.record);
}
state.activeLabelCount = entries.length;
state.cardedRecords = carded;
publishVesselOverlayEntries(entries);
}
@@ -476,22 +469,6 @@ export function createRendering({
);
}
/**
* Whether the host paints this ambient card at full strength: inside the
* start of its distance fade (applyVesselOverlayPolicy). Farther out the
* card fades away and the detection label stays the vessel's only text.
*/
function cardFullyShown(scene, record) {
const camera = scene.camera?.positionWC;
const visual = getVisual(record);
const position = visual.billboard?.position || visual.position;
if (!camera || !position) return true;
return (
Cesium.Cartesian3.distance(camera, position) <
VESSEL_CARD_FADE_DISTANCE_M * VESSEL_CARD_FADE_START_RATIO
);
}
function labelPriority(record, selected) {
if (record === selected) return 100000;
let score = 0;
-1
View File
@@ -70,7 +70,6 @@ export function createVesselState({ source, services }) {
activeFocusCount: 0,
activeLabelCount: 0,
/** @type {Set<Object>} Records that have an ambient card this pass. */
cardedRecords: new Set(),
selectedRecord: null,
/** @type {{setPositions: Function, clear: Function, destroy: Function}|null} Selected-vessel fading trail */
trail: null,