- 投稿日:2019-01-26T19:08:37+09:00
TILE38紹介(2) :空間系コマンド
TL;DR
- 前回記事で基本的なコマンドとして点データの格納と距離にとる参照を紹介した。今回は線やポリゴン(多角形)のデータの格納と検索を実現するコマンドを紹介する。
コマンド
コマンド どんな機能 WITHIN 指定された地図条件範囲内のデータの検索 INTERSECTS 線や多角形などの図形と直行するデータまたは含まれるデータの検索 バウンダリの検索
- 複数個登録した境界(バウンダリ:東西南北に沿った境界線)を中心点からの距離で検索する。
127.0.0.1:9851> SET example bounds:X BOUNDS 35.6578 139.6971 35.6581 139.6968 {"ok":true,"elapsed":"6.335µs"} 127.0.0.1:9851> SET example bounds:Y BOUNDS 35.6572 139.6984 35.6575 139.6978 {"ok":true,"elapsed":"3.575µs"} 127.0.0.1:9851> SET example bounds:Z BOUNDS 35.6590 139.6967 35.6594 139.6959 {"ok":true,"elapsed":"13.362µs"} 127.0.0.1:9851> WITHIN example IDS CIRCLE 35.6581 139.6975 120 {"ok":true,"ids":["bounds:X"],"count":1,"cursor":0,"elapsed":"66.094µs"}
- バウンダリを3つ登録して、WITHIN検索を実行した。
- WITHINでは現在地から半径120メートルを検索範囲とした。
- WITHINは検索範囲内に完全に含んでいるオブジェクトを対象とするため、図の領域Xのみが検索結果となり、領域Y、Zは結果に入らない。
- NEARBYとの違いは、点だけではなく平面領域を検索対象とできることである。
127.0.0.1:9851> INTERSECTS example IDS CIRCLE 35.6581 139.6975 120 {"ok":true,"ids":["bounds:X","bounds:Y"],"count":2,"cursor":0,"elapsed":"43.576µs"}
- コマンドをINTERSECTSにした場合は、検索範囲にオブジェクトの一部でも含まれていると検索結果の対象となることである。
線やポリゴンの検索
- TILE38の点(POINT),バンダリ(BOUNDS)を使用してきたが、GeoJsonを使用することで線やポリゴンなどの複雑な領域の検索が実現できることを説明する。
- GeoJsonは空間データとその属性情報に関するJSON形式のファイルフォーマットである。(Wikipedia)
- 空間データとしては点、線、ポリゴン(多角形)とその組み合わせを扱うことができる。
- 以下では検索基準となる領域となるポリゴンと、検索対象となる線、ポリゴンをデータベースに格納し、INTERSECTSコマンドで検索する。
127.0.0.1:9851> SET location me OBJECT {"type":"Polygon","coordinates":[[[35.6590,139.6982],[35.6589,139.6978],[35.6577,139.6965],[35.6574,139.6964],[35.6572,139.6966],[35.6575,139.6973],[35.6580,139.6988],[35.6587,139.6984],[35.6590,139.6982]]]} {"ok":true,"elapsed":"67.481µs"} 127.0.0.1:9851> SET example polygon:P OBJECT {"type":"Polygon","coordinates":[[[35.6587,139.6984],[35.6590,139.6983],[35.6589,139.6979],[35.6586,139.6980],[35.6587,139.6984]]]} {"ok":true,"elapsed":"43.118µs"} 127.0.0.1:9851> SET example polygon:Q OBJECT {"type":"Polygon","coordinates":[[[35.6591,139.6967],[35.6595,139.6960],[35.6589,139.6958],[35.6586,139.6965],[35.6591,139.6967]]]} {"ok":true,"elapsed":"37.007µs"} 127.0.0.1:9851> SET example road:R OBJECT {"type":"LineString","coordinates":[[35.6584,139.6954],[35.6567,139.6970]]} {"ok":true,"elapsed":"29.312µs"} 127.0.0.1:9851> SET example road:S OBJECT {"type":"LineString","coordinates":[[35.6585,139.6994],[35.6575,139.6953]]} {"ok":true,"elapsed":"55.785µs"} 127.0.0.1:9851> INTERSECTS example IDS GET location me {"ok":true,"ids":["polygon:P","road:S"],"count":2,"cursor":0,"elapsed":"71.981µs"}
- 検索基準となる領域(KEY:location,ID:me)として複雑な多角形(図:緑色)について、複数の検索対象(KEY:example)を検索した。
- 各領域はTILE38ではOBJECTとしてGeoJson形式でパラメータを渡して格納する。
- バウンダリの場合と同様に検索基準に全部または一部が含まれる領域が検索結果に含まれる。(図:青色)逆に検索基準に一部も含まれない領域(図:赤色)は検索結果に含まれない。
次章予定
- Redisクライアントライブラリを使用したGoプログラムからのアクセス。
- 投稿日:2019-01-26T18:14:26+09:00
【Golang】Interfaceの条件を満たしているかどうかをチェックする
type assertionを使うことで、変数の型を調べることができるが、同様にその構造体が特定のInterfaceの条件を満たしているかどうかのチェックをすることができる。
main.gopackage main import ( "fmt" ) type InterfaceA interface { doSomething() } //----InterfaceAの条件を満たす構造体Aを作成------ type A struct { } func (a A) doSomething() { fmt.Println("A has a doSomething method") } func tt(a InterfaceA) { a.doSomething() } func main() { //--interface{}として宣言-- var a interface{} a = A{} if p, ok := a.(InterfaceA); ok { //--変数pはA型の構造体!!--- p.doSomething() } }実行結果 A has a doSomething methodinterface型を受け取って、受け取ったものが満たしているinterface型に応じて処理内容を変更したりできる
- 投稿日:2019-01-26T16:54:12+09:00
rust-gdb を真似たgo-gdbという簡単gdb起動スクリプト
gdbでgolangをデバッグする方法
gdbでgolangをデバッグする方法は公式ドキュメントに書かれています。
Debugging Go Code with GDBしかし、オプションをつけたり、.gdbinit を作ったりしなくてはならないのでちょっと面倒くさい。
gdbでRustをデバッグするときもそのあたりの事情は同じはずなのですが、rust-gdbというコマンドがそのややこしさを隠蔽してくれています。go-gdbスクリプト
rust-gdb のshellスクリプト実装を見つけました。
https://github.com/rust-lang/rust/blob/master/src/etc/rust-gdb
これを真似てgolang用のものを作りました。go-gdb#!/bin/sh set -e GOROOT=`go env GOROOT` GO_GDB="${GO_GDB:-gdb}" exec ${GO_GDB} \ --directory="$GOROOT" \ -iex "add-auto-load-safe-path $GOROOT/src/runtime/runtime-gdb.py" \ "$@"gistにも置きました。
https://gist.github.com/tetsu-koba/648166471d7c3db6f02aa1ffec1f0259
これをPATHの通ったディレクトリに置く。(例えば ~/bin )
使用例
$ go-gdb hello GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from hello...done. Loading Go Runtime support. (gdb)このように起動した時に
Loading Go Runtime support.
が出ていればOK。
golangのmain関数の先頭まで実行してブレークさせるにはstart
コマンドが便利。(gdb) start Temporary breakpoint 1 at 0x483880: file /home/koba/go/src/hello/hello.go, line 5. Starting program: /home/koba/go/src/hello/hello [New LWP 2361] [New LWP 2362] [New LWP 2363] Thread 1 "hello" hit Temporary breakpoint 1, main.main () at /home/koba/go/src/hello/hello.go:5 5 func main() { (gdb)goroutineの一覧を見るには
info goroutine
。省略してinfo go
でもOK。(gdb) info go * 1 running runtime.systemstack_switch 2 waiting runtime.gopark 17 waiting runtime.gopark 18 waiting runtime.gopark (gdb)残念ながらgoroutineの切り替えはエラーになってしまって現状は使えない。
(gdb) goroutine 2 Python Exception <class 'ValueError'> not enough values to unpack (expected 2, got 1): Error occurred in Python command: not enough values to unpack (expected 2, got 1) (gdb)emacsの中からgo-gdb を起動する
M-x gdbを実行して、
Run gdb (like this): gdb -i=mi helloこれを以下のように書き換えるだけ。
Run gdb (like this): go-gdb -i=mi hello補足情報
gdbはpython拡張機能が有効になったものが必要です。ubuntuのaptでインストールできるものはそうなっているので大丈夫。
自分でgdbをビルドする時には、sudo apt install libpython-dev
をしておくこと。
- 投稿日:2019-01-26T16:03:24+09:00
chroma をつかってコードハイライトを生成するサンプル
go のコードの一部です。
type Ping struct { Status int Result string } func Sample(w http.ResponseWriter, r *http.Request) { lexer := lexers.Get("ruby") style := styles.Get("monokai") if style == nil { style = styles.Fallback } formatter := html.New(html.WithClasses()) iterator, err := lexer.Tokenise(nil, "def hoge; x=3; 6; end") buf := new(bytes.Buffer) err = formatter.Format(buf, style, iterator) if err != nil { fmt.Println(err) } sourceCode := buf.String() ping := Ping{http.StatusOK, sourceCode} res, _ := json.Marshal(ping) w.Header().Set("Content-Type", "application/json") w.Write(res) }これで、以下のような json を得る。