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