Files
2020-07-29 12:59:12 +02:00

273 lines
8.4 KiB
Python

import random
class Rect:
"""Define a pure and simple rectangle."""
# Class methods
@classmethod
def cross(cls, r1, r2):
"""Determine the rectangle resulting of the intersection of two rectangles."""
if r1.xmax < r2.xmin or r1.xmin > r2.xmax: return
if r1.ymax < r2.ymin or r1.ymin > r2.ymax: return
xmin = max(r1.xmin, r2.xmin)
ymin = max(r1.ymin, r2.ymin)
xmax = min(r1.xmax, r2.xmax)
ymax = min(r1.ymax, r2.ymax)
return Rect.createFromCorners(xmin, ymin, xmax, ymax)
@classmethod
def random(cls, borns=[-1, 1], borns_size=[0, 1]):
"""Create a random rect."""
x = random.uniform(*borns)
y = random.uniform(*borns)
sx = random.uniform(*borns_size)
sy = random.uniform(*borns_size)
return cls(x, y, sx, sy)
@classmethod
def createFromCorners(cls, *corners):
"""Create a rectangle."""
x, y, xm, ym = corners
w = xm - x
h = ym - y
return cls(x + w / 2, y + h / 2, w, h)
@classmethod
def createFromCoordinates(cls, *coordinates):
"""Create a rect using the coordinates."""
return cls(*coordinates)
@classmethod
def createFromRect(cls, *rect):
"""Create a rect from an unpacked pygame.rect"""
l, r, w, h = rect
return cls(l + w / 2, r + h / 2, w, h)
def __init__(self, x, y, w, h):
"""Create a rectangle using its x, y, width, and height, the
x and y components correspond to the center of the rectangle."""
self.components = [x, y, w, h]
def __getitem__(self, index):
return self.components[index]
def __setitem__(self, key, value):
self.components[key] = value
x = property(lambda cls: cls.__getitem__(0), lambda cls, value: cls.__setitem__(0, value),
doc="x component of the center")
y = property(lambda cls: cls.__getitem__(1), lambda cls, value: cls.__setitem__(1, value),
doc="y component of the center")
def getSize(self):
return [self.w, self.h]
def setSize(self, size):
self.w, self.height = size
size = property(getSize, setSize)
def getPosition(self):
return [self.x, self.y]
def setPosition(self, position):
self.x, self.y = position
center = position = property(getPosition, setPosition)
def __str__(self, n=2):
"""Return the string representation of a rect."""
r = self.__round__(n)
return "Rect(x=" + str(r.x) + ",y=" + str(r.y) + ",w=" + str(r.w) + ",h=" + str(r.h) + ")"
def __round__(self, n=2):
"""Round the components of the rect."""
x = round(self.x, n)
y = round(self.y, n)
w = round(self.w, n)
h = round(self.h, n)
return Rect(x, y, w, h)
def __contains__(self, position):
"""Determine if a position is in the rectangle."""
x, y = position
return (self.xmin <= x <= self.xmax) and (self.ymin <= y <= self.ymax)
def resize(self, n):
"""Allow the user to resize the rectangle."""
self.w *= n
self.h *= n
def __iter__(self):
self.iterator = 0
return self
def __next__(self):
if self.iterator < 4:
self.iterator += 1
return self.components[self.iterator - 1]
else:
raise StopIteration
# properties
# corners
def getCorners(self):
"""Return the corners of the rect."""
return [self.x - self.w / 2, self.y - self.h / 2, self.x + self.w / 2, self.y + self.h / 2]
def setCorners(self, corners):
"""Set the corners of the rect."""
x1, y1, x2, y2 = corners
self.w = x2 - x1
self.h = y2 - y1
self.x = x1 - self.w / 2
self.y = y1 - self.w / 2
# coordinates
def getCoordinates(self):
"""Return the coordinates of the rect."""
return [self.x, self.y, self.w, self.h]
def setCoordinates(self, coordinates):
"""Set the coordinates of the rect."""
self.position = coordinates[:2]
self.size = coordinates[2:]
# rect
def getRect(self):
"""Return the rect of the rectangle."""
return Rect.getRectFromCoordinates(self.getCoordinates())
def setRect(self, rect):
"""Set the rect of the rectangle."""
self.setCoordinates(Rect.getCoordinatesFromRect(rect))
# sx component
def getWidth(self):
"""Return the width."""
return self.components[2]
def setWidth(self, w):
"""Set the width."""
self.components[2] = w
# sy component
def getHeight(self):
"""Return the height."""
return self.components[3]
def setHeight(self, h):
"""Set the height."""
self.components[3] = h
# xmin component
def getXmin(self):
"""Return the minimum of the x component."""
return self.x - self.w / 2
def setXmin(self, xmin):
"""Set the minimum of the x component."""
self.x = xmin + w / 2
# ymin component
def getYmin(self):
"""Return the minimum of the y component."""
return self.y - self.h / 2
def setYmin(self, ymin):
"""Set the minimum of the y component."""
self.y = ymin + self.h / 2
# xmax component
def getXmax(self):
"""Return the maximum of the x component."""
return self.x + self.w / 2
def setXmax(self, xmax):
"""Set the maximum of the x component."""
self.x = xmax - self.w / 2
# ymax component
def getYmax(self):
"""Return the maximum of the y component."""
return self.y + self.h / 2
def setYmax(self, ymax):
"""Set the maximum of the y component."""
self.y = ymax - self.h / 2
corners = property(getCorners, setCorners, doc="Corners")
coordinates = property(getCoordinates, setCoordinates, doc="Center+Size")
w = sx = width = property(getWidth, setWidth, doc="Width")
h = sy = height = property(getHeight, setHeight, doc="Height")
xmin = x1 = left = l = property(getXmin, setXmin, doc="Left")
xmax = x2 = right = r = property(getXmax, setXmax, doc="Right")
ymin = y1 = bottom = b = property(getYmin, setYmin, doc="Bottom")
ymax = y2 = top = t = property(getYmax, setYmax, doc="Top")
# Static methods
@staticmethod
def getCornersFromCoordinates(coordinates):
"""Return the corners (top_left_corner,bottom_right_corner) using the coordinates (position+size)."""
"""[x,y,sx,sy] -> [mx,my,Mx,My]"""
x, y, sx, sy = coordinates
mx, my = x - sx / 2, y - sy / 2
Mx, My = x + sx / 2, y + sy / 2
return [mx, my, Mx, My]
@staticmethod
def getCoordinatesFromCorners(corners):
"""Return the coordinates (position+size) using the corners (top_left_corner,bottom_right_corner)."""
"""[mx,my,Mx,My] -> [x,y,sx,sy]"""
mx, my, Mx, My = corners
sx, sy = Mx - mx, My - my
x, y = mx + sx / 2, my + sy / 2
return [x, y, sx, sy]
@staticmethod
def getCoordinatesFromRect(rect):
"""Return the coordinates (position,size) using the rect (top_left_corner,size)."""
"""[x,y,sx,sy] -> [mx,my,sx,sy]"""
mx, my, sx, sy = rect
x, y = mx + sx / 2, my + sy / 2
return [x, y, sx, sy]
@staticmethod
def getRectFromCoordinates(coordinates):
"""Return the rect (top_left_corner,size) using the coordinates (position,size)."""
"""[mx,my,sx,sy] -> [x,y,sx,sy]"""
x, y, sx, sy = coordinates
mx, my = x - sx / 2, y - sy / 2
return [mx, my, sx, sy]
@staticmethod
def getRectFromCorners(corners):
"""Return the rect (top_left_corner,size) using the corners (top_left_corner,bottom_right_corner)."""
"""[mx,my,Mx,My] -> [mx,my,sx,sy]"""
mx, my, Mx, My = corners
sx, sy = Mx - mx, My - my
return [mx, my, sx, sy]
@staticmethod
def getCornersFromRect(rect):
"""Return the (top_left_corner,bottom_right_corner) using the corners rect (top_left_corner,size)."""
"""[mx,my,Mx,My] -> [mx,my,sx,sy]"""
mx, my, sx, sy = rect
Mx, My = mx + sx, my + sy
return [mx, my, Mx, My]
if __name__ == "__main__":
r1 = Rect.random()
r2 = Rect.random()
r1.x -= 1
print(r1, r2)
print(r1.corners)
print(r1.coordinates)
print(r1.x, r1.y)
print(r1.sx, r1.sy)
print(r1.width, r1.height)
r = Rect.cross(r1, r2)
print(*r1)