2023,江端さんの技術メモ

ODデータ(csv):20220518weekday

領域データ(csv):yamaguchi_area

出力データ(csv):new_20220518weekday

その他: 年齢を乱数を使って適当に作成しているコードも入っている

// ~/yamaguchi/src_try1/others/main61.go

// Usage: go run main61.go 20220518weekday.csv new_20220518weekday.csv

package main

import (
	"database/sql"
	"encoding/csv"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"

	_ "github.com/lib/pq"
)

func main() {

	file, err := os.Open("yamaguchi_area.csv")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	r := csv.NewReader(file)
	rows, err := r.ReadAll() // csvを一度に全て読み込む
	if err != nil {
		log.Fatal(err)
	}

	str := "SELECT ST_Covers(st_geomfromtext('POLYGON(("

	// 行ごとに
	for i, row := range rows {
		if i == 0 {
			continue // CSVのヘッダー行を無視
		}

		str += row[1] + " " + row[2] + ", " // rowのままで取り出せば、文字列になっている

	}
	str1 := str[:len(str)-2] + "))'),st_geomfromtext('LINESTRING(" // 上記の最後の", "を削除して、文字列を追加

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

	///////////////////////////////////////

	//file2, err2 := os.Open("20220518weekday.csv")
	file2, err2 := os.Open(os.Args[1]) // 第1パラメータ
	if err2 != nil {
		log.Fatal(err2)
	}
	defer file2.Close()

	r2 := csv.NewReader(file2)
	rows2, err2 := r2.ReadAll() // csvを一度に全て読み込む
	if err != nil {
		log.Fatal(err2)
	}

	file3, err3 := os.Create(os.Args[2]) // 第2パラメータ
	if err3 != nil {
		panic(err)
	}

	w := csv.NewWriter(file3)

	var id int

	for _, row := range rows2 {
		//if i == 0 {
		//	continue // CSVのヘッダー行を無視
		//}

		str2 := str1 + row[0] + " " + row[1] + ", " + row[2] + " " + row[3]

		str2 += ")'))"

		fmt.Println(str2)

		rows1, err := dbMap.Query(str2)
		if err != nil {
			log.Fatal(err)
		}
		defer rows1.Close()

		//var dt string
		var dt bool

		for rows1.Next() {
			if err := rows1.Scan(&dt); err != nil {
				fmt.Println(err)
			}
			// fmt.Println(dt)
			if dt {

				//if err := rows.Scan(&id, &age, &type1, &departure_name, &departure_number, &departure_lat, &departure_lng, &arrival_name, &arrival_number, &arrival_lat, &arrival_lng); err != nil {
				//	fmt.Println(err)
				// 上記のSQLのフォームと同じ形でcsvファイルを作る

				var age int

				fmt.Println("row[4]:", row[4])

				// id_str := strconv.Itoa(id) // idを文字列に
				if row[4] == "10-15" {
					age = 10 + rand.Intn(5)
				} else if row[4] == "15-29" {
					age = 15 + rand.Intn(5)
				} else if row[4] == "20-24" {
					age = 20 + rand.Intn(5)
				} else if row[4] == "25-29" {
					age = 25 + rand.Intn(5)
				} else if row[4] == "30-34" {
					age = 30 + rand.Intn(5)
				} else if row[4] == "35-39" {
					age = 35 + rand.Intn(5)
				} else if row[4] == "40-44" {
					age = 40 + rand.Intn(5)
				} else if row[4] == "44-49" {		
					age = 45 + rand.Intn(5)
				} else if row[4] == "50-54" {
					age = 50 + rand.Intn(5)
				} else if row[4] == "55-59" {
					age = 55 + rand.Intn(5)
				} else if row[4] == "60-64" {
					age = 60 + rand.Intn(5)
				} else if row[4] == "65-69" {
					age = 65 + rand.Intn(5)
				} else if row[4] == "70-74" {
					age = 70 + rand.Intn(5)
				} else if row[4] == "75-80" {
					age = 75 + rand.Intn(5)
				} else if row[4] == "80-84" {
					age = 80 + rand.Intn(5)
				} else if row[4] == "85-89" {
					age = 85 + rand.Intn(5)
				} else if row[4] == "90-94" {
					age = 90 + rand.Intn(5)
				} else if row[4] == "95-99" {
					age = 95 + rand.Intn(5)
				} else {
					age = 15 + rand.Intn(65) // 15箸キ79までの乱数
				}

				type1 := "resident"
				departure_name := ""
				_row1, _ := strconv.ParseFloat(row[1], 64)
				_row0, _ := strconv.ParseFloat(row[0], 64)

				departure_number, departure_lng, departure_lat := fixPosition(dbMap, _row1, _row0) // row[1], row[0]の順番に注意

				arrival_name := ""
				_row3, _ := strconv.ParseFloat(row[3], 64)
				_row2, _ := strconv.ParseFloat(row[2], 64)
				arrival_number, arrival_lng, arrival_lat := fixPosition(dbMap, _row3, _row2) // row[3], row[2]の順番に注意

				output := []string{fmt.Sprint(id), fmt.Sprint(age), type1, departure_name, fmt.Sprint(departure_number), fmt.Sprint(departure_lat), fmt.Sprint(departure_lng), arrival_name, fmt.Sprint(arrival_number), fmt.Sprint(arrival_lat), fmt.Sprint(arrival_lng)}

				//output := []string{row[0], row[1], row[2], row[3], row[4]}
				fmt.Println("output:", output)

				if err = w.Write(output); err != nil {
					log.Fatal(err)
				}

				id++ // idの加算
			}
		}

		err = rows1.Err()
		if err != nil {
			panic(err)
		}

		defer w.Flush()

		if err := w.Error(); err != nil {
			log.Fatal(err)
		}

	}
}

