2023,江端さんの技術メモ

C:\Users\ebata\tomioka3B\src\others\main21.goでバトル中 

tomioka_db_c=# SELECT seq, node, edge, source, target, b.cost FROM pgr_dijkstra('SELECT gid as id, source, target, cost, reverse_cost FROM ways WHERE (source NOT BETWEEN 10 AND 20 AND target NOT BETWEEN 10 AND 20) AND (source NOT BETWEEN 30 AND 40 AND target NOT BETWEEN 30 AND 40)',1, 50, directed := false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;

seq | node | edge | source | target | cost
-----+------+------+--------+--------+------------------------
1 | 1 | 2 | 1 | 2 | 8.518550262944415e-05
2 | 2 | 3 | 2 | 3 | 0.0009420518456308501
3 | 3 | 4 | 3 | 4 | 0.00026662995399998605
4 | 4 | 5 | 4 | 5 | 0.00021389117484400878
5 | 5 | 6 | 5 | 6 | 4.656362881781325e-05
6 | 6 | 7 | 6 | 7 | 0.00013184236987589488
7 | 7 | 8 | 7 | 8 | 6.438782425766514e-05
8 | 8 | 1254 | 8 | 897 | 1.2290752319372595e-05
9 | 897 | 1380 | 897 | 969 | 0.00038637624148597305
10 | 969 | 1938 | 969 | 1389 | 2.250777644883257e-05
11 | 1389 | 694 | 1389 | 542 | 0.0002978010745492113
12 | 542 | 1251 | 542 | 895 | 0.00015951582993150323
13 | 895 | 1815 | 895 | 1305 | 0.0001303909506021454
14 | 1305 | 1021 | 1305 | 753 | 3.9356066874244885e-05
15 | 753 | 1381 | 753 | 971 | 0.0002850072862639029
16 | 971 | 1382 | 976 | 971 | 0.001276712172995213
17 | 976 | 1388 | 977 | 976 | 0.0004267486614026622
18 | 977 | 1389 | 986 | 977 | 0.0006757336753520132
19 | 986 | 1404 | 906 | 986 | 0.0003707891314505199
20 | 906 | 1275 | 906 | 907 | 0.0001959266189093194
21 | 907 | 1277 | 907 | 908 | 9.052734394018332e-05
22 | 908 | 1921 | 908 | 1376 | 5.400925846418281e-05
23 | 1376 | 1279 | 1376 | 909 | 1.8504323815069496e-05
24 | 909 | 1057 | 909 | 773 | 6.840328939622445e-05
25 | 773 | 1069 | 773 | 781 | 0.000535513050350553
26 | 781 | 1071 | 781 | 784 | 0.00014276168953525706
27 | 784 | 1087 | 784 | 793 | 0.0004430493335842619
28 | 793 | 1682 | 793 | 1192 | 7.9895243915049e-05
29 | 1192 | 1111 | 1192 | 808 | 0.0005876979547862221
30 | 808 | 1125 | 808 | 816 | 0.00047564125136792903
31 | 816 | 51 | 816 | 49 | 3.10328360877585e-05
32 | 49 | 52 | 49 | 50 | 0.00028187114581170033

一応、QGISで調べて、ノード切れが発生していないことは確認しました。


新規に作ったノード182~413を、ちゃんと無視できるかの実験。ベースは以下のメモの内容。

pgr_dijkstra()で、ダイクストラの順番を壊さずにルートの座標を得る方法(getDijkstraPath())

■無視前

