feat(vessels): key vessels by their source's stable id, and share a selected vessel

AIS Vessels are keyed by the id their live source gives, with the MMSI as an
attribute: an MMSI can be shared, spoofed or reused, so two vessels with one
MMSI are now two vessels. Looking a vessel up or selecting it by MMSI still
finds it.

A share link made while a vessel is selected opens that vessel. A UUID vessel
id travels as 16 bytes in a new thing field (13). A shared thing that is not
reporting now says so in a sentence per kind, with its id (ICAO, NORAD, MMSI
or vessel UUID) on a second line.
This commit is contained in:
Sameh Khamis committed 2026-11-10 18:12:53 -08:00
1 parent 57ff81f723
commit cbbf55cacd
74 files changed
+2481 -586

No files matched your search

+27
View File
@@ -59,6 +59,12 @@ export const SHARE_VIEW_FOLLOW_OFFSET_DEFAULT = Object.freeze({
pitch: -35,
});
/**
* The follow range a thing view can carry, in whole metres: 1 to this (the
* codec clamps to the same bound).
*/
export const SHARE_VIEW_FOLLOW_RANGE_MAX_M = 1e8;
const EARTH_RADIUS_M = 6_371_000;
const RAD = Math.PI / 180;
@@ -114,6 +120,27 @@ function enuBasis(lat, lon) {
const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
/**
* The follow offset that puts the camera at `camera` (lat, lon, alt) while
* following an entity at `fix`: the inverse of {@link followCameraFor}, on
* the same sphere, in whole metres and degrees. Null when the camera is not
* above the entity's local horizontal (a view from below it, or through the
* earth, has no follow offset), or is at the entity.
*/
export function followOffsetFor(fix, camera) {
const at = toEcef(fix.lat, fix.lon, fix.alt);
const from = toEcef(camera.lat, camera.lon, camera.alt);
const basis = enuBasis(fix.lat, fix.lon);
const delta = [0, 1, 2].map((i) => from[i] - at[i]);
const local = {
east: dot(delta, basis.east),
north: dot(delta, basis.north),
up: dot(delta, basis.up),
};
if (!(local.up > 0)) return null;
return followOffsetFromEnu(local);
}
/**
* Where the camera sits while following an entity at `fix` from `offset`,
* and how it looks back at the entity, on a sphere of radius 6 371 000 m. A