geometry.py

changeset 6
6da1e81c5652
parent 5
e340e35d6e4c
child 7
0ab0d61ccee8
equal deleted inserted replaced
5:e340e35d6e4c 6:6da1e81c5652
17 ) 17 )
18 @property 18 @property
19 def coordinates(self): 19 def coordinates(self):
20 return self.x, self.y, self.z 20 return self.x, self.y, self.z
21 def __add__(self, other): 21 def __add__(self, other):
22 return Vertex(self.x + other.x, self.y + other.y, self.z + other.z) 22 return type(self)(self.x + other.x, self.y + other.y, self.z + other.z)
23 def __neg__(self): 23 def __neg__(self):
24 return Vertex(-self.x, -self.y, -self.z) 24 return type(self)(-self.x, -self.y, -self.z)
25 def __sub__(self, other): 25 def __sub__(self, other):
26 return self + (-other) 26 return self + (-other)
27 def __mul__(self, scalar): 27 def __mul__(self, scalar):
28 return Vertex(self.x * scalar, self.y * scalar, self.z * scalar) 28 return type(self)(self.x * scalar, self.y * scalar, self.z * scalar)
29 def __rmul__(self, other): 29 def __rmul__(self, other):
30 return self * other 30 return self * other
31 def __truediv__(self, scalar): 31 def __truediv__(self, scalar):
32 return Vertex(self.x / scalar, self.y / scalar, self.z / scalar) 32 return type(self)(self.x / scalar, self.y / scalar, self.z / scalar)
33 def __floordiv__(self, scalar): 33 def __floordiv__(self, scalar):
34 return Vertex(self.x // scalar, self.y // scalar, self.z // scalar) 34 return type(self)(self.x // scalar, self.y // scalar, self.z // scalar)
35 def __matmul__(self, transformation_matrix): 35 def __matmul__(self, transformation_matrix):
36 return transform(self, transformation_matrix) 36 return transform(self, transformation_matrix)
37 def __eq__(self, other): 37 def __eq__(self, other):
38 return self.coordinates == other.coordinates 38 return self.coordinates == other.coordinates
39 def __lt__(self, other): 39 def __lt__(self, other):
53 def __repr__(self): 53 def __repr__(self):
54 return str.format('LineSegment({!r}, {!r})', self.v1, self.v2) 54 return str.format('LineSegment({!r}, {!r})', self.v1, self.v2)
55 @property 55 @property
56 def vertices(self): 56 def vertices(self):
57 return self.v1, self.v2 57 return self.v1, self.v2
58 def __len__(self):
59 return 2
60 def __getitem__(self, index):
61 return self.vertices[index]
62
63 class IndexRing:
64 def __init__(self, container):
65 self.container = container
66 def __getitem__(self, index):
67 return self.container[index % len(self.container)]
68
69 class Vector(Vertex):
70 def __init__(self, x, y, z):
71 super().__init__(x, y, z)
72 def __repr__(self):
73 return str.format('Vector({!r}, {!r}. {!r})', self.x, self.y, self.z)
74 def length(self):
75 from math import sqrt
76 return sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
77 def normalized(self):
78 length = self.length()
79 if length > 0:
80 return Vector(self.x / length, self.y / length, self.z / length)
81 else:
82 return Vector(0, 0, 0)
83
84 def dot_product(v1, v2):
85 ''' Returns the dot product v1 · v2. '''
86 return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
87
88 def cross_product(v1, v2):
89 ''' Returns the cross product v1 × v2. '''
90 return Vector(
91 x = v1.y * v2.z - v1.z * v2.y,
92 y = v1.z * v2.x - v1.x * v2.z,
93 z = v1.x * v2.y - v1.y * v2.x,
94 )
95
96 def unit_normal(a, b, c):
97 x = Matrix3x3([
98 1, a.y, a.z,
99 1, b.y, b.z,
100 1, c.y, c.z,
101 ]).determinant()
102 y = Matrix3x3([
103 a.x, 1, a.z,
104 b.x, 1, b.z,
105 c.x, 1, c.z,
106 ]).determinant()
107 z = Matrix3x3([
108 a.x, a.y, 1,
109 b.x, b.y, 1,
110 c.x, c.y, 1,
111 ]).determinant()
112 return Vector(x, y, z).normalized()
113
114 def pairs(iterable, *, count = 2):
115 '''
116 Iterates the given iterable and returns tuples containing `count`
117 sequential values in the iterable.
118
119 Formally, for a vector A with indices 0…n and pair count k, this
120 function yields:
121 (A₀, A₁, …, Aₖ),
122 (A₁, A₂, …, Aₖ₊₁),
123 …,
124 (Aₙ₋₂, Aₙ₋₁, …, Aₖ₋₂),
125 (Aₙ₋₁, A₀, …, Aₖ₋₁).
126 '''
127 iterable_count = len(iterable)
128 for index in range(iterable_count):
129 yield tuple(
130 iterable[(index + offset) % iterable_count]
131 for offset in range(count)
132 )
58 133
59 class Polygon: 134 class Polygon:
60 def __init__(self, vertices): 135 def __init__(self, vertices):
61 self.vertices = vertices 136 self.vertices = vertices
62 def __repr__(self): 137 def __repr__(self):
63 return str.format('Polygon({!r})', self.vertices) 138 return str.format('Polygon({!r})', self.vertices)
139 def area(self):
140 total = Vector(0, 0, 0)
141 for v1, v2 in pairs(self.vertices):
142 total += cross_product(v1, v2)
143 return dot_product(total, unit_normal(self.vertices[0], self.vertices[1], self.vertices[2]))
144 def centroid(self):
145 ...
146 raise NotImplementedError
147 def __getitem__(self, index):
148 return self.vertices[index % len(self.vertices)]
149 def __len__(self):
150 return len(self.vertices)
64 151
65 def is_real(number): 152 def is_real(number):
66 return isinstance(number, int) or isinstance(number, float) 153 return isinstance(number, int) or isinstance(number, float)
67 154
68 class TransformationMatrix: 155 class Matrix3x3:
69 ''' 156 '''
70 A 3×3 matrix forming the top-left portion of a full 4×4 transformation 157 A 3×3 matrix forming the top-left portion of a full 4×4 transformation
71 matrix. 158 matrix.
72 ''' 159 '''
73 def __init__(self, values): 160 def __init__(self, values):
74 assert(all(is_real(x) for x in values)) 161 assert(all(is_real(x) for x in values))
75 assert len(values) == 9 162 assert len(values) == 9
76 self.values = values 163 self.values = values
77 def __repr__(self): 164 def __repr__(self):
78 return str.format('TransformationMatrix({!r})', self.values) 165 return str.format('Matrix3x3({!r})', self.values)
79 def __getitem__(self, index): 166 def __getitem__(self, index):
80 return self.values[index] 167 return self.values[index]
168 def determinant(self):
169 v = self.values
170 return sum([
171 +(v[0] * v[4] * v[8]),
172 +(v[1] * v[5] * v[6]),
173 +(v[2] * v[3] * v[7]),
174 -(v[2] * v[4] * v[6]),
175 -(v[1] * v[3] * v[8]),
176 -(v[0] * v[5] * v[7]),
177 ])
81 178
82 def complete_matrix(matrix, anchor): 179 def complete_matrix(matrix, anchor):
83 ''' 180 '''
84 Combines a 3×3 matrix and an anchor vertex into a full 4×4 181 Combines a 3×3 matrix and an anchor vertex into a full 4×4
85 transformation matrix. 182 transformation matrix.

mercurial