tests/quadrilaterals.py

changeset 103
662de6b8cfc2
parent 90
6ae063fd27dc
child 106
d93ef722bba6
equal deleted inserted replaced
102:952e2a9a669b 103:662de6b8cfc2
23 yield report_problem('concave', bad_object = quadrilateral) 23 yield report_problem('concave', bad_object = quadrilateral)
24 24
25 @problem_type('skew-major', 25 @problem_type('skew-major',
26 severity = 'hold', 26 severity = 'hold',
27 message = lambda skew_angle: 27 message = lambda skew_angle:
28 str.format('skew quadrilateral (plane angle {})', 28 str.format('skew (non-coplanar) quadrilateral (plane angle {})',
29 degree_rep(skew_angle), 29 degree_rep(skew_angle),
30 ), 30 ),
31 ) 31 )
32 @problem_type('skew-minor', 32 @problem_type('skew-minor',
33 severity = 'warning', 33 severity = 'warning',
34 message = lambda skew_angle: 34 message = lambda skew_angle:
35 str.format('slightly skew quadrilateral (plane angle {})', 35 str.format('slightly skew (non-coplanar) quadrilateral (plane angle {})',
36 degree_rep(skew_angle), 36 degree_rep(skew_angle),
37 ), 37 ),
38 ) 38 )
39 def skew_test(model): 39 def skew_test(model):
40 ''' Checks that all quadrilaterals are coplanar. ''' 40 ''' Checks that all quadrilaterals are coplanar. '''
75 'self-intersecting', 75 'self-intersecting',
76 bad_object = quadrilateral, 76 bad_object = quadrilateral,
77 ) 77 )
78 break 78 break
79 79
80 @problem_type('collinear', severity = 'hold', message = 'collinear polygon') 80 @problem_type('collinear',
81 severity = 'hold',
82 message = lambda min_angle, max_angle: str.format(
83 'collinear polygon (smallest interior angle {min_angle}, largest {max_angle})',
84 min_angle = degree_rep(min_angle),
85 max_angle = degree_rep(max_angle),
86 ),
87 )
81 def collinear_test(model): 88 def collinear_test(model):
89 from math import radians, cos, acos
90 # according to the LDraw spec, all interior angles must be
91 # between 0.025 degrees and 179.9 degrees. Note that between 0 and pi,
92 # cos(x) is a downwards curve, so the minimum cosine is for the maximum
93 # angle.
94 min_cosine = cos(radians(179.9))
95 max_cosine = cos(radians(0.025))
82 for element in model.body: 96 for element in model.body:
83 if hasattr(element, 'geometry') and len(element.geometry.vertices) >= 3: 97 if hasattr(element, 'geometry') and len(element.geometry.vertices) >= 3:
84 for a, b, c in pairs(element.geometry.vertices, count = 3): 98 cosines = list(element.geometry.angle_cosines())
85 if cross_product(b - a, c - a).length() < 1e-5: 99 if any(
86 yield report_problem('collinear', bad_object = element) 100 not(min_cosine < cosine < max_cosine)
87 break 101 for cosine in cosines
88 102 ):
89 @problem_type('hairline-polygon',
90 severity = 'warning',
91 message = lambda smallest_angle: str.format(
92 'hairline polygon (smallest angle {})',
93 degree_rep(smallest_angle),
94 ),
95 )
96 def hairline_test(model):
97 for element in model.body:
98 if hasattr(element, 'geometry') and len(element.geometry.vertices) >= 3:
99 smallest_angle = element.geometry.smallest_angle
100 if smallest_angle < radians(0.5):
101 yield report_problem( 103 yield report_problem(
102 'hairline-polygon', 104 'collinear',
103 bad_object = element, 105 bad_object = element,
104 smallest_angle = smallest_angle, 106 min_angle = min(map(acos, cosines)),
107 max_angle = max(map(acos, cosines)),
105 ) 108 )
106 109
107 manifest = { 110 manifest = {
108 'tests': [ 111 'tests': [
109 skew_test, 112 skew_test,
110 concave_test, 113 concave_test,
111 bowtie_test, 114 bowtie_test,
112 collinear_test, 115 collinear_test,
113 hairline_test,
114 ], 116 ],
115 } 117 }

mercurial