import math
import copy
import numpy
# todo (once everything is mildly sorted) - find out which of these are unused
# functions
# converts a coordinate from a coordinate with origin at the middle, to a coordinate with origin at the top left
from model import *
def conv_coord(points2d, size, scale):
for i in range(len(points2d)):
points2d[i][0] = (points2d[i][0] * scale) + size[0] / 2
points2d[i][1] = (points2d[i][1] * scale) + size[1] / 2
return points2d
# calculates the focal point distance given an FOV and screen size in units
def fov_calc(fov, size):
fp_distance = (size / (2 * (math.tan(math.radians(fov) / 2))))
return fp_distance
# todo use numpy magic to optimise + collapse these
# function that returns the angle of a face to the camera
def face_angle(points3d, fp_distance, distance):
# calculate cross product:
vec1 = points3d[0][0], points3d[0][1] - (distance), points3d[0][2]
vec2 = cross_product(sub_l(points3d[0], points3d[1]),
sub_l(points3d[1], points3d[2]))
return math.degrees(_2vec_angle(vec1, vec2))
# returns the cross product of two vectors
def cross_product(vector1, vector2):
product = [vector1[1]*vector2[2] - vector1[2]*vector2[1],
vector1[2]*vector2[0] - vector1[0]*vector2[2],
vector1[0]*vector2[1] - vector1[1]*vector2[0]]
return product
# returns the angle of 2 vectors in radians
def _2vec_angle(vector1, vector2):
result = math.acos(
(vector1[0]*vector2[0] + vector1[1]*vector2[1] + vector1[2]*vector2[2])
/ # -----------------------------------------------------------
(math.sqrt((vector1[0] ** 2) + (vector1[1] ** 2) + (vector1[2] ** 2)) *
math.sqrt((vector2[0] ** 2) + (vector2[1] ** 2) + (vector2[2] ** 2)))
)
return result
def sub_l(list1, list2):
result = list()
for i1, i2 in zip(list1, list2):
result.append(i1 - i2)
return result
# new functions
def generate_cam_matrix(rx_d: int, ry_d: int, rz_d: int, player_pos):
rx = math.radians(rx_d)
ry = math.radians(ry_d)
rz = math.radians(rz_d)
x_rot = numpy.array([[1, 0, 0, 0],
[0, math.cos(rx), math.sin(rx), 0],
[0, -math.sin(rx), math.cos(rx), 0],
[0, 0, 0, 1]])
y_rot = numpy.array([[math.cos(ry), 0, -math.sin(ry), 0],
[0, 1, 0, 0],
[math.sin(ry), 0, math.cos(ry), 0],
[0, 0, 0, 1]])
z_rot = numpy.array([[math.cos(rz), math.sin(rz), 0, 0],
[-math.sin(rz), math.cos(rz), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
rotation_matrix = x_rot.dot(y_rot).dot(z_rot)
translation_matrix = numpy.array(
[[1, 0, 0, player_pos.x],
[0, 1, 0, player_pos.y],
[0, 0, 1, player_pos.z],
[0, 0, 0, 1]]
)
# todo implement mapping matrix
# map_matrix = numpy.array([[1, 0, 0 / fp_dis, 0],
# [0, 1, 0 / fp_dis, 0],
# [0, 0, 1 / fp_dis, 0],
# [0, 0, 0, 1]])
return rotation_matrix.dot(translation_matrix)
def gen_inv_rot_matrix(rx_d, ry_d, rz_d):
rx = math.radians(rx_d)
ry = math.radians(- rx_d + 90)
rz = math.radians(- rz_d + 90)
x_rot = numpy.array([[1, 0, 0, 0],
[0, math.cos(rx), math.sin(rx), 0],
[0, -math.sin(rx), math.cos(rx), 0],
[0, 0, 0, 1]])
y_rot = numpy.array([[math.cos(ry), 0, -math.sin(ry), 0],
[0, 1, 0, 0],
[math.sin(ry), 0, math.cos(ry), 0],
[0, 0, 0, 1]])
z_rot = numpy.array([[math.cos(rz), math.sin(rz), 0, 0],
[-math.sin(rz), math.cos(rz), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
return z_rot.dot(y_rot).dot(x_rot)
def draw_face(face: Face, cam_matrix: numpy.array, fp_dis):
if type(face) is TexturedFace:
raise TypeError
# has a face to draw and precalculated camera rotation matrix, along with player position as input
# the face has the global coordinates here
# this function returns the face no matter what (face angle checking must be done elsewhere)
_2dPoints: list[Point2D] = []
# apply camera position and rotation
for point in face.points:
point.apply_matrix(cam_matrix)
_2dPoints.append(point.get_2d_point(fp_dis))
return _2dPoints
def draw_textured_face(face: Face, transform_matrix: numpy.array):
# has face and a camera rotation + position matrix as input, draws the textured face onto the screen
return None