From 344fa08dbbc1370eee0e73fc1c1ec427f47d2ff3 Mon Sep 17 00:00:00 2001 From: vini Date: Sun, 19 Jul 2026 14:28:43 -0300 Subject: [PATCH] Prevent distorted constellation artwork --- plugin/contents/ui/dancer.html | 64 ++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/plugin/contents/ui/dancer.html b/plugin/contents/ui/dancer.html index d94cba8..c273192 100644 --- a/plugin/contents/ui/dancer.html +++ b/plugin/contents/ui/dancer.html @@ -1461,26 +1461,28 @@ function renderMilkyWay(lstDeg, glareOn) { return true; } -/* Resolve a transformação afim que prende três pixels da ilustração às suas - três estrelas Hipparcos projetadas. */ +/* Ajuste de similaridade: aproxima as três âncoras Hipparcos usando apenas + translação, rotação e escala uniforme. Diferente de uma transformação + afim completa, nunca achata nem alonga a anatomia das ilustrações. */ function constellationArtTransform(source, target) { - const [p1, p2, p3] = source; - const [q1, q2, q3] = target; - const den = p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + - p3[0] * (p1[1] - p2[1]); - if (Math.abs(den) < 1e-6) return null; - const solve = (v1, v2, v3) => ({ - x: (v1 * (p2[1] - p3[1]) + v2 * (p3[1] - p1[1]) + - v3 * (p1[1] - p2[1])) / den, - y: (v1 * (p3[0] - p2[0]) + v2 * (p1[0] - p3[0]) + - v3 * (p2[0] - p1[0])) / den, - t: (v1 * (p2[0] * p3[1] - p3[0] * p2[1]) + - v2 * (p3[0] * p1[1] - p1[0] * p3[1]) + - v3 * (p1[0] * p2[1] - p2[0] * p1[1])) / den, - }); - const x = solve(q1.x, q2.x, q3.x); - const y = solve(q1.y, q2.y, q3.y); - return [x.x, y.x, x.y, y.y, x.t, y.t]; + const pc = source.reduce((p, v) => [p[0] + v[0], p[1] + v[1]], [0, 0]) + .map(v => v / source.length); + const qc = target.reduce((p, v) => [p[0] + v.x, p[1] + v.y], [0, 0]) + .map(v => v / target.length); + let dot = 0, cross = 0, energy = 0; + for (let i = 0; i < source.length; i++) { + const px = source[i][0] - pc[0], py = source[i][1] - pc[1]; + const qx = target[i].x - qc[0], qy = target[i].y - qc[1]; + dot += px * qx + py * qy; + cross += px * qy - py * qx; + energy += px * px + py * py; + } + if (energy < 1e-6) return null; + const a = dot / energy; + const b = cross / energy; + const e = qc[0] - a * pc[0] + b * pc[1]; + const f = qc[1] - b * pc[0] - a * pc[1]; + return [a, b, -b, a, e, f]; } function drawConstellationArt(c, constellation, lst, W, horizonPx) { @@ -1498,12 +1500,36 @@ function drawConstellationArt(c, constellation, lst, W, horizonPx) { }; }); if (target.every(p => p.alt < -8) || target.every(p => p.alt > ALT_TOP + 8)) return; + if (!target.some(p => p.alt >= -8 && p.alt <= ALT_TOP + 8 && + p.x >= -W * 0.15 && p.x <= W * 1.15)) return; + const targetXs = target.map(p => p.x); + if (Math.max(...targetXs) - Math.min(...targetXs) > W * 0.62) return; const matrix = constellationArtTransform( art.anchors.map(anchor => anchor.pos), target ); if (!matrix || matrix.some(v => !Number.isFinite(v))) return; + /* Mesmo com escala uniforme, uma âncora próxima da descontinuidade do + azimute pode sugerir uma figura gigantesca. Limite visual conservador. */ + const scale = Math.hypot(matrix[0], matrix[1]); + const maxScale = Math.min( + W * 0.44 / art.size[0], horizonPx * 0.82 / art.size[1] + ); + if (scale > maxScale) { + const sourceCenter = [art.size[0] / 2, art.size[1] / 2]; + const screenCenter = [ + matrix[0] * sourceCenter[0] + matrix[2] * sourceCenter[1] + matrix[4], + matrix[1] * sourceCenter[0] + matrix[3] * sourceCenter[1] + matrix[5], + ]; + const shrink = maxScale / scale; + for (let i = 0; i < 4; i++) matrix[i] *= shrink; + matrix[4] = screenCenter[0] - matrix[0] * sourceCenter[0] - + matrix[2] * sourceCenter[1]; + matrix[5] = screenCenter[1] - matrix[1] * sourceCenter[0] - + matrix[3] * sourceCenter[1]; + } + c.save(); c.beginPath(); c.rect(0, 0, W, horizonPx);