From 030a6eecc94e5e328e9236ac8dd9adb515898bed Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Thu, 10 Sep 2026 01:05:25 +0800 Subject: [PATCH] =?UTF-8?q?fix(map):=20split=20antimeridian=20edges=20inst?= =?UTF-8?q?ead=20of=20dropping=20=E2=80=94=20closes=20WAZ=20zone=201/19/31?= =?UTF-8?q?/32=20outlines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit splitRingAtAntimeridian used to drop any edge crossing ±180°, leaving visible gaps in WAZ zone outlines (zone 31's 40°N Pacific boundary, zone 1/19's polar arcs, zone 32's Antarctic arc). The edge is now split in two at ±180° with interpolated latitude, each half kept in its own segment, so outlines close across the map's left/right edges. normalizeLon now maps to (-180, 180] so edges ENDING on the antimeridian are not mistaken for crossings. --- .../feature/map/AwardBoundaryOverlay.kt | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/AwardBoundaryOverlay.kt b/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/AwardBoundaryOverlay.kt index ee49af9b..71cc892e 100644 --- a/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/AwardBoundaryOverlay.kt +++ b/feature/map/src/main/java/com/rtbishop/look4sat/feature/map/AwardBoundaryOverlay.kt @@ -261,9 +261,23 @@ class AwardBoundaryOverlay : Overlay() { val prevLon = pts[i - 1][0] val lon = pts[i][0] if (abs(lon - prevLon) > 180.0) { - // Crossed the antimeridian: start a fresh segment. + // Crossed the antimeridian. Do NOT drop this edge — that would + // leave a visible gap in the outline (WAZ Pacific zones 1/19/ + // 31/32, e.g. zone 31's 40°N boundary from 130°W to 160°E). + // Split the edge IN TWO at ±180 instead: each half stays in its + // own segment, so the outline closes across the map's left and + // right edges. The crossing latitude is interpolated along the + // edge (constant for latitude-aligned edges). + val a = pts[i - 1] + val b = pts[i] + val span = 360.0 - abs(lon - prevLon) // shortest angular distance + val edgeLon = if (prevLon < lon) -180.0 else 180.0 // side being crossed + val t = abs(edgeLon - prevLon) / span + val latAt = a[1] + (b[1] - a[1]) * t + cur.add(doubleArrayOf(edgeLon, latAt)) if (cur.size >= 2) segments.add(cur) cur = mutableListOf() + cur.add(doubleArrayOf(-edgeLon, latAt)) } cur.add(pts[i]) } @@ -378,8 +392,12 @@ class AwardBoundaryOverlay : Overlay() { private fun normalizeLon(lon: Double): Double { var l = lon % 360.0 - if (l >= 180.0) l -= 360.0 - if (l < -180.0) l += 360.0 + // Normalize into (-180, 180] — +180, not -180. An edge whose endpoint + // sits ON the antimeridian (e.g. a ring starting at -180°) must not be + // seen as a >180° jump away from a nearby 165° vertex; keeping the + // antimeridian value as +180 makes such edges short and un-split. + if (l <= -180.0) l += 360.0 + if (l > 180.0) l -= 360.0 return l }