mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
Frame a view that only follows an aircraft where the aircraft is
Asked for an aircraft's cockpit view, assistants passed only the follow, which failed for want of an area or camera, so every such request took a second call. show_in_gods_eye_view now looks the aircraft up and frames the view on it, and says so when the aircraft is not reported.
This commit is contained in:
1 parent
ae00f009e6
commit
b69d34bad2
2 files changed
+70
-9
No files matched your search
@@ -75,3 +75,36 @@ test('show_in_gods_eye_view names the panel and shows a view another answer retu
|
||||
(error) => error.code === 'invalid_arguments',
|
||||
);
|
||||
});
|
||||
|
||||
test('a view that only follows an aircraft is framed where the aircraft is', async () => {
|
||||
const { resolveViewArguments } = await import('./queries/share.js');
|
||||
const tools = {
|
||||
has: (name) => name === 'find_aircraft',
|
||||
call: async (name, args) => ({
|
||||
data: {
|
||||
rows:
|
||||
args.icao24 === 'ae1234'
|
||||
? [{ id: 'ae1234', lat: 32.7, lon: -117.2 }]
|
||||
: [],
|
||||
},
|
||||
}),
|
||||
};
|
||||
const { view, label } = await resolveViewArguments(
|
||||
{ follow: { kind: 'military_aircraft', id: 'ae1234', cockpit: true } },
|
||||
{ services: {}, tools },
|
||||
);
|
||||
assert.deepEqual(
|
||||
[view.camera.lat, view.camera.lon, view.follow.cockpit],
|
||||
[32.7, -117.2, true],
|
||||
);
|
||||
assert.equal(label, 'military aircraft ae1234');
|
||||
await assert.rejects(
|
||||
resolveViewArguments(
|
||||
{ follow: { kind: 'aircraft', id: 'abc999' } },
|
||||
{ services: {}, tools },
|
||||
),
|
||||
(error) =>
|
||||
error.code === 'invalid_arguments' &&
|
||||
/not reported now/.test(error.message),
|
||||
);
|
||||
});
|
||||
@@ -18,11 +18,30 @@ export const VIEW_ARGUMENTS = Object.freeze({
|
||||
...VIEW_PROPERTIES,
|
||||
});
|
||||
|
||||
// Altitude a view framed on a followed aircraft starts from.
|
||||
const FOLLOW_ALTITUDE_M = 20_000;
|
||||
|
||||
/** Where a followed aircraft is now, or null when no feed reports it. */
|
||||
async function followedAircraftPosition(follow, tools) {
|
||||
if (!['aircraft', 'military_aircraft'].includes(follow?.kind)) return null;
|
||||
if (!tools?.has('find_aircraft')) return null;
|
||||
try {
|
||||
const { data } = await tools.call('find_aircraft', { icao24: follow.id });
|
||||
const row = data?.rows?.find(
|
||||
(item) => Number.isFinite(item.lat) && Number.isFinite(item.lon),
|
||||
);
|
||||
return row ? { lat: row.lat, lon: row.lon } : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The view described by tool arguments. An area frames the camera straight
|
||||
* down over it; camera fields given alongside it override the framing.
|
||||
* down over it; camera fields given alongside it override the framing. A
|
||||
* view that only follows an aircraft is framed where the aircraft is now.
|
||||
*/
|
||||
export async function resolveViewArguments(args, { services, signal }) {
|
||||
export async function resolveViewArguments(args, { services, signal, tools }) {
|
||||
const base = args.view && typeof args.view === 'object' ? args.view : {};
|
||||
let camera = args.area
|
||||
? { ...args.camera }
|
||||
@@ -43,11 +62,19 @@ export async function resolveViewArguments(args, { services, signal }) {
|
||||
})
|
||||
: { ...framed, ...camera };
|
||||
}
|
||||
if (!Number.isFinite(camera.lat) || !Number.isFinite(camera.lon))
|
||||
throw new ToolError(
|
||||
'invalid_arguments',
|
||||
'Give a view, an area, or a camera with lat and lon',
|
||||
);
|
||||
const follow = args.follow ?? base.follow ?? null;
|
||||
if (!Number.isFinite(camera.lat) || !Number.isFinite(camera.lon)) {
|
||||
const position = await followedAircraftPosition(follow, tools);
|
||||
if (!position)
|
||||
throw new ToolError(
|
||||
'invalid_arguments',
|
||||
follow
|
||||
? `${follow.id} is not reported now; give an area or a camera with lat and lon too`
|
||||
: 'Give a view, an area, or a camera with lat and lon',
|
||||
);
|
||||
camera = { altitude_m: FOLLOW_ALTITUDE_M, ...camera, ...position };
|
||||
label = `${follow.kind === 'military_aircraft' ? 'military aircraft' : 'aircraft'} ${follow.id}`;
|
||||
}
|
||||
let view;
|
||||
try {
|
||||
view = createView({
|
||||
@@ -55,7 +82,7 @@ export async function resolveViewArguments(args, { services, signal }) {
|
||||
layers: args.layers ?? base.layers,
|
||||
style: args.style ?? base.style ?? null,
|
||||
map: args.map ?? base.map ?? null,
|
||||
follow: args.follow ?? base.follow ?? null,
|
||||
follow,
|
||||
annotations: args.annotations ?? base.annotations ?? [],
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -94,11 +121,12 @@ export const showInGodsEyeView = defineTool({
|
||||
},
|
||||
requires: ['app'],
|
||||
ui: { resourceUri: GLOBE_PANEL_URI },
|
||||
async run(args, { services, signal }) {
|
||||
async run(args, { services, signal, tools }) {
|
||||
const base = appBase(services);
|
||||
const { view, label } = await resolveViewArguments(args, {
|
||||
services,
|
||||
signal,
|
||||
tools,
|
||||
});
|
||||
const url = viewUrl(base, view);
|
||||
return {
|
||||
|
||||
Reference in new issue
Block a user