2024,江端さんの技術メモ

C言語を使えて、GStreamerが使えて、GO言語を使えて、CGOが使える環境を作っています。

(1)Windowsの方のmsys2とGStreamerのパッケージを削除
Windowsの方のC言語、GStreamerはコンフリクトするので削除しますが、GO言語は、別のタスク(大学の方のシミュレータ)があるので、削除できませんでした。
という訳で、MSYS2の環境を、Windowsの方と切り離して運用するという覚悟ができました。

(2)C:の容量が小さいので、G:\の方にパッケージを分離していたのですが、これをやると、全く動かなくなるので、C:\msys2の配下に勝手に作成される、/c/msys64/home/tomoi/の直下でプログラムの作成をすることにしました。

これ、/usr/local/binの配下に/home/ebataを作るような気持ち悪さがあるのですが、今回は稼動が最優先です。

MSYS2のインストール

  1. MSYS2公式サイトからインストーラをダウンロードします。
  2. インストーラを実行し、画面の指示に従ってMSYS2をインストールします。

2. MSYS2の初期設定

  1. MSYS2ターミナルを起動: MSYS2 MSYSショートカットを使用してMSYS2ターミナルを起動します。
  2. パッケージデータベースと基本パッケージの更新: 以下のコマンドを順番に実行して、パッケージデータベースと基本パッケージを更新します。

    sh

    pacman -Syu

    初回のアップデートが完了したら、ターミナルを一度閉じて再起動します。

  3. 再度更新を実行: ターミナルを再起動後、再度以下のコマンドを実行します。

    sh

    pacman -Syu

3. MinGW-w64のインストール

  1. MinGW-w64ツールチェインのインストール: MSYS2 MinGW 64-bitショートカットを使用してMSYS2ターミナルを起動し、以下のコマンドを実行します。

    sh

    pacman -S mingw-w64-x86_64-toolchain

    これにより、GCC、G++、およびその他の開発ツールがインストールされます。

4. 環境変数の設定

MinGW-w64のバイナリにアクセスするために、環境変数PATHを設定します。

  1. ~/.bashrcファイルの編集: MSYS2ターミナルで~/.bashrcファイルを開きます。

    sh

    nano ~/.bashrc
  2. PATHの設定: 以下の行を追加して保存します。

    sh

    export PATH="/mingw64/bin:$PATH"
  3. 設定の反映: 設定を反映させるために、ターミナルを再起動するか、以下のコマンドを実行します。

    sh

    source ~/.bashrc

5. GStreamerのインストール

  1. GStreamerのパッケージのインストール: MSYS2 MinGW 64-bitショートカットを使用してMSYS2ターミナルを起動し、以下のコマンドを実行します。

    sh

    pacman -S mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad mingw-w64-x86_64-gst-plugins-ugly

    pacman -S mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad mingw-w64-x86_64-gst-libav

6. 確認とテスト

  1. GCCの動作確認: GCCが正しくインストールされているか確認します。

    sh

    gcc --version
  2. 簡単なCプログラムの作成とコンパイル: 簡単なCプログラムを作成してコンパイルします。

    sh

    nano test.c

    以下の内容を入力します。

    c

    #include <stdio.h>

    int main() {
    printf("Hello, World!\n");
    return 0;
    }

    ファイルを保存してNanoエディタを閉じた後、コンパイルします。

    sh

    gcc test.c -o test.exe

    コンパイルが成功したら、実行します。

    sh

    ./test.exe
  3. GStreamerの動作確認: GStreamerが正しくインストールされているか確認します。

    sh

    gst-launch-1.0 --version

    簡単なGStreamerパイプラインを実行して動作確認します。

    sh

    gst-launch-1.0 videotestsrc ! autovideosink

とうぜん 、ここまですんなりできた訳ではありませんが、取り敢えず私が思い出せる程度の情報を載せてあります。

-----

https://github.com/go-gst/go-gst

から、/home/tomoi/go/srcで、 git clone https://github.com/go-gst/go-gst をして、/home/tomoi/go/src/go-gst を作って、

に張ってあったプログラムを、main.goでセーブしたのち、

go run main.go videotestsrc ! glimagesink

で、

と、

が、表われることを確認。

なにがどうなっているのかは、サッパリ分からないが、とりあえず、GoからGstreamerが動いたことは確認できた。

以上

なんか、サラっと書くと自分でも腹たつなぁ。10時間以上はかかったんだけどなぁ

