diff --git a/assets/hub-globe.js b/assets/hub-globe.js index ad91ded..fbb8570 100644 --- a/assets/hub-globe.js +++ b/assets/hub-globe.js @@ -12,7 +12,7 @@ * 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 + geographic mercator-flat land (360° U-wrap). - * ?latf=1.25&lngf=1&zy=0&zx=0 — land plate zoom (linear + non-linear). + * ?latf=1.25&lngf=1&zy=1&zx=1&pp=0&pe=0 — land plate zoom + pole/limb lens pinch. */ export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 }; @@ -31,7 +31,7 @@ const CONTINENT_INNER_SY = 1.2408477842003853; /** Map plate center longitude (extract_red_polygons.py CENTER_LON). */ const MERCATOR_LON_CENTER = (12 * Math.PI) / 180; /** Default land-plate zoom (?latf / ?lngf / ?zy / ?zx on globe3d=11). */ -const LAND_ZOOM_DEFAULT = { latf: 1.25, lngf: 1, zy: 1, zx: 1 }; +const LAND_ZOOM_DEFAULT = { latf: 1.25, lngf: 1, zy: 1, zx: 1, pp: 0, pe: 0 }; function clampZoomNum(v, min, max, fallback) { if (typeof v !== 'number' || !isFinite(v)) { @@ -47,21 +47,27 @@ function resolveLandZoom(raw) { lngf: clampZoomNum(r.lngf, 0.05, 4, LAND_ZOOM_DEFAULT.lngf), zy: clampZoomNum(r.zy, 0.05, 4, LAND_ZOOM_DEFAULT.zy), zx: clampZoomNum(r.zx, 0.05, 4, LAND_ZOOM_DEFAULT.zx), + pp: clampZoomNum(r.pp, 0, 0.95, LAND_ZOOM_DEFAULT.pp), + pe: clampZoomNum(r.pe, 0, 0.95, LAND_ZOOM_DEFAULT.pe), }; } /** - * Linear latf/lngf on sphere lon/lat; zy/zx bias zoom toward equator/ prime meridian: - * mul = factor × (1 + z×(1−t²)), t = |coord|/pole (1 at pole, 0 at center line). + * Land plate sample remap (globe3d=11 URL tunables): + * latf/lngf — linear zoom; zy/zx — equator/prime-meridian mag (1 = uniform). + * pp — pole lens pinch (0 = off): pulls N/S sample toward equator near poles. + * pe — limb lens pinch (0 = off): pulls E/W sample toward center near disk edges. */ function landZoomLonLat(lon, lat, zoom) { const latT = Math.min(1, Math.abs(lat) / (Math.PI / 2)); const lonT = Math.min(1, Math.abs(lon) / Math.PI); - const latMul = zoom.latf * (1 + zoom.zy * (1 - latT * latT)); - const lonMul = zoom.lngf * (1 + zoom.zx * (1 - lonT * lonT)); + const latMul = zoom.latf * (zoom.zy * (1 - latT * latT) + latT * latT); + const lonMul = zoom.lngf * (zoom.zx * (1 - lonT * lonT) + lonT * lonT); + const poleLens = 1 - zoom.pp * latT * latT; + const edgeLens = 1 - zoom.pe * lonT * lonT; return { - lon: wrapLon(lon * lonMul + MERCATOR_LON_CENTER), - lat: Math.max(-1.52, Math.min(1.52, lat * latMul)), + lon: wrapLon(lon * lonMul * edgeLens + MERCATOR_LON_CENTER), + lat: Math.max(-1.52, Math.min(1.52, lat * latMul * poleLens)), }; } const RASTER_SCALE = 2; @@ -1403,6 +1409,8 @@ export async function mountHubGlobe(stage, opts) { stage.dataset.globeLngf = String(landZoom.lngf); stage.dataset.globeZy = String(landZoom.zy); stage.dataset.globeZx = String(landZoom.zx); + stage.dataset.globePp = String(landZoom.pp); + stage.dataset.globePe = String(landZoom.pe); } stage.dataset.globeAxis = renderVersion === 11 @@ -1436,6 +1444,8 @@ export async function mountHubGlobe(stage, opts) { delete stage.dataset.globeLngf; delete stage.dataset.globeZy; delete stage.dataset.globeZx; + delete stage.dataset.globePp; + delete stage.dataset.globePe; }, }; } diff --git a/index.php b/index.php index dcfcf91..b133cb6 100644 --- a/index.php +++ b/index.php @@ -257,7 +257,7 @@ function hub_h(string $s): string { var globe3dVersion = globe3dRaw === null || globe3dRaw === '' ? 1 : parseInt(globe3dRaw, 10); if (!isFinite(globe3dVersion)) globe3dVersion = 1; var globeLandZoom = {}; - ['latf', 'lngf', 'zy', 'zx'].forEach(function (key) { + ['latf', 'lngf', 'zy', 'zx', 'pp', 'pe'].forEach(function (key) { var raw = params.get(key); if (raw === null || raw === '') return; var n = parseFloat(raw);