美文网首页
科赫曲线和ArrayList技术

科赫曲线和ArrayList技术

作者: 大龙10 | 来源:发表于2022-07-29 06:12 被阅读0次

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

8.4 科赫曲线和ArrayList技术

  • 递归函数是构建分形图案的一种技术。
  • 然而,如果你想把上面的康托尔集变成单个对象,能独立地移动,该怎么做?递归函数简单优雅,但它只能产生图案,无法把图案当作对象。
  • 有一种技术能让我们在产生分形图案的同时,还能把图案的各个部分当作对象,那就是把递归和ArrayList结合在一起。

1、科赫曲线规则

另一个有名的分形图案,它是由瑞典数学家海里格·冯·科赫于1904年提出的,下面列出了它的规则。(它的初始状态和康托尔集一样,都是一条线段。)

它的结果如下:


2、“怪物”曲线

  • 科赫曲线(即Koch Curve,和其他分形图案通常被称为“数学怪物”。因为分形经过无数次递归之后,将会出现一个奇怪的悖论:假设起始长度是1,第一次迭代后,科赫曲线的长度将会变成原来的4/3(每个线段的长度都是起始长度的1/3);再做一次迭代,长度会变成原来的16/9;经过无数次迭代之后,科赫曲线的长度会接近无穷大。然而,它依然能被这个狭小的空间(屏幕)容纳。
  • 由于我们工作在有限的像素空间内,因此并不需要考虑这个悖论。我们必须限制科赫规则的递归作用次数,以避免程序耗尽内存或崩溃。

3、对象实现

  • 前面我们用递归实现了康托尔集,在这里我们依然可以用递归实现科赫曲线。但我们打算稍稍改变其中的实现方式:把科赫曲线的每个线段当作单独的对象。
  • 这么做会增添很多新的设计思路,比如,我们可以让这些线段对象单独移动,参与物理模拟。除此之外,我们还可以用随机颜色和线条宽度绘制每个线段对象。
  • 为了把每个线段当作单独的对象,我们必须先设计这些对象:对象存放了哪些数据,以及对象有什么功能?

4、科赫曲线实现

  • 科赫曲线是一系列相互连接的线段。我们打算用KochLine对象表示这些线段。每个科赫线段都有一个起点(a)和终点(b)。这些点都是向量对象。其中的线段可以用Processing的line()函数绘制。
class KochLine {
  PVector a;   线段的起点和终点
  PVector b;

  KochLine(PVector start, PVector end) {
    a = start.get();
    b = end.get();
  }

  void display() {
    stroke(0);
    line(a.x, a.y, b.x, b.y);    在起点和终点之间画一条线段
  }
  • 有了KochLine类之后,我们就可以开始实现主程序了。我们需要用一个数据结构存放曲线中的KochLine对象,ArrayList是一个合理的选择。
    ArrayList<KochLine> lines;

5、setup()函数

  • setup()函数负责ArrayList实例的创建和初始化。
    我们应该在ArrayList中加入一个初始线段,线段从0开始,横向贯穿Sketch屏幕。
void setup() {
    size(600, 300);
    lines = new ArrayList<KochLine>(); 创建ArrayList对象
    PVector start = new PVector(0, 200); 屏幕的左边
    PVector end = new PVector(width, 200); 屏幕的右边
    lines.add(new KochLine(start, end)); 第一个KochLine对象
}

6、draw()函数

void draw() {
    background(255);
    for (KochLine l : lines) {
        l.display();
    }
}

这就是代码框架,回顾一下到目前为止我们实现了什么。

  • KochLine类  表示点A到点B之间的线段。
  • ArrayList  KochLine对象组成的列表。

7、实现科赫规则和递归过程

你还记得生命游戏中细胞自动机的实现吗?

  • 在生命游戏的模拟过程中,我们始终保持两个状态列表:当前代和下一代的细胞状态。在一次迭代完成后,我们就把下一代状态变成当前代,再开始新一代的计算。
  • 本例可以使用类似的技术,用一个ArrayList跟踪当前的KochLine对象集(在程序开始时,只有一个KochLine对象集),用第二个ArrayList存放由科赫规则产生的新KochLine对象。
  • 每一个KochLine对象都会产生4个新的KochLine对象,我们应该把这些新对象放到下一代ArrayList中。当前ArrayList遍历完成之后,下一代ArrayList就会成为当前的ArrayList。


void generate() {
    ArrayList next = new ArrayList<KochLine>();   创建下一代ArrayList对象……
    for (KochLine l : lines) {   ……对当前的每一个线段
        next.add(new KochLine(???, ???));   添加4条新线段(我们必须计算这些新线段的位置)
        next.add(new KochLine(???, ???));
        next.add(new KochLine(???, ???));
        next.add(new KochLine(???, ???));
    }
    lines = next;   现在我们只关心新的ArrayList
}
  • 通过一次次调用generate()函数(比如,每次鼠标按下时),我们递归地把科赫曲线规则作用在当前的KochLine对象上。当然,上面的代码并没有实现科赫规则。科赫规则将一条线段分解成4条线段。我们可以用一些简单的算术和三角函数完成计算。由于KochLine对象用到了向量,因此这是一个实践向量运算的绝好机会。我们先来找出KochLine对象的分解点。


  • 从上图可以看出,为了产生新的KochLine对象,我们需要找到5个点(图中的a、b、c、d和e),然后根据这些点创建线段(线段ab、cb、cd和de)。

  • 如何找到这几个点?现在我们有了KochLine对象,何不让它帮我们计算这些点?

void generate() {
    ArrayList next = new ArrayList<KochLine>();
    for (KochLine l : lines) {
        PVector a = l.kochA();   KochLine对象有5个函数,每个函数都返回一个根据科赫规则产生
        PVector b = l.kochB();
        PVector c = l.kochC();
        PVector d = l.kochD();
        PVector e = l.kochE();
        next.add(new KochLine(a, b));
        next.add(new KochLine(b, c));
        next.add(new KochLine(c, d));
        next.add(new KochLine(d, e));
    }
    lines = next;
}
  • 现在我们需要在KochLine类中实现这5个函数,每个函数分别返回图8-16中的某个点。我们先搞定kochA()函数和kochE()函数,它们分别返回原始线段的起点和终点。
  • 下面计算点B和点D,点B位于线段的1/3处,而点D位于线段的2/3处。它们的方向都是由起点指向终点,长度分别为原始线段长度的1/3和2/3。


PVector kochB() {
    PVector v = PVector.sub(end, start); 从起点到终点的PVector向量
    v.div(3); 将长度缩短为1/3
    v.add(start); 向量加上起点,得到新的点
    return v;
}
PVector kochD() {
    PVector v = PVector.sub(end, start);
    v.mult(2/3.0); 和前面的计算步骤一样,但我们需要移动2/3的长度
    v.add(start);
    return v;
}
  • 点C是最难计算的。但如果你知道等边三角形的内角都是60度,事情将会变得简单。我们只要将一个1/3长度的向量旋转60度,再从点B沿着这个向量移动,就能得到点C!


PVector kochC() {
    PVector a = start.get(); 从起点开始
    PVector v = PVector.sub(end, start);
    v.div(3); 移动1/3长度到点B
    a.add(v);
    v.rotate(-radians(60)); 将以上向量旋转60度
    a.add(v); 沿着这个向量移动到点C
    return a;
}

8、结果

  • 将上述代码整合在一起,如果我们在step()函数中调用5次generate()函数,就能得到以下结果。


相关文章

  • 科赫曲线和ArrayList技术

    书名:代码本色:用编程模拟自然系统作者:Daniel Shiffman译者:周晗彬ISBN:978-7-115-3...

  • 2018-12-08 科赫雪花绘制

    科赫曲线绘制源代码 #KochDrawV1.py importturtle defkoch(size,n): if...

  • scratch3数学之美11-雪花飘飘

    大家好,我是爱编程的小熊,上一节我们学习了绘制曼陀罗曲线,曲线的无序凌乱让人惊叹。这节,让我们来学习绘制科赫雪花吧...

  • 2016年 地球上最有钱的十个人是谁?

    第十名/第九名:科氏工业集团老板科赫兄弟(查尔斯.科赫和大卫.科赫) 之所以把第九名和第十名放在一起介绍,是因为这...

  • 2020-04-14 《复杂》- 科赫曲线

    最近在看《复杂》,内容没看完,为了提交不出局作用,将我感兴趣的科赫曲线的说明截取下来。 主要内容都是《复杂》的内容...

  • 《世界的凛冬》

    茉黛母女计划从纳粹军官科赫手中偷取情报被马科赫发觉,事态失控之下三个女人失手打死了马科赫,之后卡拉和艾达冒险 出门...

  • 今日份打卡 205/365

    技术文章RandomAccess接口ArrayList和LinkedList其中的区别Collections源码中...

  • Java 集合

    集合主要技术了解Collection和MapCollection接口ArrayList类HashSet类HashM...

  • 赫克曼曲线

    【书名】:巜盈得——与百位领航者探寻教育创新》 【日期】:2022.4.11 一、【关键词】: 陪伴 二、【金句1...

  • Hype Cycle/银行发展基本线索

    ·Hype Cycle(By Gartner美国高德纳咨询公司):技术成熟度曲线,又称技术循环曲线,光环曲线,炒作...

网友评论

      本文标题:科赫曲线和ArrayList技术

      本文链接:https://www.haomeiwen.com/subject/soggirtx.html