|
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) |