import json from math import hypot import math from helix.functions import fequal class Coordinate(object): def __init__(self, x, y, rotation=0., calculate_rounding=True): self.x = x self.y = y self.rotation = rotation if calculate_rounding: self.__rounded_x = round(x, 3) self.__rounded_y = round(y, 3) else: self.__rounded_x = x self.__rounded_y = y def __eq__(self, other): if self is other: return True if not isinstance(other, self.__class__): return False if fequal(self.rotation, other.rotation, delta=1e-3): return fequal(self.x, other.x, delta=1e-3) and fequal(self.y, other.y, delta=1e-3) return False @property def dictionary(self): return {"x": self.x, "y": self.y, "rotation": self.rotation} def __repr__(self): return json.dumps(self.dictionary, sort_keys=True) def __sub__(self, other): if fequal(self.rotation, other.rotation, delta=1e-1): return Coordinate(self.x - other.x, self.y - other.y, self.rotation) else: raise ValueError def __add__(self, other): if abs(self.rotation - other.rotation) < 1e-3: return Coordinate(self.x + other.x, self.y + other.y, self.rotation, calculate_rounding=False) else: raise ValueError def __abs__(self): return self.length() def __lt__(self, other): if self == other: return False if self.y < other.y: return True elif other.y < self.y: return False return self.x < other.x def __round__(self, n=0): return Coordinate(round(self.x, n), round(self.y, n), self.rotation) def __hash__(self): return hash(self.__rounded_x) ^ hash(self.__rounded_y) ^ hash(self.rotation) # Returns a Coordinate based on self, rotated by self's rotation def rotate(self): rotation = math.radians(self.rotation) x = self.x * math.cos(rotation) - self.y * math.sin(rotation) y = self.x * math.sin(rotation) + self.y * math.cos(rotation) return Coordinate(x, y) # Returns a Coordinate based on self, rotated by self's negative rotation def unrotate(self): rotation = math.radians(-self.rotation) x = self.x * math.cos(rotation) - self.y * math.sin(rotation) y = self.x * math.sin(rotation) + self.y * math.cos(rotation) return Coordinate(x, y) def scale(self, x, y): return Coordinate(self.x * x, self.y * y, self.rotation) def neg_translate(self, other): return Coordinate(self.x - other.x, self.y - other.y, self.rotation) def length(self): return hypot(self.x, self.y)