Commit Graph
990 Commits
Author SHA1 Message Date
Sameh Khamis 046126eb36 Merge branch 'main' into feat/aqhi
Port to current main: main reserved layer-state token 0 for street-level, so
air-quality takes the next free token, 4 (registry, ledger, and the allocation
tests shift by one). Main moved source contracts into sourceComposition.js, so
air-quality registers its getSnapshot contract there. Package boundaries keep
main's lists plus this branch's air-quality modules and packages.
2026-10-15 12:39:00 -07:00
Sameh Khamis a4e2325ded Merge branch 'main' into docker-support 2026-10-15 12:34:50 -07:00
Sameh Khamis 1bb8643a28 Merge branch 'main' into fix/cap-remaining-upstream-reads
# Conflicts:
#	CHANGELOG.md
2026-10-15 12:34:49 -07:00
Said TurkseverandClaude Opus 5.5 56b113397d Merge upstream main into pr/panoramax
CHANGELOG: kept both Unreleased entries (satellite cloud filter #1084 and
Panoramax).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 20:07:26 +01:00
German Khokhlov 80cc0b536e style: format the phase 2 files and add them to the format scope
Prettier on the 13 new test files that failed --check; format-scope.json
now lists every file phase 2 added (src/globe/**, engineChoice, navaraMode,
cameraAngles, the QA scripts and pages, build/navaraAssets and tests).
2026-10-15 22:34:25 +04:00
Meir Michanie 0211e6e877 Merge upstream/main: cockpit emergency, GNSS integrity and GeoJSON import meet i18n
Upstream advanced past the KartaView merge: transponder-emergency HUD
wording (formatCockpitEmergency in cockpitMath), the GNSS integrity
layer joined the Events group, and a GeoJSON/KML/KMZ/GPX file-import
control landed - all in regions this branch localizes.

- cockpitMath: upstream's formatCockpitEmergency kept alongside the
  branch's formatter-injected Context scope (module stays i18n-free;
  squawk/ADS-B codes and the broadcast label are data).
- cockpitInstruments: the emergency HUD line composed with t()
  placeholders; fleet/feedState stay translated, the 'emergency' class
  toggle kept.
- layerPanel: upstream's gnss-integrity id with msg('Events').
- package-boundaries: both sides' entries unioned.
- New upstream UI strings marked and translated, as the branch's
  unmarked-string detector requires: the geo-import control's markup
  (data-i18n-title/-aria-label/text), its list titles, hints and
  summarize() lines (t/tn with placeholders), the aircraft emergency
  labels (msg data), and the GNSS legend blurb (t with placeholders).
- es/ru catalogs: 26 new keys each (2019 messages).

npm run i18n: complete, no unmarked strings. npm test: 6739/6741 (the
one failure is the pre-existing environmental OPENAI_API_KEY leak in
devFreshDotenv). Build passes.
2026-10-15 19:37:26 +02:00
German Khokhlov 64d3297301 fix(globe): keep the Navara camera above the ground
Navara 0.2.1's camera controller has no terrain or tile collision; its
only zoom limit, minimumZoomDistance, is a distance from the Earth's
centre, so a wheel zoom near the ground went through it (to -5.9 km).

groundFloor.js runs on the engine's preRender after the camera model
reads Navara's camera. While the camera is free (no flight, no lookAt
target) and below 20 km it samples the ground under it (tiles, else
terrain, else the ellipsoid; at most every 250 ms or 20 m), feeds
Navara's clamp (minimumZoomDistance = geocentric radius of the ground
point + 30 m, sent on changes over 10 m, reset to Navara's default
during flights and above 20 km) so the wheel stops smoothly, and lifts a
camera still below ground + 30 m straight up without camera.commanded.
It only lifts, so it cannot oscillate with the shell's ground guard,
whose lift is a flight the floor stands aside for.
2026-10-15 21:27:57 +04:00
German Khokhlov 4ded3fbf15 feat(app): run gev on Navara behind ?engine=navara
The page's engine is ?engine=cesium|navara, else localStorage gev.engine,
else Cesium (src/app/engineChoice.js). Cesium mode is unchanged.

In Navara mode (src/app/navaraMode.js, loaded with import() only then,
and loading the Navara globe the same way) the scene builds the Navara
globe on the app container with no viewer; map stacks go through
engine.maps (Google 3D from the browser key, else Esri imagery); only the
shell's own data credits are registered. The layer catalog is empty and
the controls get empty layer stand-ins. The shell does not create its
viewer-bound parts (cockpit view, celestial ring, detection, tracked
readout, post-process stages); the tools install the render governor on
the engine, skip the director, annotations, drawing, imagery box, scope
mask, voice and embedded views, skip the first-run welcome, and show
"Experimental Navara engine: layers, cockpit, director and voice are
unavailable". window.__godsEyeView.viewer is null.

Navara's attribution card is kept clear of the location tray. A few
shell paths became null-safe for the missing viewer, layers or stages
without changing Cesium behaviour.

scripts/qa-engine-shell.mjs checks both modes headless: boot, viewer,
console errors, map drawn, search and fly, north/tilt/zoom/reset, orbit,
HUD, share link restore and map stacks.
2026-10-15 20:56:16 +04:00
German Khokhlov 306e3e9467 build: reach Navara only through import() and ship its worker wasm
The import-direction check now tells dynamic imports apart
(analyzeModule(source, { dynamic: true })) and rejects any static import
or re-export of src/globe/navara/** from outside that directory, so the
Navara engine can only be a lazily loaded chunk of the app.

Navara's prebuilt workers load their wasm by file name next to
themselves, which the bundler cannot see; a build-only Rollup plugin
copies the missing ones (draco decoder, font worker) into assets/ when
the bundle includes Navara, and adds nothing to a build without it.
2026-10-15 20:56:06 +04:00
Said TurkseverandClaude Opus 5.5 b5de533567 Merge upstream main into pr/panoramax
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 16:56:15 +01:00
Said TurkseverandClaude Opus 5.5 b645a767c8 Street Level: Panoramax review follow-ups (gekh, #1134)
Image loading (photoViewer.js)
- One AbortController per open: a new open, close or unmount stops the
  previous photo's first and sharper downloads (an <img> by src = '').
  A collapsed viewer never falls back to the original; Panoramax's flat
  fallback is the thumbnail. A superseded open resolves quietly.
- Flat HD tracked as "loading" and "shown" apart: a discarded response no
  longer blocks later upgrades, and resizes while it loads ask once.
- No upgrade of the photo still shown while another opens.
- Size limits before decoding: imageSize.js reads JPEG/PNG/WebP/GIF
  headers; more than 64 MP or 16,384 px a side is refused undecoded, an
  <img> that decodes larger is refused and let go, flat HD needs a known
  width of at most 8,192 px, and panoramas always decode with a resize.

Panoramax provider
- Retry-After parsed as seconds or an HTTP date; the browser cannot read
  it here, so busy answers back off 5 s doubling to 300 s, reset once
  answered.
- Headers timed, then the body by an idle timeout (15 s of silence), so a
  slow link still gets its megabyte tiles.
- Cones centre only on the picture shown (onShowing), never on a late
  lookup; lookups nobody waits for are aborted (shared, refcounted).
- onReopen: a GPU reset redraws in the viewer, not through the core.
- Cones draw the home z15 tile at once and add neighbours as they arrive;
  a neighbour that failed is not counted as drawn.
- Coverage tiles decode in ~8 ms slices (a 2 MB z10 tile over Paris was
  one ~85-200 ms task); sorted by measured length without a Map.
- Box search asks for 20, not 100 (the API returns them nearest first).
- looksLikeEmail checks every '@'; creatorOf de-duplicates with a Set.

lineCoverage.js
- A redraw while a swap still builds keeps what is on screen (the swap's
  old lines and its ready new ones) and drops only the unready ones.

Tests for each (mutation-checked), two vacuous tests made real, the
cones' pictures lane and readable()'s busy/timeout paths covered; the
fixture's box search is nearest first. Docs: README filters and share
links, CHANGELOG HD wording, CURRENT-STATE.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 16:55:59 +01:00
German Khokhlov ec38e6ef16 refactor(ui): navigation, orientation, share links and HUD use the globe engine
The application shell keeps the page's globe engine and hands it to the
navigation controller, location navigation (search, city and POI flights,
orbit, globe reset), the tilt and north-up controls, share-link save and
restore, share restoration's first-gesture listeners and the HUD. The
viewer is passed only where entity tracking still lives on it (phase 1c)
and to the HUD's basemap label context (voice); every such use is null-safe.

Share links and captured shots write heading and roll as Cesium's camera
reports them (src/cameraAngles.js): the contract's [0, 2π) pose maps an
exact 0 back to Cesium's 2π, except the roll of a vertical view, so
links stay byte-identical (heading=360, roll=360) on every engine.

Source-reading tests follow the moved code with the same checks.
2026-10-15 19:47:51 +04:00
German Khokhlov 16e63f4c50 refactor(camera): use the globe engine
The startup fly-in, orbit, world-target focus, the arrival ground guard,
arrival ownership, camera sensitivity claims, landmark/viewport/globe
flights and place search (with its view bias and near-view recovery) take
the globe engine. Callers that still hold a viewer (voice, layers until
phase 1c) reach the same engine through engineFromViewer, and arrival
ownership is keyed by the engine whichever one a caller names.

The ground guard yields on camera.commanded instead of patching the
viewer camera itself; on Cesium that event hooks the same command methods
and tracking changes, so direct Cesium callers still end it. Landmark
framing reads the frustum fov from the pose's fovy and aspectRatio.

Tests that built viewer doubles now run on the fake engine (or on the
Cesium engine over the same double), with the same expectations.
2026-10-15 19:47:43 +04:00
quanticsoul4772 9688f15af7 Merge branch 'main' into feat/tools-area-breakdowns 2026-10-15 08:20:45 -07:00
Said TurkseverandClaude Opus 5.5 4e7c5c24e1 test(street-level): settle coverage before reading the ON/OFF pill
The pill step read #sl-status straight after the credit wait. Tiles
requested while Cesium painted the credit can flip it back to LOADING,
which failed CI on PR #1038 (actual 'BUTTON:LOADING:true'). Wait for
coverage to settle and the pill to read ON before asserting.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 16:06:30 +01:00
German Khokhlov 83c13f330d refactor(credits): use the globe engine
Map credits (maps/credits.js) are shown through a credits capability
(engine.credits.addStatic) instead of the scene's credit display; the
shared map scene takes the engine's credits, so the Cesium engine's maps
and its credits part share one owner. Data credits (registerDataCredits,
registerDynamicCredit, show/hideOsmCredit) take the globe engine and keep
accepting a viewer from layers that still hold one; the scene registers
the data credits on its engine. The Cesium credits part reads
Viewer.creditDisplay, else the scene frame state display it aliases.
2026-10-15 18:37:02 +04:00
German Khokhlov aaa6074663 refactor(overlays): use the globe engine
The world overlay host takes its frames (frames.postRender), camera events
(camera.moveEnd), canvas size (host.size), projection matrix
(projector.viewProjection), horizon test (projector.horizonVisible) and
render requests (render.request('world-overlay')) from the globe engine.
initWorldOverlay accepts an engine or, for callers that still hold a
viewer, resolves the viewer's engine through engineFromViewer.

Contract: camera.position(result) becomes camera.livePosition, one
engine-owned object holding the current position, so per-frame readers
and paint lanes keep a live camera position without allocating; engine
events gain raiseValue for argument-list-free frame dispatch. Steady-state
frame allocation is unchanged (worker probe, 30 chunks: 2696/9536/38593
B/frame before and after; detection 473749 -> 408085).
2026-10-15 18:32:40 +04:00
German Khokhlov 58a196374f feat(globe): engine members and the viewer bridge for the shell
Contract: camera.position(result?) and camera.height() for per-frame
readers, render.request(reason?), maps.releasePhotorealTiles, sources
with a caller-owned ready provider, isGlobeEngine. engine.maps now hides
every tileset it has shown, lets the last imagery/photoreal call win, and
setPhotorealTiles(null) restores the last base imagery and its credit
instead of leaving the photoreal credit on a bare globe.

Cesium engine: reads the Viewer camera/canvas aliases, detaches bridged
events through the remover Cesium returns, raises frame timestamps
without allocating, re-aims the horizon occluder only when the camera
moved, and renders the scene directly when the governor governs another
viewer (or none yet). engineFromViewer returns the registered scene
engine of a viewer, else builds and caches one. The render governor stays
the Cesium render backend under engine.render and gains
isRenderGovernorInstalled.
2026-10-15 18:18:19 +04:00
German Khokhlov a5c98c6b07 feat(app): construct the globe engine with the viewer
The scene builds the page's Cesium engine right after the viewer
(src/app/globeEngine.js), names the startup Google tileset to it once
loaded, returns it beside the viewer and destroys it before the viewer.
The debug handle exposes it as window.__godsEyeView.engine. Nothing
consumes it yet; render holds taken before the governor is installed
apply at install.

qa-globe-contract now runs on the app's engine (self-built only when the
app has none); a throwaway engine checks creation and destroy leave the
scene untouched.
2026-10-15 18:02:11 +04:00
German Khokhlov ab2368f3f3 fix(globe): tighten the Cesium engine after review
Map sources are applied through one src/maps/sceneApply.js helper shared by MapSourceController and engine.maps (live layer kept for an unchanged provider, providers cached per source). The contract gains flyTo endTransform and rectangle destinations, flyToSphere easing, drillPick width/height and pick content, with Cesium's own flyToSphere range. Input skips listeners removed during dispatch and stays inert after destroy.
2026-10-15 17:55:00 +04:00
German Khokhlov d831cbd23a feat(globe): implement the engine on Cesium
createCesiumEngine wraps an existing viewer without changing it: camera, picker, projector, frames, render (through the render governor), surface, input, credits and maps, with geo values out and Cesium values in at the boundary. Map and surface code is shared with src/maps and services/groundSnap instead of copied. scripts/qa-globe-contract.mjs runs the contract suite against the engine in headless Chrome; the camera-events check now waits for the previous move to end, as Cesium's moveStart marks a move from rest.
2026-10-15 17:43:05 +04:00
Said TurkseverandClaude Opus 5.5 26694380fb test(track): stub the geocode proxy routes, not the browser call
Reverse geocoding now goes to /api/google/reverse-geocode on the app
server, so the harness stub for maps.googleapis.com never matched and a
keyed run would reach Google live. Answer both proxy routes with
ZERO_RESULTS instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 14:36:06 +01:00
German Khokhlov 708c96b6f6 fix(globe): tighten the engine contract after review
Engine events get their own documented semantics (single registration,
branded instances); the fake follows Cesium's roll sign, angle ranges,
synchronous zero-duration flights, flyToSphere defaults and
computeViewRectangle. The contract adds viewProjection, horizonVisible,
flightActive, lookAtTransform/transform, zoomIn/zoomOut, input modifiers,
terrainHeight and clampToHeight, with geometric suite checks. Engine
import rules now follow each engine graph transitively.
2026-10-15 17:15:35 +04:00
German Khokhlov 528ec75f32 feat(globe): add the engine contract and its test suite
src/globe/contract.js defines the engine-neutral GlobeEngine capabilities
(JSDoc), createEngineEvent with Cesium.Event semantics and
assertGlobeEngine. src/globe/testing adds a geo-based fake engine for shell
tests and an engine-agnostic contract suite that the fake passes in Node.
check-import-directions keeps the contract free of cesium, three and
@navaramap, and each engine directory free of the other engine.
2026-10-15 17:01:08 +04:00
German KhokhlovandClaude Opus 5.5 8029747b7e Merge origin/main: GNSS integrity, geo file import and cockpit emergencies meet i18n
Conflicts resolved by keeping both sides: the Events group gains
gnss-integrity with a translated label, the cockpit aircraft line shows
main's transponder emergency through a localized formatter (cockpitMath.js
stays i18n-free, like the Context scope line), and the boundary lists keep
both the i18n modules and main's new data modules.

Main's new UI is translated into es and ru: the GNSS Integrity row, legend
and notes; geo file import (button, hints, list actions, every import
error, with numbers passed as placeholders); transponder status names.
Also formats kartaview/viewer.js so format:check passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 16:55:45 +04:00
Said TurkseverandClaude Opus 5.5 de83e1c17f Merge upstream/main into pr/panoramax
CHANGELOG: keep both new [Unreleased] entries (Panoramax, and the
emergency-transponder highlight from #856).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 12:57:53 +01:00
Mazeyar Moeini Feizabadi e3c07e43e3 Merge current main and reviewed GNSS into import integration 2026-10-15 13:48:39 +02:00
Mazeyar Moeini Feizabadi 65239ed110 Merge current main into GNSS integration candidate 2026-10-15 13:46:45 +02:00
ulihhhhandClaude Opus 5.5 da0a840b7b Merge upstream/main into feature/catalonia-cctv-cameras
Keep both: Catalonia CCTV alongside the NYC DOT TMC pack in the source
imports, README layer table and CURRENT-STATE data table, and both
CHANGELOG entries.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 10:09:28 +02:00
Meir Michanie 343a5df057 Merge branch 'main' into i18n-spanish 2026-10-15 08:57:13 +02:00
Mazeyar Moeini Feizabadi 5ea6d81310 fix(import): correct clamping and bound local-file rendering
Normalize GeoJSON ground footprints, preserve explicit KML track heights,
and tessellate ground paths before native loading. Validate coordinates,
geometry types and decoded image budgets before allocating native resources;
strip loader-sensitive metadata and settle deferred failures and cancellation.

Render static pins in owned billboard collections instead of walking tens
of thousands of point entities each frame. Refine nearby ground heights in
batches, isolate imported pins from height picks, and release owned resources
and point selections on removal. Use safe ray origins above a hidden coarse
globe and retain valid mesh heights outside the current footprint.

Frame complete geometry with viewport-aware nadir arrivals, including walls
and rotated overlays; respect camera gestures and accept document file drops.
Strengthen real-loader, native 3D Tiles, paint, clock and lifecycle coverage.
Addresses both P1 and all 25 P2 findings in the follow-up review of #1122.
2026-10-15 04:10:41 +02:00
Mazeyar Moeini Feizabadi 4092c2e9a2 merge: refresh file import integration against main 2026-10-15 02:48:47 +02:00
Kevin Rajan c90e212049 chore(ui): reconcile compact Radio ownership fix with current main
Preserve upstream changes, restore the reviewed Radio ownership regression,
and retain reporter raysung-2026 credit and #804 provenance.

Reconciles upstream main 81cf437 and PR #816 head 702ecc3; no force push.
2026-10-14 18:17:57 -05:00
quanticsoul4772andClaude Opus 5.5 e312a007ab Merge upstream main into feat/tools-area-breakdowns
Keep this branch's CHANGELOG entry above upstream's; upstream main no longer lists the GBFS station-name entry an earlier merge carried here.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 16:09:11 -07:00
quanticsoul4772andSameh Khamis e50bc45674 fix(qa): run the macOS-only gates on Windows and Linux (#1061)
Seven QA scripts hard-coded macOS Google Chrome. They now share chromeExecutablePath(): PUPPETEER_EXECUTABLE_PATH when set, then macOS Chrome when installed, otherwise Puppeteer's managed browser. The cables screenshot path is built with fileURLToPath so it works on Windows. qa-overlay-baseline keeps its fixed Chrome because its baselines record the executable.

Co-authored-by: Sameh Khamis <[email protected]>
2026-10-14 15:36:35 -07:00
quanticsoul4772andSameh Khamis 4cacd4cc00 fix(qa): exit QA gates gracefully on Windows (#1064)
process.exit(2) after a successful fetch trips a libuv assertion on Windows and turns the exit code into 127. The four gates set process.exitCode and return instead, and discard the unread reachability response so an early exit does not wait for the server to finish the body.

Co-authored-by: Sameh Khamis <[email protected]>
2026-10-14 14:48:53 -07:00
Sameh Khamis a9c41e7c3e Merge branch 'main' into fix/recent-imagery-qa-relative-layout-20261003 2026-10-14 14:29:12 -07:00
Sameh Khamis 8daaa065d2 qa: log the Recent Imagery gate's stability mode and document its flag 2026-10-14 14:16:30 -07:00
Sameh Khamis cb2ead3c16 Merge branch 'main' into fix/recent-imagery-qa-relative-layout-20261003 2026-10-14 14:12:59 -07:00
Sameh Khamis 7a9463bf2f Merge branch 'main' into fix/qa-stale-mutation-anchors 2026-10-14 14:12:55 -07:00
German Khokhlov f2fcd82290 test(qa): click street-level coverage at a verified pixel
The draped coverage line is about one pixel wide and can sit on a pixel
boundary: the probe hit at a fractional x while the click at the integer
pixel missed. Wait for tiles, click only at an integer pixel that picks the
line right before the click (off the centre column first), retry up to 4x.
2026-10-15 00:19:52 +04:00
German Khokhlov e3061872cc refactor(streetLevel,traffic,transit,firms,installations,radio,bikeshare,cables,detection): take vector maths from src/geo
Street level view/cameraFollow/groundClick/index, traffic footprint/viewport/ingestion, transit viewport/trails/state/rendering, FIRMS state/viewport, installations controls/viewport/state, radio queries/navigation/state, bikeshare viewport, submarine cable overlay and data/detection now use src/geo for Math, Cartesian2/3, Cartographic and WGS84 maths. Cesium stays for Rectangle, Ray, BoundingSphere, HeadingPitchRange, EasingFunction, EllipsoidGeodesic, EllipsoidalOccluder and the Ellipsoids passed into Cesium (pickEllipsoid, occluders). traffic/state.js keeps its Cesium lerp scratch (written per frame by Cesium.Cartesian3.lerp in animation.js; a geo scratch cost +4-7% there) and traffic/timing.js stays on Cesium (a test keeps it source-equivalent to model.parseRoads, outside this batch). street-level-layer, traffic-layer, installations-layer, bikeshare-layer and submarine-cables own the src/geo files.
2026-10-15 00:19:13 +04:00
German Khokhlov a915bdb3e5 refactor(launches,cctv,alpr): take vector maths from src/geo
Launches selection/replay/panel/policy/policyHelpers/state/camera, CCTV geometry/model/projection/navigation/cards/geometryQueue/state and ALPR model/visuals now use src/geo for Math, Cartesian2/3, Cartographic, Matrix3/4, Quaternion and ENU frames. launches/paths.js keeps Cesium (EllipsoidGeodesic). In camera.js, EllipsoidGeodesic, BoundingSphere.fromPoints/union and the BoundingSphere constructor stay on Cesium; the geo Cartographics passed into EllipsoidGeodesic are only read field by field and cloned there (computeProperties). The CCTV plane orientation stays a Cesium Quaternion and plane dimensions a Cesium Cartesian2 (entity ConstantProperty values). launches-layer and alpr-cameras own the src/geo files.
2026-10-15 00:18:35 +04:00
German Khokhlov 2b83606765 refactor(vessels,satellites,awareness): take vector maths from src/geo
Moves the Cartesian3/Cartographic/Matrix3/Matrix4/Math calls of the vessel, satellite and Contacts (awareness) layers, plus flights controller/enrichment, to src/geo. The satellites-layer package boundary now owns the src/geo modules. Awareness keeps Cesium.Cartesian3.clone for the resolved subject position, which reaches the installations anchor (anchor.test pins a Cesium instance).
2026-10-15 00:17:17 +04:00
German Khokhlov 1a69368ae6 refactor(ui,voice,annotations,scenes): take vector maths from src/geo
Move the Cartesian3/Cartographic/Matrix4/Transforms/Ellipsoid/Math calls of
the second batch (cockpit camera, context and controller; camera orientation
controls; application shell; location navigation; the annotation resolver
and engine; voice actions and pointer pick; the scene director; the embed
app) to src/geo. Behaviour is unchanged: same argument order, same `result`
semantics.

Kept on Cesium: out-of-scope classes (HeadingPitchRange, BoundingSphere,
Intersect, EllipsoidalOccluder, EasingFunction, SceneTransforms, JulianDate),
WGS84 where it goes into pickEllipsoid or EllipsoidalOccluder,
Matrix4.IDENTITY handed to lookAtTransform, and the Cartesian2 window
positions that reach scene.pickPosition: Cesium keys its per-frame pick
cache on windowPosition.toString(), which a plain object would collapse to
one "[object Object]" key.

The Contacts-subject harness in gevActions.test stubbed
Cesium.Cartographic.fromCartesian to place its subject; it now builds a real
subject position at the same coordinates with geo.cartesian3.fromDegrees.
The cockpit-controls and scenes package-boundary groups now own the src/geo
files.
2026-10-15 00:16:38 +04:00
German Khokhlov d886be68a8 refactor(camera,data): take vector maths from src/geo
Move the Cartesian3/Cartographic/Matrix/Quaternion/Transforms/Math calls of
the first batch (src/data motion, anchor, tracked-camera and icon helpers;
the root camera, locations, HUD, share-link, world-focus, ground-guard,
orbit and cloud modules; services/groundSnap) to src/geo. Behaviour is
unchanged: same argument order, same `result` semantics.

Kept on Cesium: out-of-scope classes (JulianDate, Axis, HeadingPitchRange,
BoundingSphere, Rectangle, EasingFunction, EllipsoidalOccluder with its
WGS84 and seed vector, SceneTransforms) and Matrix4.IDENTITY wherever it is
handed straight to a Cesium camera call (locations.test pins its identity).

synthesizeForwardKinematicsFix now returns a plain position, so the two
snapshot renderers clone it with the static Cesium.Cartesian3.clone instead
of the instance method. The package-boundary groups that reach these
modules now own the src/geo files.
2026-10-15 00:15:59 +04:00
German Khokhlov 4a92ed8377 feat(geo): add src/geo, Cesium's vector maths without Cesium
An engine-neutral port of the CesiumJS 1.138 core maths gev uses: angle
maths, the WGS84 ellipsoid and geodetic coordinates, 2D/3D vectors, 3x3/4x4
matrices, quaternions and local east-north-up / heading-pitch-roll frames.
Formulas and operation order match Cesium, so outputs are bit-identical
(golden tests pin the centre, pole, -0 and quaternion branches).

- Values are plain-data instances of module-private constructors (own
  enumerable fields only), so geo's hot functions keep their own V8 hidden
  classes; matrices are plain column-major arrays Cesium accepts.
- Cesium's debug argument checks are ported with the same conditions, order
  and DeveloperError messages, gated on DEBUG (src/geo/debug.js): on in Node
  and the dev server, folded away by vite build, as Cesium's Build strips
  them. A release-parity test compares DEBUG=false geo with Build/Cesium.
- The import-direction check forbids cesium and @cesium/* in src/geo;
  CODE-BOUNDARIES.md and THIRD_PARTY_NOTICES.md document the port.
2026-10-15 00:15:20 +04:00
Meir Michanie 29f2885cda Merge branch 'main' into i18n-spanish 2026-10-14 22:01:40 +02:00
Sameh Khamis 85754bcf50 test: say which CI job and which files the discovery guard covers 2026-10-14 11:59:14 -07:00
Sameh Khamis 3bc41cc12a Merge branch 'main' into fix/unit-runner-discovers-server-tests 2026-10-14 11:59:00 -07:00