【问题标题】:Recursive Sierpinski carpet using turtle graphics使用海龟图形的递归谢尔宾斯基地毯
【发布时间】:2019-07-21 13:45:56
【问题描述】:

本题基于python递归。这应该在 degree = 4 的情况下完成,因此有 4 个不同级别的框。我的问题是,对于我已经拥有的代码,它对于其他学位的绘制效果不佳。请让我知道我做错了什么,下面是我用来让我的所有价值观都起作用的代码。

import turtle


def drawboxes(points, color, myTurtle):
    myTurtle.fillcolor(color)
    myTurtle.up()  # Pen up
    myTurtle.goto(points[0][0], points[0][1])
    myTurtle.down()  # Pen down
    myTurtle.begin_fill()
    myTurtle.goto(points[1][0], points[1][1])
    myTurtle.goto(points[2][0], points[2][1])
    myTurtle.goto(points[3][0], points[3][1])
    myTurtle.goto(points[0][0], points[0][1])
    myTurtle.end_fill()

def getMid1(p1, p2):
    return ((p1[0] + p2[0]) / 3, (p1[1] + p2[1]) / 3)

def getMid2(p1, p2):
    return ((p1[0] + p2[0]) / 3 * 2, (p1[1] + p2[1]) / 3 * 2)

def getMid3(p1, p2):
    return ((p1[0] + p2[0]) / 3 * 2, (p1[1] + p2[1]) / 3)

def getMid4(p1, p2):
    return ((p1[0] + p2[0]) / 3, (p1[1] + p2[1]) / 3 * 2)

def getMid5(p1, p2):
    return ((p1[0] + p2[0]) / 3, p1[1] + p2[1])

def getMid6(p1, p2):
    return ((p1[0] + p2[0]) / 3 * 2, (p1[1] + p2[1]))

def getMid7(p1, p2):
    return ((p1[0] + p2[0]), (p1[1] + p2[1]) / 3 * 2)

def getMid8(p1, p2):
    return ((p1[0] + p2[0]), (p1[1] + p2[1]) / 3)

def sierpinski(points, degree, myTurtle):
    colormap = ['blue', 'red', 'green', 'cyan', 'yellow',
                'violet', 'orange']

    drawboxes(points,colormap[degree], myTurtle)

    if degree > 0:
        sierpinski([points[0],
                getMid1(points[0], points[1]),
                getMid1(points[0], points[2]),
                getMid1(points[0], points[3])],
               degree-1, myTurtle)
        sierpinski([getMid1(points[0], points[1]),
                getMid2(points[0], points[1]),
                getMid4(points[0], points[2]),
                getMid1(points[0], points[2])],
               degree-1, myTurtle)
        sierpinski([points[1],
                    getMid2(points[0], points[1]),
                    getMid4(points[1], points[3]),
                    getMid5(points[1], points[3])],
                   degree - 1, myTurtle)
        sierpinski([getMid5(points[1], points[3]),
                    getMid4(points[0], points[2]),
                    getMid2(points[1], points[3]),
                    getMid6(points[1], points[3])],
                   degree - 1, myTurtle)
        sierpinski([getMid2(points[1], points[3]),
                    getMid6(points[1], points[3]),
                    points[2],
                    getMid7(points[1], points[3])],
                   degree - 1, myTurtle)
        sierpinski([getMid3(points[1], points[3]),
                    getMid2(points[1], points[3]),
                    getMid7(points[1], points[3]),
                    getMid8(points[1], points[3])],
                   degree - 1, myTurtle)
        sierpinski([getMid2(points[0], points[3]),
                    getMid3(points[1], points[3]),
                    getMid8(points[1], points[3]),
                    points[3]],
                   degree - 1, myTurtle)
        sierpinski([getMid1(points[0], points[3]),
                    getMid1(points[0], points[2]),
                    getMid3(points[1], points[3]),
                    getMid2(points[0], points[3])],
                   degree - 1, myTurtle)


def main():
    myTurtle = turtle.Turtle()
    myTurtle.speed(10)  # adjust the drawing speed here
    myWin = turtle.Screen()
    # 3 points of the first triangle based on [x,y] coordinates
    myPoints = [[0, 0], [0, 300], [300, 300], [300, 0]]
    degree = 1  # Vary the degree of complexity here
    # first call of the recursive function
    sierpinski(myPoints, degree, myTurtle)

    myTurtle.hideturtle()  # hide the turtle cursor after drawing is
# completed
    myWin.exitonclick()  # Exit program when user click on window


main()