2024,江端さんの技術メモ

Windows10に、GStreamerの1.24をインストール(フルインストールを選ぶこと)をしたのですが、定番の、

$ gst-launch-1.0.exe videotestsrc ! autovideosink
Use Windows high-resolution clock, precision: 1 ms
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Got context from element 'autovideosink0': gst.d3d11.device.handle=context, device=(GstD3D11Device)"
\(GstD3D11Device\)\ d3d11device2", adapter=(uint)0, adapter-luid=(gint64)41376, device-id=(uint)1042
, vendor-id=(uint)32902, hardware=(boolean)true, description=(string)"Intel\(R\)\ HD\ Graphics\ 4600
";
ERROR: from element /GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstD3D11VideoSink:autovid
eosink0-actual-sink-d3d11video: Cannot create converter
Additional debug info:
Failed to prepare d3d11window
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
ERROR: from element /GstPipeline:pipeline0/GstVideoTestSrc:videotestsrc0: Internal data stream error
.
Additional debug info:
../libs/gst/base/gstbasesrc.c(3177): gst_base_src_loop (): /GstPipeline:pipeline0/GstVideoTestSrc:vi
deotestsrc0:
streaming stopped, reason error (-5)
ERROR: pipeline doesn't want to preroll.
Freeing pipeline ...

となります。別のWindows BOXでも、先日も経験して、青ざめていました。

結果として、

$ gst-launch-1.0 videotestsrc ! glimagesink

とすれば動きます。

autovideosinkが動かん、っていうのは、結局分かっていませんが、これは困りものです。

以下自分用メモ

-UDP通信の実験

-受信側

-gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay ! udpsink host=192.168.101.10 port=38089
(ローカルの場合、host=127.0.0.1とする.  host=localhost は動かない)

-送信側

-gst-launch-1.0 udpsrc port=38089 caps="application/x-rtp,media=video,encoding-name=H264,payload=96" ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! glimagesink

-

-SRT通信の実験

-受信側

-gst-launch-1.0 srtsrc uri="srt://0.0.0.0:38089?mode=listener" keep-listening=true ! tsdemux ! h264parse ! avdec_h264 ! videoconvert ! glimagesink sync=false

-送信側

-gst-launch-1.0 rtspsrc location=rtsp://cam:Cam12345@192.168.0.10/Src/MediaInput/stream_1 latency=0 ! rtph264depay ! avdec_h264 ! videoconvert ! videoscale ! video/x-raw,width=640,height=360 ! videorate ! video/x-raw,framerate=5/1 ! x264enc speed-preset=ultrafast tune=zerolatency key-int-max=1 ! mpegtsmux ! srtserversink uri = \"srt://192.168.101.10:38089\" latency=500

2024,江端さんの技術メモ

dockerは、どのOS環境でも動くを唄っていますが、基本的に、わたしは、どんなパッケージであろうとも、「これ」を信じていません。

とくに時系列方向については、全く信用していません。

ともあれ、ノートPCにtomioka_dbをdocker-compose.ymlで再構築した時、以下の部分の変更が必要でしたので、逐次メモしていきます。

#version: '3.9'
services:
  db:
    build:
      context: .
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: tomioka_db
    ports:
      - "15432:5432"
    volumes:
      - ./tomioka_db:/tomioka_db
      - db-data:/var/lib/postgresql/data
  osm2pgsql:
    # image: openfirmware/osm2pgsql:latest
    image: osmtw/osm2pgsql:latest  # イメージ名を変更
    environment:
      PG_PORT_5432_TCP_ADDR: db
      PG_PORT_5432_TCP_PORT: 5432
      PG_ENV_OSM_DB: tomioka_db
      PG_ENV_OSM_USER: postgres
      PG_ENV_POSTGRES_PASSWORD: password
    volumes:
      - ./tomioka_db:/tomioka_db
volumes:
  db-data:

 

2024,江端さんの忘備録

私は今でも、Meadow3を使っています。

I still use Meadow3.

Meadow3とは、Windowsに特化したemacsのことです。

Meadow3 is a Windows-specific emacs.

WindowsNT 4.0より前から使っていますが、今も使い続けています。

I have been using it since before Windows NT 4.0 and continue to use it.

なぜか ―― 動くからです。

Why -- because it works.

現在、Windows11上でも動き続けています。

Currently, it continues to run on Windows 11.

vscodeのemacsキーバインドマッピング 諦めました。

-----

