scientific-programming-exer.../exam/ex16/geometry.py

123 lines
3.6 KiB
Python
Raw Normal View History

2019-02-23 21:43:31 +00:00
from abc import abstractmethod, ABCMeta
from itertools import permutations
import numpy as np
class Point(object):
__slots__ = ["x", "y"]
def __init__(self, x, y):
self.x = x
self.y = y
def __abs__(self):
return (self.x**2 + self.y**2)**0.5
def __add__(self, other):
if(isinstance(self, Point)):
return Point(self.x + other.x, self.y + other.y)
raise TypeError("cannot add {} and {}".format(type(other), type(self)))
def __sub__(self, other):
if(isinstance(self, Point)):
return Point(self.x - other.x, self.y - other.y)
raise TypeError("cannot subtract {} and {}".format(type(other), type(self)))
def rotate(self, angle):
return Point(self.x * np.cos(angle) - self.y * np.sin(angle)
, self.x * np.sin(angle) + self.y * np.cos(angle))
def __repr__(self):
return "{}({}, {})".format(type(self).__name__, self.x, self.y)
class TwoDimensionalObject(metaclass=ABCMeta):
@abstractmethod
def contains_point(self, point: Point):
pass
def __contains__(self, other):
if(isinstance(other, Point)):
return self.contains_point(other)
raise TypeError("unable to check if {} is in {}".format(type(other), type(self)))
class Circle(TwoDimensionalObject):
def __init__(self, origin: Point, radius):
self.origin = origin
self.radius = radius
def contains_point(self, point: Point):
return abs(self.origin - point) < self.radius
def __repr__(self):
return "{}({}, {})".format(type(self).__name__, self.origin, self.radius)
class Rectangle(TwoDimensionalObject):
"""
A Rectangle is constructed as follows:
The Points p1, p2 are connected using orthogonal lines::
p1 +-------+
| |
| |
| |
+-------+ p2
and then the Rectangle is rotated ``angle`` degrees around ``p1``.
"""
def __init__(self, p1: Point, p2: Point, angle=0):
self.p1 = p1
self.p2 = p2
self.local_p1 = Point(0, 0)
self.local_p2 = (p2 - p1).rotate(angle)
self.angle = angle
def contains_point(self, point: Point):
point_in_eigen_frame = (point - self.p1).rotate(self.angle)
if(self.local_p1.x < self.local_p2.x):
if(point_in_eigen_frame.x < self.local_p1.x or point_in_eigen_frame.x > self.local_p1.x):
return False
else:
if(point_in_eigen_frame.x > self.local_p1.x or point_in_eigen_frame.x < self.local_p1.x):
return False
if(self.local_p1.y < self.local_p2.y):
if(point_in_eigen_frame.y < self.local_p1.y or point_in_eigen_frame.y > self.local_p1.y):
return False
else:
if(point_in_eigen_frame.y > self.local_p1.y or point_in_eigen_frame.y < self.local_p1.y):
return False
return True
def __repr__(self):
return "{}({}, {}, angle={})".format(type(self).__name__, self.p1, self.p2, self.angle)
class Triangle(TwoDimensionalObject):
def __init__(self, p1: Point, p2: Point, p3: Point):
self.p1 = p1
self.p2 = p2
self.p3 = p3
def contains_point(self, point: Point):
points = [self.p1, self.p2, self.p3]
triangle_surface = abs(sum([points[i].x * (points[(i + 1) % 3].y - points[(i + 2) % 3].y) for i in range(3)]))
points = [point, self.p1, self.p2, self.p3]
surfaces = [abs(sum([p[i].x * (p[(i + 1) % 4].y - p[(i + 2) % 4].y) for i in range(4)])) for p in permutations(points)]
return max(surfaces) < triangle_surface
def __repr__(self):
return "{}({}, {}, {})".format(type(self).__name__, self.p1, self.p2, self.p3)
class CollectionOfFigures(object):
def __init__(self, figures):
self.figures = figures
def containing(self, point: Point):
return [f for f in self.figures if point in f]
def __repr__(self):
return "{}({})".format(type(self).__name__, repr(self.figures))