# See https://stackoverflow.com/a/33533514 from __future__ import annotations from typing import Iterable, Union from funcy import identity from cv_analysis.utils.spacial import adjacent, contains, intersection, iou, area, is_contained Coord = Union[int, float] class Rectangle: def __init__(self, x1, y1, x2, y2, discrete=True): """Creates a rectangle from two points.""" nearest_valid = int if discrete else identity self.__x1 = nearest_valid(x1) self.__y1 = nearest_valid(y1) self.__x2 = nearest_valid(x2) self.__y2 = nearest_valid(y2) def __repr__(self): return f"Rectangle({self.x1}, {self.y1}, {self.x2}, {self.y2})" @property def x1(self): return self.__x1 @property def x2(self): return self.__x2 @property def y1(self): return self.__y1 @property def y2(self): return self.__y2 @property def width(self): return abs(self.x2 - self.x1) @property def height(self): return abs(self.y2 - self.y1) @property def coords(self): return [self.x1, self.y1, self.x2, self.y2] def __hash__(self): return hash((self.x1, self.y1, self.x2, self.y2)) def __iter__(self): yield self.x1 yield self.y1 yield self.width yield self.height def area(self): """Calculates the area of this rectangle.""" return area(self) def intersection(self, other): """Calculates the intersection of this and the given other rectangle.""" return intersection(self, other) def iou(self, other: Rectangle): """Calculates the intersection over union of this and the given other rectangle.""" return iou(self, other) def includes(self, other: Rectangle, tol=3): """Checks if this rectangle contains the given other.""" return contains(self, other, tol) def is_included(self, rectangles: Iterable[Rectangle]): """Checks if this rectangle is contained by any of the given rectangles.""" return is_contained(self, rectangles) def adjacent(self, other: Rectangle, tolerance=7): """Checks if this rectangle is adjacent to the given other.""" return adjacent(self, other, tolerance)