mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix(infrastructure): sample visible ground below the ellipsoid
This commit is contained in:
1 parent
52b609480c
commit
65f0467ad8
3 files changed
+18
-10
No files matched your search
@@ -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
|
changed membership and re-enabling still publish. Ground sampling waits for
|
||||||
visible globe tiles to settle, and skips markers whose ground the camera
|
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).
|
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
|
Ground is tested at loaded globe terrain, or across -9,000 to 9,000 m when the
|
||||||
is hidden, so photoreal views skip only ground well out of view. Until it is
|
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
|
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
|
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
|
retaining rooftop and below-sea-level elevations. A hidden globe does not
|
||||||
|
|||||||
@@ -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
|
* `cameraM` metres above the ellipsoid, looking at the base's ground at
|
||||||
* `groundM` (or directly away from it).
|
* `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 entity = env.dataSources[0].entities.values[0];
|
||||||
const base = Cesium.Cartographic.fromCartesian(entity.__localBaseCartesian);
|
const base = Cesium.Cartographic.fromCartesian(entity.__localBaseCartesian);
|
||||||
const ground = Cesium.Cartesian3.fromRadians(base.longitude, base.latitude, groundM);
|
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 up = Cesium.Cartesian3.cross(right, direction, new Cesium.Cartesian3());
|
||||||
const frustum = new Cesium.PerspectiveFrustum({
|
const frustum = new Cesium.PerspectiveFrustum({
|
||||||
fov: Math.PI / 3,
|
fov,
|
||||||
aspectRatio: 800 / 600,
|
aspectRatio: 800 / 600,
|
||||||
near: 1,
|
near: 1,
|
||||||
far: 1e8,
|
far: 1e8,
|
||||||
@@ -841,7 +841,10 @@ function aimRealCamera(env, { groundM, cameraM, southM, away = false }) {
|
|||||||
const loadedTerrain = (height) => ({ show: true, tilesLoaded: true, getHeight: () => height });
|
const loadedTerrain = (height) => ({ show: true, tilesLoaded: true, getHeight: () => height });
|
||||||
const hiddenGlobe = { show: false, tilesLoaded: true, getHeight: () => undefined };
|
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
|
// 2,500 m terrain from 3 km away at a shallow angle: the ellipsoid-height
|
||||||
// base is far below the bottom of the screen.
|
// 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 },
|
{ 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);
|
const clock = installFakeClock(t);
|
||||||
t.after(() => { env.layer.destroy(env.viewer); env.cleanup(); });
|
t.after(() => { env.layer.destroy(env.viewer); env.cleanup(); });
|
||||||
env.viewer.scene.globe = globe;
|
env.viewer.scene.globe = globe;
|
||||||
const baseVisibility = aimRealCamera(env, { groundM, cameraM, southM });
|
const baseVisibility = aimRealCamera(env, { groundM, cameraM, southM, fov });
|
||||||
if (baseOffScreen)
|
if (baseOffScreen)
|
||||||
assert.equal(baseVisibility, Cesium.Intersect.OUTSIDE, 'precondition: the ellipsoid-height base is off screen');
|
assert.equal(baseVisibility, Cesium.Intersect.OUTSIDE, 'precondition: the ellipsoid-height base is off screen');
|
||||||
|
|
||||||
|
|||||||
@@ -1159,9 +1159,10 @@ function groundSamplePoint(record, height, result) {
|
|||||||
* retry, each one a full offscreen render; 110 unseen data centres there held
|
* 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
|
* 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
|
* 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
|
* tests the vertical across +/-GROUND_SAMPLE_MAX_ABS_HEIGHT_M, every height a
|
||||||
* sample can accept, so high ground in view is never mistaken for an unseen
|
* sample can accept, so high or below-ellipsoid ground in view is never
|
||||||
* base. Unseen ground is sampled on the first walk that sees it.
|
* mistaken for an unseen base. Unseen ground is sampled on the first walk that
|
||||||
|
* sees it.
|
||||||
*/
|
*/
|
||||||
function groundSampleInView(viewer, record) {
|
function groundSampleInView(viewer, record) {
|
||||||
const camera = viewer.camera;
|
const camera = viewer.camera;
|
||||||
@@ -1170,7 +1171,11 @@ function groundSampleInView(viewer, record) {
|
|||||||
const known =
|
const known =
|
||||||
Number.isFinite(terrain) &&
|
Number.isFinite(terrain) &&
|
||||||
Math.abs(terrain) <= GROUND_SAMPLE_MAX_ABS_HEIGHT_M;
|
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
|
const high = known
|
||||||
? low
|
? low
|
||||||
: groundSamplePoint(
|
: groundSamplePoint(
|
||||||
|
|||||||
Reference in new issue
Block a user