tomioka_db_c=# SELECT seq, source, target, x1, y1, x2, y2 FROM pgr_dijkstra('SELECT gid as id, source, target, cost, reverse_cost FROM ways',1036, 1320, directed := false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;
seq | source | target | x1 | y1 | x2 | y2
-----+--------+--------+-----------------+----------------+-----------------+----------------
1 | 1036 | 182 | 139.6295688 | 35.3660511 | 139.62956342765 | 35.36605302299
2 | 182 | 183 | 139.62956342765 | 35.36605302299 | 139.62952386387 | 35.36602637499
3 | 183 | 184 | 139.62952386387 | 35.36602637499 | 139.62949515388 | 35.36599335049
4 | 184 | 185 | 139.62949515388 | 35.36599335049 | 139.62949783814 | 35.3658805722
5 | 185 | 186 | 139.62949783814 | 35.3658805722 | 139.629505074 | 35.36583679324
6 | 186 | 187 | 139.629505074 | 35.36583679324 | 139.62955514143 | 35.36580196041
7 | 187 | 188 | 139.62955514143 | 35.36580196041 | 139.62972133265 | 35.36574533322
8 | 188 | 189 | 139.62972133265 | 35.36574533322 | 139.62969285571 | 35.3656615823
9 | 189 | 190 | 139.62969285571 | 35.3656615823 | 139.62929978548 | 35.36461811112
10 | 190 | 191 | 139.62929978548 | 35.36461811112 | 139.62923349573 | 35.3644776355
11 | 191 | 192 | 139.62923349573 | 35.3644776355 | 139.62887730502 | 35.36401128513
12 | 192 | 193 | 139.62887730502 | 35.36401128513 | 139.62881288258 | 35.36394808968
13 | 193 | 194 | 139.62881288258 | 35.36394808968 | 139.62878113819 | 35.36393552673
14 | 194 | 195 | 139.62878113819 | 35.36393552673 | 139.62874285819 | 35.36391763403
15 | 195 | 196 | 139.62874285819 | 35.36391763403 | 139.62711549003 | 35.36370406459
16 | 196 | 1320 | 139.62711549003 | 35.36370406459 | 139.6270944 | 35.3636816
(16 rows)

■無視後

tomioka_db_c=# SELECT seq, source, target, x1, y1, x2, y2 FROM pgr_dijkstra('SELECT gid as id, source, target, cost, reverse_cost FROM ways WHERE (source NOT BETWEEN 182 AND 413 AND target NOT BETWEEN 182 AND 413) AND (source NOT BETWEEN 182 AND 413 AND target NOT BETWEEN 182 AND 413)',1036, 1320, directed := false) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;
seq | source | target | x1 | y1 | x2 | y2
-----+--------+--------+-------------+------------+-------------+------------
1 | 1034 | 1036 | 139.6297237 | 35.365746 | 139.6295688 | 35.3660511
2 | 1034 | 1033 | 139.6297237 | 35.365746 | 139.6297007 | 35.3656671
3 | 1033 | 1325 | 139.6297007 | 35.3656671 | 139.6287884 | 35.3639297
4 | 1325 | 1320 | 139.6287884 | 35.3639297 | 139.6270944 | 35.3636816

うん、これを見ている限りは、大丈夫そうに見える。

 

2023,江端さんの技術メモ

■通常のバスルートを作ったが、表示ノードが停留所のみとなり、シミュレータが不自然になる問題の解決法
   → 強制的にタグを付ける

mapconfig_for_cars_rail_cart_bus.xml

の変更も忘れないこと。

Keyword : osm, tag, node, ダイクストラ、

 

2023,江端さんの技術メモ

QGISでノード番号のある場所を見つける方法が分からなくて困っていましたが、ようやく方法を見つけましたので、メモを残します。

この場合、180以下のノード番号が表示されていますが、特定の番号を指定したければ、(例えば、id=3)と入力すれば、そのノードだけが表示されます。

以上

2023,江端さんの技術メモ

SELECT seq, node, edge, b.cost
FROM pgr_dijkstra(
    'SELECT gid as id, source, target, cost, reverse_cost FROM ways WHERE source NOT BETWEEN 10 AND 20 AND target NOT BETWEEN 10 AND 20',
    1, 50, directed := false
) a
INNER JOIN ways b ON (a.edge = b.gid)
ORDER BY seq;

