Mon, 22 Jan 2018 21:04:53 +0200
added check for invalid colours
24 | 1 | from testsuite import warning, error |
2 | from geometry import * | |
3 | from os.path import dirname | |
4 | from pathlib import Path | |
5 | from configparser import ConfigParser | |
6 | ini_path = Path(dirname(__file__)) / 'library-standards.ini' | |
7 | library_standards = ConfigParser() | |
8 | ||
9 | with open(ini_path) as file: | |
10 | library_standards.read_file(file) | |
23 | 11 | |
12 | def determinant_test(model): | |
24 | 13 | yield from ( |
23 | 14 | error(subfile_reference, 'zero-determinant') |
15 | for subfile_reference in model.subfile_references | |
16 | if abs(subfile_reference.matrix.determinant() - 0) < 1e-15 | |
24 | 17 | ) |
18 | ||
19 | def scaling_description(scaling, axes = 'xyz'): | |
20 | ''' | |
21 | Returns a pretty description of a scaling vector. The axes parameter | |
22 | controls what axes are printed and can be used to filter away | |
23 | uninteresting values. | |
24 | ''' | |
25 | return ', '.join( | |
26 | str.format('{} = {}', letter, getattr(scaling, letter)) | |
27 | for letter in axes | |
28 | ) | |
29 | ||
30 | def check_scaling(scaling, axes): | |
31 | ''' Returns whether all given axes on the given scaling vector are 1. ''' | |
32 | return all( | |
33 | abs(getattr(scaling, axis) - 1) < 1e-5 | |
34 | for axis in axes | |
35 | ) | |
36 | ||
37 | # Restriction to checking function mapping. | |
38 | restriction_tests = { | |
39 | 'no scaling': lambda scaling: check_scaling(scaling, 'xyz'), | |
40 | 'y-scaling only': lambda scaling: check_scaling(scaling, 'xz'), | |
41 | 'stud3-like scaling': lambda scaling: all([ | |
42 | check_scaling(scaling, 'xz'), | |
43 | # check if y-scaling is 1 or -1 | |
44 | abs(abs(scaling.y) - 1) < 1e-5, | |
45 | ]), | |
46 | } | |
47 | ||
48 | def scaling_legality_test(model): | |
49 | from fnmatch import fnmatch | |
50 | scaling_restrictions = library_standards['scaling restrictions'] | |
51 | for subfile_reference in model.subfile_references: | |
52 | primitive = subfile_reference.subfile_path.lower() | |
53 | scaling = subfile_reference.matrix.scaling_vector() | |
54 | # Find all restrictions that apply to this subfile reference. | |
55 | restrictions = { | |
56 | restriction | |
57 | for pattern, restriction in scaling_restrictions.items() | |
58 | if fnmatch(primitive, pattern) | |
59 | } | |
60 | # Check restrictions against the subfile. If any restrictions were | |
61 | # found then the scaling vector must pass at least one of them. | |
62 | if restrictions and not any( | |
63 | restriction_tests[restriction](scaling) | |
64 | for restriction in restrictions | |
65 | ): | |
66 | interesting_axes = ''.join( | |
67 | axis | |
68 | for axis in 'xyz' | |
69 | if abs(getattr(scaling, axis) - 1) > 1e-5 | |
70 | ) | |
71 | yield warning(subfile_reference, 'illegal-scaling', | |
72 | primitive = primitive, | |
73 | axes = interesting_axes, | |
74 | scaling = scaling) | |
23 | 75 | |
76 | manifest = { | |
77 | 'tests': { | |
78 | 'determinant': determinant_test, | |
24 | 79 | 'scaling-legality': scaling_legality_test, |
23 | 80 | }, |
81 | 'messages': { | |
82 | 'zero-determinant': 'matrix determinant is zero ' | |
83 | '(row or column all zero)', | |
24 | 84 | 'illegal-scaling': lambda primitive, scaling, axes: |
85 | str.format('scaling of unscalable primitive {} ({})', | |
86 | primitive, | |
87 | scaling_description(scaling, axes), | |
88 | ), | |
23 | 89 | }, |
90 | } |