夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

HoloLens×MapSDKでユーザーの現在地名を取得する。

本日は昨日作成したWifi経由の位置情報取得の応用です。

昨日はWifiで取得した位置情報をもとに現在地周辺のマップを表示することを行いました。

redhologerbera.hatenablog.com

今回は位置情報をもとに地名を表示します。

〇逆ジオコーディングとは?

[ジオコーディング]とは住所情報をもとに緯度経度情報を導く地理技術を指します。

[逆ジオコーディング]とはジオコーディングの逆で、緯度経度情報をもとに地名を取得することを指します。

[MapSDK]ではこの[逆ジオコーディング]に関する機能も提供されています。

[MapSDK]で提供されているデモシーン[Map Services Example]ではMap場をAirTapすることでその場所の住所表示を行えます。

redhologerbera.hatenablog.com

今回はこの仕組みを応用してユーザーの現在地の住所が表示されるようにします。

MapSDKでは[ReverseGeocodeOnClick]クラスを用いて逆ジオコーディングを実現しています。

このコードは前述のようにMap上のAirTapされた位置のPointer情報をもとに座標を指定しています。

今回はこれを後述のコードのように編集しました。

実機でデプロイするとつぎのようになります。

f:id:Holomoto-Sumire:20210615205920j:plain

youtu.be

これは浜松町駅で行っているためおおよその正しい住所が取得できています。

〇ジオコーディングのコード

using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.Geospatial;
using TMPro;
using UnityEngine;

/// <summary>
/// Instantiates a <see cref="MapPin"/> for each location that is reverse geocoded.
/// The <see cref="MapPin"/> will display the address of the reverse geocoded location.
/// </summary>
[RequireComponent(typeof(MapRenderer))]
public class ReverseGeocodeOnClick : MonoBehaviour
{
    private MapRenderer _mapRenderer = null;

    /// <summary>
    /// The layer to place MapPins.
    /// </summary>
    [SerializeField]
    private MapPinLayer _mapPinLayer = null;

    /// <summary>
    /// The MapPin prefab to instantiate for each location that is reverse geocoded.
    /// If it uses a TextMeshPro component, the address text will be written to it.
    /// </summary>
    [SerializeField]
    private MapPin _mapPinPrefab = null;

    public void Awake()
    {
        _mapRenderer = GetComponent<MapRenderer>();
      //  Debug.Assert(_mapRenderer != null);
      //  Debug.Assert(_mapPinLayer != null);
    }

    public async void OnMapClick(MixedRealityPointerEventData mixedRealityPointerEventData)
    {
        if (ReferenceEquals(MapSession.Current, null) || string.IsNullOrEmpty(MapSession.Current.DeveloperKey))
        {
            Debug.LogError(
                "Provide a Bing Maps key to use the map services. " +
                "This key can be set on a MapSession component.");
            return;
        }

        var focusProvider = CoreServices.InputSystem.FocusProvider;
        if (focusProvider.TryGetFocusDetails(mixedRealityPointerEventData.Pointer, out var focusDetails))
        {
            var location = _mapRenderer.TransformWorldPointToLatLon(focusDetails.Point);
            var finderResult = await MapLocationFinder.FindLocationsAt(location);

            string formattedAddressString = null;
            if (finderResult.Locations.Count > 0)
            {
                formattedAddressString = finderResult.Locations[0].Address.FormattedAddress;
            }

            if (_mapPinPrefab != null)
            {
                // Create a new MapPin instance, using the location of the focus details.
                var newMapPin = Instantiate(_mapPinPrefab);
                newMapPin.Location = location;
                var textMesh = newMapPin.GetComponentInChildren<TextMeshPro>();
                textMesh.text = formattedAddressString ?? "No address found.";

                _mapPinLayer.MapPins.Add(newMapPin);
            }
        }
        else
        {
            // Unexpected.
            Debug.LogWarning("Unable to get FocusDetails from Pointer.");
        }
    }

    public TextMeshPro text;
    public async void OnMapSent(LatLon latLon)
    {

            var location = latLon;
            var finderResult = await MapLocationFinder.FindLocationsAt(location);

            string formattedAddressString = null;
            if (finderResult.Locations.Count > 0)
            {
                formattedAddressString = finderResult.Locations[0].Address.FormattedAddress;
            }


            var textMesh = text;
                textMesh.text = formattedAddressString ?? "No address found.";
            Debug.Log(formattedAddressString ?? "No address found.");
               //  _mapPinLayer.MapPins.Add(newMapPin);
            
             

    }
}

〇コード

using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
#if UNITY_WSA && !UNITY_EDITOR
using Windows.Devices.Geolocation;
#endif
using TMPro;
using Microsoft.Maps.Unity;
using Microsoft.Geospatial;

public class GetPlayerLocation : MonoBehaviour
{
    public MapRenderer mapRenderer;
    public TextMeshPro debugText;
    private uint _desireAccuracyInMetersValue = 0;

    public ReverseGeocodeOnClick _rgoc;
    // Start is called before the first frame update
    async void Start()
    {
        debugText.text = "Initialization.";
       
#if UNITY_WSA && !UNITY_EDITOR
        var accessStatus = await Geolocator.RequestAccessAsync();
        switch (accessStatus)
        {
            case GeolocationAccessStatus.Allowed:
                debugText.text = "Waiting for update...";
                Geolocator geolocator = new Geolocator { DesiredAccuracyInMeters = _desireAccuracyInMetersValue };
                Geoposition pos = await geolocator.GetGeopositionAsync();
                UpdateLocationData(pos);
                break;

            case GeolocationAccessStatus.Denied:
                debugText.text = "Access to location is denied.";
                break;

            case GeolocationAccessStatus.Unspecified:
                debugText.text = "Unspecified error.";
                UpdateLocationData(null);
                break;
        }
#endif
    }

#if UNITY_WSA && !UNITY_EDITOR
    private void UpdateLocationData(Geoposition position)
    {
        if (position == null)
        {
            debugText.text = "No data";
        }
        else
        {
            debugText.text = position.Coordinate.Point.Position.Latitude.ToString() + "\n" + position.Coordinate.Point.Position.Longitude.ToString();
            mapRenderer.SetMapScene(new MapSceneOfLocationAndZoomLevel(new LatLon(position.Coordinate.Point.Position.Latitude, position.Coordinate.Point.Position.Longitude), 17f));
             _rgoc.OnMapSent(new LatLon(position.Coordinate.Point.Position.Latitude, position.Coordinate.Point.Position.Longitude));
        }
    }
#endif
}