ldraw.py

changeset 2
50d3086070df
parent 1
5411a25cfca7
child 3
1dc58f44d556
equal deleted inserted replaced
1:5411a25cfca7 2:50d3086070df
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))

mercurial