Python如何生成树形图案


Posted in Python onJanuary 03, 2018

本文实例为大家分享了Python生成树形图案的具体代码,供大家参考,具体内容如下

先看一下效果,见下图。

Python如何生成树形图案

上面这颗大树是使用Python + Tkinter绘制的,主要原理为使用分形画树干、树枝,最终叶节点上画上绿色圆圈代表树叶。当然,为了看起来更真实,绘制过程中也加入了一些随机变化,比如树枝会稍微有些扭曲而不是一条直线,分叉的角度、长短等都会随机地作一些偏移等。

以下是完整源代码:

# -*- coding: utf-8 -*- 
 
import Tkinter 
import sys, random, math 
 
class Point(object): 
  def __init__(self, x, y): 
    self.x = x 
    self.y = y 
 
  def __str__(self): 
    return "<Point>: (%f, %f)" % (self.x, self.y) 
 
class Branch(object): 
  def __init__(self, bottom, top, branches, level = 0): 
    self.bottom = bottom 
    self.top = top 
    self.level = level 
    self.branches = branches 
    self.children = [] 
 
  def __str__(self): 
    s = "Top: %s, Bottom: %s, Children Count: %d" % / 
      (self.top, self.bottom, len(self.children)) 
    return s 
 
  def nextGen(self, n = -1, rnd = 1): 
    if n <= 0: n = self.branches 
    if rnd == 1: 
      n = random.randint(n / 2, n * 2) 
      if n <= 0: n = 1 
    dx = self.top.x - self.bottom.x 
    dy = self.top.y - self.bottom.y 
    r = 0.20 + random.random() * 0.2 
    if self.top.x == self.bottom.x: 
      # 如果是一条竖线 
      x = self.top.x 
      y = dy * r + self.bottom.y 
    elif self.top.y == self.bottom.y: 
      # 如果是一条横线 
      x = dx * r + self.bottom.x 
      y = self.top.y 
    else: 
      x = dx * r 
      y = x * dy / dx 
      x += self.bottom.x 
      y += self.bottom.y 
    oldTop = self.top 
    self.top = Point(x, y) 
    a = math.pi / (2 * n) 
    for i in range(n): 
      a2 = -a * (n - 1) / 2 + a * i - math.pi 
      a2 *= 0.9 + random.random() * 0.2 
      self.children.append(self.mkNewBranch(self.top, oldTop, a2)) 
 
  def mkNewBranch(self, bottom, top, a): 
    dx1 = top.x - bottom.x 
    dy1 = top.y - bottom.y 
    r = 0.9 + random.random() * 0.2 
    c = math.sqrt(dx1 ** 2 + dy1 ** 2) * r 
    if dx1 == 0: 
      a2 = math.pi / 2 
    else: 
      a2 = math.atan(dy1 / dx1) 
      if (a2 < 0 and bottom.y > top.y) / 
        or (a2 > 0 and bottom.y < top.y) / 
        : 
        a2 += math.pi 
    b = a2 - a 
    dx2 = c * math.cos(b) 
    dy2 = c * math.sin(b) 
    newTop = Point(dx2 + bottom.x, dy2 + bottom.y) 
    return Branch(bottom, newTop, self.branches, self.level + 1) 
 
