Beispiel #1
0
 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
Beispiel #2
0
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)
Beispiel #3
0
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