1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# Copyright 2015 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez"""Objects for convenient manipulation of points and other surface areas."""
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport collections
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Point(collections.namedtuple('Point', ['x', 'y'])):
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  """Object to represent an (x, y) point on a surface.
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  Args:
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    x, y: Two numeric coordinates that define the point.
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  """
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  __slots__ = ()
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def __str__(self):
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Get a useful string representation of the object."""
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return '(%s, %s)' % (self.x, self.y)
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def __add__(self, other):
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Sum of two points, e.g. p + q."""
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if isinstance(other, Point):
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return Point(self.x + other.x, self.y + other.y)
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    else:
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      return NotImplemented
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def __mul__(self, factor):
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Multiplication on the right is not implemented."""
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    # This overrides the default behaviour of a tuple multiplied by a constant
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    # on the right, which does not make sense for a Point.
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return NotImplemented
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def __rmul__(self, factor):
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Multiply a point by a scalar factor on the left, e.g. 2 * p."""
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return Point(factor * self.x, factor * self.y)
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Rectangle(
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    collections.namedtuple('Rectangle', ['top_left', 'bottom_right'])):
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  """Object to represent a rectangle on a surface.
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  Args:
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    top_left: A pair of (left, top) coordinates. Might be given as a Point
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      or as a two-element sequence (list, tuple, etc.).
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bottom_right: A pair (right, bottom) coordinates.
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  """
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  __slots__ = ()
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def __new__(cls, top_left, bottom_right):
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if not isinstance(top_left, Point):
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      top_left = Point(*top_left)
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if not isinstance(bottom_right, Point):
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      bottom_right = Point(*bottom_right)
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return super(Rectangle, cls).__new__(cls, top_left, bottom_right)
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def __str__(self):
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Get a useful string representation of the object."""
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return '[%s, %s]' % (self.top_left, self.bottom_right)
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  @property
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def center(self):
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Get the point at the center of the rectangle."""
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return 0.5 * (self.top_left + self.bottom_right)
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  @classmethod
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  def FromDict(cls, d):
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Create a rectangle object from a dictionary.
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Args:
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      d: A dictionary (or mapping) of the form, e.g., {'top': 0, 'left': 0,
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez         'bottom': 1, 'right': 1}.
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return cls(Point(d['left'], d['top']), Point(d['right'], d['bottom']))
76