1 from testsuite import error |
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) |
2 |
11 |
3 def determinant_test(model): |
12 def determinant_test(model): |
4 yield from [ |
13 yield from ( |
5 error(subfile_reference, 'zero-determinant') |
14 error(subfile_reference, 'zero-determinant') |
6 for subfile_reference in model.subfile_references |
15 for subfile_reference in model.subfile_references |
7 if abs(subfile_reference.matrix.determinant() - 0) < 1e-15 |
16 if abs(subfile_reference.matrix.determinant() - 0) < 1e-15 |
8 ] |
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) |
9 |
75 |
10 manifest = { |
76 manifest = { |
11 'tests': { |
77 'tests': { |
12 'determinant': determinant_test, |
78 'determinant': determinant_test, |
|
79 'scaling-legality': scaling_legality_test, |
13 }, |
80 }, |
14 'messages': { |
81 'messages': { |
15 'zero-determinant': 'matrix determinant is zero ' |
82 'zero-determinant': 'matrix determinant is zero ' |
16 '(row or column all zero)', |
83 '(row or column all zero)', |
|
84 'illegal-scaling': lambda primitive, scaling, axes: |
|
85 str.format('scaling of unscalable primitive {} ({})', |
|
86 primitive, |
|
87 scaling_description(scaling, axes), |
|
88 ), |
17 }, |
89 }, |
18 } |
90 } |