From 32c07d29136b61bdbd5aef870c368bda40d2c203 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Thu, 14 Dec 2023 15:08:49 +0100 Subject: [PATCH] Coordinate() now behaves more tupley-like (methods not accept tuples as parameters, including __add__ and __sub__) --- src/tools/coordinate.py | 128 ++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/tools/coordinate.py b/src/tools/coordinate.py index 4d0836d..d30eb4b 100644 --- a/src/tools/coordinate.py +++ b/src/tools/coordinate.py @@ -30,11 +30,11 @@ class Coordinate(tuple): return self[2] def is3D(self) -> bool: - return self.z is not None + return self[2] is not None def getDistanceTo( self, - target: Coordinate, + target: Coordinate | tuple, algorithm: DistanceAlgorithm = DistanceAlgorithm.EUCLIDEAN, includeDiagonals: bool = False, ) -> Union[int, float]: @@ -49,39 +49,39 @@ class Coordinate(tuple): """ if algorithm == DistanceAlgorithm.EUCLIDEAN: if self.z is None: - return sqrt(abs(self.x - target.x) ** 2 + abs(self.y - target.y) ** 2) + return sqrt(abs(self[0] - target[0]) ** 2 + abs(self[1] - target[1]) ** 2) else: return sqrt( - abs(self.x - target.x) ** 2 - + abs(self.y - target.y) ** 2 - + abs(self.z - target.z) ** 2 + abs(self[0] - target[0]) ** 2 + + abs(self[1] - target[1]) ** 2 + + abs(self[2] - target[2]) ** 2 ) elif algorithm == DistanceAlgorithm.CHEBYSHEV: if self.z is None: - return max(abs(target.x - self.x), abs(target.y - self.y)) + return max(abs(target[0] - self[0]), abs(target[1] - self[1])) else: return max( - abs(target.x - self.x), - abs(target.y - self.y), - abs(target.z - self.z), + abs(target[0] - self[0]), + abs(target[1] - self[1]), + abs(target[2] - self[2]), ) elif algorithm == DistanceAlgorithm.MANHATTAN: if not includeDiagonals: if self.z is None: - return abs(self.x - target.x) + abs(self.y - target.y) + return abs(self[0] - target[0]) + abs(self[1] - target[1]) else: return ( - abs(self.x - target.x) - + abs(self.y - target.y) - + abs(self.z - target.z) + abs(self[0] - target[0]) + + abs(self[1] - target[1]) + + abs(self[2] - target[2]) ) else: - dist = [abs(self.x - target.x), abs(self.y - target.y)] + dist = [abs(self[0] - target[0]), abs(self[1] - target[1])] if self.z is None: o_dist = max(dist) - min(dist) return o_dist + 1.4 * min(dist) else: - dist.append(abs(self.z - target.z)) + dist.append(abs(self[2] - target[2])) d_steps = min(dist) dist.remove(min(dist)) dist = [x - d_steps for x in dist] @@ -98,12 +98,12 @@ class Coordinate(tuple): maxZ: int = inf, ) -> bool: if self.z is None: - return minX <= self.x <= maxX and minY <= self.y <= maxY + return minX <= self[0] <= maxX and minY <= self[1] <= maxY else: return ( - minX <= self.x <= maxX - and minY <= self.y <= maxY - and minZ <= self.z <= maxZ + minX <= self[0] <= maxX + and minY <= self[1] <= maxY + and minZ <= self[2] <= maxZ ) def getCircle( @@ -119,8 +119,8 @@ class Coordinate(tuple): ) -> list[Coordinate]: ret = [] if self.z is None: # mode 2D - for x in range(self.x - radius * 2, self.x + radius * 2 + 1): - for y in range(self.y - radius * 2, self.y + radius * 2 + 1): + for x in range(self[0] - radius * 2, self[0] + radius * 2 + 1): + for y in range(self[1] - radius * 2, self[1] + radius * 2 + 1): target = Coordinate(x, y) if not target.inBoundaries(minX, minY, maxX, maxY): continue @@ -133,9 +133,9 @@ class Coordinate(tuple): ret.append(target) else: - for x in range(self.x - radius * 2, self.x + radius * 2 + 1): - for y in range(self.y - radius * 2, self.y + radius * 2 + 1): - for z in range(self.z - radius * 2, self.z + radius * 2 + 1): + for x in range(self[0] - radius * 2, self[0] + radius * 2 + 1): + for y in range(self[1] - radius * 2, self[1] + radius * 2 + 1): + for z in range(self[2] - radius * 2, self[2] + radius * 2 + 1): target = Coordinate(x, y) if not target.inBoundaries(minX, minY, maxX, maxY, minZ, maxZ): continue @@ -187,8 +187,8 @@ class Coordinate(tuple): nb_list = [(-1, 0), (1, 0), (0, -1), (0, 1)] for dx, dy in nb_list: - if minX <= self.x + dx <= maxX and minY <= self.y + dy <= maxY: - yield self.__class__(self.x + dx, self.y + dy) + if minX <= self[0] + dx <= maxX and minY <= self[0] + dy <= maxY: + yield self.__class__(self[0] + dx, self[1] + dy) else: if includeDiagonal: nb_list = [ @@ -210,19 +210,19 @@ class Coordinate(tuple): for dx, dy, dz in nb_list: if ( - minX <= self.x + dx <= maxX - and minY <= self.y + dy <= maxY - and minZ <= self.z + dz <= maxZ + minX <= self[0] + dx <= maxX + and minY <= self[1] + dy <= maxY + and minZ <= self[2] + dz <= maxZ ): - yield self.__class__(self.x + dx, self.y + dy, self.z + dz) + yield self.__class__(self[0] + dx, self[1] + dy, self[2] + dz) - def getAngleTo(self, target: Coordinate, normalized: bool = False) -> float: + def getAngleTo(self, target: Coordinate | tuple, normalized: bool = False) -> float: """normalized returns an angle going clockwise with 0 starting in the 'north'""" if self.z is not None: raise NotImplementedError() # which angle?!?! - dx = target.x - self.x - dy = target.y - self.y + dx = target[0] - self[0] + dy = target[1] - self[1] if not normalized: return degrees(atan2(dy, dx)) else: @@ -232,77 +232,77 @@ class Coordinate(tuple): else: return 180.0 + abs(angle) - def getLineTo(self, target: Coordinate) -> List[Coordinate]: + def getLineTo(self, target: Coordinate | tuple) -> List[Coordinate]: diff = target - self if self.z is None: - steps = gcd(diff.x, diff.y) - step_x = diff.x // steps - step_y = diff.y // steps + steps = gcd(diff[0], diff[0]) + step_x = diff[0] // steps + step_y = diff[1] // steps return [ - self.__class__(self.x + step_x * i, self.y + step_y * i) + self.__class__(self[0] + step_x * i, self[1] + step_y * i) for i in range(steps + 1) ] else: - steps = gcd(diff.x, diff.y, diff.z) - step_x = diff.x // steps - step_y = diff.y // steps - step_z = diff.z // steps + steps = gcd(diff[0], diff[1], diff[2]) + step_x = diff[0] // steps + step_y = diff[1] // steps + step_z = diff[2] // steps return [ self.__class__( - self.x + step_x * i, self.y + step_y * i, self.z + step_z * i + self[0] + step_x * i, self[1] + step_y * i, self[2] + step_z * i ) for i in range(steps + 1) ] def reverse(self) -> Coordinate: if self.z is None: - return self.__class__(-self.x, -self.y) + return self.__class__(-self[0], -self[1]) else: - return self.__class__(-self.x, -self.y, -self.z) + return self.__class__(-self[0], -self[1], -self[2]) - def __add__(self, other: Coordinate) -> Coordinate: + def __add__(self, other: Coordinate | tuple) -> Coordinate: if self.z is None: - return self.__class__(self.x + other.x, self.y + other.y) + return self.__class__(self[0] + other[0], self[1] + other[1]) else: - return self.__class__(self.x + other.x, self.y + other.y, self.z + other.z) + return self.__class__(self[0] + other[0], self[1] + other[1], self[2] + other[2]) - def __sub__(self, other: Coordinate) -> Coordinate: + def __sub__(self, other: Coordinate | tuple) -> Coordinate: if self.z is None: - return self.__class__(self.x - other.x, self.y - other.y) + return self.__class__(self[0] - other[0], self[1] - other[1]) else: - return self.__class__(self.x - other.x, self.y - other.y, self.z - other.z) + return self.__class__(self[0] - other[0], self[1] - other[1], self[2] - other[2]) def __mul__(self, other: int) -> Coordinate: if self.z is None: - return self.__class__(self.x * other, self.y * other) + return self.__class__(self[0] * other, self[1] * other) else: - return self.__class__(self.x * other, self.y * other, self.z * other) + return self.__class__(self[0] * other, self[1] * other, self[2] * other) - def __floordiv__(self, other) -> Coordinate: + def __floordiv__(self, other: int | float) -> Coordinate: if self.z is None: - return self.__class__(self.x // other, self.y // other) + return self.__class__(self[0] // other, self[1] // other) else: - return self.__class__(self.x // other, self.y // other, self.z // other) + return self.__class__(self[0] // other, self[1] // other, self[2] // other) - def __truediv__(self, other): + def __truediv__(self, other: int | float) -> Coordinate: return self // other def __str__(self): if self.z is None: - return "(%d,%d)" % (self.x, self.y) + return "(%d,%d)" % (self[0], self[1]) else: - return "(%d,%d,%d)" % (self.x, self.y, self.z) + return "(%d,%d,%d)" % (self[0], self[1], self[2]) def __repr__(self): if self.z is None: - return "%s(x=%d, y=%d)" % (self.__class__.__name__, self.x, self.y) + return "%s(x=%d, y=%d)" % (self.__class__.__name__, self[0], self[1]) else: return "%s(x=%d, y=%d, z=%d)" % ( self.__class__.__name__, - self.x, - self.y, - self.z, + self[0], + self[1], + self[2], ) @classmethod