動き続けている限り、使わない理由はありません。

There is no reason not to use it as long as it keeps moving.

.emacsをメンテナンスする気力もありませんので、キーバインドも、当時から固定のままです。

I don't have the energy to maintain .emacs, so key bindings have remained fixed since that time.

もはやMeadow3は、私の体の一部といっても過言ではありません。

It is no exaggeration to say that Meadow3 is now a part of my body.

-----

Meadowが、バージョンアップしたWindowsOSで動かなくなった時に、私の中でも何かが終わるような気がしています。

I feel that something will end for me when Meadow stops working with the upgraded Windows OS.

―― と言いながら、次女のPCにMeadow3をインストールして、今、それで、この文章を書いています。

-- but I installed Meadow3 on my second daughter's PC and am now writing this text with it.

あと、次女のノートPCに大量に貼ってあるステッカーが、ちょっとアバンギャルドで、このPCを学会会場に持ち込む勇気が出ませんでした。

Also, the large number of stickers on my second daughter's laptop was a bit avant-garde, and I could not find the courage to bring this computer to the conference venue.

という訳で、こんなの購入して、ノートPCに貼りつけていました。

So I bought one like this and stuck it on my laptop.

返却時に、元に戻して返すつもりですが。

I intend to return it to its original state when I return it.

2024,江端さんの技術メモ

エクスプローラで、ファイルをコピーする場合、同じファイル名の場合には時刻が新しい場合のみ上書きしたいですがどうすれば良いですか
ChatGPT
ChatGPT
Windowsエクスプローラでファイルをコピーする際、同じファイル名の場合は時刻が新しい場合のみ上書きするという機能は標準では提供されていません。しかし、以下の方法でこの操作を実現できます。

方法1: コマンドプロンプトでrobocopyを使用
Windowsにはrobocopyという強力なコマンドラインツールがあり、これを使用してファイルのコピーを行うと、指定した条件に基づいてファイルを上書きできます。

以下の手順で行います。

コマンドプロンプトを管理者権限で開く

以下のrobocopyコマンドを実行

cmd
コードをコピーする
robocopy "コピー元フォルダのパス" "コピー先フォルダのパス" /XO
ここで、/XOオプションは古いファイルを除外します。これにより、コピー元フォルダのファイルがコピー先フォルダのファイルより新しい場合にのみ上書きされます。


コピー元フォルダがC:\source、コピー先フォルダがD:\destinationの場合、次のように入力します。

cmd
コードをコピーする
robocopy "C:\source" "D:\destination" /XO


cmd.exeを管理者モードで立ち上げ

C:\WINDOWS\system32>robocopy "g:home\ebata\tomioka3B\src" "\\192.168.0.9\share\tomioka3B\src" /XO /E /Z
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー
-------------------------------------------------------------------------------
  開始: 2024年6月23日 10:23:39
   コピー元 : G:\home\ebata\tomioka3B\src\
     コピー先 : \\192.168.0.9\share\tomioka3B\src\
    ファイル: *.*
  オプション: *.* /S /E /DCOPY:DA /COPY:DAT /Z /XO /R:1000000 /W:30
------------------------------------------------------------------------------
                           4    G:\home\ebata\tomioka3B\src\
                           2    G:\home\ebata\tomioka3B\src\.vscode\
                          20    G:\home\ebata\tomioka3B\src\Agent\
                           4    G:\home\ebata\tomioka3B\src\Agent\ldarp\
                           2    G:\home\ebata\tomioka3B\src\Agent\old\
                          14    G:\home\ebata\tomioka3B\src\Agent - kese09161446\
                           2    G:\home\ebata\tomioka3B\src\Agent - kese09161446\ldarp\
                           2    G:\home\ebata\tomioka3B\src\Agent - kese09161446\old\
                          14    G:\home\ebata\tomioka3B\src\Agent-kese-09161400\
                           2    G:\home\ebata\tomioka3B\src\Agent-kese-09161400\ldarp\
                           2    G:\home\ebata\tomioka3B\src\Agent-kese-09161400\old\
                           1    G:\home\ebata\tomioka3B\src\agent_db\
                          14    G:\home\ebata\tomioka3B\src\CartはAgentに併合\
                           1    G:\home\ebata\tomioka3B\src\CartはAgentに併合\ldarp\
                           2    G:\home\ebata\tomioka3B\src\CartはAgentに併合\old\
                           1    G:\home\ebata\tomioka3B\src\inc\
                           5    G:\home\ebata\tomioka3B\src\Join\
                           1    G:\home\ebata\tomioka3B\src\Join\ldarp\
                           3    G:\home\ebata\tomioka3B\src\ldarp\
                           4    G:\home\ebata\tomioka3B\src\old\
                          22    G:\home\ebata\tomioka3B\src\old\doc\
                         253    G:\home\ebata\tomioka3B\src\others\
                           1    G:\home\ebata\tomioka3B\src\others\.vscode\
                           8    G:\home\ebata\tomioka3B\src\others\chart\
                         105    G:\home\ebata\tomioka3B\src\others\csvファイルのバックアップ\
                           1    G:\home\ebata\tomioka3B\src\others\main49\
                           1    G:\home\ebata\tomioka3B\src\others\main50\
                           8    G:\home\ebata\tomioka3B\src\PrumeMobile\
                          10    G:\home\ebata\tomioka3B\src\PrumeMobile\chart\
                           9    G:\home\ebata\tomioka3B\src\PrumeMobile\chart2\
                           8    G:\home\ebata\tomioka3B\src\PrumeMobile\old\
                          12    G:\home\ebata\tomioka3B\src\PrumeMobile\static\
                          25    G:\home\ebata\tomioka3B\src\trip_cluster\
