MathArtist

Форк
0
/
operators.pyx 
465 строк · 14.2 Кб
1

2
# Copyright (c) 2018, Yaroslav Zotov, https://github.com/qiray/
3
# All rights reserved.
4

5
# This file is part of MathArtist.
6

7
# MathArtist is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11

12
# MathArtist is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16

17
# You should have received a copy of the GNU General Public License
18
# along with MathArtist.  If not, see <https://www.gnu.org/licenses/>.
19

20
################################################################################
21

22
# This file uses code from Andrej Bauer's randomart project under 
23
# following conditions:
24

25
# Copyright (c) 2010, Andrej Bauer, http://andrej.com/
26
# All rights reserved.
27
#
28
# Redistribution and use in source and binary forms, with or without
29
# modification, are permitted provided that the following conditions are met:
30
#
31
#     * Redistributions of source code must retain the above copyright notice,
32
#       this list of conditions and the following disclaimer.
33
#
34
#     * Redistributions in binary form must reproduce the above copyright
35
#       notice, this list of conditions and the following disclaimer in the
36
#       documentation and/or other materials provided with the distribution.
37
#
38
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
39
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
42
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
44
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
45
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48

49
# cython: language_level=3
50

51
import random
52
import math
53

54
cimport libc.math as cmath
55

56
from common import (average, well, tent, parse_color, sin_curve, abs_sin,
57
    color_binary, wave)
58
from palettes import palettes
59

60
# We next define classes that represent expression trees.
61

62
# Each object that reprents and expression should have an eval(self, x, y) method
63
# which computes the value of the expression at (x, y). The __init__ should
64
# accept the objects representing its subexpressions. The class definition
65
# should contain the arity attribute which tells how many subexpressions should
66
# be passed to the __init__ constructor. Classes with arity == 0 are called
67
# terminals, the others are called nonterminals.The __repr__ method is used to
68
# print each object as a string. The mindepth attribute shows depth of
69
# expression tree where it is allowed to use this object.
70

71
# Some operators are adopted from https://github.com/vshymanskyy/randomart
72

73
# Terminals:
74

75
class VariableX():
76
    arity = 0
77
    mindepth = 4
78
    def __init__(self):
79
        pass
80
    def __repr__(self):
81
        return "x"
82
    def eval(self, x, y):
83
        return (x, x, x)
84

85
class VariableY():
86
    arity = 0
87
    mindepth = 4
88
    def __init__(self):
89
        pass
90
    def __repr__(self):
91
        return "y"
92
    def eval(self, x, y):
93
        return (y, y, y)
94

95
class Random():
96
    arity = 0
97
    mindepth = 4
98
    def __init__(self, r = None, g = None, b = None):
99
        if r and g and b: #for parsing
100
            self.c = (r, g, b)
101
            return
102
        self.c = (random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1))
103
    def __repr__(self):
104
        return 'Random(%g,%g,%g)' % self.c
105
    def eval(self, x, y): 
106
        return self.c
107

108
class Palette():
109
    arity = 0
110
    mindepth = 3
111
    palette = palettes[0]
112
    paletteIndex = 0
113
    def __init__(self, r = None, g = None, b = None):
114
        if r and g and b: #for parsing
115
            self.c = (r, g, b)
116
            return
117
        self.hex = Palette.palette[Palette.paletteIndex]
118
        Palette.paletteIndex += 1
119
        if Palette.paletteIndex >= len(Palette.palette):
120
            Palette.paletteIndex = 0
121
        self.c = tuple([x/128.0 - 1.0 for x in parse_color(self.hex)])
122
    def __repr__(self):
123
        return "Palette(%g, %g, %g)" % self.c
124
    def eval(self, x, y):
125
        return self.c
126

127
    @staticmethod
128
    def randomPalette(): #set random palette
129
        Palette.palette = random.choice(palettes)
130
        Palette.paletteIndex = 0
131

132
class White():
133
    arity = 0
134
    mindepth = 4
135
    def __init__(self, r = None, g = None, b = None): #unused arguments for parsing
136
        self.c = (1, 1, 1)
137
    def __repr__(self):
138
        return 'White(%g, %g, %g)' % self.c
139
    def eval(self, x, y):
140
        return self.c
141

142
class Chess():
143
    arity = 0
144
    mindepth = 5
145
    def __init__(self, wX=None, wY=None):
