dragon_curve.py (3288B)
1 __version__ = '0.1.0' 2 3 4 from typing import List, Tuple 5 6 7 PathType = List[Tuple[int, int]] 8 9 10 def ccw(p: Tuple[int, int]) -> Tuple[int, int]: 11 return [-p[1], p[0]] 12 13 14 def dragon_curve(generation_number: int) -> PathType: 15 l = [[0, 0], [1, 0]] 16 17 for i in range(generation_number): 18 new_portion = [ccw(n) for n in l[1:]] 19 new_pivot = new_portion[-1] 20 l = new_portion[::-1] + l 21 l = [ 22 [n[0] - new_pivot[0], 23 n[1] - new_pivot[1]] 24 for n in l] 25 26 return l 27 28 29 def write_matplotlib_png(dragon_curve_path: PathType): 30 import matplotlib.pyplot as plt 31 32 plt.scatter( 33 [n[0] for n in dragon_curve_path], 34 [n[1] for n in dragon_curve_path]) 35 plt.show() 36 plt.savefig('dragon-curve.png') 37 38 39 def transform(values, low, high): 40 min_value = min(values) 41 max_value = max(values) 42 old_difference = max_value - min_value 43 new_difference = high - low 44 # values = [n - min_value for n in values] # [0, max-min = old_difference] 45 # values = [n / old_difference for n in values] # [0, 1] 46 # values = [n * new_difference for n in values] # [0, new_difference = high - low] 47 # values = [n + low for n in values] # [low, high] 48 return [(n - min_value) * new_difference / old_difference + low 49 for n in values] 50 51 52 def path_to_svg_file_content( 53 path: PathType, 54 image_width=500, 55 image_height=500, 56 left_border=50, 57 right_border=50, 58 bottom_border=50, 59 top_border=50, 60 ) -> str: 61 path = list(zip( 62 transform([p[0] for p in path], left_border, image_width - right_border), 63 transform([p[1] for p in path], top_border, image_width - bottom_border))) 64 65 svg_path = ''.join(f'L{p[0]} {p[1]}' for p in path) 66 67 return f''' 68 <svg width="{image_width}" height="{image_height}" fill="white" xmlns="http://www.w3.org/2000/svg"> 69 70 <path fill="none" stroke="black" stroke-linejoin="round" stroke-width="0.7" d="M{path[0][0]} {path[0][1]}{svg_path}"/> 71 72 </svg> 73 '''.strip() 74 75 76 def path_to_curvy_svg_no_clue( 77 path: PathType, 78 image_width=500, 79 image_height=500, 80 left_border=50, 81 right_border=50, 82 bottom_border=50, 83 top_border=50, 84 ) -> str: 85 ''' 86 path = list(zip( 87 transform([p[0] for p in path], left_border, image_width - right_border), 88 transform([p[1] for p in path], top_border, image_width - bottom_border))) 89 ''' 90 91 min_x = min(p[0] for p in path) 92 min_y = min(p[1] for p in path) 93 max_x = max(p[0] for p in path) 94 max_y = max(p[1] for p in path) 95 96 stroke_width = (max_x - min_x) * 0.01 97 98 consecutives = list(zip(path[:-1], path[1:])) 99 100 svg_path = ''.join(f'L{p[0]} {p[1]}' for p in path) 101 102 svg_path += ( 103 ''.join( 104 f'M{pair[0][0]} {pair[0][1]}' 105 f'A2 2 0 0 0 {pair[1][0]} {pair[1][1]}' 106 for pair in consecutives)) 107 108 return f''' 109 <svg width="{image_width}" height="{image_height}" viewBox="{min_x-1} {min_y-1} {max_x-min_x+1} {max_y-min_y+1}" fill="white" xmlns="http://www.w3.org/2000/svg"> 110 111 <path fill="none" stroke="black" stroke-linejoin="round" stroke-width="{stroke_width}" d="M{path[0][0]} {path[0][1]}{svg_path}"/> 112 113 </svg> 114 '''.strip()