Selphiron
Selphiron

Reputation: 929

How to adjust the compass to the map in osmdroid

How can I snap the direction of the compass to the direction of the map?

I add a Compass to my MapView and enable map rotation like this:

 MapView mapView = findViewById(R.id.mapView);

 // Enable & add compass
 CompassOverlay compassOverlay = new CompassOverlay(this, mapView);
 compassOverlay.enableCompass();
 mapView.getOverlays().add(compassOverlay);

 // Enable map rotation with gestures
 mapView.getOverlays().add(new RotationGestureOverlay(mapView));

Now when the map is not rotated, so up is north, right is east etc, the compass works correctly. But when I rotate the map with gesture, the compass does not move accordingly. So when the device is faced north and the map is at its default rotation, the compass shows north according to the map, which is correct. But when I rotate the map by 90° clockwise, the compass still points up instead of turning 90° clockwise.

I tried using compassOverlay.setPointerMode(true); but that only changed the appearance of the compass.

Upvotes: 3

Views: 1628

Answers (3)

Peter
Peter

Reputation: 13505

Edit - use Raul's solution - leaving this answer as a historical artifact only


This post https://github.com/osmdroid/osmdroid/issues/1647 has the solution. Copying from there, with light editing...

  1. Make a new class: MapAlignedCompassOverlay.java , which is just a copy/rename of class CompassOverlay.java, change the package name to match your package, and change the class name to MapAlignedCompassOverlay.

  2. Change a line in the function drawCompass() from mCompassMatrix.setRotate(-bearing, mCompassRoseCenterX, mCompassRoseCenterY); to mCompassMatrix.setRotate(proj.getOrientation(), mCompassRoseCenterX, mCompassRoseCenterY);

  3. In the setup code (e.g. onCreate if you're in an Activity) use MapAlignedCompassOverlay as a replacement for CompassOverlay in my app, and just give it a fake OrientationProvider to make it happy. E.g. (Kotlin):

val fakeOrientationProvider = object: IOrientationProvider{
    override fun startOrientationProvider(orientationConsumer: IOrientationConsumer?) = true
    override fun stopOrientationProvider() = Unit
    override fun getLastKnownOrientation(): Float = 0f
    override fun destroy() = Unit
}
mapView.overlays.add(MapAlignedCompassOverlay(context, fakeOrientationProvider, mapView).apply {
    enableCompass()
    onOrientationChanged(0f, fakeOrientationProvider)  // Magically makes it show up.
})

And now you have a compass that actually matches the map. Note to demonstrate this, you can enable "pinch to rotate" with

mapView.overlays.add(RotationGestureOverlay(mapView))

And observe that the compass stays pointing (True) north when you rotate.

Upvotes: 0

Raul Vieira
Raul Vieira

Reputation: 21

While digging a bit and considering Peter's answer I found a simple solution (Kotlin):

  1. Create a new CompassOverlay instance and override the draw() method
val mapNorthCompassOverlay = object: CompassOverlay(context, mapView) {
    override fun draw(c: Canvas?, pProjection: Projection?) {
        drawCompass(c, -mapView.mapOrientation, pProjection?.screenRect)
    }
}
  1. Add the overlay to your mapView's instance overlay list:
mapView.overlays.add(mapNorthCompassOverlay)

And that's it.

Explanation: drawCompass() is a protected method, but we can override the public draw() that uses the former method to fetch the phone magnetometer data to get the bearing direction. Since drawCompass() inverts the bearing data to print on your map and that is not our expected behavior, in this case, we pass -mapView.mapOrientation as a parameter, as it contains the information of the north of our map. Also, this CompassOverlay does not require you to use enableCompass(), which is the method that starts listening for sensor changes in direction, so you won't need to create a fake OrientationProvider to avoid your phone wasting resources.

Upvotes: 2

dakat
dakat

Reputation: 71

I edited my previous answer: it seems that the compass works only on actual hardware.

See: Adding Compass to Rotate MapView

Upvotes: 0

Related Questions