首页 > 代码库 > 分形算法小记
分形算法小记
模式替换的分形,通常都可以使用L系统表示,想那些雪花曲线之类的都是模式替换分形的。L系统是指一个字符序列,这个字符序列内的某些子序列可以按照规则替换为特定的序列(通常更长),序列中的不同字符有不同的含义。比如改变绘制方向和绘制一条线段等等。
通过L系统可以绘制出非常接近真实的植物来,当然也可以绘制出其他的曲线。
package main import ( "github.com/hydra13142/paint" "image" "image/color" "image/png" "os" ) const ( D = 6 ) var ( X, Y, N = 6, 1536, 0 img = paint.Image{image.NewRGBA(image.Rect(0, 0, 1543, 1543)), color.RGBA{50, 125, 50, 255}, color.RGBA{50, 50, 100, 255}} ) type Lsystem struct { rp map[byte][]byte do map[byte]func() ch chan byte } func NewLsystem(a map[byte]string, b map[byte]func()) *Lsystem { c := make(map[byte][]byte, len(a)) for k, v := range a { c[k] = []byte(v) } return &Lsystem{c, b, nil} } func (l *Lsystem) Init(s string, n int) { step := func(in <-chan byte) chan byte { ex := make(chan byte) go func() { for { c, ok := <-in if !ok { break } s, ok := l.rp[c] if !ok { ex <- c } else { for _, c = range s { ex <- c } } } close(ex) }() return ex } var p, q chan byte p = make(chan byte) for q = p; n > 0; n-- { q = step(q) } l.ch = q go func() { for _, c := range []byte(s) { p <- c } close(p) }() } func (l *Lsystem) Run() { for { c, ok := <-l.ch if !ok { break } f, ok := l.do[c] if ok { f() } } } func main() { // 绘制背景色 img.Bar(0, 0, 1542, 1542) draw := func() { var x, y int switch N % 4 { case 1, -3: x, y = X, Y+D case 2, -2: x, y = X-D, Y case 3, -1: x, y = X, Y-D case 0: x, y = X+D, Y } img.Line(X, Y, x, y) X, Y = x, y } lsys := NewLsystem( map[byte]string{ ‘L‘: "+RF-LFL-FR+", ‘R‘: "-LF+RFR+FL-", }, map[byte]func(){ ‘+‘: func() { N++ }, ‘-‘: func() { N-- }, ‘F‘: func() { draw() }, }, /* 如果换成下面两个参数,则会绘制龙形曲线 map[byte]string{ ‘A‘: "-A+B+A-B", ‘B‘: "A+B-A-B+", }, map[byte]func(){ ‘+‘: func() { N++ }, ‘-‘: func() { N-- }, ‘A‘: func() { draw() }, ‘B‘: func() { draw() }, }, */ ) lsys.Init("R", 8) lsys.Run() // 写入文件保存 f, e := os.Create("frac.png") if e != nil { println("error") } defer f.Close() png.Encode(f, img) }
以上是一个模式匹配分形的例子,绘出来的图还是很漂亮的,可以作壁纸/桌面,如下:
这个小程序里,我使用了串联的管道来进行多次的模式替换,如果是c++等语言,则需要采用类似任务队列的方式来进行处理(或者也使用多线程)。go可以用管道,可以节省很多内存。
另一种分形是迭代式分形。这种分形不是严格自相似的,但往往更漂亮。
package main import ( "image" "image/color" "image/png" //"math" "os" ) func repeat(i, j int) color.RGBA { x := float64(i-3500) / 2000 y := float64(j-2500) / 2000 a := 0.0 b := 0.0 for t := 0; t < 256; t++ { m := a * a n := b * b o := a * b a = m - n + x b = o + o + y if m+n > 4 { return color.RGBA{uint8(t), uint8(t), uint8(t), 255} } } return color.RGBA{255, 255, 255, 255} } func main() { file, _ := os.Create("mdb.png") defer file.Close() img := image.NewRGBA(image.Rect(0, 0, 5000, 5000)) defer png.Encode(file, img) for i := 0; i < 5000; i++ { for j := 0; j < 5000; j++ { c := repeat(i, j) img.Set(i, j, c) } } }
最常见的迭代式分形。
以下是绘制结果的一部分(完整的图比这个大多了)
分形算法小记
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。