海岸线和科赫曲线

本章绘图要点:

  • turtle模块:python标准库自带的一个模块,可用来绘制二维图形。该模块封装了底层的数据处理逻辑,向外提供了更符合手工绘图习惯的接口函数,适用于绘制对质量、精度要求不高的图形。
  • 递归:当所绘制的图形需要多次嵌套重复计算时,可采用递归策略降低程序的复杂性,减少程序的代码量。

海岸线

独上高原,眺望沧海,海洋与陆地之间,蜿蜒而行的海岸线有多长呢?这个问题似乎很简单。按照传统的几何和数学观点,有形状的东西应该都可以被测量。例如,我们可以通过尺子来测量方桌的长和宽,从而获得它的周长。而海岸线虽曲折,但只要测量足够精确,应该就可以得到一个具体的长度。但是问题在于,当用不同大小的度量标准来测量时,每次都会得出完全不同的结果。度量标准的尺度越小,测量出的海岸线长度就会越长,以至于无穷。以1km为单位测量海岸线时,近似长度短于1km的迂回曲折线就会被忽略掉,而以1m为单位测量时,则能测出这些被忽略掉的迂回曲折,长度将变大。以此类推,测量单位越小,测得的长度将越大,这些越来越大的长度并不是趋近于一个确定值,而是会无限增大,所以海岸线的长度是不确定的,或者说,在一定意义上海岸线的长度是无穷的。

为什么会这样呢?这是因为作为海洋与陆地的分界线,海岸线的形状是极不规则、极不光滑的。海岸线由无数的曲线组成,假设我们用一把固定长度的直尺,例如米尺来测量的话,海岸线上两点间小于一米的曲线,就只能用直线来近似地表示,因此,测得的长度肯定是不精确的。使用更短的尺子来量,同样也无法测量更细小的曲线。哪怕我们有一把1纳米长(1纳米大约是1米的10亿分之一)的尺子,情况依旧如此。长度也许已不能正确地概括海岸线这类不规则图形的特征。

海岸线虽然很复杂,但是却有一个重要的性质——自相似性。从不同比例尺的地形图上,我们可以看出海岸线的形状大体相同,其曲折、复杂程度也很相似,也就是说,海岸线的任一小部分都包含有与整体相同或相似的细节。如果将一段海岸线的曲线加以放大,我们会发现,这部分放大的曲线(我们称之为A曲线)与更大范围内的海岸线形状惊人地相似。如果继续放大A曲线中更小的一段,这一小段曲线的形状又与A曲线有相似性。换句话说,任意一段海岸线就象是整个海岸线按比例缩小的结果。

科赫(Koch)曲线

我们可以在计算机上生成科赫曲线来模拟海岸线。科赫曲线是瑞典数学家科赫在1904年提出的一种不规则的几何图形。它的生成方法是把一条直线等分成三段,将中间的一段用夹角为60度的两条等长折线来替代,形成一个生成元,然后再把每个直线段都用生成元来进行替换,如此经过无穷多次迭代后就呈现出了一条有无穷多弯曲的科赫曲线。如图所示:

第一次迭代(生成元):

 

第二次迭代:

 

第三次迭代:

 

第六次迭代:

 

可以看到多次迭代后的科赫曲线由无数的曲线组成。与海岸线一样,科赫曲线的局部与整体相似,也就是说,局部是整体的缩影。

算法

我们可以在计算机上用以下方法递归生成Koch曲线:

将线段三等分,描画完第一个三分之一段后逆时针方向旋转60度,接着描画三分之一段长度,再顺时针方向旋转120度,描画三分之一段长度,再逆时针方向旋转60度,描画最后三分之一段长度。

 

 

结合上图就是:

1)       初始:起始点A,角度为0;假设线段AB长度为L;

2)       线段三等分,每一段长度为L/3,从点A开始,向前描画L/3长度到达C点;

3)       逆时针方向(也就是向左)旋转60度,向前描画L/3长度,到达D点;

4)       顺时针方向(也就是向右)旋转120度,向前描画L/3长度,到达E点;

5)       逆时针方向(也就是向左)旋转60度,向前描画L/3长度,到达结束点:B点。

源码

 1 # 导入模块
 2 import turtle
 3 
 4 # 恢复海龟状态到p点
 5 def restore(p):
 6       turtle.penup()  # 抬起海龟画笔
 7       turtle.setpos(p[0],p[1]) # 移动到p点
 8       turtle.pendown() # 放下画笔
 9       turtle.seth(p[2])   # 设置海龟方向
