跳转到主要内容

一个用于在Python的turtle模块中创建分形艺术的模块。

项目描述

fractalartmaker

一个用于在Python的turtle模块中创建分形艺术的模块。

分形是递归、自相似的形状。《code>fractalartmaker模块(简称为fam)帮助您使用Python编程语言和Python的内置turtle模块创建分形。此模块基于Al Sweigart的免费书籍《递归指南》(The Recursive Guide to Recursion)中的“分形艺术制作器”章节。已进行了一些修改,以便更容易使用和实验。

快速入门

运行pip install fractalartmaker进行安装。在Windows上运行python -m fractalartmaker,在macOS上运行python3 -m fractalartmaker以运行演示并查看Al Sweigart制作的九件分形艺术作品。

首先,您需要了解一些Python编程知识和Python的turtle模块。RealPython.com有一个turtle模块教程。

您可以通过在交互式外壳(也称为REPL)中运行以下代码来查看演示分形:

>>> import fractalartmaker as fam
>>> fam.demo_four_corners()

这将在新的turtle窗口中绘制四角分形。一旦您了解了分形艺术制作器的工作原理,您就可以自己调用fam.draw_fractal()函数

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 100, [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=100)

本例绘制了一个类似Horn演示分形的分形。`fam.square` 是一个函数,它接受两个参数 sizedepth,并使用 turtle 命令绘制一个正方形(每边应为 size 步长,depth 是当前递归层级深度,对于简单的分形通常忽略)。100 是第一个绘制的正方形的初始大小。`[{'size': 0.96, 'y': 0.5, 'angle': 11}]` 是一个 递归规范字典列表。此示例表示,对于每个绘制的正方形,递归地再绘制一个正方形,其大小为原始大小的 96%,位于旋转 11 度后的正方形的上方 50%。

如果您希望每个正方形递归绘制两个更多正方形,请向此列表添加第二个字典。检查模块中的 demo_*() 函数(以及以下“演示分形画廊”部分)以获取示例。

注意:调用 fam.draw_fractal() 会自动调用 turtle.reset() 来清除窗口并将海龟光标移回 0, 0。如果您不希望这种行为,请将 reset=False 传递给 fam.draw_fractal()

为了让您无需自己导入 turtle 模块,您可以从 fam 模块调用大多数 turtle 函数:例如 fam.reset()fam.update() 等。请参阅“Python Turtle 模块速查表”以获取函数列表。

演示分形画廊

def demo_four_corners(size=350, max_depth=5, **kwargs):
    # Four Corners:
    if 'colors' not in kwargs:
        kwargs['colors'] = (('black', 'white'), ('black', 'gray'))
    draw_fractal(square, size,
        [{'size': 0.5, 'x': -0.5, 'y': 0.5},
         {'size': 0.5, 'x': 0.5, 'y': 0.5},
         {'size': 0.5, 'x': -0.5, 'y': -0.5},
         {'size': 0.5, 'x': 0.5, 'y': -0.5}], max_depth=max_depth, **kwargs)

Screenshot of Four Corners fractal

def demo_spiral_squares(size=600, max_depth=50, **kwargs):
    # Spiral Squares:
    if 'colors' not in kwargs:
        kwargs['colors'] = (('black', 'white'), ('black', 'gray'))
    draw_fractal(square, size, [{'size': 0.95,
        'angle': 7}], max_depth=max_depth, **kwargs)

Screenshot of Spiral Squares fractal

def demo_double_spiral_squares(size=600, **kwargs):
    # Double Spiral Squares:
    if 'colors' not in kwargs:
        kwargs['colors'] = (('black', 'white'), ('black', 'gray'))
    draw_fractal(square, 600,
        [{'size': 0.8, 'y': 0.1, 'angle': -10},
         {'size': 0.8, 'y': -0.1, 'angle': 10}], **kwargs)

Screenshot of Double Spiral Squares fractal

def demo_triangle_spiral(size=20, max_depth=80, **kwargs):
    # Triangle Spiral:
    draw_fractal(triangle, size,
        [{'size': 1.05, 'angle': 7}], max_depth=max_depth, **kwargs)

Screenshot of Triangle Spiral fractal

def demo_glider(size=600, **kwargs):
    # Conway's Game of Life Glider:
    if 'colors' not in kwargs:
        kwargs['colors'] = (('black', 'white'), ('black', 'gray'))
    third = 1 / 3
    draw_fractal(square, 600,
        [{'size': third, 'y': third},
         {'size': third, 'x': third},
         {'size': third, 'x': third, 'y': -third},
         {'size': third, 'y': -third},
         {'size': third, 'x': -third, 'y': -third}], **kwargs)

