-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update docs and add convenience methods to coordinate classes. #60
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,39 +17,33 @@ def val_inside(val: float, bound1: float, bound2: float) -> bool: | |
|
||
|
||
class Coordinate2: | ||
"""""" | ||
""" A 2 dimentional coordinate | ||
""" | ||
|
||
def __init__(self, x: float, y: float): | ||
"""""" | ||
self._x = x | ||
self._y = y | ||
|
||
@property | ||
def x(self) -> float: | ||
"""""" | ||
return self._x | ||
|
||
@property | ||
def y(self) -> float: | ||
"""""" | ||
return self._y | ||
|
||
@x.setter | ||
def x(self, value: float) -> None: | ||
"""""" | ||
self._x = value | ||
|
||
@y.setter | ||
def y(self, value: float) -> None: | ||
"""""" | ||
self._y = value | ||
|
||
def __getitem__(self, key): | ||
"""""" | ||
return self._int_to_coord(key) | ||
|
||
def __setitem__(self, key, val): | ||
"""""" | ||
if key == 0: | ||
self.x = val | ||
elif key == 1: | ||
|
@@ -58,13 +52,105 @@ def __setitem__(self, key, val): | |
raise ValueError("Invalid index.") | ||
|
||
def __eq__(self, other: Coordinate2) -> bool: | ||
"""""" | ||
if self.x == other.x and self.y == other.y: | ||
return True | ||
return False | ||
|
||
def __add__(self, other: Coordinate2) -> Coordinate2: | ||
""" | ||
Positive translation by another Coordinate2. | ||
This does not modify the coordinate. | ||
|
||
:param other: The coordinate to translate by | ||
:type other: Coordinate2 | ||
:return: The translated coordinate. | ||
:rtype: Coordinate2 | ||
""" | ||
t = CSTransform() | ||
t.Translate((other.x, other.y, 0)) | ||
return self.transform(t) | ||
|
||
def __sub__(self, other: Coordinate2) -> Coordinate2: | ||
""" | ||
Negative translation by another Coordinate2. | ||
This does not modify the coordinate. | ||
|
||
:param other: The coordinate to translate by | ||
:type other: Coordinate2 | ||
:return: The translated coordinate. | ||
:rtype: Coordinate2 | ||
""" | ||
t = CSTransform() | ||
t.Translate((-other.x, -other.y, 0)) | ||
return self.transform(t) | ||
|
||
def __mul__(self, scale: float | Coordinate2) -> Coordinate2: | ||
""" | ||
Scale by a specified value. | ||
This does not modify the coordinate. | ||
|
||
:param scale: The scale factor. If a float, scale x and y by this value. | ||
If a Coordinate2, use separate x and y scale factors. | ||
:type scale: float | Coordinate2 | ||
:return: The scaled coordinate. | ||
:rtype: Coordinate2 | ||
""" | ||
if isinstance(scale, Coordinate2): | ||
scale = scale.x, scale.y, 1 | ||
t = CSTransform() | ||
t.Scale(scale) | ||
return self.transform(t) | ||
|
||
def __truediv__(self, scale: float | Coordinate2) -> Coordinate2: | ||
""" | ||
Scale but a specified value. This is equivalent to A * (1 / scale) | ||
This does not modify the coordinate. | ||
|
||
:param scale: The scale factor. If a float, scale x and y by this value. | ||
If a Coordinate2, use separate x and y scale factors. | ||
:type scale: float | Coordinate2 | ||
:return: The scaled coordinate. | ||
:rtype: Coordinate2 | ||
""" | ||
if isinstance(scale, Coordinate2): | ||
scale = 1/scale.x, 1/scale.y, 1 | ||
else: | ||
scale = 1/scale | ||
t = CSTransform() | ||
t.Scale(scale) | ||
return self.transform(t) | ||
|
||
def __neg__(self) -> Coordinate2: | ||
""" | ||
Negative both coordinate values. | ||
This does not modify the coordinate. | ||
|
||
:return: The negated coordinate | ||
:rtype: Coordinate2 | ||
""" | ||
return Coordinate2(-self.x, -self.y) | ||
|
||
def __abs__(self) -> Coordinate2: | ||
""" | ||
Absolute value of both coodinate values. | ||
This does not modify the coordinate. | ||
|
||
:return: The new coordinate. | ||
:rtype: Coordinate2 | ||
""" | ||
return Coordinate2(abs(self.x), abs(self.y)) | ||
Comment on lines
+133
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is fine. I was initially a bit on the fence because I normally think of the absolute value of a coordinate being its distance from the origin, but I think you're right this makes sense here. |
||
|
||
def __round__(self, ndigits: int=0) -> Coordinate2: | ||
""" | ||
Round to a specified precision. Calls round_prec() | ||
This does not modify the coordinate. | ||
|
||
:return: A new coordinate with the specified precision. | ||
:rtype: Coordinate2 | ||
""" | ||
return self.round_prec(ndigits) | ||
Comment on lines
+143
to
+151
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this, but let's get rid of |
||
|
||
def _int_to_coord(self, val) -> float: | ||
"""""" | ||
if val == 0: | ||
return self.x | ||
elif val == 1: | ||
|
@@ -76,6 +162,9 @@ def coordinate_list(self) -> np.ndarray: | |
""" | ||
Retrieve an array of coordinate values for use by openems, | ||
which requires coordinates in a form that can be indexed. | ||
|
||
:return: The x, y coordinates | ||
:rtype: np.ndarray | ||
""" | ||
return np.array([self._x, self._y]) | ||
|
||
|
@@ -85,17 +174,33 @@ def transform(self, transform: CSTransform) -> Coordinate2: | |
simply returns a new transformed coordinate. If you want to | ||
replace the old coordinate you must assign it to the result of | ||
this function. | ||
|
||
:param transform: The transformation | ||
:type transform: CSTransform | ||
:return: The new coordinate | ||
:rtype: Coordinate2 | ||
""" | ||
clist = list(self.coordinate_list()) | ||
clist.append(0) | ||
tclist = transform.Transform(clist) | ||
return Coordinate2(tclist[0], tclist[1]) | ||
|
||
def round_prec(self, prec: int) -> Coordinate2: | ||
"""""" | ||
""" | ||
Round the coordinate to a specified precision. | ||
This does not modify the coordinate. | ||
|
||
:param prec: The number of decimal places to round. | ||
:type prec: int | ||
:return: A new coordinate with the rounded values. | ||
:rtype: Coordinate2 | ||
""" | ||
clist = self.coordinate_list() | ||
clist = np.around(clist, prec) | ||
return Coordinate2(clist[0], clist[1]) | ||
|
||
def __repr__(self) -> str: | ||
return f'Coordinate2({self.x}, {self.y})' | ||
|
||
|
||
def list_center2(coords: List[Coordinate2]) -> Coordinate2: | ||
|
@@ -189,6 +294,100 @@ def __eq__(self, other: Coordinate3): | |
if self.x == other.x and self.y == other.y and self.z == other.z: | ||
return True | ||
return False | ||
|
||
def __add__(self, other: Coordinate3) -> Coordinate3: | ||
""" | ||
Positive translation by another Coordinate3. | ||
This does not modify the coordinate. | ||
|
||
:param other: The coordinate to translate by | ||
:type other: Coordinate3 | ||
:return: The translated coordinate. | ||
:rtype: Coordinate3 | ||
""" | ||
t = CSTransform() | ||
t.Translate((other.x, other.y, other.z)) | ||
return self.transform(t) | ||
|
||
def __sub__(self, other: Coordinate3) -> Coordinate3: | ||
""" | ||
Negative translation by another Coordinate3. | ||
This does not modify the coordinate. | ||
|
||
:param other: The coordinate to translate by | ||
:type other: Coordinate3 | ||
:return: The translated coordinate. | ||
:rtype: Coordinate3 | ||
""" | ||
t = CSTransform() | ||
t.Translate((-other.x, -other.y, -other.z)) | ||
return self.transform(t) | ||
|
||
def __mul__(self, scale: float | Coordinate3) -> Coordinate3: | ||
""" | ||
Scale by a specified value. | ||
This does not modify the coordinate. | ||
|
||
:param scale: The scale factor. If a float, scale x and y by this value. | ||
If a Coordinate3, use separate x, y, and z scale factors. | ||
:type scale: float | Coordinate3 | ||
:return: The scaled coordinate. | ||
:rtype: Coordinate3 | ||
""" | ||
if isinstance(scale, Coordinate3): | ||
scale = scale.x, scale.y, scale.z | ||
t = CSTransform() | ||
t.Scale(scale) | ||
return self.transform(t) | ||
|
||
def __truediv__(self, scale: float | Coordinate3) -> Coordinate3: | ||
""" | ||
Scale but a specified value. This is equivalent to A * (1 / scale) | ||
This does not modify the coordinate. | ||
|
||
:param scale: The scale factor. If a float, scale x and y by this value. | ||
If a Coordinate3, use separate x, y, and z scale factors. | ||
:type scale: float | Coordinate3 | ||
:return: The scaled coordinate. | ||
:rtype: Coordinate3 | ||
""" | ||
if isinstance(scale, Coordinate3): | ||
scale = 1/scale.x, 1/scale.y, 1/scale.z | ||
else: | ||
scale = 1/scale | ||
t = CSTransform() | ||
t.Scale(scale) | ||
return self.transform(t) | ||
|
||
def __neg__(self) -> Coordinate3: | ||
""" | ||
Negative both coordinate values. | ||
This does not modify the coordinate. | ||
|
||
:return: The negated coordinate | ||
:rtype: Coordinate3 | ||
""" | ||
return Coordinate3(-self.x, -self.y, -self.z) | ||
|
||
def __abs__(self) -> Coordinate3: | ||
""" | ||
Absolute value of both coodinate values. | ||
This does not modify the coordinate. | ||
|
||
:return: The new coordinate. | ||
:rtype: Coordinate3 | ||
""" | ||
return Coordinate3(abs(self.x), abs(self.y), abs(self.z)) | ||
|
||
def __round__(self, ndigits: int=0) -> Coordinate3: | ||
""" | ||
Round to a specified precision. Calls round_prec() | ||
This does not modify the coordinate. | ||
|
||
:return: A new coordinate with the specified precision. | ||
:rtype: Coordinate3 | ||
""" | ||
return self.round_prec(ndigits) | ||
|
||
def _int_to_coord(self, val): | ||
"""""" | ||
|
@@ -200,6 +399,9 @@ def _int_to_coord(self, val): | |
return self.z | ||
else: | ||
raise ValueError("Invalid index.") | ||
|
||
def __repr__(self) -> str: | ||
return f'Coordinate3({self.x}, {self.y}, {self.z})' | ||
|
||
|
||
class Axis: | ||
|
@@ -355,6 +557,9 @@ def __init__(self, min_corner: C2Tuple, max_corner: C2Tuple): | |
"""""" | ||
self._min_corner = c2_maybe_tuple(min_corner) | ||
self._max_corner = c2_maybe_tuple(max_corner) | ||
|
||
def __repr__(self) -> str: | ||
return f'Box2({self.min_corner}, {self.max_corner})' | ||
|
||
@property | ||
def min_corner(self) -> Coordinate2: | ||
|
@@ -439,6 +644,30 @@ def has_zero_dim(self) -> bool: | |
): | ||
return True | ||
return False | ||
|
||
def __add__(self, coord: Coordinate2) -> Box2: | ||
""" | ||
Translate by a specified coordinate. | ||
This does not modify the box | ||
|
||
:param coord: The coordinate to transform | ||
:type coord: Coordinate2 | ||
:return: The translated box | ||
:rtype: Box2 | ||
""" | ||
return Box2(self.min_corner + coord, self.max_corner + coord) | ||
|
||
def __sub__(self, coord: Coordinate2) -> Box2: | ||
""" | ||
Translate by a specified coordinate. | ||
This does not modify the box | ||
|
||
:param coord: The coordinate to transform | ||
:type coord: Coordinate2 | ||
:return: The translated box | ||
:rtype: Box2 | ||
""" | ||
return Box2(self.min_corner - coord, self.max_corner - coord) | ||
|
||
|
||
class Box3: | ||
|
@@ -618,6 +847,30 @@ def has_zero_dim(self) -> bool: | |
): | ||
return True | ||
return False | ||
|
||
def __add__(self, coord: Coordinate3) -> Box3: | ||
""" | ||
Translate by a specified coordinate. | ||
This does not modify the box | ||
|
||
:param coord: The coordinate to transform | ||
:type coord: Coordinate3 | ||
:return: The translated box | ||
:rtype: Box3 | ||
""" | ||
return Box3(self.min_corner + coord, self.max_corner + coord) | ||
|
||
def __sub__(self, coord: Coordinate3) -> Box3: | ||
""" | ||
Translate by a specified coordinate. | ||
This does not modify the box | ||
|
||
:param coord: The coordinate to transform | ||
:type coord: Coordinate3 | ||
:return: The translated box | ||
:rtype: Box3 | ||
""" | ||
return Box3(self.min_corner - coord, self.max_corner - coord) | ||
|
||
|
||
def box_overlap(box1: Box3, box2: Box3) -> bool: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of overloading operators for coordinate2, etc. but my personal preference is that it be done without transforms. Transforms are a bit overkill here and make it a bit harder to read IMO. So, something like
Same goes for the rest.