Coordinate() now behaves more tupley-like (methods not accept tuples as parameters, including __add__ and __sub__)
This commit is contained in:
parent
0408432e3d
commit
32c07d2913
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user