// 指定した座標に近いDB上の座標を取得
func fixPosition(db *sql.DB, _x1, _y1 float64) (int, float64, float64) {

	// Scan用の仮変数
	var source int
	var longitude float64
	var latitude float64
	var dist float64

	upperLimitMeter := 1500.0 // 近傍ノードの上限を1500 mに設定
	str := fmt.Sprintf(
		// 修正前: ways (道) の中から最近傍を取得
		// "SELECT source, x1 AS longitude, y1 AS latitude, ST_Distance('SRID=4326;POINT(%v %v)'::GEOGRAPHY, the_geom) AS dist FROM ways WHERE ST_DWithin(the_geom, ST_GeographyFromText('SRID=4326;POINT(%v %v)'), %.1f) ORDER BY dist LIMIT 1",
		// 修正後: ways_vertices_pgr (点座標) の中から最近傍を取得
		"SELECT id AS source, lon AS longitude, lat AS latitude, ST_Distance('SRID=4326;POINT(%v %v)'::GEOGRAPHY, the_geom) AS dist FROM ways_vertices_pgr WHERE ST_DWithin(the_geom, ST_GeographyFromText('SRID=4326;POINT(%v %v)'), %.1f) ORDER BY dist LIMIT 1",
		_x1, _y1, _x1, _y1, upperLimitMeter,
	)
	//fmt.Println(str)

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

	foundGoodMapNode := false

	for rows.Next() {
		foundGoodMapNode = true
		if err := rows.Scan(&source, &longitude, &latitude, &dist); err != nil {
			fmt.Println(err)
		}
		//fmt.Println(source, longitude, latitude, dist)
	}

	if !foundGoodMapNode {
		log.Println("Warning: in func fixPosition: Good Map Node not found for query point (",
			_x1, ",", _y1, ")")
	}

	return source, longitude, latitude
}

2023,江端さんの技術メモ

strconv.FormatFloatだの、strconv.FormatIntだの、色々あるけど、

fmt.Sprint(x)  xは、整数でも実数でも可

で十分だと思う。

2023,江端さんの忘備録

今年の下半期からの忙しさは凄かったと思います。

I think I have been very busy since the second half of this year.

それでも、なんとか凌げていたので『なんとかなるもんだなぁ』とか思っていました。

Still, I managed to get by, so I thought, 'I guess I can get by'.

しかし、歯痛→腰痛→風邪による全身疲労が、ここ2週間くらい立て続けで発生し、予定通りに物事が進んでいません。

However, things have not been going as planned due to a series of dental pain, back pain, and general fatigue caused by a cold that has been occurring in rapid succession for the past two weeks.

「パフォーマンスが発揮できない」 → 「予定した仕事が進まない」 → 「焦る」 という段階までは、よくあるのですが、今は、

I have often experienced the "I can't perform" → "I can't get the work done" → "I'm in a hurry" phase. However Now the situation is as follows.

『何か考えようとすると、吐き気がする』

'I get nauseous when I try to think about anything'

という状況です。

