# Zoom to show all markers #1339

Open
opened this issue May 7, 2019 · 17 comments

Projects
None yet
3 participants

[X] Question

## Description and/or steps/code to reproduce the problem

I have an app where the user can set 1 to n markers on a map. I've implemented that the markers are set correctly, but how can I zoom the map, so all markers are visible? If I have only one marker, it's quite easy as I know the location and set a fixed zoom.

Duplicate of #156, but no solution is given there.

## Environment

6.1.0

Collaborator

### spyhunter99 commented May 7, 2019

 assuming you have a list of all the markers, figure out the maximum and min lat/lon values for all points, then you have a bounding box containing all the items. Then i think map controller has a function to zoom/pan to a bounding box

Author

### mueller-ma commented May 9, 2019

 Thanks for your response. I have a look at this approach and will post the outcome here.

Author

### mueller-ma commented May 10, 2019

 This is what I have so far and it should be zoomed correctly now, but it doesn't. Screenshot and code is attached: ``` ArrayList positions = new ArrayList<>(); addGeoPoint(mapView, 52.50634f, 13.38749f, positions); addGeoPoint(mapView, 52.51634f, 13.38749f, positions); addGeoPoint(mapView, 52.51626f, 13.38800f, positions); addGeoPoint(mapView, 52.51600f, 13.38900f, positions); addGeoPoint(mapView, 52.51700f, 15.38849f, positions); if (!positions.isEmpty()) { double north = -90; double south = 90; double west = 180; double east = -180; for (GeoPoint position : positions) { north = Math.max(position.getLatitude(), north); south = Math.min(position.getLatitude(), south); west = Math.min(position.getLongitude(), west); east = Math.max(position.getLongitude(), east); } Log.d(TAG, String.format("North %f, south %f, west %f, east %f", north, south, west, east)); BoundingBox boundingBox = new BoundingBox(north, west, south, east); mapView.zoomToBoundingBox(boundingBox, true); }``` `addGeoPoint()` is just a small helper function, later the data comes from a server. ``` private void addGeoPoint(MapView mapView, float a, float b, ArrayList positions) { GeoPoint position = new GeoPoint(a,b); Marker marker = new Marker(mapView); marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM); marker.setPosition(position); mapView.getOverlays().add(marker); positions.add(position); }``` Log: ``````05-10 20:03:14.366 org.openhab.habdroid.beta D/MapViewHelper: North 52.516998, south 52.506340, west 10.388490, east 15.388490 ``````
Author

### mueller-ma commented May 10, 2019

 If I use `mapView.zoomToBoundingBox(boundingBox, true, 10);`, the app crashes: ``````05-10 20:09:49.916 org.openhab.habdroid.beta D/MapViewHelper: North 52.516998, south 52.506340, west 10.388490, east 15.388490 05-10 20:09:49.917 org.openhab.habdroid.beta D/AndroidRuntime: Shutting down VM --------- beginning of crash 05-10 20:09:49.918 org.openhab.habdroid.beta E/AndroidRuntime: FATAL EXCEPTION: main Process: org.openhab.habdroid.beta, PID: 12528 java.lang.IllegalArgumentException: north must be in [-85.05112877980658,85.05112877980658] at org.osmdroid.util.BoundingBox.set(BoundingBox.java:67) at org.osmdroid.views.Projection.refresh(Projection.java:666) at org.osmdroid.views.Projection.(Projection.java:99) at org.osmdroid.views.Projection.(Projection.java:110) at org.osmdroid.views.MapView.zoomToBoundingBox(MapView.java:545) at org.osmdroid.views.MapView.zoomToBoundingBox(MapView.java:571) at org.openhab.habdroid.ui.MapViewHelper\$OsmViewHolder.applyPositionAndLabel(MapViewHelper.java:207) at org.openhab.habdroid.ui.MapViewHelper\$OsmViewHolder.bind(MapViewHelper.java:93) at org.openhab.habdroid.ui.WidgetAdapter.onBindViewHolder(WidgetAdapter.java:239) at org.openhab.habdroid.ui.WidgetAdapter.onBindViewHolder(WidgetAdapter.java:82) at androidx.recyclerview.widget.RecyclerView\$Adapter.onBindViewHolder(RecyclerView.java:6781) at androidx.recyclerview.widget.RecyclerView\$Adapter.bindViewHolder(RecyclerView.java:6823) at androidx.recyclerview.widget.RecyclerView\$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752) at androidx.recyclerview.widget.RecyclerView\$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019) at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:286) at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:343) at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:359) at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:366) at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:397) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5597) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit\$MethodAndArgsCaller.run(ZygoteInit.java:984) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) `````` As you can see from the log message before the crash, `north` is inside the correct interval. And why does one overload of `zoomToBoundingBox()` return the zoom level, but not the others?
Collaborator

### spyhunter99 commented May 10, 2019

 thanks testing a fix now

### spyhunter99 added a commit that referenced this issue May 10, 2019

