GODSIGH/js/layers/infra.js
type-two 2a51bcad2f fix: markers bled through the globe (far-side dots didn't track rotation)
Every marker used disableDepthTestDistance: Infinity, so points/billboards on
the FAR side of the Earth drew on top of the near hemisphere instead of being
occluded — reading as 'dots stuck, not moving with the globe' when you rotate.
Changed to 50000 (50km) across all layers: the globe now occludes far-side
markers, while you can still zoom right up to one without it clipping into the
surface. Also made the billboard layers (aircraft/military/adsb/radius) explicit
for consistent behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:19:21 +10:00

162 lines
5.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Infrastructure overlay (SPEC §6.5): static vector context for the theater —
// maritime choke points, major oil pipelines, and key facilities. No time
// dynamics. All coordinates are approximate and every description says so.
export default function create(ctx) {
const { viewer, CONFIG, lib, ui, Cesium } = ctx;
const C = CONFIG.colors;
const infraDS = new Cesium.CustomDataSource('infra');
viewer.dataSources.add(infraDS);
const ents = infraDS.entities;
const APPROX = 'Location approximate — illustrative reference geometry, not survey-grade.';
// Shared label defaults: readable at range, fades in as you zoom.
const labelBase = {
font: '12px "Segoe UI", system-ui, sans-serif',
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.fromCssColorString('#0a0f14'),
outlineWidth: 3,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: 50000,
translucencyByDistance: new Cesium.NearFarScalar(2.0e6, 1.0, 1.2e7, 0.0),
};
// ---- choke points: red ring + label ----
const chokepoints = [
{ name: 'Strait of Hormuz', lon: 56.5, lat: 26.6 },
{ name: 'Bab el-Mandeb', lon: 43.33, lat: 12.58 },
{ name: 'Suez Canal', lon: 32.35, lat: 30.45 },
{ name: 'Strait of Malacca', lon: 101.0, lat: 2.5 },
];
for (const cp of chokepoints) {
ents.add({
name: `Choke point — ${cp.name}`,
position: Cesium.Cartesian3.fromDegrees(cp.lon, cp.lat),
ellipse: {
semiMajorAxis: 80000,
semiMinorAxis: 80000,
material: Cesium.Color.fromCssColorString('rgba(255,0,60,1)').withAlpha(0.06),
outline: true,
outlineColor: lib.cz(C.chokepoint),
height: 0,
},
label: {
...labelBase,
text: cp.name,
fillColor: lib.cz(C.chokepoint),
pixelOffset: new Cesium.Cartesian2(0, -6),
},
description:
`<p><b>Maritime choke point.</b></p>` +
`<p>${cp.name} — a strategic strait for global energy and trade flows.</p>` +
`<p><i>${APPROX} The ring is a fixed ~80 km radius marker, not the true channel.</i></p>`,
});
}
// ---- pipelines: amber dashed polylines clamped to ground + midpoint label ----
const pipelines = [
{
name: 'EastWest (Petroline) crude pipeline',
note: 'Abqaiq → Yanbu',
coords: [49.68, 25.94, 46.7, 24.6, 44.5, 24.3, 41.5, 24.2, 38.06, 24.09],
},
{
name: 'HabshanFujairah crude pipeline',
note: 'bypasses the Strait of Hormuz',
coords: [53.61, 23.75, 54.6, 24.2, 55.5, 24.8, 56.33, 25.12],
},
];
for (const pl of pipelines) {
ents.add({
name: `Pipeline — ${pl.name}`,
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray(pl.coords),
width: 2,
clampToGround: true,
material: new Cesium.PolylineDashMaterialProperty({ color: lib.cz(C.pipeline) }),
},
description:
`<p><b>Oil pipeline.</b> ${pl.note}.</p>` +
`<p>${pl.name}.</p>` +
`<p><i>${APPROX} The route is a simplified schematic between endpoints.</i></p>`,
});
// Midpoint label at the middle vertex of the schematic route.
const mid = pipelineMidpoint(pl.coords);
ents.add({
name: `${pl.name} (label)`,
position: Cesium.Cartesian3.fromDegrees(mid[0], mid[1]),
label: { ...labelBase, text: pl.name, fillColor: lib.cz(C.pipeline) },
});
}
// ---- facilities: small square markers + type-annotated labels ----
const facilities = [
{ name: 'Ras Tanura', type: 'oil terminal', lon: 50.16, lat: 26.64 },
{ name: 'Abqaiq', type: 'oil processing plant', lon: 49.68, lat: 25.94 },
{ name: 'Yanbu', type: 'port / oil terminal', lon: 38.06, lat: 24.09 },
{ name: 'Kharg Island', type: 'oil export terminal', lon: 50.32, lat: 29.23 },
{ name: 'Fujairah', type: 'oil terminal', lon: 56.37, lat: 25.18 },
{ name: 'Jebel Ali', type: 'desalination plant', lon: 55.02, lat: 25.01 },
{ name: 'Ras Al-Khair', type: 'desalination plant', lon: 49.19, lat: 27.55 },
{ name: 'Al Udeid', type: 'air base', lon: 51.32, lat: 25.12 },
{ name: 'Haifa', type: 'refinery', lon: 35.05, lat: 32.79 },
];
const squareGlyph = facilitySquare(Cesium, C.facility);
for (const f of facilities) {
ents.add({
name: `Facility — ${f.name} ${f.type}`,
position: Cesium.Cartesian3.fromDegrees(f.lon, f.lat),
billboard: {
image: squareGlyph,
width: 9,
height: 9,
disableDepthTestDistance: 50000,
},
label: {
...labelBase,
text: f.name,
fillColor: lib.cz(C.facility),
pixelOffset: new Cesium.Cartesian2(0, -8),
},
description:
`<p><b>${f.name}</b> — ${f.type}.</p>` +
`<p><i>${APPROX}</i></p>`,
});
}
// ---- HUD row + status ----
ui.addLayer('infra', 'Infrastructure', true, (on) => { infraDS.show = on; });
ui.setStatus(
'infra',
`${chokepoints.length} choke points · ${pipelines.length} pipelines · ${facilities.length} facilities`,
'ok',
);
return { id: 'infra' };
}
// Geographic midpoint = the middle vertex of the route's [lon,lat,...] array.
function pipelineMidpoint(coords) {
const n = coords.length / 2;
const i = Math.floor(n / 2) * 2;
return [coords[i], coords[i + 1]];
}
// Tiny filled square canvas for facility markers (billboard image).
function facilitySquare(Cesium, hex) {
const s = 16;
const c = document.createElement('canvas');
c.width = s;
c.height = s;
const g = c.getContext('2d');
g.fillStyle = hex;
g.strokeStyle = '#0a0f14';
g.lineWidth = 2;
g.fillRect(2, 2, s - 4, s - 4);
g.strokeRect(2, 2, s - 4, s - 4);
return c;
}