2023,江端さんの技術メモ

最近、映像制御の仕事をすることになりました。

WSLを使って、作業効率をはかりたいと考えていますが、WSLは基本的にコマンドインターフェースなので、表示システムを作らなければなりません。

「Windows11にWSL2+Ubuntu20.04をインストールする」を試してみて、Golangをインストールしてみた件

すったもんだしているのですが、とりあえず、Windows10の方にX-Windowの方に、X serverを立てて表示ができたので、メモを残しておきます。

(というか、『Windows10上で、X-Windowsのサーバ動かす』という発想ができなかったので、

(gedit:5386): Gtk-WARNING **: cannot open display やらで、悩んでいました。

基本は、

Windows10のWSLでX11アプリケーションを実行してみた

の通りに実施したら動きました(実は、ここまで、手当たりしだい "sudo apt-get install" を乱発して

WSLの方から、

>export DISPLAY=:0

>gedit dummy.txt

 

と投入したら、X-windowsのエディタが立ち上がってきましたが、

など、たくさん問題が出ているようなので、対応を続けます(続く)

ところで、

WSLでGUIアプリを実行する

などで、自分の「上手くできなかったことを、きちんと書き残している方」のメモは本当に素晴しい。こういうメモは、普通の成功パターンしか記載していないメモの何十倍も役に立つのです。

で、まあ、それはさておき。


本命はこちら ――

GStreamer

です。

私、映像の伝送の研究は色々やってきたのですが(10~15年前)、映像そのものの研究は初めてなので、まずは、ローカルのパソコンで色々遊ぶ・・・もとい、調査することにしました。

で、今の私、GStreamerが何なのかも分かっていないのですが、「これを使え」と指示されているので、「これに突っ込んでいく」だけです。

『ほとんどの入門書は、入門者にとっては、ただの"ゴミ"』

マルチメディアフレームワークGStreamer ~ 入門編

を参考にさせて頂き、

$ export DISPLAY=:0

$ gst-launch-1.0 videotestsrc ! autovideosink

で、これが出てきました。

おお! やった!

WSLの方はこんな感じです。

$ gst-launch-1.0 filesrc location=./out.h264 ! avdev_h264 ! autovideosink

も、ちゃんと表示されるようです。映像の違いは分かりませんが。

カーネルコンパイルしたら表示されなくなりました(それが理由かは分かりません)。

$ gst-launch-1.0 -v videotestsrc ! x264enc ! avdec_h264 ! videoconvert ! autovideosink

で、表示できました。

(とりあえず、error: XDG_RUNTIME_DIR not set in the environment. だけでも潰しておこう)

ともあれ、最初の一歩は確保しました。

エラーコメントの表示対応のため、以下の設定をしておきました。

$ cd ~
$ vi .bash_profile

以下の2行を追加(正直、上の設定の意味は分からんが、とりあえずエラーは消える)。

export XDG_RUNTIME_DIR=/tmp/runtime-futa
export DISPLAY=:0


GStreamerによるレートコントロールについて調べています。

ラズパイにWEBカメラを接続してGStreamerを使った際に小一時間ハマった話

こちらに、

そして、例えば、任意のサイズやフレームレートでキャプチャを行いたい場合は、video/x-raw,width=1280,height=720,framerate=30/1 のような指定を行います。

というような記載がありました。

$ gst-launch-1.0 videotestsrc ! autovideosink

をちょっと変更して試してみました。

$ gst-launch-1.0 videotestsrc ! videoconvert ! video/x-raw,width=1280,height=720,framerate=30/1 ! autovideosink

画面がでっかくなって表示されました。

$ gst-launch-1.0 videotestsrc ! videoconvert ! video/x-raw,width=1280,height=720,framerate=1/1 ! autovideosink

これで、1fpsの表示になりました。

で、実際に映像ファイル(start_up.mp4)を持ち込んで表示してみました。

$gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=30/1 ! autovideosink

これを、1fpsの表示に変えてみます。

$gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=1/1 ! autovideosink

これを、1fpsのmp4ファイルとして保存してみます。

■1ftp映像に変換したもの "1ftp.mp4"$ gst-launch-1.0 -e filesrc location=start_up.mp4 ! decodebin ! videoconvert ! videoscale ! videorate ! "video/x-raw,framerate=1/1" ! videoconvert ! x264enc bitrate=2000 ! mp4mux ! filesink location=1ftp.mp4

上記のコマンドでは、GStreamerのgst-launch-1.0ユーティリティを使用しています。filesrcエレメントを使用して入力ファイルを読み込み、decodebinエレメントを使用してデコードします。その後、videoconvertvideoscaleエレメントを使用して動画の形式を変換し、videorateエレメントを使用してフレームレートを変更します。最後に、x264encエレメントを使用してビットレートを設定し、mp4muxエレメントを使用して新しいmp4ファイルに変換します。


ひき続き、SRTの通信実験を行ってみます。

(2)映像転送プロトコルは、現在、SRTが有力候補

     (a)タイムスタンプが付与した再送機能付きUDP(と理解)

     (b)Gstreamerに標準装備されている(らしい)

で、高信頼の映像通信を実現するプロトコルのようです。

GStreamer で SRT を使用する その1

の内容をマネします。

私の場合、新規の設定をしないでも以下のコマンドが動きましたので、どっかで設定を終えてしまったのだと思います。

$ gst-launch-1.0 videotestsrc ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500

で、SRT の配信には、srtserversink を使用しているようです。

で、受信側は、VLCメディアプレーヤを用います。

※WSL2にしてカーネルコンパイルした後、

C:\Users\ebata>ipconfig

(中略)

Windows IP 構成

イーサネット アダプター vEthernet (WSL):

接続固有の DNS サフィックス . . . . .:
リンクローカル IPv6 アドレス. . . . .: fe80::c317:ce40:f52f:1a41%40
IPv4 アドレス . . . . . . . . . . . .: 172.22.144.1
サブネット マスク . . . . . . . . . .: 255.255.240.0
デフォルト ゲートウェイ . . . . . . .:

しか使えなくなってしまったので、上記のVLCのアドレスは、

とする必要が生じました。

これで、「再生(P)ボタン」を押すと、テスト映像が表示されます。


次にWebRTCの実験を行います。

ここでは、

Go + GStreamer でお手軽 WebRTC 体験

を試させて頂きました。

GOのソースは一つだけだったので、WSL環境から行ってみました(最初、エラーの嵐だったのですが、よく考えれば、私はWSLの方にGStremaerの環境を立てていたので当然でした。

結構エラーが出てきましたので、色々対応をしていました。

sudo apt-get install libgstreamer-plugins-base1.0-dev

で、一部解決したのですが、以下のエラーが取れません。
# pkg-config --cflags -- gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-plugins-base-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-plugins-bad-1.0 Package gstreamer-plugins-bad-1.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gstreamer-plugins-bad-1.0.pc' to the PKG_CONFIG_PATH environment variable
No package 'gstreamer-plugins-bad-1.0' found pkg-config: exit status 1

で、

https://github.com/notedit/gstreamer-go

に訪問してみたところ、

$ sudo apt-get install libgstreamer-plugins-bad1.0-dev

が、当たりだったようです。

で、後は上記のページの記載通りにGOプログラムを動かしたのですが、

2023/05/25 17:57:31 peer state change: failed

が登場してきて、変だなーと思ていたのですが、実はこれ成功しています。

このメッセージの上に、Goの出力の「長い文字列」が主力されていました。

これを入力して、「start session」ボタンを押下したら、以下の画面がブラウザに表示されました。

では、動作も確認できたので、ここからコードの勉強に入りましょう。


WebRTC を今から学ぶ人に向けて

の中にある、

WebRTC コトハジメ

が分かりやすい。

好奇心旺盛な人のためのWebRTC

も良い。

私はGolang使いなので、https://github.com/pion/webrtcを使いこなしたいが、膨大で手が出ない状況。今、とっかかりを探している。

とりあえず、wsl -d Ubuntu-20.04で、
ebata@DESKTOP-P6KREM0:/mnt/c/users/ebata/から、
get clone https://github.com/pion/webrtc で、インストール。

https://github.com/pion/webrtc/blob/master/examples/README.md

から、

$ cd webrtc
$ cd examples
$ go run examples.go --address :8080

で、ブラウザ http://localhost:8080で以下の画面が出てくる。

で、

のところで、"Run JavaScript"を押して、暫く(2~3分)待っていると、

という漢字で文字列が出てくるので、これを、上記のGo + GStreamer でお手軽 WebRTC 体験 のプログラムに放り込んで、同じように得られた文字列を放り込むと、

てな感じで映像が表示される。


$git clone https://github.com/pion/rtwatch.git

に挑戦。

https://github.com/pion/rtwatch の内容通りに設定するが、実行のところだけ少し違った

ebata@DESKTOP-P6KREM0:/mnt/c/users/ebata/rtwatch$ go run main.go -container-path=start_up.mp4
Video file 'start_up.mp4' is now available on ':8080', have fun!

これで、複数の、http://localhost:8080/ から同期した映像が配信されるようすが分かる。

2023,江端さんの技術メモ

FASTAPIを使ってPOSTでファイルを送り込む方法

 main.py

import uvicorn
from fastapi import FastAPI, File, UploadFile

import shutil
import os

app = FastAPI()

@app.post("/files/")
async def file(file: bytes = File(...)):
    content = file.decode('utf-8')
    formatfile = content.split('\n')
    return {'filedetail': formatfile}

@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    if file:
        filename = file.filename
        fileobj = file.file
        #UPLOAD_DIR = os.getcwd() 
        #print(UPLOAD_DIR)
        #upload_dir = open(os.path.join(UPLOAD_DIR, filename),'wb+')
        upload_dir = open(os.path.join("C:\\Users\\ebata\\fastapi6\\", filename),'wb+')
        shutil.copyfileobj(fileobj, upload_dir)
        upload_dir.close()
        return {"アップロードファイル名": filename}
    return {"Error": "アップロードファイルが見つかりません。"}



'''
@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    return {'filename': file.filename}
'''

で、

> uvicorn main:app --reload

でAPIサーバを起動する。

request.py

import requests
import json

# curl -X POST http://127.0.0.1:8000/uploadfile/ -H 'accept: application/json' -H 'Content-Type: multipart/form-data' -F file=@dummy.txt;type=text/plain と同じ機能を実現
# C:\Users\ebata>curl -X POST http://127.0.0.1:8000/uploadfile/  -F file=@dummy.txt;type=text/plain とすれば、エラーメッセージは出てこない

url = 'http://localhost:8000/uploadfile/'

# headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} //失敗
# headers = {'Accept': 'application/json', 'Content-Type': 'text/html'} # 失敗
headers = {'Accept': 'application/json'} # 成功

# file_payload = {'file=@dummy.txt;type=text/plain'} # 失敗
file_payload = {'file':open('data/dummy1.csv','rb')} # 成功  ファイルはdataというフォルダを掘って、dummy1.csv という名前のファイルを放り込んでおく

print("headers:",headers)
print("payload:",file_payload)

# r = requests.post('http://localhost:8000/uploadfile/', headers=headers,files=file_payload) # 成功
r = requests.post(url, headers=headers,files=file_payload) # 成功

print("--->1:", r.url)
print("--->2:",r.status_code)
print("--->3:",r.text)
print("--->4:",r.json())

>python requests.py

でクライアント起動。

以上

2023,江端さんの技術メモ

> uvicorn main:app --reload

main.py

import uvicorn
from fastapi import FastAPI, File, UploadFile

import shutil
import os

app = FastAPI()

@app.post("/files/")
async def file(file: bytes = File(...)):
    content = file.decode('utf-8')
    formatfile = content.split('\n')
    return {'filedetail': formatfile}

@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    if file:
        filename = file.filename
        fileobj = file.file
        #UPLOAD_DIR = os.getcwd() 
        #print(UPLOAD_DIR)
        #upload_dir = open(os.path.join(UPLOAD_DIR, filename),'wb+')
        upload_dir = open(os.path.join("C:\\Users\\ebata\\fastapi6\\", filename),'wb+')
        shutil.copyfileobj(fileobj, upload_dir)
        upload_dir.close()
        return {"アップロードファイル名": filename}
    return {"Error": "アップロードファイルが見つかりません。"}



'''
@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    return {'filename': file.filename}
'''

クライアントは、こうなる。

前提は、C:\Users\ebata に dummy.txtがあること。
そして上記のmain.pyは、C:\Users\ebata\fastapi6にあること(まあ、そのへんは適当に変えて使って下さい)

 

C:\Users\ebata>curl -X POST http://127.0.0.1:8000/uploadfile/ -H 'accept: application/json' -H 'Content-Type: multipart/form-data' -F file=@dummy.txt;type=text/plain

クライアントプログラムは作成中

2023,江端さんの技術メモ

https://teratail.com/questions/8xzab7sat8gujj#reply-3jfh5txotuqxqb

の質問サイトに投げたものですが、ローカルでも作っておきます。

実現したいこと

TLS対応にしているGo言語のサーバを、Dockerコンテナの中から使えるようにしたい

前提

GO言語を使ってサーバを作っています。これらのサーバをDockerコンテナに格納して、運用しやすくしたいと考えております。

発生している問題・エラーメッセージ

Dockerコンテナに格納すると、https(×http)通信が使えません。

cert.pem、key.pemを使わない場合、http://127.0.0.1:18888で、ブラウザに"hello"メッセージがされますが、cert.pem、key.pemを使ってhttps://127.0.0.1:18888とした場合、「このサイトにアクセスできません」と表示されます。

該当のソースコード

GO言語

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
)

var url_host string

func handler(w http.ResponseWriter, r *http.Request) {
	dump, err := httputil.DumpRequest(r, true)
	if err != nil {
		http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
		return
	}
	fmt.Println(string(dump))
	fmt.Fprintf(w, "<html><body>hello</body></html>\n")
}

var addr = flag.String("addr", "127.0.0.1:18888", "http service address") // テスト

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("url_host:", url_host)

	log.Println("start http listening :18888")

	var httpErr error
	if _, err := os.Stat("./cert.pem"); err == nil {
		if httpErr = http.ListenAndServeTLS(*addr, "./cert.pem", "./key.pem", nil); httpErr != nil {
			log.Fatal("No pem file with https error: ", httpErr.Error())
		}
	}
}

ちなみに、cert.pemと、key.pemは、"127.0.0.1","localhost"で通るように作ってあります。

ローカルネットワークにおける「オレオレ証明書」の作り方 "http: TLS handshake error from 192.168.0.22:59914: remote error: tls: unknown certificate"のエラーを、ようやく消せました

Dockerfile
#FROM golang:apline
FROM golang:1.16.3-alpine
WORKDIR /go
ADD . /go
CMD ["go", "run", "main.go"]

docker-compose.yml

version: '3'
services:
  app:
    build: .
    ports:
      - "18888:18888" # "ホストのポート:コンテナのポート"

試したこと

上記のmain.go のfunc main()を以下のようにしている場合は,http(×https)で通信できます。

func main() {
    var httpServer http.Server
    http.HandleFunc("/", handler)
    log.Println("start http listening :18888")
    httpServer.Addr = ":18888"
    log.Println(httpServer.ListenAndServe())
}

補足情報(FW/ツールのバージョンなど)

■Windows10上のDocker for Windowsを使用しています。
■Dockerコンテナを使わないで、 windowsのコマンドプロンプトから起動する場合は、"https://127.0.0.1:18888"は問題なく起動します。

で、頂いたご回答が以下の通り。

Dockerfile

#FROM golang:apline
FROM golang:1.16.3-alpine
WORKDIR /app
ADD . /app
CMD ["go", "run", "main.go", "-addr", ":18888"]

と最後の一行を、CMD ["go", "run", "main.go", "-addr", ":18888"]

とするだけでした。

で、以外な盲点が、

ブラウザのキャッシュを消去しないと、変更がブラウザに反映されない

だったりします。(何度も経験しているのに、これをよく忘れるんだよなぁ)

感想

散々、色々試したあげく、最初に頂いた、Dockerfileの内容に変更することで、無事問題を解決することができました。現在、Dockerの中で立ち上げたgoのサーバに対して、https://localhost:18888で表示されることを確認しました。

今後のサーバ立ち上げに関して、かなり有益な知見となりました(実サーバ運用では、ご指摘の内容を反映してリスクを回避したいと思います)。 この度は、誠にありがとうございました。

以上

2023,江端さんの技術メモ

cert.pem やら key.pem に、localhost や 127.0.0.1を含めて作っていなかったから。以上

C:\Users\ebata\kitaya>curl https://localhost:8080
curl: (35) schannel: next InitializeSecurityContext failed: Unknown error (0x80092012) - 失効の関数は証明書の失効を確認できませんでした。

cert.pem = fullchain.pem  key.pem = privkey.pem ということで良いのだろう

ローカルネットワークにおける「オレオレ証明書」の作り方 "http: TLS handshake error from 192.168.0.22:59914: remote error: tls: unknown certificate"のエラーを、ようやく消せました

2023,江端さんの技術メモ

    // C:\Users\ebata\yoko_bus_route\others>go run test2.go
    バスルート情報(LINESTRING)に幅を当与えてPOLYGONにして、データベースに格納する方法

 

    (Step.1)テーブルの作成
    CREATE TABLE bus_route(name varchar(50), geom geometry(POLYGON,4326) );

 

    (Step.2)以下でエントリーを追加できることを確認
    INSERT INTO bus_route(name, geom) VALUES('test2', ST_Buffer(st_setsrid(ST_GeomFromtext('linestring(139.595873 35.378154,139.595779 35.37812,139.595766 35.378045,139.595922 35.377752,139.596212 35.377193)'),4326),0.0001,'endcap=round join=round'));

 

    route_db=# select * from bus_route;
    name  |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                geom
    ------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    test1 | 0103000020E61000000100000031000000EC55D36C11736140FEFA05EA63B04140F87A208412736140B5B6AEB75BB04140C96A2B8512736140A12BBFAF5BB041404BFB57E514736140AACF835E49B04140E6839BF41473614026E3D2C548B04140BE7F21FC1473614016C2272448B041401EEB9FFB147361406DE8B87F47B04140D5C01BF314736140A104D8DE46B0414036C9E8E21473614005CDB34746B04140DB61A6CB147361402D2D1BC045B04140CF5D39AE14736140AF21444D45B04140673AC38B147361407C7498F344B0414046FF96651473614010528AB644B0414002372C3D14736140B062729844B0414098801014147361402FB5789A44B04140A547D8EB13736140535E89BC44B04140BE390FC613736140D03C55FD44B04140C71129A4137361403DDA5E5A45B04140E84E7387137361406CEA12D045B041409B630871137361400C78EB5946B0414084EF5F1111736140ED342CA758B041402CE6BECA0F73614067FE133D62B04140F2C8AEB90F736140BD9C67E862B04140C33964B20F736140124B819E63B04140E26F39B50F736140B5E0935664B0414047C27CD00F736140C026B9CB66B0414071B186DC0F736140AD16347567B041404E3A26F10F736140171FE31068B041401A76720D10736140BA15E89768B041405CD22B30107361400A2E4E0469B04140E229CA5710736140113D4D5169B041408307EC1C11736140BDAE836E6AB041401240C444117361402E7E05976AB041403D3DD26D117361405331A89F6AB041406B1A82961173614073D316886AB04140009143BD117361406E4039516AB04140435A99E011736140BD3B2BFD69B0414055D627FF1173614044B2278F69B041401B68C217127361401BF3680B69B04140A802772912736140D717FF7668B0414084769733127361409F359ED767B041404D23C03512736140F240663367B04140D5CBDB2F127361403ACCA69066B041401467242212736140E5F1A0F565B04140E8E5200D12736140D9CC496865B041408A03A0F11173614090DC0FEE64B04140BF53B0D0117361407895A58B64B04140EFDC95AB11736140452BD34464B04140EC55D36C11736140FEFA05EA63B04140
    SQLのコマンド画面からは、上記の"INSERT INTO bus_route...."でエントリーできるのですが、これをプログラム(ins.Exec())を使うと、
    どうしても、
    Exec Error: pq: parse error - invalid geometry
    というエラーが出てきて、これを消すことができないです。
    そこで、まず、"selectで"0103000020E6100000010....."を受けとってから、これを、ins.Exec()を使ってエントリーすることにしました(原因はよく分かっていません)
/*
	// C:\Users\ebata\yoko_bus_route\others>go run test2.go

	バスルート情報(LINESTRING)に幅を当与えてPOLYGONにして、データベースに格納する方法

	テーブルの作成
	CREATE TABLE bus_route(name varchar(50), geom geometry(POLYGON,4326) );

	以下でエントリーを追加できることを確認
	INSERT INTO bus_route(name, geom) VALUES('test2', ST_Buffer(st_setsrid(ST_GeomFromtext('linestring(139.595873 35.378154,139.595779 35.37812,139.595766 35.378045,139.595922 35.377752,139.596212 35.377193)'),4326),0.0001,'endcap=round join=round'));

	route_db=# select * from bus_route;
 	name  |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                geom
	------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 	test1 | 0103000020E61000000100000031000000EC55D36C11736140FEFA05EA63B04140F87A208412736140B5B6AEB75BB04140C96A2B8512736140A12BBFAF5BB041404BFB57E514736140AACF835E49B04140E6839BF41473614026E3D2C548B04140BE7F21FC1473614016C2272448B041401EEB9FFB147361406DE8B87F47B04140D5C01BF314736140A104D8DE46B0414036C9E8E21473614005CDB34746B04140DB61A6CB147361402D2D1BC045B04140CF5D39AE14736140AF21444D45B04140673AC38B147361407C7498F344B0414046FF96651473614010528AB644B0414002372C3D14736140B062729844B0414098801014147361402FB5789A44B04140A547D8EB13736140535E89BC44B04140BE390FC613736140D03C55FD44B04140C71129A4137361403DDA5E5A45B04140E84E7387137361406CEA12D045B041409B630871137361400C78EB5946B0414084EF5F1111736140ED342CA758B041402CE6BECA0F73614067FE133D62B04140F2C8AEB90F736140BD9C67E862B04140C33964B20F736140124B819E63B04140E26F39B50F736140B5E0935664B0414047C27CD00F736140C026B9CB66B0414071B186DC0F736140AD16347567B041404E3A26F10F736140171FE31068B041401A76720D10736140BA15E89768B041405CD22B30107361400A2E4E0469B04140E229CA5710736140113D4D5169B041408307EC1C11736140BDAE836E6AB041401240C444117361402E7E05976AB041403D3DD26D117361405331A89F6AB041406B1A82961173614073D316886AB04140009143BD117361406E4039516AB04140435A99E011736140BD3B2BFD69B0414055D627FF1173614044B2278F69B041401B68C217127361401BF3680B69B04140A802772912736140D717FF7668B0414084769733127361409F359ED767B041404D23C03512736140F240663367B04140D5CBDB2F127361403ACCA69066B041401467242212736140E5F1A0F565B04140E8E5200D12736140D9CC496865B041408A03A0F11173614090DC0FEE64B04140BF53B0D0117361407895A58B64B04140EFDC95AB11736140452BD34464B04140EC55D36C11736140FEFA05EA63B04140

	SQLのインタースを使うと、上記の"INSERT INTO bus_route...."でエントリーできるのですが、これをプログラム(ins.Exec())を使うと、
	どうしても、
	Exec Error: pq: parse error - invalid geometry
	というエラーが出てきて、これを消すことができないです。

	そこで、まず、"selectで"0103000020E6100000010....."を受けとってから、これを、ins.Exec()を使ってエントリーすることにしました(原因はよく分かっていません)
*/

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/lib/pq" // ←これを追記
)

