Fri, 18 Sep 2020 21:07:11 +0300
added unit tests for official parts
22 | 1 | from math import radians |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
2 | from testsuite import problem_type, report_problem |
12 | 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 | ||
64
1c0884f5506e
changed severity names to be better understood
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
9 | @problem_type('concave', severity = 'hold', message = 'concave quadrilateral') |
12 | 10 | def concave_test(model): |
26
7c263b864371
Added command line option to list all checks.
Santeri Piippo
parents:
22
diff
changeset
|
11 | ''' Checks that all quadrilaterals are convex. ''' |
13 | 12 | for quadrilateral in model.quadrilaterals: |
28 | 13 | # Rotate the polygon into the XY plane. Then z is facing |
14 | # away from the quadrilateral. | |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
15 | geometry = transform_to_xy(quadrilateral.geometry) |
28 | 16 | # Now do a 2D concavity test: |
17 | # https://math.stackexchange.com/a/1745427 | |
12 | 18 | z_scores = [ |
19 | cross_product(v2 - v1, v3 - v1).z | |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
20 | for v1, v2, v3 in pairs(geometry.vertices, count = 3) |
12 | 21 | ] |
22 | if not sign_consistency(z_scores): | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
23 | yield report_problem('concave', bad_object = quadrilateral) |
13 | 24 | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
25 | @problem_type('skew-major', |
64
1c0884f5506e
changed severity names to be better understood
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
26 | severity = 'hold', |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
27 | message = lambda skew_angle: |
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:
90
diff
changeset
|
28 | str.format('skew (non-coplanar) quadrilateral (plane angle {})', |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
29 | degree_rep(skew_angle), |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
30 | ), |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
31 | ) |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
32 | @problem_type('skew-minor', |
64
1c0884f5506e
changed severity names to be better understood
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
33 | severity = 'warning', |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
34 | message = lambda skew_angle: |
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:
90
diff
changeset
|
35 | str.format('slightly skew (non-coplanar) quadrilateral (plane angle {})', |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
36 | degree_rep(skew_angle), |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
37 | ), |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
38 | ) |
13 | 39 | def skew_test(model): |
26
7c263b864371
Added command line option to list all checks.
Santeri Piippo
parents:
22
diff
changeset
|
40 | ''' Checks that all quadrilaterals are coplanar. ''' |
13 | 41 | for quadrilateral in model.quadrilaterals: |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
42 | for triangles in split_quadrilateral(quadrilateral.geometry): |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
43 | plane_1 = triangle_plane_normal(triangles[0]) |
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
44 | plane_2 = triangle_plane_normal(triangles[1]) |
16 | 45 | skew_angle = vector_angle(plane_1, plane_2, normalized = True) |
27
3089611c99d1
Changed threshold skew test, added warning for slightly skew quads
Santeri Piippo
parents:
26
diff
changeset
|
46 | if skew_angle > radians(3.0): |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
47 | yield report_problem( |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
48 | 'skew-major', |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
49 | bad_object = quadrilateral, |
16 | 50 | skew_angle = skew_angle, |
51 | ) | |
13 | 52 | break |
27
3089611c99d1
Changed threshold skew test, added warning for slightly skew quads
Santeri Piippo
parents:
26
diff
changeset
|
53 | elif skew_angle > radians(1.0): |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
54 | yield report_problem( |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
55 | 'skew-minor', |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
56 | bad_object = quadrilateral, |
27
3089611c99d1
Changed threshold skew test, added warning for slightly skew quads
Santeri Piippo
parents:
26
diff
changeset
|
57 | skew_angle = skew_angle, |
3089611c99d1
Changed threshold skew test, added warning for slightly skew quads
Santeri Piippo
parents:
26
diff
changeset
|
58 | ) |
3089611c99d1
Changed threshold skew test, added warning for slightly skew quads
Santeri Piippo
parents:
26
diff
changeset
|
59 | break |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
60 | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
61 | @problem_type('self-intersecting', |
64
1c0884f5506e
changed severity names to be better understood
Teemu Piippo <teemu@hecknology.net>
parents:
62
diff
changeset
|
62 | severity = 'hold', |
106
d93ef722bba6
added a reference for bowtie quadrilaterals
Teemu Piippo <teemu@hecknology.net>
parents:
103
diff
changeset
|
63 | message = 'bowtie (self-intersecting) quadrilateral', |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
64 | ) |
28 | 65 | def bowtie_test(model): |
66 | for quadrilateral in model.quadrilaterals: | |
67 | geometry = transform_to_xy(quadrilateral.geometry) | |
68 | vertices = IndexRing(geometry.vertices) | |
69 | for i in (0, 1): | |
70 | line_1 = LineSegment(vertices[0 + i], vertices[1 + i]) | |
71 | line_2 = LineSegment(vertices[2 + i], vertices[3 + i]) | |
72 | intersection = line_segment_intersection_xy(line_1, line_2) | |
73 | if intersection: | |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
74 | yield report_problem( |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
75 | 'self-intersecting', |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
76 | bad_object = quadrilateral, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
77 | ) |
28 | 78 | break |
79 | ||
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:
90
diff
changeset
|
80 | @problem_type('collinear', |
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:
90
diff
changeset
|
81 | severity = 'hold', |
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:
90
diff
changeset
|
82 | message = lambda min_angle, max_angle: str.format( |
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:
90
diff
changeset
|
83 | 'collinear polygon (smallest interior angle {min_angle}, largest {max_angle})', |
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:
90
diff
changeset
|
84 | min_angle = degree_rep(min_angle), |
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:
90
diff
changeset
|
85 | max_angle = degree_rep(max_angle), |
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:
90
diff
changeset
|
86 | ), |
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:
90
diff
changeset
|
87 | ) |
30
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
88 | def collinear_test(model): |
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:
90
diff
changeset
|
89 | from math import radians, cos, acos |
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:
90
diff
changeset
|
90 | # according to the LDraw spec, all interior angles must be |
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:
90
diff
changeset
|
91 | # between 0.025 degrees and 179.9 degrees. Note that between 0 and pi, |
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:
90
diff
changeset
|
92 | # cos(x) is a downwards curve, so the minimum cosine is for the maximum |
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:
90
diff
changeset
|
93 | # angle. |
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:
90
diff
changeset
|
94 | min_cosine = cos(radians(179.9)) |
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:
90
diff
changeset
|
95 | max_cosine = cos(radians(0.025)) |
30
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
96 | for element in model.body: |
0d9ca37901ed
added test for collinearity, fixed bowtie test
Santeri Piippo
parents:
28
diff
changeset
|
97 | if hasattr(element, 'geometry') and len(element.geometry.vertices) >= 3: |
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:
90
diff
changeset
|
98 | cosines = list(element.geometry.angle_cosines()) |
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:
90
diff
changeset
|
99 | if any( |
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:
90
diff
changeset
|
100 | not(min_cosine < cosine < max_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:
90
diff
changeset
|
101 | for cosine in cosines |
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:
90
diff
changeset
|
102 | ): |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
103 | yield report_problem( |
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:
90
diff
changeset
|
104 | 'collinear', |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
105 | bad_object = element, |
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:
90
diff
changeset
|
106 | min_angle = min(map(acos, cosines)), |
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:
90
diff
changeset
|
107 | max_angle = max(map(acos, cosines)), |
32
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
30
diff
changeset
|
108 | ) |
75f44d3063da
Reworked web front, problems are now sorted by category as well as line number
Santeri Piippo
parents:
30
diff
changeset
|
109 | |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
110 | manifest = { |
62
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
111 | 'tests': [ |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
112 | skew_test, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
113 | concave_test, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
114 | bowtie_test, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
115 | collinear_test, |
f0a6bf48b05e
Problem reporting revamp, program is now aware of its problem types
Teemu Piippo <teemu@hecknology.net>
parents:
32
diff
changeset
|
116 | ], |
14
d383f319f35b
transform_to_xy implemented and concave test online
Santeri Piippo
parents:
13
diff
changeset
|
117 | } |