出力結果
seq | node | edge | cost
-----+------+------+------------------------
1 | 1 | 2 | 8.518550262944416e-06
2 | 2 | 3 | 9.420518456308501e-05
3 | 3 | 4 | 2.6662995399998606e-05
4 | 4 | 6 | 2.1389117484400878e-05
5 | 5 | 7 | 4.6563628817813256e-06
6 | 6 | 1313 | 7.188606587820858e-06
7 | 863 | 126 | 1.0007051975223507e-05
8 | 99 | 127 | 1.450451593740212e-05
9 | 100 | 129 | 7.160567611289415e-06
10 | 101 | 131 | 4.109420419283505e-05
11 | 102 | 133 | 2.934679929904221e-05
12 | 103 | 135 | 1.5514200871555155e-05
13 | 104 | 137 | 1.2955240951715268e-05
14 | 105 | 139 | 3.932409601088787e-05
15 | 106 | 141 | 3.756326743314803e-05
16 | 107 | 143 | 6.437495269868342e-05
17 | 108 | 145 | 3.580138401404371e-05
18 | 109 | 147 | 5.81727588604755e-05
19 | 110 | 148 | 4.310761927462597e-05
20 | 651 | 1196 | 0.00021148735186994806
21 | 780 | 995 | 0.00017553851429442523
22 | 653 | 997 | 5.381635439655622e-05
23 | 654 | 996 | 3.9727662820583996e-05
24 | 21 | 24 | 6.931684268013142e-06
25 | 22 | 25 | 7.70969814835397e-06
26 | 23 | 26 | 1.2029326750062135e-05
27 | 24 | 27 | 3.163056561909417e-05
28 | 25 | 28 | 3.715561627508799e-05
29 | 26 | 29 | 1.6759949788587843e-05
30 | 27 | 30 | 1.3935943447597369e-05
31 | 28 | 31 | 7.276956035534738e-06
32 | 29 | 32 | 1.2096545992840006e-05
33 | 30 | 33 | 4.534133154905821e-05
34 | 31 | 34 | 1.8836761764769703e-05
35 | 32 | 35 | 8.806681794688408e-06
36 | 33 | 36 | 7.526055852520615e-06
37 | 34 | 37 | 1.0243676427727028e-05
38 | 35 | 38 | 1.5622874238716658e-05
39 | 36 | 39 | 6.894091782961944e-06
40 | 37 | 40 | 1.786596350373829e-05
41 | 38 | 41 | 1.796453895498639e-05
42 | 39 | 42 | 6.566793603978039e-05
43 | 40 | 43 | 4.0144224056584715e-05
44 | 41 | 44 | 2.037304658526977e-05
45 | 42 | 45 | 1.643518634972223e-05
46 | 43 | 46 | 1.1916705412252495e-05
47 | 44 | 47 | 1.0031152210412222e-05
48 | 45 | 48 | 1.1949163674231717e-05
49 | 46 | 49 | 1.7529822253810993e-05
50 | 47 | 50 | 1.9115799546536715e-05
51 | 48 | 51 | 5.101757589403705e-05
52 | 49 | 53 | 2.8187114581170035e-05

2023,江端さんの技術メモ

送信プログラム(send_data.c):

#include <stdio.h>
#include <stdint.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    uint32_t data = 0x12345678; // 4バイトのデータ(0x12345678)

    // ソケットの作成
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        return 1;
    }

    // 送信先サーバの情報を設定
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345); // 送信先ポート番号
    server_addr.sin_addr.s_addr = INADDR_LOOPBACK; // ループバックアドレス (127.0.0.1)
    # INADDR_LOOPBACK で動かなければ、INADDR_ANY を使う

    // データを送信
    if (sendto(sockfd, &data, sizeof(uint32_t), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("sendto");
        close(sockfd);
        return 1;
    }

    printf("Data sent: 0x%X\n", data);

    close(sockfd);

    return 0;
}

受信プログラム(receive_data.c):

#include <stdio.h>
#include <stdint.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    socklen_t client_addr_size = sizeof(client_addr);
    uint32_t received_data;

    // ソケットの作成
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        return 1;
    }

    // サーバの情報を設定
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345); // 受信ポート番号
    server_addr.sin_addr.s_addr = INADDR_ANY;

    // ソケットとポートを結びつける
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        close(sockfd);
        return 1;
    }

    printf("UDP Server is waiting for messages...\n");

    while (1) {
        // データを受信
        if (recvfrom(sockfd, &received_data, sizeof(uint32_t), 0, (struct sockaddr *)&client_addr, &client_addr_size) == -1) {
            perror("recvfrom");
            close(sockfd);
            return 1;
        }

        printf("Received Data: 0x%X\n", received_data);
    }

    close(sockfd);

    return 0;
}

2023,江端さんの技術メモ

■ダイクストラ計算を使った方法(一般的なやりかた)
tomioka_db_b=# SELECT seq, node, edge, b.cost FROM pgr_dijkstra('SELECT gid as id, source, target, cost, reverse_cost FROM ways',1, 11) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;
seq | node | edge | cost
-----+------+------+------------------------
1 | 1 | 2 | 8.518550262944416e-06
2 | 2 | 3 | 9.420518456308501e-05
3 | 3 | 4 | 2.6662995399998606e-05
4 | 4 | 6 | 2.1389117484400878e-05
5 | 5 | 7 | 4.6563628817813256e-06
6 | 6 | 8 | 1.3184236987589488e-05
7 | 7 | 9 | 6.438782425766514e-06
8 | 8 | 10 | 3.92599380897713e-05
9 | 9 | 11 | 3.1320245670872654e-05
10 | 10 | 12 | 1.7193010226696205e-05

■ところが、こうすると、2番目の最短距離が算出できます。

