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.580736Re:Bus Stop: すみれが丘公園
Re:Coordinates: Lat 35.566768, Lon 139.583192Re:Bus Stop: 有馬変電所
Re:Coordinates: Lat 35.569075, Lon 139.584080Re:Bus Stop: 中有馬
Re:Coordinates: Lat 35.571500, Lon 139.584235Re:Bus Stop: 神明社前
Re:Coordinates: Lat 35.571684, Lon 139.580940Re:Bus Stop: 地区センター前
Re:Coordinates: Lat 35.560333, Lon 139.595547Re:Bus Stop: 北山田駅
Re:Coordinates: Lat 35.561022, Lon 139.592536Re:Bus Stop: 山田富士
Re:Coordinates: Lat 35.561428, Lon 139.590315Re:Bus Stop: 重代
Re:Coordinates: Lat 35.563485, Lon 139.584835Re:Bus Stop: 北山田小学校入口
Re:Coordinates: Lat 35.563816, Lon 139.582279Re:Bus Stop: 東山田営業所
Re:Coordinates: Lat 35.561115, Lon 139.606000Re:Bus Stop: 東山田営業所前
Re:Coordinates: Lat 35.561358, Lon 139.604353Re:Bus Stop: 山田小学校
Re:Coordinates: Lat 35.560874, Lon 139.602905Re:Bus Stop: 長泉寺
Re:Coordinates: Lat 35.560052, Lon 139.597552=========================
Route Name: 鷺沼線;有馬線
Re:Bus Stop: 神明社前