class Tree(object): 
  def __init__(self, root, canvas, bottom, top, branches = 3, depth = 3): 
    self.root = root 
    self.canvas = canvas 
    self.bottom = bottom 
    self.top = top 
    self.branches = branches 
    self.depth = depth 
    self.new() 
 
  def gen(self, n = 1): 
    for i in range(n): 
      self.getLeaves() 
      for node in self.leaves: 
        node.nextGen() 
    self.show() 
 
  def new(self): 
    self.leavesCount = 0 
    self.branch = Branch(self.bottom, self.top, self.branches) 
    self.gen(self.depth) 
    print "leaves count: %d" % self.leavesCount 
 
  def chgDepth(self, d): 
    self.depth += d 
    if self.depth < 0: self.depth = 0 
    if self.depth > 10: self.depth = 10 
    self.new() 
 
  def chgBranch(self, d): 
    self.branches += d 
    if self.branches < 1: self.branches = 1 
    if self.branches > 10: self.branches = 10 
    self.new() 
 
  def getLeaves(self): 
    self.leaves = [] 
    self.map(self.findLeaf) 
 
  def findLeaf(self, node): 
    if len(node.children) == 0: 
      self.leaves.append(node) 
 
  def show(self): 
    for i in self.canvas.find_all(): 
      self.canvas.delete(i) 
    self.map(self.drawNode) 
    self.canvas.tag_raise("leaf") 
 
  def exit(self, evt): 
    sys.exit(0) 
 
  def map(self, func = lambda node: node): 
    # 遍历树 
    children = [self.branch] 
    while len(children) != 0: 
      newChildren = [] 
      for node in children: 
        func(node) 
        newChildren.extend(node.children) 
      children = newChildren 
 
  def drawNode(self, node): 
    self.line2( 
#    self.canvas.create_line( 
        node.bottom.x, 
        node.bottom.y, 
        node.top.x, 
        node.top.y, 
        fill = "#100", 
        width = 1.5 ** (self.depth - node.level), 
        tags = "branch level_%d" % node.level, 
      ) 
 
    if len(node.children) == 0: 
      # 画叶子 
      self.leavesCount += 1 
      self.canvas.create_oval( 
          node.top.x - 3, 
          node.top.y - 3, 
          node.top.x + 3, 
          node.top.y + 3, 
          fill = "#090", 
          tag = "leaf", 
        ) 
 
    self.canvas.update() 
 
  def line2(self, x0, y0, x1, y1, width = 1, fill = "#000", minDist = 10, tags = ""): 
    dots = midDots(x0, y0, x1, y1, minDist) 
    dots2 = [] 
    for i in range(len(dots) - 1): 
      dots2.extend([dots[i].x, 
        dots[i].y, 
        dots[i + 1].x, 
        dots[i + 1].y]) 
    self.canvas.create_line( 
        dots2, 
        fill = fill, 
        width = width, 
        smooth = True, 
        tags = tags, 
      ) 
 
def midDots(x0, y0, x1, y1, d): 
  dots = [] 
  dx, dy, r = x1 - x0, y1 - y0, 0 
  if dx != 0: 
    r = float(dy) / dx 
  c = math.sqrt(dx ** 2 + dy ** 2) 
  n = int(c / d) + 1 
  for i in range(n): 
    if dx != 0: 
      x = dx * i / n 
      y = x * r 
    else: 
      x = dx 
      y = dy * i / n 
    if i > 0: 
      x += d * (0.5 - random.random()) * 0.25 
      y += d * (0.5 - random.random()) * 0.25 
    x += x0 
    y += y0 
    dots.append(Point(x, y)) 
  dots.append(Point(x1, y1)) 
  return dots 
 
if __name__ == "__main__": 
  root = Tkinter.Tk() 
  root.title("Tree") 
  gw, gh = 800, 600 
  canvas = Tkinter.Canvas(root, 
      width = gw, 
      height = gh, 
    ) 
  canvas.pack() 
  tree = Tree(root, canvas, Point(gw / 2, gh - 20), Point(gw / 2, gh * 0.2), / 
    branches = 2, depth = 8) 
  root.bind("n", lambda evt: tree.new()) 
  root.bind("=", lambda evt: tree.chgDepth(1)) 
  root.bind("+", lambda evt: tree.chgDepth(1)) 
  root.bind("-", lambda evt: tree.chgDepth(-1)) 
  root.bind("b", lambda evt: tree.chgBranch(1)) 
  root.bind("c", lambda evt: tree.chgBranch(-1)) 
  root.bind("q", tree.exit) 
  root.mainloop()

因为每次生成的树都是随机的,所以你生成的树和上图会不太一样,可能会更为枝繁叶茂,也可能会看起来才刚刚发芽。程序中绑定了若干快捷键,比如“n”是随机产生一颗新的树,“q”是退出程序。另外还有一些不太常用的快捷键,如“+”/“-”是增加/减少树的深度,“b”/“c”分别代表更多/更少的分叉,需要注意的是,增加深度或分叉可能需要更多的计算时间。

