ARCore Geospatial APIの緯度経度の情報を持つAREarthManagerについて調べてみた

# 概要

- ARCore Geospatial APIとはGoogleの発表したVPS（Visual Positioning Service/System）です
- ARCoreですが、Android/iOS両方で利用することができます
- AREarthManagerについて調べてみました

# はじめに

こんにちは、ARエンジニアのイワケンです。

本日は[Geospatial道場](https://withar.connpass.com/event/249282/)を主催・参加し、GeoSpatialの記事を書いています。

今回「[ARCore Geospatial APIをUnityで使ってみる](https://zenn.dev/tkada/articles/04b44474149130)」の記事を見ながら進めていくうえで、AREarthManagerというクラスの変数や関数を見ながら理解を深めました。

# 環境

- Unity2021.3.4f1
- AR Fundation 4.2.3
- ARCore XR Plugin 4.2.3
- ARKit XR Plugin 4.2.3
- ARCore Extensions 1.31.0

# 筆者のアウトプット

Unity -> XCodeへビルド
XCodeからiPhoneへ実機実行

ハチ公前で試してみました。見事成功

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/fb7e0b96-6cdd-27a1-8b3a-8d3fc2a3eb88.png width=300>

## 上のこの数字なんだろう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/bbd66172-6e3e-bc08-a4a5-0041c95d4bc5.png)

この数字はGeoSpatial APIから取得した数値なのですが、これらの情報を理解するためにはAREarthManagerについて理解する必要があるでしょう。

```csharp
if (earthTrackingState == TrackingState.Tracking)
            {
                InfoText.text = string.Format(
                "Latitude/Longitude: {1}°, {2}°{0}" +
                "Horizontal Accuracy: {3}m{0}" +
                "Altitude: {4}m{0}" +
                "Vertical Accuracy: {5}m{0}" +
                "Heading: {6}°{0}" +
                "Heading Accuracy: {7}°",
                Environment.NewLine,
                pose.Latitude.ToString("F6"),
                pose.Longitude.ToString("F6"),
                pose.HorizontalAccuracy.ToString("F6"),
                pose.Altitude.ToString("F2"),
                pose.VerticalAccuracy.ToString("F2"),
                pose.Heading.ToString("F1"),
                pose.HeadingAccuracy.ToString("F1"));
            }
```

# AREarthManagerについて調べる

公式ドキュメントはこちら

https://developers.google.com/ar/reference/unity-arf/class/Google/XR/ARCoreExtensions/AREarthManager

こちらを読みながら日本語訳や自分の理解を整理した記事になります。

順序としては

- Geospatial APIで情報取得する前の準備
- CameraGeospatialPoseで中身を見る

の2段階になります。

# Geospatial APIで情報取得する前の準備

結論、緯度経度などの情報は `AREarthManager.CameraGeospatialPose`というプロパティに含まれています。
しかし、その前に取得する前に前準備が必要になります。

1. `AREarthManager.IsGeospatialModeSupported` で、現在のデバイスがGeospatialModeをサポートしているか調べる
2. `AREarthManager.EarthTrackingState`のenum値が`Tracking`になっているか調べる
3. `AREarthManager.CameraGeospatialPose`を取得することができる

## AREarthManager.IsGeospatialModeSupportedでサポートしているか調べる。

端末によってはGeospatialの機能をサポートしていない端末もあります。

それを判別するために

```csharp
 var featureSupport = EarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled);
            switch (featureSupport)
            {
                case FeatureSupported.Unknown:
                    return;
                case FeatureSupported.Unsupported:
                    Debug.Log("Geospatial API is not supported by this devices.");
                    return;
                case FeatureSupported.Supported: //good
                    Debug.Log("Geospatial API is supported by this devices.");
                    break;
            }
```

このような関数を使います。

## AREarthManager.EarthTrackingStateのenum値がTrackingになっているか調べる

例えば、下のような書き方で調べます
```csharp
if(EarthManager.EarthTrackingState == TrackingState.Tracking){
    //トラッキング中
}
```

## AREarthManager.CameraGeospatialPoseを取得することができる

```csharp
GeospatialPose pose = EarthManager.CameraGeospatialPose;
```

# GeospatialPoseの中身

では、GeospatialPoseにはどんな情報が入っているでしょうか？

https://developers.google.com/ar/reference/unity-arf/struct/Google/XR/ARCoreExtensions/GeospatialPose#structGoogle_1_1XR_1_1ARCoreExtensions_1_1GeospatialPose

一言
地球からの相対的な位置、標高、コンパスの方位を記述します。

## Summary

以下の構成になっています

- Latitude(緯度)・longitude(経度)は度数で指定し、正の値は[WGS84仕様](https://en.wikipedia.org/wiki/World_Geodetic_System)で定義された赤道より北、本初子午線より東を意味する。
- Altitude(標高)はWGS84楕円体からの高さで、海抜メートルとほぼ等しい値で指定します。
- Heading (方位)は北から時計回りの度で指定します。詳しくは[GeospatialPose.Heading](https://developers.google.com/ar/reference/unity-arf/struct/Google/XR/ARCoreExtensions/GeospatialPose#heading)を参照してください。
- 緯度、経度、高度、方位の精度は信頼区間の数値で見ることができ、数値が大きい（信頼区間大）ほど信頼度が低く、数値が小さい（信頼区間小）ほど信頼度が高いことを示します。

GeospatialPose は AREarthManager.CameraGeospatialPose から取得することができる。

## Public attributes (publuc変数)

|GeospatialPoseの変数名|型|内容|
|---|---|---|
|Altitude|double|WGS 84楕円体からの高さでのポーズの高度（単位：メートル）|
|Heading|double|ポーズの方位（単位：度数）|
|HeadingAccuracy|double|推定方位精度（単位：度数）|
|HorizontalAccuracy|double|緯度・経度に対する水平精度の推定値（単位：メートル）|
|Latitude|double|ポーズの緯度（単位：度数）|
|Longitude|double|ポーズの経度（単位：度数）|
|VerticalAccuracy|double|水平精度の推定値（単位：メートル）|

### Altitude (高度)

WGS 84楕円体からの高さでのポーズの高度。

### Heading (方位)

ポーズのヘディングを度数で示す。

Headingは真北から時計回りで指定され、デバイスが向いている方向を近似する。北向きの場合は 0°、東向きの場合は 90°、南向きの場合は +/-180°、西向きの場合は -90° が返されます。

ヘディングの近似は、デバイスの現在のオリエンテーションモード（すなわち、縦または横）での回転とピッチに基づきます。例えば、デバイスが垂直または直立に保持されている場合、方位はカメラ光軸に基づきます。デバイスが水平に保持され、下を向いている場合、方位は、オリエンテーションモードに関して、デバイスの上部に基づきます。


現在、ヘディングはデバイスのデフォルトのオリエンテーションモード（ほとんどのサポートデバイスのポートレートモード）のみでサポートされています。
つまりスマホ縦型のみ反応する。

### HeadingAccuracy (方位の精度)

推定方位精度を度単位で表示します。

**低いほど精度が高い**

`Heading`精度は`Heading`を中心とした68%信頼度の半径と定義しています。言い換えると、真の`Heading`が`HeadingAccuracy`の範囲内にある確率は68%です。値が大きい程、精度が低いことを示します。

例えば、推定された`heading`が60°で`HeadingAccuracy`が10°の場合、真のヘディングが50°から70°の間にある確率は68%です。

### HorizontalAccuracy (水平精度)

緯度・経度に対する水平精度の推定値（メートル）。

つまり、円の半径の精度。**低いほど精度が高い**

水平精度は、推定された水平位置の周りの68パーセンタイル信頼度の半径と定義しています。つまり、緯度と経度を中心とし、水平精度と同じ半径の円を描くと、68%の確率で真の位置が円の内側にあることになります。数字が大きくなるほど精度は低くなります。

例えば、緯度が10°、経度が10°で、返されたHorizontalAccuracy値が15であれば、真の位置が(10°, 10°)の緯度経度座標から15m以内にある確率は68%であることを示しています。

### VerticalAccuracy (垂直精度)

緯度・経度に対する垂直精度の推定値（単位：メートル）。

つまり、高さの精度。**低いほど精度が高い**

垂直方向の精度を、推定高度を中心とした68%信頼度の半径と定義します。言い換えれば、真の高度がこのAltitudeの出力値（メートル単位）以内である確率は68％です（上か下か）。数値が大きいほど精度が低いことを示します。

例えば、Altitudeが100メートルで、VerticalAccuracyが20メートルの場合、真の高度が100メートルから20メートル以内 (高度80m ~ 120m)にある確率は68％です。

### Latitude (緯度)

ポーズの緯度（度）。

正の値は、[WGS84仕様](https://en.wikipedia.org/wiki/World_Geodetic_System)で定義された赤道より北にあることを意味する。

### Longitude (経度)

ポーズの経度（度数）。

正の値は、WGS84仕様で定義された本初子午線より東である。


# まとめ

この記事では、AREarthManagerについて調べることで、

- Geospatial APIで情報取得する前の準備
- GeospatialPoseによって取得できる情報

について述べました。