はじめに
ポケモンGOのAR+モードみたいに、端末の向きを知りたいなと思って調べたことを書きます。
TYPE_ORIENTATION が廃止された話
端末の向きを調べたい! ってことでググると、TYPE_ORIENTATION
が廃止されたので、TYPE_ACCELEROMETER
と TYPE_MAGNETIC_FIELD
と SensorManager.getRotationMatrix()
と SensorManager.getOrientation()
を使いましょうって話が出てきます。
廃止の代替策だし、公式ドキュメントでも同様の話があるので、これがベストプラックティスなんだろうなと思って試してみました。
するとなんだがガタガタして安定しません。ローパスフィルタを通してみましたが、どうにも遅延せずに安定させる方法が見つかりません。
どうしたらいいのーーー??? と迷子になってしまいました。
stardroidのソース
Sky Map(旧 Google Sky Map)という、プラネタリウムアプリがあります。端末を空にかざすと、その方向に見える星空を確認することができるアプリです。
試してみるとめっちゃ滑らかです。Sky Mapと同様の滑らかさを実現したい!
幸運なことに、Sky Mapはオープンソースになってて stardroid という名前で公開されています。ソースが見れればどのセンサーを使っているか分かる!
ベストプラックティス
ということで調べてみたら、TYPE_ROTATION_VECTOR
を使ってました。
4つの値で得られるので、たぶんクォータニオンです。
前述の TYPE_ACCELEROMETER
と TYPE_MAGNETIC_FIELD
を使うパターンでは、SensorManager.getRotationMatrix()
で回転行列に変換していましたが、TYPE_ROTATION_VECTOR
の場合は SensorManager.getRotationMatrixFromVector()
で回転行列に変換できます。
分からないこと
端末によって搭載しているセンサーが千差万別です。
TYPE_ACCELEROMETER
と TYPE_MAGNETIC_FIELD
があれば、必ずTYPE_ROTATION_VECTOR
があるのか、不明です。
stardroidではTYPE_ROTATION_VECTOR
がない場合にTYPE_ACCELEROMETER
と TYPE_MAGNETIC_FIELD
を使う処理があります。また、設定から強制的にTYPE_ACCELEROMETER
と TYPE_MAGNETIC_FIELD
を使うようにもできます。
TYPE_ROTATION_VECTOR
に磁気偏角の補正がかかっているのか、利用側で補正しなきゃいけないのかわかりません。stardroidのソースをちゃんと見ればいいのですが、複雑過ぎて追いきれませんでした(涙目)
センサ精度の読み取りもよくわかっていません。巷のアプリでよく、「8の字に動かしてセンサの精度を上げましょう」みたいな表示を見たことがあるかと思います。その情報を拾おうとしたら、かならず精度が問題ない風に報告してくるので、どこで読み取っているんだろう?という疑問が解決してません。これもstardroidのソースをちゃんと見ればいいんですけどね(死んだ魚の目)