0

我已经制作了 3 个函数来绘制希尔伯特曲线。这更像是一个数学问题,但我会包括编码以防万一。我使用turtle python模块来绘制。

第一个,这个让我推导出一个列表。

def derive(c1,c2,l,l1,l2):
    """
    derive list l by list l1 for every c1 element and by list2 for every
    c2 element. designed for hilbert fractal and dragon fractal

    :param c1: element by which l2 will derive l1
    :type c1: str
    :param c2: element by which l2 will derive l1
    :type c2: str
    :param l: list to be derived
    :type l: list
    :param l1: list to derive with
    :type l1: list
    :param l2: list to derive with
    :type l2: list
    :return: list
    :CU: l1 and l2 must only contain these elements : 'R','L','F','+','-'
    :Example:

    >>>derive('-','A',['F','-','F'],['+','+','F'])
    ['F', '+', '+', 'F', 'F']

    """

    assert type(l) in {list} and type(l1) in {list} and type(l2) in {list},'parameter l1 or l2 must be a list'
    assert type(c1) in {str} and type(c2) in {str},'parameter c1 and c2 must be a string'

    lret = []

    for e in l:
        if e != c1 and e!= c2:
#            assert type(e) in {str},'parameter l must only contain str'
#            assert e == 'R' or e == 'L' or e == 'F' or e == '+' or e == '-','parameter l1 elements must be \'R\' or \'L\' or \'F\' or \'-\' or \'+\'' 
            lret.append(e)
        elif e == c1:
            for e1 in l1:
#                assert type(e1) in {str},'parameter l1 must only contain str'
#                assert e1 == 'R' or e1 == 'L' or e1 == 'F' or e1 == '+' or e1 == '-','parameter l1 elements must be \'R\' or \'L\' or \'F\' or \'-\' or \'+\'' 
                lret.append(e1)
        elif e == c2:
            for e2 in l2:
#                assert type(e2) in {str},'parameter l2 must only contain str'
#                assert e2 == 'R' or e2 == 'L' or e2 == 'F' or e2 == '+' or e2 == '-','parameter l1 elements must be \'R\' or \'L\' or \'F\' or \'-\' or \'+\'' 
                lret.append(e2)


    return lret

第二个,这个派生第n次

def derive_n(n,c1,c2,l,l1,l2):
    """
    derive list l1 by list l2 for every c element n-th times

    :param c1: element by which l1 will derive l
    :type c1: str
    :param c2: element by which l2 will derive l
    :type c2: str
    :param l: list to be derived
    :type l: list
    :param l1: list to derived with
    :type l1: list
    :param l2: list to derive with
    :type l2: list
    :param n: number of time l1 will be derived
    :type n: int
    :return: list
    :CU: n >= 0
    :Example:

    >>>derive_n(0,'F','L',['F','-','F'],['F','+','F'],['L','R'])
    ['F', '-', 'F']

    >>>derive_n(1,'F','L',['F','-','F'],['F','+','F'],['L','R'])
    ['F', '+', 'F', '-', 'F', '+', 'F']

    >>>derive_n(2,'F','L',['F','-','F'],['F','+','F'],['L','R'])
    ['F', '+', 'F', '+', 'F', '+', 'F', '-', 'F', '+', 'F', '+', 'F', '+', 'F']


    """

    if n == 0:
        return l
    else:
        return derive(c1,c2,derive_n(n-1,c1,c2,l,l1,l2),l1,l2)

第三个函数绘制曲线:

def draw(il,l,a):
    """
    draw a fractal by following parameter il

    :param il: instruction list
    :type il: list
    :param l: length for forward() function
    :type l: float or int
    :param a: angle for left and right function in degree
    :type a: float or int
    :CU: l > 0 
    """
    assert type(a) in {int,float},'parameter a must be an int or float'
    assert type(l) in {int,float},'parameter l must be an int or float'
    assert type(il) in {list},'parameter il must be a list'
    assert l > 0,'parameter l must be strictly superior to 0'

    board_reset()

    pendown()

    for e in il:
        if e == 'F':
            forward(l)
        elif e == '+':
            left(a)
        elif e == '−':
            right(a)


    penup()

boardrese() 是一个重新初始化绘图板的函数。

这是我必须为课堂做的一个项目。我几乎完成了,但根据我的教授的说法,无论您导出多少次列表,绘图必须始终填充一个大小不变的正方形。

基本上,我需要对绘图函数的长度参数做一些数学运算。我只是不知道是什么。我试过 l/n,l/(“F”出现在最终列表中的次数),l/(最终列表的长度)...

谢谢

4

2 回答 2

0

我已经单独实现了使用turtle绘制希尔伯特曲线的代码,因为我的Processing l-systems项目中有一堆可重用的代码(如果你真的想参考以获得灵感)。它使用递归生成器而不是列表 - 这意味着它在内存中非常有效,并且只需要跟踪几个堆栈帧,并且只需要跟踪它将返回的单个“动作”。它还有一个 hacky 小 argparser 用于我自己的测试目的。

import turtle
import sys

from enum import Enum

screen = turtle.Screen()
t = turtle.Turtle()
t.speed(0)
t.pu()
t.setpos(-screen.window_width() * 0.5 + 50,
         -screen.window_height() * 0.5 + 50)
t.pd()

class HilA(Enum):
    F = 0
    L = 1
    R = 2
    A = 3
    B = 4

RULES = {HilA.A: [HilA.L, HilA.B, HilA.F, HilA.R, HilA.A, HilA.F, HilA.A, HilA.R, HilA.F, HilA.B, HilA.L],
         HilA.B: [HilA.R, HilA.A, HilA.F, HilA.L, HilA.B, HilA.F, HilA.B, HilA.L, HilA.F, HilA.A, HilA.R]}

def gen_l(depth, pattern=RULES[HilA.A], rules=RULES):
    if depth > 1:
        for i in pattern:
            if i in rules:
                yield from gen_l(depth - 1, pattern=rules[i], rules=rules)
            else:
               yield i
    else:
        yield from pattern

def draw_hil(depth):
    line_length = (min(screen.window_width(), screen.window_height()) - 100) * 2 ** -depth
    for action in gen_l(depth):
        if action == HilA.F:
            t.forward(line_length)
        elif action == HilA.L:
            t.left(90)
        elif action == HilA.R:
            t.right(90)

try:
    draw_hil(int(sys.argv[1]))
except (TypeError, IndexError):
    draw_hil(5)
print("done")
input()

但是,您几乎可以忽略所有这些 - 重要的部分是

    line_length = (min(screen.window_width(), screen.window_height()) - 100) * 2 ** -depth

这归结为

    line_length = width / (2 ** depth)

这对于深度〜= 2的任何东西都很好地限制了它。对于深度= 1,由于“连接”线与结构线的收缩因子非常快,它有点偏离。

请注意,这不考虑除 90 以外的任何角度,但就我而言,这没有多大意义,因为只有角度 90 会产生一个正方形来约束自己。如果你确实需要其他角度,你可能需要一些触发。

于 2017-10-05T16:14:27.950 回答
0

一种方法不是围绕问题进行编码,而是更改您的坐标系以适应。例如在 Python 乌龟中:

recursions = 5  # or whatever

size = 2 ** recursions

screen = Screen()  # whatever window size you want via .setup()
screen.setworldcoordinates(0, 0, size, size)
于 2017-10-05T18:41:23.487 回答