fix(street-level): IC8 review of the Street View provider

Google's Maps Platform terms forbid Street View imagery beside non-Google
maps, so the provider declares requiresMapStack: 'photoreal': off Google
3D its chip is dashed with the reason, lookups and opens skip it, and
leaving Google 3D closes its panorama.

- Ground clicks: only a click on the map itself (scenePick.isSurfacePick:
  nothing picked or Google 3D tile content) at street zoom opens Street
  View, and the camera stays put; higher up the hint says to zoom in.
  scenePick.pickGroundPosition replaces the copy in Directions.
- Viewer: poses go out at once and again when the date and address
  arrive, so an open never hangs on that lookup; one lookup per panorama,
  seeded by the nearest lookup; a close settles a pending open; failed
  lookups are asked again; poses follow position changes, not pano_changed.
- Loader: the gm_authFailure handler is installed once, so a retried load
  reports a refusal once.
- Viewer host: a prewarm that lands after another provider took the host
  is released; FIT/FILL availability is set on every open.
- Provider: a refusal while switched off reports no error over another
  photo; SINCE compares against the end of Google's month; messages name
  the referrer and network causes; FLAT says Street View is 360° only.
- The layer row names the key of the providers that are on; the MCP panel
  CSP admits Street View's tiles, control images and photos.
- Tests for each, against fakes that now follow Google's event order; the
  browser gate restores its state, waits instead of sleeping, aims its
  panel clicks and corner drags, and asserts the camera stays put.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-08 02:59:51 +01:00
1 parent 22b0009138
commit 7bfcf177ac
35 files changed
+1108 -388

No files matched your search

+37 -19
View File
@@ -1,31 +1,49 @@
import * as Cesium from 'cesium';
import { GROUND_CLICK_MAX_HEIGHT_M } from './policy.js';
import { cameraHeightAboveGround, groundPointAt } from './view.js';
import { cameraHeightAboveGround } from './view.js';
/** Whether the camera is low enough for a click on the ground to mean a street. */
export function groundClickHeightOk(viewer, groundAt) {
if (!viewer?.camera?.positionCartographic) return false;
return (
cameraHeightAboveGround(viewer, { groundAt }) <= GROUND_CLICK_MAX_HEIGHT_M
);
}
/**
* A click on bare ground at street zoom opens the nearest image of the active
* providers that have no coverage to click (`groundClick`, Google Street
* View). `openNearest(point, {providerIds})` is the layer's lookup.
* @returns {(screenPosition: {x: number, y: number}) => Promise<boolean>|false}
* A click on the map itself (nothing picked, or Google 3D tile content) at
* street zoom opens the nearest image of the active, available providers
* that have no coverage to click (`groundClick`, Google Street View). The
* camera stays put: the user chose the spot.
* @param {{state: object, openNearest: Function, isAvailable: (entry: object) => boolean}} options
* @returns {(screenPosition: {x: number, y: number}, picked?: object) => Promise<boolean>|false}
*/
export function createGroundClick({ state, parts, openNearest }) {
return function openAtGround(screenPosition) {
const isWorldPosition = state.services.scenePick?.isPickedWorldPosition;
if (!state.enabled || !state.viewer || !isWorldPosition) return false;
export function createGroundClick({ state, openNearest, isAvailable }) {
return function openAtGround(screenPosition, picked) {
const scenePick = state.services.scenePick;
if (!state.enabled || !state.viewer || !scenePick?.pickGroundPosition)
return false;
if (!scenePick.isSurfacePick(picked) || !state.groundClickReady)
return false;
const providerIds = [...state.providers.values()]
.filter(
(entry) =>
entry.on && entry.def.groundClick && entry.status?.configured,
entry.on &&
entry.def.groundClick &&
entry.status?.configured &&
isAvailable(entry),
)
.map((entry) => entry.def.id);
if (!providerIds.length) return false;
// From higher up a click is a misclick, not a street.
const height = cameraHeightAboveGround(state.viewer, {
groundAt: parts.groundCaster?.groundAt,
});
if (!(height <= GROUND_CLICK_MAX_HEIGHT_M)) return false;
const point = groundPointAt(state.viewer, screenPosition, {
isWorldPosition,
});
return point ? openNearest(point, { providerIds }) : false;
const position = scenePick.pickGroundPosition(state.viewer, screenPosition);
const carto = position && Cesium.Cartographic.fromCartesian(position);
if (!carto) return false;
return openNearest(
{
lon: Cesium.Math.toDegrees(carto.longitude),
lat: Cesium.Math.toDegrees(carto.latitude),
},
{ providerIds, frame: false },
);
};
}