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 繪製出的不同樹梢開紅花的分叉