10 
11 # 获取海龟当前点状态
12 def get_point():
13     x,y = turtle.pos()  # 获取海龟的位置
14     d = turtle.heading() # 获取海龟的方向   
15     return (x,y,d)
16 
17 # 生成器函数,A为起始点,B为结束点,L为线段AB的长度,n为递归次数
18 def Generator(A,B,L,n):
19       if n == 1:
20          # 绘制图形
21          restore(A)
22          turtle.forward(L/3) # 画笔向前移动L/3距离
23          turtle.left(60)      # 画笔方向向左旋转60度(也就是逆时针旋转)
24          turtle.forward(L/3)
25          turtle.right(120)    # 向右旋转120度(也就是顺时针旋转)
26          turtle.forward(L/3)
27          turtle.left(60)
28          turtle.setpos(B[0],B[1]) # 移动到B点,并画线
29       else:
30          # 获取中间点:C、D、E的位置和方向,不显示图形
31          restore(A)      
32          turtle.pencolor((59,209,207)) # 画笔颜色设置和背景色相同       
33          turtle.forward(L/3)
34          turtle.left(60)
35          C = get_point()     
36          turtle.forward(L/3)
37          turtle.right(120)
38          D = get_point()      
39          turtle.forward(L/3)
40          turtle.left(60)
41          E = get_point()      
42          turtle.pencolor('white') # 画笔颜色设置为白色
43          
44          # 递归调用生成器,使用生成元替换线段AC、CD、DE、EB
45          Generator(A,C,L/3,n-1)
46          Generator(C,D,L/3,n-1)
47          Generator(D,E,L/3,n-1)
48          Generator(E,B,L/3,n-1)
49     
50       return True
51 
52 # 开始主程序
53 if __name__ == '__main__':
54    # 隐藏画笔形状
55    turtle.hideturtle()
56    # 设置颜色模式
57    turtle.colormode(255)
58    # 设置背景色为海蓝色
59    turtle.bgcolor((59,209,207))
60    # 设置画笔颜色为白色
61    turtle.pencolor('white') 
62    # 设置画笔大小
63    turtle.pensize(2)
64 
65    # 设置初始值
66    A = (-450,0,0)
67    B = (450,0,0)
68    L = 900
69    n = 6
70 
71    # 生成科赫曲线
72    restore(A)
73    Generator(A,B,L,n)
 

科赫曲线彩图(海蓝色RGB(59,209,207)/白色)

程序剖析

turtle模块

turtle模块是python标准库自带的一个模块,用于绘制二维图形。在使用之前,需要使用import turtle语句导入该模块。

turtle在英文中的含义是海龟,想象一下,在画布的中间,有一只海龟,四处行走,走过的痕迹就绘成了图形。在画布中,海龟的位置是以二维笛卡尔坐标的方式来确定的,也就是x-y轴坐标,如下图:

 

海龟的初始位置在原点(0,0)处。海龟的状态除了位置以外,还有一个方向,方向以与水平的角度来确定,逆时针的角度为正数,顺时针的角度为负数。海龟的初始方向为0,也就是在原点上,向右朝向x正轴。

所以,海龟的状态可以用一个三元组(x,y,d)来表示,x和y分别代表横坐标和纵坐标,d代表方向。

以下列出了程序中所用到的turtle模块函数:

turtle.hideturtle() # 海龟画笔是有形状的,如果只想看到绘制的图形,可以使用该函数把画笔的形状隐藏起来

turtle.setpos(x,y)  # 移动海龟到指定位置,

使用turtle.setpos(x,y)改变海龟的位置,默认情况会在画布上留下痕迹,也就是一条直线。要想不留下痕迹,就必须把海龟画笔抬起来,函数是:turtle.penup(),到达指定位置后,把画笔放下来,函数是:turtle.pendown()。

turtle.seth(angle)# 海龟方向旋转angle度,这个角度是相对于水平x正轴的,和海龟当前的方向无关

                    angle为正数,逆时针旋转;angle为负数,顺时针旋转

turtle.pos() # 获取海龟的坐标位置

turtle.heading() # 获取海龟的方向

turtle.pensize(width) # 指定画笔的大小,参数width为一个正整数

 turtle.pencolor(color)# 指定画笔的颜色

turtle.bgcolor(color) # 指定画布背景的颜色

pencolor()和bgcolor()函数的参数color可以是字符串,如“red“,”yellow”,“white”等,也可以是一个RGB数字,如(255,255,0),但是,在使用RGB数字前,必须调用colormode()函数指定颜色的模式:

turtle.colormode(255) # 指定颜色的色彩取值范围为0-255的整数

turtle.forward(distance) # 画笔向前移动distance距离

