mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
fix: handle antimeridian crossing in clampBoundsAroundCenter
east - west assumed a linear longitude axis, so a viewport crossing the antimeridian (west=179.98, east=-179.98) produced a negative span and unnormalized output coordinates outside [-180, 180). Wrap the span through 360 and normalize the clamped west/east back into range. Fixes #352.
This commit is contained in:
1 parent
5f60d86bc9
commit
c22ad6af32
2 files changed
+61
-3
No files matched your search
@@ -113,6 +113,33 @@ export function deriveFetchCenter({ nadirLat, nadirLon, hitLat, hitLon, maxPullK
|
||||
return { lat: pulled.lat, lon: pulled.lon, source: 'pulled' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapped longitude span between two meridians, in degrees.
|
||||
*
|
||||
* Longitude is cyclic, so a box crossing the antimeridian (±180°) has
|
||||
* `east < west` (e.g. `west = 179.98, east = -179.98`). A plain `east - west`
|
||||
* goes negative in that case; wrap through 360° instead.
|
||||
*
|
||||
* @param {number} west - West edge longitude (degrees).
|
||||
* @param {number} east - East edge longitude (degrees).
|
||||
* @returns {number} Span in degrees, always >= 0.
|
||||
*/
|
||||
function longitudeSpanDeg(west, east) {
|
||||
const raw = east - west;
|
||||
return raw >= 0 ? raw : raw + 360;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a longitude into [-180, 180). Matches the wrap idiom already
|
||||
* used by `destinationPoint()` above.
|
||||
*
|
||||
* @param {number} lon - Longitude in degrees.
|
||||
* @returns {number} Longitude normalized to [-180, 180).
|
||||
*/
|
||||
function normalizeLonDeg(lon) {
|
||||
return ((lon + 540) % 360) - 180;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp a bounding box's spans to `maxSpanDeg` and recenter it on `center`.
|
||||
*
|
||||
@@ -120,6 +147,10 @@ export function deriveFetchCenter({ nadirLat, nadirLon, hitLat, hitLon, maxPullK
|
||||
* but centers the box on the derived look-at point instead of the view
|
||||
* rectangle's midpoint. Idempotent when `center` is the box's own midpoint.
|
||||
*
|
||||
* Longitude is handled as a cyclic axis: the input span wraps correctly
|
||||
* across the antimeridian, and the output west/east are normalized back into
|
||||
* [-180, 180) instead of drifting outside the normal coordinate range.
|
||||
*
|
||||
* @param {{south:number, west:number, north:number, east:number}} bounds
|
||||
* Source bounds (span donor).
|
||||
* @param {{lat:number, lon:number}} center - Fetch center (degrees).
|
||||
@@ -128,11 +159,11 @@ export function deriveFetchCenter({ nadirLat, nadirLon, hitLat, hitLon, maxPullK
|
||||
*/
|
||||
export function clampBoundsAroundCenter(bounds, center, maxSpanDeg = 0.05) {
|
||||
const latSpan = Math.min(bounds.north - bounds.south, maxSpanDeg);
|
||||
const lonSpan = Math.min(bounds.east - bounds.west, maxSpanDeg);
|
||||
const lonSpan = Math.min(longitudeSpanDeg(bounds.west, bounds.east), maxSpanDeg);
|
||||
return {
|
||||
south: center.lat - latSpan / 2,
|
||||
north: center.lat + latSpan / 2,
|
||||
west: center.lon - lonSpan / 2,
|
||||
east: center.lon + lonSpan / 2,
|
||||
west: normalizeLonDeg(center.lon - lonSpan / 2),
|
||||
east: normalizeLonDeg(center.lon + lonSpan / 2),
|
||||
};
|
||||
}
|
||||
@@ -108,3 +108,30 @@ test('span clamp is idempotent on already-clamped bounds (loadRoadsForBounds re-
|
||||
const twice = clampBoundsAroundCenter(once, midpoint, 0.05);
|
||||
assert.deepEqual(twice, once);
|
||||
});
|
||||
|
||||
test('span clamp handles bounds crossing the antimeridian', () => {
|
||||
const bounds = {
|
||||
south: -0.02,
|
||||
north: 0.02,
|
||||
west: 179.98,
|
||||
east: -179.98,
|
||||
};
|
||||
|
||||
const center = {
|
||||
lat: 0,
|
||||
lon: 179.99,
|
||||
};
|
||||
|
||||
const result = clampBoundsAroundCenter(bounds, center, 0.05);
|
||||
|
||||
assert.ok(result.west >= -180 && result.west < 180);
|
||||
assert.ok(result.east >= -180 && result.east < 180);
|
||||
|
||||
// Wrapped longitude span should remain about 0.04 degrees.
|
||||
const span =
|
||||
result.east >= result.west
|
||||
? result.east - result.west
|
||||
: result.east - result.west + 360;
|
||||
|
||||
assert.ok(Math.abs(span - 0.04) < 1e-12);
|
||||
});
|
||||
Reference in new issue
Block a user