Tue, 28 May 2019 19:11:01 +0300
added primitive CCW test
#!/usr/bin/env python3 from sys import version_info if version_info < (3, 4): raise RuntimeError('Python 3.4 or newer required') from parse import parse_ldraw_code from colours import load_colours from geometry import * from pathlib import Path import linetypes import header from os.path import realpath script_directory = Path(realpath(__file__)).parent def load_config(filename): from configobj import ConfigObj from copy import deepcopy config = ConfigObj(filename, encoding = 'UTF8') read_config = deepcopy(config) if 'libraries' not in config: config['libraries'] = ['/path/to/ldraw'] if config != read_config: config.write() check_library_paths(config) return config def read_ldraw(file, *, name = '', config): model_body = [ parse_ldraw_code(line) for line in file ] headerparser = header.HeaderParser() try: header_parse_result = headerparser.parse(model_body) header_object = header_parse_result['header'] end = header_parse_result['end-index'] except header.HeaderError as error: header_object = header.BadHeader(error.index, error.reason) end = 0 model = Model( header = header_object, body = model_body, header_size = end) model.name = name return model def library_paths(config): for library_path_string in config['libraries']: yield Path(library_path_string).expanduser() def check_library_paths(config): from sys import exit problems = False have_paths = False for library_path in library_paths(config): have_paths = True if not library_path.exists(): problems = True print(str.format( 'Library path {} does not exist', library_path, )) elif not library_path.exists(): problems = True print(str.format( 'Library path {} is not a directory', library_path, )) if not have_paths: print('No LDraw path specified') problems = True if problems: print('Please fix ldcheck.cfg') exit(1) def find_ldconfig_ldr_paths(config): for library_path in library_paths(config): yield from [ library_path / path for path in ['LDConfig.ldr', 'ldconfig.ldr'] if (library_path / path).is_file() ] class Model: def __init__(self, header, body, *, header_size = 0): self.header = header self.body = body self.header_size = header_size def filter_by_type(self, type): yield from [ element for element in self.body if isinstance(element, type) ] @property def subfile_references(self): yield from self.filter_by_type(linetypes.SubfileReference) @property def line_segments(self): yield from self.filter_by_type(linetypes.LineSegment) @property def triangles(self): yield from self.filter_by_type(linetypes.Triangle) @property def quadrilaterals(self): yield from self.filter_by_type(linetypes.Quadrilateral) @property def has_header(self): return self.header and not isinstance(self.header, header.BadHeader) import argparse class ListTestSuiteAction(argparse.Action): def __init__(self, option_strings, dest, nargs = None, **kwargs): super().__init__(option_strings, dest, nargs = 0, **kwargs) def __call__(self, *args, **kwargs): from testsuite import load_tests from sys import exit from re import sub test_suite = load_tests() for test_name in sorted(test_suite['tests'].keys()): test_function = test_suite['tests'][test_name] help = sub(r'\s+', ' ', test_function.__doc__ or '').strip() print(test_name + ': ' + help) exit(0) if __name__ == '__main__': from sys import argv parser = argparse.ArgumentParser() parser.add_argument('filename') parser.add_argument('--list', action = ListTestSuiteAction, help = 'Lists all possible checks and exit', ) parser.add_argument('--dump-structure', action = 'store_true') parser.add_argument('--rebuild', action = 'store_true') args = parser.parse_args() config = load_config('ldcheck.cfg') for ldconfig_ldr_path in find_ldconfig_ldr_paths(config): with ldconfig_ldr_path.open() as ldconfig_ldr: load_colours(ldconfig_ldr) with open(args.filename) as file: from os.path import basename model = read_ldraw( file, name = basename(args.filename), config = config, ) if args.dump_structure: print('header: ' + type(model.header).__name__) for key in sorted(dir(model.header)): if not key.startswith('__'): print('\t' + key + ': ' + repr(getattr(model.header, key))) for entry in model.body: print(entry) elif args.rebuild: for entry in model.body: print(entry.textual_representation(), end = '\r\n') else: from testsuite import load_tests, check_model, format_report test_suite = load_tests() report = check_model(model, test_suite) print(format_report(report, model, test_suite))