【问题讨论】:

  • 我放慢了速度,看看它是如何工作的,并了解哪里可能出现问题,但我不知道。很久以前我制作了自己的版本,但我发现它的工作方式不同,而且要小得多:furas/python-examples/turtle/sierpinski-carpet 我不计算点来绘制矩形,而是计算与forward()left()/right() 一起使用的长度@
  • 所以唯一的方法就是以某种方式对其进行调试。您可以在某个时刻放慢速度并在变量中显示值。也许它有助于看到问题。也许某些值被四舍五入太多或
  • 版主注意:请不要破坏您的帖子。一旦您发布问题,它们就属于该网站及其用户。即使它不再对您有用,它也可能对将来的某人有所帮助。回答者也会努力写下他们的答案,如果您从帖子中删除了内容,这将不再有用。另外,请注意,通过在 Stack Exchange 网络上发布,您已授予 SE 分发该内容的不可撤销的权利(根据 CC BY-SA 3.0 许可)。根据 SE 政策,任何破坏行为都将被撤销。

标签: python recursion turtle-graphics fractals


【解决方案1】:

我对你称四个有角的形状“三角形”感到困惑。继续:

我相信您的代码的问题在于您如何确定每次递归的原点 - 正如所写的那样,代码返回绝对 (0, 0) 的频率比它应该的要高。为了理解您的代码,我将其拆开并重新组合在一起。但它现在是一个非常不同的野兽。我调用了turtle 的Vec2D 来作为一个整体来操作位置,而不是分别操作它们的X 和Y 坐标。我用循环替换了你的八个递归调用块:

from turtle import Screen, Turtle, Vec2D

COLOR_MAP = ['blue', 'red', 'green', 'cyan', 'yellow', 'violet', 'orange']

def drawRectangle(points, color, myTurtle):
    myTurtle.fillcolor(color)

    myTurtle.begin_fill()

    for point in points:
        myTurtle.goto(point)

    myTurtle.goto(points[0])

    myTurtle.end_fill()

def sierpinski(points, degree, myTurtle):

    """ Draw a rectangle based on the 4 points given """

    drawRectangle(points, COLOR_MAP[degree % len(COLOR_MAP)], myTurtle)

    if degree > 0:
        origin = points[0] * (2 / 3)  # vectors multiply by a scalar, but not divide

        points = [point * (1 / 3) for point in points]  # new rectangle is 1/3 size of old rectangle

        width, height = points[2] - points[0]  # vector subtraction

        for y in range(3):
            for x in range(3):
                if x == 1 == y:
                    continue  # leave hole in the center

                offset = origin + Vec2D(width * x, height * y)

                sierpinski([offset + point for point in points], degree - 1, myTurtle)

def main():
    # 4 points of the first rectangle based on [x, y] coordinates
    POINTS = [Vec2D(0, 0), Vec2D(0, 300), Vec2D(300, 300), Vec2D(300, 0)]

    myWin = Screen()
    myWin.tracer(False)

    myTurtle = Turtle()
    myTurtle.penup()

    degree = 3  # Vary the degree of complexity here
    # first call of the recursive function
    sierpinski(POINTS, degree, myTurtle)

    myTurtle.hideturtle()  # hide turtle cursor after drawing is completed

    myWin.tracer(True)
    myWin.exitonclick()  # Exit program when user click on window

main()

我意识到这不是您可以直接合并的代码,但希望其中的一些想法会有所帮助,并且能够打印和比较位置。

