You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化递归实现的谢尔宾斯基地毯?消除异常粗线条

解决谢尔宾斯基地毯的粗线条问题与代码优化方案

嘿,很高兴看到你跟着Shiffman的递归教程探索分形图形!咱们一步步解决你遇到的两个问题:不该出现的粗线条,以及代码的优化空间。

一、消除粗线条的根本原因与修复方案

你看到的粗线条,本质是两个核心问题导致的:

  • 递归坐标计算错误:你当前代码里用了x+d/x-d作为偏移量,这完全偏离了谢尔宾斯基地毯的分形逻辑——当大正方形边长为d时,下一级小正方形的中心应该相对于大中心偏移d/3(而非d),因为小正方形的边长是d/3,中心间距刚好是d/3。
  • 整数坐标的舍入误差:强制用int()转换坐标会导致位置偏移,相邻矩形出现重叠或间隙,视觉上就呈现出了粗线条。

修复后的核心递归函数调整如下:

void Serpinski(float x, float y, float d) {
  rect(x, y, d, d);
  if (d > 1.5) { // 用更合理的终止阈值,避免绘制肉眼无法分辨的过小矩形
    float newD = d / 3;
    float offset = d / 3;
    // 八个方向的递归调用
    Serpinski(x + offset, y, newD);
    Serpinski(x - offset, y, newD);
    Serpinski(x, y + offset, newD);
    Serpinski(x, y - offset, newD);
    Serpinski(x + offset, y + offset, newD);
    Serpinski(x - offset, y - offset, newD);
    Serpinski(x + offset, y - offset, newD);
    Serpinski(x - offset, y + offset, newD);
  }
}

同时调整主函数,去掉不必要的int转换,并把全局设置移到setup里:

void setup() {
  size(800, 800);
  rectMode(CENTER); // 全局只设置一次即可
  noStroke();
  fill(0);
}

void draw() {
  background(255);
  Serpinski(width/2, height/2, width/3);
  noLoop(); // 只绘制一次,避免draw循环重复执行浪费资源
}

二、代码优化方案

除了修复粗线条,还可以从这几个方面优化代码:

  • 避免重复绘制:draw()默认每秒执行60次,加入noLoop()让图形只绘制一次,节省性能开销。
  • 提取重复变量:把newD和offset单独提取出来,避免重复计算d/3,让代码更清晰易读。
  • 合理终止递归:用d > 1.5替代d > 1,当d小到肉眼无法分辨时提前终止递归,提升运行效率。
  • 统一参数类型:全部用float处理坐标和边长,彻底避免整数转换带来的精度损失。

修改后,谢尔宾斯基地毯的每个小矩形都会精准定位,不会再出现重叠的粗线条,同时递归逻辑更清晰,性能也有所提升。

内容的提问来源于stack exchange,提问作者jirm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:12:07