1 #!/usr/bin/env python3 |
1 #!/usr/bin/env python3 |
2 import linetypes |
2 from parse import parse_ldraw_code |
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 elif line == '0': |
|
14 return linetypes.Comment('') |
|
15 elif line.startswith('0 '): |
|
16 return linetypes.Comment(line[2:].strip()) |
|
17 elif line.startswith('1 '): |
|
18 return parse_ldraw_subfile_reference(line) |
|
19 elif line.startswith('2 '): |
|
20 return parse_ldraw_line(line) |
|
21 elif line.startswith('3 '): |
|
22 return parse_ldraw_triangle(line) |
|
23 elif line.startswith('4 '): |
|
24 return parse_ldraw_quadrilateral(line) |
|
25 elif line.startswith('5 '): |
|
26 return parse_ldraw_contour(line) |
|
27 else: |
|
28 raise BadLdrawLine('unknown line type') |
|
29 |
|
30 def parse_ldraw_subfile_reference(line): |
|
31 pattern = r'^1\s+(\d+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' |
|
32 match = re.search(pattern, line) |
|
33 if not match: |
|
34 raise BadLdrawLine('unable to parse') |
|
35 groups = list(match.groups()) |
|
36 indices = { |
|
37 'color': 0, |
|
38 'anchor': slice(1, 4), |
|
39 'matrix': slice(4, 13), |
|
40 'subfile_path': 13 |
|
41 } |
|
42 try: |
|
43 color = int(groups[indices['color']]) |
|
44 vertex_values = [float(x) for x in groups[indices['anchor']]] |
|
45 matrix_values = [float(x) for x in groups[indices['matrix']]] |
|
46 except ValueError: |
|
47 raise BadLdrawLine('bad numeric values') |
|
48 return linetypes.SubfileReference( |
|
49 color = color, |
|
50 anchor = Vertex(*vertex_values), |
|
51 matrix = TransformationMatrix(matrix_values), |
|
52 subfile_path = groups[indices['subfile_path']] |
|
53 ) |
|
54 |
|
55 def generic_parse_polygon(line, *, type_code, vertex_count): |
|
56 pattern = r'^' \ |
|
57 + str(type_code) \ |
|
58 + '\s+(\d+)' \ |
|
59 + r'\s+([^ ]+)' * (vertex_count * 3) \ |
|
60 + r'\s*$' |
|
61 match = re.search(pattern, line) |
|
62 if not match: |
|
63 raise BadLdrawLine(str.format('cannot parse type-{} line', type_code)) |
|
64 vertices = [] |
|
65 for vertex_index in range(vertex_count): |
|
66 slice_begin = 1 + vertex_index * 3 |
|
67 slice_end = 1 + (vertex_index + 1) * 3 |
|
68 coordinates = match.groups()[slice_begin:slice_end] |
|
69 assert(len(coordinates) == 3) |
|
70 try: |
|
71 coordinates = [float(x) for x in coordinates] |
|
72 except ValueError: |
|
73 raise BadLdrawLine('bad numeric values') |
|
74 vertices.append(Vertex(*coordinates)) |
|
75 return { |
|
76 'color': int(match.group(1)), |
|
77 'vertices': vertices, |
|
78 } |
|
79 |
|
80 def parse_ldraw_line(line): |
|
81 parse_result = generic_parse_polygon(line, type_code = 2, vertex_count = 2) |
|
82 return linetypes.LineSegment( |
|
83 color = parse_result['color'], |
|
84 geometry = LineSegment(*parse_result['vertices']), |
|
85 ) |
|
86 |
|
87 def parse_ldraw_triangle(line): |
|
88 parse_result = generic_parse_polygon(line, type_code = 3, vertex_count = 3) |
|
89 return linetypes.Triangle( |
|
90 color = parse_result['color'], |
|
91 geometry = Polygon(parse_result['vertices']), |
|
92 ) |
|
93 |
|
94 def parse_ldraw_quadrilateral(line): |
|
95 parse_result = generic_parse_polygon(line, type_code = 4, vertex_count = 4) |
|
96 return linetypes.Quadrilateral( |
|
97 color = parse_result['color'], |
|
98 geometry = Polygon(parse_result['vertices']), |
|
99 ) |
|
100 |
|
101 def parse_ldraw_contour(line): |
|
102 parse_result = generic_parse_polygon(line, type_code = 5, vertex_count = 4) |
|
103 return linetypes.Contour( |
|
104 color = parse_result['color'], |
|
105 geometry = LineSegment(*parse_result['vertices'][0:2]), |
|
106 control_points = parse_result['vertices'][2:], |
|
107 ) |
|
108 |
3 |
109 def read_ldraw(file, *, libraries): |
4 def read_ldraw(file, *, libraries): |
110 result = list() |
5 result = list() |
111 for line in file: |
6 for line in file: |
112 result.append(parse_ldraw_code(line)) |
7 result.append(parse_ldraw_code(line)) |