def connection_point(self, point_1, point_2): """Returns the intersection point between the rectangle and the line between `point_1` and `point_2`. If no intersection exists (both points are either inside or outside) than None is returned. """ line = D2.Line(point_1, point_2) for side in (self.bottom, self.left, self.right, self.top): cp = side.intersection(line) if cp is not None: return cp return None
class Rect(TFL.Meta.Object, metaclass=M_Rect): """Model an axes-parallel rectangle in 2D space. >>> def rect_points (r) : ... for p in sorted (r.corner_dict.keys ()) : ... print ("%-20s : %s" % (p, getattr (r, p))) >>> def rect_sides (r) : ... for s in sorted (r.side_dict.keys ()) : ... print ("%-20s : %s" % (s, getattr (r, s))) >>> def connection_points (r) : ... P = D2.Point ... for p, off in sorted ( ... [ (r.top_left, P ( 0.0, +0.5)) ... , (r.top_left, P (-0.5, 0.0)) ... , (r.top_right, P ( 0.0, +0.5)) ... , (r.top_right, P ( 0.5, 0.0)) ... , (r.bottom_left, P ( 0.0, -0.5)) ... , (r.bottom_left, P (-0.5, 0.0)) ... , (r.bottom_right, P ( 0.0, -0.5)) ... , (r.bottom_right, P ( 0.5, 0.0)) ... ] ... , key = lambda x : tuple (x [0] + x [1]) ... ) : ... q = p + off ... print ("%s : %s" % (q, r.connection_point (q, r.center))) >>> q = Rect (D2.Point (1.0, 1.0), D2.Point (2.0, 1.0)) >>> rect_points (q) bottom_left : (1.0, 1.0) bottom_right : (3.0, 1.0) center : (2.0, 1.5) center_bottom : (2.0, 1.0) center_left : (1.0, 1.5) center_right : (3.0, 1.5) center_top : (2.0, 2.0) top_left : (1.0, 2.0) top_right : (3.0, 2.0) >>> q.scale (2) Rect ((1.0, 1.0), (4.0, 2.0)) >>> rect_points (q) bottom_left : (1.0, 1.0) bottom_right : (5.0, 1.0) center : (3.0, 2.0) center_bottom : (3.0, 1.0) center_left : (1.0, 2.0) center_right : (5.0, 2.0) center_top : (3.0, 3.0) top_left : (1.0, 3.0) top_right : (5.0, 3.0) >>> q.shift (D2.Point (1, 1)) Rect ((2.0, 2.0), (4.0, 2.0)) >>> rect_points (q) bottom_left : (2.0, 2.0) bottom_right : (6.0, 2.0) center : (4.0, 3.0) center_bottom : (4.0, 2.0) center_left : (2.0, 3.0) center_right : (6.0, 3.0) center_top : (4.0, 4.0) top_left : (2.0, 4.0) top_right : (6.0, 4.0) >>> rect_sides (q) bottom : ((2.0, 2.0), (6.0, 2.0)) left : ((2.0, 2.0), (2.0, 4.0)) right : ((6.0, 2.0), (6.0, 4.0)) top : ((2.0, 4.0), (6.0, 4.0)) >>> q = Rect (D2.Point (1.0, 1.0), D2.Point (1.0, 1.0)) >>> connection_points (q) (0.5, 1.0) : (1.0, 1.25) (0.5, 2.0) : (1.0, 1.75) (1.0, 0.5) : (1.25, 1.0) (1.0, 2.5) : (1.25, 2.0) (2.0, 0.5) : (1.75, 1.0) (2.0, 2.5) : (1.75, 2.0) (2.5, 1.0) : (2.0, 1.25) (2.5, 2.0) : (2.0, 1.75) """ Bottom_Left = D2.Point(0.0, 0.0) Bottom_Right = D2.Point(1.0, 0.0) Center = D2.Point(0.5, 0.5) Center_Bottom = D2.Point(0.5, 0.0) Center_Left = D2.Point(0.0, 0.5) Center_Right = D2.Point(1.0, 0.5) Center_Top = D2.Point(0.5, 1.0) Top_Left = D2.Point(0.0, 1.0) Top_Right = D2.Point(1.0, 1.0) side_dict = \ { "bottom" : (lambda r : D2.Line (r.bottom_left, r.bottom_right)) , "left" : (lambda r : D2.Line (r.bottom_left, r.top_left)) , "right" : (lambda r : D2.Line (r.bottom_right, r.top_right)) , "top" : (lambda r : D2.Line (r.top_left, r.top_right)) } @property def corners(self): return \ self.bottom_left, self. bottom_right, self.top_left, self.top_right # end def sides @property def ref_point(self): return self.bottom_left # end def ref_point @ref_point.setter def ref_point(self, value): self.bottom_left = value # end def ref_point def __init__(self, pos=(0.0, 0.0), size=(1.0, 1.0)): if isinstance(pos, (list, tuple)): pos = D2.Point(*pos) if isinstance(size, (list, tuple)): size = D2.Point(*size) self.ref_point = pos self.size = size # end def __init__ @classmethod def Sides(cls, diagonal, ratio): """Return the sides `(a, b)` of a rectangle with `diagonal` and `ratio` between the sides. """ b = math.sqrt(diagonal * diagonal / (1 + ratio * ratio)) a = b * ratio return a, b # end def Sides def connection_point(self, point_1, point_2): """Returns the intersection point between the rectangle and the line between `point_1` and `point_2`. If no intersection exists (both points are either inside or outside) than None is returned. """ line = D2.Line(point_1, point_2) for side in (self.bottom, self.left, self.right, self.top): cp = side.intersection(line) if cp is not None: return cp return None # end def connection_point def point(self, p=Center): """Return point at position `p` relative to the rectangle.""" return self.ref_point + (self.size * p) # end def point def point_in_rect(self, point): if isinstance(point, (list, tuple)): point = D2.Point(*point) tl = self.top_left br = tl + self.size if ((point.x < tl.x) or (point.x > br.x) or (point.y < tl.y) or (point.y > br.y)): return None return 1 # end def point_in_rect def scale(self, right): self.size.scale(right) return self # end def scale def shift(self, right): self.ref_point.shift(right) return self # end def shift def transformed(self, affine): """Return another rectangle whose coordinates are derived via `affine` transform from `self`. """ return self.__class__ \ (self.ref_point.transform (affine), self.size.transformed (affine)) # end def transformed def __getattr__(self, name): """Return the point or side `name`. The possible names are defined by `corner_dict` and `side_dict`. """ if name in self.corner_dict: return self.point(self.corner_dict[name]) elif name in self.side_dict: return self.side_dict[name](self) else: raise AttributeError(name) # end def __getattr__ def __repr__(self): return "%s %s" % (self.__class__.__name__, str(self)) # end def __repr__ def __str__(self): return "(%s, %s)" % (self.ref_point, self.size)
class _Screen_Rect_(D2.Rect): """Model an axes-parallel rectangle in 2D screen coordinates. >>> def rect_points (r) : ... for p in sorted (r.corner_dict.keys ()) : ... print ("%-20s : %s" % (p, getattr (r, p))) >>> def rect_sides (r) : ... for s in sorted (r.side_dict.keys ()) : ... print ("%-20s : %s" % (s, getattr (r, s))) >>> def connection_points (r) : ... P = D2.Point ... for p, off in sorted ( ... [ (r.top_left, P ( 0.0, -0.5)) ... , (r.top_left, P (-0.5, 0.0)) ... , (r.top_right, P ( 0.0, -0.5)) ... , (r.top_right, P ( 0.5, 0.0)) ... , (r.bottom_left, P ( 0.0, 0.5)) ... , (r.bottom_left, P (-0.5, 0.0)) ... , (r.bottom_right, P ( 0.0, 0.5)) ... , (r.bottom_right, P ( 0.5, 0.0)) ... ] ... , key = lambda x : tuple (x [0] + x [1]) ... ) : ... q = p + off ... print ("%s : %s" % (q, r.connection_point (q, r.center))) >>> q = Rect (D2.Point (1.0, 1.0), D2.Point (2.0, 1.0)) >>> rect_points (q) bottom_left : (1.0, 2.0) bottom_right : (3.0, 2.0) center : (2.0, 1.5) center_bottom : (2.0, 2.0) center_left : (1.0, 1.5) center_right : (3.0, 1.5) center_top : (2.0, 1.0) top_left : (1.0, 1.0) top_right : (3.0, 1.0) >>> q.scale (2) Rect ((1.0, 1.0), (4.0, 2.0)) >>> rect_points (q) bottom_left : (1.0, 3.0) bottom_right : (5.0, 3.0) center : (3.0, 2.0) center_bottom : (3.0, 3.0) center_left : (1.0, 2.0) center_right : (5.0, 2.0) center_top : (3.0, 1.0) top_left : (1.0, 1.0) top_right : (5.0, 1.0) >>> q.shift (D2.Point (1, 1)) Rect ((2.0, 2.0), (4.0, 2.0)) >>> rect_points (q) bottom_left : (2.0, 4.0) bottom_right : (6.0, 4.0) center : (4.0, 3.0) center_bottom : (4.0, 4.0) center_left : (2.0, 3.0) center_right : (6.0, 3.0) center_top : (4.0, 2.0) top_left : (2.0, 2.0) top_right : (6.0, 2.0) >>> rect_sides (q) bottom : ((2.0, 4.0), (6.0, 4.0)) left : ((2.0, 2.0), (2.0, 4.0)) right : ((6.0, 2.0), (6.0, 4.0)) top : ((2.0, 2.0), (6.0, 2.0)) >>> q = Rect (D2.Point (1.0, 1.0), D2.Point (1.0, 1.0)) >>> connection_points (q) (0.5, 1.0) : (1.0, 1.25) (0.5, 2.0) : (1.0, 1.75) (1.0, 0.5) : (1.25, 1.0) (1.0, 2.5) : (1.25, 2.0) (2.0, 0.5) : (1.75, 1.0) (2.0, 2.5) : (1.75, 2.0) (2.5, 1.0) : (2.0, 1.25) (2.5, 2.0) : (2.0, 1.75) """ _real_name = "Rect" Bottom_Left = D2.Point(0.0, 1.0) Bottom_Right = D2.Point(1.0, 1.0) Center = D2.Point(0.5, 0.5) Center_Bottom = D2.Point(0.5, 1.0) Center_Left = D2.Point(0.0, 0.5) Center_Right = D2.Point(1.0, 0.5) Center_Top = D2.Point(0.5, 0.0) Top_Left = D2.Point(0.0, 0.0) Top_Right = D2.Point(1.0, 0.0) side_dict = \ { "bottom" : (lambda r : D2.Line (r.bottom_left, r.bottom_right)) , "left" : (lambda r : D2.Line (r.top_left, r.bottom_left)) , "right" : (lambda r : D2.Line (r.top_right, r.bottom_right)) , "top" : (lambda r : D2.Line (r.top_left, r.top_right)) } @property def ref_point(self): return self.top_left # end def ref_point @ref_point.setter def ref_point(self, value): self.top_left = value