确定罗盘方向
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);
}
}
我正在浏览互联网,试图找到对我的 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);
}
}