tomioka_db_b=# SELECT seq, node, edge, b.cost FROM pgr_ksp('SELECT gid as id, source, target, cost, reverse_cost FROM ways',1, 11, 2) a INNER JOIN ways b ON (a.edge = b.gid) ORDER BY seq;
seq | node | edge | cost
-----+------+------+------------------------
1 | 1 | 2 | 8.518550262944416e-06
2 | 2 | 3 | 9.420518456308501e-05
3 | 3 | 4 | 2.6662995399998606e-05
4 | 4 | 6 | 2.1389117484400878e-05
5 | 5 | 7 | 4.6563628817813256e-06
6 | 6 | 8 | 1.3184236987589488e-05
7 | 7 | 9 | 6.438782425766514e-06
8 | 8 | 10 | 3.92599380897713e-05
9 | 9 | 11 | 3.1320245670872654e-05
10 | 10 | 12 | 1.7193010226696205e-05
12 | 1 | 2 | 8.518550262944416e-06
13 | 2 | 1214 | 7.368115779153013e-06
14 | 792 | 118 | 8.976775615866592e-06
15 | 95 | 119 | 9.423341104506603e-05
16 | 96 | 121 | 2.578196166482512e-05
17 | 97 | 123 | 2.35136729002621e-05
18 | 98 | 125 | 6.587696385101331e-06
19 | 99 | 126 | 1.0007051975223507e-05
20 | 863 | 1313 | 7.188606587820858e-06
21 | 6 | 8 | 1.3184236987589488e-05
22 | 7 | 9 | 6.438782425766514e-06
23 | 8 | 10 | 3.92599380897713e-05
24 | 9 | 11 | 3.1320245670872654e-05
25 | 10 | 12 | 1.7193010226696205e-05

10番目までを出したかったら、上記の"2"を、"10"にすれば出てきます。
綺麗に直す方法については、がんばって下さい。

 

 

 

2023,江端さんの忘備録

メンタルヘルスに対する研究や理解は、日々進んでいると思います。

I believe that research and understanding of mental health is advancing every day.

もちろん、まだまだ十分ではないことは分かっています。

Of course, I know that it is still not enough.

メンタル疾患が誰にでも簡単に発生することは、「自分」で理解しています。

I understand that mental illness can quickly occur in anyone.

加えて、私は、メンタル疾患の被害者でもありますが、加害者でもあったという自覚もあります。

In addition, I am aware that I have been both a victim and a perpetrator of mental illness.

私なら、『今でも報復を諦めていない』くらいのことは言うと思う。

現在のメンタルヘルス研究は、『加害者としての自己』という観点がスッポリ抜けているような気がします。

I feel that current mental health research is missing the perspective of 'self as perpetrator.'

-----

私、最近、

I recently, want someone to try

―― 歴史上の人物(特に日本史)における、特に戦国武将のメンタル疾患についての研究

"Research on mental illness in historical figures (especially Japanese history), especially warlords of the Warring States period"

を、誰かにやってもらいたいと思っています。

一応、Google Scholarで調べてみたのですが、ドンピシャと思われる研究論文は見つけられませんでした。

In the meantime, I checked Google Scholar but could not find any research papers that seemed to be downloadable.

-----

YouTubeで、大河ドラマのビデオクリップを見ているのですが、戦国武将の日常は、殺戮と裏切りと身内の粛清のオンパレードです。

I have been watching video clips of the Taiga drama on YouTube, and the daily life of the warlords was a parade of carnage, betrayal, and purges of their team.

そんな状態で、「武士道」だの「武人の誉れ」などと、綺麗ごとを言えるメンタルが、全然理解できません。

In such a state, I cannot understand the mentality of having said beautiful words such as "bushido" and "honor of the warrior."

ダブルスタンダードもいいところです。

That was typical double standards.

戦国武将は、多重人格障害をデフォルトで持っているとしか思えないです。

I can only assume that warlords have dissociative identity disorder by default.

私は、日本でもっとも著名な戦国武将について『双極性障害』であったと決めつけていますが、他の戦国武将はどうだったのかなぁ、と興味があります。

I have determined that the most famous warlord in Japan was "bipolar," but I am curious to know what other warlords were like.

―― 何やってんだろうなあ、桶狭間合戦場跡は

-----

限られた歴史文献だけを使って、戦国武将たちのメンタルを推定する、というのは、相当難しい研究だとは思います。

I think it is quite a problematic study to estimate the mentality of warlords using only limited historical documents.

しかし、その研究は、現在の私たちのメンタル疾患の治療法に寄与する、と思っています。

However, I believe the research contributes to treating our mental illnesses.