こうなると、もう、何もできなくなります

When this happens, there is nothing more that can be done.

こういう状況になって、普段の自分を俯瞰すると、

In situations like this, when I look down on my normal,

―― 私、一体、何のために、毎日あんなに頑張っていたんだっけ?

"What in the world was I working so hard every day for?"

という気持ちになってきます。

This is the feeling I have now

-----

多分、私は、この状態が回復したら、こんなことを忘れたかのように、自分のことや、他人のことを言い始めると思います。

Maybe when I recover from this condition, I will start talking about myself and others as if I have forgotten all this.

しかし、今の『弱っていて、何もできないこの状態の自分がデフォルト』である、ということを覚えておくために、この日記を残しておきます。

However, I leave this diary to remember that I am now 'weak and unable to do anything about this situation', which is my default.

被災して、罹患して、心が壊れて、疲れ果てて、立ち上がることもできない人々に、『がんばれ』とだけ言い放つ人間にだけは決してなるまい、と、再度、自分に言い聞かせるためにも。

To remind myself once again that I will never make me a person who only says, "Hang in there," to people who have been affected by the disaster, who have been afflicted, who are broken, exhausted, and unable to stand up.

今は頑張らなくていいんですよ

 

2023,江端さんの忘備録

■日中、倦怠感でだるさを感じる

- Feels tired throughout the day

■夜中に咳で目がさめる。

- Wake up at night with a cough.

■喉にタンが絡む。タンを切る時に痛みがある

- Phlegm in throat. Pain when cutting phlegm.

■夜寝る前に猛烈な悪寒がある

- Violent chills before going to bed at night.

■夜中にぐっしょりの汗をかく

- Sweating profusely at night

■水は定期的に摂取している。

- Water is consumed regularly.

■市販薬は、「改源」と「コンタックEX」を摂取したが、改善は見られない

- Over-the-counter medications were ingested "Kaigen" and "Contac EX", but no improvement was seen

-----

というメモを作って、本日クリニックに行ってきました。

I went to the clinic today after making the note.

コロナかインフルエンザか、とも思ったのですが、熱が36.6度なので、どっちでもないだろうなと思いました。

I thought it might be corona or influenza, but since my fever was 36.6 degrees, I thought it could be neither.

それでも、発熱者扱いとして、診察室の外で待たされました ―― 窓が開けっぱなしの廊下は寒かったです。

Still, I was treated as a fever patient and made to wait outside the examination room -- it was cold in the hallway with the windows left open.

-----

薬を貰って、早速飲みました。

I got the medicine and took it immediately.

その一時間後ですが、さっきまで指一本動かせない倦怠感の中にいたのですが、、現在は、この文章を書ける状態になっています(まだ、倦怠感はあります)。

An hour later, I was in a state of fatigue where I could not move a finger, but now I am able to write this sentence (I still have the fatigue).

やっぱり処方薬は凄いなぁ、と思いました、

I knew that prescription drugs were great.

2023,江端さんの忘備録

私が自分のブログで、頻繁に、短いプログラムをアップロードしているのは、マニュアル読んだって、APIの使い方が分からないからです。

I frequently upload short programs on my blog because I don't know how to use the API even after reading the manual.

このようなマニュアル読んでもさっぱり分からないし、サンプルプログラムは、私のやりたいこととズレています。

I have no idea what I'm doing by reading these manuals, and the sample programs are out of sync with what I want to do.

ですので、以下のように、

So, as shown in the following

golangによるcsvファイルのライン単位での書き出し方法

実際に、自分で書いて動いたコードを、小まめに残するようにしています。

In reality, I try to keep a small code that I have written and worked with.

他の人の役に立つかどうかは、二の次です。

Whether it is useful to others is secondary.

この方法に名前をつけるとすれば「具体例ベース」というのかもしれません。

If I had to give a name to this method, it might be called "concrete example-based".

それはさておき。

Aside from that.

-----

イベントの招待状などで、『平服にてご参加下さい』という文言が入っていることがありますが ――

In invitations to events, you may see the phrase, "Please attend in plain clothes.

私に言われれば、これは、最低最悪のホスピタリティです。

If you ask me, this is hospitality at its worst.

つまり『礼服はやめてね』と言っているだけで、カジュアルのレベルの判断をゲストに押しつける、無責任極まりない要求であるからです。

In other words, he/she is simply saying, 'Please don't wear formal wear,' and you are forced to judge the level of casual wear. This is an extremely irresponsible request.

