7 return min(container) * max(container) >= 0 |
7 return min(container) * max(container) >= 0 |
8 |
8 |
9 def concave_test(model): |
9 def concave_test(model): |
10 ''' Checks that all quadrilaterals are convex. ''' |
10 ''' Checks that all quadrilaterals are convex. ''' |
11 for quadrilateral in model.quadrilaterals: |
11 for quadrilateral in model.quadrilaterals: |
|
12 # Rotate the polygon into the XY plane. Then z is facing |
|
13 # away from the quadrilateral. |
12 geometry = transform_to_xy(quadrilateral.geometry) |
14 geometry = transform_to_xy(quadrilateral.geometry) |
|
15 # Now do a 2D concavity test: |
|
16 # https://math.stackexchange.com/a/1745427 |
13 z_scores = [ |
17 z_scores = [ |
14 cross_product(v2 - v1, v3 - v1).z |
18 cross_product(v2 - v1, v3 - v1).z |
15 for v1, v2, v3 in pairs(geometry.vertices, count = 3) |
19 for v1, v2, v3 in pairs(geometry.vertices, count = 3) |
16 ] |
20 ] |
17 if not sign_consistency(z_scores): |
21 if not sign_consistency(z_scores): |
33 yield warning(quadrilateral, 'skew-warning', |
37 yield warning(quadrilateral, 'skew-warning', |
34 skew_angle = skew_angle, |
38 skew_angle = skew_angle, |
35 ) |
39 ) |
36 break |
40 break |
37 |
41 |
|
42 def bowtie_test(model): |
|
43 for quadrilateral in model.quadrilaterals: |
|
44 geometry = transform_to_xy(quadrilateral.geometry) |
|
45 vertices = IndexRing(geometry.vertices) |
|
46 for i in (0, 1): |
|
47 line_1 = LineSegment(vertices[0 + i], vertices[1 + i]) |
|
48 line_2 = LineSegment(vertices[2 + i], vertices[3 + i]) |
|
49 intersection = line_segment_intersection_xy(line_1, line_2) |
|
50 if intersection: |
|
51 yield error(quadrilateral, 'self-intersecting') |
|
52 break |
|
53 |
38 manifest = { |
54 manifest = { |
39 'tests': { |
55 'tests': { |
40 'skew': skew_test, |
56 'skew': skew_test, |
41 'concave': concave_test, |
57 'concave': concave_test, |
|
58 'bowtie': bowtie_test, |
42 }, |
59 }, |
43 'messages': { |
60 'messages': { |
44 'skew-error': lambda skew_angle: |
61 'skew-error': lambda skew_angle: |
45 str.format('skew quadrilateral (plane angle {})', |
62 str.format('skew quadrilateral (plane angle {})', |
46 degree_rep(skew_angle), |
63 degree_rep(skew_angle), |
48 'skew-warning': lambda skew_angle: |
65 'skew-warning': lambda skew_angle: |
49 str.format('slightly skew quadrilateral (plane angle {})', |
66 str.format('slightly skew quadrilateral (plane angle {})', |
50 degree_rep(skew_angle), |
67 degree_rep(skew_angle), |
51 ), |
68 ), |
52 'concave-error': 'concave quadrilateral', |
69 'concave-error': 'concave quadrilateral', |
|
70 'self-intersecting': 'bowtie quadrilateral', |
53 }, |
71 }, |
54 } |
72 } |