From c58bc9864b401a32eabd024f6c772291cc28cf6c Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Wed, 28 Oct 2026 09:47:40 +0400 Subject: [PATCH] refactor(installations): make model engine neutral --- scripts/package-boundaries.json | 1 + src/layers/installations/model.js | 11 +++--- src/layers/installations/model.test.mjs | 45 +++++++++++++++++++++++++ src/layers/installations/state.js | 3 +- 4 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/layers/installations/model.test.mjs diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index d7181b767..171c65dd2 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -1257,6 +1257,7 @@ "src/layers/installations/source.js", "src/layers/installations/state.js", "src/layers/installations/viewport.js", + "src/layers/shared/color.js", "src/data/inputOwnership.js", "src/data/tomtomTiles.js", "src/sources/capability.js", diff --git a/src/layers/installations/model.js b/src/layers/installations/model.js index 19e10098b..e5aad2730 100644 --- a/src/layers/installations/model.js +++ b/src/layers/installations/model.js @@ -1,5 +1,6 @@ import { installationResponseSaturated } from './source.js'; -import * as Cesium from 'cesium'; +import * as geo from '../../geo/index.js'; +import { rgbaFromCss } from '../shared/color.js'; import { EARTH_MEAN_RADIUS_M, COLOR_BY_CLASS, @@ -18,8 +19,8 @@ export function createModel({ state: layerState, services, parts, source }) { latitudeBDeg, longitudeBDeg, ) { - const latitudeBRad = Cesium.Math.toRadians(latitudeBDeg); - const longitudeBRad = Cesium.Math.toRadians(longitudeBDeg); + const latitudeBRad = geo.math.toRadians(latitudeBDeg); + const longitudeBRad = geo.math.toRadians(longitudeBDeg); const latitudeDelta = latitudeBRad - latitudeARad; const longitudeDelta = Math.atan2( Math.sin(longitudeBRad - longitudeARad), @@ -39,9 +40,7 @@ export function createModel({ state: layerState, services, parts, source }) { } function colorFor(record) { - return Cesium.Color.fromCssColorString( - COLOR_BY_CLASS[record.class] || '#9ca6b0', - ); + return rgbaFromCss(COLOR_BY_CLASS[record.class] || '#9ca6b0'); } /** diff --git a/src/layers/installations/model.test.mjs b/src/layers/installations/model.test.mjs new file mode 100644 index 000000000..ebd1a76e3 --- /dev/null +++ b/src/layers/installations/model.test.mjs @@ -0,0 +1,45 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import * as geo from '../../geo/index.js'; +import { createModel } from './model.js'; + +const model = createModel({ state: {}, services: {}, parts: {}, source: {} }); + +test('installation distance prefilter wraps the date line and stays conservative at high latitudes', () => { + const from = geo.math.toRadians(179.8); + const distance = model.approximateSurfaceDistanceM( + geo.math.toRadians(70), + from, + 69.9, + -179.8, + ); + const start = geo.cartographic.fromDegrees(179.8, 70); + const end = geo.cartographic.fromDegrees(-179.8, 69.9); + const exact = geo.ellipsoidGeodesic.create(start, end).surfaceDistance; + + assert.ok(distance > 0 && distance < 50_000); + assert.ok(distance >= exact * 0.99); + assert.ok(distance <= exact * 1.03); +}); + +test('installation model returns engine-neutral palette and source presentation', () => { + const record = { + class: 'military_land', + sources: [ + { name: 'OpenStreetMap', id: 'way:1' }, + { name: 'OpenStreetMap', id: 'relation:2' }, + { name: 'Bundled registry', id: 'registry:3' }, + ], + }; + + assert.deepEqual(model.colorFor(record).rgba(), [ + 156 / 255, + 166 / 255, + 176 / 255, + 1, + ]); + assert.equal( + model.installationSourceLabel(record), + 'OpenStreetMap + Bundled registry', + ); +}); diff --git a/src/layers/installations/state.js b/src/layers/installations/state.js index 24ffc6e8f..d07ce006c 100644 --- a/src/layers/installations/state.js +++ b/src/layers/installations/state.js @@ -1,4 +1,3 @@ -import * as Cesium from 'cesium'; import * as geo from '../../geo/index.js'; export function createState({ services }) { @@ -6,7 +5,7 @@ export function createState({ services }) { state.distanceEndpointScratch = geo.cartographic.create(); - state.distanceGeodesicScratch = new Cesium.EllipsoidGeodesic(); + state.distanceGeodesicScratch = geo.ellipsoidGeodesic.create(); Object.assign(state, { viewer: null,