Tue, 12 Dec 2017 13:46:17 +0200
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)