diff --git a/index.html b/index.html
index c4e7ccd..65953ee 100644
--- a/index.html
+++ b/index.html
@@ -54,6 +54,13 @@
+
+
+
+
+
+
+
@@ -110,17 +117,18 @@
Calibration empirique sur la vidéo earth-rotation.mp4 :
- Centre de la Terre dans le frame 1280×720 : (640, 360)
- Rayon visible : 340 px
- - Longitude centrale à t=0 : 140°E
- - Vitesse de rotation : -5.75°/s (apparent)
- La SVG utilise viewBox 1280×720 avec preserveAspectRatio="xMidYMid slice",
- même comportement que le video object-fit:cover → alignement parfait.
+ - Longitude centrale à t=0 : 150°E
+ - Vitesse de rotation : -6°/s (apparent)
+ Override en URL : ?lon0=150&rate=-6&debug=1
-------------------------------------------------------------------- */
(function () {
- const EARTH_CX = 640;
- const EARTH_CY = 360;
- const EARTH_R = 340;
- const LON0 = 140; // central longitude visible à t=0
- const ROT_RATE = -5.75; // °/s (négatif = view's central decreases)
+ const params = new URLSearchParams(location.search);
+ const EARTH_CX = +params.get('cx') || 640;
+ const EARTH_CY = +params.get('cy') || 360;
+ const EARTH_R = +params.get('r') || 340;
+ const LON0 = parseFloat(params.get('lon0') ?? '150');
+ const ROT_RATE = parseFloat(params.get('rate') ?? '-6');
+ const DEBUG = params.has('debug');
const PARIS = { lat: 48.85, lon: 2.35 };
const TANA = { lat: -18.9, lon: 47.5 };
@@ -172,6 +180,49 @@
const arcVecs = [];
for (let i = 0; i <= SAMPLES; i++) arcVecs.push(slerp(parisVec, tanaVec, i / SAMPLES));
+ // Debug overlay : projected sphere outline + equator + longitude grid
+ const dbgLayer = document.getElementById('debugLayer');
+ const dbgEarth = document.getElementById('dbgEarth');
+ const dbgEquator = document.getElementById('dbgEquator');
+ const dbgGrid = document.getElementById('dbgGrid');
+ const dbgLabel = document.getElementById('dbgLabel');
+ if (DEBUG) {
+ dbgLayer.style.display = '';
+ dbgEarth.setAttribute('cx', EARTH_CX);
+ dbgEarth.setAttribute('cy', EARTH_CY);
+ dbgEarth.setAttribute('r', EARTH_R);
+ }
+ function buildArcPath(vecs, rotAngle) {
+ let d = '', open = false;
+ for (const v of vecs) {
+ const p = project(rotateY(v, rotAngle));
+ if (p.z > 0) {
+ d += (open ? ' L ' : 'M ') + p.x.toFixed(1) + ' ' + p.y.toFixed(1);
+ open = true;
+ } else { open = false; }
+ }
+ return d;
+ }
+ // Pre-compute equator + meridians (every 30°)
+ const eqVecs = [];
+ for (let i = 0; i <= 180; i++) eqVecs.push(toCart(0, i * 2 - 180));
+ const meridianSets = [];
+ for (let lon = -180; lon < 180; lon += 30) {
+ const set = [];
+ for (let lat = -90; lat <= 90; lat += 5) set.push(toCart(lat, lon));
+ meridianSets.push(set);
+ if (DEBUG) {
+ const p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ p.setAttribute('stroke', '#ffea00');
+ p.setAttribute('stroke-width', '0.6');
+ p.setAttribute('fill', 'none');
+ p.setAttribute('opacity', '0.5');
+ p.setAttribute('stroke-dasharray', '3 3');
+ p.dataset.lon = lon;
+ dbgGrid.appendChild(p);
+ }
+ }
+
function update() {
// Time source : video.currentTime (loops automatically). Fallback : Date.now()
const t = (video && !isNaN(video.currentTime)) ? video.currentTime : (performance.now() / 1000);
@@ -237,6 +288,17 @@
pulseDot.style.opacity = 0;
}
+ // Debug overlay update
+ if (DEBUG) {
+ dbgEquator.setAttribute('d', buildArcPath(eqVecs, rotAngle));
+ const meridianPaths = dbgGrid.children;
+ for (let i = 0; i < meridianPaths.length; i++) {
+ meridianPaths[i].setAttribute('d', buildArcPath(meridianSets[i], rotAngle));
+ }
+ const central = ((LON0 + ROT_RATE * t) % 360 + 540) % 360 - 180;
+ dbgLabel.textContent = 't=' + t.toFixed(1) + 's central=' + central.toFixed(1) + '° rate=' + ROT_RATE + '°/s lon0=' + LON0;
+ }
+
// Group opacity = fade out when both pins are on the back side
const visFactor = Math.max(0, Math.min(1, (Math.max(pPar.z, pTan.z) + 0.05) * 4));
routeGroup.setAttribute('opacity', visFactor.toFixed(2));