J'ai trouvé ce que je cherchais, des matrices rotatives. J'utilisais des angles d'Euler (roulis, tangage, lacet) pour le tangage et le roulis. Lorsque le téléphone est à 90 degrés, les plis x et z sont les mêmes et le téléphone devient fou, un défaut fondamental avec des angles d'Euler.
Je dois obtenir la hauteur et degrés rouleau en utilisant des matrices de rotation via getRotationMatrix
Ici, il est pour tous;)
XML:
<?xml version="1.0" encoding="utf-8"?>
<!-- This file is res/layout/main.xml -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button android:id="@+id/update" android:text="Update Values"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doUpdate" />
<Button android:id="@+id/show" android:text="Show Me!"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doShow" android:layout_toRightOf="@id/update" />
<TextView android:id="@+id/preferred" android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/update" />
<TextView android:id="@+id/orientation" android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/preferred" />
</RelativeLayout>
code:
package YOURPACKAGE;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
public class YOURCLASS extends Activity implements SensorEventListener {
private static final String TAG = "VirtualJax";
private SensorManager mgr;
private Sensor accel;
private Sensor compass;
private Sensor orient;
private TextView preferred;
private TextView orientation;
private boolean ready = false;
private float[] accelValues = new float[3];
private float[] compassValues = new float[3];
private float[] inR = new float[9];
private float[] inclineMatrix = new float[9];
private float[] orientationValues = new float[3];
private float[] prefValues = new float[3];
private float mAzimuth;
private double mInclination;
private int counter;
private int mRotation;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preferred = (TextView)findViewById(R.id.preferred);
orientation = (TextView)findViewById(R.id.orientation);
mgr = (SensorManager) this.getSystemService(SENSOR_SERVICE);
accel = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
compass = mgr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
orient = mgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
WindowManager window = (WindowManager) this.getSystemService(WINDOW_SERVICE);
int apiLevel = Integer.parseInt(Build.VERSION.SDK);
if(apiLevel <8) {
mRotation = window.getDefaultDisplay().getOrientation();
}
else {
mRotation = window.getDefaultDisplay().getRotation();
}
}
@Override
protected void onResume() {
mgr.registerListener(this, accel, SensorManager.SENSOR_DELAY_GAME);
mgr.registerListener(this, compass, SensorManager.SENSOR_DELAY_GAME);
mgr.registerListener(this, orient, SensorManager.SENSOR_DELAY_GAME);
super.onResume();
}
@Override
protected void onPause() {
mgr.unregisterListener(this, accel);
mgr.unregisterListener(this, compass);
mgr.unregisterListener(this, orient);
super.onPause();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// ignore
}
public void onSensorChanged(SensorEvent event) {
// Need to get both accelerometer and compass
// before we can determine our orientationValues
switch(event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
for(int i=0; i<3; i++) {
accelValues[i] = event.values[i];
}
if(compassValues[0] != 0)
ready = true;
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for(int i=0; i<3; i++) {
compassValues[i] = event.values[i];
}
if(accelValues[2] != 0)
ready = true;
break;
case Sensor.TYPE_ORIENTATION:
for(int i=0; i<3; i++) {
orientationValues[i] = event.values[i];
}
break;
}
if(!ready)
return;
if(SensorManager.getRotationMatrix(inR, inclineMatrix, accelValues, compassValues)) {
// got a good rotation matrix
SensorManager.getOrientation(inR, prefValues);
mInclination = SensorManager.getInclination(inclineMatrix);
// Display every 10th value
if(counter++ % 10 == 0) {
doUpdate(null);
counter = 1;
}
}
}
public void doUpdate(View view) {
if(!ready)
return;
mAzimuth = (float) Math.toDegrees(prefValues[0]);
if(mAzimuth < 0) {
mAzimuth += 360.0f;
}
String msg = String.format(
"Preferred:\nazimuth (Z): %7.3f \npitch (X): %7.3f\nroll (Y): %7.3f",
mAzimuth, Math.toDegrees(prefValues[1]),
Math.toDegrees(prefValues[2]));
preferred.setText(msg);
msg = String.format(
"Orientation Sensor:\nazimuth (Z): %7.3f\npitch (X): %7.3f\nroll (Y): %7.3f",
orientationValues[0],
orientationValues[1],
orientationValues[2]);
orientation.setText(msg);
preferred.invalidate();
orientation.invalidate();
}
public void doShow(View view) {
// google.streetview:cbll=30.32454,-81.6584&cbp=1,yaw,,pitch,1.0
// yaw = degrees clockwise from North
// For yaw we can use either mAzimuth or orientationValues[0].
//
// pitch = degrees up or down. -90 is looking straight up,
// +90 is looking straight down
// except that pitch doesn't work properly
Intent intent=new Intent(Intent.ACTION_VIEW, Uri.parse(
"google.streetview:cbll=30.32454,-81.6584&cbp=1," +
Math.round(orientationValues[0]) + ",,0,1.0"
));
startActivity(intent);
return;
}
J'ai le même problème, bien que j'utilise aussi des matrices de rotation. J'utilise getRotationMatrixFromVector() à la place de getRotationMatrix(), car j'utilise TYPE_ROTATION_VECTOR. Y a-t-il des différences entre ces deux méthodes? La deuxième question est ce que ceci est pour vous dans le code si (mAzimuth <0) { mAzimuth + = 360.0f; }? – Nazerke
Impossible de commenter sur le vecteur, mais le mAzimuth est le cap de la boussole, il ne fournit pas comme une lecture propre 0-360, vous devez convertir les valeurs neg en 360, plus beaucoup d'autres réglages si vous vouloir calculer correctement. Vous penseriez que vous pourriez juste demander à l'appareil pour le lancement, le rouleau et la boussole et le ramener, pas moyen, vous arrivez à le comprendre, un PITA majeur pour ce qui aurait dû être simple. – user1234051
Quels sont ces autres tweaks? Que faites-vous avec mInclination? Est-ce que cela fait partie de la correction? J'utilise aussi getRotationMatrixFromVector() et je vois l'azimut varier avec la hauteur, ce que je ne veux pas, et Google maps ne le fait pas en mode boussole. – Flyview