Thu, 26 Aug 2021 19:37:00 +0300
Update license year
7 | 1 | def degree_rep(angle): |
2 | from math import degrees | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
38
diff
changeset
|
3 | try: |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
38
diff
changeset
|
4 | return '%.2f°' % degrees(angle) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
38
diff
changeset
|
5 | except TypeError: |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
38
diff
changeset
|
6 | return angle |
7 | 7 | |
8 | def position_vector(vertex): | |
9 | assert isinstance(vertex, Vertex) | |
10 | return Vector(*vertex.coordinates) | |
11 | ||
12 | def angle_magnitude_key(angle): | |
13 | ''' | |
14 | Returns how great an angle is. | |
15 | ''' | |
16 | from math import pi as π | |
17 | normalized_angle = abs(angle) % (2 * π) | |
18 | if normalized_angle > π: | |
19 | normalized_angle = (2 * π) - normalized_angle | |
20 | return normalized_angle | |
21 | ||
0 | 22 | class Vertex: |
23 | def __init__(self, x, y, z): | |
5 | 24 | if not all(is_real(coordinate) for coordinate in (x, y, z)): |
25 | raise ValueError(str.format('Bad vertex coordinates: {!r}', | |
26 | (x, y, z), | |
27 | )) | |
0 | 28 | self.x, self.y, self.z = x, y, z |
29 | def __repr__(self): | |
30 | return str.format('Vertex({!r}, {!r}, {!r})', self.x, self.y, self.z) | |
31 | def distance_to(self, other): | |
32 | # can't use hypot because of 3 arguments | |
33 | from math import sqrt | |
34 | return sqrt( | |
35 | (self.x - other.x) ** 2 + | |
36 | (self.y - other.y) ** 2 + | |
37 | (self.z - other.z) ** 2 | |
38 | ) | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
39 | @property |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
40 | def coordinates(self): |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
41 | return self.x, self.y, self.z |
5 | 42 | def __add__(self, other): |
7 | 43 | assert not (type(self) == type(other) == Vertex) |
44 | if type(self) == Vector and type(other) == Vector: | |
45 | result_type = Vector | |
46 | else: | |
47 | result_type = Vertex | |
48 | return result_type(self.x + other.x, self.y + other.y, self.z + other.z) | |
49 | def __radd__(self, other): | |
50 | return self + other | |
5 | 51 | def __neg__(self): |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
52 | return type(self)(-self.x, -self.y, -self.z) |
5 | 53 | def __sub__(self, other): |
7 | 54 | result = self + (-position_vector(other)) |
55 | if isinstance(other, Vertex): | |
56 | return Vector(*result.coordinates) | |
57 | else: | |
58 | return result | |
5 | 59 | def __mul__(self, scalar): |
7 | 60 | assert is_real(scalar) |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
61 | return type(self)(self.x * scalar, self.y * scalar, self.z * scalar) |
5 | 62 | def __rmul__(self, other): |
63 | return self * other | |
64 | def __truediv__(self, scalar): | |
7 | 65 | assert is_real(scalar) |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
66 | return type(self)(self.x / scalar, self.y / scalar, self.z / scalar) |
5 | 67 | def __floordiv__(self, scalar): |
7 | 68 | assert is_real(scalar) |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
69 | return type(self)(self.x // scalar, self.y // scalar, self.z // scalar) |
5 | 70 | def __matmul__(self, transformation_matrix): |
71 | return transform(self, transformation_matrix) | |
72 | def __eq__(self, other): | |
38
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
73 | return self.is_close(other, threshold = 1.0e-10) |
13 | 74 | def __ne__(self, other): |
75 | return not self.__eq__(other) | |
5 | 76 | def __lt__(self, other): |
77 | return self.coordinates < other.coordinates | |
78 | def __hash__(self): | |
79 | return hash(self.coordinates) | |
38
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
80 | def is_close(self, other, *, threshold = 1.0e-05): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
81 | return self.distance_to(other) < threshold |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
82 | #return all( |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
83 | # abs(a - b) < threshold |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
84 | # for a, b in zip(self.coordinates, other.coordinates) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
31
diff
changeset
|
85 | #) |
0 | 86 | |
87 | class LineSegment: | |
88 | def __init__(self, v1, v2): | |
89 | self.v1, self.v2 = v1, v2 | |
90 | def __repr__(self): | |
91 | 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
|
92 | @property |
7 | 93 | def length(self): |
94 | return self.v1.distance_to(self.v2) | |
95 | @property | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
96 | def vertices(self): |
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
1
diff
changeset
|
97 | return self.v1, self.v2 |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
98 | def __len__(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
99 | return 2 |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
100 | def __getitem__(self, index): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
101 | return self.vertices[index] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
102 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
103 | class IndexRing: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
104 | def __init__(self, container): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
105 | self.container = container |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
106 | def __getitem__(self, index): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
107 | return self.container[index % len(self.container)] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
108 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
109 | class Vector(Vertex): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
110 | def __init__(self, x, y, z): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
111 | super().__init__(x, y, z) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
112 | def __repr__(self): |
7 | 113 | return str.format('Vector({!r}, {!r}, {!r})', self.x, self.y, self.z) |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
114 | def length(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
115 | from math import sqrt |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
116 | 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
|
117 | def normalized(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
118 | length = self.length() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
119 | if length > 0: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
120 | 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
|
121 | else: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
122 | return Vector(0, 0, 0) |
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 | def dot_product(v1, v2): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
125 | ''' Returns the dot product v1 · v2. ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
126 | 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
|
127 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
128 | def cross_product(v1, v2): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
129 | ''' Returns the cross product v1 × v2. ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
130 | return Vector( |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
131 | 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
|
132 | 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
|
133 | 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
|
134 | ) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
135 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
136 | def unit_normal(a, b, c): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
137 | x = Matrix3x3([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
138 | 1, a.y, a.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
139 | 1, b.y, b.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
140 | 1, c.y, c.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
141 | ]).determinant() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
142 | y = Matrix3x3([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
143 | a.x, 1, a.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
144 | b.x, 1, b.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
145 | c.x, 1, c.z, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
146 | ]).determinant() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
147 | z = Matrix3x3([ |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
148 | a.x, a.y, 1, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
149 | b.x, b.y, 1, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
150 | c.x, c.y, 1, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
151 | ]).determinant() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
152 | return Vector(x, y, z).normalized() |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
153 | |
13 | 154 | class NoIntersection(Exception): |
155 | pass | |
156 | ||
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
157 | def pairs(iterable, *, count = 2): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
158 | ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
159 | 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
|
160 | sequential values in the iterable. |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
161 | |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
162 | 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
|
163 | function yields: |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
164 | (A₀, A₁, …, Aₖ), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
165 | (A₁, A₂, …, Aₖ₊₁), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
166 | …, |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
167 | (Aₙ₋₂, Aₙ₋₁, …, Aₖ₋₂), |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
168 | (Aₙ₋₁, A₀, …, Aₖ₋₁). |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
169 | ''' |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
170 | iterable_count = len(iterable) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
171 | for index in range(iterable_count): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
172 | yield tuple( |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
173 | iterable[(index + offset) % iterable_count] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
174 | for offset in range(count) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
175 | ) |
0 | 176 | |
1 | 177 | class Polygon: |
178 | def __init__(self, vertices): | |
179 | self.vertices = vertices | |
180 | def __repr__(self): | |
181 | return str.format('Polygon({!r})', self.vertices) | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
182 | def area(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
183 | total = Vector(0, 0, 0) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
184 | for v1, v2 in pairs(self.vertices): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
185 | total += cross_product(v1, v2) |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
186 | 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
|
187 | def centroid(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
188 | ... |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
189 | raise NotImplementedError |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
190 | def __getitem__(self, index): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
191 | return self.vertices[index % len(self.vertices)] |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
192 | def __len__(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
193 | return len(self.vertices) |
7 | 194 | @property |
195 | def perimeter_lines(self): | |
196 | for v1, v2 in pairs(self.vertices): | |
197 | yield LineSegment(v1, v2) | |
103
662de6b8cfc2
replaced the collinear test with a new one based on the hairline test that checks interior angles against official limits of 0.025 and 179.9
Teemu Piippo <teemu@hecknology.net>
parents:
92
diff
changeset
|
198 | def angle_cosines(self): |
662de6b8cfc2
replaced the collinear test with a new one based on the hairline test that checks interior angles against official limits of 0.025 and 179.9
Teemu Piippo <teemu@hecknology.net>
parents:
92
diff
changeset
|
199 | from math import isclose |
7 | 200 | for v1, v2, v3 in pairs(self.vertices, count = 3): |
201 | vec1 = (position_vector(v3) - position_vector(v2)).normalized() | |
202 | vec2 = (position_vector(v1) - position_vector(v2)).normalized() | |
90
6ae063fd27dc
fixed the collinear test for polygons with identical vertices
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
203 | if not isclose(vec1.length(), 0) and not isclose(vec2.length(), 0): |
6ae063fd27dc
fixed the collinear test for polygons with identical vertices
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
204 | cosine = dot_product(vec1, vec2) / vec1.length() / vec2.length() |
103
662de6b8cfc2
replaced the collinear test with a new one based on the hairline test that checks interior angles against official limits of 0.025 and 179.9
Teemu Piippo <teemu@hecknology.net>
parents:
92
diff
changeset
|
205 | yield cosine |
662de6b8cfc2
replaced the collinear test with a new one based on the hairline test that checks interior angles against official limits of 0.025 and 179.9
Teemu Piippo <teemu@hecknology.net>
parents:
92
diff
changeset
|
206 | else: |
662de6b8cfc2
replaced the collinear test with a new one based on the hairline test that checks interior angles against official limits of 0.025 and 179.9
Teemu Piippo <teemu@hecknology.net>
parents:
92
diff
changeset
|
207 | yield 1 # cos(0) |
7 | 208 | @property |
209 | def hairline_ratio(self): | |
210 | lengths = [line.length for line in self.perimeter_lines] | |
211 | return max(lengths) / min(lengths) | |
1 | 212 | |
0 | 213 | def is_real(number): |
214 | return isinstance(number, int) or isinstance(number, float) | |
215 | ||
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
216 | def matrix_indices(): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
217 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
218 | Yields index pairs for matrix iteration |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
219 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
220 | from itertools import product |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
221 | yield from product(range(3), range(3)) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
222 | |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
223 | class Matrix3x3: |
0 | 224 | ''' |
225 | A 3×3 matrix forming the top-left portion of a full 4×4 transformation | |
226 | matrix. | |
227 | ''' | |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
228 | class Row: |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
229 | def __init__(self, matrix_ref, i1, i2, i3): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
230 | self.matrix_ref = matrix_ref |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
231 | self.matrix_indices = i1, i2, i3 |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
232 | def __getitem__(self, row_index): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
233 | return self.matrix_ref[self.matrix_indices[row_index]] |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
234 | def __setitem__(self, row_index, value): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
235 | self.matrix_ref[self.matrix_indices[row_index]] = value |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
236 | def __init__(self, values = None): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
237 | if values is not None: |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
238 | assert(all(is_real(x) for x in values)) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
239 | assert len(values) == 9 |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
240 | self.values = values |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
241 | else: |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
242 | self.values = [1, 0, 0, 0, 1, 0, 0, 0, 1] |
0 | 243 | def __repr__(self): |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
244 | if self != Matrix3x3(): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
245 | return str.format('Matrix3x3({!r})', self.values) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
246 | else: |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
247 | return 'Matrix3x3()' |
0 | 248 | def __getitem__(self, index): |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
249 | if isinstance(index, tuple): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
250 | assert all(k in [0, 1, 2] for k in index) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
251 | return self.values[index[0] * 3 + index[1]] |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
252 | else: |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
253 | return Matrix3x3.Row(self, index * 3, index * 3 + 1, index * 3 + 2) |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
254 | def determinant(self): |
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
255 | return sum([ |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
256 | +(self[0, 0] * self[1, 1] * self[2, 2]), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
257 | +(self[0, 1] * self[1, 2] * self[2, 0]), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
258 | +(self[0, 2] * self[1, 0] * self[2, 1]), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
259 | -(self[0, 2] * self[1, 1] * self[2, 0]), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
260 | -(self[0, 1] * self[1, 0] * self[2, 2]), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
261 | -(self[0, 0] * self[1, 2] * self[2, 1]), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
262 | ]) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
263 | def scaling_vector(self): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
264 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
265 | Extracts scaling factors from this transformation matrix. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
266 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
267 | from math import sqrt |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
268 | return Vector( |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
269 | x = sqrt(self[0, 0] ** 2 + self[1, 0] ** 2 + self[2, 0] ** 2), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
270 | y = sqrt(self[0, 1] ** 2 + self[1, 1] ** 2 + self[2, 1] ** 2), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
271 | z = sqrt(self[0, 2] ** 2 + self[1, 2] ** 2 + self[2, 2] ** 2), |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
272 | ) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
273 | def rotation_component(self): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
274 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
275 | Extracts rotation from this matrix. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
276 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
277 | return self.split()[0] |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
278 | def split(self): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
279 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
280 | Extracts the rotation matrix and scaling vector. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
281 | ''' |
24 | 282 | vec = self.scaling_vector() |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
283 | return Matrix3x3([ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
284 | self[i, j] / vec.coordinates[j] |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
285 | for i, j in matrix_indices() |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
286 | ]), vec |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
287 | def contains_scaling(self): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
288 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
289 | Returns whether this matrix contains scaling factors. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
290 | ''' |
24 | 291 | vec = self.scaling_vector() |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
292 | return abs((vec.x * vec.y * vec.z) - 1) >= 1e-10 |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
293 | def contains_rotation(self): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
294 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
295 | Returns whether this matrix contains rotation factors. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
296 | ''' |
24 | 297 | return self.rotation_component() != Matrix3x3() |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
298 | def __eq__(self, other): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
299 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
300 | Returns whether two matrices are equivalent. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
301 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
302 | return all( |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
303 | abs(self[(i, j)] - other[(i, j)]) < 1e-10 |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
304 | for i, j in matrix_indices() |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
305 | ) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
306 | def __matmul__(self, other): |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
307 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
308 | Computes the matrix multiplication self × other. |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
309 | ''' |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
310 | return Matrix3x3([ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
311 | sum(self[i, k] * other[k, j] for k in range(3)) |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
312 | for i, j in matrix_indices() |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
5
diff
changeset
|
313 | ]) |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
314 | def __add__(self, other): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
315 | return Matrix3x3([ |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
316 | a + b |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
317 | for a, b in zip(self.values, other.values) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
318 | ]) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
319 | def __mul__(self, scalar): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
320 | return Matrix3x3([ |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
321 | x * scalar |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
322 | for x in self.values |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
323 | ]) |
92
b8d72909d593
improved the mirrored stud check to catch cases where a subfile that contains studs is mirrored
Teemu Piippo <teemu@hecknology.net>
parents:
90
diff
changeset
|
324 | def is_mirrored(self): |
b8d72909d593
improved the mirrored stud check to catch cases where a subfile that contains studs is mirrored
Teemu Piippo <teemu@hecknology.net>
parents:
90
diff
changeset
|
325 | return self.determinant() < 0 |
0 | 326 | |
327 | def complete_matrix(matrix, anchor): | |
328 | ''' | |
329 | Combines a 3×3 matrix and an anchor vertex into a full 4×4 | |
330 | transformation matrix. | |
331 | ''' | |
332 | return [ | |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
333 | matrix[0, 0], matrix[0, 1], matrix[0, 2], anchor.x, |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
334 | matrix[1, 0], matrix[1, 1], matrix[1, 2], anchor.y, |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
335 | matrix[2, 0], matrix[2, 1], matrix[2, 2], anchor.z, |
0 | 336 | 0, 0, 0, 1, |
337 | ] | |
338 | ||
339 | def transform(vertex, transformation_matrix): | |
340 | ''' | |
341 | Transforms a vertex by a 4×4 transformation matrix. | |
342 | ''' | |
9
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
343 | return Vertex( |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
344 | x = transformation_matrix[0] * vertex.x \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
345 | + transformation_matrix[1] * vertex.y \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
346 | + transformation_matrix[2] * vertex.z \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
347 | + transformation_matrix[3], |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
348 | y = transformation_matrix[4] * vertex.x \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
349 | + transformation_matrix[5] * vertex.y \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
350 | + transformation_matrix[6] * vertex.z \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
351 | + transformation_matrix[7], |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
352 | z = transformation_matrix[8] * vertex.x \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
353 | + transformation_matrix[9] * vertex.y \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
354 | + transformation_matrix[10] * vertex.z \ |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
355 | + transformation_matrix[11], |
fea8e9ae6f29
Added matrix code, moved library paths to ldcheck.cfg.
Santeri Piippo
parents:
7
diff
changeset
|
356 | ) |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
357 | |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
358 | def transform_to_xy(polygon): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
359 | ''' |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
360 | Transforms the provided polygon into the XY plane. The polygon is |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
361 | assumed to be planar. |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
362 | |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
363 | Implementation is based on this StackOverflow answer: |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
364 | https://math.stackexchange.com/a/476311 |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
365 | ''' |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
366 | v1, v2, v3 = polygon.vertices[:3] |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
367 | a, b = v3 - v2, v1 - v2 |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
368 | normal = cross_product(a, b).normalized() |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
369 | v_matrix = Matrix3x3([ |
15 | 370 | 0, 0, -normal.x, |
371 | 0, 0, -normal.y, | |
372 | normal.x, normal.y, 0, | |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
373 | ]) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
374 | try: |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
375 | rotation_matrix = Matrix3x3() |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
376 | rotation_matrix += v_matrix |
15 | 377 | rotation_matrix += (v_matrix @ v_matrix) * (1 / (1 + normal.z)) |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
378 | except ZeroDivisionError: |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
379 | rotation_matrix = Matrix3x3() |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
380 | full_matrix = complete_matrix(rotation_matrix, Vertex(0, 0, 0)) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
381 | return Polygon([ |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
382 | transform(vertex = vertex, transformation_matrix = full_matrix) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
383 | for vertex in polygon.vertices |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
384 | ]) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
385 | |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
386 | def vector_angle(vec_1, vec_2, normalized = False): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
387 | from math import acos, pi as π |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
388 | cosine = dot_product(vec_1, vec_2) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
389 | try: |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
390 | cosine /= vec_1.length() * vec_2.length() |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
391 | except ZeroDivisionError: |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
392 | return 0 |
31 | 393 | # Fix the cosine, it can go outside bounds due to rounding errors, |
394 | # e.g. 1.0000000000000002, which then causes a math domain error. | |
395 | cosine = min(max(-1, cosine), 1) | |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
396 | angle = acos(cosine) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
397 | if normalized and angle > π / 2: |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
398 | angle = π - angle |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
399 | return angle |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
400 | |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
401 | def split_quadrilateral(polygon): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
402 | assert(len(polygon.vertices) == 4) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
403 | vertices = IndexRing(polygon.vertices) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
404 | for i in (0, 1): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
405 | a, b = vertices[0 + i], vertices[1 + i] |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
406 | c, d = vertices[2 + i], vertices[3 + i] |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
407 | yield Polygon([a, b, c]), Polygon([b, c, d]) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
408 | |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
409 | def triangle_plane_normal(polygon): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
410 | assert(len(polygon.vertices) == 3) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
411 | a, b, c = polygon.vertices[:3] |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
412 | return cross_product(b - a, b - c) |
28 | 413 | |
414 | def line_intersection_xy(line_1, line_2): | |
415 | ''' | |
416 | Computes 2D line intersection. Can return a point outside the given | |
417 | segments. Z is ignored. | |
418 | ''' | |
419 | a, b = line_1.vertices | |
420 | c, d = line_2.vertices | |
421 | denominator = (a.x - b.x) * (c.y - d.y) - (a.y - b.y) * (c.x - d.x) | |
422 | x = (c.x - d.x) * (a.x * b.y - a.y * b.x) | |
423 | x -= (a.x - b.x) * (c.x * d.y - c.y * d.x) | |
424 | y = (c.y - d.y) * (a.x * b.y - a.y * b.x) | |
425 | y -= (a.y - b.y) * (c.x * d.y - c.y * d.x) | |
426 | try: | |
427 | x /= denominator | |
428 | y /= denominator | |
429 | except ZeroDivisionError: | |
430 | return None | |
431 | else: | |
432 | return Vertex(x, y, 0) | |
433 | ||
434 | def line_segment_intersection_xy(line_1, line_2): | |
435 | ''' | |
436 | Computes 2D line intersection. Only returns a result if it falls | |
437 | inside the line segments. Z is ignored. | |
438 | ''' | |
439 | from math import inf | |
440 | intersection = line_intersection_xy(line_1, line_2) | |
441 | if intersection: | |
442 | a, b = line_1.vertices | |
443 | c, d = line_2.vertices | |
444 | try: | |
30
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
445 | t1 = (intersection.x - a.x) / (b.x - a.x) |
28 | 446 | except ZeroDivisionError: |
30
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
447 | t1 = inf |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
448 | try: |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
449 | t2 = (intersection.x - c.x) / (d.x - c.x) |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
450 | except ZeroDivisionError: |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
451 | t2 = inf |
28 | 452 | try: |
30
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
453 | u1 = (intersection.y - a.y) / (b.y - a.y) |
28 | 454 | except ZeroDivisionError: |
30
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
455 | u1 = inf |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
456 | try: |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
457 | u2 = (intersection.y - c.y) / (d.y - c.y) |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
458 | except ZeroDivisionError: |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
459 | u2 = inf |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
460 | if (0 < t1 < 1 and 0 < t2 < 1) or (0 < u1 < 1 and 0 < u2 < 1): |
28 | 461 | return intersection |
462 | else: | |
463 | return None | |
464 | else: | |
465 | return None |