Wed, 31 Jan 2018 15:19:31 +0200
Renamed hair test
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): | |
29 | 10 | if isinstance(line, bytes): |
41
4d87bc126368
don't crash and burn if someone sends something that's not LDraw
Santeri Piippo
parents:
29
diff
changeset
|
11 | try: |
4d87bc126368
don't crash and burn if someone sends something that's not LDraw
Santeri Piippo
parents:
29
diff
changeset
|
12 | line = line.decode() |
4d87bc126368
don't crash and burn if someone sends something that's not LDraw
Santeri Piippo
parents:
29
diff
changeset
|
13 | except UnicodeDecodeError: |
4d87bc126368
don't crash and burn if someone sends something that's not LDraw
Santeri Piippo
parents:
29
diff
changeset
|
14 | raise BadLdrawLine("bad unicode") |
2 | 15 | line = line.strip() |
16 | if not line: | |
19 | 17 | return linetypes.EmptyLine() |
2 | 18 | elif line == '0': |
19 | 19 | return linetypes.Comment('') |
2 | 20 | elif line.startswith('0 '): |
19 | 21 | return linetypes.Comment(line[2:].strip()) |
2 | 22 | elif line.startswith('1 '): |
19 | 23 | return parse_ldraw_subfile_reference(line) |
2 | 24 | elif line.startswith('2 '): |
19 | 25 | return parse_ldraw_line(line) |
2 | 26 | elif line.startswith('3 '): |
19 | 27 | return parse_ldraw_triangle(line) |
2 | 28 | elif line.startswith('4 '): |
19 | 29 | return parse_ldraw_quadrilateral(line) |
2 | 30 | elif line.startswith('5 '): |
19 | 31 | return parse_ldraw_contour(line) |
2 | 32 | else: |
33 | raise BadLdrawLine('unknown line type') | |
34 | ||
35 | def parse_ldraw_subfile_reference(line): | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
2
diff
changeset
|
36 | pattern = r'^1\s+([^ ]+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' |
2 | 37 | match = re.search(pattern, line) |
38 | if not match: | |
39 | raise BadLdrawLine('unable to parse') | |
40 | groups = list(match.groups()) | |
41 | indices = { | |
4 | 42 | 'colour_index': 0, |
2 | 43 | 'anchor': slice(1, 4), |
44 | 'matrix': slice(4, 13), | |
45 | 'subfile_path': 13 | |
46 | } | |
47 | try: | |
4 | 48 | colour = Colour(groups[indices['colour_index']]) |
2 | 49 | vertex_values = [float(x) for x in groups[indices['anchor']]] |
50 | matrix_values = [float(x) for x in groups[indices['matrix']]] | |
51 | except ValueError: | |
52 | raise BadLdrawLine('bad numeric values') | |
53 | return linetypes.SubfileReference( | |
4 | 54 | colour = colour, |
2 | 55 | anchor = Vertex(*vertex_values), |
6
6da1e81c5652
Added code to compute areas of triangles and quadrilaterals
Santeri Piippo
parents:
4
diff
changeset
|
56 | matrix = Matrix3x3(matrix_values), |
2 | 57 | subfile_path = groups[indices['subfile_path']] |
58 | ) | |
59 | ||
60 | def generic_parse_polygon(line, *, type_code, vertex_count): | |
61 | pattern = r'^' \ | |
62 | + str(type_code) \ | |
3
1dc58f44d556
Can now write dat files, added direct color handling
Santeri Piippo
parents:
2
diff
changeset
|
63 | + '\s+([^ ]+)' \ |
2 | 64 | + r'\s+([^ ]+)' * (vertex_count * 3) \ |
65 | + r'\s*$' | |
66 | match = re.search(pattern, line) | |
67 | if not match: | |
68 | raise BadLdrawLine(str.format('cannot parse type-{} line', type_code)) | |
69 | vertices = [] | |
70 | for vertex_index in range(vertex_count): | |
71 | slice_begin = 1 + vertex_index * 3 | |
72 | slice_end = 1 + (vertex_index + 1) * 3 | |
73 | coordinates = match.groups()[slice_begin:slice_end] | |
74 | assert(len(coordinates) == 3) | |
75 | try: | |
76 | coordinates = [float(x) for x in coordinates] | |
77 | except ValueError: | |
78 | raise BadLdrawLine('bad numeric values') | |
79 | vertices.append(Vertex(*coordinates)) | |
80 | return { | |
4 | 81 | 'colour': Colour(match.group(1)), |
2 | 82 | 'vertices': vertices, |
83 | } | |
84 | ||
85 | def parse_ldraw_line(line): | |
86 | parse_result = generic_parse_polygon(line, type_code = 2, vertex_count = 2) | |
87 | return linetypes.LineSegment( | |
4 | 88 | colour = parse_result['colour'], |
2 | 89 | geometry = LineSegment(*parse_result['vertices']), |
90 | ) | |
91 | ||
92 | def parse_ldraw_triangle(line): | |
93 | parse_result = generic_parse_polygon(line, type_code = 3, vertex_count = 3) | |
94 | return linetypes.Triangle( | |
4 | 95 | colour = parse_result['colour'], |
2 | 96 | geometry = Polygon(parse_result['vertices']), |
97 | ) | |
98 | ||
99 | def parse_ldraw_quadrilateral(line): | |
100 | parse_result = generic_parse_polygon(line, type_code = 4, vertex_count = 4) | |
101 | return linetypes.Quadrilateral( | |
4 | 102 | colour = parse_result['colour'], |
2 | 103 | geometry = Polygon(parse_result['vertices']), |
104 | ) | |
105 | ||
106 | def parse_ldraw_contour(line): | |
107 | parse_result = generic_parse_polygon(line, type_code = 5, vertex_count = 4) | |
108 | return linetypes.Contour( | |
4 | 109 | colour = parse_result['colour'], |
2 | 110 | geometry = LineSegment(*parse_result['vertices'][0:2]), |
111 | control_points = parse_result['vertices'][2:], | |
112 | ) |