ゲスト(招待客)は、カジュアルのレベルを間違えて、会場で恥しい思いをするかもしれません ―― しかし、そういう配慮をするホスト(主催者)には、滅多にお目にかかることができません。

Guests (invitees) may be embarrassed at the venue because of the wrong level of casualness -- but I rarely see a host (organizer) who takes such considerations into account.

-----

先日、父と母の納骨供養の案内を出しました。

I recently sent out information about the event laying their ashes to rest for my father and mother.

江端一夫・瑤子 納骨供養のご案内(公開版)

その中で、私は、ドレスコードを以下のような文章で、正確に規定しました。

In it, I have defined the dress code precisely in the following sentence.

『ご都合がよろしければ、平服にて御気軽にお立ち寄りをご検討頂ければ幸いです』

I hope you will consider stopping by in plain clothes if it is convenient for you.

『(私(智一)は、ジーパンとスニーカーと数珠持参で参加予定です)』

I (Tomoichi) will wear jeans, sneakers and prayer beads.

このように、ホストが、ホスト自身のドレスコードを具体的に提示することで、ゲストの負担を減らすことができます。

In this way, the host can reduce the burden on the guests by providing them with a specific dress code for themselves.

これが、「具体例ベース」です。

It is "concrete example-based".

-----

今後、「平服」を具体例で示さないホストには、このブログのURLをメールで送りつけようと考えています。

In the future, I will email the URL of this blog to hosts who do not provide specific examples of "plain clothes".

2023,江端さんの技術メモ

Keyword: golang csv write 書き出し ライン

package main

import (
	"database/sql"
	"encoding/csv"
	"fmt"
	"log"
	"os"

	_ "github.com/lib/pq"
)

func main() {
	file, err := os.Open("yamaguchi_area.csv")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	r := csv.NewReader(file)
	rows, err := r.ReadAll() // csvを一度に全て読み込む
	if err != nil {
		log.Fatal(err)
	}

	str := "SELECT ST_Covers(st_geomfromtext('POLYGON(("

	// 行ごとに
	for i, row := range rows {
		if i == 0 {
			continue // CSVのヘッダー行を無視
		}

		str += row[1] + " " + row[2] + ", " // rowのままで取り出せば、文字列になっている

	}
	str1 := str[:len(str)-2] + "))'),st_geomfromtext('LINESTRING(" // 上記の最後の", "を削除して、文字列を追加

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

	///////////////////////////////////////

	file2, err2 := os.Open("20220518weekday.csv")
	if err2 != nil {
		log.Fatal(err2)
	}
	defer file2.Close()

	r2 := csv.NewReader(file2)
	rows2, err2 := r2.ReadAll() // csvを一度に全て読み込む
	if err != nil {
		log.Fatal(err2)
	}

	file3, err3 := os.Create("testtest.csv")
	if err3 != nil {
		panic(err)
	}
	w := csv.NewWriter(file3)

	for _, row := range rows2 {
		//if i == 0 {
		//	continue // CSVのヘッダー行を無視
		//}

		str2 := str1 + row[0] + " " + row[1] + ", " + row[2] + " " + row[3]

		str2 += ")'))"

		//fmt.Println(str2)

		rows1, err := dbMap.Query(str2)
		if err != nil {
			log.Fatal(err)
		}
		defer rows1.Close()

		//var dt string
		var dt bool

		for rows1.Next() {
			if err := rows1.Scan(&dt); err != nil {
				fmt.Println(err)
			}
			// fmt.Println(dt)
			if dt {
				output := []string{row[0], row[1], row[2], row[3], row[4]}
				//fmt.Println("output:", output)

				if err = w.Write(output); err != nil {
					log.Fatal(err)
				}
			}
		}

		err = rows1.Err()
		if err != nil {
			panic(err)
		}

		defer w.Flush()

		if err := w.Error(); err != nil {
			log.Fatal(err)
		}

	}
}

重要なのは、以下のコード

file3, err3 := os.Create("testtest.csv")
if err3 != nil {
panic(err)
}

w := csv.NewWriter(file3)

output := []string{row[0], row[1], row[2], row[3], row[4]}
//fmt.Println("output:", output)

if err = w.Write(output); err != nil {
log.Fatal(err)
}

defer w.Flush()

2023,江端さんの忘備録

