mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
fix: show the whole weather map when a window cannot cover the area
The map window was moved inside the product's bounds without checking that it still covered the requested area, so an area across the antimeridian got an image of only one side. A window must now hold the whole area, clipped to the product, or the tool returns the product's full extent.
This commit is contained in:
1 parent
4cfca57cfb
commit
7f56679a46
2 files changed
+31
-6
No files matched your search
@@ -33,10 +33,12 @@ const round = (value, digits) =>
|
||||
|
||||
/**
|
||||
* A 2:1 box snapped to 0.25° around the area, moved inside the product's
|
||||
* bounds. Returns null when the box would not fit, meaning the whole
|
||||
* extent should be shown instead.
|
||||
* bounds. Returns null when no such box covers the whole area (it would not
|
||||
* fit, or the area crosses the antimeridian), meaning the whole extent
|
||||
* should be shown instead.
|
||||
*/
|
||||
export function weatherWindow(area, bounds) {
|
||||
if (area.west > area.east) return null;
|
||||
const center = areaCenter(area);
|
||||
const halfHeight = Math.max(
|
||||
MIN_HALF_HEIGHT_DEGREES,
|
||||
@@ -57,12 +59,19 @@ export function weatherWindow(area, bounds) {
|
||||
snapDown(bounds.north - height),
|
||||
);
|
||||
const mapBox = { west, south, east: west + width, north: south + height };
|
||||
return mapBox.west >= bounds.west &&
|
||||
const insideProduct =
|
||||
mapBox.west >= bounds.west &&
|
||||
mapBox.east <= bounds.east &&
|
||||
mapBox.south >= bounds.south &&
|
||||
mapBox.north <= bounds.north
|
||||
? mapBox
|
||||
: null;
|
||||
mapBox.north <= bounds.north;
|
||||
// Moving the box inside the product can uncover part of the area; only a
|
||||
// box that still holds the whole area (clipped to the product) will do.
|
||||
const coversArea =
|
||||
mapBox.west <= Math.max(area.west, bounds.west) &&
|
||||
mapBox.east >= Math.min(area.east, bounds.east) &&
|
||||
mapBox.south <= Math.max(area.south, bounds.south) &&
|
||||
mapBox.north >= Math.min(area.north, bounds.north);
|
||||
return insideProduct && coversArea ? mapBox : null;
|
||||
}
|
||||
|
||||
export const getWeatherMap = defineTool({
|
||||
|
||||
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { composeCatalog, coreTools } from '../index.js';
|
||||
import { weatherWindow } from './atmosphere.js';
|
||||
import { resolveArea } from '../area.js';
|
||||
|
||||
const CONUS = { west: -130, south: 20, east: -60, north: 55 };
|
||||
const PNG = Uint8Array.from([0x89, 0x50, 0x4e, 0x47]);
|
||||
@@ -156,3 +157,18 @@ test('wind is sampled from the model grid at the location', async () => {
|
||||
(error) => error.code === 'unavailable',
|
||||
);
|
||||
});
|
||||
|
||||
test('a weather window that cannot cover the area falls back to the whole map', async () => {
|
||||
const world = { west: -180, south: -90, east: 180, north: 90 };
|
||||
// 100 km around 179.8° crosses the antimeridian.
|
||||
const dateline = await resolveArea({ lat: 0, lon: 179.8, radius_km: 100 });
|
||||
assert.equal(weatherWindow(dateline, world), null);
|
||||
// Near a product edge the window moves inside and still covers the area.
|
||||
const conus = { west: -130, south: 20, east: -60, north: 55 };
|
||||
const edge = await resolveArea({ lat: 40, lon: -129.5, radius_km: 50 });
|
||||
const box = weatherWindow(edge, conus);
|
||||
assert.ok(box);
|
||||
assert.ok(box.west <= Math.max(edge.west, conus.west));
|
||||
assert.ok(box.east >= edge.east);
|
||||
assert.ok(box.south <= edge.south && box.north >= edge.north);
|
||||
});
|
||||
Reference in new issue
Block a user