146
        if wX and wY: #for parsing
147
            self.wX = wX
148
            self.wY = wY
149
            return
150
        self.wX = random.uniform(0.1, 1.0)
151
        self.wY = random.uniform(0.1, 1.0)
152
    def __repr__(self):
153
        return "Chess(%g, %g)" % (self.wX, self.wY)
154
    def eval(self, x, y):
155
        isOdd = False
156
        isOdd ^= int(cmath.floor(x/self.wX)) & 1
157
        isOdd ^= int(cmath.floor(y/self.wY)) & 1
158
        return (-1, -1, -1) if isOdd else (1, 1, 1)
159

160
class Fibonacci():
161
    arity = 0
162
    mindepth = 3
163
    fib_array = [0, 1]
164
    def __init__(self):
165
        pass
166
    def __repr__(self):
167
        return "Fibonacci()"
168
    def eval(self, x, y):
169
        result = (self.fibonacci(len(Fibonacci.fib_array) + 1)%255)/255 - 128
170
        return (result, result, result)
171
    def fibonacci(self, n):
172
        if n < 0:
173
            return Fibonacci.fib_array[0]
174
        elif n < len(Fibonacci.fib_array):
175
            return Fibonacci.fib_array[n]
176
        else:
177
            max_limit = 200 if n > 200 else n + 1
178
            for i in range(len(Fibonacci.fib_array), max_limit): 
179
                Fibonacci.fib_array.append(Fibonacci.fib_array[i - 1] + Fibonacci.fib_array[i - 2])
180
            return Fibonacci.fib_array[max_limit - 1]
181

182
# Nonterminals:
183

184
class Well():
185
    arity = 1
186
    mindepth = 3
187
    def __init__(self, e):
188
        self.e = e
189
        self.e_func = self.e.eval
190
    def __repr__(self):
191
        return 'Well(%s)' % self.e
192
    def eval(self, x, y):
193
        (r, g, b) = self.e_func(x, y)
194
        return (well(r), well(g), well(b))
195

196
class Tent():
197
    arity = 1
198
    mindepth = 3
199
    def __init__(self, e):
200
        self.e = e
201
        self.e_func = self.e.eval
202
    def __repr__(self):
203
        return 'Tent(%s)' % self.e
204
    def eval(self, x, y):
205
        (r, g, b) = self.e_func(x, y)
206
        return (tent(r), tent(g), tent(b))
207

208
class Sin():
209
    arity = 1
210
    mindepth = 0
211
    def __init__(self, e, phase = None, freq = None):
212
        self.e = e
213
        self.e_func = self.e.eval
214
        if phase and freq: #for parsing
215
            self.phase = phase
216
            self.freq = freq
217
            return
218
        self.phase = random.uniform(0, math.pi)
219
        self.freq = random.uniform(1.0, 6.0)
220
    def __repr__(self):
221
        return 'Sin(%s, %g, %g)' % (self.e, self.phase, self.freq)
222
    def eval(self, x, y):
223
        (r1, g1, b1) = self.e_func(x, y)
224
        r2 = cmath.sin(self.phase + self.freq * r1)
225
        g2 = cmath.sin(self.phase + self.freq * g1)
226
        b2 = cmath.sin(self.phase + self.freq * b1)
227
        return (r2, g2, b2)
228

229
class Not():
230
    arity = 1
231
    mindepth = 3
232
    def __init__(self, e):
233
        self.e = e
234
        self.e_func = self.e.eval
235
    def __repr__(self):
236
        return "Not(%s)" % self.e
237
    def eval(self, x, y):
238
        (r, g, b) = self.e_func(x, y)
239
        return (-r, -g, -b)
240

241
class SinCurve():
242
    arity = 1
243
    mindepth = 0
244
    def __init__(self, e):
245
        self.e = e
246
        self.e_func = self.e.eval
247
    def __repr__(self):
248
        return 'SinCurve(%s)' % self.e
249
    def eval(self, x, y):
250
        (r, g, b) = self.e_func(x, y)
251
        return (sin_curve(r), sin_curve(g), sin_curve(b))
252

253
class AbsSin():
254
    arity = 1
255
    mindepth = 3
256
    def __init__(self, e):
257
        self.e = e
258
        self.e_func = self.e.eval
259
    def __repr__(self):
260
        return 'AbsSin(%s)' % self.e
261
    def eval(self, x, y):
262
        (r, g, b) = self.e_func(x, y)
263
        return (abs_sin(r), abs_sin(g), abs_sin(b))
264

265
class Atan():
266
    arity = 1
267
    mindepth = 0
268
    def __init__(self, e):
269
        self.e = e
270
        self.e_func = self.e.eval
271
    def __repr__(self):
272
        return 'Atan(%s)' % (self.e)
273
    def eval(self, x, y):
274
        (r, g, b) = self.e_func(x, y)
275
        return (cmath.atan(r)*2/cmath.pi, cmath.atan(g)*2/cmath.pi, cmath.atan(b)*2/cmath.pi)
276

277
class Sum():
278
    arity = 2
279
    mindepth = 2
280
    def __init__(self, e1, e2):
281
        self.e1 = e1
282
        self.e2 = e2
283
    def __repr__(self):
284
        return 'Sum(%s, %s)' % (self.e1, self.e2)
285
    def eval(self, x, y):
286
        return average(self.e1.eval(x, y), self.e2.eval(x, y))
287

288
class Product():
289
    arity = 2
290
    mindepth = 2
291
    def __init__(self, e1, e2):
292
        self.e1 = e1
293
        self.e2 = e2
294
    def __repr__(self):
295
        return 'Product(%s, %s)' % (self.e1, self.e2)
296
    def eval(self, x, y):
297
        (r1, g1, b1) = self.e1.eval(x, y)
298
        (r2, g2, b2) = self.e2.eval(x, y)
299
        r3 = r1 * r2
300
        g3 = g1 * g2
301
        b3 = b1 * b2
302
        return (r3, g3, b3)
303

304
class Mod():
305
    arity = 2
306
    mindepth = 3
307
    def __init__(self, e1, e2):
308
        self.e1 = e1
309
        self.e2 = e2
310
    def __repr__(self):
311
        return 'Mod(%s, %s)' % (self.e1, self.e2)
312
    def eval(self, x, y):
313
        (r1, g1, b1) = self.e1.eval(x, y)
314
        (r2, g2, b2) = self.e2.eval(x, y)
315
        try:
316
            r3 = r1 % r2
317
            g3 = g1 % g2
318
            b3 = b1 % b2
319
            return (r3, g3, b3)
320
        except:
321
            return (0, 0, 0)
322

323
class And():
324
    arity = 2
325
    mindepth = 0
326
    def __init__(self, e1, e2):
327
        self.e1 = e1
328
        self.e2 = e2
329
    def __repr__(self):
330
        return 'And(%s, %s)' % (self.e1, self.e2)
331
    def eval(self, x, y):
332
        return color_binary(self.e1.eval(x, y), self.e2.eval(x, y), lambda x1,x2 : x1 & x2)
333

334
class Or():
335
    arity = 2
336
    mindepth = 0
337
    def __init__(self, e1, e2):
338
        self.e1 = e1
339
        self.e2 = e2
340
    def __repr__(self):
341
        return 'Or(%s, %s)' % (self.e1, self.e2)
342
    def eval(self, x, y):
343
        return color_binary(self.e1.eval(x, y), self.e2.eval(x, y), lambda x1,x2 : x1 | x2)
344

345
class Xor():
346
    arity = 2
347
    mindepth = 0
348
    def __init__(self, e1, e2):
349
        self.e1 = e1
350
        self.e2 = e2
351
    def __repr__(self):
352
        return 'Xor(%s, %s)' % (self.e1, self.e2)
353
    def eval(self, x, y):
354
        return color_binary(self.e1.eval(x, y), self.e2.eval(x, y), lambda x1,x2 : x1 ^ x2)
355

356
class Wave():
357
    arity = 2
358
    mindepth = 0
359
    def __init__(self, e1, e2):
360
        self.e1 = e1
361
        self.e2 = e2
362
    def __repr__(self):
363
        return 'Wave(%s, %s)' % (self.e1, self.e2)
364
    def eval(self, x, y):
365
        (r1, g1, b1) = self.e1.eval(x, y)
366
        (r2, g2, b2) = self.e2.eval(x, y)
367
        return (wave(r1, r2), wave(g1, g2), wave(b1, b2))
368

369
class Level():
370
    arity = 3
371
    mindepth = 0
372
    def __init__(self, level, e1, e2, treshold = None):
373
        self.treshold = treshold if treshold else random.uniform(-1.0, 1.0) #for parsing
374
        self.level = level
375
        self.e1 = e1
376
        self.e2 = e2
377
    def __repr__(self):
378
        return 'Level(%s, %s, %s, %g)' % (self.level, self.e1, self.e2, self.treshold)
379
    def eval(self, x, y):
380
        (r1, g1, b1) = self.level.eval(x, y)
381
        (r2, g2, b2) = self.e1.eval(x, y)
382
        (r3, g3, b3) = self.e2.eval(x, y)
383
        r4 = r2 if r1 < self.treshold else r3
384
        g4 = g2 if g1 < self.treshold else g3
385
        b4 = b2 if b1 < self.treshold else b3
386
        return (r4, g4, b4)
387

388
class Mix():
389
    arity = 3
390
    mindepth = 0
391
    def __init__(self, w, e1, e2):
392
        self.w = w
393
        self.e1 = e1
394
        self.e2 = e2
395
        self.w_func = self.w.eval
396
        self.e1_func = self.e1.eval
397
        self.e2_func = self.e2.eval
398
    def __repr__(self):
399
        return 'Mix(%s, %s, %s)' % (self.w, self.e1, self.e2)
400
    def eval(self, x, y):
401
        w = 0.5 * (self.w_func(x, y)[0] + 1.0)
402
        c1 = self.e1_func(x, y)
403
        c2 = self.e2_func(x, y)
404
        return average(c1, c2, w)
405

406
class RGB():
407
    arity = 3
408
    mindepth = 4
409
    def __init__(self, e1, e2, e3):
410
        self.e1 = e1
411
        self.e2 = e2
412
        self.e3 = e3
413
        self.e1_func = self.e1.eval
414
        self.e2_func = self.e2.eval
415
        self.e3_func = self.e3.eval
416
    def __repr__(self):
417
        return 'RGB(%s, %s, %s)' % (self.e1, self.e2, self.e3)
418
    def eval(self, x, y):
419
        (r, _, _) = self.e1_func(x, y)
420
        (_, g, _) = self.e2_func(x, y)
421
        (_, _, b) = self.e3_func(x, y)
422
        return (r, g, b)
423

424
class Closest():
425
    arity = 3
426
    mindepth = 3
427
    def __init__(self, target, e1, e2):
428
        self.target = target
429
        self.e1 = e1
430
        self.e2 = e2
431
        self.target_func = self.target.eval
432
        self.e1_func = self.e1.eval
433
        self.e2_func = self.e2.eval
434
    def __repr__(self):
435
        return 'Closest(%s, %s, %s)' % (self.target, self.e1, self.e2)
436
    def eval(self, x, y):
437
        (r1, g1, b1) = self.target_func(x, y)
438
        (r2, g2, b2) = self.e1_func(x, y)
439
        (r3, g3, b3) = self.e2_func(x, y)
440
        #distances between colors:
441
        d1 = math.sqrt((r2-r1)**2+(g2-g1)**2+(b2-b1)**2)
442
        d2 = math.sqrt((r3-r1)**2+(g3-g1)**2+(b3-b1)**2)
443

444
        return (r2, g2, b2) if d1 < d2 else (r3, g3, b3)
445

446
class Far():
447
    arity = 3
448
    mindepth = 3
449
    def __init__(self, target, e1, e2):
450
        self.target = target
451
        self.e1 = e1
452
        self.e2 = e2
453
        self.target_func = self.target.eval
454
        self.e1_func = self.e1.eval
455
        self.e2_func = self.e2.eval
456
    def __repr__(self):
457
        return 'Far(%s, %s, %s)' % (self.target, self.e1, self.e2)
458
    def eval(self, x, y):
459
        (r1, g1, b1) = self.target_func(x, y)
460
        (r2, g2, b2) = self.e1_func(x, y)
461
        (r3, g3, b3) = self.e2_func(x, y)
462
        #distances between colors:
463
        d1 = math.sqrt((r2-r1)**2+(g2-g1)**2+(b2-b1)**2)
464
        d2 = math.sqrt((r3-r1)**2+(g3-g1)**2+(b3-b1)**2)
465

466
        return (r2, g2, b2) if d1 > d2 else (r3, g3, b3)
467

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.