mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
refactor(street-level): drop openNearest; QA opens a photo by clicking a line then a cone
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
07a239fd82
commit
94049c5667
15 files changed
+61
-439
No files matched your search
@@ -27,15 +27,6 @@ export const THUMB_HOST = 'qa-fixture.mapillary.com';
|
||||
|
||||
const METRES_PER_DEG_LAT = 110_540;
|
||||
|
||||
/** Ground distance in metres, as the app's metresBetween. */
|
||||
export function metresApart(a, b) {
|
||||
const lat = (((a.lat + b.lat) / 2) * Math.PI) / 180;
|
||||
return Math.hypot(
|
||||
(b.lon - a.lon) * 111_320 * Math.cos(lat),
|
||||
(b.lat - a.lat) * METRES_PER_DEG_LAT,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Photos along PHOTO_LINE, south to north; every third one is a panorama.
|
||||
* @returns {Array<{id: string, lon: number, lat: number, isPano: boolean, capturedAt: number, compassAngle: number}>}
|
||||
@@ -181,18 +172,6 @@ export function answerMapillaryRequest({ method, url, images }) {
|
||||
: [];
|
||||
return { ...json(200, { data }), known: true };
|
||||
}
|
||||
if (q.has('lat') && q.has('lng')) {
|
||||
const at = { lat: Number(q.get('lat')), lon: Number(q.get('lng')) };
|
||||
const radius = Math.min(50, Number(q.get('radius')) || 50);
|
||||
const limit = Number(q.get('limit')) || 10;
|
||||
// In no particular order, as the real API answers.
|
||||
const data = photos
|
||||
.filter((image) => metresApart(at, image) <= radius)
|
||||
.reverse()
|
||||
.slice(0, limit)
|
||||
.map((image) => withFields(imageRecord(image), fields));
|
||||
return { ...json(200, { data }), known: true };
|
||||
}
|
||||
if (q.has('s2')) return { ...json(200, { data: [] }), known: true };
|
||||
return {
|
||||
...json(400, { error: 'unsupported images query' }),
|
||||
|
||||
@@ -264,6 +264,35 @@ async function assertKeyRequired(page) {
|
||||
assert.match(shown.hint, /MAPILLARY_CLIENT_TOKEN/, 'names the key to add');
|
||||
}
|
||||
|
||||
/**
|
||||
* Client coordinates of the first thing drawn whose pick id starts with
|
||||
* `prefix`, scanning `box` ({x, y, w, h} in canvas pixels; default: a row
|
||||
* across the middle) every `step` px; null when nothing matches.
|
||||
*/
|
||||
const findPick = (page, prefix, { box = null, step = 3 } = {}) =>
|
||||
page.evaluate(
|
||||
(want, area, stride) => {
|
||||
const { scene } = window.__godsEyeView.viewer;
|
||||
const rect = scene.canvas.getBoundingClientRect();
|
||||
const { x, y, w, h } = area || {
|
||||
x: 0,
|
||||
y: Math.round(rect.height / 2),
|
||||
w: rect.width,
|
||||
h: 1,
|
||||
};
|
||||
for (let py = y; py < y + h; py += stride)
|
||||
for (let px = x; px < x + w; px += stride) {
|
||||
const id = scene.pick({ x: px, y: py })?.id;
|
||||
if (typeof id === 'string' && id.startsWith(want))
|
||||
return { x: rect.left + px, y: rect.top + py, local: { x: px, y: py } };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
prefix,
|
||||
box,
|
||||
step,
|
||||
);
|
||||
|
||||
/** Park the camera over the photo line; a late startup flight can move it. */
|
||||
async function park(page) {
|
||||
for (let attempt = 0; attempt < 5; attempt++) {
|
||||
@@ -519,14 +548,30 @@ async function main() {
|
||||
await park(page);
|
||||
await waitForCoverage(page);
|
||||
await step(
|
||||
'the viewer loads and the nearest photo opens with a caption',
|
||||
'a line selects its sequence, and a cone opens its photo with a caption',
|
||||
async () => {
|
||||
await page.evaluate(() => {
|
||||
// Fire and forget: the open can outlive one CDP call.
|
||||
void window.__godsEyeView.dataManager.layers
|
||||
.get('street-level')
|
||||
.module.openNearest();
|
||||
// Fixtures answer lookups for the photo sequence only.
|
||||
const line = await findPick(
|
||||
page,
|
||||
fixtures ? `mly:seq:${PHOTO_SEQUENCE_ID}` : 'mly:seq:',
|
||||
);
|
||||
assert.ok(line, 'a sequence line across the middle of the view');
|
||||
await page.mouse.click(line.x, line.y);
|
||||
await uiUntil(
|
||||
page,
|
||||
(u) => u.sequence.selectedId && !u.sequence.loading,
|
||||
);
|
||||
const cone = await findPick(page, 'mly:img:', {
|
||||
box: {
|
||||
x: Math.max(0, line.local.x - 150),
|
||||
y: Math.max(0, line.local.y - 150),
|
||||
w: 300,
|
||||
h: 300,
|
||||
},
|
||||
step: 8,
|
||||
});
|
||||
assert.ok(cone, 'an image cone near the selected line');
|
||||
await page.mouse.click(cone.x, cone.y);
|
||||
await uiUntil(
|
||||
page,
|
||||
(u) => (u.street.imageId && !u.street.loading) || u.street.error,
|
||||
|
||||
Reference in new issue
Block a user