-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupdate_display.py
More file actions
175 lines (136 loc) · 6.86 KB
/
Copy pathupdate_display.py
File metadata and controls
175 lines (136 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# -*- coding: utf-8 -*-
"""
Updated on Wed Jul 29 07:00:30 2020
@author: Qaisar TanvirS
"""
import time
import os
import operator
from cellular_automaton import automaton
"""
Copyright 2019 Richard Feistenauer
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
class _Rect:
def __init__(self, left=0, top=0, width=0, height=0, rect=None, pos=None, size=None):
if rect is not None and (pos is not None or size is not None):
raise ValueError("define either rect OR position and size OR left, top, width and height")
if not (left == top == width == height == 0) and not(rect == pos == size is None):
raise ValueError("define either rect OR position and size OR left, top, width and height")
self.__direct_initialisation(height, left, top, width)
self.__pos_and_size_initialisation(pos, size)
self.__rect_initialisation(rect)
def __rect_initialisation(self, rect):
if rect is not None:
self.__direct_initialisation(rect[1][1], rect[0][0], rect[0][1], rect[1][0])
def __pos_and_size_initialisation(self, pos, size):
if pos is not None:
self.left = pos[0]
self.top = pos[1]
if size is not None:
self.width = size[0]
self.height = size[1]
def __direct_initialisation(self, height, left, top, width):
self.left = left
self.top = top
self.width = width
self.height = height
def get_rect_tuple(self):
return (self.left, self.top), (self.width, self.height)
class DrawEngine(object):
def __init__(self, window_size=None, *args, **kwargs):
super().__init__(*args, **kwargs)
global pygame
import pygame
pygame.init()
pygame.display.set_caption("Cellular Automaton")
self.__screen = pygame.display.set_mode(window_size)
self.__font = pygame.font.SysFont("monospace", 15)
self._width = window_size[0]
self._height = window_size[1]
def write_text(self, pos, text, color=(0, 255, 0)):
label = self.__font.render(text, 1, color)
update_rect = self.__screen.blit(label, pos)
DrawEngine.update_rectangles(update_rect)
def fill_surface_with_color(self, rect, color=(0, 0, 0)):
return self.__screen.fill(color, rect)
@staticmethod
def update_rectangles(rectangles):
pygame.display.update(rectangles)
def get_screen_state(self):
return self.__screen
@staticmethod
def is_active():
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
return True
class _CASurface:
def __init__(self,
grid_rect,
cellular_automaton: automaton.CellularAutomatonProcessor,
draw_engine,
*args, **kwargs):
super().__init__(*args, **kwargs)
self._cellular_automaton = cellular_automaton
self.__rect = grid_rect
self.__cell_size = self._calculate_cell_display_size()
self.__draw_engine = draw_engine
def _calculate_cell_display_size(self):
grid_dimension = self._cellular_automaton.get_dimension()
return [self.__rect.width / grid_dimension[0], self.__rect.height / grid_dimension[1]]
def redraw_cellular_automaton(self):
""" Redraws those cells which changed their state since last redraw. """
self.__draw_engine.update_rectangles(list(self.__redraw_dirty_cells()))
pygame.image.save(self.__draw_engine.get_screen_state(), f"{os.getcwd()}\Images\{time.time()}.jpg")
def __redraw_dirty_cells(self):
for coordinate, cell in self._cellular_automaton.get_cells().items():
if cell.is_set_for_redraw():
yield from self.__redraw_cell(cell, coordinate)
def __redraw_cell(self, cell, coordinate):
cell_color = self.__get_cell_color(cell)
cell_pos = self._calculate_cell_position_in_the_grid(coordinate)
surface_pos = self._calculate_cell_position_on_screen(cell_pos)
cell.was_redrawn()
yield self._draw_cell_surface(surface_pos, cell_color)
def __get_cell_color(self, cell):
return self._cellular_automaton.get_current_rule().get_state_draw_color(
cell.get_current_state(self._cellular_automaton.get_current_evolution_step()))
def _calculate_cell_position_in_the_grid(self, coordinate):
return list(map(operator.mul, self.__cell_size, coordinate))
def _calculate_cell_position_on_screen(self, cell_pos):
return [self.__rect.left + cell_pos[0], self.__rect.top + cell_pos[1]]
def _draw_cell_surface(self, surface_pos, cell_color):
return self.__draw_engine.fill_surface_with_color((surface_pos, self.__cell_size), cell_color)
class CAWindow(DrawEngine):
def __init__(self, cellular_automaton: automaton.CellularAutomatonProcessor,
evolution_steps_per_draw=1,
window_size=(1000, 800),
*args, **kwargs):
super().__init__(window_size=window_size, *args, **kwargs)
self._ca = cellular_automaton
self.ca_display = _CASurface(_Rect(pos=(0, 30), size=(window_size[0], window_size[1] - 30)),
self._ca,
self)
self.__loop_evolution_and_redraw_of_automaton(evolution_steps_per_draw=evolution_steps_per_draw)
def __loop_evolution_and_redraw_of_automaton(self, evolution_steps_per_draw):
while super().is_active():
time_ca_start = time.time()
self._ca.evolve_x_times(evolution_steps_per_draw)
time_ca_end = time.time()
self.ca_display.redraw_cellular_automaton()
time_ds_end = time.time()
self.__print_process_duration(time_ca_end, time_ca_start, time_ds_end)
def __print_process_duration(self, time_ca_end, time_ca_start, time_ds_end):
super().fill_surface_with_color(_Rect(size=(self._width, 30)).get_rect_tuple())
super().write_text((10, 5), "CA: " + "{0:.4f}".format(time_ca_end - time_ca_start) + "s")
super().write_text((310, 5), "Display: " + "{0:.4f}".format(time_ds_end - time_ca_end) + "s")
super().write_text((660, 5), "Step: " + str(self._ca.get_current_evolution_step()))