КомпГр_ЛР5_Заболотников_Петрова_Романова_9373
.pdfМИНОБРНАУКИ РОССИИ САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ «ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА) Кафедра информационных систем
ОТЧЕТ по лабораторной работе№5
по дисциплине «Компьютерная графика» Тема: Исследование алгоритмов выявления видимости сложных сцен
Студент гр. 9373 |
_______________ |
Заболотников М. Е. |
Студентка гр. 9373 |
_______________ |
Петрова С. В. |
Студентка гр. 9373 |
_______________ |
Романова Е. С. |
Преподаватель |
_______________ |
Матвеева И.В. |
Санкт-Петербург
2022
Цель работы.
Обеспечить реализацию алгоритма выявления видимых граней и ребер для одиночного выпуклого объемного тела.
Задание на работу.
Необходимо написать программу, которая убирает невидимые грани у одиночного выпуклого тела, в данном случае у правильного параллелепипеда.
Общие сведения.
Для выполнения работы потребовались следующие теоретические
сведения.
Матрицы поворотов вокруг осей на угол :
1 |
0 |
0 |
1) Вокруг оси OX: |0 |
|
−| |
0 |
|
|
|
|
0 |
|
|
2) |
Вокруг оси OY: | 0 |
1 |
|
0 | |
|
− |
0 |
|
|
|
|
− |
0 |
|
3) |
Вокруг оси OZ: | |
|
0| |
|
|
0 |
0 |
|
1 |
В математике перекрестное произведение или векторное произведение представляет собой двоичную операцию над двумя векторами в трехмерном ориентированном евклидовом векторном пространстве. Учитывая два линейно независимых вектора a и b, перекрестное произведение, a × b (читается "a cross b") является вектором, который перпендикулярен как a, так и b, и, следовательно, перпендикулярен плоскости, содержащей их. Он имеет множество применений в математике, физике, инженерии и компьютерном программировании.
Если два вектора имеют одинаковое направление или имеют прямо противоположное направление друг от друга (то есть они не являются линейно независимыми), или если любой из них имеет нулевую длину, то их
2
перекрестное произведение равно нулю. В более общем смысле величина произведения равна площади параллелограмма с векторами сторон; в
частности, величина произведения двух перпендикулярных векторов равна произведению их длин.
Ход работы.
Рассмотрим работу программы, которая заключается вызове функции,
отвечающей за поворот фигуры и функции для проверки невидимости граней одиночного выпуклого объемного тела.
Выполнение работы.
Ссылка на видео с демонстрацией работы программы: https://www.youtube.com/watch?v=CVsyEPP7_T0
Программа была написана в приложении Jupiter на языке Python с
использованием графических библиотек.
Для работы с программой необходимо указать углы поворота по оси и нажать на «Отобразить». Сбоку появится правильный параллелепипед,
повернутый на указанный угол с видимыми ребрами.
Тесты работы программы.
На рис.1 – 4 представлены результаты выполнения работы программы:
Рисунок 1 – Вращение фигуры (1 часть)
3
Рисунок 2 – Вращение фигуры (2 часть)
Рисунок 3 – Вращение фигуры (3 часть)
Рисунок 4 – Вращение фигуры (4 часть)
4
Выводы.
В данной работе была обеспечена реализация алгоритма выявления видимых граней и ребер для одиночного выпуклого объемного тела. Для демонстрации корректности работы программы реализован поворот рассматриваемого тела вокруг осей OX, OY и OZ.
5
ПРИЛОЖЕНИЕ А Файл «Komp_GR.ipynb»
import tkinter as tk from tkinter import *
from tkinter.messagebox import showerror import numpy as np
import math
from math import cos, sin import cmath
points = [(100,200,0),( 200,200,0), (200,0,0),(100,0,0), (100,200,100),( 200,200,100), (200,0,100),(100,0,100)]
points_2d = [(100,200),( 200,200), (200,0),(100,0), (100,200),( 200,200), (200,0),(100,0)]
faces = [(0,1,2,3),(5,4,7,6),(4,0,3,7),(1,5,6,2),(4,5,1,0),(3,2,6,7)] def rot(a, b):
a_len = 3 a_row_l = 3
res = a.copy()*0 res[0]=a[0]*b[0,0]+a[1]*b[1,0]+a[2]*b[2,0] res[1]=a[0]*b[0,1]+a[1]*b[1,1]+a[2]*b[2,1] res[2]=a[0]*b[0,2]+a[1]*b[1,2]+a[2]*b[2,2] return res
def rotation(self,p):
(x, y, z) = (p[0], p[1], p[2]) Temp_matrix = np.empty((1, 3)) angle_x = int(self.X_value.get()) angle_y = int(self.Y_value.get()) angle_z= int(self.Z_value.get())
angle_x = angle_x*math.pi / 180 angle_y = angle_y*math.pi / 180 angle_z = angle_z*math.pi / 180
matr_rot_ox = np.array([[1,0,0],
[0, cos(angle_x), -sin(angle_x)], [0, sin(angle_x), cos(angle_x)]])
matr_rot_oy = np.array([[cos(angle_y),0,sin(angle_y)], [0, 1, 0],
6
[-sin(angle_y), 0, cos(angle_y)]])
matr_rot_oz = np.array([[cos(angle_z),-sin(angle_z),0], [sin(angle_z), cos(angle_z), 0], [0, 0, 1]])
points_2 = np.array([x,y,z])
res = rot(points_2, matr_rot_ox) res = rot(res, matr_rot_oy)
res = rot(res, matr_rot_oz) Temp_matrix[0][0]=res[0] Temp_matrix[0][1]=res[1] Temp_matrix[0][2]=res[2]
return Temp_matrix
def cross(a, b): #перекрестное произведение
return [a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]]
def createFace(self,points):
a, b, c, d = points[0], points[1], points[2], points[3]
v1 = b[0]-a[0], b[1]-a[1], b[2]-a[2] v2 = c[0]-a[0], c[1]-a[1], c[2]-a[2] n = cross(v1, v2)
if n[2] < 0: return
coords = ((b[0], b[1]), (a[0], a[1]), (d[0], d[1]),(c[0], c[1])) self.canvas.create_polygon(coords,fill='orange', outline='blue')
def flattenPoint(point):
(x, y, z) = (point[0][0], point[0][1], point[0][2]) return (x, y, z)
def createOutline(self,points):
a, b, c, d = points[0], points[1], points[2], points[3]
v1 = b[0]-a[0], b[1]-a[1], b[2]-a[2] v2 = c[0]-a[0], c[1]-a[1], c[2]-a[2]
7
n = cross(v1, v2) if n[2] < 0:
return
coords = ((b[0], b[1]), (a[0], a[1]), (d[0], d[1]),(c[0], c[1])) #self.canvas.create_polygon(coords,fill='', outline='blue')
class Gui:
def __init__(self, root): self.root = root
self.X_value = tk.StringVar() self.X_value.set("0") #угол поворот оси ОХ self.Y_value = tk.StringVar() self.Y_value.set("0") #угол поворот оси OY self.Z_value = tk.StringVar() self.Z_value.set("0") #угол поворот оси ОZ
temp = tk.Tk()
self.WIDTH = temp.winfo_screenwidth() self.HEIGHT = temp.winfo_screenheight() temp.destroy()
self.canvas = tk.Canvas(root, width=self.WIDTH - 400, height=self.HEIGHT - 200, background='white', bd=0)
self.canvas.grid(row=0, column=1)
#self.canvas.create_line(-self.WIDTH, 0, self.WIDTH, 0, fill="black", width=0.1) #ОСИ
#self.canvas.create_line(0, -self.HEIGHT, 0, self.HEIGHT, fill="black", width=0.1)#ОСИ
#self.canvas.create_line(1000, -1000, 0, 1000, fill="black", width=0.5) #ОСИ
zeros = [0] * 4
self.canvas.create_polygon(points_2d,fill='orange', outline='blue')
self.canvas.configure(scrollregion=(int(-(self.WIDTH - 400) / 2) + 2, int(-(self.HEIGHT - 200) / 2) + 1, 0, 0))
frame = Frame(self.root)
8
frame["border"] = 5 frame['relief'] = 'groove'
frame.grid(row=0, column=0, sticky="n")
label_agent = Label(frame, text=" Угол поворота по оси").grid(row=0, column=0, sticky="nw", padx=20)
label_OX = Label(frame, text="OX").grid(row=1, column=0, sticky="w",
padx=40)
label_OY = Label(frame, text="OY").grid(row=2, column=0, sticky="w",
padx=40)
label_OZ = Label(frame, text="OZ").grid(row=3, column=0, sticky="w",
padx=40)
entry_OX = Entry(frame, width=5, textvariable=self.X_value).grid(row=1, column=0, sticky=W, padx=62)
entry_OY = Entry(frame, width=5, textvariable=self.Y_value).grid(row=2, column=0, sticky=W, padx=62)
entry_OZ = Entry(frame, width=5, textvariable=self.Z_value).grid(row=3, column=0, sticky=W, padx=62)
#ИЗМЕНИТЬ ФУНКЦИИ
button_rotation = Button(frame, text="Отобразить", command=self.draw_cube, height=1, width=10,
highlightcolor="darkgrey",
border=5).grid(row=3, column=1,
sticky="we")
def draw_cube(self): self.canvas.delete("all") #очистка экрана
#self.canvas.create_line(-self.WIDTH, 0, self.WIDTH, 0, fill="black", width=0.1) #ОСИ
#self.canvas.create_line(0, -self.HEIGHT, 0, self.HEIGHT, fill="black", width=0.1)#ОСИ
#self.canvas.create_line(1000, -1000, 0, 1000, fill="black", width=0.5) #ОСИ
coords = []
for point in points: Tmp_matr=rotation(self,point)
9
point = Tmp_matr coords.append(flattenPoint(point))
for face in faces:
createFace(self,(coords[face[0]], coords[face[1]], coords[face[2]], coords[face[3]]))
for face in faces:
createOutline(self,(coords[face[0]], coords[face[1]], coords[face[2]], coords[face[3]]))
if __name__ == '__main__': app = tk.Tk()
screen_width = app.winfo_screenwidth() screen_height = app.winfo_screenheight()
app.geometry(f"{screen_width - 100}x{screen_height - 150}+{50}+{50}") gui = Gui(app)
app.mainloop()
10