Sun, 10 Dec 2017 15:45:50 +0200
Parsing function complete
#!/usr/bin/env python3 import linetypes import re from geometry import * class BadLdrawLine(Exception): pass def parse_ldraw_code(line): line = line.strip() if not line: return linetypes.EmptyLine() elif line == '0': return linetypes.Comment('') elif line.startswith('0 '): return linetypes.Comment(line[2:].strip()) elif line.startswith('1 '): return parse_ldraw_subfile_reference(line) elif line.startswith('2 '): return parse_ldraw_line(line) elif line.startswith('3 '): return parse_ldraw_triangle(line) elif line.startswith('4 '): return parse_ldraw_quadrilateral(line) elif line.startswith('5 '): return parse_ldraw_contour(line) else: raise BadLdrawLine('unknown line type') def parse_ldraw_subfile_reference(line): pattern = r'^1\s+(\d+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' match = re.search(pattern, line) if not match: raise BadLdrawLine('unable to parse') groups = list(match.groups()) indices = { 'color': 0, 'anchor': slice(1, 4), 'matrix': slice(4, 13), 'subfile_path': 13 } try: color = int(groups[indices['color']]) vertex_values = [float(x) for x in groups[indices['anchor']]] matrix_values = [float(x) for x in groups[indices['matrix']]] except ValueError: raise BadLdrawLine('bad numeric values') return linetypes.SubfileReference( color = color, anchor = Vertex(*vertex_values), matrix = TransformationMatrix(matrix_values), subfile_path = groups[indices['subfile_path']] ) def generic_parse_polygon(line, *, type_code, vertex_count): pattern = r'^' \ + str(type_code) \ + '\s+(\d+)' \ + r'\s+([^ ]+)' * (vertex_count * 3) \ + r'\s*$' match = re.search(pattern, line) if not match: raise BadLdrawLine(str.format('cannot parse type-{} line', type_code)) vertices = [] for vertex_index in range(vertex_count): slice_begin = 1 + vertex_index * 3 slice_end = 1 + (vertex_index + 1) * 3 coordinates = match.groups()[slice_begin:slice_end] assert(len(coordinates) == 3) try: coordinates = [float(x) for x in coordinates] except ValueError: raise BadLdrawLine('bad numeric values') vertices.append(Vertex(*coordinates)) return { 'color': int(match.group(1)), 'vertices': vertices, } def parse_ldraw_line(line): parse_result = generic_parse_polygon(line, type_code = 2, vertex_count = 2) return linetypes.LineSegment( color = parse_result['color'], geometry = LineSegment(*parse_result['vertices']), ) def parse_ldraw_triangle(line): parse_result = generic_parse_polygon(line, type_code = 3, vertex_count = 3) return linetypes.Triangle( color = parse_result['color'], geometry = Polygon(parse_result['vertices']), ) def parse_ldraw_quadrilateral(line): parse_result = generic_parse_polygon(line, type_code = 4, vertex_count = 4) return linetypes.Quadrilateral( color = parse_result['color'], geometry = Polygon(parse_result['vertices']), ) def parse_ldraw_contour(line): parse_result = generic_parse_polygon(line, type_code = 5, vertex_count = 4) return linetypes.Contour( color = parse_result['color'], geometry = LineSegment(*parse_result['vertices'][0:2]), control_points = parse_result['vertices'][2:], ) def read_ldraw(file, *, libraries): result = list() for line in file: result.append(parse_ldraw_code(line)) return result if __name__ == '__main__': from sys import argv libraries = [{'path': '/home/teemu/ldraw', 'role': 'official'}] with open(argv[1], 'r') as file: model = read_ldraw(file, libraries = libraries) from pprint import pprint pprint(model)