草庐IT

分形树

大龙10 2023-09-14 原文

书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
第8章目录

8.5 树

  • 到目前为止,我们接触的分形都是确定性的,也就是说,这类分形没有任何随机因
    素,每次运行都会构建出相同的结果。
  • 对于传统分形和可视化编程技术的演示,它们是非常不错的素材;
  • 但在模拟方面,它们过于准确,不够贴近自然。
  • 接下来讨论随机(非确定性)分形的构建技术。

1、确定性分形技术构建

  • 本节要模拟的是带有分支的树。

  • 首先,让我们用确定性分形技术构建一棵分形树。构建规则如下:


  • 再一次,我们用递归方式构建了一个分形:树枝是一个线段,线段末尾有两根小树枝。


2、实现的思路

  • 这个分形的难点在于它的分形规则用到了旋转,每个新的树枝必须在原树枝上旋转一定的角度,而原树枝也是如此。幸运的是:Processing专门有一个机制用于管理旋转角度,即变换矩阵。
  • 让我们从主干开始。由于要涉及rotate()函数,我们必须在绘制过程中不断地沿着树枝平移。主干是从屏幕底部开始的(如上图所示),因此我们要做的第一件事就是平移到主干所在的位置。
    translate(width/2,height);
  • 紧接着我们要画一根向上延伸的线段
    line(0,0,0,-100);
  • 树干绘制完成后,为了画出它的树枝,我们需要平移到树干的末端,然后进行旋转。
    (最后,我们需要把这些操作实现为递归函数,但在此之前要先梳理出具体步骤。)
  • 记住,在Processing中,旋转始终都是绕着原点进行的。因此,我们必须把原点平移到当前树枝的末端。
translate(0,-100);
rotate(PI/6);
line(0,0,0,-100);
  • 现在我们已经画好了右边的树枝,下面要添加左边的树枝。在向右旋转之前,我们可以调用pushMatrix()函数保存转换矩阵的当前状态,旋转完成后再调用popMatrix()函数恢复状态,接着在树干左边画树枝。以下是全部代码。
translate(width/2, height);
line(0,0,0,-100); 树干
translate(0,-100);
pushMatrix();
rotate(PI/6);
line(0,0,0,-100); 右边的树枝
popMatrix();
rotate(-PI/6);
line(0,0,0,-100); 左边的树枝

3、递归树的实现

  • 如果把每个line()函数调用都当成一根“树枝”,你会发现,树枝其实是一条线段,线段的末尾还连接着两条线段。
    我们可以直接调用line()函数产生更多树枝,但类似于康托尔集和科赫曲线,这么做会让代码变得复杂而笨重。
    相反地,我们可以把上述逻辑作为递归函数的实现思路,把其中的line()函数调用替换为递归的branch()函数。
    下面来看看这种实现。
void branch() {
    line(0, 0, 0, -100); 绘制树枝
    translate(0, -100); 平移到末尾
    pushMatrix();
    rotate(PI/6); 向右旋转,再画新的树枝
    branch();
    popMatrix();
    pushMatrix();
    rotate(-PI/6); 向左旋转,再画新的树枝
    branch();
    popMatrix();
}
  • 在上面的代码中,每个branch()函数调用的周围都有成对的pushMatrix()函数和popMatrix()函数调用。
    这种实现方式非常神奇。每次调用branch()函数之前,pushMatrix()函数都会事先记住当前树枝的位置。
    请把自己当作Processing,尝试着用笔和纸跟踪递归函数的执行,你会发现:程序首先画所有右边的树枝,当它达到终点时,popMatrix()函数会逐个恢复之前每个树枝的状态,然后再开始画左边的树枝。
  • 以上递归函数并不会画出一棵树,因为它没有退出条件,最终只是陷入无限的递归调用。你可能还会发现,图中树枝随着层数的增加而缩短。以下代码让树枝的长度不断缩短,一旦树枝长度小于某个值,就停止递归。
void branch(float len) { branch()函数接受一个长度参数
    line(0, 0, 0, -len);
    translate(0, -len);
    len *= 0.66; 每个树枝的长度以2/3的倍数缩短
    if (len > 2) {
        pushMatrix();
        rotate(theta);
        branch(len); 后续的branch()调用必须传入长度参数
        popMatrix()
        pushMatrix();
        rotate(-theta);
        branch(len);
        popMatrix();
        }
}

4、随机分形树

  • 在分形树中加入一点点随机性就可以使它的外形更贴近自然。
    查看一棵树的外形,你会发现每根树枝的角度和长度都不相同,此外,每根树枝的分支数量也不相同。
    简单地改变树枝的角度和长度能带来什么样的结果?这很容易实现,只要在绘制时获取一个随机数即可。
void branch(float len) {
    float theta = random(0, PI/3); 选择一个随机数作为树枝的角度
    line(0, 0, 0, -len);
    translate(0, -len);
    len *= 0.66;
    if (len > 2) {
        pushMatrix();
        rotate(theta);
        branch(len);
        popMatrix();
        pushMatrix();
        rotate(-theta);
        branch(len);
        popMatrix();
        }
}

