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