Файл: Разработка вебприложения логической игры Найди пару по тематике игры 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('', left_key)

root.bind('', right_key)

root.bind('', up_key)

root.bind('', down_key)
root.mainloop()



Архангельск 2023