6 from parse import parse_ldraw_code |
6 from parse import parse_ldraw_code |
7 from colours import load_colours |
7 from colours import load_colours |
8 from geometry import * |
8 from geometry import * |
9 from pathlib import Path |
9 from pathlib import Path |
10 import linetypes |
10 import linetypes |
|
11 import header |
11 |
12 |
12 from os.path import realpath |
13 from os.path import realpath |
13 script_directory = Path(realpath(__file__)).parent |
14 script_directory = Path(realpath(__file__)).parent |
14 |
15 |
15 def load_config(filename): |
16 def load_config(filename): |
27 def read_ldraw(file, *, name = '', config): |
28 def read_ldraw(file, *, name = '', config): |
28 model_body = [ |
29 model_body = [ |
29 parse_ldraw_code(line) |
30 parse_ldraw_code(line) |
30 for line in file |
31 for line in file |
31 ] |
32 ] |
32 model = Model(body = model_body) |
33 headerparser = header.HeaderParser() |
|
34 try: |
|
35 header_parse_result = headerparser.parse(model_body) |
|
36 header_object = header_parse_result['header'] |
|
37 end = header_parse_result['end-index'] |
|
38 except header.HeaderError as error: |
|
39 header_object = header.BadHeader(error.index, error.reason) |
|
40 end = 0 |
|
41 model = Model( |
|
42 header = header_object, |
|
43 body = model_body, |
|
44 header_size = end) |
33 model.name = name |
45 model.name = name |
34 return model |
46 return model |
35 |
47 |
36 def library_paths(config): |
48 def library_paths(config): |
37 for library_path_string in config['libraries']: |
49 for library_path_string in config['libraries']: |
69 for path in ['LDConfig.ldr', 'ldconfig.ldr'] |
81 for path in ['LDConfig.ldr', 'ldconfig.ldr'] |
70 if (library_path / path).is_file() |
82 if (library_path / path).is_file() |
71 ] |
83 ] |
72 |
84 |
73 class Model: |
85 class Model: |
74 def __init__(self, body): |
86 def __init__(self, header, body, *, header_size = 0): |
|
87 self.header = header |
75 self.body = body |
88 self.body = body |
76 self.body_offset = 0 |
89 self.header_size = header_size |
77 def filter_by_type(self, type): |
90 def filter_by_type(self, type): |
78 yield from [ |
91 yield from [ |
79 element |
92 element |
80 for element in self.body |
93 for element in self.body |
81 if isinstance(element, type) |
94 if isinstance(element, type) |
90 def triangles(self): |
103 def triangles(self): |
91 yield from self.filter_by_type(linetypes.Triangle) |
104 yield from self.filter_by_type(linetypes.Triangle) |
92 @property |
105 @property |
93 def quadrilaterals(self): |
106 def quadrilaterals(self): |
94 yield from self.filter_by_type(linetypes.Quadrilateral) |
107 yield from self.filter_by_type(linetypes.Quadrilateral) |
|
108 @property |
|
109 def has_header(self): |
|
110 return self.header and not isinstance(self.header, header.BadHeader) |
95 |
111 |
96 import argparse |
112 import argparse |
97 class ListTestSuiteAction(argparse.Action): |
113 class ListTestSuiteAction(argparse.Action): |
98 def __init__(self, option_strings, dest, nargs = None, **kwargs): |
114 def __init__(self, option_strings, dest, nargs = None, **kwargs): |
99 super().__init__(option_strings, dest, nargs = 0, **kwargs) |
115 super().__init__(option_strings, dest, nargs = 0, **kwargs) |
129 file, |
145 file, |
130 name = basename(args.filename), |
146 name = basename(args.filename), |
131 config = config, |
147 config = config, |
132 ) |
148 ) |
133 if args.dump_structure: |
149 if args.dump_structure: |
|
150 print('header: ' + type(model.header).__name__) |
|
151 for key in sorted(dir(model.header)): |
|
152 if not key.startswith('__'): |
|
153 print('\t' + key + ': ' + repr(getattr(model.header, key))) |
134 for entry in model.body: |
154 for entry in model.body: |
135 print(entry) |
155 print(entry) |
136 elif args.rebuild: |
156 elif args.rebuild: |
137 for entry in model.body: |
157 for entry in model.body: |
138 print(entry.textual_representation(), end = '\r\n') |
158 print(entry.textual_representation(), end = '\r\n') |