100%      新しいファイル                     105        #robocopy#
100%            新しい              7540        main.go
                          12    G:\home\ebata\tomioka3B\src\trip_cluster\bic\
100%      新しいファイル                     858        plot_cluster7.gnuplot
                           4    G:\home\ebata\tomioka3B\src\trip_cluster\bus\
100%      新しいファイル                     357        plot_cluster2.gnuplot
100%      新しいファイル                     858        plot_cluster2.gnuplot~
                          56    G:\home\ebata\tomioka3B\src\trip_cluster\data(最初に手動で作成)\
                           9    G:\home\ebata\tomioka3B\src\trip_cluster\walk\
100%      新しいファイル                     775        plot_cluster7.gnuplot
100%      新しいファイル                     858        plot_cluster7.gnuplot~
                        2001    G:\home\ebata\tomioka3B\src\trip_normalization\
100%            新しい              4466        main.go
100%      新しいファイル                    3678        main.go~
                          73    G:\home\ebata\tomioka3B\src\trip_test\
                          75    G:\home\ebata\tomioka3B\src\trip_test_tomioka2018\
100%            新しい             23276        main.go
100%      新しいファイル                     124        robocopy
                           0    G:\home\ebata\tomioka3B\src\trip_test_tomioka2018\main copy.go(5\
                          75    G:\home\ebata\tomioka3B\src\trip_test_tomioka2018_harugakkai\
                           6    G:\home\ebata\tomioka3B\src\trip_test_tomioka2018_harugakkai\others\
                           4    G:\home\ebata\tomioka3B\src\trip_tomioka2018\
                           4    G:\home\ebata\tomioka3B\src\trip_tomioka2018\others\
100%      新しいファイル                     587        dummy.txt
100%      新しいファイル                      58        dummy.txt~
100%            新しい              3272        main.go
        新しいディレクトリ       4      G:\home\ebata\tomioka3B\src\trip_tomioka2018_harugakkai\
100%      新しいファイル                  162161        agent_od_test.csv
100%      新しいファイル                    9022        libdarp.go
100%      新しいファイル                   15470        main.go
100%      新しいファイル                   18255        tools.go
        新しいディレクトリ       4      G:\home\ebata\tomioka3B\src\trip_tomioka2018_harugakkai\others\
100%      新しいファイル                  162161        agent_od_test.csv
100%      新しいファイル                     587        dummy.txt
100%      新しいファイル                      58        dummy.txt~
100%      新しいファイル                    3272        main.go
------------------------------------------------------------------------------
                  合計     コピー済み      スキップ       不一致        失敗    Extras
   ディレクトリ:        47         2        45         0         0         0
     ファイル:      2890        22      2868         0         0         0
      バイト:   35.39 m   408.0 k   34.99 m         0         0         0
       時刻:   0:00:02   0:00:01                       0:00:00   0:00:01
       速度:              278161 バイト/秒
       速度:              15.916 MB/分
   終了: 2024年6月23日 10:23:42

 

2024,江端さんの技術メモ

gnuplotで
0.98, 0.40, 0.30
0.98, 0.41, 0.30
0.97, 0.42, 0.30
0.96, 0.42, 0.30
0.98, 0.42, 0.31
0.98, 0.41, 0.31
のようにx,y,z座標で記載された、cluster1.csvの内容を、Gnuplotで表示するコマンドを教えて下さい。

ChatGPT
ChatGPT
以下は、cluster1.csv の内容を Gnuplot で表示するためのコマンドです。まず、CSVファイルの内容を正しく読み込むためのスクリプトを作成し、その後に3Dプロットを行います。

cluster1.csv の内容が次のようになっていると仮定します:
コードをコピーする
0.98, 0.40, 0.30
0.98, 0.41, 0.30
0.97, 0.42, 0.30
0.96, 0.42, 0.30
0.98, 0.42, 0.31
0.98, 0.41, 0.31
Gnuplot を使用してこのデータをプロットするためのスクリプトを作成します。以下はそのスクリプトです:
gnuplot
コードをコピーする
set datafile separator ","
set title "Cluster 1 Data"
set xlabel "X-axis"
set ylabel "Y-axis"
set zlabel "Z-axis"
set xrange [0:1]
set yrange [0:1]
set zrange [0:1]
set ticslevel 0
splot 'cluster1.csv' using 1:2:3 with points pt 7 ps 1 lc rgb "blue" title 'Cluster 1'

複数個出すのであれば、こんな感じ
splot 'cluster1.csv' using 1:2:3 with points pt 7 ps 1 lc rgb "blue" title 'Cluster 1', 'cluster2.csv' using 1:2:3 with points pt 7 ps 1 lc rgb "red" title 'Cluster 2', 'cluster3.csv' using 1:2:3 with points pt 7 ps 1 lc rgb "yellow" title 'Cluster 3'

splot 'cluster1.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "blue" title 'Cluster 1', 'cluster2.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "red" title 'Cluster 2', 'cluster3.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "yellow" title 'Cluster 3', 'cluster4.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "green" title 'Cluster 4', 'cluster5.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "cyan" title 'Cluster 5', 'cluster6.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "magenta" title 'Cluster 6', 'cluster7.csv' using 1:2:3 with points pt 7 ps 2 lc rgb "orange" title 'Cluster 7'

このスクリプトを Gnuplot に読み込むことで、3Dプロットが作成されます。具体的な手順は以下の通りです。

Gnuplot を起動します。
上記のスクリプトをコマンドラインに入力するか、ファイルに保存して load コマンドで読み込みます。
例えば、スクリプトを plot_cluster1.gnuplot というファイルに保存した場合:

sh
コードをコピーする
gnuplot> load 'plot_cluster1.gnuplot'
これで、cluster1.csv の内容が3Dプロットとして表示されます。プロットのポイントの形状や色、サイズは必要に応じて調整できます。

2024,江端さんの技術メモ

User
You
type LocInfo struct { Lon float64 Lat float64 Source int } という型があり、 route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: 432}, LocInfo{Source: 1070}) のように LocInfo{Source: 432} を使いたいのですが、423,が変数aに入っている場合は、どのように取り扱えば良いでしょうか
ChatGPT
ChatGPT

