JavaScript图形实例:递归生成树
观察自然界中树的分叉,一根主干生长出两个侧干,每个侧干又长出两个侧干,以此类推,便生长出疏密有致的结构。这样的生长结构,使用递归算法可以模拟出来。
例如,分叉的侧干按45°的偏转角度进行生长的递归示意图如图1所示。

图1 生成树的递归示意图
按照树分叉生长侧干的递归思想,编写如下的HTML代码。
<!DOCTYPE html>
<head>
<title>递归分形树(一)</title>
</head>
<body>
<canvas id="myCanvas" width="600" height="400" style="border:3px double #996633;">
</canvas>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var maxdepth =4;
var curdepth = 0;
var alph=Math.PI/4;
function growtree()
{
ctx.translate(300,380);
branch(-Math.PI/2);
}
function branch(angle)
{
curdepth++;
ctx.save();
ctx.strokeStyle = "green";
ctx.lineWidth = 6;
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.stroke();
ctx.translate(100,0);
ctx.scale(0.75,0.75);
if(curdepth <= maxdepth)
{
branch(alph);
branch(-alph);
}
ctx.restore();
curdepth--;
}
growtree();
</script>
</body>
</html>
在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中绘制出分叉树形,如图2所示。

图2 递归深度maxdepth =4,alph=45°的分叉树形
若将递归深度“maxdepth=4”修改为“maxdepth=12”,则在浏览器窗口中绘制出如图3所示的分叉树形。

图3 递归深度maxdepth =12,alph=45°的分叉树形
若将递归深度“maxdepth=4”修改为“maxdepth=10”,分叉偏转角度从45°(alph=Math.PI/4)修改为30°(alph=Math.PI/6),则在浏览器窗口中绘制出如,4所示的分叉树形。
图4 递归深度maxdepth =10,alph=30°的分叉树形
由图3和图4可知,分叉的偏转角度不同,树形也会不同。实际上,自然界中树的侧干的生长不会按同一个角度进行分叉的,若将分叉的偏转角度取随机值,编写如下的HTML代码。
<!DOCTYPE html>
<head>
<title>递归分形树(二)</title>
</head>
<body>
<canvas id="myCanvas" width="600" height="400" style="border:3px double #996633;"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var maxdepth =10;
var curdepth = 0;
function growtree()
{
ctx.translate(300,380);
branch(-Math.PI/2);
}
function branch(angle)
{
curdepth++;
ctx.save();
ctx.strokeStyle = "green";
ctx.lineWidth = 6;
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.stroke();
ctx.translate(100,0);
ctx.scale(0.75,0.75);
if(curdepth <= maxdepth)
{
branch(randomRange(0,Math.PI/4));
branch(randomRange(-Math.PI/4,0));
}
ctx.restore();
curdepth--;
}
function randomRange(min,max)
{
return Math.random()*(max-min) + min;
}
growtree();
</script>
</body>
</html>
在浏览器中打开包含这段HTML代码的html文件,在浏览器窗口中可能会绘制出如图5所示的分叉树形。

图5 分叉树形
不断地刷新浏览器窗口,可以随机绘制出不同的分叉树形,如图6所示。

图6 绘制出的不同分叉树形
如果将递归树形的生成元改为如图7所示的三分叉,即在上面HTML文件中的两行代码
branch(randomRange(0,Math.PI/4));
branch(randomRange(-Math.PI/4,0));
中间加上一行代码 branch(0); 再将递归深度“var maxdepth =10;”修改为“var maxdepth =6;”,则在浏览器窗口中可能会绘制出如图8所示的分叉树形。

图7 三分叉生成元

图8 三分叉递归树形
我们可以在树梢画一个红色小圆,表示树儿开花了,编写如下的HTML文件。
<!DOCTYPE html>
<head>
<title>递归分形树(三)</title>
</head>
<body>
<canvas id="myCanvas" width="600" height="400" style="border:3px double #996633;"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var maxdepth =10;
var curdepth = 0;
function growtree()
{
ctx.translate(300,380);
branch(-Math.PI/2);
}
function branch(angle)
{
curdepth++;
ctx.save();
ctx.strokeStyle = "green";
ctx.lineWidth = 6;
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.stroke();
ctx.translate(100,0);
ctx.scale(0.75,0.75);
if(curdepth < maxdepth)
{
branch(randomRange(0,Math.PI/4));
branch(randomRange(-Math.PI/4,0));
}
if(curdepth == maxdepth)
{
ctx.fillStyle = '#ff0000';
ctx.beginPath();
ctx.arc(0,0,20,0,Math.PI*2,true);
ctx.fill();
}
ctx.restore();
curdepth--;
}
function randomRange(min,max)
{
return Math.random()*(max-min) + min;
}
growtree();
</script>
</body>
</html>
在浏览器中打开包含这段HTML代码的html文件,在浏览器窗口中可能会绘制出如图9所示的分叉树形。

图9 树梢开红花的分叉树形
不断地刷新浏览器窗口,可以随机绘制出不同的分叉树形,如图10所示。

