分形图的绘制

更多算法(语言为JavaScript) 持续更新...

戳我去GitHub看更多算法问题>>>>目录

戳我去GitHub看详细代码>>>>分形基础绘制

Vicsek fractal

基本正方形在3×3网格中分解为9个较小的正方形,绘制角落处的四个正方形和中间正方形。对于剩余的五个子方格中的每一个,递归地重复该过程。Vicsek分形是在此程序的极限下获得的集合。

https://en.wikipedia.org/wiki/Vicsek_fractal
// 绘制图形
    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 的矩阵 根据位置分别绘制小格子
      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) 
    }

分形结果如下图:


Vicsek分形.gif

Sierpinski carpet 分形

Sierpinski carpet 始于一个正方形"方形几何"。该正方形在3×3网格中被切割成9个一致的子方形,只绘制中心子方,然后,无限制地将相同的过程递归地应用于剩余的8个子方格。


流程图
// 绘制图形
   draw(ctx, depth = this.depth, x = 0, y = 0, w = this.width, h = this.width) {

     ctx.fillStyle = '#fff';

     // 要绘制的格子容器中的小格子的宽高  将格子容器划分为3 * 3 的矩阵 根据位置分别绘制小格子
     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)
         }
       }
     }
   }

分形结果如下图:


sierpinski_carpet_分形.gif

sierpinski triangle 分形

  • 从等边三角形开始。
  • 将其细分为四个较小的全等边三角形并移除中心三角形。
  • 重复步骤2,永远保留每个剩余的较小三角形。


    sierpinski triangle 分形

    思路
    // 绘制图形
    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();
    }

分形结果如下图:


sierpinski_triangle_分形.gif

koch snowflake 分形

概念:Koch雪花可以通过等边三角形开始构建,然后递归地改变每个线段,如下所示:

  • 将线段划分为三个相等长度的段
  • 绘制一个等边三角形,其中以第1步的中间部分作为基准,并指向外部。
  • 从第2步中删除作为三角形底边的线段。

在该过程的一次迭代之后,得到的形状是六芒星的轮廓。

koch snowflake 分形
思路
    // 绘制图形
    draw(ctx, depth = this.depth, x1 = 0, y1 = this.width / 2, side = this.width, deg = 0) {

      ctx.strokeStyle = '#fff';

      // 要绘制的格子容器中的小格子的宽高  将格子容器划分为3 * 3 的矩阵 根据位置分别绘制小格子
      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();
    }

分形结果如下图:


koch_snowflake_分形.gif

分形绘制树

   
   // 绘制图形
   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();
   }

分形结果如下图:


绘制树_分形.gif

你可能感兴趣的:(分形图的绘制)