func main() {

	db, err := sql.Open("postgres",
		"user=postgres password=password host=192.168.0.23 port=15432 dbname=route_db sslmode=disable")
	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer db.Close()

	str := "select ST_Buffer(st_setsrid(ST_GeomFromtext('linestring(139.595873 35.378154,139.595779 35.37812,139.595766 35.378045,139.595922 35.377752,139.596212 35.377193)'),4326),0.0001,'endcap=round join=round')"

	rows, err := db.Query(str)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	var ret_str string
	for rows.Next() {
		if err := rows.Scan(&ret_str); err != nil {
			fmt.Println(err)
		}
		fmt.Println(ret_str)
	}

	ins, err := db.Prepare("insert into bus_route (name, geom) VALUES($1, $2)")
	if err != nil {
		log.Fatal("db.Prepare Error: ", err)
	}

	a := "test2"
	_, err = ins.Exec(a, ret_str)
	if err != nil {
		log.Fatal("ins.Exec Error: ", err)
	}

}

ちなみに

route_db=# SELECT name, ST_AsText(geom) from bus_route;

とすると、ちゃんとポリゴンで表示されます。

test2 | POLYGON((139.595877087369 35.378049137993,139.596010268629 35.3777989962668,139.596010765838 35.3777980502557,139.596300765838 35.3772390502557,139.596308044186 35.3772208480571,139.596311631611 35.3772015756733,139.596311390248 35.3771819737311,139.596307329374 35.3771627955223,139.596299605045 35.3771447780546,139.596288514104 35.3771286137292,139.596274482769 35.3771149237322,139.596258050256 35.3771042341623,139.596239848057 35.3770969558137,139.596220575673 35.3770933683894,139.596200973731 35.377093609752,139.596181795522 35.3770976706261,139.596163778055 35.3771053949546,139.596147613729 35.3771164858958,139.596133923732 35.3771305172312,139.596123234162 35.3771469497443,139.595833480238 35.3777054754117,139.595677731371 35.3779980037332,139.595669595124 35.3780184274596,139.595666118386 35.378040135509,139.595667469198 35.3780620786724,139.595680469198 35.3781370786724,139.595686209748 35.3781572822894,139.595696043647 35.3781758412353,139.595709537084 35.3781919368007,139.595726094808 35.3782048589456,139.595744986392 35.3782140376226,139.595838986392 35.3782480376226,139.595857985784 35.3782528664418,139.595877562164 35.3782538958791,139.595896963222 35.3782510863738,139.595915443388 35.3782445458936,139.595932292477 35.3782345257855,139.59594686299 35.3782214111166,139.59595859499 35.3782057058763,139.595967037623 35.3781880136082,139.595971866442 35.3781690142161,139.595972895879 35.3781494378362,139.595970086374 35.3781300367777,139.595963545894 35.3781115566124,139.595953525785 35.3780947075226,139.595940411117 35.3780801370095,139.595924705876 35.3780684050097,139.595907013608 35.3780599623774,139.595877087369 35.378049137993))

