确定罗盘方向

Determine compass direction

我正在浏览互联网,试图找到对我的 Android 应用程序有用的东西。 我在 Google 地图上添加了 GPS 位置和几个标记。当我转身时,无论我面对什么,位置箭头都会倾斜。我担心的是是否有任何方法可以确定我指向哪个标记?我做了一张图片来澄清这一点。

我想我可以使用 getRotationMatrix() 方法获取罗盘方位,但我如何确定位置和标记之间的角度?

在这个项目中检查指南针 class:https://github.com/iutinvg/compass

我在这个应用程序中成功地使用了它:https://play.google.com/store/apps/details?id=com.gps.build

此致。

更新:

再次阅读您的问题后,我意识到我没有为您提供 "pointing to marker" 部分的足够详细信息。请检查下面的完整 class。要计算指向方向,请使用 startBearing 和 stopBearing 方法。

请注意,在 BringMeBack class 中使用 setBearingDegrees 方法,方位角随设备旋转而变化。那不是你需要的,所以你只需要删除 locationManager 并放置静态方位坐标。并且只调用该方法一次。

扩展罗盘class:

package com.gps.bitlab;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;

import com.gps.bitlab.fragment.MessageDialogFragment;
import com.gps.bitlab.util.Utility;

public class Compass implements SensorEventListener {
    private static final String TAG = "Compass";

    private SensorManager sensorManager;
    private Sensor gsensor;
    private Sensor msensor;
    private float[] mGravity = new float[3];
    private float[] mGeomagnetic = new float[3];
    private float azimuth = 0f;
    private float currectAzimuth = 0;

    private boolean bearing = false;
    private float bearingDegrees = -1;

    // compass arrow to rotate
    public ImageView arrowView = null;

    FragmentActivity activity;

    public Compass(FragmentActivity activity) {

        this.activity = activity;

        sensorManager = (SensorManager) activity.getApplicationContext()
                .getSystemService(Context.SENSOR_SERVICE);
        gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }

    public void start() {

        boolean deviceSensorCompatible = true;

        if(!sensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_GAME))
            deviceSensorCompatible = false;

        if(!sensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_GAME))
            deviceSensorCompatible = false;

        if(!deviceSensorCompatible) {
            Utility.ShowMessage(activity, activity.getString(R.string.erroroccured), activity.getString(R.string.deviceIncompatible),  1);
            stop();
        }
    }

    public void startBearing()
    {
        bearing = true;
        start();
    }

    public void setBearingDegrees(float bearingDegrees)
    {
        this.bearingDegrees = bearingDegrees;
    }

    public void stop() {
        sensorManager.unregisterListener(this);
    }

    public void stopBearing()
    {
        bearing = false;
        stop();
    }

    private void adjustArrow() {
        if (arrowView == null) {
            Log.i(TAG, "arrow view is not set");
            return;
        }

        Animation an = new RotateAnimation(-currectAzimuth, -azimuth,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        currectAzimuth = azimuth;

        an.setDuration(250);
        an.setRepeatCount(0);
        an.setFillAfter(true);

        arrowView.startAnimation(an);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        final float alpha = 0.97f;

        synchronized (this) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

                mGravity[0] = alpha * mGravity[0] + (1 - alpha)
                        * event.values[0];
                mGravity[1] = alpha * mGravity[1] + (1 - alpha)
                        * event.values[1];
                mGravity[2] = alpha * mGravity[2] + (1 - alpha)
                        * event.values[2];

                // mGravity = event.values;

                // Log.e(TAG, Float.toString(mGravity[0]));
            }

            if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                // mGeomagnetic = event.values;

                mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha)
                        * event.values[0];
                mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha)
                        * event.values[1];
                mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha)
                        * event.values[2];
                // Log.e(TAG, Float.toString(event.values[0]));

            }

            float R[] = new float[9];
            float I[] = new float[9];
            boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
                    mGeomagnetic);
            if (success) {
                float orientation[] = new float[3];
                SensorManager.getOrientation(R, orientation);
                // Log.d(TAG, "azimuth (rad): " + azimuth);
                azimuth = (float) Math.toDegrees(orientation[0]); // orientation
                azimuth = (azimuth + 360) % 360;

                if(bearing) {
                    if(bearingDegrees != -1) {
                        azimuth -= bearingDegrees;
                        adjustArrow();
                    }
                }
                else
                    adjustArrow();

                // Log.d(TAG, "azimuth (deg): " + azimuth);

            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}

