1 import linetypes |
1 import linetypes |
2 import re |
2 import re |
3 from geometry import * |
3 from geometry import * |
4 from colours import Colour |
4 from colours import Colour |
5 from testsuite import error |
5 from testsuite import error |
|
6 import header |
6 |
7 |
7 class BadLdrawLine(Exception): |
8 class BadLdrawLine(Exception): |
8 pass |
9 pass |
|
10 |
|
11 class Model: |
|
12 def __init__(self, header, body, *, ldraw_directories, header_size = 0): |
|
13 self.header = header |
|
14 self.body = body |
|
15 self.header_size = header_size |
|
16 self.ldraw_directories = ldraw_directories |
|
17 def filter_by_type(self, type): |
|
18 yield from [ |
|
19 element |
|
20 for element in self.body |
|
21 if isinstance(element, type) |
|
22 ] |
|
23 @property |
|
24 def subfile_references(self): |
|
25 yield from self.filter_by_type(linetypes.SubfileReference) |
|
26 @property |
|
27 def line_segments(self): |
|
28 yield from self.filter_by_type(linetypes.LineSegment) |
|
29 @property |
|
30 def triangles(self): |
|
31 yield from self.filter_by_type(linetypes.Triangle) |
|
32 @property |
|
33 def quadrilaterals(self): |
|
34 yield from self.filter_by_type(linetypes.Quadrilateral) |
|
35 @property |
|
36 def has_header(self): |
|
37 return self.header and not isinstance(self.header, header.BadHeader) |
|
38 |
|
39 def model_vertices( |
|
40 model, |
|
41 transformation_matrix = None, |
|
42 file_cache = None, |
|
43 ): |
|
44 if transformation_matrix is None: |
|
45 transformation_matrix = complete_matrix(Matrix3x3(), Vertex(0, 0, 0)) |
|
46 if file_cache is None: |
|
47 import filecache |
|
48 file_cache = filecache.SubfileCache(model.ldraw_directories) |
|
49 for element in model.body: |
|
50 if isinstance(element, linetypes.BasePolygon): |
|
51 for point in element.geometry.vertices: |
|
52 yield point @ transformation_matrix |
|
53 if isinstance(element, linetypes.ConditionalLine): |
|
54 for point in element.control_points: |
|
55 yield point @ transformation_matrix |
|
56 if isinstance(element, linetypes.SubfileReference): |
|
57 subfile = file_cache.prepare_file(element.subfile_path) |
|
58 for point in subfile.vertices: |
|
59 matrix_4x4 = complete_matrix(element.matrix, element.anchor) |
|
60 point @= matrix_4x4 |
|
61 yield point @ transformation_matrix |
|
62 |
|
63 def read_ldraw(file, *, ldraw_directories, name = ''): |
|
64 model_body = [ |
|
65 parse_ldraw_code(line) |
|
66 for line in file |
|
67 ] |
|
68 headerparser = header.HeaderParser() |
|
69 try: |
|
70 header_parse_result = headerparser.parse(model_body) |
|
71 header_object = header_parse_result['header'] |
|
72 end = header_parse_result['end-index'] |
|
73 except header.HeaderError as error: |
|
74 header_object = header.BadHeader(error.index, error.reason) |
|
75 end = 0 |
|
76 model = Model( |
|
77 header = header_object, |
|
78 body = model_body, |
|
79 header_size = end, |
|
80 ldraw_directories = ldraw_directories) |
|
81 model.name = name |
|
82 return model |
9 |
83 |
10 def parse_ldraw_code(line): |
84 def parse_ldraw_code(line): |
11 try: |
85 try: |
12 if isinstance(line, bytes): |
86 if isinstance(line, bytes): |
13 line = line.decode() |
87 line = line.decode() |