From 3d15f20c7f65b866005ff9157c26322fc9701c6f Mon Sep 17 00:00:00 2001 From: Gregory Salaun Date: Tue, 16 Jun 2026 20:24:49 +0200 Subject: [PATCH] fix: proper beam heading on the map --- frontend/src/components/MainMap.tsx | 35 ++++++++++------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/MainMap.tsx b/frontend/src/components/MainMap.tsx index 70a870e..4b1d30e 100644 --- a/frontend/src/components/MainMap.tsx +++ b/frontend/src/components/MainMap.tsx @@ -122,10 +122,8 @@ export function MainMap({ fromGrid, toGrid, fromLabel, toLabel, beamAzimuths, be if (from && beamAzimuths && beamAzimuths.length) { const half = (beamWidth ?? 30) / 2; const D = 5500; // lobe length (km) - // A great circle pointing poleward runs to lat ±90, where Mercator is - // infinite — the line then snaps across the top of the map. Generate the - // radial with plenty of points (smooth curve) and STOP it just before the - // pole, so a north/south beam draws a clean line toward the edge instead. + // Great-circle radial out to distance D, stopping just short of the pole so + // a poleward line doesn't snap across the top of the Mercator map. const radial = (b: number): [number, number][] => { const pts: [number, number][] = []; const N = 64; @@ -137,26 +135,17 @@ export function MainMap({ fromGrid, toGrid, fromLabel, toLabel, beamAzimuths, be return pts; }; for (const az of beamAzimuths) { - const arc: [number, number][] = []; - for (let b = az - half; b <= az + half + 0.001; b += 2) { - const d = destinationPoint(from.lat, from.lon, b, D); - arc.push([d.lat, d.lon]); + // Draw the lobe as a FAN of translucent great-circle radials, not a + // filled polygon: a polygon breaks badly near the poles on Mercator (its + // edges run off toward ±90° and the fill smears across the map), while + // each radial LINE stays clean. The overlapping lines read as a lobe — + // solid near the antenna, fanning out toward the front. Works for any + // azimuth, north/south included. + for (let b = az - half; b <= az + half + 0.001; b += 1.5) { + const line = unwrapLon([[from.lat, from.lon], ...radial(b)]); + L.polyline(line as L.LatLngExpression[], { color: '#dc2626', weight: 6, opacity: 0.07 }).addTo(wo); } - const ring = unwrapLon([ - [from.lat, from.lon], - ...radial(az - half), - ...arc, - ...radial(az + half).reverse(), - ]); - // Near a pole the lobe's two edges diverge wildly (one runs NW, the - // other NE) and look broken on a Mercator map — so for a poleward beam - // show ONLY the clean boresight (below). Otherwise draw the filled lobe. - if (!ring.some(([la]) => Math.abs(la) > 78)) { - L.polygon(ring as L.LatLngExpression[], { - color: '#dc2626', weight: 1, opacity: 0.5, fillColor: '#dc2626', fillOpacity: 0.14, - }).addTo(wo); - } - // Boresight (dashed centre line) — always; great-circle polyline is safe. + // Boresight (dashed centre line). const cl = unwrapLon([[from.lat, from.lon], ...radial(az)]); L.polyline(cl as L.LatLngExpression[], { color: '#dc2626', weight: 1.5, opacity: 0.7, dashArray: '5 4' }) .bindTooltip(`Beam ${Math.round(az)}°`, { permanent: false, direction: 'top' }).addTo(wo);