Wed, 20 Dec 2017 17:25:09 +0200
Added code to compute areas of triangles and quadrilaterals
0 | 1 | class Vertex: |
2 | def __init__(self, x, y, z): | |
5 | 3 | if not all(is_real(coordinate) for coordinate in (x, y, z)): |
4 | raise ValueError(str.format('Bad vertex coordinates: {!r}', | |
5 | (x, y, z), | |
6 | )) | |
0 | 7 | self.x, self.y, self.z = x, y, z |
8 | def __repr__(self): | |
9 | return str.format('Vertex({!r}, {!r}, {!r})', self.x, self.y, self.z) | |
10 | def distance_to(self, other): | |
11 | # can't use hypot because of 3 arguments | |
12 | from math import sqrt | |
13 | return sqrt( | |
14 | (self.x - other.x) ** 2 + | |
15 | (self.y - other.y) ** 2 + | |
16 | (self.z - other.z) ** 2 | |
17 | ) | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
18 | @property |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
19 | def coordinates(self): |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
20 | return self.x, self.y, self.z |
5 | 21 | def __add__(self, other): |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
22 | return type(self)(self.x + other.x, self.y + other.y, self.z + other.z) |
5 | 23 | def __neg__(self): |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
24 | return type(self)(-self.x, -self.y, -self.z) |
5 | 25 | def __sub__(self, other): |
26 | return self + (-other) | |
27 | def __mul__(self, scalar): | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
28 | return type(self)(self.x * scalar, self.y * scalar, self.z * scalar) |
5 | 29 | def __rmul__(self, other): |
30 | return self * other | |
31 | def __truediv__(self, scalar): | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
32 | return type(self)(self.x / scalar, self.y / scalar, self.z / scalar) |
5 | 33 | def __floordiv__(self, scalar): |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
34 | return type(self)(self.x // scalar, self.y // scalar, self.z // scalar) |
5 | 35 | def __matmul__(self, transformation_matrix): |
36 | return transform(self, transformation_matrix) | |
37 | def __eq__(self, other): | |
38 | return self.coordinates == other.coordinates | |
39 | def __lt__(self, other): | |
40 | return self.coordinates < other.coordinates | |
41 | def __hash__(self): | |
42 | return hash(self.coordinates) | |
43 | ||
44 | class VertexOp: | |
45 | def __init__(self, callable): | |
46 | self.callable = callable | |
47 | def __rmul__(self, coordinate): | |
48 | return self.callable(coordinate) | |
0 | 49 | |
50 | class LineSegment: | |
51 | def __init__(self, v1, v2): | |
52 | self.v1, self.v2 = v1, v2 | |
53 | def __repr__(self): | |
54 | return str.format('LineSegment({!r}, {!r})', self.v1, self.v2) | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
55 | @property |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
56 | def vertices(self): |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
57 | return self.v1, self.v2 |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
58 | def __len__(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
59 | return 2 |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
60 | def __getitem__(self, index): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
61 | return self.vertices[index] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
62 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
63 | class IndexRing: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
64 | def __init__(self, container): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
65 | self.container = container |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
66 | def __getitem__(self, index): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
67 | return self.container[index % len(self.container)] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
68 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
69 | class Vector(Vertex): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
70 | def __init__(self, x, y, z): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
71 | super().__init__(x, y, z) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
72 | def __repr__(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
73 | return str.format('Vector({!r}, {!r}. {!r})', self.x, self.y, self.z) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
74 | def length(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
75 | from math import sqrt |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
76 | return sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
77 | def normalized(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
78 | length = self.length() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
79 | if length > 0: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
80 | return Vector(self.x / length, self.y / length, self.z / length) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
81 | else: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
82 | return Vector(0, 0, 0) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
83 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
84 | def dot_product(v1, v2): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
85 | ''' Returns the dot product v1 · v2. ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
86 | return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
87 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
88 | def cross_product(v1, v2): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
89 | ''' Returns the cross product v1 × v2. ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
90 | return Vector( |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
91 | x = v1.y * v2.z - v1.z * v2.y, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
92 | y = v1.z * v2.x - v1.x * v2.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
93 | z = v1.x * v2.y - v1.y * v2.x, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
94 | ) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
95 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
96 | def unit_normal(a, b, c): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
97 | x = Matrix3x3([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
98 | 1, a.y, a.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
99 | 1, b.y, b.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
100 | 1, c.y, c.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
101 | ]).determinant() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
102 | y = Matrix3x3([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
103 | a.x, 1, a.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
104 | b.x, 1, b.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
105 | c.x, 1, c.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
106 | ]).determinant() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
107 | z = Matrix3x3([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
108 | a.x, a.y, 1, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
109 | b.x, b.y, 1, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
110 | c.x, c.y, 1, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
111 | ]).determinant() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
112 | return Vector(x, y, z).normalized() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
113 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
114 | def pairs(iterable, *, count = 2): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
115 | ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
116 | Iterates the given iterable and returns tuples containing `count` |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
117 | sequential values in the iterable. |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
118 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
119 | Formally, for a vector A with indices 0…n and pair count k, this |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
120 | function yields: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
121 | (A₀, A₁, …, Aₖ), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
122 | (A₁, A₂, …, Aₖ₊₁), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
123 | …, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
124 | (Aₙ₋₂, Aₙ₋₁, …, Aₖ₋₂), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
125 | (Aₙ₋₁, A₀, …, Aₖ₋₁). |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
126 | ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
127 | iterable_count = len(iterable) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
128 | for index in range(iterable_count): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
129 | yield tuple( |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
130 | iterable[(index + offset) % iterable_count] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
131 | for offset in range(count) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
132 | ) |
0 | 133 | |
1 | 134 | class Polygon: |
135 | def __init__(self, vertices): | |
136 | self.vertices = vertices | |
137 | def __repr__(self): | |
138 | return str.format('Polygon({!r})', self.vertices) | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
139 | def area(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
140 | total = Vector(0, 0, 0) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
141 | for v1, v2 in pairs(self.vertices): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
142 | total += cross_product(v1, v2) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
143 | return dot_product(total, unit_normal(self.vertices[0], self.vertices[1], self.vertices[2])) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
144 | def centroid(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
145 | ... |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
146 | raise NotImplementedError |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
147 | def __getitem__(self, index): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
148 | return self.vertices[index % len(self.vertices)] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
149 | def __len__(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
150 | return len(self.vertices) |
1 | 151 | |
0 | 152 | def is_real(number): |
153 | return isinstance(number, int) or isinstance(number, float) | |
154 | ||
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
155 | class Matrix3x3: |
0 | 156 | ''' |
157 | A 3×3 matrix forming the top-left portion of a full 4×4 transformation | |
158 | matrix. | |
159 | ''' | |
160 | def __init__(self, values): | |
161 | assert(all(is_real(x) for x in values)) | |
162 | assert len(values) == 9 | |
163 | self.values = values | |
164 | def __repr__(self): | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
165 | return str.format('Matrix3x3({!r})', self.values) |
0 | 166 | def __getitem__(self, index): |
167 | return self.values[index] | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
168 | def determinant(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
169 | v = self.values |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
170 | return sum([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
171 | +(v[0] * v[4] * v[8]), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
172 | +(v[1] * v[5] * v[6]), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
173 | +(v[2] * v[3] * v[7]), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
174 | -(v[2] * v[4] * v[6]), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
175 | -(v[1] * v[3] * v[8]), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
176 | -(v[0] * v[5] * v[7]), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
177 | ]) |
0 | 178 | |
179 | def complete_matrix(matrix, anchor): | |
180 | ''' | |
181 | Combines a 3×3 matrix and an anchor vertex into a full 4×4 | |
182 | transformation matrix. | |
183 | ''' | |
184 | return [ | |
185 | matrix[0], matrix[1], matrix[2], anchor.x, | |
186 | matrix[3], matrix[4], matrix[5], anchor.y, | |
187 | matrix[6], matrix[7], matrix[8], anchor.z, | |
188 | 0, 0, 0, 1, | |
189 | ] | |
190 | ||
191 | def transform(vertex, transformation_matrix): | |
192 | ''' | |
193 | Transforms a vertex by a 4×4 transformation matrix. | |
194 | ''' | |
195 | u = transformation_matrix[0] * vertex.x \ | |
196 | + transformation_matrix[1] * vertex.y \ | |
197 | + transformation_matrix[2] * vertex.z \ | |
198 | + transformation_matrix[3] | |
199 | v = transformation_matrix[4] * vertex.x \ | |
200 | + transformation_matrix[5] * vertex.y \ | |
201 | + transformation_matrix[6] * vertex.z \ | |
202 | + transformation_matrix[7] | |
203 | w = transformation_matrix[8] * vertex.x \ | |
204 | + transformation_matrix[9] * vertex.y \ | |
205 | + transformation_matrix[10] * vertex.z \ | |
206 | + transformation_matrix[11] | |
207 | return Vertex(u, v, w) |