更多算法(語言為JavaScript) 持續(xù)更新...
戳我去GitHub看詳細代碼>>>>分形基礎(chǔ)繪制
Vicsek fractal
基本正方形在3×3網(wǎng)格中分解為9個較小的正方形乔妈,繪制角落處的四個正方形和中間正方形租悄。對于剩余的五個子方格中的每一個真慢,遞歸地重復(fù)該過程。Vicsek分形是在此程序的極限下獲得的集合。
// 繪制圖形
draw(ctx, depth = this.depth, x = 0, y = 0, w = this.width, h = this.width) {
ctx.fillStyle = '#ccc';
if (depth <= 0 && depth != undefined || w <= 1 || h <= 1) {
// 繪制
ctx.fillRect(x, y, w, h)
return
}
this.depth = depth
// 要繪制的格子容器中的小格子的寬高 將格子容器劃分為3 * 3 的矩陣 根據(jù)位置分別繪制小格子
let w_3 = w / 3
let h_3 = h / 3
// 遞歸繪制每個格子的5個方向
this.draw(ctx, depth - 1,x, y, w_3, h_3)
this.draw(ctx, depth - 1, x + 2 * w_3, y, w_3, h_3)
this.draw(ctx, depth - 1, x + 2 * w_3, y + 2 * w_3, w_3, h_3)
this.draw(ctx, depth - 1, x + w_3, y + w_3, w_3, h_3)
this.draw(ctx, depth - 1, x, y + 2 * w_3, w_3, h_3)
}
分形結(jié)果如下圖:
Sierpinski carpet 分形
Sierpinski carpet 始于一個正方形"方形幾何"。該正方形在3×3網(wǎng)格中被切割成9個一致的子方形,只繪制中心子方躯护,然后,無限制地將相同的過程遞歸地應(yīng)用于剩余的8個子方格拔恰。
// 繪制圖形
draw(ctx, depth = this.depth, x = 0, y = 0, w = this.width, h = this.width) {
ctx.fillStyle = '#fff';
// 要繪制的格子容器中的小格子的寬高 將格子容器劃分為3 * 3 的矩陣 根據(jù)位置分別繪制小格子
let w_3 = w / 3
let h_3 = h / 3
if (depth <= 0 && depth != undefined || w <= 1 || h <= 1) return
this.depth = depth
// 遞歸繪制9個格子
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
// 中心的格子 直接繪制
ctx.fillRect( x + w_3, y + w_3, w_3, h_3)
} else {
// 其他八個角的格子 遞歸
this.draw(ctx, depth - 1, x + i * w_3, y + j * w_3, w_3, h_3)
}
}
}
}
分形結(jié)果如下圖:
sierpinski triangle 分形
- 從等邊三角形開始夹厌。
- 將其細分為四個較小的全等邊三角形并移除中心三角形。
-
重復(fù)步驟2,永遠保留每個剩余的較小三角形恢氯。
// 繪制圖形
draw(ctx, depth = this.depth, Ax = 0, Ay = this.side, side = this.side, all = this.depth) {
ctx.fillStyle = '#ccc';
// 計算三角形其余兩點坐標
let Bx = Ax + side
let By = Ay
let Cx = Ax + side / 2
let Cy = Ay - Math.sin( 2 * Math.PI / 360 * 60) * side
if (depth <= 0 && depth != undefined || side <= 1) {
// 傳入三點坐標
this.triangle(ctx, Ax, Ay,Bx, By, Cx, Cy)
return
}
// 遞歸 在左下角坐標為 (Ax, Ay)且邊長為 side 的正方形中繪制三個等邊三角形
this.draw(ctx, depth - 1, Ax, Ay, side / 2, all)
this.draw(ctx, depth - 1, (Ax + Bx) / 2, (Ay + By) / 2, side / 2, all)
this.draw(ctx, depth - 1, (Ax + Cx) / 2, (Ay + Cy) / 2, side / 2, all)
}
// 繪制三角形 傳入三點的坐標
triangle(ctx, x1, y1, x2, y2, x3, y3) {
ctx.beginPath()
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.closePath();
ctx.fill();
}
分形結(jié)果如下圖:
koch snowflake 分形
概念:Koch雪花可以通過等邊三角形開始構(gòu)建,然后遞歸地改變每個線段程腹,如下所示:
- 將線段劃分為三個相等長度的段
- 繪制一個等邊三角形嚼吞,其中以第1步的中間部分作為基準,并指向外部刽严。
- 從第2步中刪除作為三角形底邊的線段昂灵。
在該過程的一次迭代之后避凝,得到的形狀是六芒星的輪廓。
// 繪制圖形
draw(ctx, depth = this.depth, x1 = 0, y1 = this.width / 2, side = this.width, deg = 0) {
ctx.strokeStyle = '#fff';
// 要繪制的格子容器中的小格子的寬高 將格子容器劃分為3 * 3 的矩陣 根據(jù)位置分別繪制小格子
let w_3 = side / 3
if (depth < 0 && depth != undefined || w_3 <= 1) {
let x2 = x1 + Math.cos(2 * Math.PI / 360 * deg) * side
let y2 = y1 - Math.sin(2 * Math.PI / 360 * deg) * side
this.line(ctx, x1, y1, x2, y2)
return
}
let x2 = x1 + Math.cos(2 * Math.PI / 360 * deg) * w_3
let y2 = y1 - Math.sin(2 * Math.PI / 360 * deg) * w_3
this.draw(ctx, depth - 1, x1, y1, w_3, deg)
let x3 = x2 + w_3 * Math.cos(2 * Math.PI / 360 * (deg + 60))
let y3 = y2 - w_3 * Math.sin(2 * Math.PI / 360 * (deg + 60))
this.draw(ctx, depth - 1, x2, y2, w_3, deg + 60)
let x4 = x3 + w_3 * Math.cos(2 * Math.PI / 360 * (deg - 60))
let y4 = y3 - w_3 * Math.sin(2 * Math.PI / 360 * (deg - 60))
this.draw(ctx, depth - 1, x3, y3, w_3, deg - 60)
this.draw(ctx, depth - 1, x4, y4, w_3, deg)
}
// 繪制線條
line(ctx, x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
ctx.stroke();
}
分形結(jié)果如下圖:
分形繪制樹??
// 繪制圖形
draw(ctx, depth = this.depth, x1 = this.width / 2, y1 = this.width, side = this.width, deg = 0) {
ctx.strokeStyle = '#fff';
let w_2 = side / 2
if (depth < 0 && depth != undefined || w_2 <= 1) {
let x2 = x1 - Math.sin(2 * Math.PI / 360 * deg) * side
let y2 = y1 - Math.cos(2 * Math.PI / 360 * deg) * side
this.line(ctx, x1, y1, x2, y2)
return
}
// 獲取中點坐標
let x2 = x1 - Math.sin(2 * Math.PI / 360 * deg) * w_2
let y2 = y1 - Math.cos(2 * Math.PI / 360 * deg) * w_2
// 下邊的樹杈
this.line(ctx, x1, y1, x2, y2)
// 左邊的樹杈
this.draw(ctx, depth - 1, x2, y2, w_2, deg + this.splitDeg / 2)
// 右邊的樹杈
this.draw(ctx, depth - 1, x2, y2, w_2, deg - this.splitDeg / 2)
}
// 繪制線條
line(ctx, x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
ctx.stroke();
}
分形結(jié)果如下圖: