Sat, 25 May 2019 09:41:33 +0200
added work on header check
2 | 1 | import linetypes |
2 | import re | |
3 | from geometry import * | |
8 | 4 | from colours import Colour |
47
4da025d0b283
added work on header check
Teemu Piippo <teemu@hecknology.net>
parents:
38
diff
changeset
|
5 | from testsuite import error |
2 | 6 | |
7 | class BadLdrawLine(Exception): | |
8 | pass | |
9 | ||
10 | def parse_ldraw_code(line): | |
38
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
11 | try: |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
12 | if isinstance(line, bytes): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
13 | line = line.decode() |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
14 | line = line.strip() |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
15 | if not line: |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
16 | return linetypes.EmptyLine() |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
17 | elif line == '0': |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
18 | return linetypes.MetaCommand('') |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
19 | elif line.startswith('0 '): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
20 | return parse_ldraw_meta_line(line) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
21 | elif line.startswith('1 '): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
22 | return parse_ldraw_subfile_reference(line) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
23 | elif line.startswith('2 '): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
24 | return parse_ldraw_line(line) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
25 | elif line.startswith('3 '): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
26 | return parse_ldraw_triangle(line) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
27 | elif line.startswith('4 '): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
28 | return parse_ldraw_quadrilateral(line) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
29 | elif line.startswith('5 '): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
30 | return parse_ldraw_conditional_line(line) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
31 | else: |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
32 | raise BadLdrawLine('unknown line type') |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
33 | except BadLdrawLine as error: |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
34 | return linetypes.Error(line, str(error)) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
35 | |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
36 | def parse_ldraw_meta_line(line): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
37 | if line.startswith('0 //'): |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
38 | return linetypes.Comment(line[4:]) |
2 | 39 | else: |
38
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
40 | return linetypes.MetaCommand(line[2:]) |
2 | 41 | |
42 | def parse_ldraw_subfile_reference(line): | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
2
diff
changeset
|
43 | pattern = r'^1\s+([^ ]+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' |
2 | 44 | match = re.search(pattern, line) |
45 | if not match: | |
46 | raise BadLdrawLine('unable to parse') | |
47 | groups = list(match.groups()) | |
48 | indices = { | |
4 | 49 | 'colour_index': 0, |
2 | 50 | 'anchor': slice(1, 4), |
51 | 'matrix': slice(4, 13), | |
52 | 'subfile_path': 13 | |
53 | } | |
54 | try: | |
4 | 55 | colour = Colour(groups[indices['colour_index']]) |
2 | 56 | vertex_values = [float(x) for x in groups[indices['anchor']]] |
57 | matrix_values = [float(x) for x in groups[indices['matrix']]] | |
58 | except ValueError: | |
59 | raise BadLdrawLine('bad numeric values') | |
60 | return linetypes.SubfileReference( | |
4 | 61 | colour = colour, |
2 | 62 | anchor = Vertex(*vertex_values), |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
4
diff
changeset
|
63 | matrix = Matrix3x3(matrix_values), |
2 | 64 | subfile_path = groups[indices['subfile_path']] |
65 | ) | |
66 | ||
67 | def generic_parse_polygon(line, *, type_code, vertex_count): | |
35 | 68 | pattern = r'^' # matches the start of line |
69 | pattern += str(type_code) # matches the type code | |
70 | pattern += '\s+([^ ]+)' # matches the colour | |
71 | pattern += r'\s+([^ ]+)' * (vertex_count * 3) # matches the vertices | |
72 | pattern += r'\s*$' # matches any trailing space | |
2 | 73 | match = re.search(pattern, line) |
74 | if not match: | |
75 | raise BadLdrawLine(str.format('cannot parse type-{} line', type_code)) | |
76 | vertices = [] | |
77 | for vertex_index in range(vertex_count): | |
78 | slice_begin = 1 + vertex_index * 3 | |
79 | slice_end = 1 + (vertex_index + 1) * 3 | |
80 | coordinates = match.groups()[slice_begin:slice_end] | |
81 | assert(len(coordinates) == 3) | |
82 | try: | |
83 | coordinates = [float(x) for x in coordinates] | |
84 | except ValueError: | |
85 | raise BadLdrawLine('bad numeric values') | |
86 | vertices.append(Vertex(*coordinates)) | |
38
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
87 | try: |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
88 | colour = int(match.group(1), 0) |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
89 | except ValueError: |
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
90 | raise BadLdrawLine('invalid syntax for colour: ' + repr(match.group(1))) |
2 | 91 | return { |
38
66c9591b733d
added proper handling of syntax errors
Teemu Piippo <teemu@hecknology.net>
parents:
35
diff
changeset
|
92 | 'colour': Colour(colour), |
2 | 93 | 'vertices': vertices, |
94 | } | |
95 | ||
96 | def parse_ldraw_line(line): | |
97 | parse_result = generic_parse_polygon(line, type_code = 2, vertex_count = 2) | |
98 | return linetypes.LineSegment( | |
4 | 99 | colour = parse_result['colour'], |
2 | 100 | geometry = LineSegment(*parse_result['vertices']), |
101 | ) | |
102 | ||
103 | def parse_ldraw_triangle(line): | |
104 | parse_result = generic_parse_polygon(line, type_code = 3, vertex_count = 3) | |
105 | return linetypes.Triangle( | |
4 | 106 | colour = parse_result['colour'], |
2 | 107 | geometry = Polygon(parse_result['vertices']), |
108 | ) | |
109 | ||
110 | def parse_ldraw_quadrilateral(line): | |
111 | parse_result = generic_parse_polygon(line, type_code = 4, vertex_count = 4) | |
112 | return linetypes.Quadrilateral( | |
4 | 113 | colour = parse_result['colour'], |
2 | 114 | geometry = Polygon(parse_result['vertices']), |
115 | ) | |
116 | ||
35 | 117 | def parse_ldraw_conditional_line(line): |
2 | 118 | parse_result = generic_parse_polygon(line, type_code = 5, vertex_count = 4) |
35 | 119 | return linetypes.ConditionalLine( |
4 | 120 | colour = parse_result['colour'], |
2 | 121 | geometry = LineSegment(*parse_result['vertices'][0:2]), |
122 | control_points = parse_result['vertices'][2:], | |
123 | ) |