mirror of
git://f0xx.org/ac/ac-be-hub
synced 2026-08-09 20:59:23 +03:00
fix(globe3d=11): mercator-only land wrap with correct projection
Drop ortho hub layer (ghost/double shadow). Sample flat plate with 12° lon center and inverse Mercator Y matching extract_red_polygons.py. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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 + visible-hemisphere continent wrap (ortho hub + mercator flat).
|
||||
* globe3d=11: v10 grid + mercator-flat land wrap (lon center 12°, inverse Mercator Y).
|
||||
*/
|
||||
export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 };
|
||||
|
||||
@@ -20,6 +20,8 @@ const DRAG_ROTATION_PER_PX = 0.004;
|
||||
const OCEAN_FALLBACK = { r: 22, g: 38, b: 60 };
|
||||
const FRONT_Z = 0.04;
|
||||
const LIMB_Z = 0.002;
|
||||
/** hub-logo-continents ortho / flat map center (extract_red_polygons.py). */
|
||||
const MERCATOR_LON_CENTER = (12 * Math.PI) / 180;
|
||||
const RASTER_SCALE = 2;
|
||||
const AXIS_STEPS = 160;
|
||||
const SPHERE_AXIS_STEPS = 180;
|
||||
@@ -877,19 +879,44 @@ function texLonLat(tex) {
|
||||
};
|
||||
}
|
||||
|
||||
function wrapLon(lon) {
|
||||
let l = lon;
|
||||
while (l > Math.PI) {
|
||||
l -= Math.PI * 2;
|
||||
}
|
||||
while (l < -Math.PI) {
|
||||
l += Math.PI * 2;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/** Inverse Mercator row — matches extract_red_polygons.py mercator_y_to_lat. */
|
||||
function latToMercatorRow(lat, h) {
|
||||
const clamped = Math.max(-1.52, Math.min(1.52, lat));
|
||||
const t = 0.5 + Math.asinh(Math.tan(clamped)) / (2 * Math.PI);
|
||||
return Math.max(0, Math.min(h - 1, (1 - t) * (h - 1)));
|
||||
}
|
||||
|
||||
function sampleMercFlat(mercFlat, lon, lat) {
|
||||
const u = ((lon + Math.PI) / (2 * Math.PI)) * (mercFlat.w - 1);
|
||||
const v = (0.5 - lat / Math.PI) * (mercFlat.h - 1);
|
||||
const u = ((wrapLon(lon) + Math.PI) / (2 * Math.PI)) * (mercFlat.w - 1);
|
||||
const v = latToMercatorRow(lat, mercFlat.h);
|
||||
return sampleImageDataBilinear(mercFlat.data, mercFlat.w, mercFlat.h, u, v);
|
||||
}
|
||||
|
||||
/** Sphere tex → mercator-flat plate (lon offset + inverse Mercator Y). */
|
||||
function sampleMercFlatFromTex(mercFlat, tex) {
|
||||
const ll = texLonLat(tex);
|
||||
const lon = wrapLon(ll.lon + MERCATOR_LON_CENTER);
|
||||
return sampleMercFlat(mercFlat, lon, ll.lat);
|
||||
}
|
||||
|
||||
function isLandPixel(r, g, b, a) {
|
||||
return a > 10 && r > 100 && g < 140 && b < 140;
|
||||
}
|
||||
|
||||
/** hub-logo-continents-mercator-{globe,flat}.svg grey-blue fills (not red JPG extract). */
|
||||
function isHubContinentPixel(r, g, b, a) {
|
||||
if (a < 12) {
|
||||
if (a < 8) {
|
||||
return false;
|
||||
}
|
||||
if (r > 168 && g > 198 && b > 218) {
|
||||
@@ -905,6 +932,10 @@ function isHubContinentPixel(r, g, b, a) {
|
||||
return b >= 100 && g >= 95 && r >= 68;
|
||||
}
|
||||
|
||||
function hubContinentRgba(sample) {
|
||||
return [sample[0], sample[1], sample[2], 255];
|
||||
}
|
||||
|
||||
/** Light hub grid strokes baked into hub-logo-fragment-globe.svg (vector grid drawn separately). */
|
||||
function isGridPixel(r, g, b, a) {
|
||||
if (a < 12) {
|
||||
@@ -969,19 +1000,14 @@ function sampleLandRgbaMercator(mercFlat, tex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** globe3d=11 — same visible hemisphere as v10 grid (z > LIMB_Z); ortho hub then mercator wrap. */
|
||||
function sampleLandVisibleHemisphere(continents, mercFlat, tex) {
|
||||
/** globe3d=11 — visible hemisphere (z > LIMB_Z); mercator-flat wrap (single source, no ortho ghost). */
|
||||
function sampleLandVisibleHemisphere(mercFlat, tex) {
|
||||
if (tex.z <= LIMB_Z) {
|
||||
return null;
|
||||
}
|
||||
const ortho = sampleHub(continents, tex);
|
||||
if (isHubContinentPixel(ortho[0], ortho[1], ortho[2], ortho[3])) {
|
||||
return [ortho[0], ortho[1], ortho[2], Math.min(255, ortho[3])];
|
||||
}
|
||||
const ll = texLonLat(tex);
|
||||
const flat = sampleMercFlat(mercFlat, ll.lon, ll.lat);
|
||||
const flat = sampleMercFlatFromTex(mercFlat, tex);
|
||||
if (isHubContinentPixel(flat[0], flat[1], flat[2], flat[3])) {
|
||||
return [flat[0], flat[1], flat[2], Math.min(255, flat[3])];
|
||||
return hubContinentRgba(flat);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1196,7 +1222,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];
|
||||
})
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user