2023,江端さんの技術メモ

自分用のメモ。PC落すと、忘れてしまうので残します。

目的

バスルートをDBで格納する。

やってきたこと

新規に、データベースを作る。postgisとpgroutingの対応できるようにしておく。

yoko_db=# create database route_db;
CREATE DATABASE
yoko_db=# \c route_db
psql (13.4, server 12.5 (Debian 12.5-1.pgdg100+1))
You are now connected to database "route_db" as user "postgres".
route_db=# CREATE EXTENSION postgis;
CREATE EXTENSION
route_db=# create extension pgrouting;
CREATE EXTENSION

色々分かったこと

geometry型のデータには指定方法がある(らしい)。

http://cse.naro.affrc.go.jp/yellow/pgisman/3.0.0/using_postgis_dbmanagement.html

POINT: SRID指定なしでの2次元ポイントジオグラフィのテーブル生成は次の通りです。デフォルトは4326 WGS84経度緯度となります。

CREATE TABLE ptgeogwgs(gid serial PRIMARY KEY, geog geography(POINT) );
POINT: NAD83経度緯度での2次元ポイントジオグラフィのテーブル生成は次の通りです。

CREATE TABLE ptgeognad83(gid serial PRIMARY KEY, geog geography(POINT,4269) );
Z値を持ち、明示的にSRIDを指定したポイントのテーブル生成は次の通りです。

