技術にっき

気になる技術について呟いてます

Googleマイマップのルート情報をUnityで扱う方法

地図上のある移動経路における各地点の地理座標系(緯度・経度)を取得して
Unityで扱う方法
を調べてみました。

移動経路における各地点のイメージ図
今回は、Googleマップのマイマップの機能を利用する方法の一つを紹介します。

Unity バージョン:Unity 2020.3.32f1


マイマップとは

マイマップGoogleマップの機能のひとつで、好きな場所にマーカーを置いたり
メモやルートを作成するなど自分用のマップを作ることができる機能です。
また、他の人にマイマップを共有して同時編集することも可能です。

ルート情報をUnityで扱う方法

下記の手順を行うことで、マイマップで作成したルートにおける
各地点の地理座標系をUnityで扱うことができます。

1. マイマップでルートを作成する
2. マイマップを公開する
3. マイマップのKMLファイルをUnityで取得する
4. 特定のルートにおける地理座標系の情報を取得する

各手順の方法を下記で説明します。
Googleアカウント保有を前提としています。
 活用の際はGoogleマップの利用規約をご確認ください。

1. マイマップでルートを作成する

保有するマイマップがない場合は、My Mapsのサイトから「+ 新しい地図を作成」
ボタンを押して新しいマイマップを作成します。

マイマップを作成

その後、マイマップでルートを作成します。具体的な作成方法は
割愛しますが、移動経路における目的地と移動方法、ルート名を設定します。

ルートの作成

2. マイマップを公開する

マイマップ名の下にある「共有」を押して、地図タイトルと説明を
記載後、「OK」ボタンを押します。
さらに地図の共有で、図のようにリンクを知っている人に公開する
設定を行い、リンクをコピーしておきましょう。

リンクを知っている人へのマイマップの公開

3. マイマップのKMLファイルをUnityで取得する

UnityWebRequestを使い、マイマップのKMLファイルを取得します。

KML(Keyhole Markup Language)はGoogleマップなどで地理データの表示に
使用されるファイル形式です。

Unity内で下記のようなC#スクリプトを作成し、GameObjectにアタッチ
することで、UnityでKMLファイルを取得し、ログにてKMLファイルの中身を
確認することができます。
※ midは手順2でコピーしたURLのリクエストパラメータの値を参照

// MyBehaviour.cs
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
 
public class MyBehaviour : MonoBehaviour {

    // コピーしたURL中のmidの値を設定する
    [SerializeField] string mid = "******************************";

    void Start() {
        StartCoroutine(GetText());
    }
 
    IEnumerator GetText() {
        UnityWebRequest www = UnityWebRequest.Get("https://www.google.com/maps/d/u/0/kml?mid=" + mid + "&forcekml=1");
        yield return www.SendWebRequest();
 
        if (www.result != UnityWebRequest.Result.Success) {
            Debug.Log(www.error);
        }
        else {
            Debug.Log(www.downloadHandler.text);
        }
    }
}

KMLファイルをログに出力

4. 特定のルートにおける地理座標系の情報を取得する

3で取得したKMLファイルのデータから特定ルートの部分を切り出して
Unityで扱えるようリストの状態に変換します。
3で作成したC#スクリプトを下記の様に修正することで
ルートの地理座標系情報をリストで扱えるようになりました!

// MyBehaviour.cs
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;

public class MyBehaviour : MonoBehaviour {

    // ルート名とコピーしたURL中のmidの値を設定する
    [SerializeField] string mid = "******************************";
    [SerializeField] string route = "***********";

    void Start() {
        StartCoroutine(GetText());
    }
 
    IEnumerator GetText() {
        UnityWebRequest www = UnityWebRequest.Get("https://www.google.com/maps/d/u/0/kml?mid=" + mid + "&forcekml=1");
        yield return www.SendWebRequest();
 
        if (www.result != UnityWebRequest.Result.Success) {
            Debug.Log(www.error);
        }
        else {
            //Debug.Log(www.downloadHandler.text);
            string areaText;
            List<List<double>> coordinateList;
            areaText = GetRouteArea(www.downloadHandler.text);
            if(areaText!=""){
                coordinateList = CreateCoordinateList(areaText);
                DisplayCoordinateList(coordinateList);
            } 
        }
    }

    // ルート名に対応する地理座標系を抽出する
    private string GetRouteArea(string text){
        string returnStr = "";        
        System.Text.RegularExpressions.Regex r =
            new System.Text.RegularExpressions.Regex(
                    @"<Placemark>\s*<name>"
                    + System.Text.RegularExpressions.Regex.Escape(route) 
                    + @"</name>.*?<(coordinates)>(.*?)</\1>",
                System.Text.RegularExpressions.RegexOptions.IgnoreCase
                | System.Text.RegularExpressions.RegexOptions.Singleline);
        System.Text.RegularExpressions.MatchCollection mc = r.Matches(text);

        if(mc.Count==0){
            Debug.Log("No match.");
            return returnStr;
        }
        foreach (System.Text.RegularExpressions.Match m in mc){
            returnStr = m.Groups[2].Value;
        }  
        return returnStr;
    }

    // 地理座標系のリストを作成する
    private List<List<double>> CreateCoordinateList(string text){
        var list = new List<List<double>>();
        int i = 0;
        System.Text.RegularExpressions.Regex r =
            new System.Text.RegularExpressions.Regex(
                    @"\s+([^\s]+?),([^\s]+?),0\s",
                System.Text.RegularExpressions.RegexOptions.IgnoreCase
                | System.Text.RegularExpressions.RegexOptions.Singleline);
        System.Text.RegularExpressions.MatchCollection mc = r.Matches(text);
                      
        foreach (System.Text.RegularExpressions.Match m in mc){
            // 緯度:list[x][0] - Groups[2].Value
            // 経度:list[x][1] - Groups[1].Value
            list.Add(new List<double>());
            list[i].Add(double.Parse(m.Groups[2].Value));
            list[i].Add(double.Parse(m.Groups[1].Value));
            i++;
        }      
        return list;
    }

    // 地理座標系のリストを一覧表示する
    private void DisplayCoordinateList(List<List<double>> list){
        int i=0;
        string displayStr="";
        foreach (List<double> li in list){
                displayStr +=(i+1) + ":緯度: " + li[0] + " 経度: " +  li[1] + "\n";
                i++;
        }     
        Debug.Log(displayStr);
    }
}



参考:
HTTP サーバーからテキストやバイナリデータを取得 (GET)/Unity Documentation
UnityでHTMLからテキスト出力/Sirohood

※当ブログに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。
 当サイトで掲載している画像や動画の著作権・肖像権等は各権利所有者に帰属致します。