Solución:
Ok, así es como creo que debería hacerse un año después. Corríjame si detecta algún problema.
La mayor parte del siguiente código trata sobre una discrepancia entre los sistemas de coordenadas. Estoy usando un sensor de vector de rotación. De los documentos: Y is tangential to the ground at the device's current location and points towards magnetic north.
El rumbo en los mapas de Google, por otro lado, parece apuntar al norte verdadero. esta página muestra cómo se realiza la conversión
1) obtenga la declinación actual de su ubicación GPS actual
@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) calcular el rumbo a partir de la declinación y el norte magnético
@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) actualizar mapas
private void updateCamera(float bearing) {
CameraPosition oldPos = mMap.getCameraPosition();
CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing).build();
mMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));
}
He implementado con éxito la solución aleph_null y aquí agregaré algunos detalles que no se mencionan en la solución aceptada:
Para que la solución anterior funcione, debe implementar la interfaz android.hardware.SensorEventListener.
También debe registrarse en SensorEventListener en sus métodos onResume y onPause de la siguiente manera:
@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);
}
Nota para “@Bytecode”: para evitar el parpadeo, use un valor bajo para el período de muestreo, algo como SensorManager.SENSOR_STATUS_ACCURACY_LOW.
También he notado que el sensor envía en algún momento más datos de los que el dispositivo puede manejar y, como resultado, ¡la cámara del mapa comienza a moverse de una manera extraña!
Para controlar la cantidad de datos que maneja onSensorChanged, sugiero la siguiente implementación:
@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]);
}
}
Es posible registrando su aplicación con Sensor Listener para Orientación y obteniendo el ángulo relativo al norte verdadero dentro de onSensorChanged y actualizando la cámara en consecuencia. El ángulo se puede utilizar para cojinetes. Se puede utilizar el siguiente código:
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));
}