geometry.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 3
1dc58f44d556
child 6
6da1e81c5652
permissions
-rw-r--r--

Added vertex operators

class Vertex:
    def __init__(self, x, y, z):
        if not all(is_real(coordinate) for coordinate in (x, y, z)):
            raise ValueError(str.format('Bad vertex coordinates: {!r}',
                (x, y, z),
            ))
        self.x, self.y, self.z = x, y, z
    def __repr__(self):
        return str.format('Vertex({!r}, {!r}, {!r})', self.x, self.y, self.z)
    def distance_to(self, other):
        # can't use hypot because of 3 arguments
        from math import sqrt
        return sqrt(
            (self.x - other.x) ** 2 +
            (self.y - other.y) ** 2 +
            (self.z - other.z) ** 2
        )
    @property
    def coordinates(self):
        return self.x, self.y, self.z
    def __add__(self, other):
        return Vertex(self.x + other.x, self.y + other.y, self.z + other.z)
    def __neg__(self):
        return Vertex(-self.x, -self.y, -self.z)
    def __sub__(self, other):
        return self + (-other)
    def __mul__(self, scalar):
        return Vertex(self.x * scalar, self.y * scalar, self.z * scalar)
    def __rmul__(self, other):
        return self * other
    def __truediv__(self, scalar):
        return Vertex(self.x / scalar, self.y / scalar, self.z / scalar)
    def __floordiv__(self, scalar):
        return Vertex(self.x // scalar, self.y // scalar, self.z // scalar)
    def __matmul__(self, transformation_matrix):
        return transform(self, transformation_matrix)
    def __eq__(self, other):
        return self.coordinates == other.coordinates
    def __lt__(self, other):
        return self.coordinates < other.coordinates
    def __hash__(self):
        return hash(self.coordinates)

class VertexOp:
    def __init__(self, callable):
        self.callable = callable
    def __rmul__(self, coordinate):
        return self.callable(coordinate)

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):
        self.vertices = vertices
    def __repr__(self):
        return str.format('Polygon({!r})', self.vertices)

def is_real(number):
    return isinstance(number, int) or isinstance(number, float)

class TransformationMatrix:
    '''
        A 3×3 matrix forming the top-left portion of a full 4×4 transformation
        matrix.
    '''
    def __init__(self, values):
        assert(all(is_real(x) for x in values))
        assert len(values) == 9
        self.values = values
    def __repr__(self):
        return str.format('TransformationMatrix({!r})', self.values)
    def __getitem__(self, index):
        return self.values[index]

def complete_matrix(matrix, anchor):
    '''
        Combines a 3×3 matrix and an anchor vertex into a full 4×4
        transformation matrix.
    '''
    return [
        matrix[0], matrix[1], matrix[2], anchor.x,
        matrix[3], matrix[4], matrix[5], anchor.y,
        matrix[6], matrix[7], matrix[8], anchor.z,
        0, 0, 0, 1,
    ]

def transform(vertex, transformation_matrix):
    '''
        Transforms a vertex by a 4×4 transformation matrix.
    '''
    u = transformation_matrix[0] * vertex.x \
        + transformation_matrix[1] * vertex.y \
        + transformation_matrix[2] * vertex.z \
        + transformation_matrix[3]
    v = transformation_matrix[4] * vertex.x \
        + transformation_matrix[5] * vertex.y \
        + transformation_matrix[6] * vertex.z \
        + transformation_matrix[7]
    w = transformation_matrix[8] * vertex.x \
        + transformation_matrix[9] * vertex.y \
        + transformation_matrix[10] * vertex.z \
        + transformation_matrix[11]
    return Vertex(u, v, w)

mercurial