OSMファイルからバスルート情報を取り出して、同じバス停留所の名前が同じの場合、位置情報の平均値を計算して算出する方法

OSMファイルからバスルート情報を取り出して、同じバス停留所の名前が同じの場合、位置情報の平均値を計算して算出する方法

(以下、"私だけが分かればいい"メモ)

/*

F:\しゅらばしゅう\有吉先生データ\Transfer(2018)>go run bus_route_try_10.go

Golangで、以下のXML分の中から、<tag k="route" v="bus"/>を発見した時に、refの要素を参照にして位置情報を取り出すプログラム

そんで、同じ名前の停留所があったら、その座標の平均値として出力する

*/

package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

type Osm struct {
	XMLName   xml.Name   `xml:"osm"`
	Nodes     []Node     `xml:"node"`
	Relations []Relation `xml:"relation"`
}

type Node struct {
	ID   int64   `xml:"id,attr"`
	Lat  float64 `xml:"lat,attr"`
	Lon  float64 `xml:"lon,attr"`
	Tags []Tag   `xml:"tag"`
}

type Relation struct {
	ID      int64    `xml:"id,attr"`
	Members []Member `xml:"member"`
	Tags    []Tag    `xml:"tag"`
}

type Member struct {
	Type string `xml:"type,attr"`
	Ref  string `xml:"ref,attr"`
	Role string `xml:"role,attr"`
}

type Tag struct {
	K string `xml:"k,attr"`
	V string `xml:"v,attr"`
}

func main() {

	// XMLファイルの読み込み
	xmlFile, err := os.Open("tsuzuki.osm") // これがベースとなるosmファイル
	if err != nil {
		log.Fatal(err)
	}
	defer xmlFile.Close()

	// XMLデータの読み込み
	xmlData, err := ioutil.ReadAll(xmlFile)
	if err != nil {
		log.Fatal(err)
	}

	var osmData Osm

	// XMLデータのUnmarshal
	err = xml.Unmarshal(xmlData, &osmData)
	if err != nil {
		log.Fatal(err)
	}

	for _, relation := range osmData.Relations {

		//hasBusRouteTag := false

		for _, tag := range relation.Tags {

			if tag.K == "route" && tag.V == "bus" {

				for _, tag := range relation.Tags { // Tagの中で再度tagを回してnameを取得する(こんなことができるとは知りませんでした)
					if tag.K == "name" {
						fmt.Println("=========================")
						fmt.Printf("Route Name: %s\n", tag.V)
						break
					}
				}

				count := 0
				start_flag := 0
				//end_flag := 0
				pre_node := "ddd"
				sum_Lat := 0.0
				sum_Lon := 0.0

				for i, member := range relation.Members {

					if i == len(relation.Members)-1 { // 最後のノードを検知したら、その時点で纏めて計算して出力する
						//end_flag = 1

						fmt.Printf("Re:Bus Stop: %s\n", pre_node)
						fmt.Printf("Re:Coordinates: Lat %f, Lon %f\n\n", sum_Lat/float64(count), sum_Lon/float64(count))
					}

					if member.Type == "node" {
						node := getNodeByID(member.Ref, osmData.Nodes)
						if node != nil {

							if pre_node == getNodeName(node) || start_flag == 0  { // 停留所名が前回と同じであるなら

								count++
								sum_Lat += node.Lat
								sum_Lon += node.Lon

								start_flag = 1

							} else {

								fmt.Printf("Re:Bus Stop: %s\n", pre_node)
								fmt.Printf("Re:Coordinates: Lat %f, Lon %f\n\n", sum_Lat/float64(count), sum_Lon/float64(count))

								count = 1
								sum_Lat = node.Lat
								sum_Lon = node.Lon
							}

							pre_node = getNodeName(node)

						} 					   
					}
				}

			}
		}
	}
}

func getNodeByID(ref string, nodes []Node) *Node {
	for _, node := range nodes {
		if fmt.Sprintf("%d", node.ID) == ref {
			return &node
		}
	}
	return nil
}

func getNodeName(node *Node) string {
	for _, tag := range node.Tags {
		if tag.K == "name" {
			return tag.V
		}
	}
	return ""
}

出力はこんな感じになります。

F:\しゅらばしゅう\有吉先生データ\Transfer(2018)>go run bus_route_try_10.go
=========================
Route Name: IKEAシャトルバス 新横浜駅前-IKEA前
Re:Bus Stop: IKEAシャトルバス IKEA前
Re:Coordinates: Lat 35.522547, Lon 139.590950

=========================
Route Name: IKEAシャトルバス IKEA前-新横浜駅前
Re:Bus Stop: IKEAシャトルバス IKEA前
Re:Coordinates: Lat 35.522547, Lon 139.590950

=========================
Route Name: すみれが丘線
Re:Bus Stop: すみれが丘
Re:Coordinates: Lat 35.564881, Lon 139.580736

Re:Bus Stop: すみれが丘公園
Re:Coordinates: Lat 35.566768, Lon 139.583192

Re:Bus Stop: 有馬変電所
Re:Coordinates: Lat 35.569075, Lon 139.584080

Re:Bus Stop: 中有馬
Re:Coordinates: Lat 35.571500, Lon 139.584235

Re:Bus Stop: 神明社前
Re:Coordinates: Lat 35.571684, Lon 139.580940

Re:Bus Stop: 地区センター前
Re:Coordinates: Lat 35.560333, Lon 139.595547

Re:Bus Stop: 北山田駅
Re:Coordinates: Lat 35.561022, Lon 139.592536

Re:Bus Stop: 山田富士
Re:Coordinates: Lat 35.561428, Lon 139.590315

Re:Bus Stop: 重代
Re:Coordinates: Lat 35.563485, Lon 139.584835

Re:Bus Stop: 北山田小学校入口
Re:Coordinates: Lat 35.563816, Lon 139.582279

Re:Bus Stop: 東山田営業所
Re:Coordinates: Lat 35.561115, Lon 139.606000

Re:Bus Stop: 東山田営業所前
Re:Coordinates: Lat 35.561358, Lon 139.604353

Re:Bus Stop: 山田小学校
Re:Coordinates: Lat 35.560874, Lon 139.602905

Re:Bus Stop: 長泉寺
Re:Coordinates: Lat 35.560052, Lon 139.597552

=========================
Route Name: 鷺沼線;有馬線
Re:Bus Stop: 神明社前

2023,江端さんの技術メモ

Posted by ebata