SensorEvent.valuesのZ軸データを使用しようとしましたが、XY平面での電話の回転が検出されません。Z軸の周り。
これを座標軸の基準として使用しています。それが正しいか?
加速度計の値を使用してその動きを測定するにはどうすればよいですか?
これらのゲームは似たようなことをします:Extreme Skater、DoodleJump。
PS:私の電話の向きは横向きになります。
SensorEvent.valuesのZ軸データを使用しようとしましたが、XY平面での電話の回転が検出されません。Z軸の周り。
これを座標軸の基準として使用しています。それが正しいか?
加速度計の値を使用してその動きを測定するにはどうすればよいですか?
これらのゲームは似たようなことをします:Extreme Skater、DoodleJump。
PS:私の電話の向きは横向きになります。
基本的に、ここには2つのケースがあります。デバイスが平らに置かれている場合と平らになっていない場合です。ここでフラットとは、デバイス画面の表面とワールドxy平面(私はこれを傾斜と呼びます)の間の角度が25度未満または155度より大きいことを意味します。電話が平らになっている、またはテーブルから少し上に傾いていると考えてください。
まず、加速度計のベクトルを正規化する必要があります。
つまり、gが加速度計センサーのイベント値によって返されるベクトルである場合です。コード内
float[] g = new float[3];
g = event.values.clone();
double norm_Of_g = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
// Normalize the accelerometer vector
g[0] = g[0] / norm_Of_g
g[1] = g[1] / norm_Of_g
g[2] = g[2] / norm_Of_g
次に、傾斜は次のように計算できます。
int inclination = (int) Math.round(Math.toDegrees(Math.acos(g[2])));
したがって
if (inclination < 25 || inclination > 155)
{
// device is flat
}
else
{
// device is not flat
}
平らに置く場合は、コンパスを使用して、デバイスが開始位置からどれだけ回転しているかを確認する必要があります。
平らでない場合、回転(傾き)は次のように計算されます
int rotation = (int) Math.round(Math.toDegrees(Math.atan2(g[0], g[1])));
ここで、rotation = 0は、デバイスが通常の位置にあることを意味します。これは、ほとんどの携帯電話では傾きのない縦向きであり、タブレットではおそらく横向きです。したがって、上の写真のように電話を持って回転を開始すると、回転が変化し、電話が横向きの場合、回転は90または-90になります。これは回転の方向によって異なります。
Hoanが非常にうまく示したように、加速度計は電話が平らかどうかをチェックするのに十分です。
電話が平らかどうかだけでなく、電話の回転が何であるかを確認するためにここに到着した人は、回転ベクトルモーションセンサーを使用してそれを行うことができます。
private double pitch, tilt, azimuth;
@Override
public void onSensorChanged(SensorEvent event) {
//Get Rotation Vector Sensor Values
double[] g = convertFloatsToDoubles(event.values.clone());
//Normalise
double norm = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2] + g[3] * g[3]);
g[0] /= norm;
g[1] /= norm;
g[2] /= norm;
g[3] /= norm;
//Set values to commonly known quaternion letter representatives
double x = g[0];
double y = g[1];
double z = g[2];
double w = g[3];
//Calculate Pitch in degrees (-180 to 180)
double sinP = 2.0 * (w * x + y * z);
double cosP = 1.0 - 2.0 * (x * x + y * y);
pitch = Math.atan2(sinP, cosP) * (180 / Math.PI);
//Calculate Tilt in degrees (-90 to 90)
double sinT = 2.0 * (w * y - z * x);
if (Math.abs(sinT) >= 1)
tilt = Math.copySign(Math.PI / 2, sinT) * (180 / Math.PI);
else
tilt = Math.asin(sinT) * (180 / Math.PI);
//Calculate Azimuth in degrees (0 to 360; 0 = North, 90 = East, 180 = South, 270 = West)
double sinA = 2.0 * (w * z + x * y);
double cosA = 1.0 - 2.0 * (y * y + z * z);
azimuth = Math.atan2(sinA, cosA) * (180 / Math.PI);
}
private double[] convertFloatsToDoubles(float[] input)
{
if (input == null)
return null;
double[] output = new double[input.length];
for (int i = 0; i < input.length; i++)
output[i] = input[i];
return output;
}
次に、電話がフラットかどうかを確認するには、との値を許容値と比較するだけtilt
ですpitch
。例えば
public boolean flatEnough(double degreeTolerance) {
return tilt <= degreeTolerance && tilt >= -degreeTolerance && pitch <= degreeTolerance && pitch >= -degreeTolerance;
}
この方法の利点は、電話が特定の回転で保持されているかどうかを確認できることです。
アプリの向きがピッチ、チルト、方位角の値に影響を与えないことは注目に値します。
@Danからの完璧な応答に取り組んでいます
彼は@davy307が指摘したごくわずかな情報を見逃していました。
mAccelerometerを初期化するときは、 Sensor.TYPE_ROTATION_VECTORとして定義する必要があります。そうしないと、3番目の回転ベクトルがなくなり、ArrayIndexOutOfBounds例外がスローされます。
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
そうでなければ、これは完璧な解決策です...感謝します!