江端家では、テレビの音声を手元に届ける為に、FMトランスミッタ + ラジオを使ったシステムを使っています。

The Ebata family uses an FM transmitter + radio system to bring the TV sound to their hands.

『他の人たちは、ホワイトボードにスペックアウト(書き出す)せずに、他の人に自分の考えを伝えることができるのか?』と、いつも不思議に思っています。

上記の「豊作ラジオ」は、江端家で2台稼動中ですが、

Two of the above "bumper radios" are now in operation in the Ebata household.

下記の、固定局FMトランスミッタ(車載用を除く)は、販売されていないようです。

However, the following, fixed station FM transmitters (except for in-vehicle use) do not appear to be available for sale.

まあ、江端家では、まだ2台、予備の在庫を確保しているので大丈夫なのですが(先日、実家の一台を回収しました)。

Well, the Ebata family still has two of them in reserve, so we are fine (we recently retrieved one from my parents' house).

-----

最近、音声を認識できなくなることで、認知障害が進行しやすくなる、という研究結果のニュースを見ました。

I recently saw a news story about a study that found that the inability to recognize speech sounds can lead to progressive cognitive impairment.

「補聴器」の早期着用が推奨されていましたが、こういうラジオを使ったシステムも有効だと思います。

Early wearing of "hearing aids" was recommended, but I think this kind of radio-based system is also effective.

ラジオをどこに運んでも、音声が聞こえるのは、嬉しいです(例えば、私は2Fの書斎で、NHKスペシャルを「聞きながら」、プログラミングをしています)。

It is nice to be able to hear the audio wherever I carry the radio (for example, I am programming in my study on the 2nd floor while "listening" to the NHK special).

-----

ただ、そういう製品、結構販売されているようですので、無理して、このようなシステムを作る必要はないのかもしれません。

However, such products seem to be sold quite well, so there may be no need to force the creation of such a system.

しかし、「送信機(FMトランスミッタ)」だけ販売してで、どんなラジオでも対応O.K.というのは、結構「美味しい」と思うのですが、案外、一体型の方が、高齢者のニーズに合っているのかもしれません。

However, I think it is quite "good" to sell only a "transmitter (FM transmitter)" and any radio can be used with it, but perhaps the integrated type is better suited to the needs of the elderly.

-----

私は、ラジオの電池にも工夫しています。

I am also creative with my radio batteries.

電池2個だけで動くようにしたり、と、いろいろとチマチマとした省エネ対策しています。

I am taking various chiseled energy-saving measures, such as making it work with only two batteries.

2023,江端さんの技術メモ

簡単にできるみたいです。

package main

import (
	"fmt"
	"os"
)

func main() {
	//fmt.Printf("args count: %d\n", len(os.Args))
	//fmt.Printf("args : %#v\n", os.Args)

	// これでも拾えるし
	for i, v := range os.Args {
		fmt.Printf("args[%d] -> %s\n", i, v)
	}

	// こんな風にダイレクトにも取れる
	fmt.Println(os.Args[1])
	fmt.Println(os.Args[2])

}

出力結果

PS C:\Users\ebata\yamaguchi\src_try1\others> go run main7.go test1 test2
args[0] -> C:\Users\ebata\AppData\Local\Temp\go-build2152603201\b001\exe\main7.exe
args[1] -> test1
args[2] -> test2
test1
test2

2023,江端さんの忘備録

昨日の日記の中で紹介した私のコラムは、私が人生最初に公開したものです。

My column, published yesterday, was the first one I published in my life.

江端さんのひとりごと'94 「渋谷駅の惨劇」

これを、私、社内の同期のメーリングリストに流して、仲間から絶賛されたことで ―― 調子に乗りました。

I put this out to a mailing list of my peers in the company, and after receiving rave reviews from my peers -- I was in a good mood.

で、その後、ずーーーーーーと、文章を書き続けています。

And then, I've been writing ever since.

つまり、『調子に乗る』とか『いい気になる』ということが、人生のターニングポイントになることがある、ということです。

In other words, 'getting on a roll' or 'feeling good' can be a turning point in one's life.

-----

当然ですが、こんなこと(他人から絶賛されること)は、連続して続くことはありません。

Of course, this kind of thing (being praised by others) does not last continuously.

いずれ絶賛されなくなり、さらには、批判されるようになります。

Eventually, they will stop being acclaimed and even criticized.

すると、凹みます ―― 誰だってそうです。

Then you get depressed -- everyone does.

-----

この現象は、二次創作の小説などで、顕著に見られます。

This phenomenon is most noticeable in secondary novels.

私の知っている範囲で、二次創作の小説の中で、最後まで完遂しているものは、全体の1~2%程度です。

As far as I know, only 1-2% of all second novels are completed to the end.

途中で創作を投げ出してしまう人が、本当に多い。

There are so many people who give up creating in the middle of the process.

もちろん、二次創作者は、『自己満足』で『自分の娯楽』で、そして『無償』で行われているものです。

Of course, the secondary creators are 'self-satisfied', 'for their own amusement', and done 'for free'.

これを他人(読者)が批判するのは『酷』 ―― というよりは『不当』で『非礼』ですらあるとすら思います。

I think it is "harsh" -- or even "unfair" and "impolite" -- for others (readers) to criticize this.

それでも、壮大な伏線で物語を始めておいて、それを回収せず、完遂もしないのは、「作品に対して気の毒だ」とは思います。

Still, I do feel "sorry for the work" if you start a story with grand foreshadowing and never retrieve it or complete it.

-----

チヤホヤされなければ、書き続けることができない ―― 私は、この気持ちを『支持』します。

They can't keep writing if they don't get cheesed off -- I 'support' this sentiment.

しかし、しょせん他人は他人。他人は気紛れです。

But, after all, strangers are strangers. Strangers are freaks.

定常的に、自分をチヤホヤし続けてくれる人は、ほとんどいません(というか「いません」)。

There are few (or rather, "no") people who will keep you constantly cheer for you.

それ故、

Hence,

―― 私(江端)だけは、いつまでも私(江端)自身をチヤホヤし続けること

"I will continue to cheer myself forever"

は、とても大切なことなのです。

is very important for me.

-----

(以下、「日本最高峰のブロックチェーンは、世界最長を誇るあのシステムだった」より抜粋)

(The following is an excerpt from "Japan's highest blockchain was that system that boasts of being the world's longest.)

江端:「別にいいんだ。私の書いたコラムは、『たった一人の読者に届けばいい』って思っているから」

Ebata: "It doesn't matter. I just want my columns to reach just one reader."

後輩:「何ですかそれ、初めて聞きましたよ。その意味深な言葉。江端さんが、その”思い”を伝えたいたった一人の方って、一体誰です?」

Junior: "What is that? I've never heard that before. That's the first time I've heard such a meaningful word. Who is the one person to whom you want to convey your "feelings"?"

江端:「“私”」

Ebata: "It's me"

後輩:「……は?」

Juniors: "What?"

江端:「だから、“私”。私、自分のコラム読み返すのが好きなんだよねー。読み直す度に『あの時の私って、すごいこと考えていたんだなぁ』とか、『ああ、こういう考え方、いいわー、合うわー、この人好きだわー』って思うもん』

Ebata: "So, "It is me". I like to reread my columns. Every time I reread it, I think, 'I was thinking such great things at that time,' or 'Oh, I like this way of thinking, it fits well, I like this person.

2023,江端さんの技術メモ

keyword: postgres postgis st_geomfromtext ST_Covers POLYGON LINESTRING

早い話、

postgres=# \c yama_db
psql (13.4, server 12.5 (Debian 12.5-1.pgdg100+1))
You are now connected to database "yama_db" as user "postgres".

yama_db=# SELECT ST_Covers(st_geomfromtext('POLYGON((34.15131035 131.5194525, 34.16270729 131.5152409, 34.16516798 131.5115994, 34.16898442 131.5047413, 34.17907707 131.5010998, 34.18354557 131.4989149, 34.18561453 131.5025188, 34.18856404 131.5058416, 34.18909138 131.5050188, 34.19687848 131.5103978, 34.19927298 131.5072766, 34.20121465 131.510747, 34.20300086 131.5120785, 34.20536452 131.5096798, 34.20975399 131.5068729, 34.20709501 131.5009018, 34.20388724 131.5048315, 34.20194564 131.5047294, 34.19785124 131.4988093, 34.20194564 131.4969721, 34.20528011 131.4932975, 34.20114366 131.4948286, 34.19802009 131.4962576, 34.19894873 131.4931955, 34.19705211 131.4916877, 34.19973769 131.4886834, 34.19579714 131.490747, 34.19717761 131.4888048, 34.19802009 131.4962576, 34.20061613 131.483555, 34.19383935 131.482506, 34.19306821 131.4800321, 34.18962489 131.4802896, 34.20041552 131.4735871, 34.19870882 131.4691668, 34.19193378 131.4719122, 34.19281714 131.4631425, 34.18750372 131.4649829, 34.18208468 131.4692086, 34.17814677 131.4619382, 34.18089338 131.4606752, 34.18352048 131.465583, 34.18537135 131.4575717, 34.18358019 131.4532773, 34.17689286 131.4597008, 34.17568909 131.4574644, 34.17805351 131.453254, 34.18115671 131.4490436, 34.18094562 131.4462621, 34.17766341 131.4457491, 34.17637565 131.444856, 34.17452943 131.4472807, 34.17400259 131.4457099, 34.1745741 131.4435783, 34.17591761 131.4391215, 34.17349927 131.4370465, 34.171469 131.4367036, 34.17997306 131.4313284, 34.17831615 131.4270193, 34.16993073 131.4276566, 34.17045141 131.4197235, 34.16662955 131.4242344, 34.17054098 131.4093664, 34.16585321 131.4150321, 34.16292695 131.4256418, 34.16209086 131.4305497, 34.15853738 131.4324262, 34.1555247 131.431539, 34.1368104 131.4231705, 34.13155312 131.4262604, 34.13252285 131.4303061, 34.12981919 131.4361751, 34.12994592 131.4412276, 34.13256509 131.4488319, 34.13167796 131.4539864, 34.13486474 131.4591635, 34.13933143 131.4660729, 34.14099198 131.4710403, 34.14447279 131.4734114, 34.14677254 131.4766944, 34.14983145 131.488296, 34.14860698 131.5025144, 34.15034783 131.5173554, 34.15131035 131.5194525))'),st_geomfromtext('LINESTRING(34.17282136235268 131.4810495539796, 34.17234106467595 131.47746432882846)'));

というSQL文をGoプログラムで作る。

(1)csvファイル(84点)からなる領域を作っておいて、エリアデータ
(2)ODデータを直線として取り込み、直線データ
(3)上記(2)の直線が、上記(1)の領域に入っているかどうかを調べて、入っている場合は標準出力で出力する


// ~/yamaguchi/src_try1/others/main6.go

package main

import (
	"database/sql"
	"encoding/csv"
	"fmt"
	"log"
	"os"

	_ "github.com/lib/pq"
)

func main() {
	file, err := os.Open("yamaguchi_area.csv")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	r := csv.NewReader(file)
	rows, err := r.ReadAll() // csvを一度に全て読み込む
	if err != nil {
		log.Fatal(err)
	}

	str := "SELECT ST_Covers(st_geomfromtext('POLYGON(("

	// 行ごとに
	for i, row := range rows {
		if i == 0 {
			continue // CSVのヘッダー行を無視
		}

		str += row[1] + " " + row[2] + ", " // rowのままで取り出せば、文字列になっている

	}
	str1 := str[:len(str)-2] + "))'),st_geomfromtext('LINESTRING(" // 上記の最後の", "を削除して、文字列を追加

	dbMap, err := sql.Open("postgres",
		"user=postgres password=password host=192.168.0.23 port=15432 dbname=yama_db sslmode=disable")
	// log.Println("------------------ map db open ------------------")
	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer dbMap.Close()

	///////////////////////////////////////

	file2, err2 := os.Open("20220518weekday.csv")
	if err2 != nil {
		log.Fatal(err2)
	}
	defer file2.Close()

	r2 := csv.NewReader(file2)
	rows2, err2 := r2.ReadAll() // csvを一度に全て読み込む
	if err != nil {
		log.Fatal(err2)
	}

	for _, row := range rows2 {
		//if i == 0 {
		//	continue // CSVのヘッダー行を無視
		//}

		str2 := str1 + row[0] + " " + row[1] + ", " + row[2] + " " + row[3]

		str2 += ")'))"

		//fmt.Println(str2)

		rows1, err := dbMap.Query(str2)
		if err != nil {
			log.Fatal(err)
		}
		defer rows1.Close()

		//var dt string
		var dt bool

		for rows1.Next() {
			if err := rows1.Scan(&dt); err != nil {
				fmt.Println(err)
			}
			// fmt.Println(dt)
			if dt {
				output := row[0] + "," + row[1] + "," + row[2] + "," + row[3] + "," + row[4]
				fmt.Println(output)
			}

		}

	}
}