谢尔宾斯基地毯的构造与谢尔宾斯基三角形相似,区别仅在于谢尔宾斯基地毯是以正方形而非等边三角形为基础的。将一个实心正方形划分为的9个小正方形,去掉中间的小正方形,再对余下的小正方形重复这一操作便能得到谢尔宾斯基地毯。
js实现思路和我之前写的分形--谢尔宾斯基三角形的类似。
js效果:
贴关键代码:
1、画点
function point(x,y){ this.x = x; this.y = y; }
2、画线
function drawLine (ctx,point1,point2) { ctx.beginPath(); ctx.moveTo(point1.x,point1.y); ctx.lineTo(point2.x,point2.y); ctx.closePath(); ctx.stroke(); }
function drawRect (ctx,point1,point2,point3,point4) { ctx.beginPath(); ctx.moveTo(point1.x,point1.y); ctx.lineTo(point2.x,point2.y); ctx.lineTo(point3.x,point3.y); ctx.lineTo(point4.x,point4.y); ctx.closePath(); ctx.stroke(); }
4、取矩形各边的3等分点的两个中间点坐标
///获取3等分的两个中间点坐标 function getTwoMiddlePoint (point1,point2) { var temp1 = new point(0,0); var temp2 = new point(0,0); if (point1.x == point2.x) { var indentX = Math.abs(point1.y - point2.y)/3; if (point1.y>point2.y) { temp1.x = point2.x; temp1.y = point2.y + indentX; temp2.x = point1.x; temp2.y = point2.y + indentX*2; } else{ temp1.x = point1.x; temp1.y = point1.y + indentX*2; temp2.x = point2.x; temp2.y = point1.y + indentX; } } else if (point1.y == point2.y) { var indentY = Math.abs(point1.x - point2.x)/3; if (point1.x>point2.x) { temp1.x = point2.x + indentY; temp1.y = point2.y; temp2.x = point2.x + indentY*2; temp2.y = point1.y; } else{ temp1.x = point1.x + indentY*2; temp1.y = point1.y; temp2.x = point1.x + indentY; temp2.y = point2.y; } } return new doublePoint(temp1,temp2); }
5、迭代函数
function drawMengo(ctx,pointa,pointb,pointc,pointd,count) { if (count>=2) { drawRect(ctx,pointa,pointb,pointc,pointd); var double_ab = getTwoMiddlePoint(pointa,pointb); console.log(double_ab); var double_bc = getTwoMiddlePoint(pointb,pointc); var double_cd = getTwoMiddlePoint(pointd,pointc); console.log(double_cd); var double_da = getTwoMiddlePoint(pointa,pointd); { drawLine(ctx,double_ab.point1,double_cd.point1); drawLine(ctx,double_ab.point2,double_cd.point2); drawLine(ctx,double_da.point1,double_bc.point1); drawLine(ctx,double_da.point2,double_bc.point2); count -= 1; drawMengo(ctx,pointa,double_ab.point2,new point(double_ab.point2.x, double_da.point2.y),double_da.point2,count); drawMengo(ctx,double_ab.point2,double_ab.point1,new point(double_ab.point1.x, double_da.point2.y), new point(double_ab.point2.x, double_da.point2.y),count); drawMengo(ctx,double_ab.point1,pointb,double_bc.point2,new point(double_ab.point1.x, double_bc.point2.y),count); drawMengo(ctx,double_da.point2,new point(double_ab.point2.x, double_da.point2.y), new point(double_ab.point2.x, double_da.point1.y),double_da.point1,count); drawMengo(ctx,new point(double_ab.point1.x, double_bc.point2.y),double_bc.point2,double_bc.point1, new point(double_ab.point1.x,double_bc.point1.y),count); drawMengo(ctx,double_da.point1,new point(double_ab.point2.x,double_da.point1.y),double_cd.point2,pointd,count); drawMengo(ctx,new point(double_ab.point2.x,double_da.point1.y),new point(double_ab.point1.x,double_da.point1.y),double_cd.point1,double_cd.point2,count); drawMengo(ctx,new point(double_ab.point1.x,double_da.point1.y),double_bc.point1,pointc,double_cd.point1,count); } } else{ drawRect(ctx,pointa,pointb,pointc,pointd); } }
完整可运行代码:
<html> <head> <title>门格海绵--谢尔宾斯基地毯</title> <meta charset='utf-8'/> <script type="text/javascript"> function point(x,y){ this.x = x; this.y = y; } function doublePoint (point1,point2) { this.point1 = point1; this.point2 = point2; } function drawLine (ctx,point1,point2) { ctx.beginPath(); ctx.moveTo(point1.x,point1.y); ctx.lineTo(point2.x,point2.y); ctx.closePath(); ctx.stroke(); } function drawRect (ctx,point1,point2,point3,point4) { ctx.beginPath(); ctx.moveTo(point1.x,point1.y); ctx.lineTo(point2.x,point2.y); ctx.lineTo(point3.x,point3.y); ctx.lineTo(point4.x,point4.y); ctx.closePath(); ctx.stroke(); } ///获取3等分的两个中间点坐标 function getTwoMiddlePoint (point1,point2) { var temp1 = new point(0,0); var temp2 = new point(0,0); if (point1.x == point2.x) { var indentX = Math.abs(point1.y - point2.y)/3; if (point1.y>point2.y) { temp1.x = point2.x; temp1.y = point2.y + indentX; temp2.x = point1.x; temp2.y = point2.y + indentX*2; } else{ temp1.x = point1.x; temp1.y = point1.y + indentX*2; temp2.x = point2.x; temp2.y = point1.y + indentX; } } else if (point1.y == point2.y) { var indentY = Math.abs(point1.x - point2.x)/3; if (point1.x>point2.x) { temp1.x = point2.x + indentY; temp1.y = point2.y; temp2.x = point2.x + indentY*2; temp2.y = point1.y; } else{ temp1.x = point1.x + indentY*2; temp1.y = point1.y; temp2.x = point1.x + indentY; temp2.y = point2.y; } } return new doublePoint(temp1,temp2); } function drawMengo(ctx,pointa,pointb,pointc,pointd,count) { if (count>=2) { drawRect(ctx,pointa,pointb,pointc,pointd); var double_ab = getTwoMiddlePoint(pointa,pointb); console.log(double_ab); var double_bc = getTwoMiddlePoint(pointb,pointc); var double_cd = getTwoMiddlePoint(pointd,pointc); console.log(double_cd); var double_da = getTwoMiddlePoint(pointa,pointd); { drawLine(ctx,double_ab.point1,double_cd.point1); drawLine(ctx,double_ab.point2,double_cd.point2); drawLine(ctx,double_da.point1,double_bc.point1); drawLine(ctx,double_da.point2,double_bc.point2); count -= 1; drawMengo(ctx,pointa,double_ab.point2,new point(double_ab.point2.x, double_da.point2.y),double_da.point2,count); drawMengo(ctx,double_ab.point2,double_ab.point1,new point(double_ab.point1.x, double_da.point2.y), new point(double_ab.point2.x, double_da.point2.y),count); drawMengo(ctx,double_ab.point1,pointb,double_bc.point2,new point(double_ab.point1.x, double_bc.point2.y),count); drawMengo(ctx,double_da.point2,new point(double_ab.point2.x, double_da.point2.y), new point(double_ab.point2.x, double_da.point1.y),double_da.point1,count); drawMengo(ctx,new point(double_ab.point1.x, double_bc.point2.y),double_bc.point2,double_bc.point1, new point(double_ab.point1.x,double_bc.point1.y),count); drawMengo(ctx,double_da.point1,new point(double_ab.point2.x,double_da.point1.y),double_cd.point2,pointd,count); drawMengo(ctx,new point(double_ab.point2.x,double_da.point1.y),new point(double_ab.point1.x,double_da.point1.y),double_cd.point1,double_cd.point2,count); drawMengo(ctx,new point(double_ab.point1.x,double_da.point1.y),double_bc.point1,pointc,double_cd.point1,count); } } else{ drawRect(ctx,pointa,pointb,pointc,pointd); } } window.onload=function () { var cav = document.getElementById('cav'); var ctx = cav.getContext('2d'); ctx.strokeStyle = 'green';//rgba(100,200,100,50); var count = document.getElementById('num'); drawMengo(ctx,new point(10,10),new point(709,10),new point(709,709),new point(10,709),count.value); var btn = document.getElementById('clk'); btn.onclick=function () { ctx.clearRect(0,0,800,800); drawMengo(ctx,new point(10,10),new point(709,10),new point(709,709),new point(10,709),count.value); } } </script> </head> <body> <div style='margin:0 auto;'> <div> <input type='text' id='num' value='6'/> <input type='button' id='clk' value='run'/> </div> <canvas id='cav' width='750' height='750' style='border:1px solid red;'></canvas> </div> </body> </html>
编后语:
迭代函数的逻辑其实不复杂,主要是靠细心,注意对应点的连接,最后可以得到最终效果,算法很挫,还请指教。