CREATE TABLE ptzgeogwgs84(gid serial PRIMARY KEY, geog geography(POINTZ,4326) );
LINESTRING

CREATE TABLE lgeog(gid serial PRIMARY KEY, geog geography(LINESTRING) );
POLYGON

-- ポリゴン NAD 1927経度緯度
CREATE TABLE lgeognad27(gid serial PRIMARY KEY, geog geography(POLYGON,4267) );
MULTIPOINT

MULTILINESTRING

MULTIPOLYGON

GEOMETRYCOLLECTION

ジオグラフィ型のフィールドはgeography_columnsシステムビューに登録されます。

"geography_columns"ビューをチェックして、テーブルが一覧にあるか見て下さい。

CREATE TABLEの文法でジオグラフィカラムを持つテーブルを新規に生成できます。

CREATE TABLE global_points (
    id SERIAL PRIMARY KEY,
    name VARCHAR(64),
    location GEOGRAPHY(POINT,4326)
  );

で、ちょっと、試しに、ちょっと以下のgeomデータを入れてみたのですが、興味深い結果が得られました。

route_db=# create table route_geom(geog geography(LINESTRING));
CREATE TABLE
route_db=#
route_db=# insert into route_geom(geog) VALUES('0105000020E610000001000000010200000012000000E97DE36BCF6F6140CDCCCCCCCCCC4140E4141DC9E56F614006D847A7AECC41400D8E9257E76F61400DFD135CACCC4140BEBC00FBE86F6140A27A6B60ABCC4140404D2D5BEB6F61401422E010AACC414045F0BF95EC6F6140A99F3715A9CC4140923F1878EE6F614062F3716DA8CC41400708E6E8F16F61401B47ACC5A7CC4140ABECBB22F86F6140F870C971A7CC414055F65D11FC6F61401B47ACC5A7CC414014ED2AA4FC6F61403F1D8F19A8CC414072A774B0FE6F6140A99F3715A9CC414047ACC5A70070614038F8C264AACC414075C8CD700370614031D3F6AFACCC4140130A117008706140B1E1E995B2CC4140C3B645990D70614006F52D73BACC414043C5387F13706140E23B31EBC5CC4140003ACC9717706140A2D11DC4CECC4140');
ERROR:  Geometry type (MultiLineString) does not match column type (LineString)

とエラーが出てきます。LineStringではなくて、MultiLineStringにしなさい と注意されました。

insertの段階でパースされているとは思いませんでした。

という訳で、次のようにやってみました。

route_db=# drop table route_geom;
DROP TABLE
route_db=# create table route_geom(geog geography(MULTILINESTRING));
CREATE TABLE
route_db=# insert into route_geom(geog) VALUES('0105000020E610000001000000010200000012000000E97DE36BCF6F6140CDCCCCCCCCCC4140E4141DC9E56F614006D847A7AECC41400D8E9257E76F61400DFD135CACCC4140BEBC00FBE86F6140A27A6B60ABCC4140404D2D5BEB6F61401422E010AACC414045F0BF95EC6F6140A99F3715A9CC4140923F1878EE6F614062F3716DA8CC41400708E6E8F16F61401B47ACC5A7CC4140ABECBB22F86F6140F870C971A7CC414055F65D11FC6F61401B47ACC5A7CC414014ED2AA4FC6F61403F1D8F19A8CC414072A774B0FE6F6140A99F3715A9CC414047ACC5A70070614038F8C264AACC414075C8CD700370614031D3F6AFACCC4140130A117008706140B1E1E995B2CC4140C3B645990D70614006F52D73BACC414043C5387F13706140E23B31EBC5CC4140003ACC9717706140A2D11DC4CECC4140');
INSERT 0 1

と、今度はinsertできました。

postGISで接触する線を抽出する方法を探す

のgeomのデータを入力したのですが、座標がおかしい、と、こちらも入力を拒否されました。

2023,江端さんの技術メモ

 

プレゼンテーション1

http://cse.naro.affrc.go.jp/yellow/pgisman/2.2.0/ST_ClosestPoint.html」

http://postgres.cn/docs/postgis-2.3/ST_Buffer.html

このジオメトリ/ジオグラフィからの距離が指定された距離以下となる点全てを表現するジオメトリ/ジオグラフィを返します。

■線の接触を検知するテスト用の線

ちなみに、現実世界の座標では、0,150や100,100などの座標はないのだけど、

create extension postgis
create extension pgrouting

を仕込んだpostGISのDBであれば、こんな訳の分からない座標でもちゃんと計算してくれます。

■線に幅10を与える方法

