diff --git a/assets/hub-globe.js b/assets/hub-globe.js index f97cfd1..fc7e189 100644 --- a/assets/hub-globe.js +++ b/assets/hub-globe.js @@ -11,7 +11,7 @@ * globe3d=8: hub SVG ellipse trace (breaks under rotation — deprecated). * globe3d=9: v4 sphere grid only (thin E–W + N–S) — proper rotation baseline. * globe3d=10: v4 visible-arc → screen ellipse (hub ry), disk-clipped. - * globe3d=11: v10 grid + ortho hub land + affine flat-plate wrap fallback. + * globe3d=11: v10 grid + geographic mercator-flat land (360° U-wrap). */ export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 }; @@ -27,6 +27,8 @@ const CONTINENT_INNER_TX = 223.66088631984587; const CONTINENT_INNER_TY = 238.0; const CONTINENT_INNER_SX = 1.2408477842003853; const CONTINENT_INNER_SY = 1.2408477842003853; +/** Map plate center longitude (extract_red_polygons.py CENTER_LON). */ +const MERCATOR_LON_CENTER = (12 * Math.PI) / 180; const RASTER_SCALE = 2; const AXIS_STEPS = 160; const SPHERE_AXIS_STEPS = 180; @@ -948,11 +950,13 @@ function sampleFlatPlateFromHub(mercFlat, hpX, hpY) { return sampleImageDataBilinearWrapU(mercFlat.data, mercFlat.w, mercFlat.h, sx, sy); } -/** Sphere tex → mercator-flat plate (lon offset + inverse Mercator Y). */ +/** Sphere tex → mercator-flat plate (lon center + inverse Mercator Y). */ function sampleMercFlatFromTex(mercFlat, tex) { const ll = texLonLat(tex); - const lon = wrapLon(ll.lon + (12 * Math.PI) / 180); - return sampleMercFlat(mercFlat, lon, ll.lat); + const lon = wrapLon(ll.lon + MERCATOR_LON_CENTER); + const lat = + Math.max(-1.52, Math.min(1.52, ll.lat / CONTINENT_INNER_SY)); + return sampleMercFlat(mercFlat, lon, lat); } function isLandPixel(r, g, b, a) { @@ -1063,19 +1067,13 @@ function sampleLandRgbaMercator(mercFlat, tex) { return null; } -/** globe3d=11 — ortho hub (reference N–S) + wrapped flat-plate fallback. */ -function sampleLandVisibleHemisphere(continents, mercFlat, tex) { +/** globe3d=11 — geographic mercator wrap (360°); z > LIMB_Z only. */ +function sampleLandVisibleHemisphere(mercFlat, tex) { if (tex.z <= LIMB_Z) { return null; } - const ortho = sampleHub(continents, tex); - if (isSolidContinentPixel(ortho[0], ortho[1], ortho[2], ortho[3])) { - return hubContinentRgba(ortho); - } - const hpX = GLOBE_VIEW.cx + tex.x * GLOBE_VIEW.r; - const hpY = GLOBE_VIEW.cy - tex.y * GLOBE_VIEW.r; - const flat = sampleFlatPlateFromHub(mercFlat, hpX, hpY); - if (flat && isHubContinentPixel(flat[0], flat[1], flat[2], flat[3])) { + const flat = sampleMercFlatFromTex(mercFlat, tex); + if (isHubContinentPixel(flat[0], flat[1], flat[2], flat[3])) { return hubContinentRgba(flat); } return null; @@ -1291,7 +1289,7 @@ export async function mountHubGlobe(stage, opts) { cy, r, fillDiskRegion(ctx, cx, cy, r, rotation, function (tex) { - const l = sampleLandVisibleHemisphere(continents, mercFlat, tex); + const l = sampleLandVisibleHemisphere(mercFlat, tex); return l || [0, 0, 0, 0]; }) ); diff --git a/index.php b/index.php index c3f6e87..ab45f4d 100644 --- a/index.php +++ b/index.php @@ -187,7 +187,7 @@ function hub_h(string $s): string { var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover')); var logoEnabled = !!(stage && supportsSvg && supportsLayout); - var logoBuild = '20260704globe16'; + var logoBuild = '20260704globe17'; function hubAsset(rel) { var link = document.querySelector('link[href*="hub.css"]');