Screenshot of Conway Glider fractal

def demo_sierpinski_triangle(size=600, **kwargs):
    # Sierpinski Triangle:
    toMid = math.sqrt(3) / 6
    draw_fractal(triangle, 600,
        [{'size': 0.5, 'y': toMid, 'angle': 0},
         {'size': 0.5, 'y': toMid, 'angle': 120},
         {'size': 0.5, 'y': toMid, 'angle': 240}], **kwargs)

Screenshot of Sierpinski Triangle fractal

def demo_wave(size=280, **kwargs):
    # Wave:
    draw_fractal(triangle, size,
        [{'size': 0.5, 'x': -0.5, 'y': 0.5},
         {'size': 0.3, 'x': 0.5, 'y': 0.5},
         {'size': 0.5, 'y': -0.7, 'angle': 15}], **kwargs)

Screenshot of Wave fractal

def demo_horn(size=100, max_depth=100, **kwargs):
    # Horn:
    if 'colors' not in kwargs:
        kwargs['colors'] = (('black', 'white'), ('black', 'gray'))
    draw_fractal(square, size,
        [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=max_depth, **kwargs)

Screenshot of Horn fractal

def demo_snowflake(size=200, **kwargs):
    # Snowflake:
    if 'colors' not in kwargs:
        kwargs['colors'] = (('black', 'white'), ('black', 'gray'))
    draw_fractal(square, size,
        [{'x': math.cos(0 * math.pi / 180),
          'y': math.sin(0 * math.pi / 180), 'size': 0.4},
         {'x': math.cos(72 * math.pi / 180),
          'y': math.sin(72 * math.pi / 180), 'size': 0.4},
         {'x': math.cos(144 * math.pi / 180),
          'y': math.sin(144 * math.pi / 180), 'size': 0.4},
         {'x': math.cos(216 * math.pi / 180),
          'y': math.sin(216 * math.pi / 180), 'size': 0.4},
         {'x': math.cos(288 * math.pi / 180),
          'y': math.sin(288 * math.pi / 180), 'size': 0.4}], **kwargs)

Screenshot of Snowflake fractal

创建您自己的分形

使用分形艺术制作器创建分形涉及两个部分。

首先,您需要编写我所说的 形状绘制函数。这是一个使用 turtle 函数绘制简单形状的函数,该形状将被绘制数十或数百次以创建您的分形。该函数必须接受至少两个参数:第一个参数名为 size,第二个参数名为 depth

例如,此形状绘制函数绘制一个正方形(depth 参数被忽略)

def square(size, depth):
    # Move to the top-right corner before drawing:
    turtle.penup()
    turtle.forward(size // 2)
    turtle.left(90)
    turtle.forward(size // 2)
    turtle.left(180)
    turtle.pendown()

    # Draw a square:
    for i in range(4):  # Draw four lines.
        turtle.forward(size)
        turtle.right(90)

fam 库调用您的形状绘制函数,并提供适当的 size 参数。您的形状大小只需相对于传递给此参数的数字是相对的即可

您的形状绘制函数必须相对于 size 的尺寸和当前面向的方向绘制一个形状。使用相对的 turtle 函数,如 forward()back()left()right(),而不是绝对函数,如 goto()setheading()。传递给 forward()back() 调用的参数应始终取决于 size 参数,而不是静态的、固定的数字。

depth 参数是形状绘制所在的递归级别。因此,对于第一级它是 0,第二级它是 1,依此类推。您可以使用它来执行一些更高级的效果(稍后讨论)。

您的形状绘制函数不会调用自己或进行任何递归。让它保持简单:它只是使用 turtle 函数绘制一个形状。

fam 库提供了一些形状绘制函数供您使用:`fam.square()` 和 `fam.triangle()`

其次,您必须调用 fam.draw_fractal() 函数,并传递三个东西:一个形状绘制函数、起始大小(通常 100 是一个好选择)和一个 递归规范字典列表。列表中的每个字典指定了形状在递归的每个级别上的变化:`'size'` 用于大小变化,`'x'` 用于左右移动,`'y'` 用于上下移动,`'angle'` 用于旋转。

请注意,对于 Fractal Art Maker 的递归规范字典,正的 `'y'` 向上移动,负的 `'y'` 向下移动。(这与学校数学课中的图表类似,而不是计算机图形。)

例如,让我们看看 Fractal Art Maker 中包含的 Horn 演示分形。您可以通过运行 import fractalartmaker as fam; fam.demo_horn() 来查看它

Screenshot of Horn fractal

此分形是通过绘制一个正方形,然后递归地绘制一个更小的第二个正方形来制作的

  • 略小。 (确切地说是前一个正方形大小的 96%。)
  • 放置在上方。(确切地说,是前一个正方形大小的50%)
  • 顺时针轻微旋转。(确切地说,11度。)

第二个正方形(由于这个分形在白色和灰色正方形之间交替,所以是灰色)依次递归地产生一个更小的第三个正方形,放置在上方,并轻微顺时针旋转。请注意,由于第二个正方形是向左/顺时针旋转的,因此它的“上方”也相应旋转。这就是为什么后续的正方形会向左倾斜。

我们可以用以下递归指定字典来绘制:{'size': 0.96, 'y': 0.5, 'angle': 11}

因此,要在Fractal Art Maker中绘制Horn分形,我们运行以下代码

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 100, [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=100)

max_depth关键字参数表示您想要进行多少层递归。默认设置为8

如果我们传递一个'x''y'参数为0.0,则下一个递归形状不会从父形状的位置移动。如果我们传递一个'size'1.0,则下一个递归形状与父形状的大小相同。如果我们传递一个'angle'0,则下一个递归形状不旋转。如果从字典中省略了键,这些也是默认值。

虽然'angle'始终是旋转的绝对度数,但'x''y''size'的值始终相对于形状绘制函数的当前形状大小。

让我们做一个与四边形演示类似的另一个示例。运行fam.reset()以清除海龟窗口并将海龟光标放回0,0。此函数与turtle.reset()相同。我想先画一个正方形,然后递归步骤在先前的正方形上方和左方画一个更小的正方形(不旋转)。运行以下代码

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 350, [{'size': 0.5, 'x': -0.5, 'y': 0.5}], max_depth=5)

此代码绘制以下内容

Screenshot of Four Corners with only one corner drawn.

max_depth=5关键字参数防止绘制过多的正方形。(默认最大递归深度为8。)

我们可以在所有这些正方形中添加一个第二个递归正方形,通过将第二个递归指定字典添加到列表中。这个第二个字典将绘制一个向上和向右的另一个递归步骤。通过以下代码继续交互式外壳示例。注意第二个字典有一个'x'0.5而不是-0.5

>>> fam.reset()  # Clears the screen.
>>> fam.draw_fractal(fam.square, 350, [{'size': 0.5, 'x': -0.5, 'y': 0.5}, {'size': 0.5, 'x': 0.5, 'y': 0.5}], max_depth=5)

此代码绘制以下内容

Screenshot of Four Corners with only two corners drawn.

请注意,不仅仅是第一个正方形有两个递归正方形,每个得到两个递归正方形的正方形。

我们可以通过将第三个指定字典添加到列表中来添加一个第三个正方形,这个字典有一个'y'-0.5

>>> fam.reset()  # Clears the screen.
>>> fam.draw_fractal(fam.square, 350, [{'size': 0.5, 'x': -0.5, 'y': 0.5}, {'size': 0.5, 'x': 0.5, 'y': 0.5}, {'size': 0.5, 'x': -0.5, 'y': -0.5}], max_depth=5)

此代码绘制以下内容

Screenshot of Four Corners with only three corners drawn.

最后,我们可以添加一个第四个正方形

>>> fam.reset()  # Clears the screen.
>>> fam.draw_fractal(fam.square, 350, [{'size': 0.5, 'x': -0.5, 'y': 0.5}, {'size': 0.5, 'x': 0.5, 'y': 0.5}, {'size': 0.5, 'x': -0.5, 'y': -0.5}, {'size': 0.5, 'x': 0.5, 'y': -0.5}], max_depth=5)

此代码绘制以下内容

Screenshot of Four Corners with all four corners drawn.

您会注意到这个分形并不完全像fam.demo_four_corners()中的一个。我们可以在形状绘制函数中交替使用白色和灰色填充颜色。让我们看看下一个。

FAM的形状绘制函数的高级功能

所有形状绘制函数都传递一个size参数和一个depth参数。我们可以通过检查depth参数来创建白色和灰色的交替颜色。在以下形状绘制函数中,正方形的填充颜色设置为白色或灰色,取决于递归深度

def square_alternating_white_gray(size, depth):
    # Move to the top-right corner before drawing:
    turtle.penup()
    turtle.forward(size // 2)
    turtle.left(90)
    turtle.forward(size // 2)
    turtle.left(180)
    turtle.pendown()

    # Set fill color:
    if depth % 2 == 0:
        turtle.fillcolor('white')
    else:
        turtle.fillcolor('gray')

    # Draw a square:
    turtle.begin_fill()
    for i in range(4):  # Draw four lines.
        turtle.forward(size)
        turtle.right(90)
    turtle.end_fill()

待办事项:本节的其余部分尚未完成。我将快速写下代码示例和基本描述,因为只是需要完成这个教程。

Fractal Art Maker 自带的 fam.squarefam.triangle 形状绘制函数具有特殊功能,您可以通过关键字参数传递给 fam.draw_fractal() 函数。(这些功能仅适用于这两个函数。您可以按照自己的意愿编写任何具有任何功能的形状绘制函数。关键字参数将转发到您的形状绘制函数。您的形状绘制函数应具有参数 size, depth, \*\*kwargsFor,并且这些额外的参数将包含在 kwargs 字典中。《Kwargs》是 Python 的一个约定。[链接](https://realpython.com/python-kwargs-and-args/)

例如,下面是带有一些这些功能的 Horn 示例

蓝色笔色和红色填充色

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 100, [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=100, pen='blue', fill='red')

第一迭代为蓝色笔和红色填充色,第二迭代为绿色笔和黄色填充色,然后循环回到第一组颜色

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 100, [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=100, colors=[['blue', '#FF0000'], ['green', 'yellow']])

笔粗为 10

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 100, [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=100, pensize=10)

随机抖动,移动位置为大小的 25%

>>> import fractalartmaker as fam
>>> fam.draw_fractal(fam.square, 100, [{'size': 0.96, 'y': 0.5, 'angle': 11}], max_depth=100, jiggle=0.25)

Python Turtle 模块速查表

import turtle
turtle.forward(100)   # Move forward 100 steps.
turtle.backward(100)  # Move backwards 100 steps.
turtle.left(90)       # Turn left/clockwise 90 degrees.
turtle.right(90)      # Turn right/counterclockwise 90 degrees.

turtle.position()  # Return (0, 0), the current XY position of the turtle.
turtle.heading()   # Return 0.0, the current heading/direction of the turtle. (0 is right, 90 is up, 180 is left, 270 is down)

turtle.goto(30, 25)     # Move turtle to X of 30 and Y of 25.
turtle.setx(30)         # Move turtle left/right to X of 30 and current Y coordinate.
turtle.sety(25)         # Move turtle up/down to Y of 25 and current X coordinate.
turtle.towards(30, 25)  # Return degrees to turn left to face XY 30, 25 from current position/heading.
turtle.setheading(90)   # Make the turtle face up (90 degrees).

turtle.penup()    # "Raise the pen" and stop drawing as the turtle moves.
turtle.pendown()  # "Lower the pen" and start drawing as the turtle moves.

turtle.pensize(4)       # Set pen thickness size to 4. (Default is 1.)
turtle.width()          # Return 4, the current pen thickness size.
turtle.pencolor('red')  # Lines drawn will now be red. (Also use color formats '#FF0000' or (255, 0, 0))

turtle.fillcolor('white')  # Set fill color of begin_fill() and end_fill() to white.
turtle.begin_fill()        # Start drawing a filled-in shape.
turtle.end_fill()          # End drawing a filled-in shape and draw the fill color.

turtle.home()   # Move the turtle to 0, 0 and facing right (0 degrees).
turtle.clear()  # Erase all drawings on the screen, but leave the turtle in its place.
turtle.reset()  # Erase all drawings and move turtle to 0, 0 and facing right.

turtle.hideturtle()  # Don't show the turtle cursor in the window.
turtle.showturtle()  # Show the turtle cursor in the window.

turtle.bgcolor('blue')  # Make the background color of the window blue. (Default is white.)

turtle.tracer(1000, 0)  # Do 1000 turtle commands with 0 delay all at once. (Increase 1000 to make drawing speed faster.)
turtle.update()         # Call this when done to update the screen with any remaining turtle commands' drawings.

turtle.exitonclick()  # Close the window when the user clicks it.

简短函数名速查表

turtle.fd()  # forward()
turtle.bk()  # backward()
turtle.lt()  # left()
turtle.rt()  # right()

turtle.pos()  # position()

turtle.pd()  # pendown()
turtle.pu()  # penup()

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

fractalartmaker-0.2.0.tar.gz (10.0 kB 查看哈希值

上传时间

由以下支持

AWSAWS云计算和安全赞助商DatadogDatadog监控FastlyFastlyCDNGoogleGoogle下载分析MicrosoftMicrosoftPSF赞助商PingdomPingdom监控SentrySentry错误日志StatusPageStatusPage状态页面