From f4c8eefc06889c2ca0b7a76f542fbbf0513e87b4 Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Thu, 22 Feb 2024 21:18:16 +0100 Subject: [PATCH] clean up old zoom-to logic --- .../screens/main/map/MainMapFragment.kt | 4 +- .../screens/main/map/MapFragment.kt | 2 - .../components/FocusGeometryMapComponent.kt | 56 +++++-------------- .../main/map/tangram/KtMapController.kt | 50 +++++------------ 4 files changed, 29 insertions(+), 83 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MainMapFragment.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MainMapFragment.kt index adfb0b8bb9..ce0e1d647d 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MainMapFragment.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MainMapFragment.kt @@ -132,7 +132,7 @@ class MainMapFragment : LocationAwareMapFragment(), ShowsGeometryMarkers { pinsMapComponent = PinsMapComponent(ctrl) selectedPinsMapComponent = SelectedPinsMapComponent(requireContext(), ctrl) - geometryMapComponent = FocusGeometryMapComponent(ctrl, mapboxMap) + geometryMapComponent = FocusGeometryMapComponent(ctrl) questPinsManager = QuestPinsManager(ctrl, pinsMapComponent!!, questTypeOrderSource, questTypeRegistry, resources, visibleQuestsSource) viewLifecycleOwner.lifecycle.addObserver(questPinsManager!!) @@ -684,7 +684,7 @@ class MainMapFragment : LocationAwareMapFragment(), ShowsGeometryMarkers { // geometrySource?.setGeoJson(thisIsNoFeature) // nullable, but crashes maplibre (native) if null. great. geometrySource?.setGeoJson(FeatureCollection.fromFeatures(emptyList())) focusedGeometrySource?.setGeoJson(FeatureCollection.fromFeatures(emptyList())) -// pinsLayer?.setFilter(Expression.gte(Expression.zoom(), 14f)) + pinsLayer?.setFilter(Expression.gte(Expression.zoom(), 14f)) pinsDotLayer?.setFilter(Expression.gte(Expression.zoom(), 14f)) } diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MapFragment.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MapFragment.kt index f5555d45e6..6c0495f670 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MapFragment.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/MapFragment.kt @@ -41,8 +41,6 @@ open class MapFragment : Fragment() { private val binding by viewBinding(FragmentMapBinding::bind) -// private val defaultCameraInterpolator = AccelerateDecelerateInterpolator() - protected var controller: KtMapController? = null protected var mapboxMap : MapboxMap? = null protected var sceneMapComponent: SceneMapComponent? = null diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/components/FocusGeometryMapComponent.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/components/FocusGeometryMapComponent.kt index 07aa279114..40d87f5c01 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/components/FocusGeometryMapComponent.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/components/FocusGeometryMapComponent.kt @@ -1,15 +1,9 @@ package de.westnordost.streetcomplete.screens.main.map.components import android.graphics.RectF -import com.mapbox.geojson.Feature import com.mapbox.geojson.FeatureCollection -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory -import com.mapbox.mapboxsdk.geometry.LatLngBounds import com.mapbox.mapboxsdk.maps.MapboxMap -import de.westnordost.streetcomplete.data.maptiles.toLatLng import de.westnordost.streetcomplete.data.osm.geometry.ElementGeometry -import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry -import de.westnordost.streetcomplete.screens.MainActivity import de.westnordost.streetcomplete.screens.main.map.MainMapFragment import de.westnordost.streetcomplete.screens.main.map.maplibre.CameraPosition import de.westnordost.streetcomplete.screens.main.map.maplibre.toLatLon @@ -23,7 +17,7 @@ import kotlin.math.roundToInt /** Display element geometry and enables focussing on given geometry. I.e. to highlight the geometry * of the element a selected quest refers to. Also zooms to the element in question so that it is * contained in the screen area */ -class FocusGeometryMapComponent(private val ctrl: KtMapController, private val mapboxMap: MapboxMap) { +class FocusGeometryMapComponent(private val ctrl: KtMapController) { private var previousCameraPosition: CameraPosition? = null @@ -43,43 +37,23 @@ class FocusGeometryMapComponent(private val ctrl: KtMapController, private val m } @Synchronized fun beginFocusGeometry(g: ElementGeometry, offset: RectF) { - val pos = ctrl.getEnclosingCameraPosition(g.getBounds(), offset) ?: return - val currentPos = ctrl.cameraPosition - val targetZoom = min(pos.zoom.toFloat(), 20f) - - // do not zoom in if the element is already nicely in the view - if (ctrl.screenAreaContains(g, RectF()) && targetZoom - currentPos.zoom < 2.5) return + val targetPos = ctrl.getEnclosingCameraPosition(g, offset) ?: return - if (previousCameraPosition == null) previousCameraPosition = currentPos + val currentPos = ctrl.cameraPosition + // limit max zoom to not zoom in to the max when zooming in on points; + // also zoom in a bit less to have a padding around the zoomed-in element + val targetZoom = min(targetPos.zoom - 0.5, 21.0) - val zoomTime = max(450, (abs(currentPos.zoom - targetZoom) * 300).roundToInt()) + val zoomDiff = abs(currentPos.zoom - targetZoom) + val zoomTime = max(450, (zoomDiff * 300).roundToInt()) - // todo: works, but seems needlessly complicated - // and still might have some issues - MainActivity.activity!!.runOnUiThread { - val bounds = LatLngBounds.fromLatLngs(listOf(g.getBounds().max.toLatLng(), g.getBounds().min.toLatLng())) - val c = MainMapFragment.mapboxMap!!.getCameraForLatLngBounds( - bounds, - arrayOf( - offset.left.toInt(), - offset.top.toInt(), - offset.right.toInt(), - offset.bottom.toInt() - ).toIntArray() - ) - c?.let { - if (g is ElementPointGeometry) { - ctrl.updateCameraPosition(zoomTime) { - zoom = targetZoom.toDouble() - position = it.target?.toLatLon() - } - } else { - // TODO - // above is nice for nodes, but actually it gets the wrong position (ignores padding) - MainMapFragment.mapboxMap!!.easeCamera(CameraUpdateFactory.newCameraPosition(it), zoomTime.toInt()) - } - } + ctrl.updateCameraPosition(zoomTime) { + position = targetPos.position + zoom = targetZoom + padding = targetPos.padding } + + if (previousCameraPosition == null) previousCameraPosition = currentPos } @Synchronized fun clearFocusGeometry() { @@ -95,8 +69,6 @@ class FocusGeometryMapComponent(private val ctrl: KtMapController, private val m ctrl.updateCameraPosition(zoomTime) { position = pos.position zoom = pos.zoom - tilt = pos.tilt - rotation = pos.rotation } } previousCameraPosition = null diff --git a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/tangram/KtMapController.kt b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/tangram/KtMapController.kt index adeaaecdab..fe35092eb2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/tangram/KtMapController.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/screens/main/map/tangram/KtMapController.kt @@ -22,6 +22,7 @@ import de.westnordost.streetcomplete.screens.main.map.maplibre.toLatLon import de.westnordost.streetcomplete.screens.main.map.maplibre.toMapLibreCameraPosition import de.westnordost.streetcomplete.screens.main.map.maplibre.toMapLibreCameraPosition import de.westnordost.streetcomplete.screens.main.map.maplibre.toMapLibreCameraUpdate +import de.westnordost.streetcomplete.screens.main.map.maplibre.toMapLibreGeometry import de.westnordost.streetcomplete.util.math.centerPointOfPolyline import de.westnordost.streetcomplete.util.math.distanceTo import de.westnordost.streetcomplete.util.math.enclosingBoundingBox @@ -162,28 +163,18 @@ class KtMapController( return positions.enclosingBoundingBox() } - fun getEnclosingCameraPosition(bounds: BoundingBox, padding: RectF): CameraPosition? { - val zoom = getMaxZoomThatContainsBounds(bounds, padding) ?: return null - val boundsCenter = listOf(bounds.min, bounds.max).centerPointOfPolyline() - val pos = getLatLonThatCentersLatLon(boundsCenter, padding, zoom) ?: return null - val camera = cameraPosition - return CameraPosition(pos, camera.rotation, camera.tilt, zoom.toDouble()) - } - - private fun getMaxZoomThatContainsBounds(bounds: BoundingBox, padding: RectF): Float? { - val screenBounds: BoundingBox = screenAreaToBoundingBox(padding) ?: return null - val currentZoom: Float = cameraPosition.zoom.toFloat() - - val screenWidth = normalizeLongitude(screenBounds.max.longitude - screenBounds.min.longitude) - val screenHeight = screenBounds.max.latitude - screenBounds.min.latitude - val objectWidth = normalizeLongitude(bounds.max.longitude - bounds.min.longitude) - val objectHeight = bounds.max.latitude - bounds.min.latitude - - val zoomDeltaX = log10(screenWidth / objectWidth) / log10(2.0) - val zoomDeltaY = log10(screenHeight / objectHeight) / log10(2.0) - val zoomDelta = min(zoomDeltaX, zoomDeltaY) - return max(1.0, min(currentZoom + zoomDelta, 20.0)).toFloat() - } + fun getEnclosingCameraPosition(geometry: ElementGeometry, padding: RectF): CameraPosition? = + mapboxMap.getCameraForGeometry( + geometry.toMapLibreGeometry(), + intArrayOf( + padding.left.toInt(), + padding.top.toInt(), + padding.right.toInt(), + padding.bottom.toInt() + ), + mapboxMap.cameraPosition.bearing, + mapboxMap.cameraPosition.tilt + )?.toCameraPosition() fun getLatLonThatCentersLatLon(position: LatLon, padding: RectF, zoom: Float = cameraPosition.zoom.toFloat()): LatLon? { val w = mapboxMap.width @@ -301,21 +292,6 @@ class KtMapController( val bottom = screenPositionToLatLon(PointF(w / 2f, h * 1f)) ?: return null return center.distanceTo(bottom) } - - fun screenAreaContains(g: ElementGeometry, offset: RectF): Boolean { - val p = PointF() - return when (g) { - is ElementPolylinesGeometry -> g.polylines - is ElementPolygonsGeometry -> g.polygons - else -> listOf(listOf(g.center)) - }.flatten().all { -// latLonToScreenPosition(it, p, false) ?? - p.x >= offset.left - && p.x <= mapboxMap.width - offset.right - && p.y >= offset.top - && p.y <= mapboxMap.height - offset.bottom - } - } } //class LoadSceneException(message: String, val sceneUpdate: SceneUpdate) : RuntimeException(message)