ToyDesigner/toydesigner/objects.py

143 lines
4.1 KiB
Python

def point_maker(pre_point):
if isinstance(pre_point, Point):
return pre_point
elif isinstance(pre_point, tuple):
return Point(pre_point[0], pre_point[1])
else:
raise ValueError("Invalid input for Point")
class ShapeBase(object):
def __init__(self):
pass
def show(self):
pass
def move(self, dx, dy):
pass
def set_color(self, color):
pass
def get_color(self):
pass
class Shape2D(ShapeBase):
def __init__(self, **kwargs):
super(Shape2D, self).__init__()
self.color = kwargs.get("color", "white")
self.fill = kwargs.get("fill", False)
self.width = kwargs.get("width", 1)
class Point(Shape2D):
def __init__(self, x, y):
super(Point, self).__init__()
self._x = x
self._y = y
@property
def x(self):
return self._x
@property
def y(self):
return self._y
class Line(Shape2D):
def __init__(self, point1, point2, **kwargs):
super(Line, self).__init__(**kwargs)
self.point1 = point_maker(point1)
self.point2 = point_maker(point2)
def contains(self, point, allow_on_extended=False):
"""判断点`point`是否在线段上
Args:
point (Point or tuple): 需要判断的点
allow_on_extended (bool, optional): 是否允许点在线段的延长线上. Defaults to False.
Returns:
_type_: boolean
"""
point = point_maker(point)
f = self.function()
if allow_on_extended:
return f(point.x) == point.y
else:
return f(point.x) == point.y and (
(point.x >= min(self.point1.x, self.point2.x) and point.x <= max(self.point1.x, self.point2.x)))
# 通过关键字`in`判断点是否在线段上
def __contains__(self, point):
return self.contains(point)
# 该线段所在直线的纵截距
def y_intercept(self):
if self.point1.x == self.point2.x:
return 0
return ((self.point1.y * self.point2.x) \
- (self.point1.x * self.point2.y)) \
/ (self.point2.x - self.point1.x)
# 该线段的斜率
def slope(self):
if self.point1.x - self.point2.x == 0:
return float("inf")
else:
return (self.point1.y - self.point2.y) / (self.point1.x - self.point2.x)
# 该线段所在直线的函数方程
def function(self):
a = self.slope()
b = self.y_intercept()
return lambda x: a * x + b
# 该线段的函数式
def equation(self):
if self.point1.x - self.point2.x == 0:
return "y = " + str(self.point1.y)
else:
a = self.slope()
b = self.y_intercept()
return f"y = {a}x{' + ' if b != 0 else ''}{b if b != 0 else ''}"
# 该线段的长度
def length(self):
return (
(self.point1.x - self.point2.x) ** 2 + (self.point1.y - self.point2.y) ** 2
) ** 0.5
# 该线段与另一线段的交点
def intersection(self, other):
if isinstance(other, Line):
if self.slope() == other.slope():
return None
else:
x = (
self.slope() * other.point1.x
- self.point1.y
+ other.slope() * self.point1.x
- other.point1.y
) / (self.slope() - other.slope())
y = self.slope() * (x - self.point1.x) + self.point1.y
return Point(x, y)
else:
raise ValueError("Invalid input for Line")
class Rectangle(Shape2D):
def __init__(self, point1, point2):
super(Rectangle, self).__init__()
if isinstance(point1, Point) and isinstance(point2, Point):
self.point1 = point1
self.point2 = point2
elif isinstance(point1, tuple) and isinstance(point2, tuple):
self.point1 = Point(point1[0], point1[1])
self.point2 = Point(point2[0], point2[1])
else:
raise ValueError("Invalid input for Rectangle")