Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Map Heading Marker or Indicator

The "Google Maps" app in Jellybean has an indicator which adjusts based on the way you're facing. I am interested in implementing a similar indicator but for multiple indicators.

Does anyone have an idea on how they implemented their heading indicator (note it maintains its heading even when the map is rotated). I attempted my own approach using markers, then I realized that markers will not rotate with the map (kind of an oh duh moment after a few hours of labor...)

To summarize: How do I implement an icon in google maps that rotates based on heading, and not the map.

So as of right now I see two solutions:

  • Capture map rotation and transfer it to the marker
  • Draw over the map using OpenGL

Could anyone offer any advice before I start down another rabbit hole? Thanks!

like image 558
Constantin Avatar asked Mar 28 '26 13:03

Constantin


1 Answers

There are a couple things you can do if you want to show orientation on a map.

Here are all of the imports that are used:

import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;

1.Move the map so that the bearing is on top.

private final GoogleMap mMap;

//Get the current position from the map
CameraPosition camPosition = mMap.getCameraPosition();

//Update only the orientation/bearing, get all of the other values from the existing position.
CameraPosition newPos = new CameraPosition(
   camPosition.target,
   camPosition.zoom,        
   camPosition.tilt,
   azimuthInDegress);

//Set the position so that the map will update. The desired heading should not be on top
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(newPos));

The problem with this idea is that if you don't stabilize your orientation updates, the map will move all over the place.

2.Implement a LocationSource

Google maps give you the ability to override it's location provider. First you'll want to implement a new Location source:

import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.MapFragment;


public class LocationSourceImplActivity extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    //Assume using the example from Google
    GoogleMap map = ((MapFragment) getFragmentManager()
            .findFragmentById(R.id.map)).getMap();

    map.setMyLocationEnabled(true);

    LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    map.setLocationSource(new LocationSourceImpl(locManager));
}

    /**
    *The Goal of this class is to listen for both location and heading updates 
    *and combine these into a single update, which will be passed to Google Maps.
    */ 
private class LocationSourceImpl implements LocationSource, LocationListener {

    private OnLocationChangedListener mListener = null;
    private Location mLastLoc = null;
    //Use your desired location provider. You can also update this class to better
    //determine when and how to register
    private static final String PREF_LOC_SRC ="";
    private final LocationManager mLocationManager;
    private float mLastHeading = Float.MAX_VALUE;


    public LocationSourceImpl(LocationManager pLocManager) {
        mLocationManager = pLocManager;

        //Get all updates, modify as desired. 
        mLocationManager.requestLocationUpdates(PREF_LOC_SRC, 0, 0, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        mLastLoc = location;
        notifyListener();
    }

    private void notifyListener() {

        if(mListener != null && mLastLoc!=null) {

            if(mLastHeading != Float.MAX_VALUE) {
                mLastLoc.setBearing(mLastHeading);
            }

            //The listener will be the maps: 
            mListener.onLocationChanged(mLastLoc);

        }

    }

    @Override
    public void activate(OnLocationChangedListener pListener) {
                    //When the setLocationSource is called on the map, the map
                    //will be passed in as an OnLocationChangedListener (may not be the
                    //map, but may be a delegator created by the map. 
        mListener = pListener;
    }

    @Override
    public void deactivate() {
        mListener = null;

    }

    /**
     * This method can/should be replaced with a heading calculation
     * @param pDegrees
     *  Heading in degrees
     */
    public void updateHeadingInDegrees(float pDegrees) {
        mLastHeading = pDegrees;
        notifyListener();

    }

    @Override
    public void onProviderDisabled(String paramString) {

    }

    @Override
    public void onProviderEnabled(String paramString) {

    }

    @Override
    public void onStatusChanged(String paramString, int paramInt,
            Bundle paramBundle) {

    }

}

}

like image 70
lordoku Avatar answered Apr 02 '26 21:04

lordoku



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!