2023,江端さんの技術メモ

package main
/*

f:\しゅらばしゅう\有吉先生データ\Transfer(2018)\N07-11_14_GML>go run nearest_node3.go 

golangで、以下のbus_stop_modified.csvというファイル名から読み取った位置情報ごとに、
以下のtsuzuki_bus.osmファイルのnodeに記載された位置情報と50メートル以内のnodeと
その距離を算出するプログラムを作って下さい。

[bus_stop_modified.csv]
35.522547,139.590950
35.522547,139.590950
35.564881,139.580736
35.566768,139.583192
35.569075,139.584080

[tsuzuki_bus.osm]
<?xml version='1.0' encoding='UTF-8'?>
<osm version='0.6' generator='JOSM'>
<node id='200000' visible='true' version='1' lat='35.568239' lon='139.552822' />
<node id='200001' visible='true' version='1' lat='35.568164' lon='139.5528' />
<node id='200002' visible='true' version='1' lat='35.568321' lon='139.551491' />
<node id='200003' visible='true' version='1' lat='35.568338' lon='139.55136' />
<node id='200004' visible='true' version='1' lat='35.568355' lon='139.551264' />
</osm>

*/
import (
"encoding/csv"
"encoding/xml"
"fmt"
"math"
"os"
"strconv"
)


type Node struct {
XMLName xml.Name `xml:"node"`
ID      string   `xml:"id,attr"`
Lat     string   `xml:"lat,attr"`
Lon     string   `xml:"lon,attr"`
}


func haversine(lat1, lon1, lat2, lon2 float64) float64 {
radius := 6371.0 // Earth's radius in kilometers
latRad1 := lat1 * (math.Pi / 180)
latRad2 := lat2 * (math.Pi / 180)
deltaLat := (lat2 - lat1) * (math.Pi / 180)
deltaLon := (lon2 - lon1) * (math.Pi / 180)


a := math.Sin(deltaLat/2)*math.Sin(deltaLat/2) +
math.Cos(latRad1)*math.Cos(latRad2)*
math.Sin(deltaLon/2)*math.Sin(deltaLon/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))


distance := radius * c
return distance
}


func main() {
// Read CSV file
csvFile, err := os.Open("bus_stop_modified.csv")
if err != nil {
fmt.Println("Error opening CSV file:", err)
return
}
defer csvFile.Close()


csvReader := csv.NewReader(csvFile)
positions, err := csvReader.ReadAll()
if err != nil {
fmt.Println("Error reading CSV:", err)
return
}


// Read OSM file
xmlFile, err := os.Open("tsuzuki_bus.osm")
if err != nil {
fmt.Println("Error opening OSM file:", err)
return
}
defer xmlFile.Close()


var nodes struct {
XMLName xml.Name `xml:"osm"`
Nodes   []Node   `xml:"node"`
}


// Parse OSM XML
decoder := xml.NewDecoder(xmlFile)
err = decoder.Decode(&nodes)
if err != nil {
fmt.Println("Error decoding OSM XML:", err)
return
}


// Find nodes within 50 meters for each position
for _, position := range positions {
lat, _ := strconv.ParseFloat(position[0], 64)
lon, _ := strconv.ParseFloat(position[1], 64)


fmt.Printf("For Position (%s, %s):\n", position[0], position[1])


for _, node := range nodes.Nodes {
nodeLat, _ := strconv.ParseFloat(node.Lat, 64)
nodeLon, _ := strconv.ParseFloat(node.Lon, 64)


dist := haversine(lat, lon, nodeLat, nodeLon)
if dist <= 0.05 { // 50 meters in kilometers
fmt.Printf("Node ID: %s\n", node.ID)
fmt.Printf("Node Coordinates: %s, %s\n", node.Lat, node.Lon)
fmt.Printf("Distance to Node: %.2f km\n", dist)
}
}
fmt.Println("--------------------------")
}
}

出力結果

go run nearest_node3.go
For Position (35.522547, 139.590950):
Node ID: 216067
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 216068
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
Node ID: 253004
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 253005
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
Node ID: 287056
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
Node ID: 287057
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 335005
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 335006
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
Node ID: 350106
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
Node ID: 350107
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 351568
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 351569
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
--------------------------
For Position (35.522547, 139.590950):
Node ID: 216067
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km
Node ID: 216068
Node Coordinates: 35.522885, 139.591253
Distance to Node: 0.05 km
Node ID: 253004
Node Coordinates: 35.522356, 139.591082
Distance to Node: 0.02 km

2023,江端さんの技術メモ

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: 神明社前