From 49617d2e197e486849606acce0baa4dbed80e9ec Mon Sep 17 00:00:00 2001 From: andrekir Date: Thu, 27 Jul 2023 05:56:59 -0300 Subject: [PATCH] fix: calculate download BoundingBox based on zoom factor instead of calling `setZoom()` before/after `MapView.boundingBox` which can get out of sync and cause inconsistencies in the tile count. fixes #670 --- .../com/geeksville/mesh/ui/map/MapFragment.kt | 11 ++++---- .../com/geeksville/mesh/util/LocationUtils.kt | 28 +++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt index 85ec4aca3..412e12927 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/map/MapFragment.kt @@ -52,6 +52,7 @@ import com.geeksville.mesh.util.EnableWakeLock import com.geeksville.mesh.util.SqlTileWriterExt import com.geeksville.mesh.util.requiredZoomLevel import com.geeksville.mesh.util.formatAgo +import com.geeksville.mesh.util.zoomIn import com.geeksville.mesh.waypoint import com.google.accompanist.themeadapter.appcompat.AppCompatTheme import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -461,21 +462,21 @@ fun MapView(model: UIViewModel = viewModel()) { */ fun generateBoxOverlay(zoomLevel: Double) = map.apply { overlayManager = CustomOverlayManager(TilesOverlay(tileProvider, context)) + val zoomFactor = 1.3 // zoom difference between view and download area polygon + controller.setZoom(zoomLevel - zoomFactor) setMultiTouchControls(false) // furthest back zoomLevelMax = zoomLevelHighest // FIXME zoomLevel // furthest in min should be > than max - zoomLevelMin = map.tileProvider.tileSource.maximumZoomLevel.toDouble() - controller.setZoom(zoomLevel) - downloadRegionBoundingBox = map.boundingBox + zoomLevelMin = tileProvider.tileSource.maximumZoomLevel.toDouble() + downloadRegionBoundingBox = boundingBox.zoomIn(zoomFactor) val polygon = Polygon().apply { points = Polygon.pointsAsRect(downloadRegionBoundingBox).map { GeoPoint(it.latitude, it.longitude) } } overlayManager.add(polygon) - controller.setZoom(zoomLevel - 1.0) - val tileCount: Int = CacheManager(map).possibleTilesInArea( + val tileCount: Int = CacheManager(this).possibleTilesInArea( downloadRegionBoundingBox, zoomLevelMax.toInt(), zoomLevelMin.toInt() diff --git a/app/src/main/java/com/geeksville/mesh/util/LocationUtils.kt b/app/src/main/java/com/geeksville/mesh/util/LocationUtils.kt index 9fe6ed9f8..1d8cb8fc5 100644 --- a/app/src/main/java/com/geeksville/mesh/util/LocationUtils.kt +++ b/app/src/main/java/com/geeksville/mesh/util/LocationUtils.kt @@ -12,6 +12,7 @@ import kotlin.math.acos import kotlin.math.atan2 import kotlin.math.cos import kotlin.math.log2 +import kotlin.math.pow import kotlin.math.sin /******************************************************************************* @@ -251,3 +252,30 @@ fun BoundingBox.requiredZoomLevel(): Double { return maxOf(requiredLatZoom, requiredLonZoom) } +/** + * Creates a new bounding box with adjusted dimensions based on the provided [zoomFactor]. + * @return A new [BoundingBox] with added [zoomFactor]. Example: + * ``` + * // Setting the zoom level directly using setZoom() + * map.setZoom(14.0) + * val boundingBoxZoom14 = map.boundingBox + * + * // Using zoomIn() results the equivalent BoundingBox with setZoom(15.0) + * val boundingBoxZoom15 = boundingBoxZoom14.zoomIn(1.0) + * ``` + */ +fun BoundingBox.zoomIn(zoomFactor: Double): BoundingBox { + val center = GeoPoint((latNorth + latSouth) / 2, (lonWest + lonEast) / 2) + val latDiff = latNorth - latSouth + val lonDiff = lonEast - lonWest + + val newLatDiff = latDiff / (2.0.pow(zoomFactor)) + val newLonDiff = lonDiff / (2.0.pow(zoomFactor)) + + return BoundingBox( + center.latitude + newLatDiff / 2, + center.longitude + newLonDiff / 2, + center.latitude - newLatDiff / 2, + center.longitude - newLonDiff / 2 + ) +}