mirror of
git://f0xx.org/ac/ac-be-hub
synced 2026-08-09 20:59:23 +03:00
Hub globe3d=8: hub ellipses on sphere, gap-safe stroke.
Latitude bands (v6/7) are flat strips under Y-rot; trace hub SVG ellipses to sphere with null-gap flush to avoid chord artifacts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,8 @@
|
|||||||
* globe3d=5: hub ellipse trace (deprecated — breaks under rotation).
|
* globe3d=5: hub ellipse trace (deprecated — breaks under rotation).
|
||||||
* globe3d=6: v4 math + latitude band fill (continuous arc paths).
|
* globe3d=6: v4 math + latitude band fill (continuous arc paths).
|
||||||
* globe3d=7: v4 math + wide centerline stroke bands (no fill quads).
|
* globe3d=7: v4 math + wide centerline stroke bands (no fill quads).
|
||||||
|
* globe3d=8: hub SVG ellipse → sphere trace, wide stroke, gap-safe (ellipses at rest).
|
||||||
|
* globe3d=9: v8 parallels + v4 sphere meridians (split best-of).
|
||||||
*/
|
*/
|
||||||
export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 };
|
export const GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 322, rim: 330 };
|
||||||
|
|
||||||
@@ -208,13 +210,9 @@ function ellipseBodyRing(ellipse, steps) {
|
|||||||
const out = [];
|
const out = [];
|
||||||
for (let i = 0; i <= steps; i++) {
|
for (let i = 0; i <= steps; i++) {
|
||||||
const a = (i / steps) * Math.PI * 2;
|
const a = (i / steps) * Math.PI * 2;
|
||||||
const body = hubPixelToBody(
|
out.push(
|
||||||
ellipse.cx + ellipse.rx * Math.cos(a),
|
hubPixelToBody(ellipse.cx + ellipse.rx * Math.cos(a), ellipse.cy + ellipse.ry * Math.sin(a))
|
||||||
ellipse.cy + ellipse.ry * Math.sin(a)
|
|
||||||
);
|
);
|
||||||
if (body) {
|
|
||||||
out.push(body);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -278,6 +276,10 @@ function strokeBodyRing(ctx, cx, cy, r, rotY, bodies, styleAt, limbZ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < bodies.length; i++) {
|
for (let i = 0; i < bodies.length; i++) {
|
||||||
|
if (!bodies[i]) {
|
||||||
|
flush();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const view = bodyToView(bodies[i], rotY);
|
const view = bodyToView(bodies[i], rotY);
|
||||||
if (view.z <= zCut) {
|
if (view.z <= zCut) {
|
||||||
flush();
|
flush();
|
||||||
@@ -486,6 +488,67 @@ function drawSphereGridBanded(ctx, cx, cy, r, rotY, layoutScale, opts) {
|
|||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Hub ellipse centerline on sphere, wide stroke — stays elliptical under Y rotation (globe3d=8). */
|
||||||
|
function strokeHubEllipseParallel(ctx, cx, cy, r, rotY, ellipse, layoutScale) {
|
||||||
|
const scale = r / GLOBE_VIEW.r;
|
||||||
|
const bandPx = Math.max(ellipse.bright ? 5 : 8, 2 * ellipse.ry * scale);
|
||||||
|
const par = { bright: ellipse.bright };
|
||||||
|
const ring = ellipseBodyRing(ellipse, AXIS_STEPS);
|
||||||
|
strokeBodyRing(
|
||||||
|
ctx,
|
||||||
|
cx,
|
||||||
|
cy,
|
||||||
|
r,
|
||||||
|
rotY,
|
||||||
|
ring,
|
||||||
|
function (z) {
|
||||||
|
return parallelBandStyle(par, z, bandPx, 'halo');
|
||||||
|
},
|
||||||
|
LIMB_Z
|
||||||
|
);
|
||||||
|
strokeBodyRing(
|
||||||
|
ctx,
|
||||||
|
cx,
|
||||||
|
cy,
|
||||||
|
r,
|
||||||
|
rotY,
|
||||||
|
ring,
|
||||||
|
function (z) {
|
||||||
|
return parallelBandStyle(par, z, bandPx, 'core');
|
||||||
|
},
|
||||||
|
LIMB_Z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** globe3d=8 — hub E–W ellipses on sphere; v4 N–S meridians. */
|
||||||
|
function drawHubEllipseGridRotated(ctx, cx, cy, r, rotY, layoutScale) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
||||||
|
ctx.clip();
|
||||||
|
|
||||||
|
HUB_EW_PARALLELS.forEach(function (ellipse) {
|
||||||
|
strokeHubEllipseParallel(ctx, cx, cy, r, rotY, ellipse, layoutScale);
|
||||||
|
});
|
||||||
|
|
||||||
|
SPHERE_MERIDIANS.forEach(function (mer) {
|
||||||
|
strokeBodyRing(
|
||||||
|
ctx,
|
||||||
|
cx,
|
||||||
|
cy,
|
||||||
|
r,
|
||||||
|
rotY,
|
||||||
|
meridianBodyRingAtLon(mer.lon, SPHERE_AXIS_STEPS),
|
||||||
|
function (z) {
|
||||||
|
return meridianStyle(mer.prime, layoutScale, z, LIMB_Z);
|
||||||
|
},
|
||||||
|
LIMB_Z
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
/** globe3d=7 — v4 sphere model, wide stroke bands (no path fill). */
|
/** globe3d=7 — v4 sphere model, wide stroke bands (no path fill). */
|
||||||
function drawSphereGridWideStroke(ctx, cx, cy, r, rotY, layoutScale, opts) {
|
function drawSphereGridWideStroke(ctx, cx, cy, r, rotY, layoutScale, opts) {
|
||||||
const parallelsOnly = !!(opts && opts.parallelsOnly);
|
const parallelsOnly = !!(opts && opts.parallelsOnly);
|
||||||
@@ -623,6 +686,10 @@ function drawGlobeGrid(ctx, cx, cy, r, rotY, layoutScale, renderVersion) {
|
|||||||
drawSphereGridWideStroke(ctx, cx, cy, r, rotY, layoutScale, { parallelsOnly: false });
|
drawSphereGridWideStroke(ctx, cx, cy, r, rotY, layoutScale, { parallelsOnly: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (renderVersion === 8 || renderVersion === 9) {
|
||||||
|
drawHubEllipseGridRotated(ctx, cx, cy, r, rotY, layoutScale);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (renderVersion >= 2) {
|
if (renderVersion >= 2) {
|
||||||
drawSphereGrid(ctx, cx, cy, r, rotY, layoutScale, { parallelsOnly: false });
|
drawSphereGrid(ctx, cx, cy, r, rotY, layoutScale, { parallelsOnly: false });
|
||||||
return;
|
return;
|
||||||
@@ -1014,17 +1081,19 @@ export async function mountHubGlobe(stage, opts) {
|
|||||||
raf = requestAnimationFrame(tick);
|
raf = requestAnimationFrame(tick);
|
||||||
stage.dataset.globe3d = String(renderVersion);
|
stage.dataset.globe3d = String(renderVersion);
|
||||||
stage.dataset.globeAxis =
|
stage.dataset.globeAxis =
|
||||||
renderVersion >= 7
|
renderVersion >= 8
|
||||||
? 'ew-sphere-stroke'
|
? 'ew-hub-ellipse-rot'
|
||||||
: renderVersion >= 6
|
: renderVersion >= 7
|
||||||
? 'ew-sphere-band'
|
? 'ew-sphere-stroke'
|
||||||
: renderVersion >= 5
|
: renderVersion >= 6
|
||||||
? 'ew-hub-ellipse'
|
? 'ew-sphere-band'
|
||||||
: renderVersion >= 3
|
: renderVersion >= 5
|
||||||
? 'ew-sphere'
|
? 'ew-hub-ellipse'
|
||||||
: renderVersion >= 2
|
: renderVersion >= 3
|
||||||
? 'ew-ns-sphere'
|
? 'ew-sphere'
|
||||||
: 'ew-ns-grid';
|
: renderVersion >= 2
|
||||||
|
? 'ew-ns-sphere'
|
||||||
|
: 'ew-ns-grid';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ function hub_h(string $s): string {
|
|||||||
var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover'));
|
var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover'));
|
||||||
var logoEnabled = !!(stage && supportsSvg && supportsLayout);
|
var logoEnabled = !!(stage && supportsSvg && supportsLayout);
|
||||||
|
|
||||||
var logoBuild = '20260704globe7';
|
var logoBuild = '20260704globe8';
|
||||||
|
|
||||||
function hubAsset(rel) {
|
function hubAsset(rel) {
|
||||||
var link = document.querySelector('link[href*="hub.css"]');
|
var link = document.querySelector('link[href*="hub.css"]');
|
||||||
|
|||||||
Reference in New Issue
Block a user