Файл: Разработка вебприложения логической игры Найди пару по тематике игры God Of War.docx
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 25.04.2024
Просмотров: 11
Скачиваний: 0
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
################################################
teta = 0
phi = -pi/2
# d и ro
d = 200
ro = 7
window_width = 600
window_height = 400
# количество точек в линии
#number_of_points = 12
# количество рёбер
#number_of_edges = 6
# количество точек в линии
number_of_points = 21
# количество рёбер
number_of_edges = 40
################################################
# глобальные переменные - конец #
################################################
class T2DPoint:
def __init__(self, x, y) -> None:
self.x = float(x)
self.y = float(y)
class T3DPoint:
def __init__(self, x, y, z) -> None:
self.x = float(x)
self.y = float(y)
self.z = float(z)
class Vase:
def __init__(self) -> None:
self.points_array = []
def add_point(self, x, y, z):
self.points_array.append(T3DPoint(x, y, z))
def __iter__(self):
return self.points_array
class Curve:
def __init__(self, z0, zn, number_of_points) -> None:
self.points_array = []
points = np.linspace(z0, zn, num=number_of_points, endpoint=True)
for i in points:
self.points_array.append(T3DPoint(2 + cos(i), 0, i))
def __iter__(self):
return self.points_array
def transform_rotate(self, number_of_edges):
vase = Vase()
deg = float(2 * pi / number_of_edges)
for i in range(number_of_edges):
d1 = deg * i
for point in self.points_array:
x = point.x * cos(d1) + point.y * sin(d1)
y = (-1) * point.x * sin(d1) + point.y * cos(d1)
vase.add_point(x, y, point.z)
return vase
class PolygonsMatrix:
def __init__(self, points, midz, normal_z) -> None:
self.points = points
self.midz = midz
self.normal_z = normal_z
def view_transformation(matrix):
global phi, teta, window_width, window_height, d, ro
# пустая матрица для видовых координат
v_matrix = []
# пустая матрица для координат после перспективного преобразования
d_matrix = []
for i in matrix:
# видовое преобразование
vx = i.x * (-1) * sin(teta) + i.y * cos(teta)
vy = i.x * (-1) * cos(phi) * cos(teta) - i.y * \
cos(phi) * sin(teta) + i.z * sin(phi)
vz = i.x * (-1) * sin(phi) * cos(teta) - i.y * \
sin(phi) * sin(teta) - i.z * cos(phi) + ro
v_matrix.append(T3DPoint(vx, vy, vz))
# перспективное преобразование
x = round(d * (vx / vz)) + window_width // 2
y = round(d * (vy / vz)) + window_height // 2
d_matrix.append(T2DPoint(x, y))
return d_matrix, v_matrix
def get_hex_color(nvz):
# из нормали по Z -> в RGB цвет
nvz = abs(nvz)
r = format(round(122 * nvz), '02x')
g = format(round(122 * nvz), '02x')
b = format(round(122 * nvz), '02x')
return f"#{r}{g}{b}"
def calculate_normal(point1, point2, point3):
nvx = point1.y * (point2.z - point3.z) + point2.y * \
(point3.z - point1.z) + point3.y * (point1.z - point2.z)
nvy = point1.z * (point2.x - point3.x) + point2.z * \
(point3.x - point1.x) + point3.z * (point1.x - point2.x)
nvz = point1.x * (point2.y - point3.y) + point2.x * \
(point3.y - point1.y) + point3.x * (point1.y - point2.y)
dl = sqrt(nvx ** 2 + nvy ** 2 + nvz ** 2)
if dl != 0:
return nvz / dl
else:
return nvz
def draw_object(d_mtrx, v_mtrx, image):
global number_of_edges, number_of_points
draw = ImageDraw.Draw(image)
# количество полигонов должно быть равно
# количество точек в линии -1 * количество рёбер + 1 полигон для низа вазы
# матрица всех полигонов
poly_matrix = []
# массив точек дна вазы
points_bottom = []
# для каждого полигона считаем нормаль +
# среднее значение Z
for i in range(number_of_edges):
for j in range(number_of_points-1):
# обрабатываем боковые стороны:
p1 = i * number_of_points + j
p4 = p1 + 1
if i != number_of_edges-1:
p2 = (i + 1) * number_of_points + j
p3 = p2 + 1
else:
p2 = j
p3 = p2 + 1
#print(f"{i} {j} {p1} {p2} {p3} {p4}")
# считаем нормали по 3 точкам видовых координат
nvz = calculate_normal(v_mtrx[p1], v_mtrx[p2], v_mtrx[p3])
# print(nvz)
# [ координаты точек, которые надо соединить полигоном] + среднее значение Z для грани + нормаль по Z
poly_matrix.append(PolygonsMatrix([(d_mtrx[p1].x, d_mtrx[p1].y), (d_mtrx[p2].x, d_mtrx[p2].y),(d_mtrx[p3].x, d_mtrx[p3].y), (d_mtrx[p4].x, d_mtrx[p4].y)],(v_mtrx[p1].z + v_mtrx[p2].z + v_mtrx[p3].z + v_mtrx[p4].z) / 4, nvz))
# обрабатываем дно вазы:
points_bottom.append(i * number_of_points)
if i == number_of_edges-1:
nvz = calculate_normal(
v_mtrx[points_bottom[0]], v_mtrx[points_bottom[1]], v_mtrx[points_bottom[2]])
bottom_coords = []
botoom_avg_z = 0
for point in points_bottom:
bottom_coords.append((d_mtrx[point].x, d_mtrx[point].y))
botoom_avg_z += v_mtrx[point].z
botoom_avg_z = botoom_avg_z / len(points_bottom)
poly_matrix.append(PolygonsMatrix(
bottom_coords, botoom_avg_z, nvz))
# сортируем в обратном порядке матрицу полигонов по полю среднего Z для грани
poly_matrix.sort(reverse=True, key=lambda poly_matrix: poly_matrix.midz)
# рисуем все полигоны
for polygon in poly_matrix:
draw.polygon(polygon.points, fill=get_hex_color(polygon.normal_z))
def update():
# функция обновления формы
global c, vase, window_width, window_height
# найдём матрицу координат после перспективного преобразования
# и видовую матрицу
d_matrix, v_matrix = view_transformation(vase.points_array)
# нарисуем объект
image1 = Image.new("RGB", (window_width, window_height), "white")
draw_object(d_matrix, v_matrix, image1)
# преобразуем рисунок в формат, который понимает tkinter
# и проставим на него ссылку в объекте Canvas
photo = ImageTk.PhotoImage(image1)
c.image_ref = photo
# удалим всё с Canvas
c.delete("all")
# добавим нарисованный объект в один проход
# т.к. Canvas сам по себе с двойной буферизацией
# https://mail.python.org/pipermail/python-list/2001-March/090344.html
# то он за нас сам всё сделает, когда мы добавим
# на него сразу всё изображение разом
c.create_image(0, 0, image=c.image_ref, anchor=tk.NW)
def turn_right():
global teta
teta += 0.1
update()
def turn_left():
global teta
teta -= 0.1
update()
def turn_up():
global phi
phi += 0.1
update()
def turn_down():
global phi
phi -= 0.1
update()
def left_key(event):
turn_left()
def right_key(event):
turn_right()
def up_key(event):
turn_up()
def down_key(event):
turn_down()
################################################
# начало работы программы #
################################################
root = tk.Tk()
c = tk.Canvas(root, width=window_width, height=window_height, bg='white')
c.grid(columnspan=3)
# генерируем кривую с необходимым количеством точек
# кривая задаётся уравнением x = 2 + cos(z)
curve = Curve(-3.6, 4.2, number_of_points)
# преобразовываем кривую в "вазу",
# вращая кривую вокруг оси Z
vase = curve.transform_rotate(number_of_edges)
# первичный вызов функции отрисовки
update()
# каждый раз, когда мы нажимаем на кнопку,
# мы меняем значения teta или phi,
# потом высчитываем новую матрицу в update
# рисуем новый объект и обновляем его в Canvas
b2 = tk.Button(text='Влево', command=turn_left, padx="70")
b2.grid(row=1, sticky="NSW", rowspan=2)
b4 = tk.Button(text='Вправо', command=turn_right, padx="70")
b4.grid(row=1, column=2, sticky="NSE", rowspan=2)
b1 = tk.Button(text='Вверх', command=turn_up, pady="15", padx="100")
b1.grid(row=1, column=1, sticky="NSEW")
b3 = tk.Button(text='Вниз', command=turn_down, pady="15", padx="100")
b3.grid(row=2, column=1, sticky="NSEW")
# добавим немного управления клавишами
root.bind('
root.bind('
root.bind('
root.bind('
root.mainloop()
Архангельск 2023