-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeometry.py
157 lines (129 loc) · 4.37 KB
/
geometry.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from math import sqrt
class Line():
def __init__(self, slope, start):
"""
Slope is a 3-element tuple representing the line slope
Start is a 3-element tuple representing one point in the line
"""
self.slope = slope
self.start = start
@staticmethod
def through_points(point0, point1):
"""
Creates a line that passes in two given points
"""
x1, y1, z1 = point1
x0, y0, z0 = point0
return Line((x1 - x0, y1 - y0, z1 - z0), (x0, y0, z0))
def distance_to_point(self, point):
"""
Returns the distance between a line and a point
"""
q = Vector(point)
v = Vector(self.slope)
p = Vector(self.start)
vec = q.subtract(p)
proj = vec.project(v)
return (proj.subtract(vec)).norm()
def point_after_t(self, num):
p = Vector(self.start)
q = Vector(self.slope)
return p.add(q.mul_by_number(num))
class HorizontalPlane():
def __init__(self, cte, color1, color2):
self.cte = cte
self.color1 = color1
self.color2 = color2
self.reflectivity = 0.2
def intersection_value(self, line):
a = line.slope[2]
if a == 0:
return []
t = float(self.cte - line.start[2])/line.slope[2]
if t > 0.01:
return [t]
else:
return []
def color_at_point(self, point):
if int(point[0]) % 2 == int(point[1]) % 2:
return self.color1
else:
return self.color2
def normal(self, point):
return Vector((0, 0, 1))
class Sphere():
def __init__(self, center, radius, color, reflectivity=0):
"""
Center is a 3-element tuple representing a spacial position
Radius is a positive number
Color is 3-element tuple representing RGB values of the sphere's color
"""
self.center = center
self.radius = radius
self.color = color
self.reflectivity = reflectivity
def intersection_value(self, line):
v = Vector(line.slope)
s = Vector(line.start)
c = Vector(self.center)
q = s.subtract(c)
A = v.squared_norm()
B = 2*v.scalar_product(q)
C = q.squared_norm() - self.radius**2
return solve_quadradic(A, B, C)
def color_at_point(self, point):
return self.color
def normal(self, point):
line = Line.through_points(self.center, point)
q = Vector(line.slope)
return q.normalize()
class Vector():
def __init__(self, coords):
self.coords = coords
def scalar_product(self, v2):
return sum(x*y for (x, y) in zip(self.coords, v2.coords))
def subtract(self, v2):
return Vector([self.coords[0] - v2.coords[0], self.coords[1] - v2.coords[1], self.coords[2] - v2.coords[2]])
def add(self, v2):
return Vector([self.coords[0] + v2.coords[0], self.coords[1] + v2.coords[1], self.coords[2] + v2.coords[2]])
def squared_norm(self):
return sum(x**2 for x in self.coords)
def norm(self):
return sqrt(self.squared_norm())
def cross_product(self, v2):
a0, a1, a2 = self.coords
b0, b1, b2 = v2.coords
return Vector([a1*b2 - a2*b1, a2*b0 - a0*b2, a0*b1 - a1*b0])
def equals(self, v2):
eps = 0.0001
for i in range(len(self.coords)):
if abs(self.coords[i] - v2.coords[i]) > eps:
return False
return True
def mul_by_number(self, num):
return Vector([x*num for x in self.coords])
def project(self, v2):
n = float(self.scalar_product(v2))/v2.scalar_product(v2)
return v2.mul_by_number(n)
def normalize(self):
n = 1.0/self.norm()
return self.mul_by_number(n)
# Some extra mathematical methods
def solve_quadradic(a, b, c):
delta = b**2 - 4*a*c
if delta < 0:
return []
ans = []
ans.append((-b - sqrt(delta))/(2.0*a))
ans.append((-b + sqrt(delta))/(2.0*a))
return filter(lambda x: x > 0.01, ans)
def tuple_times_num(tup, num):
return (int(num*tup[0]), int(num*tup[1]), int(num*tup[2]))
def tuple_average(array_of_tuples):
n = len(array_of_tuples)
a, b, c = 0, 0, 0
for k in range(n):
a += array_of_tuples[k][0]
b += array_of_tuples[k][1]
c += array_of_tuples[k][2]
return (a/n, b/n, c/n)