1cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Copyright 2015 The Chromium Authors. All rights reserved. 2cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Use of this source code is governed by a BSD-style license that can be 3cef7893435aa41160dd1255c43cb8498279738ccChris Craik# found in the LICENSE file. 4cef7893435aa41160dd1255c43cb8498279738ccChris Craik 5cef7893435aa41160dd1255c43cb8498279738ccChris Craik"""Objects for convenient manipulation of points and other surface areas.""" 6cef7893435aa41160dd1255c43cb8498279738ccChris Craik 7cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport collections 8cef7893435aa41160dd1255c43cb8498279738ccChris Craik 9cef7893435aa41160dd1255c43cb8498279738ccChris Craik 10cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass Point(collections.namedtuple('Point', ['x', 'y'])): 11cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Object to represent an (x, y) point on a surface. 12cef7893435aa41160dd1255c43cb8498279738ccChris Craik 13cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 14cef7893435aa41160dd1255c43cb8498279738ccChris Craik x, y: Two numeric coordinates that define the point. 15cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 16cef7893435aa41160dd1255c43cb8498279738ccChris Craik __slots__ = () 17cef7893435aa41160dd1255c43cb8498279738ccChris Craik 18cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __str__(self): 19cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Get a useful string representation of the object.""" 20cef7893435aa41160dd1255c43cb8498279738ccChris Craik return '(%s, %s)' % (self.x, self.y) 21cef7893435aa41160dd1255c43cb8498279738ccChris Craik 22cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __add__(self, other): 23cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Sum of two points, e.g. p + q.""" 24cef7893435aa41160dd1255c43cb8498279738ccChris Craik if isinstance(other, Point): 25cef7893435aa41160dd1255c43cb8498279738ccChris Craik return Point(self.x + other.x, self.y + other.y) 26cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 27cef7893435aa41160dd1255c43cb8498279738ccChris Craik return NotImplemented 28cef7893435aa41160dd1255c43cb8498279738ccChris Craik 29cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __mul__(self, factor): 30cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Multiplication on the right is not implemented.""" 31cef7893435aa41160dd1255c43cb8498279738ccChris Craik # This overrides the default behaviour of a tuple multiplied by a constant 32cef7893435aa41160dd1255c43cb8498279738ccChris Craik # on the right, which does not make sense for a Point. 33cef7893435aa41160dd1255c43cb8498279738ccChris Craik return NotImplemented 34cef7893435aa41160dd1255c43cb8498279738ccChris Craik 35cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __rmul__(self, factor): 36cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Multiply a point by a scalar factor on the left, e.g. 2 * p.""" 37cef7893435aa41160dd1255c43cb8498279738ccChris Craik return Point(factor * self.x, factor * self.y) 38cef7893435aa41160dd1255c43cb8498279738ccChris Craik 39cef7893435aa41160dd1255c43cb8498279738ccChris Craik 40cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass Rectangle( 41cef7893435aa41160dd1255c43cb8498279738ccChris Craik collections.namedtuple('Rectangle', ['top_left', 'bottom_right'])): 42cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Object to represent a rectangle on a surface. 43cef7893435aa41160dd1255c43cb8498279738ccChris Craik 44cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 45cef7893435aa41160dd1255c43cb8498279738ccChris Craik top_left: A pair of (left, top) coordinates. Might be given as a Point 46cef7893435aa41160dd1255c43cb8498279738ccChris Craik or as a two-element sequence (list, tuple, etc.). 47cef7893435aa41160dd1255c43cb8498279738ccChris Craik bottom_right: A pair (right, bottom) coordinates. 48cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 49cef7893435aa41160dd1255c43cb8498279738ccChris Craik __slots__ = () 50cef7893435aa41160dd1255c43cb8498279738ccChris Craik 51cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __new__(cls, top_left, bottom_right): 52cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not isinstance(top_left, Point): 53cef7893435aa41160dd1255c43cb8498279738ccChris Craik top_left = Point(*top_left) 54cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not isinstance(bottom_right, Point): 55cef7893435aa41160dd1255c43cb8498279738ccChris Craik bottom_right = Point(*bottom_right) 56cef7893435aa41160dd1255c43cb8498279738ccChris Craik return super(Rectangle, cls).__new__(cls, top_left, bottom_right) 57cef7893435aa41160dd1255c43cb8498279738ccChris Craik 58cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __str__(self): 59cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Get a useful string representation of the object.""" 60cef7893435aa41160dd1255c43cb8498279738ccChris Craik return '[%s, %s]' % (self.top_left, self.bottom_right) 61cef7893435aa41160dd1255c43cb8498279738ccChris Craik 62cef7893435aa41160dd1255c43cb8498279738ccChris Craik @property 63cef7893435aa41160dd1255c43cb8498279738ccChris Craik def center(self): 64cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Get the point at the center of the rectangle.""" 65cef7893435aa41160dd1255c43cb8498279738ccChris Craik return 0.5 * (self.top_left + self.bottom_right) 66cef7893435aa41160dd1255c43cb8498279738ccChris Craik 67cef7893435aa41160dd1255c43cb8498279738ccChris Craik @classmethod 68cef7893435aa41160dd1255c43cb8498279738ccChris Craik def FromDict(cls, d): 69cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Create a rectangle object from a dictionary. 70cef7893435aa41160dd1255c43cb8498279738ccChris Craik 71cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 72cef7893435aa41160dd1255c43cb8498279738ccChris Craik d: A dictionary (or mapping) of the form, e.g., {'top': 0, 'left': 0, 73cef7893435aa41160dd1255c43cb8498279738ccChris Craik 'bottom': 1, 'right': 1}. 74cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 75cef7893435aa41160dd1255c43cb8498279738ccChris Craik return cls(Point(d['left'], d['top']), Point(d['right'], d['bottom'])) 76