| 1 from math import acos, degrees, radians, pi as π |
|
| 2 from testsuite import warning, error |
|
| 3 from geometry import * |
|
| 4 |
|
| 5 def sign_consistency(container): |
|
| 6 # Returns whether all elements in container have the same sign |
|
| 7 return min(container) * max(container) >= 0 |
|
| 8 |
|
| 9 def concave_test(model): |
|
| 10 for quadrilateral in model.quadrilaterals: |
|
| 11 geometry = transform_to_xy(quadrilateral.geometry) |
|
| 12 z_scores = [ |
|
| 13 cross_product(v2 - v1, v3 - v1).z |
|
| 14 for v1, v2, v3 in pairs(geometry.vertices, count = 3) |
|
| 15 ] |
|
| 16 if not sign_consistency(z_scores): |
|
| 17 yield error(quadrilateral, 'concave-error') |
|
| 18 |
|
| 19 def skew_test(model): |
|
| 20 ''' Test for non-coplanar quadrilaterals. ''' |
|
| 21 for quadrilateral in model.quadrilaterals: |
|
| 22 for triangles in split_quadrilateral(quadrilateral.geometry): |
|
| 23 plane_1 = triangle_plane_normal(triangles[0]) |
|
| 24 plane_2 = triangle_plane_normal(triangles[1]) |
|
| 25 skew_angle = vector_angle(plane_1, plane_2, normalized = True) |
|
| 26 if skew_angle > radians(0.1): |
|
| 27 yield error(quadrilateral, 'skew-error', |
|
| 28 skew_angle = skew_angle, |
|
| 29 ) |
|
| 30 break |
|
| 31 |
|
| 32 manifest = { |
|
| 33 'tests': { |
|
| 34 'skew': skew_test, |
|
| 35 'concave': concave_test, |
|
| 36 }, |
|
| 37 'messages': { |
|
| 38 'skew-error': lambda skew_angle: |
|
| 39 str.format('skew quadrilateral (plane angle {}°)', |
|
| 40 '%.2f' % degrees(skew_angle), |
|
| 41 ), |
|
| 42 'concave-error': 'concave quadrilateral', |
|
| 43 }, |
|
| 44 } |
|