mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(analyst): restore exact region matches and remove search rescue
This commit is contained in:
commit
b0e0945360
86 files changed
+18094
-581
No files matched your search
+37
-121
@@ -152,39 +152,27 @@ test('regionFramingPlan: E-W elongated region looks along the east axis', () =>
|
||||
assert.equal(plan.headingDeg, 90);
|
||||
});
|
||||
|
||||
// Synthetic service responses exercise collisions with the physical-region
|
||||
// pack. These are authored fixtures, not captured geocoder responses.
|
||||
for (const [query, label, lat, lng, type, bounds] of [
|
||||
['Gold Coast', 'Gold Coast, Queensland, Australia', -28, 153.4, 'locality', [-28.2, 153.2, -27.8, 153.6]],
|
||||
['Santa Cruz', 'Santa Cruz, California, USA', 37, -122, 'locality', [36.9, -122.1, 37.1, -121.9]],
|
||||
['Isabela', 'Isabela, Philippines', 17, 122, 'administrative_area_level_1', [16.5, 121.5, 17.5, 122.5]],
|
||||
['India', 'India', 22, 79, 'country', [7, 67, 37, 91]],
|
||||
['Korea', 'South Korea', 36, 128, 'country', [33, 126, 39, 130]],
|
||||
]) {
|
||||
test(`search keeps the geocoded ${label} over its Natural Earth namesake`, async () => {
|
||||
const viewer = stubViewer();
|
||||
const geocodes = [];
|
||||
const result = await searchAndFlyTo(viewer, query, {
|
||||
placeSearch: {
|
||||
async geocode(request) {
|
||||
geocodes.push(request);
|
||||
return { place: { lat, lng, label, types: [type, 'political'], viewport: boxOf(...bounds) } };
|
||||
},
|
||||
// Compatibility guard for inherited geocode authority, not a newly fixed bug.
|
||||
test('search retains main geocode authority for Gold Coast, Australia', async () => {
|
||||
const viewer = stubViewer();
|
||||
const result = await runSearch(viewer, {}, {
|
||||
query: 'Gold Coast',
|
||||
result: {
|
||||
formatted_address: 'Gold Coast, Queensland, Australia',
|
||||
types: ['locality', 'political'],
|
||||
geometry: {
|
||||
location: { lat: -28, lng: 153.4 },
|
||||
viewport: boxOf(-28.2, 153.2, -27.8, 153.6),
|
||||
},
|
||||
recoverNearView: async () => null,
|
||||
});
|
||||
assert.deepEqual(geocodes, [query]);
|
||||
assert.equal(result.label, label);
|
||||
assert.equal(result.navigationMode, type === 'locality' ? 'city-overview' : 'region-overview');
|
||||
assert.equal(viewer.flights.length, 1);
|
||||
const flown = flownRectangleDegrees(viewer);
|
||||
assert.ok(Math.abs((flown.south + flown.north) / 2 - lat) < 0.000001, `${query}: latitude remains geocoded`);
|
||||
assert.ok(Math.abs((flown.west + flown.east) / 2 - lng) < 0.000001, `${query}: longitude remains geocoded`);
|
||||
assert.ok(flown.south <= bounds[0] && flown.north >= bounds[2], 'frames the geocoded north-south extent');
|
||||
assert.ok(flown.west <= bounds[1] && flown.east >= bounds[3], 'frames the geocoded east-west extent');
|
||||
assert.ok(flown.widthDeg < (bounds[3] - bounds[1]) * 1.6, 'keeps the geocoded place scale');
|
||||
},
|
||||
});
|
||||
}
|
||||
assert.equal(result.label, 'Gold Coast, Queensland, Australia');
|
||||
assert.equal(result.navigationMode, 'city-overview');
|
||||
assert.equal(viewer.flights.length, 1);
|
||||
const flown = flownRectangleDegrees(viewer);
|
||||
assert.ok(Math.abs((flown.south + flown.north) / 2 + 28) < 0.000001);
|
||||
assert.ok(Math.abs((flown.west + flown.east) / 2 - 153.4) < 0.000001);
|
||||
});
|
||||
|
||||
function alpsViewer() {
|
||||
const viewer = stubViewer();
|
||||
@@ -196,25 +184,7 @@ function alpsViewer() {
|
||||
return viewer;
|
||||
}
|
||||
|
||||
for (const answered of [true, false]) {
|
||||
test(`search recovers contained Alps only after geocoder ${answered ? 'miss' : 'unavailability'} and nearby recovery miss`, async () => {
|
||||
const viewer = alpsViewer();
|
||||
const order = [];
|
||||
const result = await searchAndFlyTo(viewer, 'the Alps', {
|
||||
placeSearch: { async geocode() { order.push('geocode'); return { place: null, answered }; } },
|
||||
recoverNearView: async () => { order.push('nearby'); return null; },
|
||||
});
|
||||
assert.deepEqual(order, ['geocode', 'nearby']);
|
||||
assert.equal(result?.label, 'Alps');
|
||||
assert.equal(result?.navigationMode, 'natural-region-swath');
|
||||
assert.equal(viewer.flights.length, 1);
|
||||
const target = Cesium.Cartographic.fromCartesian(viewer.flights[0].sphere.center);
|
||||
assert.ok(Cesium.Math.toDegrees(target.latitude) > 43 && Cesium.Math.toDegrees(target.latitude) < 49);
|
||||
assert.ok(Cesium.Math.toDegrees(target.longitude) > 5 && Cesium.Math.toDegrees(target.longitude) < 17);
|
||||
});
|
||||
}
|
||||
|
||||
test('a successful nearby recovery keeps precedence over a contained natural region', async () => {
|
||||
test('a successful nearby recovery resolves after a geocoder miss', async () => {
|
||||
const viewer = alpsViewer();
|
||||
const result = await searchAndFlyTo(viewer, 'the Alps', {
|
||||
placeSearch: { async geocode() { return { place: null, answered: true }; } },
|
||||
@@ -231,51 +201,19 @@ test('a successful nearby recovery keeps precedence over a contained natural reg
|
||||
assert.equal(viewer.flights.length, 1);
|
||||
});
|
||||
|
||||
test('missing searches never choose a natural namesake outside the view or without a view anchor', async () => {
|
||||
const withoutAnchor = alpsViewer();
|
||||
delete withoutAnchor.camera.positionCartographic;
|
||||
for (const [query, viewer] of [['the Alps', stubViewer()], ['not a real location', alpsViewer()], ['the Alps', withoutAnchor]]) {
|
||||
const result = await searchAndFlyTo(viewer, query, {
|
||||
placeSearch: { async geocode() { return { place: null, answered: true }; } },
|
||||
test('a geocoder miss returns null even over a namesake region', async () => {
|
||||
for (const answered of [true, false]) {
|
||||
const viewer = alpsViewer();
|
||||
const result = await searchAndFlyTo(viewer, 'the Alps', {
|
||||
placeSearch: { async geocode() { return { place: null, answered }; } },
|
||||
recoverNearView: async () => null,
|
||||
});
|
||||
assert.equal(result, null, query);
|
||||
assert.equal(viewer.flights.length, 0, query);
|
||||
assert.equal(result, null);
|
||||
assert.equal(viewer.flights.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
test('a duplicate natural name can recover when exactly one candidate contains the view', async () => {
|
||||
const viewer = stubViewer();
|
||||
Object.assign(viewer.camera.positionCartographic, {
|
||||
latitude: Cesium.Math.toRadians(5),
|
||||
longitude: Cesium.Math.toRadians(-73),
|
||||
});
|
||||
const result = await searchAndFlyTo(viewer, 'Cordillera Oriental', {
|
||||
placeSearch: { async geocode() { return { place: null, answered: true }; } },
|
||||
recoverNearView: async () => null,
|
||||
});
|
||||
assert.equal(result?.label, 'Cordillera Oriental');
|
||||
assert.equal(result?.navigationMode, 'natural-region-swath');
|
||||
assert.equal(viewer.flights.length, 1);
|
||||
const target = Cesium.Cartographic.fromCartesian(viewer.flights[0].sphere.center);
|
||||
assert.ok(Cesium.Math.toDegrees(target.latitude) > 0, 'frames the northern candidate');
|
||||
});
|
||||
|
||||
test('an overlapping natural name stays unresolved after geocoder and nearby recovery miss', async () => {
|
||||
const viewer = stubViewer();
|
||||
Object.assign(viewer.camera.positionCartographic, {
|
||||
latitude: Cesium.Math.toRadians(45.6336),
|
||||
longitude: Cesium.Math.toRadians(-74.86493),
|
||||
});
|
||||
const result = await searchAndFlyTo(viewer, 'Canadian Shield', {
|
||||
placeSearch: { async geocode() { return { place: null, answered: true }; } },
|
||||
recoverNearView: async () => null,
|
||||
});
|
||||
assert.equal(result, null);
|
||||
assert.equal(viewer.flights.length, 0);
|
||||
});
|
||||
|
||||
test('a geocoder rejection propagates without natural-region recovery or a flight', async () => {
|
||||
test('a geocoder rejection propagates without nearby recovery or a flight', async () => {
|
||||
const viewer = alpsViewer();
|
||||
const failure = new Error('geocoder failed');
|
||||
let recoveries = 0;
|
||||
@@ -287,7 +225,7 @@ test('a geocoder rejection propagates without natural-region recovery or a fligh
|
||||
assert.equal(viewer.flights.length, 0);
|
||||
});
|
||||
|
||||
test('search cancellation before or during geocoding cannot issue a fallback flight', async () => {
|
||||
test('search cancellation before or during geocoding cannot issue a flight', async () => {
|
||||
for (const preAborted of [true, false]) {
|
||||
const viewer = alpsViewer();
|
||||
const controller = new AbortController();
|
||||
@@ -312,48 +250,26 @@ test('search cancellation before or during geocoding cannot issue a fallback fli
|
||||
}
|
||||
});
|
||||
|
||||
test('cancellation while the bundled fallback is resolving cannot issue a flight', async () => {
|
||||
test('cancellation during nearby recovery cannot issue a flight', async () => {
|
||||
const viewer = alpsViewer();
|
||||
const carto = viewer.camera.positionCartographic;
|
||||
const controller = new AbortController();
|
||||
let recoveryFinished = false;
|
||||
let fallbackRead = false;
|
||||
let authorityChecks = 0;
|
||||
Object.defineProperty(viewer.camera, 'positionCartographic', {
|
||||
get() {
|
||||
if (recoveryFinished && !fallbackRead) {
|
||||
fallbackRead = true;
|
||||
// The fallback reads the view after nearby recovery, then awaits the
|
||||
// bundled lookup. Abort in that async gap, even when the pack is warm.
|
||||
queueMicrotask(() => controller.abort());
|
||||
}
|
||||
return carto;
|
||||
},
|
||||
});
|
||||
await assert.rejects(searchAndFlyTo(viewer, 'the Alps', {
|
||||
signal: controller.signal,
|
||||
placeSearch: { async geocode() { return { place: null, answered: true }; } },
|
||||
recoverNearView: async () => { recoveryFinished = true; return null; },
|
||||
recoverNearView: async () => {
|
||||
controller.abort();
|
||||
return {
|
||||
lat: 46.6, lon: 10.1, label: 'Alpine landmark',
|
||||
types: ['locality'],
|
||||
};
|
||||
},
|
||||
beforeFly: () => { authorityChecks += 1; return true; },
|
||||
}), { name: 'AbortError' });
|
||||
assert.equal(fallbackRead, true, 'reached the bundled recovery');
|
||||
assert.equal(authorityChecks, 0);
|
||||
assert.equal(viewer.flights.length, 0);
|
||||
});
|
||||
|
||||
test('a final authority veto blocks a contained natural-region recovery flight', async () => {
|
||||
const viewer = alpsViewer();
|
||||
const order = [];
|
||||
const result = await searchAndFlyTo(viewer, 'the Alps', {
|
||||
placeSearch: { async geocode() { order.push('geocode'); return { place: null, answered: true }; } },
|
||||
recoverNearView: async () => { order.push('nearby'); return null; },
|
||||
beforeFly: () => { order.push('veto'); return false; },
|
||||
});
|
||||
assert.deepEqual(order, ['geocode', 'nearby', 'veto']);
|
||||
assert.equal(result, CANCELLED_SEARCH);
|
||||
assert.equal(viewer.flights.length, 0);
|
||||
});
|
||||
|
||||
test('regionFramingPlan: park- and lake-scale viewports keep full framing', () => {
|
||||
// Zilker Park (~3 km).
|
||||
assert.equal(regionFramingPlan({
|
||||
|
||||
Reference in new issue
Block a user