Sun, 10 Dec 2017 15:37:26 +0200
Initial commit with half-done parsing function
0 | 1 | #!/usr/bin/env python3 |
2 | import linetypes | |
3 | import re | |
4 | from geometry import * | |
5 | ||
6 | class BadLdrawLine(Exception): | |
7 | pass | |
8 | ||
9 | def parse_ldraw_code(line): | |
10 | line = line.strip() | |
11 | if not line: | |
12 | return linetypes.EmptyLine() | |
13 | if line == '0': | |
14 | return linetypes.Comment('') | |
15 | if line.startswith('0 '): | |
16 | return linetypes.Comment(line[2:].strip()) | |
17 | if line.startswith('1 '): | |
18 | return parse_ldraw_subfile_reference(line) | |
19 | if line.startswith('2 '): | |
20 | return parse_ldraw_line(line) | |
21 | ... | |
22 | ||
23 | def parse_ldraw_subfile_reference(line): | |
24 | pattern = r'^1\s+(\d+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' | |
25 | match = re.search(pattern, line) | |
26 | if not match: | |
27 | raise BadLdrawLine('unable to parse') | |
28 | groups = list(match.groups()) | |
29 | indices = { | |
30 | 'color': 0, | |
31 | 'anchor': slice(1, 4), | |
32 | 'matrix': slice(4, 13), | |
33 | 'subfile_path': 13 | |
34 | } | |
35 | try: | |
36 | color = int(groups[indices['color']]) | |
37 | vertex_values = [float(x) for x in groups[indices['anchor']]] | |
38 | matrix_values = [float(x) for x in groups[indices['matrix']]] | |
39 | except ValueError: | |
40 | raise BadLdrawLine('bad numeric values') | |
41 | return linetypes.SubfileReference( | |
42 | color = color, | |
43 | anchor = Vertex(*vertex_values), | |
44 | matrix = TransformationMatrix(matrix_values), | |
45 | subfile_path = groups[indices['subfile_path']] | |
46 | ) | |
47 | ||
48 | def generic_parse_polygon(line, *, type_code, vertex_count): | |
49 | pattern = r'^' \ | |
50 | + str(type_code) \ | |
51 | + '\s+(\d+)' \ | |
52 | + r'\s+([^ ]+)' * (vertex_count * 3) \ | |
53 | + r'\s*$' | |
54 | match = re.search(pattern, line) | |
55 | if not match: | |
56 | raise BadLdrawLine(str.format('cannot parse type-{} line', type_code)) | |
57 | vertices = [] | |
58 | for vertex_index in range(vertex_count): | |
59 | slice_begin = 1 + vertex_index * 3 | |
60 | slice_end = 1 + (vertex_index + 1) * 3 | |
61 | coordinates = match.groups()[slice_begin:slice_end] | |
62 | assert(len(coordinates) == 3) | |
63 | try: | |
64 | coordinates = [float(x) for x in coordinates] | |
65 | except ValueError: | |
66 | raise BadLdrawLine('bad numeric values') | |
67 | vertices.append(Vertex(*coordinates)) | |
68 | return { | |
69 | 'color': int(match.group(1)), | |
70 | 'vertices': vertices, | |
71 | } | |
72 | ||
73 | def parse_ldraw_line(line): | |
74 | parse_result = generic_parse_polygon(line, type_code = 2, vertex_count = 2) | |
75 | line_segment = LineSegment(*parse_result['vertices']) | |
76 | return linetypes.LineSegment( | |
77 | color = parse_result['color'], | |
78 | geometry = line_segment) | |
79 | ||
80 | def read_ldraw(file, *, libraries): | |
81 | result = list() | |
82 | for line in file: | |
83 | result.append(parse_ldraw_code(line)) | |
84 | return result | |
85 | ||
86 | if __name__ == '__main__': | |
87 | from sys import argv | |
88 | libraries = [{'path': '/home/teemu/ldraw', 'role': 'official'}] | |
89 | with open(argv[1], 'r') as file: | |
90 | model = read_ldraw(file, libraries = libraries) | |
91 | from pprint import pprint | |
92 | pprint(model) |