316 ''' |
316 ''' |
317 return Matrix3x3([ |
317 return Matrix3x3([ |
318 sum(self[i, k] * other[k, j] for k in range(3)) |
318 sum(self[i, k] * other[k, j] for k in range(3)) |
319 for i, j in matrix_indices() |
319 for i, j in matrix_indices() |
320 ]) |
320 ]) |
|
321 def __add__(self, other): |
|
322 return Matrix3x3([ |
|
323 a + b |
|
324 for a, b in zip(self.values, other.values) |
|
325 ]) |
|
326 def __mul__(self, scalar): |
|
327 return Matrix3x3([ |
|
328 x * scalar |
|
329 for x in self.values |
|
330 ]) |
321 |
331 |
322 def complete_matrix(matrix, anchor): |
332 def complete_matrix(matrix, anchor): |
323 ''' |
333 ''' |
324 Combines a 3×3 matrix and an anchor vertex into a full 4×4 |
334 Combines a 3×3 matrix and an anchor vertex into a full 4×4 |
325 transformation matrix. |
335 transformation matrix. |
347 z = transformation_matrix[8] * vertex.x \ |
357 z = transformation_matrix[8] * vertex.x \ |
348 + transformation_matrix[9] * vertex.y \ |
358 + transformation_matrix[9] * vertex.y \ |
349 + transformation_matrix[10] * vertex.z \ |
359 + transformation_matrix[10] * vertex.z \ |
350 + transformation_matrix[11], |
360 + transformation_matrix[11], |
351 ) |
361 ) |
|
362 |
|
363 def transform_to_xy(polygon): |
|
364 ''' |
|
365 Transforms the provided polygon into the XY plane. The polygon is |
|
366 assumed to be planar. |
|
367 |
|
368 Implementation is based on this StackOverflow answer: |
|
369 https://math.stackexchange.com/a/476311 |
|
370 ''' |
|
371 v1, v2, v3 = polygon.vertices[:3] |
|
372 a, b = v3 - v2, v1 - v2 |
|
373 normal = cross_product(a, b).normalized() |
|
374 v = cross_product(normal, Vector(0, 0, 1)) |
|
375 cosine = dot_product(normal, Vector(0, 0, 1)) |
|
376 v_matrix = Matrix3x3([ |
|
377 0, -v.z, v.y, |
|
378 v.z, 0, -v.x, |
|
379 -v.y, v.x, 0, |
|
380 ]) |
|
381 try: |
|
382 rotation_matrix = Matrix3x3() |
|
383 rotation_matrix += v_matrix |
|
384 rotation_matrix += (v_matrix @ v_matrix) * (1 / (1 + cosine)) |
|
385 except ZeroDivisionError: |
|
386 rotation_matrix = Matrix3x3() |
|
387 full_matrix = complete_matrix(rotation_matrix, Vertex(0, 0, 0)) |
|
388 return Polygon([ |
|
389 transform(vertex = vertex, transformation_matrix = full_matrix) |
|
390 for vertex in polygon.vertices |
|
391 ]) |
|
392 |
|
393 def vector_angle(vec_1, vec_2, normalized = False): |
|
394 from math import acos, pi as π |
|
395 cosine = dot_product(vec_1, vec_2) |
|
396 try: |
|
397 cosine /= vec_1.length() * vec_2.length() |
|
398 except ZeroDivisionError: |
|
399 return 0 |
|
400 angle = acos(cosine) |
|
401 if normalized and angle > π / 2: |
|
402 angle = π - angle |
|
403 return angle |
|
404 |
|
405 def split_quadrilateral(polygon): |
|
406 assert(len(polygon.vertices) == 4) |
|
407 vertices = IndexRing(polygon.vertices) |
|
408 for i in (0, 1): |
|
409 a, b = vertices[0 + i], vertices[1 + i] |
|
410 c, d = vertices[2 + i], vertices[3 + i] |
|
411 yield Polygon([a, b, c]), Polygon([b, c, d]) |
|
412 |
|
413 def triangle_plane_normal(polygon): |
|
414 assert(len(polygon.vertices) == 3) |
|
415 a, b, c = polygon.vertices[:3] |
|
416 return cross_product(b - a, b - c) |