2017-10-05 5 views
0

J'ai effectué 3 fonctions pour tracer une courbe d'hilbert. c'est plus un problème de maths mais j'inclurai le codage juste au cas où. J'utilise le module tortue python pour dessiner.Comment puis-je m'assurer que ma courbe hilbert remplisse toujours un espace de la même zone?

Le premier, celui-ci me laisse dériver une liste.

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 

2e, celui-ci dérivent énième

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) 

la troisième fonction dessine la courbe:

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() est une fonction de réinitialiser à la planche à dessin.

c'est un projet que je dois faire pour la classe. Je l'ai presque fini mais selon mon professeur, peu importe combien de temps vous dérivez la liste, le dessin doit toujours remplir un carré avec une taille qui ne change pas.

fondamentalement, j'ai besoin de faire quelques calculs sur le paramètre de longueur pour la fonction draw. Je ne sais pas quoi. J'ai essayé l/n, l/(nombre de temps 'F' apparaît dans la liste finale), l/(longueur de la liste finale) ...

grâce

+0

Considérez que chaque itération prend deux fois plus de largeur - donc vous devez générer l par quelque chose comme 'largeur/(2 profondeur **)' –

Répondre

0

J'ai Code implémentés séparément pour dessiner une courbe de Hilbert en utilisant la tortue, car j'avais un tas de code réutilisable qui traînait dans mon projet Processing l-systems (si vous voulez vraiment vous référer à it pour l'inspiration). Il utilise un générateur récursif plutôt qu'une liste - cela signifie qu'il est assez efficace en mémoire, et qu'il a juste besoin de garder trace de quelques cadres de pile, et seulement de la seule "action" qu'il va retourner. Il a également un petit argparser hacky pour mes propres tests.

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() 

Cependant, vous pouvez très ignores beaucoup tout cela - la partie importante est

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

Cela se résume à

line_length = width/(2 ** depth) 

Ce confine assez bien pour quoi que ce soit sur la profondeur ~ = 2. Pour la profondeur = 1, c'est un peu à cause du facteur de rétrécissement très rapide dans les lignes de «connexion» par rapport aux lignes structurelles. Notez que cela ne tient pas compte d'un angle autre que 90, mais en ce qui me concerne cela n'aurait pas beaucoup de sens, car seul l'angle 90 produira un carré pour se lier. Si vous avez besoin d'autres angles, vous pourriez avoir besoin de trig pour cela.

+0

j'ai essayé divisant la longueur par 2 ** profondeur mais ça ne marche pas. ça devient de plus en plus gros. :/ –

+0

edit to previous comment: en fait, je pense que mon professeur a dit que le chiffre se rapprocherait d'une certaine taille mais n'atteindrait jamais cette taille.Je vais essayer avec plus de profondeur et voir si ça a marché –

0

Une approche consiste à ne pas coder autour du problème, mais plutôt à modifier votre système de coordonnées pour s'adapter. Par exemple, dans la tortue Python:

recursions = 5 # or whatever 

size = 2 ** recursions 

screen = Screen() # whatever window size you want via .setup() 
screen.setworldcoordinates(0, 0, size, size) 
+0

je ne sais pas si je l'ai bien fait mais j'ai essayé de faire ce que tu as fait mais il a seulement fait torturer quelque part en bas de l'écran –

+0

@oozmakoopa, selon ce qui te coordonne Si vous utilisez, vous pouvez utiliser 'screen.setworldcoordinates (-size // 2, -size // 2, size // 2, size // 2)' à la place. – cdlane