126 lines
3.4 KiB
Python
126 lines
3.4 KiB
Python
|
|
class StructureBase(object):
|
|
@classmethod
|
|
def _attrs(cls):
|
|
a = []
|
|
i = cls()
|
|
for attr in dir(i):
|
|
if not attr.startswith('_') and not callable(getattr(i, attr)):
|
|
a.append(attr)
|
|
return a
|
|
|
|
def _dict(self):
|
|
d = {}
|
|
attrs = self._attrs()
|
|
for a in attrs:
|
|
d[a] = getattr(self, a)
|
|
return d
|
|
|
|
def _dict_string(self):
|
|
return ', '.join('{}={}'.format(key, val) for key, val in self._dict().items())
|
|
|
|
def __repr__(self):
|
|
return unicode(self)
|
|
|
|
def __str__(self):
|
|
return unicode(self).encode('utf-8')
|
|
|
|
def __unicode__(self):
|
|
return u'{} [{}]'.format(self.__class__.__name__, self._dict_string())
|
|
|
|
@classmethod
|
|
def is_like(cls, obj):
|
|
"""Checks if the object is like the current class
|
|
If it has everything a duck has, then it's good."""
|
|
for key in cls._attrs():
|
|
if not hasattr(obj, key):
|
|
return False
|
|
return True
|
|
|
|
class Position(StructureBase):
|
|
def __init__(self, x=0, y=0):
|
|
self.x = x
|
|
self.y = y
|
|
|
|
def __add__(self, other):
|
|
other = Position.from_value(other)
|
|
return Position(self.x+other.x, self.y+other.y)
|
|
|
|
def __sub__(self, other):
|
|
other = Position.from_value(other)
|
|
return Position(self.x-other.x, self.y-other.y)
|
|
|
|
@classmethod
|
|
def from_value(cls, value):
|
|
if not value:
|
|
return cls()
|
|
if cls.is_like(value):
|
|
return value
|
|
elif len(value) >= 2:
|
|
return cls(value[0], value[1])
|
|
else:
|
|
return cls()
|
|
|
|
|
|
class Size(StructureBase):
|
|
def __init__(self, width=0, height=0):
|
|
self.height = height
|
|
self.width = width
|
|
|
|
def __add__(self, other):
|
|
other = Size.from_value(other)
|
|
return Size(self.width+other.width, self.height+other.height)
|
|
|
|
def __sub__(self, other):
|
|
other = Size.from_value(other)
|
|
return Size(self.width-other.width, self.height-other.height)
|
|
|
|
@classmethod
|
|
def from_value(cls, value):
|
|
if not value:
|
|
return cls()
|
|
if cls.is_like(value):
|
|
return value
|
|
elif len(value) >= 2:
|
|
return cls(value[0], value[1])
|
|
else:
|
|
return cls()
|
|
|
|
|
|
class Rectangle(StructureBase):
|
|
def __init__(self, position=None, size=None):
|
|
""" A rectangle object with coordinates and size.
|
|
position: can take the first two values of an array or a Position object
|
|
size: can take the first two values of an array or a Size object
|
|
"""
|
|
self._position = None
|
|
self._size = None
|
|
self.position = position
|
|
self.size = size
|
|
|
|
@property
|
|
def position(self):
|
|
return self._position
|
|
|
|
@position.setter
|
|
def position(self, position):
|
|
self._position = Position.from_value(position)
|
|
|
|
@property
|
|
def size(self):
|
|
return self._size
|
|
|
|
@size.setter
|
|
def size(self, size):
|
|
self._size = Size.from_value(size)
|
|
|
|
def intersects_with(self, position):
|
|
"""Checks if the position is within the bounds of the rectangle including the edges"""
|
|
pos = Position.from_value(position)
|
|
if pos.x < self.position.x + self.size.width and\
|
|
pos.x >= self.position.x:
|
|
if pos.y < self.position.y + self.size.height and\
|
|
pos.y >= self.position.y:
|
|
return True
|
|
return False
|
|
|