def primitive_vectors(self): half_a = self._a / 2.0 return ( Vector3D(-half_a, +half_a, +half_a), Vector3D(+half_a, +half_a, +half_a), Vector3D(-half_a, -half_a, +half_a), )
def rand_normal(vec, tries=10): """ :type vec: Vector3D :type tries: int """ for i in range(tries): a = random.randint(-50, 50) b = random.randint(-50, 50) if vec.z != 0: two = vec.x * a + vec.y * b c = two / (-vec.z) c = round(c) if two + c * vec.z == 0 and (a != 0 or b != 0 or c != 0): return Vector3D(a, b, c) elif vec.y != 0: two = vec.x * a + vec.z * b c = two / (-vec.y) c = round(c) if two + c * vec.y == 0 and (a != 0 or b != 0 or c != 0): return Vector3D(a, c, b) else: two = vec.z * a + vec.y * b c = two / (-vec.x) c = round(c) if two + c * vec.x == 0 and (a != 0 or b != 0 or c != 0): return Vector3D(c, b, a) return None
def primitive_vectors(self): half_a = self._a / 2.0 return ( Vector3D(half_a, 0, 0), Vector3D(0, half_a, 0), Vector3D(0, 0, half_a) )
def primitive_vectors(self): a = Decimal(self._a) half_a = Decimal(self._a / 2.) c = Decimal(8 / 3.).sqrt() * a return (Vector3D(a, 0, 0), Vector3D(half_a, half_a * Decimal(3).sqrt(), 0), Vector3D(0, 0, c))
def primitive_vectors(self): a = Decimal(self._a) half_a = Decimal(self._a / 2.) return ( Vector3D(+half_a, +half_a, 0), Vector3D(+half_a, -half_a, 0), Vector3D(0, 0, a), )
def __sort_vertices(points): """Return vertices that are sorted by average center of all points.""" points = list(set(points)) if len(points) < 3: return None start_point = __find_average_center(points) start_vector = Vector3D.by_points(start_point, points[0]) return sorted(points, key=lambda point: GeometryUtils.angle_between( start_vector, Vector3D.by_points(start_point, point)))
def test_vector_product(self): self.assertEqual( Vector3D(1, 2, 3) * Vector3D(4, 5, 6), Vector3D(-3, 6, -3)) self.assertEqual( Vector3D(1, 0, 0) * Vector3D(0, 0, 1), Vector3D(0, -1, 0)) self.assertEqual( Vector3D(-1, 2, -3) * Vector3D(2, -3, -4), Vector3D(-17, -10, -1))
def test_add(self): self.assertEqual( Vector3D(0, 0, 0) + Vector3D(1, 1, 1), Vector3D(1, 1, 1)) self.assertEqual( Vector3D(1, 0, 1) + Vector3D(0, 2, 0), Vector3D(1, 2, 1)) self.assertEqual( Vector3D(1, 2, -3) + Vector3D(-2, -3, 3), Vector3D(-1, -1, 0))
def test_sub(self): self.assertEqual( Vector3D(0, 0, 0) - Vector3D(1, 1, 1), Vector3D(-1, -1, -1)) self.assertEqual( Vector3D(1, 0, 1) - Vector3D(0, 2, 0), Vector3D(1, -2, 1)) self.assertEqual( Vector3D(1, 2, -3) - Vector3D(-2, -3, 3), Vector3D(3, 5, -6))
def test_rotate(self): self.assertEqual( Vector3D(0, 0, 1).rotate(math.pi, Vector3D(1, 0, 0)), Vector3D(0, 0, -1)) self.assertEqual( Vector3D(-1, 0, 0).rotate(math.pi / 2, Vector3D(0, -1, 0)), Vector3D(0, 0, 1)) self.assertEqual( Vector3D(0, 2, 0).rotate(-math.pi / 4, Vector3D(1, 0, 0)), Vector3D(0, math.sqrt(2), math.sqrt(2)))
def solve(eye, look, up, fov, aspect_ratio, near, far): """ :type eye: Point3D :type look: Point3D :type up: Vector3D :type fov: int or float :type aspect_ratio: int or float :type near: int or float :type far: int or float """ solution = {} n = look.vector_to(eye) u = Vector3D.cross_product(up, n) n.normalize() u.normalize() v = Vector3D.cross_product(n, u) solution['n'] = n solution['u'] = u solution['v'] = v view_mat = Mat4() view_mat.set_element(0, 0, u.x) view_mat.set_element(0, 1, u.y) view_mat.set_element(0, 2, u.z) view_mat.set_element(1, 0, v.x) view_mat.set_element(1, 1, v.y) view_mat.set_element(1, 2, v.z) view_mat.set_element(2, 0, n.x) view_mat.set_element(2, 1, n.y) view_mat.set_element(2, 2, n.z) neg_eye = eye.to_vector().scaled(-1) view_mat.set_element(0, 3, neg_eye.dot_product(u)) view_mat.set_element(1, 3, neg_eye.dot_product(v)) view_mat.set_element(2, 3, neg_eye.dot_product(n)) solution['view_mat'] = view_mat t = near * tan(fov * pi / 360) b = -t r = t * aspect_ratio l = -r projection_mat = Mat4() projection_mat.set_element(0, 0, 2 * near / (r - l)) projection_mat.set_element(0, 2, (r + l) / (r - l)) projection_mat.set_element(1, 1, 2 * near / (t - b)) projection_mat.set_element(1, 2, (t + b) / (t - b)) projection_mat.set_element(2, 2, -(far + near) / (far - near)) projection_mat.set_element(2, 3, -(2 * far * near) / (far - near)) projection_mat.set_element(3, 2, -1) projection_mat.set_element(3, 3, 0) solution['projection_mat'] = projection_mat return solution
def test_3d(self): point = Vector3D(1, 1, 1) point += Vector3D(2, 2, 2) self.assertEqual(point, Vector3D(3, 3, 3)) self.assertEqual(point.length(), math.sqrt(27)) point = point.set_length(math.sqrt(3)) self.assertEqual(point, Vector3D(1, 1, 1)) point -= Vector3D(0, 1, 1) point = point.rotate(math.pi, Vector3D(0, 1, 0)) self.assertEqual(point, Vector3D(-1, 0, 0))
def test_distance_to(self): self.assertEqual( Vector3D(0, 0, 0).distance_to(Vector3D(1, 1, 1)), math.sqrt(3)) self.assertEqual( Vector3D(10, 10, 10).distance_to(Vector3D(20, 10, 10)), 10) self.assertEqual( Vector3D(-1, -1, -1).distance_to(Vector3D(-2, -3, -4)), math.sqrt(14))
def __init__(self, name: str = "", playerid: int = None, userid: int = None, possession: bool = False, position: List[float] = None, stats: dict = {}): self.name = name self.playerid = playerid self.userid = userid self.possession = possession self.position = Vector3D(*position) self.stats = Stats(**stats)
def generate(): problem = {} while True: vertex_pos = Point3D(random.randint(-100, 100), random.randint(-100, 100), random.randint(-100, 100)) vertex_normal = Vector3D(random.randint(-10, 10), random.randint(-10, 10), random.randint(-10, 10)) cam = Point3D(random.randint(-100, 100), random.randint(-100, 100), random.randint(-100, 100)) light = Point3D(random.randint(-100, 100), random.randint(-100, 100), random.randint(-100, 100)) if vertex_pos != cam and vertex_pos != light and cam != light: v = vertex_pos.vector_to(cam) s = vertex_pos.vector_to(light) h = v + s if vertex_normal.dot_self() == 0 or s.dot_self() == 0 or h.dot_self() == 0: continue problem['v_pos'] = vertex_pos problem['v_norm'] = vertex_normal problem['c_pos'] = cam problem['l_pos'] = light break while True: g_a = Color.random_color() l_a = Color.random_color() if g_a.r + l_a.r > 1.0 or g_a.b + l_a.b > 1.0 or g_a.g + l_a.g > 1.0: continue l_d = Color.random_color() l_s = Color.random_color() m_a = Color.random_color() m_d = Color.random_color() m_s = Color.random_color() shine = random.randint(10, 250) s = solve(problem['v_pos'], problem['v_norm'], problem['c_pos'], problem['l_pos'], g_a, l_a, l_d, l_s, m_a, m_d, m_s, shine) if s.r > 1.0 or s.g > 1.0 or s.b > 1.0: continue problem['g_a'] = g_a problem['l_a'] = l_a problem['l_d'] = l_d problem['l_s'] = l_s problem['m_a'] = m_a problem['m_d'] = m_d problem['m_s'] = m_s problem['shine'] = shine return problem
def test_solve2(self): s = solve(v_pos=Point3D(4, 4, 3), v_normal=Vector3D(0, 1, 0), c_pos=Point3D(4, 6, 5), l_pos=Point3D(5, 8, -1), g_a=Color(0.3, 0.2, 0.4), l_a=Color(0, 0, 0), l_d=Color(0.5, 0.3, 0.7), l_s=Color(0.3, 0.8, 0.7), m_a=Color(0.4, 0.2, 0.3), m_d=Color(0.4, 0.7, 0.2), m_s=Color(0.6, 0.6, 0.6), shine=13) expected = Color(r=0.336555752545358, g=0.392341571751585, b=0.397835285490389) self.assertAlmostEqual(s.r, expected.r, delta=1E-5, msg='r') self.assertAlmostEqual(s.g, expected.g, delta=1E-5, msg='g') self.assertAlmostEqual(s.b, expected.b, delta=1E-5, msg='b')
def test_solve3(self): s = solve(v_pos=Point3D(0, 1, 1), v_normal=Vector3D(1, -1, 3), c_pos=Point3D(-3, 3, 4), l_pos=Point3D(3, -2, 2), l_a=Color(0, 0, 0), l_d=Color(0.5, 0.3, 0.7), l_s=Color(0.3, 0.8, 0.7), g_a=Color(0.3, 0.2, 0.4), m_a=Color(0.4, 0.7, 0.3), m_d=Color(0.4, 0.7, 0.2), m_s=Color(0.6, 0.6, 0.6), shine=21) expected = Color(r=0.3067022520099555, g=0.4365837630415202, b=0.3522745356466035) self.assertAlmostEqual(s.r, expected.r, delta=1E-5, msg='r') self.assertAlmostEqual(s.g, expected.g, delta=1E-5, msg='g') self.assertAlmostEqual(s.b, expected.b, delta=1E-5, msg='b')
def test_solve1(self): s = solve(v_pos=Point3D(1, 4, 3), v_normal=Vector3D(0, 0, -1), c_pos=Point3D(-1, -1, 5), l_pos=Point3D(3, 8, -2), g_a=Color(0, 0, 0), l_a=Color(0.3, 0.7, 0.6), l_d=Color(0.3, 0.7, 0.6), l_s=Color(0.3, 0.7, 0.6), m_a=Color(0.3, 0.1, 0.2), m_d=Color(0.6, 0.2, 0.4), m_s=Color(1, 1, 1), shine=10) expected = Color(r=0.401311078649987, g=0.587692838949990, b=0.653179438199983) self.assertAlmostEqual(s.r, expected.r, delta=1E-5, msg='r') self.assertAlmostEqual(s.g, expected.g, delta=1E-5, msg='g') self.assertAlmostEqual(s.b, expected.b, delta=1E-5, msg='b')
def test_div(self): self.assertEqual(Vector3D(0, 0, 0) / 2, Vector3D(0, 0, 0)) self.assertEqual(Vector3D(1, 0, 2) / 2, Vector3D(0.5, 0, 1)) self.assertEqual(Vector3D(1, 2, 3) / (-0.5), Vector3D(-2, -4, -6)) self.assertRaises(Exception, Vector3D(1, 2, 3).__truediv__, 1e-12)
def test_set_length(self): self.assertEqual( Vector3D(1, 1, 0).set_length(1), Vector3D(math.cos(math.pi / 4), math.sin(math.pi / 4), 0)) self.assertEqual(Vector3D(0, 0, 0).set_length(0), Vector3D(0, 0, 0)) self.assertRaises(Exception, Vector3D(0, 0, 0).set_length, 1)
def test_scalar_product(self): self.assertEqual(Vector3D(0, 2, 0) % Vector3D(2, 0, 0), 0) self.assertEqual(Vector3D(2, 2, 2) % Vector3D(-2, -2, -2), -12) self.assertEqual(Vector3D(1, 3, 5) % Vector3D(2, 4, 6), 44)
def test_normalize(self): self.assertEqual( Vector3D(1, 1, 0).normalize(), Vector3D(math.cos(math.pi / 4), math.sin(math.pi / 4), 0)) self.assertEqual(Vector3D(2, 0, 0).normalize(), Vector3D(1, 0, 0)) self.assertRaises(Exception, Vector3D(0, 0, 0).normalize)
def test_length(self): self.assertEqual(Vector3D(0, 5, 0).length(), 5) self.assertEqual(Vector3D(5, 5, 5).length(), math.sqrt(75)) self.assertEqual(Vector3D(-1, -1, -1).length(), math.sqrt(3))
def test_solve3(self): d = 1E-5 s = solve( eye=Point3D(-1, -2, 4), look=Point3D(3, 1, -2), up=Vector3D(0, 1, 0), fov=30, aspect_ratio=16 / 9, near=1, far=11 ) n = s['n'] u = s['u'] v = s['v'] vm = s['view_mat'] pm = s['projection_mat'] expected = ( #u ( 3/sqrt(13), 0, 2/sqrt(13) ), #v ( -6/sqrt(793), 26/sqrt(793), 9/sqrt(793) ), #n ( -4/sqrt(61), -3/sqrt(61), 6/sqrt(61) ), #vm { (0, 0): 3/sqrt(13), (0, 1): 0, (0, 2): 2/sqrt(13), (0, 3): -5/sqrt(13), (1, 0): -6/sqrt(793), (1, 1): 26/sqrt(793), (1, 2): 9/sqrt(793), (1, 3): 10/sqrt(793), (2, 0): -4/sqrt(61), (2, 1): -3/sqrt(61), (2, 2): 6/sqrt(61), (2, 3): -34/sqrt(61), (3, 0): 0, (3, 1): 0, (3, 2): 0, (3, 3): 1, }, #pm { # T = tan(30 * pi / 360) # B = -tan(30 * pi / 360) # R = 16 * tan(30 * pi / 360) / 9 # L = -16 * tan(30 * pi / 360) / 9 (0, 0): 1 / (16 * tan(30 * pi / 360) / 9), (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 0): 0, (1, 1): 1 / (tan(30 * pi / 360)), (1, 2): 0, (1, 3): 0, (2, 0): 0, (2, 1): 0, (2, 2): -1.2, (2, 3): -2.2, (3, 0): 0, (3, 1): 0, (3, 2): -1, (3, 3): 0, } ) # U self.assertAlmostEqual(u.x, expected[0][0], delta=d) self.assertAlmostEqual(u.y, expected[0][1], delta=d) self.assertAlmostEqual(u.z, expected[0][2], delta=d) # V self.assertAlmostEqual(v.x, expected[1][0], delta=d) self.assertAlmostEqual(v.y, expected[1][1], delta=d) self.assertAlmostEqual(v.z, expected[1][2], delta=d) # N self.assertAlmostEqual(n.x, expected[2][0], delta=d) self.assertAlmostEqual(n.y, expected[2][1], delta=d) self.assertAlmostEqual(n.z, expected[2][2], delta=d) # View matrix for vm_kv in expected[3].items(): self.assertAlmostEqual(vm.get_element(*vm_kv[0]), vm_kv[1], delta=d) # Projection matrix for pm_kv in expected[4].items(): self.assertAlmostEqual(pm.get_element(*pm_kv[0]), pm_kv[1], delta=d)
def test_solve1(self): d = 1E-5 s = solve( eye=Point3D(0, 8, 4), look=Point3D(0, 3, -1), up=Vector3D(0, 0, -1), fov=75, aspect_ratio=16 / 9, near=3, far=25 ) n = s['n'] u = s['u'] v = s['v'] vm = s['view_mat'] pm = s['projection_mat'] expected = ( #u ( 1.0, 0, 0 ), #v ( 0, sqrt(2) / 2, -sqrt(2) / 2 ), #n ( 0, sqrt(2) / 2, sqrt(2) / 2 ), #vm { (0, 0): 1, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 0): 0, (1, 1): sqrt(2)/2, (1, 2): -sqrt(2)/2, (1, 3): -2*sqrt(2), (2, 0): 0, (2, 1): sqrt(2)/2, (2, 2): sqrt(2)/2, (2, 3): -6*sqrt(2), (3, 0): 0, (3, 1): 0, (3, 2): 0, (3, 3): 1, }, #pm { (0, 0): 9 / (16 * (sqrt(6) + sqrt(3) - sqrt(2) - 2)), (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 0): 0, (1, 1): 1 / (sqrt(6) + sqrt(3) - sqrt(2) - 2), (1, 2): 0, (1, 3): 0, (2, 0): 0, (2, 1): 0, (2, 2): -14 / 11, (2, 3): -75 / 11, (3, 0): 0, (3, 1): 0, (3, 2): -1, (3, 3): 0, } ) # U self.assertAlmostEqual(u.x, expected[0][0], delta=d) self.assertAlmostEqual(u.y, expected[0][1], delta=d) self.assertAlmostEqual(u.z, expected[0][2], delta=d) # V self.assertAlmostEqual(v.x, expected[1][0], delta=d) self.assertAlmostEqual(v.y, expected[1][1], delta=d) self.assertAlmostEqual(v.z, expected[1][2], delta=d) # N self.assertAlmostEqual(n.x, expected[2][0], delta=d) self.assertAlmostEqual(n.y, expected[2][1], delta=d) self.assertAlmostEqual(n.z, expected[2][2], delta=d) # View matrix for vm_kv in expected[3].items(): self.assertAlmostEqual(vm.get_element(*vm_kv[0]), vm_kv[1], delta=d) # Projection matrix for pm_kv in expected[4].items(): self.assertAlmostEqual(pm.get_element(*pm_kv[0]), pm_kv[1], delta=d)
def test_neg(self): self.assertEqual(-Vector3D(1, 1, 1), Vector3D(-1, -1, -1)) self.assertEqual(-Vector3D(1, 0, -1), Vector3D(-1, 0, 1)) self.assertEqual(-Vector3D(2, 5, -6), Vector3D(-2, -5, 6))
def test_mul(self): self.assertEqual(Vector3D(0, 0, 0) * 2, Vector3D(0, 0, 0)) self.assertEqual(Vector3D(1, 0, 2) * 3, Vector3D(3, 0, 6)) self.assertEqual(Vector3D(1, 2, 3) * (-0.5), Vector3D(-0.5, -1, -1.5))
def test_get_intersection(self): self.assertEqual( get_intersection(Vector3D(0, 0, 0), Vector3D(0, 0, 1), Vector3D(0, 0, 0), Vector3D(0, 1, 0), Vector3D(1, 0, 0)), Vector3D(0, 0, 0)) self.assertIsNone( get_intersection(Vector3D(0, 0, 0), Vector3D(1, 0, 0), Vector3D(0, 0, 0), Vector3D(0, 1, 0), Vector3D(1, 0, 0))) self.assertEqual( get_intersection(Vector3D(1, 1, 0), Vector3D(0, 0, 1), Vector3D(0, 0, 0), Vector3D(0, 1, 0), Vector3D(1, 0, 0)), Vector3D(1, 1, 0))
def test_solve2(self): d = 1E-5 s = solve( eye=Point3D(-29, -18, -93), look=Point3D(70, -76, -10), up=Vector3D(26, -10, -38), fov=74, aspect_ratio=7/4, near=8, far=23 ) n = s['n'] u = s['u'] v = s['v'] vm = s['view_mat'] pm = s['projection_mat'] expected = ( #u ( 0.45471427033982176, 0.8872473567606278, 0.07763414371655494 ), #v ( 0.5518192679714115, -0.21223817998900443, -0.8065050839582169 ), #n ( -0.6990925745885297, 0.409569387132674, -0.5861079160691713 ), #vm { (0, 0): 0.45471427033982176, (0, 1): 0.8872473567606278, (0, 2): 0.07763414371655494, (0, 3): 36.37714162718574, (1, 0): 0.5518192679714115, (1, 1): -0.21223817998900443, (1, 2): -0.806505083958216, (1, 3): -62.822501276745314, (2, 0): -0.6990925745885297, (2, 1): 0.409569387132674, (2, 2): -0.5861079160691713, (2, 3): -67.40947188911215, (3, 0): 0, (3, 1): 0, (3, 2): 0, (3, 3): 1, }, #pm { (0, 0): 0.7583113266402343, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 0): 0, (1, 1): 1.32704482162041, (1, 2): 0, (1, 3): 0, (2, 0): 0, (2, 1): 0, (2, 2): -2.066666666666667, (2, 3): -24.533333333333335, (3, 0): 0, (3, 1): 0, (3, 2): -1, (3, 3): 0, } ) # U self.assertAlmostEqual(u.x, expected[0][0], delta=d) self.assertAlmostEqual(u.y, expected[0][1], delta=d) self.assertAlmostEqual(u.z, expected[0][2], delta=d) # V self.assertAlmostEqual(v.x, expected[1][0], delta=d) self.assertAlmostEqual(v.y, expected[1][1], delta=d) self.assertAlmostEqual(v.z, expected[1][2], delta=d) # N self.assertAlmostEqual(n.x, expected[2][0], delta=d) self.assertAlmostEqual(n.y, expected[2][1], delta=d) self.assertAlmostEqual(n.z, expected[2][2], delta=d) # View matrix for vm_kv in expected[3].items(): self.assertAlmostEqual(vm.get_element(*vm_kv[0]), vm_kv[1], delta=d) # Projection matrix for pm_kv in expected[4].items(): self.assertAlmostEqual(pm.get_element(*pm_kv[0]), pm_kv[1], delta=d)
def test_length2(self): self.assertEqual(Vector3D(0, 5, 0).length2(), 25) self.assertEqual(Vector3D(5, 5, 5).length2(), 75) self.assertEqual(Vector3D(-1, -1, -1).length2(), 3)