Mon, 11 Dec 2017 00:46:35 +0200
Can now write dat files, added direct color handling
geometry.py | file | annotate | diff | comparison | revisions | |
ldraw.py | file | annotate | diff | comparison | revisions | |
ldverify.py | file | annotate | diff | comparison | revisions | |
linetypes.py | file | annotate | diff | comparison | revisions | |
parse.py | file | annotate | diff | comparison | revisions |
--- a/geometry.py Sun Dec 10 15:46:47 2017 +0200 +++ b/geometry.py Mon Dec 11 00:46:35 2017 +0200 @@ -11,12 +11,18 @@ (self.y - other.y) ** 2 + (self.z - other.z) ** 2 ) + @property + def coordinates(self): + return self.x, self.y, self.z class LineSegment: def __init__(self, v1, v2): self.v1, self.v2 = v1, v2 def __repr__(self): return str.format('LineSegment({!r}, {!r})', self.v1, self.v2) + @property + def vertices(self): + return self.v1, self.v2 class Polygon: def __init__(self, vertices):
--- a/ldraw.py Sun Dec 10 15:46:47 2017 +0200 +++ b/ldraw.py Mon Dec 11 00:46:35 2017 +0200 @@ -1,16 +1,11 @@ -#!/usr/bin/env python3 -from parse import parse_ldraw_code - -def read_ldraw(file, *, libraries): - result = list() - for line in file: - result.append(parse_ldraw_code(line)) - return result - -if __name__ == '__main__': - from sys import argv - libraries = [{'path': '/home/teemu/ldraw', 'role': 'official'}] - with open(argv[1], 'r') as file: - model = read_ldraw(file, libraries = libraries) - from pprint import pprint - pprint(model) +class Color: + def __init__(self, index): + self.index = int(index, 0) + def __str__(self): + if self.is_direct_color(): + # write direct colors with hex codes + return '0x%07X' % self.index + else: + return str(self.index) + def is_direct_color(self): + return self.index >= 0x2000000
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ldverify.py Mon Dec 11 00:46:35 2017 +0200 @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +from parse import parse_ldraw_code + +def read_ldraw(file, *, libraries): + result = list() + for line in file: + result.append(parse_ldraw_code(line)) + return result + +if __name__ == '__main__': + from sys import argv + libraries = [{'path': '/home/teemu/ldraw', 'role': 'official'}] + with open(argv[1], 'r') as file: + model = read_ldraw(file, libraries = libraries) + for entry in model: + #print(repr(entry)) + print(entry.textual_representation().strip(), end = '\r\n')
--- a/linetypes.py Sun Dec 10 15:46:47 2017 +0200 +++ b/linetypes.py Mon Dec 11 00:46:35 2017 +0200 @@ -1,11 +1,23 @@ +def ldraw_str(value): + ' Like str() except removes unneeded ".0"-suffixes ' + rep = str(value) + if isinstance(value, float): + if rep.endswith('.0'): + rep = rep[:-2] + if rep == '-0': + rep = '0' + return rep + class EmptyLine: def __repr__(self): return 'linetypes.EmptyLine()' + def textual_representation(self): + return '' class Comment: def __init__(self, text, style = 'old'): if style == 'old' and text.startswith('//'): - self.text = text[3:].strip() + self.text = text[2:].strip() self.style = 'new' else: self.text = text @@ -15,6 +27,11 @@ text = self.text, style = self.style, ) + def textual_representation(self): + if self.style == 'old': + return '0 ' + self.text + else: + return '0 // ' + self.text class SubfileReference: def __init__(self, *, color, subfile_path, anchor, matrix): @@ -26,8 +43,17 @@ 'subfile_path = {subfile_path!r}, ' \ 'anchor = {anchor!r}, ' \ 'matrix = {matrix!r})', **self.__dict__) + def textual_representation(self): + args = [ + 1, + self.color, + *self.anchor.coordinates, + *self.matrix.values, + self.subfile_path, + ] + return ' '.join(ldraw_str(arg) for arg in args) -class LineSegment: +class BasePolygon: def __init__(self, *, color, geometry): self.color, self.geometry = color, geometry def __repr__(self): @@ -38,12 +64,23 @@ color = self.color, geometry = self.geometry, ) + def base_textual_representation(self): + args = [self.color] + for vertex in self.geometry.vertices: + args += vertex.coordinates + return ' '.join(ldraw_str(arg) for arg in args) -class Triangle(LineSegment): - pass +class LineSegment(BasePolygon): + def textual_representation(self): + return '2 ' + self.base_textual_representation() -class Quadrilateral(LineSegment): - pass +class Triangle(BasePolygon): + def textual_representation(self): + return '3 ' + self.base_textual_representation() + +class Quadrilateral(BasePolygon): + def textual_representation(self): + return '4 ' + self.base_textual_representation() class Contour(LineSegment): def __init__(self, *, color, geometry, control_points): @@ -55,3 +92,10 @@ 'color = {color!r}, ' \ 'geometry = {geometry!r}, ' \ 'control_points = {control_points!r})', **self.__dict__) + def textual_representation(self): + result = '5 ' + self.base_textual_representation() + for control_point in self.control_points: + strings = (ldraw_str(value) for value in control_point.coordinates) + result += ' ' + result += ' '.join(strings) + return result
--- a/parse.py Sun Dec 10 15:46:47 2017 +0200 +++ b/parse.py Mon Dec 11 00:46:35 2017 +0200 @@ -1,6 +1,7 @@ import linetypes import re from geometry import * +from ldraw import Color class BadLdrawLine(Exception): pass @@ -27,19 +28,19 @@ raise BadLdrawLine('unknown line type') def parse_ldraw_subfile_reference(line): - pattern = r'^1\s+(\d+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' + pattern = r'^1\s+([^ ]+)' + r'\s+([^ ]+)' * (3 + 9 + 1) + r'\s*$' match = re.search(pattern, line) if not match: raise BadLdrawLine('unable to parse') groups = list(match.groups()) indices = { - 'color': 0, + 'color_index': 0, 'anchor': slice(1, 4), 'matrix': slice(4, 13), 'subfile_path': 13 } try: - color = int(groups[indices['color']]) + color = Color(groups[indices['color_index']]) vertex_values = [float(x) for x in groups[indices['anchor']]] matrix_values = [float(x) for x in groups[indices['matrix']]] except ValueError: @@ -54,7 +55,7 @@ def generic_parse_polygon(line, *, type_code, vertex_count): pattern = r'^' \ + str(type_code) \ - + '\s+(\d+)' \ + + '\s+([^ ]+)' \ + r'\s+([^ ]+)' * (vertex_count * 3) \ + r'\s*$' match = re.search(pattern, line) @@ -72,7 +73,7 @@ raise BadLdrawLine('bad numeric values') vertices.append(Vertex(*coordinates)) return { - 'color': int(match.group(1)), + 'color': Color(match.group(1)), 'vertices': vertices, }