parse.py

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

mercurial