変数aにLocInfo型の値が入っていて、その中のSourceフィールドの値を使いたい場合、以下のようにすれば良いでしょう:

// 変数aがLocInfo型であると仮定する
var a LocInfo

// aのSourceフィールドの値を使ってgetDijkstraPath関数を呼び出す
route, dis := getDijkstraPath(db_agent_od, LocInfo{Source: a.Source}, LocInfo{Source: 1070})

これにより、変数aのSourceフィールドの値がLocInfo構造体のインスタンスを作成する際に使用され、その値がgetDijkstraPath関数に渡されます。

2024,江端さんの技術メモ

/*

		こちらは、length_m as cost を使っている
		query := `
		SELECT seq, source, target, x1, y1, x2, y2, agg_cost
		FROM pgr_dijkstra(
			'SELECT gid as id, source, target, length_m as cost FROM ways',
			$1::bigint,
			$2::bigint,
			directed:=false
		) a
		INNER JOIN ways b ON (a.edge = b.gid)
		ORDER BY seq
		`
	*/

	// こちらは、cost, reverse_cost を使っている
	query := `
	SELECT seq, source, target, x1, y1, x2, y2, agg_cost 
	FROM pgr_dijkstra(
		'SELECT gid as id, source, target, cost, reverse_cost FROM ways', 
		$1::bigint, 
		$2::bigint, 
		directed:=false
	) a 
	INNER JOIN ways b ON (a.edge = b.gid) 
	ORDER BY seq
	`