从这次树形图案的绘制过程中,我也有一些有趣的发现,比如,树枝上某一处的横截面宽度与它与树根之间的距离似乎呈一种指数函数的关系。如用H表示树的总高度,h表示树枝上某一点的高度,w表示这一点横截面的宽度,那么w与h之间似乎存在这样一种关系:w = a * b ^ (H - h) + c,这儿a、b、c都是常数。当然,这只是一个猜测,因为绘制的过程中我发现当w与h满足这样关系时画出来的图案看起来最“自然”,这个问题或许下次可以再深入研究一下。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现端口转发器的方法
Mar 13 Python
Python中使用items()方法返回字典元素对的教程
May 21 Python
python使用Pycharm创建一个Django项目
Mar 05 Python
Python WSGI的深入理解
Aug 01 Python
Python语言快速上手学习方法
Dec 14 Python
详解重置Django migration的常见方式
Feb 15 Python
python导入坐标点的具体操作
May 10 Python
python求一个字符串的所有排列的实现方法
Feb 04 Python
浅谈在django中使用redirect重定向数据传输的问题
Mar 13 Python
python 爬取小说并下载的示例
Dec 07 Python
2020年10款优秀的Python第三方库,看看有你中意的吗?
Jan 12 Python
Python人工智能之混合高斯模型运动目标检测详解分析
Nov 07 Python
Python爬取十篇新闻统计TF-IDF
Jan 03 #Python
Python制作词云的方法
Jan 03 #Python
Python读取Json字典写入Excel表格的方法
Jan 03 #Python
python基于ID3思想的决策树
Jan 03 #Python
python遍历文件夹下所有excel文件
Jan 03 #Python
Python将多份excel表格整理成一份表格
Jan 03 #Python
Python将多个excel文件合并为一个文件
Jan 03 #Python
You might like
虚拟主机中对PHP的特殊设置
2006/10/09 PHP
php基础知识:类与对象(4) 范围解析操作符(::)
2006/12/13 PHP
Apache环境下PHP利用HTTP缓存协议原理解析及应用分析
2010/02/16 PHP
动态表单验证的操作方法和TP框架里面的ajax表单验证
2017/07/19 PHP
PHP使用栈解决约瑟夫环问题算法示例
2017/08/27 PHP
JavaScript 学习笔记(五)
2009/12/31 Javascript
js为空或不是对象问题的快速解决方法
2013/12/11 Javascript
javascript客户端遍历控件与获取父容器对象示例代码
2014/01/06 Javascript
用原生JS获取CLASS对象(很简单实用)
2014/10/15 Javascript
jQuery实现类似标签风格的导航菜单效果代码
2015/08/25 Javascript
详解javascript实现瀑布流绝对式布局
2016/01/29 Javascript
JavaScript如何实现组合列表框中元素移动效果
2016/03/01 Javascript
jQuery实现指定区域外单击关闭指定层的方法【经典】
2016/06/22 Javascript
深入理解Angular2 模板语法
2016/08/07 Javascript
使用Promise链式调用解决多个异步回调的问题
2017/01/15 Javascript
详解nodejs微信jssdk后端接口
2017/05/25 NodeJs
利用Dectorator分模块存储Vuex状态的实现
2019/02/05 Javascript
基于纯JS实现多张图片的懒加载Lazy过程解析
2019/10/14 Javascript
小程序使用wxs解决wxml保留2位小数问题
2019/12/13 Javascript
JS实现容器模块左右拖动效果
2020/01/14 Javascript
JS实现图片懒加载(lazyload)过程详解
2020/04/02 Javascript
js实现全选和全不选功能
2020/07/28 Javascript
[01:04:30]Fnatic vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
Python命令启动Web服务器实例详解
2017/02/23 Python
Python中表示字符串的三种方法
2017/09/06 Python
python多进程读图提取特征存npy
2019/05/21 Python
Python django搭建layui提交表单,表格,图标的实例
2019/11/18 Python
python 代码实现k-means聚类分析的思路(不使用现成聚类库)
2020/06/01 Python
python 获取字典键值对的实现
2020/11/12 Python
Python实现一个论文下载器的过程
2021/01/18 Python
HTML5 背景的显示区域实现
2020/07/09 HTML / CSS
String、StringBuffer、StringBuilder有区别
2015/09/18 面试题
心理健康教育制度
2014/01/27 职场文书
幼儿园教师奖惩制度
2014/02/01 职场文书
应用外语系自荐信
2014/06/26 职场文书
健康证明
2015/06/19 职场文书