fix(infrastructure): sample visible ground below the ellipsoid

This commit is contained in:
German Khokhlov committed 2026-11-03 15:10:15 +04:00
1 parent 52b609480c
commit 65f0467ad8
3 files changed
+18 -10

No files matched your search

+2 -2
View File
@@ -2048,8 +2048,8 @@ Unchanged overlay entries do not request another frame; moved positions,
changed membership and re-enabling still publish. Ground sampling waits for
visible globe tiles to settle, and skips markers whose ground the camera
cannot see (unseen ground reads through the Earth and would retry every 2 s).
Ground is tested at loaded globe terrain, or across 0-9,000 m when the globe
is hidden, so photoreal views skip only ground well out of view. Until it is
Ground is tested at loaded globe terrain, or across -9,000 to 9,000 m when the
globe is hidden, so photoreal views skip only ground well out of view. Until it is
seen, a stem keeps its unsampled height, which can show for a stem whose base
is just off screen. Sampling uses valid loaded terrain as a floor while
retaining rooftop and below-sea-level elevations. A hidden globe does not
+7 -4
View File
@@ -797,7 +797,7 @@ test('an unseen base is not sampled and arms no retry until it is in view', asyn
* `cameraM` metres above the ellipsoid, looking at the base's ground at
* `groundM` (or directly away from it).
*/
function aimRealCamera(env, { groundM, cameraM, southM, away = false }) {
function aimRealCamera(env, { groundM, cameraM, southM, away = false, fov = Math.PI / 3 }) {
const entity = env.dataSources[0].entities.values[0];
const base = Cesium.Cartographic.fromCartesian(entity.__localBaseCartesian);
const ground = Cesium.Cartesian3.fromRadians(base.longitude, base.latitude, groundM);
@@ -822,7 +822,7 @@ function aimRealCamera(env, { groundM, cameraM, southM, away = false }) {
);
const up = Cesium.Cartesian3.cross(right, direction, new Cesium.Cartesian3());
const frustum = new Cesium.PerspectiveFrustum({
fov: Math.PI / 3,
fov,
aspectRatio: 800 / 600,
near: 1,
far: 1e8,
@@ -841,7 +841,10 @@ function aimRealCamera(env, { groundM, cameraM, southM, away = false }) {
const loadedTerrain = (height) => ({ show: true, tilesLoaded: true, getHeight: () => height });
const hiddenGlobe = { show: false, tilesLoaded: true, getHeight: () => undefined };
for (const { label, globe, groundM, cameraM, southM, baseOffScreen } of [
for (const { label, globe, groundM, cameraM, southM, fov, baseOffScreen } of [
// The Dead Sea (about -430 m) under a hidden globe, seen steeply down
// through a narrow view: both 0 m and 9,000 m above it are off screen.
{ label: 'hidden-globe depression', globe: hiddenGlobe, groundM: -430, cameraM: 20, southM: 180, fov: Math.PI / 12, baseOffScreen: true },
// 2,500 m terrain from 3 km away at a shallow angle: the ellipsoid-height
// base is far below the bottom of the screen.
{ label: 'high ground with loaded terrain', globe: loadedTerrain(2_500), groundM: 2_500, cameraM: 3_500, southM: 3_000, baseOffScreen: true },
@@ -857,7 +860,7 @@ for (const { label, globe, groundM, cameraM, southM, baseOffScreen } of [
const clock = installFakeClock(t);
t.after(() => { env.layer.destroy(env.viewer); env.cleanup(); });
env.viewer.scene.globe = globe;
const baseVisibility = aimRealCamera(env, { groundM, cameraM, southM });
const baseVisibility = aimRealCamera(env, { groundM, cameraM, southM, fov });
if (baseOffScreen)
assert.equal(baseVisibility, Cesium.Intersect.OUTSIDE, 'precondition: the ellipsoid-height base is off screen');
+9 -4
View File
@@ -1159,9 +1159,10 @@ function groundSamplePoint(record, height, result) {
* retry, each one a full offscreen render; 110 unseen data centres there held
* rest frames at 58-589 ms. Unsampled bases sit on the ellipsoid, so the test
* uses loaded globe terrain when there is some. Otherwise (a hidden globe) it
* tests the vertical from 0 to GROUND_SAMPLE_MAX_ABS_HEIGHT_M, every height a
* sample can accept, so high ground in view is never mistaken for an unseen
* base. Unseen ground is sampled on the first walk that sees it.
* tests the vertical across +/-GROUND_SAMPLE_MAX_ABS_HEIGHT_M, every height a
* sample can accept, so high or below-ellipsoid ground in view is never
* mistaken for an unseen base. Unseen ground is sampled on the first walk that
* sees it.
*/
function groundSampleInView(viewer, record) {
const camera = viewer.camera;
@@ -1170,7 +1171,11 @@ function groundSampleInView(viewer, record) {
const known =
Number.isFinite(terrain) &&
Math.abs(terrain) <= GROUND_SAMPLE_MAX_ABS_HEIGHT_M;
const low = groundSamplePoint(record, known ? terrain : 0, groundSampleLow);
const low = groundSamplePoint(
record,
known ? terrain : -GROUND_SAMPLE_MAX_ABS_HEIGHT_M,
groundSampleLow,
);
const high = known
? low
: groundSamplePoint(