こちらは、"length_m as cost" を使っては駄目だった。

cost, reverse_cost を使わなければならなかった。

宇都宮ライトレールに優先的に乗車させるような、ダイクストラをどうやって作ろうか?

もう、これで完成だ、と思っても次々問題が出てきて、本当に疲れる・・・

2024,江端さんの技術メモ

ロングランで、pgr_dijkstra()の挙動の振舞が変であることを発見したので、ChatGPTに相談してみました
User
You
直結する2つのノードの場合、最短距離は当然一意に決定します。postGISのpgr_dijkstra()は、この直結する2つのノードを指定すると、値を返さないようですが、これは正しい仕様でしょうか
ChatGPT
ChatGPT

直結する2つのノードの場合、最短経路は確かに一意に決定します。そのため、pgRoutingのpgr_dijkstra()関数が直結する2つのノード間で値を返さない場合、これは通常は仕様としては誤っています。

pgRoutingのpgr_dijkstra()関数は、通常、始点と終点が異なるノード間の最短経路を見つけるために使用されます。この場合、始点と終点が同じノードである直結する2つのノード間の最短経路を求める必要はないため、関数が値を返さない可能性があります。

しかしながら、直結する2つのノード間の最短経路を求める必要がある場合、通常はpgr_dijkstra()ではなく、pgr_dijkstraCost()やpgr_dijkstraVia()などの関数が使用されます。これらの関数は、エッジ間のコスト(重み)を考慮して最短経路を見つけるため、直結する2つのノード間の最短経路を正しく返すことが期待されます。

したがって、直結する2つのノード間の最短経路を求める場合、適切な関数を使用し、正しい結果が得られるようにすることが重要です。

 

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

を改造する必要が出てきました。


User

You
postGISのpgr_dijkstraVia()は何をしてくれるAPIですか
ChatGPT
ChatGPT

PostGISのpgr_dijkstraVia()は、指定された複数の経由地を通過する最短経路を見つけるためのAPIです。これはpgRoutingの一部であり、Dijkstraアルゴリズムを使用して経路を計算します。

このAPIを使用すると、始点と終点の間に複数の経由地が与えられ、それらの経由地を通過する最短経路を見つけることができます。つまり、指定された始点から終点までの最短経路を見つける際に、特定の地点(経由地)を経由しなければならない場合に役立ちます。

pgr_dijkstraVia()関数の基本的な使い方は次のとおりです:

sql

SELECT * FROM pgr_dijkstraVia(
'edge_table', -- エッジテーブル
ARRAY[start_node, end_node], -- 始点と終点のノードIDの配列
ARRAY[via_node1, via_node2, ...], -- 経由地のノードIDの配列
directed := true/false, -- エッジが有向か無向かを指定
has_reverse_cost := true/false -- エッジに逆コストがあるかどうかを指定
);

この関数は、指定されたエッジテーブル内のエッジを使用して最短経路を見つけます。始点と終点のノードIDの配列と、経由地のノードIDの配列が指定されます。また、エッジが有向か無向か、およびエッジに逆コストがあるかどうかを指定することもできます。

このようにして、pgr_dijkstraVia()は指定された経由地を通過する最短経路を見つけることができます。

You
pgr_dijkstraCost()は、どういうAPIですか
ChatGPT
ChatGPT

pgr_dijkstraCost()は、PostGISのpgRoutingエクステンションで提供されるAPIの一つで、指定された始点と終点間の最短経路を見つけるために使用されます。しかし、pgr_dijkstra()とは異なり、この関数は経路を探す際にエッジのコスト(距離、時間、または任意の重み付け)を考慮します

この関数は、始点と終点のノードIDを指定し、エッジのコストを計算するための重みのカラムを指定します。その後、指定された始点から終点までの最短経路を見つけます。

基本的な使い方は次のとおりです:

sql

SELECT * FROM pgr_dijkstraCost(
'edge_table', -- エッジテーブル
ARRAY[start_node], -- 始点のノードIDの配列
ARRAY[end_node], -- 終点のノードIDの配列
cost_column := 'cost', -- エッジのコストを示すカラム名
directed := true/false -- エッジが有向か無向かを指定
);

この関数は、指定されたエッジテーブル内のエッジを使用して、始点から終点までの最短経路を見つけます。エッジのコストは、指定されたカラムに基づいて計算されます。また、エッジが有向か無向かを指定することもできます。

