Browse Source

Initial commit

Yann Weber 3 years ago
commit
49cf3b29f4
1 changed files with 176 additions and 0 deletions
  1. 176
    0
      pyasciimandel.py

+ 176
- 0
pyasciimandel.py View File

@@ -0,0 +1,176 @@
1
+#!/usr/bin/env python3
2
+# Copyright 2019 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
+            delta_xmove = 0.7 / zoom
99
+            delta_ymove = 0.5 / zoom
100
+            delta_zoom = 1.2
101
+            
102
+            if k == 'q':
103
+                exit(0)
104
+            elif k == '+':
105
+                zoom *= delta_zoom
106
+            elif k == '-':
107
+                if zoom >= delta_zoom:
108
+                    zoom /= delta_zoom
109
+            elif k == 'j':
110
+                center[1] -= delta_xmove
111
+            elif k == 'l':
112
+                center[1] += delta_xmove
113
+            elif k == 'i':
114
+                center[0] -= delta_ymove
115
+            elif k == 'k':
116
+                center[0] += delta_ymove
117
+            elif k == 's':
118
+                random.shuffle(colors)
119
+            elif k == 'S':
120
+                colors = list(std_colors)
121
+            elif k == 'd':
122
+                decimal_mode = not decimal_mode
123
+            elif k == 'p':
124
+                max_iter += 25
125
+            elif k == 'm':
126
+                max_iter -= 25
127
+            elif k == 'I':
128
+                lines, cols = stdscr.getmaxyx()
129
+                win = curses.newwin(20, 40, (lines - 20)//2,
130
+                                    (cols - 40)//2)
131
+                win.addstr(1,12, 'Current status')
132
+                win.addstr(2,12, '==============')
133
+                win.addstr(5,0, '''\
134
+ Max iteration = %d
135
+ Zoom level    = %f
136
+
137
+ X = %f
138
+ Y = %f''' % (max_iter, zoom, center[0], center[1]))
139
+                win.border()
140
+                win.refresh()
141
+                k = stdscr.getkey()
142
+            else:
143
+                lines, cols = stdscr.getmaxyx()
144
+                win = curses.newwin(22, 40, (lines - 20)//2,
145
+                                    (cols - 40)//2)
146
+                win.addstr(1,11, 'pyasciimandel')
147
+                win.addstr(2,11, '=============')
148
+                win.addstr(4,0, '''\
149
+ +   zoom in
150
+ -   zoom out
151
+ j   left
152
+ l   right
153
+ i   up
154
+ k   down
155
+ s   shuffle colors
156
+ S   standard colors
157
+ d   decimal mode (useless)
158
+ p   add 25 to maximum iterations
159
+ m   sub 25 to maximum iterations
160
+ I   information
161
+ q   quit
162
+ h   display this help
163
+''')
164
+                win.addstr(20, 1, 'Press any key to continue')
165
+                win.border()
166
+                win.refresh()
167
+                k = stdscr.getkey()
168
+                if k == 'q':
169
+                    exit(0)
170
+
171
+    finally:
172
+        curses.nocbreak()
173
+        curses.echo()
174
+        curses.endwin()
175
+    exit()
176
+

Loading…
Cancel
Save