turtle.left(angle)  # 海龟的方向向左旋转angle度,这个角度angle是相对于海龟当前方向的

turtle.right(angle) # 海龟的方向向右旋转angle度,这个角度angle是相对于海龟当前方向的

可以使用python自带的帮助文件,来查看模块函数的具体说明。帮助文件打开的方式:单击开始按钮,选择【所有程序】→【Python 3.6】 → 【Python 3.6 Manuals (32-bit)】,显示窗口如下:

 

单击“索引”,在输入框中输入turtle,在下拉列表中选择“turtle (module)”,显示窗口如下:

 

右边文档中包含了turtle模块所有函数的说明和示例。

递归

程序中的Generator()函数使用了递归来生成曲线。在计算机科学中,递归(Recursion)指的是函数的定义中使用函数本身的方法,也就是说,自己调用自己。递归是有去有回的“有去”指的是:递归问题可以层层分解成子问题,这些子问题与原问题定义相同,都可以采用相同的方法来解决;“有回”指的是:问题的分解不会无休止,而是会到达一个终点,从这个终点开始,问题不再分解,而是逐步解决,下层的问题解决了,导致上一层的问题解决,如此顺着原路返回,直到返回到原点,导致原问题解决。

分形图像具有自我相似、自我嵌套的特点,因此非常适合用递归算法来生成。我们来看一下函数Generator(A,B,L,n)的运行过程:

假设n为2,n不等于1,所以Generator(A,B,L,2)执行else子句:

    获取中间点:C、D、E的位置和方向,不显示图形

    然后,4次调用自身:

    首先,调用函数Generator(A,C,L/3,n-1)

         n = 2-1 = 1,所以执行if子句:

              恢复海龟状态到A点,绘制AC段图形

        Generator(A,C,L/3,n-1)程序终止

 返回到上层,继续执行函数Generator(A,B,L,2)

 函数Generator(A,B,L,2)继续调用函数Generator(C,D,L/3,n-1)

         n等于1,所以执行if子句:

             恢复海龟状态到C点,绘制CD段图形

        Generator(C,D,L/3,n-1)程序终止

 返回到上层,继续执行函数Generator(A,B,L,2)

 函数Generator(A,B,L,2)继续调用函数Generator(D,E,L/3,1)

         n等于1,所以执行if子句:

              恢复海龟状态到D点,绘制DE段图形

        Generator(D,E,L/3,1)程序终止

 返回到上层,继续执行函数Generator(A,B,L,2)

 函数Generator(A,B,L,2)继续调用函数Generator(E,B,L/3,1)

        n等于1,所以执行if子句:

            恢复海龟状态到E点,绘制EB段图形

        Generator(E,B,L/3,1)程序终止

 返回到上层,继续执行函数Generator(A,B,L,2)

 函数Generator(A,B,L,2)没有执行语句了,结束

数据可视化Tips

颜色

在信息可视化与视觉设计中,颜色、形状与布局构成了最基本的数据编码手段,其中,颜色可以编码大量的数据信息。如何设置可视化元素的颜色?采用什么样的颜色来编码数据信息,也就是如何将数据信息映射到颜色上?这些决定了可视化结果的表达力与视觉美感。

色彩空间(也称色彩模型或色彩系统)是使用一组数值(通常使用3个或4个值)来表示颜色的抽象数学模型。常用的色彩模式有CMYK、RGB以及HSB等等,其中,CMYK是在印刷上使用比较普遍的色彩模式,RGB是常用于计算机的色彩模式,而HSB的色相、饱和度和明度则是基于人眼视觉细胞而设定的。不同的色彩模式之间通常存在有损或无损的数学转换关系。

计算机采用的RGB色彩模式,R代表red(红 ),G代表green(绿),B代表blue(蓝)。红、绿、蓝叫做三原色,用它们的组合可以表示任何一种颜色。R、G和B的取值范围都是0到255,各有256种取值。通常说的“纯红”,用RGB值表示就是(255,0,0);“纯绿”用RGB表示为(0,255,0);“纯蓝”用RGB表示就是(0,0,255);“黄”色用RGB表示则为(255,255,0);“青”色用RGB表示则为(0,255,255); “粉红”色用RGB表示则为(255,0,255);任意三个值也必定对应一种颜色。如果在RGB模式上再加上一个值,就是RGBA (red, green, blue, alpha),RGBA格式的最后一个元素表示颜色的透明度。

 

 

 

 

 

 

 

 

 

 

 

 

        

posted @ 2021-03-15 15:04  timedot  阅读(744)  评论(0编辑  收藏  举报