これにより、指定された始点から終点までの最短経路とその経路の合計コストが返されます。

2024,江端さんの技術メモ

特定領域内で、乱数的な緯度・経度の作成を行うコードをChatGPTに考えて貰いました。

package main

import (
	"fmt"
	"math"
	"math/rand"
)

// Polygon represents a polygon defined by its vertices
type Polygon [][]float64

// Point represents a point with x and y coordinates
type Point struct {
	X float64
	Y float64
}

// isInPolygon checks if a point is inside a polygon using the ray casting algorithm
func (p Polygon) isInPolygon(point Point) bool {
	intersections := 0
	for i := 0; i < len(p); i++ {
		p1 := p[i]
		p2 := p[(i+1)%len(p)]

		if point.Y > math.Min(p1[1], p2[1]) && point.Y <= math.Max(p1[1], p2[1]) &&
			point.X <= math.Max(p1[0], p2[0]) && p1[1] != p2[1] {
			xIntersection := (point.Y-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1]) + p1[0]
			if p1[0] == p2[0] || point.X <= xIntersection {
				intersections++
			}
		}
	}
	return intersections%2 != 0
}

// generateRandomPointInPolygon generates a random point inside the given polygon
func generateRandomPointInPolygon(p Polygon) Point {
	var minX, minY, maxX, maxY float64
	minX = math.MaxFloat64
	minY = math.MaxFloat64
	maxX = -math.MaxFloat64
	maxY = -math.MaxFloat64

	// Find bounding box of the polygon
	for _, vertex := range p {
		if vertex[0] < minX {
			minX = vertex[0]
		}
		if vertex[1] < minY {
			minY = vertex[1]
		}
		if vertex[0] > maxX {
			maxX = vertex[0]
		}
		if vertex[1] > maxY {
			maxY = vertex[1]
		}
	}

	// Generate random points until a point inside the polygon is found
	var randomPoint Point
	for {
		randomPoint.X = rand.Float64()*(maxX-minX) + minX
		randomPoint.Y = rand.Float64()*(maxY-minY) + minY

		if p.isInPolygon(randomPoint) {
			break
		}
	}
	return randomPoint
}

func main() {
	// Define the polygon
	polygon := Polygon{
		{35.36394967, 139.61846500},
		{35.36216810, 139.61890850},
		{35.36170465505306, 139.6220415552594},
		{35.36163108058289, 139.62334070015595},
		{35.363117271878345, 139.62314221968566},
		{35.36335187635167, 139.62481739887647},
		{35.36310056060587, 139.62485183402688},
		{35.36376860001917, 139.6288186562702},
		{35.36420166714637, 139.6297897196359},
		{35.36754482323006, 139.6296024603071},
		{35.37126945661188, 139.62886244945108},
		{35.37375189636854, 139.62615207124352},
		{35.37464657021711, 139.623189740366},
		{35.37574882601201, 139.6213765671167},
		{35.37527643251494, 139.6210117866997},
		{35.37306314467156, 139.6217413475337},
		{35.37268696718477, 139.62013202216457},
		{35.37018828750506, 139.61840497406456},
		{35.370782160278, 139.61705458898427},
		{35.36947068533102, 139.61641732865053},
		{35.370596575495014, 139.61476348635583},
		{35.37078029225879, 139.61403393574466},
		{35.36864433631068, 139.61438212951467},
		{35.36653571408147, 139.61453772192408},
		{35.36394967, 139.61846500},
	}

	// Generate a random point inside the polygon
	randomPoint := generateRandomPointInPolygon(polygon)
	fmt.Println("Random point inside polygon:", randomPoint)
}

なるほど、と思いながらコードを読んでいたのですが、『あれ? これって、領域に入った緯度・経度の乱数を採用するだけだから、発生頻度が均一にならないんじゃないかな?』と思い、ChatGPTにたずねてみたら『Yes』と言われました。

で、発生頻度を均一になるコードを再度要求したのですが ―― コードを一目見て、『このコードは間違っているな』と分かるようなものが出てきました。

『ChatGPTは、もの凄く真摯な言葉で、嘘をつく』

で、昔のコードを探していたら、PostGISを使うものが出てきました。

