1. 程式人生 > 實用技巧 >JavaScript圖形例項:隨機SierPinski三角形

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三角形