100 primitive = primitive, |
100 primitive = primitive, |
101 axes = interesting_axes, |
101 axes = interesting_axes, |
102 scaling = scaling, |
102 scaling = scaling, |
103 ) |
103 ) |
104 |
104 |
|
105 def subfile_references_with_invertnext(model): |
|
106 import linetypes |
|
107 has_invertnext = False |
|
108 for element in model.body: |
|
109 if isinstance(element, linetypes.MetaCommand) \ |
|
110 and element.text == 'BFC INVERTNEXT': |
|
111 has_invertnext = True |
|
112 else: |
|
113 if isinstance(element, linetypes.SubfileReference): |
|
114 yield element, has_invertnext |
|
115 has_invertnext = False |
|
116 |
105 @problem_type('cyclical-reference', |
117 @problem_type('cyclical-reference', |
106 severity = 'hold', |
118 severity = 'hold', |
107 message = lambda chain: |
119 message = lambda chain: |
108 str.format('cyclical subfile dependency: {chain}', |
120 str.format('cyclical subfile dependency: {chain}', |
109 **locals(), |
121 **locals(), |
130 'subfile unnecessarily scaled in the {dims} ({scaling})', |
142 'subfile unnecessarily scaled in the {dims} ({scaling})', |
131 dims = dimensions_description(scaled_flat_dimensions), |
143 dims = dimensions_description(scaled_flat_dimensions), |
132 scaling = scaling_description(scaling_vector), |
144 scaling = scaling_description(scaling_vector), |
133 ), |
145 ), |
134 ) |
146 ) |
|
147 @problem_type('unnecessary-invertnext', |
|
148 severity = 'warning', |
|
149 message = 'flat subfile unnecessarily inverted using BFC INVERTNEXT' |
|
150 ) |
135 def dependent_subfile_tests(model): |
151 def dependent_subfile_tests(model): |
136 ''' |
152 ''' |
137 Tests subfile references for such qualities that are dependent on the |
153 Tests subfile references for such qualities that are dependent on the |
138 actual contents of the subfiles. Checks whether moved-to files are used. |
154 actual contents of the subfiles. Checks whether moved-to files are used. |
139 Checks whether flat subfiles are scaled in the flat direction. |
155 Checks whether flat subfiles are scaled in the flat direction. |
140 ''' |
156 ''' |
141 import filecache |
157 import filecache |
142 cache = filecache.SubfileCache(model.ldraw_directories) |
158 cache = filecache.SubfileCache(model.ldraw_directories) |
143 failed_subfiles = set() |
159 failed_subfiles = set() |
144 for subfile_reference in model.subfile_references: |
160 for subfile_reference, has_invertnext in subfile_references_with_invertnext(model): |
145 path = subfile_reference.subfile_path.lower() |
161 path = subfile_reference.subfile_path.lower() |
146 if path in failed_subfiles: |
162 if path in failed_subfiles: |
147 # Already proven to be a bad apple, don't complain twice |
163 # Already proven to be a bad apple, don't complain twice |
148 pass |
164 pass |
149 else: |
165 else: |
163 path = path, |
179 path = path, |
164 problem_text = subfile.problem, |
180 problem_text = subfile.problem, |
165 ) |
181 ) |
166 failed_subfiles.add(path) |
182 failed_subfiles.add(path) |
167 else: |
183 else: |
|
184 # Test for use of moved-to files |
168 import re |
185 import re |
169 match = re.search(r'^\~Moved(?: to (\w+))?$', subfile.description) |
186 match = re.search(r'^\~Moved(?: to (\w+))?$', subfile.description) |
170 if match: |
187 if match: |
171 yield report_problem( |
188 yield report_problem( |
172 'moved-file-used', |
189 'moved-file-used', |
173 bad_object = subfile_reference, |
190 bad_object = subfile_reference, |
174 moved_file = path, |
191 moved_file = path, |
175 new_file = match.group(1), |
192 new_file = match.group(1), |
176 ) |
193 ) |
|
194 # Test for scaling in flat direction |
177 scaling_vector = subfile_reference.matrix.scaling_vector() |
195 scaling_vector = subfile_reference.matrix.scaling_vector() |
178 scaled_dimensions = { |
196 scaled_dimensions = { |
179 dimension |
197 dimension |
180 for dimension in subfile.flatness |
198 for dimension in subfile.flatness |
181 if not math.isclose( |
199 if not math.isclose( |
189 yield report_problem( |
207 yield report_problem( |
190 'unnecessary-scaling', |
208 'unnecessary-scaling', |
191 bad_object = subfile_reference, |
209 bad_object = subfile_reference, |
192 scaled_flat_dimensions = scaled_flat_dimensions, |
210 scaled_flat_dimensions = scaled_flat_dimensions, |
193 scaling_vector = scaling_vector, |
211 scaling_vector = scaling_vector, |
|
212 ) |
|
213 # Test whether a flat subfile is inverted using invertnext |
|
214 if has_invertnext and subfile.flatness: |
|
215 yield report_problem( |
|
216 'unnecessary-invertnext', |
|
217 bad_object = subfile_reference, |
194 ) |
218 ) |
195 |
219 |
196 def dimensions_description(dimensions): |
220 def dimensions_description(dimensions): |
197 if isinstance(dimensions, str): |
221 if isinstance(dimensions, str): |
198 return dimensions |
222 return dimensions |