// C:\Users\ebata\tomioka3B\src\others\main35.go
/*
	実験用の座標を作る
	修正後 (富岡西5丁目を削除し、富岡6丁目の下1/4を削除)

	このプログラムは、Go言語を使用してPostgreSQLデータベースから空間データを取得し、指定された多角形内に均等に配置された乱数の座標を生成します。以下はプログラムの概要です:

	パッケージのインポート: 必要なパッケージをインポートします。database/sql はデータベースの操作に使用され、fmt と log は出力とログのために使用されます。また、PostgreSQLデータベースへの接続に使用するドライバもインポートされます。
	main() 関数: プログラムのエントリーポイントです。まず、PostgreSQLデータベースに接続します。接続情報は、ユーザー名、パスワード、ホスト、ポート、およびデータベース名で構成されます。
	SQLクエリの実行: query 変数にSQLクエリが格納されています。このクエリは、指定された多角形の領域内に均等に配置された15000個の点を生成するものです。db.Query() を使用してクエリを実行し、結果を rows に格納します。
	結果の処理: rows.Next() を使用して、結果セットの各行を処理します。各行は msg として取得されます。次に、regexp パッケージを使用して、取得した座標データを処理します。
	座標データの分解: 取得した座標データは、MULTIPOINT 形式の文字列として提供されます。この文字列をバラバラに分解し、各点の緯度と経度を取得します。regexp.MustCompile("[() ,]").Split(msg, -1) を使用して、文字列を分割します。
	座標の表示: 緯度と経度のペアを取得し、それぞれを浮動小数点数に変換して表示します。

	このプログラムは、指定された多角形内に均等に分布する乱数の座標を生成し、それを取得して表示します。


*/

package main

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

	_ "github.com/lib/pq"
)

func main() {
	// 取り扱うDBによってノード番号が代わるので注意すること
	// 例えばtomioka_db_c とtomioka_dbは全く異なる
	db, err := sql.Open("postgres",
		"user=postgres password=password host=192.168.0.23 port=15432 dbname=tomioka_db_f sslmode=disable")
	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer db.Close()

	// 修正後のターゲットの富岡地区 (富岡西5丁目を削除し、富岡6丁目の下1/4を削除)

	query := `
	SELECT st_asText(
		ST_GeneratePoints(
			ST_GeomFromText(
				'POLYGON((
					35.36394967 139.61846500,
					35.36216810 139.61890850,
					35.36170465505306 139.6220415552594,
					35.36163108058289 139.62334070015595,
					35.363117271878345 139.62314221968566,
					35.36335187635167 139.62481739887647,
					35.36310056060587 139.62485183402688,
					35.36376860001917 139.6288186562702,
					35.36420166714637 139.6297897196359,
					35.36754482323006 139.6296024603071,
					35.37126945661188 139.62886244945108,
					35.37375189636854 139.62615207124352,
					35.37464657021711 139.623189740366,
					35.37574882601201 139.6213765671167,
					35.37527643251494 139.6210117866997,
					35.37306314467156 139.6217413475337,
					35.37268696718477 139.62013202216457,
					35.37018828750506 139.61840497406456,
					35.370782160278 139.61705458898427,
					35.36947068533102 139.61641732865053,
					35.370596575495014 139.61476348635583,
					35.37078029225879 139.61403393574466,
					35.36864433631068 139.61438212951467,
					35.36653571408147 139.61453772192408,
					35.36394967 139.61846500
				))'
			),
		15000)
	)
	`
	rows, err := db.Query(query) // この25が生成する乱数座標

	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	var msg string

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

		// まずはMULTIPOINTをバラバラに分解する
		arr1 := regexp.MustCompile("[() ,]").Split(msg, -1) // '('か、')'か、' 'か、","で分割する → "[中身]" という構造でまぎらわしい

		// 2つの値を一度に取得する (最初の値" MULTIPOIN"をスキップする為に、i:=1から始める)
		for i := 1; i < len(arr1); i += 2 {
			// arr1[i]とarr1[i+1]は2つの値を表します
			if i+1 < len(arr1) {
				value1, _ := strconv.ParseFloat(arr1[i], 64)   // 乱数の緯度
				value2, _ := strconv.ParseFloat(arr1[i+1], 64) // 乱数の経度
				fmt.Println(i, value1, value2)
			}
		}
	}
}

ポイントは、指定された多角形内に均等に分布する乱数の座標を生成 という点です。

どういう仕組みか分かりませんし、ChatGPTが真実を言っているのかも不明ですが、『postGISなら、その程度の仕組みは入れてくるだろう』と期待して、今回は、こちらを使うことにしました。

以上