mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
fix(map): grid mode centering via view.post (first-layout reset); antimeridian unwrap of visible bbox fixes Pacific-centered vanishing grid; tile meridians/fills across world repeats at low zoom
This commit is contained in:
1 parent
e75d2dc410
commit
05170541ed
2 files changed
+39
-17
No files matched your search
+34
-15
@@ -84,8 +84,19 @@ class MaidenheadGridOverlay : Overlay() {
|
||||
val south = projection.fromPixels(canvas.width, canvas.height)
|
||||
val topLat = max(north.latitude, south.latitude).coerceIn(-90.0, 90.0)
|
||||
val bottomLat = min(north.latitude, south.latitude).coerceIn(-90.0, 90.0)
|
||||
val leftLon = min(north.longitude, south.longitude)
|
||||
val rightLon = max(north.longitude, south.longitude)
|
||||
// Longitude: osmdroid normalizes to [-180, 180), so when the view
|
||||
// straddles the antimeridian (e.g. left edge 170°E, right edge 170°W)
|
||||
// the raw min/max swap sides and the bounding box spans the wrong way
|
||||
// (center on the Pacific → grid painted 180° off-screen). Unwrap by
|
||||
// shifting one edge by +360° so left < right again.
|
||||
var lonA = north.longitude
|
||||
var lonB = south.longitude
|
||||
if (lonA > lonB) {
|
||||
val t = lonA; lonA = lonB; lonB = t
|
||||
}
|
||||
if (lonB - lonA > 180.0) lonA += 360.0
|
||||
val leftLon = lonA
|
||||
val rightLon = lonB
|
||||
|
||||
val firstRow = floor(bottomLat / cellLat).toInt()
|
||||
val lastRow = ceil(topLat / cellLat).toInt()
|
||||
@@ -98,6 +109,12 @@ class MaidenheadGridOverlay : Overlay() {
|
||||
// 2^zoom tiles across the whole 360° world). Used by the custom
|
||||
// Mercator-X computation in projectionToX.
|
||||
val worldWidthPx = 256.0 * Math.pow(2.0, zoom)
|
||||
// At low zoom the world is narrower than the viewport and osmdroid shows
|
||||
// repeating copies on both sides. The visible bounding box spans more
|
||||
// than 360° of longitude there; extend the column range by whole world
|
||||
// turns so meridians, fills and labels tile across the repeats too.
|
||||
val worldTurns = ceil(((rightLon - leftLon) / 360.0) - 1e-9).toInt().coerceAtLeast(0)
|
||||
val colRepeats = if (worldTurns > 0) worldTurns else 0
|
||||
|
||||
// The station's own grid square (4-char, only meaningful at sub-square zoom)
|
||||
val ownCell = ownGrid?.takeIf { zoom >= GRID_ZOOM_SUB }
|
||||
@@ -117,7 +134,7 @@ class MaidenheadGridOverlay : Overlay() {
|
||||
val yTop = projectionToY(projection, topLatCell)
|
||||
val yBottom = projectionToY(projection, lat)
|
||||
if (yTop == null || yBottom == null) continue
|
||||
for (col in firstCol..lastCol) {
|
||||
for (turn in -colRepeats..colRepeats) for (col in firstCol..lastCol) {
|
||||
val lon = col * cellLon
|
||||
val xLeft = projectionToX(projection, lon, centerLon, worldWidthPx) ?: continue
|
||||
val xRight = projectionToX(projection, lon + cellLon, centerLon, worldWidthPx) ?: continue
|
||||
@@ -130,22 +147,24 @@ class MaidenheadGridOverlay : Overlay() {
|
||||
} else {
|
||||
for (grid in workedGrids) {
|
||||
val cell = gridCellBounds(grid) ?: continue
|
||||
if (cell.lonRight <= leftLon || cell.lonLeft >= rightLon ||
|
||||
cell.latTop <= bottomLat || cell.latBottom >= topLat
|
||||
) continue
|
||||
val yTop = projectionToY(projection, cell.latTop) ?: continue
|
||||
val yBottom = projectionToY(projection, cell.latBottom) ?: continue
|
||||
val xLeft = projectionToX(projection, cell.lonLeft, centerLon, worldWidthPx) ?: continue
|
||||
val xRight = projectionToX(projection, cell.lonRight, centerLon, worldWidthPx) ?: continue
|
||||
if (xRight < 0f || xLeft > canvas.width) continue
|
||||
if (yBottom < 0f || yTop > canvas.height) continue
|
||||
canvas.drawRect(xLeft, yTop, xRight, yBottom, workedPaint)
|
||||
for (turn in -colRepeats..colRepeats) {
|
||||
// Shift the cell by whole world turns to cover repeats.
|
||||
val dLon = turn * 360.0
|
||||
if (cell.lonRight + dLon <= leftLon || cell.lonLeft + dLon >= rightLon) continue
|
||||
val yTop = projectionToY(projection, cell.latTop) ?: continue
|
||||
val yBottom = projectionToY(projection, cell.latBottom) ?: continue
|
||||
val xLeft = projectionToX(projection, cell.lonLeft + dLon, centerLon, worldWidthPx) ?: continue
|
||||
val xRight = projectionToX(projection, cell.lonRight + dLon, centerLon, worldWidthPx) ?: continue
|
||||
if (xRight < 0f || xLeft > canvas.width) continue
|
||||
if (yBottom < 0f || yTop > canvas.height) continue
|
||||
canvas.drawRect(xLeft, yTop, xRight, yBottom, workedPaint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical lines (meridians)
|
||||
for (col in firstCol..lastCol) {
|
||||
for (turn in -colRepeats..colRepeats) for (col in firstCol..lastCol) {
|
||||
val lon = col * cellLon
|
||||
val x = projectionToX(projection, lon, centerLon, worldWidthPx)
|
||||
if (x == null) continue
|
||||
@@ -209,7 +228,7 @@ class MaidenheadGridOverlay : Overlay() {
|
||||
val yBottom = projectionToY(projection, lat) ?: continue
|
||||
val yCenter = (yTop + yBottom) / 2f - textHalfHeight
|
||||
if (yBottom < 0f || yTop > canvas.height) continue
|
||||
for (col in firstCol..lastCol) {
|
||||
for (turn in -colRepeats..colRepeats) for (col in firstCol..lastCol) {
|
||||
val lon = col * cellLon
|
||||
val xLeft = projectionToX(projection, lon, centerLon, worldWidthPx) ?: continue
|
||||
val xRight = projectionToX(projection, lon + cellLon, centerLon, worldWidthPx) ?: continue
|
||||
|
||||
@@ -314,7 +314,10 @@ private fun setGridMode(
|
||||
mapView.overlays.getOrNull(index)?.isEnabled = !gridMode
|
||||
}
|
||||
// Entering grid mode: center on the station's current grid square,
|
||||
// keeping the current zoom level unchanged.
|
||||
// keeping the current zoom level unchanged. post{} is essential: on the
|
||||
// first composition this runs before MapView's first layout, and a
|
||||
// setCenter issued pre-layout is discarded when the view lays out —
|
||||
// the map then keeps its default center forever.
|
||||
if (gridMode) {
|
||||
val pos = stationPosition ?: return
|
||||
val lat = pos.latitude
|
||||
@@ -323,7 +326,7 @@ private fun setGridMode(
|
||||
val fieldLon = ((lon + 180.0) / 20.0).toInt().coerceIn(0, 17)
|
||||
val centerLat = fieldLat * 10.0 + 5.0
|
||||
val centerLon = fieldLon * 20.0 + 10.0
|
||||
mapView.controller.setCenter(GeoPoint(centerLat, centerLon))
|
||||
mapView.post { mapView.controller.setCenter(GeoPoint(centerLat, centerLon)) }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
println(e)
|
||||
|
||||
Reference in new issue
Block a user