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 | } |