有关分形树的更多相关文章

  1. c# - 为什么我的龙分形不完整 - 2

    很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visitthehelpcenter.关闭11年前。我已经将代码从javascript翻译成c#,可以通过访问这个出色的演示找到http://fractal.qfox.nl/dragon.js我的翻译旨在点击按钮时只生成一条龙,但我想我的版本中遗漏了一些东西。请参阅维基百科文章:DragonCurve获取更多信息。不完整的龙分形输出:代码:publicpartialclassMainPage:UserControl{PointCollection

  2. php - Laravel 5.1 和分形 : including pivot table data on the transformer - 2

    表:contact、company和具有自定义数据透视属性的关系表company_contact(company_id,contact_id,is_main)Company和Contact具有多对多关系(belongsTo在两个模型上)。检索公司联系人时的预期输出:{"data":[{"id":1,"name":"JohnDoe","is_main":false},{"id":2,"name":"JaneDoe","is_main":true}]}当我使用?include=companies检索联系人列表时的预期输出:{"data":[{"id":1,"name":"JohnDoe",

  3. PHP 分形转换器返回嵌入数据 - 2

    我正在尝试使用Fractal来转换API数据输出。这适用于单个项目和集合,但我似乎无法让它与嵌入式数据一起使用。不幸的是,我在Fractal上找不到很多“操作方法”。我关注了Fractal网站上的信息,但它不起作用。我使用Laravel4作为我的框架。这是我的Transformer类中的内容:protected$availableEmbeds=array('requirements');publicfunctiontransform(){etc...}publicfunctionembedRequirements(Regions$regions){return$this->collec

  4. php - Laravel 5 - 分形更改器(mutator) - 将参数发送到更改器(mutator)以缩小响应范围 - 2

    所以我有一个名为VIP的模型,其中包含大量相关信息。因此,当我们转到路线vip/{id}时,我会返回大部分信息。但是,当我转到vips/{per-page}时,我不想返回所有数据,因为API会呈指数级下降。相反,我宁愿只返回一些更基本的东西。为了做到这一点,我有一个Transformer,它在顶部创建基本响应,然后进入下面一些更复杂的关联,然后将其全部返回。我想向转换器发送某种标志,如果为真,则只返回基本响应。但是,我正在使用分形,似乎无法想出一种能够将此标志发送到变压器的方法。VipsController@index:/***Displayalistingoftheresource.

  5. c++ - 分形编程 - 有什么方法可以优化此代码以进行实时渲染? - 2

    除了降低最大迭代次数之外,我还想尽可能优化一些代码。我听说有一些方法可以检测循环,但我尝试以不同的方式实现它,但它要么变得更慢,要么产生垃圾。显示功能未显示,因为它不是减速的原因。#pragmaonce#include#include#include#include#include#includeusingnamespacestd;templateclassFractal{public:Fractal(void);~Fractal(void);//themostimportantfunctionvectorevaluate(constsf::Rect&area,constsf::Vec

  6. c++ - 开源分形图 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭7年前。Improvethisquestion我有兴趣制作一款使用分形map来获得更逼真的地理信息的游戏。但是,我发现的唯一分形图程序仅适用于Windows,例如FractalMapper.不用说,它们也不是开源的。是否有可用的开源分形图创建器,最好使用Python或C/C++?理想情况下,我想要可以“插入”程序的东西,而不是独立的东西。

  7. php - 将参数传递给分形更改器(mutator)变换方法 - 2

    我正在使用phpleague的分形包。我有一个像这样的转换类设置classConversationTransformerextendsTransformerAbstract{publicfunctiontransform(Conversation$conversation,$user){return[];}}然而,当我尝试访问它时,我得到了missingargument2exceptionfortransform$user=$this->people->get($this->user());//conversations$conversations=$this->conversatio

  8. android - Android 上的分形应用程序 - 2

    在Android上生成分形曲线的最佳方法是什么?ShouldIuseNDK?如果不是WhatistherightclasstoextendVieworSurfaceView我生成了两个扩展View和覆盖onDraw()的分形,当迭代次数大和曲线比例太小时,生成太慢 最佳答案 您想知道如何在绘图中获得更快的速度。这个网站上有很多关于这个的信息(forexamplehereyouhavesomecharts).基本上,扩展SurfaceView会比扩展View获得更好的性能,并且通过使用GLSurfaceView会更好。您可以阅读her

  9. 分形树 - 2

    书名:代码本色:用编程模拟自然系统作者:DanielShiffman译者:周晗彬ISBN:978-7-115-36947-5第8章目录8.5 树到目前为止,我们接触的分形都是确定性的,也就是说,这类分形没有任何随机因素,每次运行都会构建出相同的结果。对于传统分形和可视化编程技术的演示,它们是非常不错的素材;但在模拟方面,它们过于准确,不够贴近自然。接下来讨论随机(非确定性)分形的构建技术。1、确定性分形技术构建本节要模拟的是带有分支的树。首先,让我们用确定性分形技术构建一棵分形树。构建规则如下:再一次,我们用递归方式构建了一个分形:树枝是一个线段,线段末尾有两根小树枝。2、实现的思路这个分形的

  10. python - 如何使用 numpy 数组加速分形生成? - 2

    这是我为使用牛顿法制作分形而编写的一个小脚本。importnumpyasnpimportmatplotlib.pyplotaspltf=np.poly1d([1,0,0,-1])#x^3-1fp=np.polyder(f)defnewton(i,guess):ifabs(f(guess))>.00001:returnnewton(i+1,guess-f(guess)/fp(guess))else:returnipic=[]foryinnp.linspace(-10,10,1000):pic.append([newton(0,x+y*1j)forxinnp.linspace(-10,10

随机推荐