分形图的绘制

更多算法(语言为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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容