Browse Source

Initial commit

Yann Weber 3 years ago
commit
54e453f70c
1 changed files with 177 additions and 0 deletions
  1. 177
    0
      pyasciimandel.py

+ 177
- 0
pyasciimandel.py View File

@@ -0,0 +1,177 @@
1
+#!/usr/bin/env python3
2
+# Copyright 2020 Yann Weber <yannweb@member.fsf.org>
3
+#
4
+# pyasciimandel is free software: you can redistribute it and/or modify
5
+# it under the terms of the GNU General Public License as published by
6
+# the Free Software Foundation, either version 3 of the License, or
7
+# any later version.
8
+#
9
+# pyasciimandel is distributed in the hope that it will be useful,
10
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+# GNU General Public License for more details.
13
+#
14
+# You should have received a copy of the GNU General Public License
15
+# along with pyasciimandel.  If not, see <http://www.gnu.org/licenses/>.
16
+#
17
+import sys
18
+import os
19
+import random
20
+import curses
21
+import multiprocessing
22
+
23
+
24
+def in_set(x0, y0, colors, max_iter):
25
+    """ Return True if given point is in mandel set"""
26
+    c = y0 * 1j + x0
27
+    z = 0.0j+0.0
28
+    i = 0
29
+    for i in range(max_iter):
30
+        z = z**2 + c
31
+        if z.imag ** 2 + z.real ** 2 >= 4:
32
+            return colors[int(i * len(colors) / max_iter)]
33
+    return ' '
34
+
35
+
36
+def process_line(args):
37
+    point_list, colors, max_iter = args
38
+    return ''.join([in_set(x, y, colors, max_iter) for y, x in point_list])
39
+
40
+
41
+def fill_screen_multi(stdscr, pool, zoom, center, colors, max_iter):
42
+
43
+    lines, cols = stdscr.getmaxyx()
44
+    lines-=1
45
+    term_sz = lines, cols
46
+    set_len = (2, 3)
47
+
48
+    deltas = [ set_len[i] / zoom / term_sz[i] for i in range(2)]
49
+    ranges = [ (int(-sz/2), int(sz/2)) for sz in term_sz]
50
+
51
+    ys, xs = [ [center[c] + (i * deltas[c]) for i in range(*ranges[c])]
52
+               for c in range(2)]
53
+
54
+    points = [([(y, x) for x in xs], colors, max_iter) for y in ys]
55
+
56
+
57
+    for i, line in enumerate(pool.imap(process_line, points)):
58
+        stdscr.addstr(i,0, line)
59
+
60
+
61
+if __name__ == '__main__':
62
+
63
+    center = [0,-0.5] # Mandelbrot Set center (y,x)
64
+    # other color sets
65
+    #std_colors = ".,:;-=+*oO8&@#"
66
+    #std_colors = ".:-=+*#%@"
67
+    #std_colors = '.\'`^",:;-=+*mwqpdbkhaoOIlXYUJCLQ0OZ><?][}{)(|\\/#MW&8%B@$'
68
+    std_colors = '.\'`^",:;-=+*mwaoO><?][}{)(|\\/#MW&8%B@$'
69
+    colors = list(std_colors)
70
+
71
+    max_iter = 290
72
+    zoom = 1
73
+    decimal_mode = False
74
+
75
+    pool = multiprocessing.Pool(os.cpu_count())
76
+    stdscr = curses.initscr()
77
+    curses.noecho()
78
+    curses.cbreak()
79
+    try:
80
+        while True:
81
+            iter2cols = lambda i, max_i: colors[int(i * len(colors) / max_iter)]
82
+            fill_screen_multi(stdscr, pool, zoom, center, colors, max_iter)
83
+            stdscr.refresh()
84
+            k = stdscr.getkey()
85
+            if k == '\x1b':
86
+                if stdscr.getkey() != '[':
87
+                    continue
88
+                stdscr.refresh()
89
+                k = stdscr.getkey()
90
+                kmap = {'D':'j', 'A':'i', 'B':'k', 'C':'l'}
91
+                if k in kmap:
92
+                    k = kmap[k]
93
+                else:
94
+                    print('\\1b[%r' % k, file=sys.stderr)
95
+                    sys.stderr.flush()
96
+                    continue
97
+
98
+
99
+            delta_xmove = 0.7 / zoom
100
+            delta_ymove = 0.5 / zoom
101
+            delta_zoom = 1.2
102
+            
103
+            if k == 'q':
104
+                exit(0)
105
+            elif k == '+':
106
+                zoom *= delta_zoom
107
+            elif k == '-':
108
+                if zoom >= delta_zoom:
109
+                    zoom /= delta_zoom
110
+            elif k == 'j':
111
+                center[1] -= delta_xmove
112
+            elif k == 'l':
113
+                center[1] += delta_xmove
114
+            elif k == 'i':
115
+                center[0] -= delta_ymove
116
+            elif k == 'k':
117
+                center[0] += delta_ymove
118
+            elif k == 's':
119
+                random.shuffle(colors)
120
+            elif k == 'S':
121
+                colors = list(std_colors)
122
+            elif k == 'd':
123
+                decimal_mode = not decimal_mode
124
+            elif k == 'p':
125
+                max_iter += 25
126
+            elif k == 'm':
127
+                max_iter -= 25
128
+            elif k == 'I':
129
+                lines, cols = stdscr.getmaxyx()
130
+                win = curses.newwin(20, 40, (lines - 20)//2,
131
+                                    (cols - 40)//2)
132
+                win.addstr(1,12, 'Current status')
133
+                win.addstr(2,12, '==============')
134
+                win.addstr(5,0, '''\
135
+ Max iteration = %d
136
+ Zoom level    = %f
137
+
138
+ X = %f
139
+ Y = %f''' % (max_iter, zoom, center[0], center[1]))
140
+                win.border()
141
+                win.refresh()
142
+                k = stdscr.getkey()
143
+            else:
144
+                lines, cols = stdscr.getmaxyx()
145
+                win = curses.newwin(22, 40, (lines - 20)//2,
146
+                                    (cols - 40)//2)
147
+                win.addstr(1,11, 'pyasciimandel')
148
+                win.addstr(2,11, '=============')
149
+                win.addstr(4,0, '''\
150
+ +   zoom in
151
+ -   zoom out
152
+ j   left
153
+ l   right
154
+ i   up
155
+ k   down
156
+ s   shuffle colors
157
+ S   standard colors
158
+ d   decimal mode (useless)
159
+ p   add 25 to maximum iterations
160
+ m   sub 25 to maximum iterations
161
+ I   information
162
+ q   quit
163
+ h   display this help
164
+''')
165
+                win.addstr(20, 1, 'Press any key to continue')
166
+                win.border()
167
+                win.refresh()
168
+                k = stdscr.getkey()
169
+                if k == 'q':
170
+                    exit(0)
171
+
172
+    finally:
173
+        curses.nocbreak()
174
+        curses.echo()
175
+        curses.endwin()
176
+    exit()
177
+

Loading…
Cancel
Save