JavaScript圖形例項:隨機SierPinski三角形
在“JavaScript圖形例項:SierPinski三角形”中,我們介紹了SierPinski三角形的基本繪製方法,在“JavaScript圖形例項:迭代函式系統生成圖形”一文中,介紹了採用IFS方法生成SierPinski三角形的方法。下面再介紹兩種SierPinski三角形的構造方法,以擴充套件知識面。
1.隨機點法
採用隨機點的方法可以得到SierPinski三角形。具體過程為:
(1)任意取平面上三點A、B、C,組成一個三角形,並任意取三角形ABC內的一點P;
(2)求出P和A、B、C三個頂點中任意一個頂點的中點P1;
(3)描出該中點P1;
(4)將P1作為新的P點,轉步驟(2),直到描出的點數達到規定要求(如10000個點)。
按上述思想,編寫如下的HTML檔案。在程式設計時,為簡單計,不保證初始的P點一定在三角形ABC內(有可能在三角形外會描出幾個散點,但不影響最後結果),也沒有判斷A、B、C三點可能共線的情況(此時無法構成三角形)。有興趣的讀者可以自行處理這兩種情況,以完善程式碼。
<!DOCTYPE html>
<head>
<title>隨機SierPinski三角形</title>
</head>
<body>
<canvas id="myCanvas" width="300" height="300" style="border:3px double #996633;">
</canvas>
<script type="text/javascript">
var canvas=document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
function draw()
{
ctx.fillStyle="#EEEEFF";
ctx.fillRect(0,0,300,300);
ctx.fillStyle="red";
ctx.font="32px";
var ax=Math.floor(Math.random()*200+50);
var ay=Math.floor(Math.random()*200+50);
var bx=Math.floor(Math.random()*200+50);
var by=Math.floor(Math.random()*200+50);
var cx=Math.floor(Math.random()*200+50);
var cy=Math.floor(Math.random()*200+50);
var px=Math.floor(Math.random()*200+50);
var py=Math.floor(Math.random()*200+50);
var dx=0;
var dy=0;
for (i=0; i<10000; i++)
{
index =Math.floor(Math.random()*3+1);
if (index==1)
{
dx = (ax + px)/2;
dy = (ay + py)/2;
}
else if (index == 2)
{
dx = (bx + px)/2;
dy = (by + py)/2;
}
else
{
dx = (cx + px)/2;
dy = (cy + py)/2;
}
ctx.fillText('.',dx,dy);
px = dx;
py = dy;
}
}
draw();
</script>
</body>
</html>
在瀏覽器中開啟包含這段HTML程式碼的html檔案,可以看到在瀏覽器視窗中繪製出一個SierPinski三角形,如圖1所示。
圖1 SierPinski三角形
將程式中的呼叫語句“draw()”改寫為“window.setInterval('draw()', 1500);”,則在瀏覽器視窗中會每隔1.5秒繪製一個隨機SierPinski三角形,如圖2所示。
圖2 每隔1.5秒繪製一個隨機SierPinski三角形
由圖2可以看出,有些三角形太小,設定有些成一條直線,因此,可以改寫上面的程式,要求隨機取點A、B、C時,保證三個邊長均大於100,且三點不共線。改寫的HTML檔案內容如下。
<!DOCTYPE html>
<head>
<title>隨機SierPinski三角形</title>
</head>
<body>
<canvas id="myCanvas" width="300" height="300" style="border:3px double #996633;">
</canvas>
<script type="text/javascript">
var canvas=document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
function draw()
{
ctx.fillStyle="#EEEEFF";
ctx.fillRect(0,0,300,300);
ctx.fillStyle="red";
ctx.font="32px";
while (1)
{
var ax=Math.floor(Math.random()*200+50);
var ay=Math.floor(Math.random()*200+50);
var bx=Math.floor(Math.random()*200+50);
var by=Math.floor(Math.random()*200+50);
var cx=Math.floor(Math.random()*200+50);
var cy=Math.floor(Math.random()*200+50);
ab=Math.sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay));
ac=Math.sqrt((cx-ax)*(cx-ax)+(cy-ay)*(cy-ay));
bc=Math.sqrt((cx-bx)*(cx-bx)+(cy-by)*(cy-by));
if (ab<100 || ac<100 || bc<100) continue;
if (ab+bc==ac || ab+ac==bc || ac+bc==ab) continue;
var px=Math.floor(Math.random()*200+50);
var py=Math.floor(Math.random()*200+50);
break;
}
var dx=0;
var dy=0;
for (i=0; i<10000; i++)
{
index =Math.floor(Math.random()*3+1);
if (index==1)
{
dx = (ax + px)/2;
dy = (ay + py)/2;
}
else if (index == 2)
{
dx = (bx + px)/2;
dy = (by + py)/2;
}
else
{
dx = (cx + px)/2;
dy = (cy + py)/2;
}
ctx.fillText('.',dx,dy);
px = dx;
py = dy;
}
}
window.setInterval('draw()', 1500);
</script>
</body>
</html>
在瀏覽器中開啟包含這段改寫後的HTML程式碼的html檔案,在瀏覽器視窗中也會每隔1.5秒繪製一個隨機SierPinski三角形,如圖3所示,此時每個隨機SierPinski三角形的最小邊長均會超過100,三角形不會顯得較小。
圖3 每隔1.5秒繪製一個較大的隨機SierPinski三角形
上面程式中隨機點法構造SierPinski三角形是描點10000個得到的。為展示描點過程,編寫如下的HTML檔案。
<!DOCTYPE html>
<head>
<title>隨機SierPinski三角形</title>
</head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">
</canvas>
<script type="text/javascript">
var canvas=document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
ctx.fillStyle="#EEEEFF";
ctx.fillRect(0,0,400,400);
ctx.fillStyle="red";
ctx.font="32px";
while (1)
{
var ax=Math.floor(Math.random()*400);
var ay=Math.floor(Math.random()*400);
var bx=Math.floor(Math.random()*400);
var by=Math.floor(Math.random()*400);
var cx=Math.floor(Math.random()*400);
var cy=Math.floor(Math.random()*400);
ab=Math.sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay));
ac=Math.sqrt((cx-ax)*(cx-ax)+(cy-ay)*(cy-ay));
bc=Math.sqrt((cx-bx)*(cx-bx)+(cy-by)*(cy-by));
if (ab<200 || ac<200 || bc<200) continue;
if (ab+bc==ac || ab+ac==bc || ac+bc==ab) continue;
var px=Math.floor(Math.random()*400);
var py=Math.floor(Math.random()*400);
break;
}
var i=0;
function draw()
{
index =Math.floor(Math.random()*3+1);
if (index==1)
{
dx = (ax + px)/2;
dy = (ay + py)/2;
}
else if (index == 2)
{
dx = (bx + px)/2;
dy = (by + py)/2;
}
else
{
dx = (cx + px)/2;
dy = (cy + py)/2;
}
ctx.fillText('.',dx,dy);
px = dx;
py = dy;
i++;
if (i>=10000)
{
ctx.fillStyle="#EEEEFF";
ctx.fillRect(0,0,400,400);
ctx.fillStyle="red";
i=0;
}
}
window.setInterval('draw()',1);
</script>
</body>
</html>
在瀏覽器中開啟包含這段HTML程式碼的html檔案,在瀏覽器視窗中呈現出一個隨機SierPinski三角形的噴出過程,如圖4所示。
圖4 隨機SierPinski三角形的噴出過程
2.按組合數的奇偶性直接描點構造SierPinski三角形
設有如下的楊輝三角形,若將楊輝三角形的奇數處畫圓點,偶數處留空,則會得到SierPinski三角形。
由於楊輝三角中第i行第j列的數字正是組合數C(i,j)的結果。因此,對楊輝三角形中各行各列數字的討論轉化為對組合數C(n,m)的討論。
組合數的奇偶性判定方法為:
對於C(n,m),若n&m == m 則C(n,m)為奇數,否則為偶數。
根據這個結論,直接編寫如下的HTML檔案。
<!DOCTYPE html>
<head>
<title>按組合數奇偶性構造SierPinski三角形</title>
<script type="text/javascript">
function draw(id)
{
var canvas=document.getElementById(id);
if (canvas==null)
return false;
var ctx=canvas.getContext('2d');
ctx.fillStyle="#EEEEFF";
ctx.fillRect(0,0,300,300);
ctx.fillStyle="red";
for (i=0;i<256;i++)
{
for (j=0;j<=i;j++)
if ((i&j)==j)
ctx.fillText('.',j+30,i+30);
}
}
</script>
</head>
<body onload="draw('myCanvas');">
<canvas id="myCanvas" width="300" height="300" style="border:3px double #996633;">
</canvas>
</body>
</html>
在瀏覽器中開啟包含這段HTML程式碼的html檔案,可以看到在瀏覽器視窗中繪製出如圖5所示的SierPinski三角形。
圖5 SierPinski三角形