上次画了一棵分形树:用Python画一棵分形树,得到的图如下
发现看的人还是挺多的,但没什么人点赞,这说明我能给大家画分形树,大家很高兴,但这棵树太秃了,大家不喜欢。
分形树,就是用分形的逻辑去画一棵树,所谓分形,若从编程的角度去理解,其实就是简单规则的反复迭代。
例如,现在有一条线段,长为LLL,在这个线段的端点处再画两个线段,每个线段的长度为23L\frac23L32L,与前一个线段的夹角为±10°\pm 10°±10°,将这个规则不断进行下去,直到线段长度小于δ\deltaδ。
如想让分形树变得茂盛,第一步就是让树枝多一些分岔点,如果仍旧以线段为骨架,那么树枝将不在端点分岔,而在某个位置分岔。
不过无论如何变化,作为骨架的线段类是不会变的,变的是分岔方法,即getChild
。
import numpy as np
rand = lambda r : 1 + r*(np.random.rand()-0.5)class segment:def __init__(self, st, th, L):self.st = np.array(st)self.th = thself.L = Lself.setEd()def setEd(self):x, y = self.stth = np.deg2rad(self.th)dx = self.L*np.cos(th)dy = self.L*np.sin(th)self.ed = np.array([x+dx, y+dy])def getAxis(self):xs = (self.st[0], self.ed[0])ys = (self.st[1], self.ed[1])return (xs, ys)# dL表示树枝生长的位置def getChild(self, dTh, L, dL):st = (1-dL)*self.st + dL*self.edreturn segment(st, self.th+dTh, L)
接下来更改分形逻辑,由于这次的getChild
一次只产生一个子线段,所以在分形逻辑中,需要将生成子线段的个数也考虑进去。
def fractal(L, minL, dL, st=0.7, dTh=15, th0=90, rL=0.1, rTh=0.1):segs = [[segment((0,0), th0, L)]]while L > minL:L *= dLsegs.append([])for seg in segs[-2]:segs[-1].append(seg.getChild(dTh*rand(rTh), L*rand(rL), st))segs[-1].append(seg.getChild(-dTh*rand(rTh), L*rand(rL), st))return segs
然后写测试和绘图代码
from itertools import chain
import matplotlib.pyplot as plt
segs = fractal(10, 1, 0.7, 0.7, 15, 90, rL=1, rTh=1)def drawSegs(segs):segs = list(chain(*segs))pts = np.array([s.ed for s in segs])for seg in segs:xs, ys = seg.getAxis()test = plt.plot(xs, ys, color='g', zorder=1)xs, ys = pts.TN = len(xs)colors = np.random.rand(N)areas = (np.random.rand(N)*30)**2plt.scatter(xs, ys, s=areas, c=colors, marker='*', alpha=0.8, zorder=2)plt.axis("off")plt.show()
得到如图所示,发现,从观感上来说,貌似比之前更秃了
为了摆脱这种尴尬的局面,第一步就是在树干的正前方添加一根树枝,即在fractal
中的for
循环里,添加一个
segs[-1].append(seg.getChild(0, L*rand(rL), 0.7))
然后再生成,绘图
segs = fractal(10, 1, 0.7, 0.7, 15, 90, rL=1, rTh=1)
drawSegs(segs)
最后得到的树如下图所示,枝繁叶茂了许多
下一篇:SqlSugar的使用