【讨论】:

    【解决方案2】:

    您的某些计算仅在 P1 为 (0,0) 时才能正确运行,但在 P1 不同时给出错误结果。

    对于getMid1,你有

     X = (A + B)/3
    

    A=0, B=3 给出正确的结果

     X = (0 + 3)/3 = 1          
    

    它是A和B之间距离的1/3处的点

    但是对于 A=1,B=2 给出

     X = (1 + 2)/3 = 1          
    

    所以它给出了X=A,但正确的值是X=1+(1/3)

    正确的结果给出公式

     X = A + ((B - A)/3)
    

     X = A + (1/3 * (B-A))
    

    其他点应该有类似的公式,但我还没有检查。

     X = A + (0/3 * (B-A)) # = A
     X = A + (1/3 * (B-A)) 
     X = A + (2/3 * (B-A))
     X = A + (3/3 * (B-A)) # = B
    

    编辑:

    使用我的公式我创建了工作代码。

    但我将代码减少为一个函数 get() 而不是八个 getMid1 ... getMid8。它使用VH来计算V/3H/30/31/32/33/3

    def get(p1, p2, V, H, show=False): # Vertical, Horizontal
        x1, y1 = p1
        x2, y2 = p2
    
        dx = x2 - x1
        dy = y2 - y1
    
        new_x = x1 + V/3 * dx
        new_y = y1 + H/3 * dy
    
        if show:
            print('NEW:', new_x, new_y)
    
        return new_x, new_y
    

    在计算中我也只使用points[0], points[2],因为我可以在points[0], points[2] 中找到points[1], points[3] 中的值

    完整代码:

    import turtle
    
    def drawTriangle(points, color, myTurtle, show=False):
        if show:
            print('DRAW:', points)
    
        myTurtle.fillcolor(color)
        myTurtle.up()  # Pen up
        myTurtle.goto(points[0][0], points[0][1])
        myTurtle.down()  # Pen down
        myTurtle.begin_fill()
        myTurtle.goto(points[1][0], points[1][1])
        myTurtle.goto(points[2][0], points[2][1])
        myTurtle.goto(points[3][0], points[3][1])
        myTurtle.goto(points[0][0], points[0][1])
        myTurtle.end_fill()
    
    
    def get(p1, p2, V, H, show=False): # Vertical, Horizontal
        x1, y1 = p1
        x2, y2 = p2
    
        dx = x2 - x1
        dy = y2 - y1
    
        new_x = x1 + V/3 * dx
        new_y = y1 + H/3 * dy
    
        if show:
            print('NEW:', new_x, new_y)
    
        return new_x, new_y
    
    
    def sierpinski(points, degree, myTurtle):
    
        colormap = ['blue', 'red', 'green', 'cyan', 'yellow',
                    'violet', 'orange']
    
        # Draw a triangle based on the 3 points given
        drawTriangle(points, colormap[degree], myTurtle)
    
        if degree > 0:
            #print('--- 1 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 0, 0),
                    get(points[0], points[2], 0, 1),
                    get(points[0], points[2], 1, 1),
                    get(points[0], points[2], 1, 0)
                   ], degree-1, myTurtle)
    
            #print('--- 2 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 0, 1),
                    get(points[0], points[2], 0, 2),
                    get(points[0], points[2], 1, 2),
                    get(points[0], points[2], 1, 1)
                   ], degree-1, myTurtle)
    
            #print('--- 3 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 0, 2),
                    get(points[0], points[2], 0, 3),
                    get(points[0], points[2], 1, 3),
                    get(points[0], points[2], 1, 2)
                   ], degree-1, myTurtle)
    
            #print('--- 4 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 1, 2),
                    get(points[0], points[2], 1, 3),
                    get(points[0], points[2], 2, 3),
                    get(points[0], points[2], 2, 2)
                   ], degree-1, myTurtle)
    
            #print('--- 5 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 2, 2),
                    get(points[0], points[2], 2, 3),
                    get(points[0], points[2], 3, 3),
                    get(points[0], points[2], 3, 2)
                   ], degree-1, myTurtle)
    
            #print('--- 6 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 2, 1),
                    get(points[0], points[2], 2, 2),
                    get(points[0], points[2], 3, 2),
                    get(points[0], points[2], 3, 1)
                   ], degree-1, myTurtle)
    
            #print('--- 7 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 2, 0),
                    get(points[0], points[2], 2, 1),
                    get(points[0], points[2], 3, 1),
                    get(points[0], points[2], 3, 0)
                   ], degree-1, myTurtle)
    
            #print('--- 8 ---')
            #print(points)
            sierpinski([
                    get(points[0], points[2], 1, 0),
                    get(points[0], points[2], 1, 1),
                    get(points[0], points[2], 2, 1),
                    get(points[0], points[2], 2, 0)
                   ], degree-1, myTurtle)
    
    
    def main():
        myTurtle = turtle.Turtle()
        myTurtle.speed(0)  # adjust the drawing speed here
        myWin = turtle.Screen()
    
        size = 300
        # 3 points of the first triangle based on [x,y] coordinates
        myPoints = [[0, 0], [0, size], [size, size], [size, 0]]
    
        degree = 3  # Vary the degree of complexity here
    
        # first call of the recursive function
        sierpinski(myPoints, degree, myTurtle)
    
        myTurtle.hideturtle()  # hide the turtle cursor after drawing is completed
        myWin.exitonclick()  # Exit program when user click on window
    
    
    main()
    

    【讨论】:

      猜你喜欢
      • 2014-11-04
      • 2018-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多