android maps auto-rotate
Asked Answered
H

5

22

If you open the Google maps app, there is a button on the top right of the screen that you can press to center the map on your current location. The button's icon then changes. If you press the same button again, the map auto-rotates based on your compass heading. In other words, the map becomes egocentric (as opposed to allocentric AKA north always up).

Google recently launched maps API V2 for Android and I certainly like it more than the old one. By default, android maps V2 will include the "center on location" button. However, pressing it more than once does not enable auto-rotation; it merely tries to center the map on your location again.

Does anyone know how I can auto-rotate the map using maps API v2 just like the google maps app does? Will I have to implement this functionality myself or is it in the API and i'm just not seeing it? I appreciate all help.

Histoplasmosis answered 14/1, 2013 at 14:8 Comment(2)
That was helpful... I didn't even know about that feature, thanks. For me, it works fine (v7)Dichroic
he, I want to do the same thing, please share your solution if you have done this.Littell
H
28

Ok here's how I think it should be done a year later. Please correct me if you spot any issues.

Most of the following code deals with a discrepancy between coordinate systems. I'm using a rotation vector sensor. From the docs: Y is tangential to the ground at the device's current location and points towards magnetic north. Bearing in google maps, on the other hand, seems to point to true north. this page shows how the conversion is done

1) get the current declination from your current GPS location

@Override
public void onLocationChanged(Location location) {
    GeomagneticField field = new GeomagneticField(
            (float)location.getLatitude(),
            (float)location.getLongitude(),
            (float)location.getAltitude(),
            System.currentTimeMillis()
        );

    // getDeclination returns degrees
    mDeclination = field.getDeclination();
} 

2) calculate bearing from declination and magnetic north

    @Override
public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
        SensorManager.getRotationMatrixFromVector(
                mRotationMatrix , event.values);
        float[] orientation = new float[3];
        SensorManager.getOrientation(mRotationMatrix, orientation);
        float bearing = Math.toDegrees(orientation[0]) + mDeclination;
        updateCamera(bearing);  
    }
}

3) update maps

private void updateCamera(float bearing) {
    CameraPosition oldPos = mMap.getCameraPosition();

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing).build();
            mMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));
}
Histoplasmosis answered 31/1, 2014 at 5:45 Comment(6)
private float[] mRotationMatrix = new float[16]; getRotationMatrixFromVector will populate mRotationMatrix based on the values in the event.Histoplasmosis
This create flickering effect on map, how can i limit the rotationComforter
It should be noted that getRotationMatrixFromVector() limits this to API 9+. Should be relevant for those supporting legacy apps.Bandeau
hi i implement the above code , I got the rotation feature in my application but Google Map is continuously moving to the upward direction.Strike
and mDeclination?Pepi
@SHAHMDMONIRULISLAM You can see in the first code of this post this: "mDeclination = field.getDeclination();". field is an instance of GeomagneticField. If you search for the method "getDeclination()", you will see it's returning float; Therefore, mDeclination is float; You can also see, in the second code this: "float bearing = Math.toDegrees(orientation[0]) + mDeclination;", so from here you can also assume that it's a float.Quadriplegia
C
8

I have successfully implemented aleph_null solution and here I will add some details that are not mentioned in the accepted solution:

For the above solution to work you need to implement android.hardware.SensorEventListener interface.

You need also to register to the SensorEventListener in your onResume and onPause methods as follow:

@Override
    protected void onResume() {
     super.onResume();
     mSensorManager.registerListener(this,
             mRotVectSensor,
             SensorManager.SENSOR_STATUS_ACCURACY_LOW);
    }

@Override
protected void onPause() {
    // unregister listener
    super.onPause();
    mSensorManager.unregisterListener(this);
}

Note to "@Bytecode": To avoid flickering, use low value for the sampling period, something like SensorManager.SENSOR_STATUS_ACCURACY_LOW.

I have noticed also that the sensor sends sometime more data than the device can handle and as a result, the map camera starts to move in a strange way!

To control the amount of data handled by onSensorChanged, I suggest the following implementation:

@Override
public void onSensorChanged(SensorEvent event) {
    if(event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
        SensorManager.getRotationMatrixFromVector(
                mRotationMatrix, event.values);
        float[] orientation = new float[3];
        SensorManager.getOrientation(mRotationMatrix, orientation);
        if (Math.abs(Math.toDegrees(orientation[0]) - angle) > 0.8) {
            float bearing = (float) Math.toDegrees(orientation[0]) + mDeclination;
            updateCamera(bearing);
        }
        angle = Math.toDegrees(orientation[0]);
    }
}
Colorant answered 26/8, 2015 at 17:5 Comment(3)
mRotVectSensor ?Vazquez
where is angle definedTeneshatenesmus
mRotVectSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);Hast
A
2

It is possible by registering your application with Sensor Listener for Orientation and getting the angle relative to true north inside onSensorChanged and update camera accordingly. Angle can be used for bearing. The following code can be used:

Instead of using Sensor.TYPE_ORIENTATION try using getOrinetation api. Sensor.TYPE_ORIENTATION
has been deprecated.

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    if (sensorManager != null)
        sensorManager.registerListener(this,
                sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_GAME);
}

public void onSensorChanged(SensorEvent event) {

    float degree = Math.round(event.values[0]);

    Log.d(TAG, "Degree ---------- " + degree);

    updateCamera(degree);

}

private void updateCamera(float bearing) {
    CameraPosition oldPos = googleMap.getCameraPosition();

    CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing)
            .build();

    googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));

}
Arianaariane answered 14/1, 2015 at 8:7 Comment(0)
I
0

Sorry, you'll have to implement it yourself with the sensor manager and the camera

if those functions were available to the map api V2 they would certainly be either on the GoogleMap or the UiSettings

Inquietude answered 14/1, 2013 at 15:6 Comment(0)
D
0

The new Location class already gives you the bearing automatically, why not use it?

Sample code:

private void updateCameraBearing(GoogleMap googleMap, Location myLoc) {
    if ( googleMap == null) return;
    CameraPosition camPos = CameraPosition
            .builder(googleMap.getCameraPosition())
            .bearing(myLoc.getBearing())
             // if you want to stay centered - then add the line below
            .target(new LatLng(myLoc.getLatitude(), myLoc.getLongitude()))
            .build();
    googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(camPos));
}
Deodorant answered 23/5, 2020 at 23:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.