yoko_db=#
yoko_db=# SELECT ST_Buffer(
yoko_db(# ST_GeomFromText(
yoko_db(# 'LINESTRING(50 50,150 150,150 50)'
yoko_db(# ), 10, 'endcap=round join=round');
st_buffer
-----------------------------------------------------------------------------
01030000000100000031000000AA07FFCFB9DD614056F8003046A26340E82FBFAF370E624050929AFD11CA6340B196BE928A45624085F91736A4E76340E1F76833928162409FA91FEED9F963400000000000C0624000000000000064401F0897CC6DFE62409FA91FEED9F963404F69416D753A634085F91736A4E7634018D04050C871634050929AFD11CA634056F8003046A2634056F8003046A2634050929AFD11CA634018D04050C871634085F91736A4E763404F69416D753A63409FA91FEED9F963401F0897CC6DFE624000000000000064400000000000C06240000000000000644000000000000049409FA91FEED9F9634082DFA3CD4806484085F91736A4E76340C35AFA4A2A16474050929AFD11CA6340A0BFFCBEDE38464056F8003046A26340A71EFC3FE776454018D04050C8716340BEB69509B8D744404F69416D753A6340ED19A0276F6144401F0897CC6DFE624084598147981844400000000000C062400000000000004440E1F76833928162408459814798184440B196BE928A456240EC19A0276F614440E92FBFAF370E6240BEB69509B8D74440AA07FFCFB9DD6140A71EFC3FE7764540B06D6502EEB561409FBFFCBEDE3846407B06E8C95B986140C25AFA4A2A1647406156E0112686614081DFA3CD48064840000000000080614000000000000049400000000000806140A81EFC3FE7765F4058E103C018894C40A81EFC3FE77645405E40034121C74B40BEB69509B8D744403AA505B5D5E94A40EC19A0276F6144407B205C32B7F949408459814798184440FFFFFFFFFFFF4840000000000000444083DFA3CD480648408459814798184440C45AFA4A2A164740ED19A0276F614440A1BFFCBEDE384640BEB69509B8D74440A81EFC3FE7764540A81EFC3FE7764540BFB69509B8D74440A0BFFCBEDE384640EE19A0276F614440C45AFA4A2A164740855981479818444082DFA3CD480648400000000000004440FFFFFFFFFFFF484084598147981844407A205C32B7F94940EC19A0276F6144403AA505B5D5E94A40BDB69509B8D744405D40034121C74B40A81EFC3FE776454058E103C018894C40AA07FFCFB9DD614056F8003046A26340
(1 row)

■幅10の線を交差させる

SELECT ST_AsEWKT(ST_Intersection(ST_Buffer(ST_GeomFromText('LINESTRING(50 50,150 150,150 50)'), 10, 'endcap=round join=round'), ST_Buffer(ST_GeomFromText('LINESTRING(0 100,100 100,150 150,0 150)'), 10, 'endcap=round join=round')));

で、その出力値をグラフにするとこうなっていました。

重ね併わせてみます。

線の幅を1にしてみました。

SELECT ST_AsEWKT(ST_Intersection(ST_Buffer(ST_GeomFromText('LINESTRING(50 50,150 150,150 50)'), 1, 'endcap=round join=round'), ST_Buffer(ST_GeomFromText('LINESTRING(0 100,100 100,150 150,0 150)'), 1, 'endcap=round join=round')));

併わせてみます。

■領域と線の点(ブルーの線)

# SELECT ST_AsEWKT(ST_Intersection(ST_Intersection(ST_Buffer(ST_GeomFromText('LINESTRING(50 50,150 150,150 50)'), 10, 'endcap=round join=round'), ST_Buffer(ST_GeomFromText('LINESTRING(0 100,100 100,150 150,0 150)'), 10, 'endcap=round join=round')),ST_GeomFromText('LINESTRING(0 100,100 100,150 150, 0 150)')));

st_asewkt

----------------------------------------------------------------------

LINESTRING(85.857864376269 100,100 100,150 150,135.857864376269 150)

(1 row)

■領域と線の点(オレンジの線)

yoko_db=# SELECT ST_AsEWKT(ST_Intersection(ST_Intersection(ST_Buffer(ST_GeomFromText('LINESTRING(50 50,150 150,150 50)'), 10, 'endcap=round join=round'), ST_Buffer(ST_GeomFromText('LINESTRING(0 100,100 100,150 150,0 150)'), 10, 'endcap=round join=round')),ST_GeomFromText('LINESTRING(50 50,150 150, 150 50)')));

st_asewkt

------------------------------------------------

LINESTRING(90 90,150 150,150 135.857864376269)

(1 row)

■実世界におけるST_Bufferが作る"幅"は?

先程、『現実世界の座標では、0,150や100,100などの座標はないのだけど、create extension postgis
、create extension pgroutingを仕込んだpostGISのDBであれば、こんな訳の分からない座標でもちゃんと計算してます』と記載しましたが、現実世界の座標では、どうやってこのサイズを決めればいいのかが分かりません。

という訳で実際の座標を使って試してみます。

139.622931 35.489653 と、 139.6401889 35.502831をつかって試してみます。

yoko_db=# SELECT ST_Distance('SRID=4326;POINT(139.622931 35.489653)'::GEOGRAPHY,'SRID=4326;POINT(139.6401889 35.502831)'::GEOGRAPHY);
st_distance
---------------
2142.35290029
(1 row)

ざっくり2km強ですね。

で、ここで、「描画しないと確認が面倒だなぁ」ということに気がつきました。どうやらpgAdminを使えばこれが可能なようです(先程、最新版をインストールして、古いバージョンをアンインストール(デジレクトリレベルで手動で消去しないと、最新版の起動に失敗します)

上記は古いpgadmin4のビューです。新しいpgAdmin4では、これで地図が表示されるようです

 

 

これで、SQL文を入力すると、その絵が出てくる環境が整いました。

で、まずは、

select ST_Buffer(ST_GeomFromText('LINESTRING(139.622931 35.489653, 35.502831 139.6401889)'),10, 'endcap=round join=round')

をやってみました。

定規で図ってみたところ、1/10くらいの幅になっているので、実際この場合、この線の幅は200メートルくらいでしょう。

誤差として50メートルとして、"2"くらいで試してみます。

select ST_Buffer(ST_GeomFromText('LINESTRING(139.622931 35.489653, 35.502831 139.6401889)'),2, 'endcap=round join=round')

よく分からなけど、GPSの誤差を鑑みて、このくらいの幅を取っておくべきかな。とりあえず、これをデフォルトとして、まずはDBを作ってみます。

テストとして、バスルートを記載してみます。

select ST_GeomFromText('LINESTRING(139.595873 35.378154,139.595779 35.37812,139.595766 35.378045,139.595922 35.377752,139.596212 35.377193,139.596704 35.376296,139.596804 35.376139,139.597005 35.375862,139.597443 35.375322,139.597832 35.374847,139.598029 35.374589,139.598145 35.374415,139.598302 35.374138,139.598369 35.374024,139.598422 35.373919,139.598491 35.373738,139.599019 35.372353,139.599495 35.371156,139.599468 35.371081,139.599338 35.371056,139.59899 35.370963,139.597059 35.370473,139.595393 35.370028,139.594419 35.369764,139.59407 35.369659,139.593798 35.369572,139.593476 35.369457,139.592966 35.369259,139.592779 35.369176,139.592465 35.369025,139.591683 35.368627,139.590731 35.368134,139.590073 35.367794,139.589176 35.367331,139.588262 35.366863,139.587735 35.366595,139.587508 35.366492,139.587332 35.366423,139.587176 35.366366,139.586864 35.36627,139.586549 35.36619,139.586207 35.366124,139.585855 35.366079,139.58554 35.366056,139.585204 35.366045,139.584925 35.366056,139.584641 35.366077,139.584445 35.366098,139.584247 35.366129,139.583902 35.366197,139.583561 35.366286,139.583199 35.366401,139.582906 35.366519,139.582565 35.366683,139.582309 35.366816,139.582119 35.366939,139.581933 35.36708,139.581569 35.367314,139.580995 35.367738,139.58035 35.368227,139.57968 35.368715,139.579054 35.36918,139.57882 35.369336,139.578604 35.369493,139.578352 35.369657,139.57811 35.369804,139.577878 35.369934,139.577738 35.37001,139.577589 35.370082,139.577418 35.37016,139.57732 35.37024,139.577346 35.370322,139.577492 35.37064,139.577597 35.370922,139.577664 35.371296,139.577672 35.371576,139.577637 35.371872,139.577594 35.372092,139.577509 35.37234,139.577434 35.372512,139.577012 35.373505,139.576949 35.373583,139.576554 35.374506,139.576609 35.374598,139.576838 35.374662,139.577089 35.374742,139.577114 35.374811,139.577011 35.375071,139.576926 35.375085,139.576557 35.374996,139.576471 35.374952,139.576471 35.374876,139.576599 35.374564,139.576916 35.37381,139.577 35.373789,139.577313 35.373871,139.577775 35.373993,139.57802 35.374046,139.578323 35.374087,139.578673 35.37412,139.578925 35.374131,139.579275 35.374129,139.579628 35.374106,139.580017 35.374068,139.581646 35.373846,139.582008 35.373789,139.582074 35.373858,139.581963 35.374391,139.581837 35.374905,139.581765 35.375135,139.581633 35.375534,139.581499 35.375863,139.58136 35.376167,139.581301 35.376281,139.580964 35.376851,139.580326 35.377869,139.578402 35.380965,139.577251 35.382825,139.577101 35.383021,139.577006 35.383152,139.576828 35.383389,139.576656 35.383641,139.576268 35.38417,139.575843 35.384739,139.575346 35.385415,139.57515 35.385681,139.574998 35.385894,139.574891 35.386055,139.574838 35.386181,139.574775 35.386347,139.574692 35.386563,139.574638 35.386697,139.574542 35.386724,139.574012 35.386604,139.572348 35.386248,139.571268 35.386011,139.570946 35.385959,139.570646 35.385931,139.570348 35.385922,139.570073 35.385934,139.569805 35.385966,139.569487 35.38603,139.568931 35.386182,139.568571 35.386286,139.568349 35.386354,139.568135 35.386442,139.56792 35.386576,139.567769 35.386716,139.56766 35.386853,139.56657 35.388671,139.566268 35.389177,139.566173 35.389362,139.566128 35.389529,139.566101 35.389744,139.566109 35.389929,139.566138 35.390063,139.566177 35.390179,139.566254 35.390338,139.567047 35.391736,139.567153 35.391917,139.567294 35.39212,139.567409 35.392281,139.56767 35.392568,139.568151 35.393053,139.568317 35.393216,139.568846 35.393747,139.569264 35.394174,139.569335 35.394232,139.569419 35.394281,139.569508 35.394292,139.570315 35.394297,139.571173 35.3943,139.571345 35.394307,139.571454 35.394351,139.57165 35.394627,139.572146 35.395394,139.573316 35.397176,139.573368 35.39726,139.573414 35.397345,139.573465 35.397477,139.573485 35.397559,139.573544 35.398079,139.573553 35.398228,139.573516 35.398354,139.573465 35.398447,139.57337 35.398541,139.57296 35.398854,139.57273 35.399024,139.570967 35.400511,139.570926 35.400555,139.570918 35.400594,139.571046 35.400985,139.57111 35.401124,139.571253 35.401304,139.571308 35.401365,139.571382 35.401397,139.571453 35.401399,139.57153 35.401349,139.571716 35.401204,139.571767 35.401149,139.571763 35.401079,139.57172 35.401031,139.571503 35.400935,139.571434 35.40092,139.57138 35.400931,139.57135 35.400995)')

では、次に、このルートに幅を与えてみます。
select ST_Buffer(ST_GeomFromText('LINESTRING(139.595873 35.378154,139.595779 35.37812,139.595766 35.378045,139.595922 35.377752,139.596212 35.377193,139.596704 35.376296,139.596804 35.376139,139.597005 35.375862,139.597443 35.375322,139.597832 35.374847,139.598029 35.374589,139.598145 35.374415,139.598302 35.374138,139.598369 35.374024,139.598422 35.373919,139.598491 35.373738,139.599019 35.372353,139.599495 35.371156,139.599468 35.371081,139.599338 35.371056,139.59899 35.370963,139.597059 35.370473,139.595393 35.370028,139.594419 35.369764,139.59407 35.369659,139.593798 35.369572,139.593476 35.369457,139.592966 35.369259,139.592779 35.369176,139.592465 35.369025,139.591683 35.368627,139.590731 35.368134,139.590073 35.367794,139.589176 35.367331,139.588262 35.366863,139.587735 35.366595,139.587508 35.366492,139.587332 35.366423,139.587176 35.366366,139.586864 35.36627,139.586549 35.36619,139.586207 35.366124,139.585855 35.366079,139.58554 35.366056,139.585204 35.366045,139.584925 35.366056,139.584641 35.366077,139.584445 35.366098,139.584247 35.366129,139.583902 35.366197,139.583561 35.366286,139.583199 35.366401,139.582906 35.366519,139.582565 35.366683,139.582309 35.366816,139.582119 35.366939,139.581933 35.36708,139.581569 35.367314,139.580995 35.367738,139.58035 35.368227,139.57968 35.368715,139.579054 35.36918,139.57882 35.369336,139.578604 35.369493,139.578352 35.369657,139.57811 35.369804,139.577878 35.369934,139.577738 35.37001,139.577589 35.370082,139.577418 35.37016,139.57732 35.37024,139.577346 35.370322,139.577492 35.37064,139.577597 35.370922,139.577664 35.371296,139.577672 35.371576,139.577637 35.371872,139.577594 35.372092,139.577509 35.37234,139.577434 35.372512,139.577012 35.373505,139.576949 35.373583,139.576554 35.374506,139.576609 35.374598,139.576838 35.374662,139.577089 35.374742,139.577114 35.374811,139.577011 35.375071,139.576926 35.375085,139.576557 35.374996,139.576471 35.374952,139.576471 35.374876,139.576599 35.374564,139.576916 35.37381,139.577 35.373789,139.577313 35.373871,139.577775 35.373993,139.57802 35.374046,139.578323 35.374087,139.578673 35.37412,139.578925 35.374131,139.579275 35.374129,139.579628 35.374106,139.580017 35.374068,139.581646 35.373846,139.582008 35.373789,139.582074 35.373858,139.581963 35.374391,139.581837 35.374905,139.581765 35.375135,139.581633 35.375534,139.581499 35.375863,139.58136 35.376167,139.581301 35.376281,139.580964 35.376851,139.580326 35.377869,139.578402 35.380965,139.577251 35.382825,139.577101 35.383021,139.577006 35.383152,139.576828 35.383389,139.576656 35.383641,139.576268 35.38417,139.575843 35.384739,139.575346 35.385415,139.57515 35.385681,139.574998 35.385894,139.574891 35.386055,139.574838 35.386181,139.574775 35.386347,139.574692 35.386563,139.574638 35.386697,139.574542 35.386724,139.574012 35.386604,139.572348 35.386248,139.571268 35.386011,139.570946 35.385959,139.570646 35.385931,139.570348 35.385922,139.570073 35.385934,139.569805 35.385966,139.569487 35.38603,139.568931 35.386182,139.568571 35.386286,139.568349 35.386354,139.568135 35.386442,139.56792 35.386576,139.567769 35.386716,139.56766 35.386853,139.56657 35.388671,139.566268 35.389177,139.566173 35.389362,139.566128 35.389529,139.566101 35.389744,139.566109 35.389929,139.566138 35.390063,139.566177 35.390179,139.566254 35.390338,139.567047 35.391736,139.567153 35.391917,139.567294 35.39212,139.567409 35.392281,139.56767 35.392568,139.568151 35.393053,139.568317 35.393216,139.568846 35.393747,139.569264 35.394174,139.569335 35.394232,139.569419 35.394281,139.569508 35.394292,139.570315 35.394297,139.571173 35.3943,139.571345 35.394307,139.571454 35.394351,139.57165 35.394627,139.572146 35.395394,139.573316 35.397176,139.573368 35.39726,139.573414 35.397345,139.573465 35.397477,139.573485 35.397559,139.573544 35.398079,139.573553 35.398228,139.573516 35.398354,139.573465 35.398447,139.57337 35.398541,139.57296 35.398854,139.57273 35.399024,139.570967 35.400511,139.570926 35.400555,139.570918 35.400594,139.571046 35.400985,139.57111 35.401124,139.571253 35.401304,139.571308 35.401365,139.571382 35.401397,139.571453 35.401399,139.57153 35.401349,139.571716 35.401204,139.571767 35.401149,139.571763 35.401079,139.57172 35.401031,139.571503 35.400935,139.571434 35.40092,139.57138 35.400931,139.57135 35.400995)'),1, 'endcap=round join=round')

あれ? この円は何? と思い色々弄っていたのですが

を、変えてみました。

としてみました。

"当たり"だったようです。

ただ、これでは幅をメートルで設定できないので、メートル設定をしてみました.

GPSの誤差として50メートルくらいでいいかな、と

SELECT ST_Buffer(st_transform(st_setsrid(ST_GeomFromtext(
'linestring(139.595873 35.378154,139.595779 35.37812,139.595766 35.378045,..... ,139.57138 35.400931,139.57135 35.400995)'
),4326),3857),50,'endcap=round join=round')

 

2023,江端さんの技術メモ

osm.pbfファイルを、osmファイルに変換する方法

■pbfからpbfを切り出す

osmconvert chugoku-latest.osm.pbf -b=133.455201,34.274923,134.298740,35.284564 --complete-ways -o=okayama.pbf

は、chugoku-latest.osm.pbf から、133.455201,34.274923,134.298740,35.284564の領域で、Pbfファイルとして切り取れ。

■osmをpbfに変換する

osmconvert yokohama.osm --out-pbf >yokohama.pbf

 

2023,江端さんの技術メモ

OpenStreetMapとOpenTripPlannerで経路検索してバスに乗れと言ってもらった

オープンソースの経路探索「OpenTripPlanner」をUbuntuで動かして岡山県で経路探索をする

上記の「岡山県」を丸ごと試させて頂いています。

違いがあるのは、私は、>wsl -d Ubuntu-20.04  on Windows10を使っているところと、

「Windows11にWSL2+Ubuntu20.04をインストールする」を試してみて、Golangをインストールしてみた件

otp-1.3.0-shaded.jar → 1.4.0のバージョンアップ版を使っているところです。

中々 Grizzly server running.  の表示が出てこないので、1.4.0を使ったということと、あと、

wget "http://www.shimoden.net/busmada/opendata/GTFS-JP.zip" -O shimodenbus.gtfs.zip

だけにしたところです。全部入れたら、エラーになるので、どれかのファイルに問題があるものと思います。

後は、明日以降にします。


横浜市交通局 バスの情報に適用します

https://ckan.odpt.org/dataset?q=%E6%A8%AA%E6%B5%9C&tags=%E3%83%90%E3%82%B9-bus&sort=score+desc%2C+metadata_modified+desc

から、データをダウンロードします。

これを、C:\Users\ebata\yokohama\yoko_db などを作っておき、

>wsl -d Ubuntu-20.04

を立ち上げて、osmをpbfに変換する

osmconvert yokohama.osm --out-pbf >yokohama.pbf

を作ります。

osmconvertの使い方

 

C:\Users\ebata\yokohama\yoko_dbに移動して、

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata/yokohama/yoko_db$ java -Xmx5G -jar otp-1.4.0-shaded.jar --build ./ --inMemory

を実施すると、サーバが立ち上がります。

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata/yokohama/otp$ java -Xmx5G -jar otp-1.4.0-shaded.jar --build ./ --inMemory
14:24:02.863 INFO (OTPServer.java:39) Wiring up and configuring server.
14:24:02.868 INFO (GraphBuilder.java:165) Wiring up and configuring graph builder task.
14:24:02.870 INFO (GraphBuilder.java:171) Searching for graph builder input files in .
(中略)
14:24:13.837 INFO (NetworkListener.java:750) Started listener bound to [0.0.0.0:8080]
14:24:13.849 INFO (NetworkListener.java:750) Started listener bound to [0.0.0.0:8081]
14:24:13.851 INFO (HttpServer.java:300) [HttpServer] Started.
14:24:13.851 INFO (GrizzlyServer.java:153) Grizzly server running.

http://localhost:8080/

をすると、以下のような画面が出てきます。

この使い方は後回しにして、とりあえず以下を確認します。

http://localhost:8080/otp/routers/default/index/agencies/1

http://localhost:8080/otp/routers/default/index/agencies/1/3000020141003/routes

使い方は、まだ良く分かりませんし、エラーも出ていますが、今日はここまで。