今回はヒルベルト曲線っす。フラクタルの定番。ダフィット・ヒルベルト大先生の御発見。空間を埋め尽くす空間充填曲線のひとつであります。勿論埋め尽くすところまで描かないけれど。プログラムは簡単。そのうえGWだし、ということでスマホ上でプログラムせず、Ubuntu20.04LTS上のGo言語で実習。手抜き。
※「やっつけな日常」投稿順 indexはこちら
超有名なフラクタル図形なので、解説ページなど多数発見(ぐぐっただけですが。)数学的な意味など説明しているページが多いなかで、以下のページがあり、純粋プログラミング的にこの手の図形を多数取り扱われていて感服いたしました。
一か所、lurと書くべきところを lru と書かれているような(druの定義の中)。コマケー話ですが。
当方作成のGo言語版の実験プログラム
冒頭のアイキャッチ画像を描くのに使ったプログラムが以下です。Go言語のお勉強としてはほとんど進歩なし。今までに学んだことの繰り返し。忘却力に対抗するためには反復練習必要だと言い訳させていただきましょう。パラメータのうち、以下が重要であります。
-
- -order オーダーを与える、アイキャッチ画像は5。多くすると急激に複雑になり計算量は増えていく。
- -siz 一遍の長さのパラメータ。1.0とすると画像上の10ドットになるので適宜調整。
なお、自作の local/turtle モジュールに1関数追加してしまったので、そちらのソースを末尾に掲げました。本体コードが以下に(勿論スマホ上のGoでも走るはず。)
Hilbert.go
package main import ( "flag" "fmt" "local/turtle" "local/ppm" ) func dru(t *turtle.TurtleGraphics, order int, siz float64) { if order == 0 { return } else { rdl(t, order - 1, siz) t.Step(0, -siz) dru(t, order - 1, siz) t.Step(siz, 0) dru(t, order - 1, siz) t.Step(0, siz) lur(t, order - 1, siz) } } func rdl(t *turtle.TurtleGraphics, order int, siz float64) { if order == 0 { return } else { dru(t, order - 1, siz) t.Step(siz, 0) rdl(t, order - 1, siz) t.Step(0, -siz) rdl(t, order - 1, siz) t.Step(-siz, 0) uld(t, order - 1, siz) } } func lur(t *turtle.TurtleGraphics, order int, siz float64) { if order == 0 { return } else { uld(t, order - 1, siz) t.Step(-siz, 0) lur(t, order - 1, siz) t.Step(0, siz) lur(t, order - 1, siz) t.Step(siz,0) dru(t, order - 1, siz) } } func uld(t *turtle.TurtleGraphics, order int, siz float64) { if order == 0 { return } else { lur(t, order - 1, siz) t.Step(0, siz) uld(t, order - 1, siz) t.Step(-siz, 0) uld(t, order - 1, siz) t.Step(0, -siz) rdl(t, order - 1, siz) } } func main() { sz := flag.Float64("siz", 0.2, "Size") order := flag.Int("order", 3, "Order") fnam := flag.String("f", "Hilbelt_default.ppm", "PPM file name") verbose := flag.Bool("v", false, "verbose flag") flag.Parse() var img ppm.PpmImage XMAX:= 512 YMAX:= 512 img.InitPpmImage(XMAX, YMAX, 256) img.Verbose = *verbose var ttl turtle.TurtleGraphics ttl.InitTurtleGraphics(1, 1, 10.0, img.Line) ttl.Color(255, 0, 128) dru(&ttl, *order, *sz) if img.FwritePPM(*fnam) { fmt.Println("Success.") } else { fmt.Println("PPM file genaration, failed.") } }
描けましたな。それだけかよ。GWだからって言って手抜きだな。自分。
やっつけな日常(14) スマホでGo!パラメータを変えると飽きない2分木?を描く へ戻る
やっつけな日常(16) スマホでGo!じゃない。「外部コマンドを実行」でコケたトホホな理由 へ進む
tutle.go 改訂版
package turtle import "math" type LineFunc func(x1 int, y1 int, x2 int, y2 int, r int, g int, b int) bool type TurtleGraphics struct { xpos float64 ypos float64 direction float64 ijSCALE float64 iORG int jORG int ipos int jpos int iold int jold int colR int colG int colB int penDOWN bool line LineFunc verbose bool } func (t *TurtleGraphics) InitTurtleGraphics(x int, y int, sca float64, lf LineFunc) bool { t.xpos = 0.0 t.ypos = 0.0 t.direction = 0.0 t.colR = 128 t.colG = 128 t.colB = 128 t.penDOWN = true t.verbose = false t.line = lf t.ijSCALE = sca t.iORG = x t.jORG = y t.ipos = x t.jpos = y return true } func(t *TurtleGraphics) Mov(dist float64) bool { t.xpos += math.Cos(t.direction)*dist t.ypos += math.Sin(t.direction)*dist t.iold = t.ipos t.jold = t.jpos t.ipos = int(math.Round(t.xpos * t.ijSCALE)) + t.iORG t.jpos = t.jORG - int(math.Round(t.ypos * t.ijSCALE)) if t.penDOWN { t.line(t.iold, t.jold, t.ipos, t.jpos, t.colR, t.colG, t.colB) } return true } func(t *TurtleGraphics) Rot(theta float64) bool { rad := theta * math.Pi / 180 t.direction += rad if t.direction < (-math.Pi) { t.direction = 2.0*math.Pi + t.direction } else if t.direction > math.Pi { t.direction = t.direction - 2.0*math.Pi } return true } func(t* TurtleGraphics) Color(r int, g int, b int) { t.colR = r t.colG = g t.colB = b } func(t* TurtleGraphics) PenDown(x bool) { t.penDOWN = x } func(t *TurtleGraphics) Draw(x float64, y float64) bool { t.xpos = x t.ypos = y t.iold = t.ipos t.jold = t.jpos t.ipos = int(math.Round(t.xpos * t.ijSCALE)) + t.iORG t.jpos = t.jORG - int(math.Round(t.ypos * t.ijSCALE)) if t.penDOWN { t.line(t.iold, t.jold, t.ipos, t.jpos, t.colR, t.colG, t.colB) } return true } func(t *TurtleGraphics) Step(x float64, y float64) bool { t.xpos = t.xpos + x t.ypos = t.ypos + y t.iold = t.ipos t.jold = t.jpos t.ipos = int(math.Round(t.xpos * t.ijSCALE)) + t.iORG t.jpos = t.jORG - int(math.Round(t.ypos * t.ijSCALE)) if t.penDOWN { t.line(t.iold, t.jold, t.ipos, t.jpos, t.colR, t.colG, t.colB) } return true }