parse.py

Tue, 12 Dec 2017 13:46:17 +0200

author
Santeri Piippo
date
Tue, 12 Dec 2017 13:46:17 +0200
changeset 5
e340e35d6e4c
parent 4
8eb83f200486
child 6
6da1e81c5652
permissions
-rw-r--r--

Added vertex operators

import linetypes
import re
from geometry import *
from ldraw import Colour

class BadLdrawLine(Exception):
    pass

def parse_ldraw_code(line):
    line = line.strip()
    if not line:
        return linetypes.EmptyLine()
    elif line == '0':
        return linetypes.Comment('')
    elif line.startswith('0 '):
        return linetypes.Comment(line[2:].strip())
    elif line.startswith('1 '):
        return parse_ldraw_subfile_reference(line)
    elif line.startswith('2 '):
        return parse_ldraw_line(line)
    elif line.startswith('3 '):
        return parse_ldraw_triangle(line)
    elif line.startswith('4 '):
        return parse_ldraw_quadrilateral(line)
    elif line.startswith('5 '):
        return parse_ldraw_contour(line)
    else:
        raise BadLdrawLine('unknown line type')

def parse_ldraw_subfile_reference(line):
    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 = {
        'colour_index': 0,
        'anchor': slice(1, 4),
        'matrix': slice(4, 13),
        'subfile_path': 13
    }
    try:
        colour = Colour(groups[indices['colour_index']])
        vertex_values = [float(x) for x in groups[indices['anchor']]]
        matrix_values = [float(x) for x in groups[indices['matrix']]]
    except ValueError:
        raise BadLdrawLine('bad numeric values')
    return linetypes.SubfileReference(
        colour = colour,
        anchor = Vertex(*vertex_values),
        matrix = TransformationMatrix(matrix_values),
        subfile_path = groups[indices['subfile_path']]
    )

def generic_parse_polygon(line, *, type_code, vertex_count):
    pattern = r'^' \
        + str(type_code) \
        + '\s+([^ ]+)' \
        + r'\s+([^ ]+)' * (vertex_count * 3) \
        + r'\s*$'
    match = re.search(pattern, line)
    if not match:
        raise BadLdrawLine(str.format('cannot parse type-{} line', type_code))
    vertices = []
    for vertex_index in range(vertex_count):
        slice_begin = 1 + vertex_index * 3
        slice_end = 1 + (vertex_index + 1) * 3
        coordinates = match.groups()[slice_begin:slice_end]
        assert(len(coordinates) == 3)
        try:
            coordinates = [float(x) for x in coordinates]
        except ValueError:
            raise BadLdrawLine('bad numeric values')
        vertices.append(Vertex(*coordinates))
    return {
        'colour': Colour(match.group(1)),
        'vertices': vertices,
    }

def parse_ldraw_line(line):
    parse_result = generic_parse_polygon(line, type_code = 2, vertex_count = 2)
    return linetypes.LineSegment(
        colour = parse_result['colour'],
        geometry = LineSegment(*parse_result['vertices']),
    )

def parse_ldraw_triangle(line):
    parse_result = generic_parse_polygon(line, type_code = 3, vertex_count = 3)
    return linetypes.Triangle(
        colour = parse_result['colour'],
        geometry = Polygon(parse_result['vertices']),
    )

def parse_ldraw_quadrilateral(line):
    parse_result = generic_parse_polygon(line, type_code = 4, vertex_count = 4)
    return linetypes.Quadrilateral(
        colour = parse_result['colour'],
        geometry = Polygon(parse_result['vertices']),
    )

def parse_ldraw_contour(line):
    parse_result = generic_parse_polygon(line, type_code = 5, vertex_count = 4)
    return linetypes.Contour(
        colour = parse_result['colour'],
        geometry = LineSegment(*parse_result['vertices'][0:2]),
        control_points = parse_result['vertices'][2:],
    )

mercurial