图10 绘制出的不同树梢开红花的分叉树形
JavaScript图形实例:递归生成树的更多相关文章
- JavaScript图形实例:线段构图
在“JavaScript图形实例:四瓣花型图案”和“JavaScript图形实例:蝴蝶结图案”中,我们绘制图形时,主要采用的方法是先根据给定的曲线参数方程计算出两点坐标,然后将两点用线段连接起来,线段 ...
- JavaScript图形实例:再谈IFS生成图形
在“JavaScript图形实例:迭代函数系统生成图形”一文中,我们介绍了采用迭代函数系统(Iterated Function System,IFS)创建分形图案的一些实例.在该文中,仿射变换函数W的 ...
- JavaScript图形实例:随机SierPinski三角形
在“JavaScript图形实例:SierPinski三角形”中,我们介绍了SierPinski三角形的基本绘制方法,在“JavaScript图形实例:迭代函数系统生成图形”一文中,介绍了采用IFS方 ...
- JavaScript图形实例:图形的旋转变换
旋转变换:图形上的各点绕一固定点沿圆周路径作转动称为旋转变换.可用旋转角表示旋转量的大小. 旋转变换通常约定以逆时针方向为正方向.最简单的旋转变换是以坐标原点(0,0)为旋转中心,这时,平面上一点P( ...
- JavaScript图形实例:SierPinski三角形
1.SierPinski三角形 Sierpinski三角形是一种分形,由波兰数学家谢尔宾斯基在1915年提出,它是一种典型的自相似集.其生成过程为: (1)取一个三角形(多数使用等边三角形): (2) ...
- JavaScript图形实例:Hilbert曲线
德国数学家David Hilbert在1891年构造了一种曲线,首先把一个正方形等分成四个小正方形,依次从西北角的正方形中心出发往南到西南正方形中心,再往东到东南角的正方形中心,再往北到东北角正方形中 ...
- JavaScript图形实例:合成花卉图
我们知道在直角坐标系中,圆的方程可描述为: X=R*COS(α) Y=R*SIN(α) 用循环依次取α值为0~2π,计算出X和Y,在canvas画布中将坐标点(X,Y)用线连起来,可绘制出一个圆.编写 ...
- JavaScript图形实例:四瓣花型图案
设有坐标计算公式如下: X=L*(1+SIN(4α))*COS(α) Y=L*(1+SIN(4α))*SIN(α) 用循环依次取α值为0~2π,计算出X和Y,在canvas画布中对坐标位置(X,Y)描 ...
- JavaScript图形实例:图形的扇形变换和环形变换
1.1 扇形变换 将如图1所示的上边长方形的图形变换为下边的扇形图形的变换称为扇形变换. 设长方形图形中任一点P1(X1,Y1)变换为扇形图形上的点P2(X2,Y2),长方形的长为X,扇形圆心坐标为 ...
随机推荐
- Java实现 LeetCode 728 自除数(暴力)
728. 自除数 自除数 是指可以被它包含的每一位数除尽的数. 例如,128 是一个自除数,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0. 还有,自除数不允许包含 ...
- Java实现 LeetCode 313 超级丑数
313. 超级丑数 编写一段程序来查找第 n 个超级丑数. 超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数. 示例: 输入: n = 12, primes = [2,7, ...
- JavaScript实现html购物车代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- java实现第六届蓝桥杯熊怪吃核桃
熊怪吃核桃 题目描述 森林里有一只熊怪,很爱吃核桃.不过它有个习惯,每次都把找到的核桃分成相等的两份,吃掉一份,留一份.如果不能等分,熊怪就会扔掉一个核桃再分.第二天再继续这个过程,直到最后剩一个核桃 ...
- JPA入门及深入
一:ORM介绍 ORM(Object-Relational Mapping) 表示对象关系映射.在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中.只要有一套程序能够做到建立对象与数 ...
- Mac 制作 Linux 启动盘
本文原始地址:https://sitoi.cn/posts/28583.html 前期准备 一个 Mac 电脑 一个 U 盘(8GB 以上) 下载好 Linux 系统镜像(iso 文件) 具体步骤 挂 ...
- android在service中stopself遇到的问题
在service的oncreate中直接调用stopservice停止自己,依然会执行onstartcommand方法后,最后才调用ondestory方法
- SpringSceurity(4)---短信验证码功能实现
SpringSceurity(4)---短信验证码功能实现 有关SpringSceurity系列之前有写文章 1.SpringSecurity(1)---认证+授权代码实现 2.SpringSecur ...
- ubuntu12.04 dnw2 fl2440 配置
1.安装libusb-dev sudo apt-get install libusb-dev 2.dnw2编译配置 源码如下,将其保存为dnw2.c 编译命令 gcc dnw2.c -o dnw2 - ...
- 【华为云技术分享】数据库开发:MySQL Seconds_Behind_Master简要分析
[摘要]对于mysql主备实例,seconds_behind_master是衡量master与slave之间延时的一个重要参数.通过在slave上执行"show slave status;& ...