Class 使用定位功能:

package com.gps.bitlab;

import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.gps.bitlab.R;
import com.gps.bitlab.fragment.OnDialogClickListener;
import com.gps.bitlab.util.Utility;

public class BringMeBack extends ActionBarActivity implements LocationListener, OnDialogClickListener {

    LocationManager locMng;

    Location location;
    double lat;
    double lon;
    double alt;
    String name;
    Compass compass;

    FrameLayout bearingParentLayout;
    LinearLayout BaseLayout;
    ImageView arrow;

    boolean layoutReplaced = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Utility.SetLocalization(this);
        setContentView(R.layout.activity_bring_me_back);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        getActionBar().setDisplayHomeAsUpEnabled(true);

        bearingParentLayout = (FrameLayout)findViewById(R.id.bearingParentLayout);
        BaseLayout = Utility.GetLoadingView(getLayoutInflater(), getString(R.string.waitingForLocation));

        if(savedInstanceState != null)
        {
            lat = savedInstanceState.getDouble("lat");
            lon = savedInstanceState.getDouble("lon");
            alt = savedInstanceState.getDouble("alt");
            name = savedInstanceState.getString("name");
        }
        else {
            lat = getIntent().getExtras().getDouble("lat");
            lon = getIntent().getExtras().getDouble("lon");
            alt = getIntent().getExtras().getDouble("alt");
            name = getIntent().getExtras().getString("name");
        }

        if(name != null && !name.equals(""))
            getActionBar().setTitle(name);

        locMng = (LocationManager)getSystemService(LOCATION_SERVICE);
        location = new Location(LocationManager.GPS_PROVIDER);
        location.setLongitude(lon);
        location.setLatitude(lat);
        location.setAltitude(alt);


        arrow = (ImageView)findViewById(R.id.bearingArrow);
        compass = new Compass(this);
        compass.arrowView = arrow;

        arrow.setVisibility(View.GONE);
        bearingParentLayout.addView(BaseLayout);
    }



    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == android.R.id.home) {
            BringMeBack.this.finish();
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPause() {
        super.onPause();
        compass.stopBearing();
        locMng.removeUpdates(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        compass.startBearing();
        RequestLocationUpdates();
    }


    @Override
    public void onLocationChanged(Location currentLocation) {

        float bearing = currentLocation.bearingTo(location);
        Log.d("Location bearing", String.valueOf(bearing));
        compass.setBearingDegrees(bearing);

        if(!layoutReplaced) {
            bearingParentLayout.removeView(BaseLayout);
            arrow.setVisibility(View.VISIBLE);
            layoutReplaced = true;
        }
    }

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {

    }

    @Override
    public void onProviderEnabled(String s) {
        Log.d("GPS", "Service enabled");
        RequestLocationUpdates();
    }

    @Override
    public void onProviderDisabled(String s) {
        locMng.removeUpdates(this);
        Utility.ShowMessage(BringMeBack.this, getString(R.string.locationServiceDisabledMessage), getString(R.string.locationServiceDisabled), 0);
    }

    @Override
    public void OnPositiveClick(int key, Object... args) {
        startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
    }

    @Override
    public void OnNegativeClick(int key, Object... args) {

    }

    private void RequestLocationUpdates()
    {
        if(!locMng.isProviderEnabled(LocationManager.GPS_PROVIDER))
            Utility.ShowMessage(BringMeBack.this, getString(R.string.locationServiceDisabledMessage), getString(R.string.locationServiceDisabled), 0);
        else
            locMng.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, this);
    }
}