Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zoom to show all markers #1339

Open
mueller-ma opened this issue May 7, 2019 · 17 comments

Comments

Projects
None yet
3 participants
@mueller-ma
Copy link

commented May 7, 2019

Issue Type

[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

Version of osmdroid the issue relates to:

6.1.0

@spyhunter99

This comment has been minimized.

Copy link
Collaborator

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

@spyhunter99 spyhunter99 added the question label May 8, 2019

@mueller-ma

This comment has been minimized.

Copy link
Author

commented May 9, 2019

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

@mueller-ma

This comment has been minimized.

Copy link
Author

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<GeoPoint> 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<GeoPoint> 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

image

@mueller-ma

This comment has been minimized.

Copy link
Author

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.<init>(Projection.java:99)
        at org.osmdroid.views.Projection.<init>(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?

@spyhunter99

This comment has been minimized.

Copy link
Collaborator

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
@spyhunter99

This comment has been minimized.

Copy link
Collaborator

commented May 10, 2019

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

@mueller-ma

This comment has been minimized.

Copy link
Author

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.<init>(Projection.java:99)
        at org.osmdroid.views.Projection.<init>(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)
@spyhunter99

This comment has been minimized.

Copy link
Collaborator

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

@mueller-ma

This comment has been minimized.

Copy link
Author

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
@MKergall

This comment has been minimized.

Copy link
Collaborator

commented May 11, 2019

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

@spyhunter99

This comment has been minimized.

Copy link
Collaborator

commented May 11, 2019

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

@mueller-ma

This comment has been minimized.

Copy link
Author

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.

from https://en.wikipedia.org/wiki/Latitude

@spyhunter99

This comment has been minimized.

Copy link
Collaborator

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.

@mueller-ma

This comment has been minimized.

Copy link
Author

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)?

@spyhunter99

This comment has been minimized.

Copy link
Collaborator

commented May 14, 2019

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

@mueller-ma

This comment has been minimized.

Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.