mirror of
git://f0xx.org/ac/ac-be-hub
synced 2026-08-09 20:59:23 +03:00
Hub globe3d=10: v4 latitude arcs with screen-Y strip depth.
Hub 2D ellipses (v8) are not latitude circles and fail when rotated. Use v4 sphere arcs plus hub ry vertical thickness clipped at limb. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,8 +8,9 @@
|
|||||||
* 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=8: hub SVG ellipse trace (breaks under rotation — deprecated).
|
||||||
* globe3d=9: v8 parallels + v4 sphere meridians (split best-of).
|
* globe3d=9: reserved / same as 10.
|
||||||
|
* globe3d=10: v4 latitude arcs + screen-Y strip thickness (hub ry), limb-clipped.
|
||||||
*/
|
*/
|
||||||
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 };
|
||||||
|
|
||||||
@@ -549,6 +550,99 @@ function drawHubEllipseGridRotated(ctx, cx, cy, r, rotY, layoutScale) {
|
|||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** v4 latitude arc with hub ry as vertical screen thickness — rotates correctly. */
|
||||||
|
function fillParallelScreenStrip(ctx, cx, cy, r, rotY, par) {
|
||||||
|
const halfPx = (par.bright ? HUB_EW_PARALLELS[0].ry : HUB_EW_PARALLELS[1].ry) * (r / GLOBE_VIEW.r);
|
||||||
|
const ring = parallelBodyRingAtLat(par.lat, SPHERE_AXIS_STEPS);
|
||||||
|
const rgb = par.bright ? '219,231,246' : '231,236,243';
|
||||||
|
let run = [];
|
||||||
|
|
||||||
|
function flushFill() {
|
||||||
|
if (run.length < 2) {
|
||||||
|
run = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let zSum = 0;
|
||||||
|
for (let k = 0; k < run.length; k++) {
|
||||||
|
zSum += run[k].z;
|
||||||
|
}
|
||||||
|
const zAvg = zSum / run.length;
|
||||||
|
const t = Math.max(0, Math.min(1, (zAvg - LIMB_Z) / (0.95 - LIMB_Z)));
|
||||||
|
if (t <= 0) {
|
||||||
|
run = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const alpha = (par.bright ? 0.16 + 0.48 * t : 0.09 + 0.34 * t).toFixed(3);
|
||||||
|
ctx.beginPath();
|
||||||
|
for (let k = 0; k < run.length; k++) {
|
||||||
|
ctx.lineTo(run[k].sx, run[k].sy - halfPx);
|
||||||
|
}
|
||||||
|
for (let k = run.length - 1; k >= 0; k--) {
|
||||||
|
ctx.lineTo(run[k].sx, run[k].sy + halfPx);
|
||||||
|
}
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fillStyle = 'rgba(' + rgb + ',' + alpha + ')';
|
||||||
|
ctx.fill();
|
||||||
|
run = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < ring.length; i++) {
|
||||||
|
const view = bodyToView(ring[i], rotY);
|
||||||
|
if (view.z <= LIMB_Z) {
|
||||||
|
flushFill();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
run.push({
|
||||||
|
sx: cx + view.x * r,
|
||||||
|
sy: cy - view.y * r,
|
||||||
|
z: view.z,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
flushFill();
|
||||||
|
|
||||||
|
strokeBodyRing(
|
||||||
|
ctx,
|
||||||
|
cx,
|
||||||
|
cy,
|
||||||
|
r,
|
||||||
|
rotY,
|
||||||
|
ring,
|
||||||
|
function (z) {
|
||||||
|
return parallelStyle(par.bright, 1, z, LIMB_Z);
|
||||||
|
},
|
||||||
|
LIMB_Z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** globe3d=10 — v4 E–W arcs, screen-vertical band; v4 meridians. */
|
||||||
|
function drawSphereGridScreenStrip(ctx, cx, cy, r, rotY, layoutScale) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
||||||
|
ctx.clip();
|
||||||
|
|
||||||
|
SPHERE_PARALLELS.forEach(function (par) {
|
||||||
|
fillParallelScreenStrip(ctx, cx, cy, r, rotY, par);
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
|||||||
@@ -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 = '20260704globe8';
|
var logoBuild = '20260704globe10';
|
||||||
|
|
||||||
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