``` #1339 possible fix for random zoom to bounds crash caused by lat/lons… ```
`… past the max bounds of the projection`
``` b6ea341 ```
Collaborator

### spyhunter99 commented May 10, 2019

 ok the snapshots are updated, can you try to reproduce this with 6.1.1-SNAPSHOT
Author

### mueller-ma commented May 10, 2019

 Same crash then before: ``````05-10 22:53:23.356 org.openhab.habdroid.beta D/MapViewHelper: North 52.516998, south 52.506340, west 10.388490, east 15.388490 05-10 22:53:23.357 org.openhab.habdroid.beta D/AndroidRuntime: Shutting down VM 05-10 22:53:23.361 org.openhab.habdroid.beta E/AndroidRuntime: FATAL EXCEPTION: main Process: org.openhab.habdroid.beta, PID: 7685 java.lang.IllegalArgumentException: north must be in [-85.05112877980658,85.05112877980658] at org.osmdroid.util.BoundingBox.set(BoundingBox.java:67) at org.osmdroid.views.Projection.refresh(Projection.java:680) at org.osmdroid.views.Projection.(Projection.java:99) at org.osmdroid.views.Projection.(Projection.java:110) at org.osmdroid.views.MapView.zoomToBoundingBox(MapView.java:556) at org.osmdroid.views.MapView.zoomToBoundingBox(MapView.java:582) at org.openhab.habdroid.ui.MapViewHelper\$OsmViewHolder.applyPositionAndLabel(MapViewHelper.java:207) ``````
Collaborator

### spyhunter99 commented May 10, 2019

 maybe it's a caching issue? gradle doesn't always check for updates to snapshot versions. usually the fix is to either alter the gradle config or to delete the gradle cache. There's an example here: https://github.com/osmdroid/osmdroid/blob/master/build.gradle#L32
Author

### mueller-ma commented May 11, 2019

 I cleared all "osmdroid" files from `~/.gradle` and re-run the build. Same crash: ``````[ ~/.gradle]\$ find . -name "*osmdroid*" ./caches/modules-2/files-2.1/org.osmdroid ./caches/modules-2/files-2.1/org.osmdroid/osmdroid-android ./caches/modules-2/files-2.1/org.osmdroid/osmdroid-android/6.1.1-SNAPSHOT/6a02ed0aad0994516c944efdae4b90a640cf1308/osmdroid-android-6.1.1-SNAPSHOT.pom ./caches/modules-2/files-2.1/org.osmdroid/osmdroid-android/6.1.1-SNAPSHOT/8adc5763f4eac4d46d9cc9cd02703eada6597a0f/osmdroid-android-6.1.1-SNAPSHOT-debug.aar ./caches/modules-2/metadata-2.69/descriptors/org.osmdroid ./caches/modules-2/metadata-2.69/descriptors/org.osmdroid/osmdroid-android ``````
Collaborator

### MKergall commented May 11, 2019

 @mueller-ma Are you calling your piece of code from onCreate ?
Author

Collaborator

### spyhunter99 commented May 11, 2019

 Instead of starting at 90 degrees, start at org.osmdroid.views.MapView.getTileSystem()#getMaxLatitude and getMinLatitude
Author

### mueller-ma commented May 11, 2019

 I don't understand why I want to use a smaller area: Latitude is an angle [...] which ranges from 0° at the Equator to 90° (North or South) at the poles.
Collaborator

### spyhunter99 commented May 11, 2019

 osmdroid uses a projected map based on open street map's slippy tile format. It translates ground coordinates to lat/lon using a formula into square tiles. The earth is not flat so i make a sphere into s square, the points near the poles are stretched out. Back to the formula, coordinates beyond +-85 degrees basically can't be displayed accurately. All 2d maps that use some kind of z/x/y tiling system have the same problem. This becomes very apparent when setting the map to disable wrap around and allowing a point to be plotted > 85 degrees. It behaves similar to a math limit function.
Author

### mueller-ma commented May 14, 2019

 `MapView.getTileSystem()` doesn't seem to exist. Maybe this can be fixed by disabling wrap around. Is there any short handy function for that, like `mapView.setWrapAround(false)`?
Collaborator

### spyhunter99 commented May 14, 2019

 i think it was added in v6. It's there. Also mapView.set....i think it's vertical/horizontal replication
Author

### mueller-ma commented May 15, 2019

 Found the issue: I called `zoomToBoundingBox()` before the view was inflated, leading `getWidth()` returning 0 here: https://github.com/osmdroid/osmdroid/blob/master/osmdroid-android/src/main/java/org/osmdroid/views/MapView.java#L543. Thus `nextZoom` was 0. IMO this is more a workaround than a real fix. Maybe `zoomToBoundingBox()` should wait until the map is inflated or log something. And it shouldn't crash if the view isn't inflated and `pBorderSizeInPixels != 0`. Also: the comment (https://github.com/osmdroid/osmdroid/blob/master/osmdroid-android/src/main/java/org/osmdroid/views/MapView.java#L534) is incorrect. `pBoundingBox` cannot be a single `GeoPoint`.

Merged