From b349bc87fa0ec6574a8189b2cdc2c8573635263f Mon Sep 17 00:00:00 2001 From: Jared Denning <32106348+hewentto@users.noreply.github.com> Date: Fri, 28 Apr 2023 19:10:59 -0600 Subject: [PATCH 01/11] Added Geometry Methods! Added the following methods Rectangle.scale() RuneliteObject.scale() Rectangle.get_center_left RuneliteObject.distance_from_rect_left RuneliteObject.distance_from_top_left() --- src/utilities/geometry.py | 117 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 00b6e52f..66a2cab7 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -41,6 +41,46 @@ def __init__(self, left: int, top: int, width: int, height: int): self.width = width self.height = height + def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float = 0.5, anchor_y: float = 0.5): + """ + Scales the rectangle by the given factors for width and height, and adjusts its position based on the anchor point. + Args: + scale_width: The scaling factor for the width of the rectangle (default 1). + scale_height: The scaling factor for the height of the rectangle (default 1). + anchor_x: The horizontal anchor point for scaling (default 0.5, which corresponds to the center). + anchor_y: The vertical anchor point for scaling (default 0.5, which corresponds to the center). + Returns: + The Rectangle object, after scaling. + Examples: + rect = Rectangle(left=10, top=10, width=100, height=100) + + # Scale the rectangle by a factor of 2, using the center as the anchor point (default behavior). + rect.scale(2, 2) + + # Scale the rectangle by a factor of 2, using the top-left corner as the anchor point. + rect.scale(2, 2, anchor_x=0, anchor_y=0) + + # Scale the rectangle by a factor of 2, using the bottom-right corner as the anchor point. + rect.scale(2, 2, anchor_x=1, anchor_y=1) + + # Scale the rectangle width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. + rect.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) + """ + old_width = self.width + old_height = self.height + + self.width = int(self.width * scale_width) + self.height = int(self.height * scale_height) + + x_offset = int(old_width * (1 - scale_width) * anchor_x) + y_offset = int(old_height * (1 - scale_height) * anchor_y) + + self.left += x_offset + self.top += y_offset + + return self + + def set_rectangle_reference(self, rect): """ Sets the rectangle reference of the object. @@ -132,6 +172,14 @@ def get_top_left(self) -> Point: """ return Point(self.left, self.top) + def get_center_left(self) -> Point: + """ + Gets the center left point of the rectangle. + Returns: + A Point representing the center left of the rectangle. + """ + return Point(self.left, self.top + self.height // 2) + def get_top_right(self) -> Point: """ Gets the top right point of the rectangle. @@ -194,6 +242,49 @@ def __init__(self, x_min, x_max, y_min, y_max, width, height, center, axis): self._center = center self._axis = axis + def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float = 0.5, anchor_y: float = 0.5): + """ + Scales the RuneLiteObject by the given factors for width and height, and adjusts its position based on the anchor point. + Args: + scale_width: The scaling factor for the width of the RuneLiteObject (default 1). + scale_height: The scaling factor for the height of the RuneLiteObject (default 1). + anchor_x: The horizontal anchor point for scaling (default 0.5, which corresponds to the center). + anchor_y: The vertical anchor point for scaling (default 0.5, which corresponds to the center). + Returns: + The RuneLiteObject, after scaling. + Examples: + obj = RuneLiteObject(x_min=10, x_max=110, y_min=10, y_max=110, width=100, height=100, center=(60, 60), axis=None) + + # Scale the object by a factor of 2, using the center as the anchor point (default behavior). + obj.scale(2, 2) + + # Scale the object by a factor of 2, using the top-left corner as the anchor point. + obj.scale(2, 2, anchor_x=0, anchor_y=0) + + # Scale the object by a factor of 2, using the bottom-right corner as the anchor point. + obj.scale(2, 2, anchor_x=1, anchor_y=1) + + # Scale the object width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. + obj.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) + """ + old_width = self._width + old_height = self._height + + self._width = int(self._width * scale_width) + self._height = int(self._height * scale_height) + + x_offset = int(old_width * (1 - scale_width) * anchor_x) + y_offset = int(old_height * (1 - scale_height) * anchor_y) + + self._x_min += x_offset + self._x_max = self._x_min + self._width + self._y_min += y_offset + self._y_max = self._y_min + self._height + + self._center = (round((self._x_min + self._x_max) / 2), round((self._y_min + self._y_max) / 2)) + + return self + def set_rectangle_reference(self, rect: Rectangle): """ Sets the rectangle reference of the object. @@ -225,6 +316,32 @@ def distance_from_rect_center(self) -> float: center: Point = self.center() rect_center: Point = self.rect.get_center() return math.dist([center.x, center.y], [rect_center.x, rect_center.y]) + + def distance_from_rect_left(self) -> float: + """ + Gets the distance between the object and it's Rectangle parent left edge. + Useful for sorting lists of RuneLiteObjects. + Returns: + The distance from the point to the center of the object. + Note: + Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. + """ + center: Point = self.center() + rect_left: Point = self.rect.get_center_left() + return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) + + def distance_from_top_left(self) -> float: + """ + Gets the distance between the object and it's Rectangle parent left edge. + Useful for sorting lists of RuneLiteObjects. + Returns: + The distance from the point to the center of the object. + Note: + Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. + """ + center: Point = self.center() + rect_left: Point = self.rect.get_top_left() + return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) def random_point(self, custom_seeds: List[List[int]] = None) -> Point: """ From d9177170e4395866781651e557feb176b1a4e556 Mon Sep 17 00:00:00 2001 From: Jared Denning <32106348+hewentto@users.noreply.github.com> Date: Fri, 28 Apr 2023 21:33:45 -0600 Subject: [PATCH 02/11] updates scale methods returns new objects instead of modifying existing ones --- src/utilities/geometry.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 66a2cab7..f4b03fc8 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -69,16 +69,16 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float old_width = self.width old_height = self.height - self.width = int(self.width * scale_width) - self.height = int(self.height * scale_height) + new_width = int(self.width * scale_width) + new_height = int(self.height * scale_height) x_offset = int(old_width * (1 - scale_width) * anchor_x) y_offset = int(old_height * (1 - scale_height) * anchor_y) - self.left += x_offset - self.top += y_offset + new_left = self.left + x_offset + new_top = self.top + y_offset - return self + return Rectangle(new_left, new_top, new_width, new_height) def set_rectangle_reference(self, rect): @@ -270,20 +270,20 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float old_width = self._width old_height = self._height - self._width = int(self._width * scale_width) - self._height = int(self._height * scale_height) + new_width = int(self._width * scale_width) + new_height = int(self._height * scale_height) x_offset = int(old_width * (1 - scale_width) * anchor_x) y_offset = int(old_height * (1 - scale_height) * anchor_y) - self._x_min += x_offset - self._x_max = self._x_min + self._width - self._y_min += y_offset - self._y_max = self._y_min + self._height + new_x_min = self._x_min + x_offset + new_x_max = new_x_min + new_width + new_y_min = self._y_min + y_offset + new_y_max = new_y_min + new_height - self._center = (round((self._x_min + self._x_max) / 2), round((self._y_min + self._y_max) / 2)) + new_center = (round((new_x_min + new_x_max) / 2), round((new_y_min + new_y_max) / 2)) - return self + return RuneLiteObject(new_x_min, new_x_max, new_y_min, new_y_max, new_width, new_height, new_center, self._axis) def set_rectangle_reference(self, rect: Rectangle): """ From 01553b943f35127b2ad404cffd8c16df9b3b4991 Mon Sep 17 00:00:00 2001 From: Jared Denning <32106348+hewentto@users.noreply.github.com> Date: Fri, 28 Apr 2023 22:20:27 -0600 Subject: [PATCH 03/11] Update geometry.py created a copy, then scaled --- src/utilities/geometry.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index f4b03fc8..2b4695fe 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -267,6 +267,7 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float # Scale the object width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. obj.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) """ + newObject = self old_width = self._width old_height = self._height @@ -283,7 +284,15 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float new_center = (round((new_x_min + new_x_max) / 2), round((new_y_min + new_y_max) / 2)) - return RuneLiteObject(new_x_min, new_x_max, new_y_min, new_y_max, new_width, new_height, new_center, self._axis) + newObject._x_min = new_x_min + newObject._x_max = new_x_max + newObject._y_min = new_y_min + newObject._y_max = new_y_max + newObject._width = new_width + newObject._height = new_height + newObject._center = new_center + + return newObject def set_rectangle_reference(self, rect: Rectangle): """ From 8f7b7483d0730a59a24bbd025b8925e52dc0b6e7 Mon Sep 17 00:00:00 2001 From: Jared Denning <32106348+hewentto@users.noreply.github.com> Date: Sat, 29 Apr 2023 07:26:42 -0600 Subject: [PATCH 04/11] added top right distance calc --- src/utilities/geometry.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 2b4695fe..f00c65cb 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -341,7 +341,7 @@ def distance_from_rect_left(self) -> float: def distance_from_top_left(self) -> float: """ - Gets the distance between the object and it's Rectangle parent left edge. + Gets the distance between the object and it's Rectangle parent top left corner. Useful for sorting lists of RuneLiteObjects. Returns: The distance from the point to the center of the object. @@ -351,6 +351,19 @@ def distance_from_top_left(self) -> float: center: Point = self.center() rect_left: Point = self.rect.get_top_left() return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) + + def distance_from_top_right(self) -> float: + """ + Gets the distance between the object and it's Rectangle parent top right corner. + Useful for sorting lists of RuneLiteObjects. + Returns: + The distance from the point to the center of the object. + Note: + Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. + """ + center: Point = self.center() + rect_left: Point = self.rect.get_top_right() + return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) def random_point(self, custom_seeds: List[List[int]] = None) -> Point: """ From 617a9a70127501acd94a6f3df07fbf53b0c58a43 Mon Sep 17 00:00:00 2001 From: Jared Denning <32106348+hewentto@users.noreply.github.com> Date: Sat, 29 Apr 2023 08:12:51 -0600 Subject: [PATCH 05/11] added scaling for axis --- src/utilities/geometry.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index f00c65cb..8ca36d7a 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -284,6 +284,24 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float new_center = (round((new_x_min + new_x_max) / 2), round((new_y_min + new_y_max) / 2)) + scaled_axis = np.empty((0, 2), dtype=self._axis.dtype) + for point in self._axis: + # Calculate the scaled coordinates + scaled_x = int(new_x_min + (point[0] - self._x_min) * scale_width) + scaled_y = int(new_y_min + (point[1] - self._y_min) * scale_height) + + # Calculate the intermediate points between the original and scaled coordinates + num_points = max(abs(scaled_x - point[0]), abs(scaled_y - point[1])) + if num_points > 0: + x_coords = np.linspace(point[0], scaled_x, num=num_points+1, dtype=int) + y_coords = np.linspace(point[1], scaled_y, num=num_points+1, dtype=int) + intermediate_points = np.column_stack((x_coords[1:], y_coords[1:])) + scaled_axis = np.concatenate((scaled_axis, intermediate_points), axis=0) + + # Add the scaled point to the scaled axis + scaled_point = np.array([[scaled_x, scaled_y]], dtype=self._axis.dtype) + scaled_axis = np.concatenate((scaled_axis, scaled_point)) + newObject._x_min = new_x_min newObject._x_max = new_x_max newObject._y_min = new_y_min @@ -291,6 +309,7 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float newObject._width = new_width newObject._height = new_height newObject._center = new_center + newObject._axis = scaled_axis return newObject From 6416c039d2fd6d647a6507aa172f9b9322ef8ab4 Mon Sep 17 00:00:00 2001 From: Jared Denning <32106348+hewentto@users.noreply.github.com> Date: Sat, 29 Apr 2023 08:49:52 -0600 Subject: [PATCH 06/11] changed axis scaling --- src/utilities/geometry.py | 70 +++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 8ca36d7a..b61609ce 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -81,6 +81,46 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float return Rectangle(new_left, new_top, new_width, new_height) + def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float = 0.5, anchor_y: float = 0.5): + """ + Scales the rectangle by the given factors for width and height, and adjusts its position based on the anchor point. + Args: + scale_width: The scaling factor for the width of the rectangle (default 1). + scale_height: The scaling factor for the height of the rectangle (default 1). + anchor_x: The horizontal anchor point for scaling (default 0.5, which corresponds to the center). + anchor_y: The vertical anchor point for scaling (default 0.5, which corresponds to the center). + Returns: + The Rectangle object, after scaling. + Examples: + rect = Rectangle(left=10, top=10, width=100, height=100) + + # Scale the rectangle by a factor of 2, using the center as the anchor point (default behavior). + rect.scale(2, 2) + + # Scale the rectangle by a factor of 2, using the top-left corner as the anchor point. + rect.scale(2, 2, anchor_x=0, anchor_y=0) + + # Scale the rectangle by a factor of 2, using the bottom-right corner as the anchor point. + rect.scale(2, 2, anchor_x=1, anchor_y=1) + + # Scale the rectangle width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. + rect.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) + """ + old_width = self.width + old_height = self.height + + new_width = int(self.width * scale_width) + new_height = int(self.height * scale_height) + + x_offset = int(old_width * (1 - scale_width) * anchor_x) + y_offset = int(old_height * (1 - scale_height) * anchor_y) + + new_left = self.left + x_offset + new_top = self.top + y_offset + + return Rectangle(new_left, new_top, new_width, new_height) + + def set_rectangle_reference(self, rect): """ Sets the rectangle reference of the object. @@ -180,6 +220,14 @@ def get_center_left(self) -> Point: """ return Point(self.left, self.top + self.height // 2) + def get_center_left(self) -> Point: + """ + Gets the center left point of the rectangle. + Returns: + A Point representing the center left of the rectangle. + """ + return Point(self.left, self.top + self.height // 2) + def get_top_right(self) -> Point: """ Gets the top right point of the rectangle. @@ -284,23 +332,11 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float new_center = (round((new_x_min + new_x_max) / 2), round((new_y_min + new_y_max) / 2)) - scaled_axis = np.empty((0, 2), dtype=self._axis.dtype) - for point in self._axis: - # Calculate the scaled coordinates - scaled_x = int(new_x_min + (point[0] - self._x_min) * scale_width) - scaled_y = int(new_y_min + (point[1] - self._y_min) * scale_height) - - # Calculate the intermediate points between the original and scaled coordinates - num_points = max(abs(scaled_x - point[0]), abs(scaled_y - point[1])) - if num_points > 0: - x_coords = np.linspace(point[0], scaled_x, num=num_points+1, dtype=int) - y_coords = np.linspace(point[1], scaled_y, num=num_points+1, dtype=int) - intermediate_points = np.column_stack((x_coords[1:], y_coords[1:])) - scaled_axis = np.concatenate((scaled_axis, intermediate_points), axis=0) - - # Add the scaled point to the scaled axis - scaled_point = np.array([[scaled_x, scaled_y]], dtype=self._axis.dtype) - scaled_axis = np.concatenate((scaled_axis, scaled_point)) + # Generate all possible combinations of x and y coordinates inside the bounding box + x_coords = np.arange(new_x_min, new_x_max + 1) + y_coords = np.arange(new_y_min, new_y_max + 1) + xx, yy = np.meshgrid(x_coords, y_coords) + scaled_axis = np.column_stack((xx.ravel(), yy.ravel())) newObject._x_min = new_x_min newObject._x_max = new_x_max From 501053d661176059ca671a4b683a656e49bd98b1 Mon Sep 17 00:00:00 2001 From: Kellen Evoy <44652363+kelltom@users.noreply.github.com> Date: Sun, 30 Apr 2023 17:49:56 -0400 Subject: [PATCH 07/11] Linting --- src/utilities/geometry.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index b61609ce..18e367d4 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -56,13 +56,13 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float # Scale the rectangle by a factor of 2, using the center as the anchor point (default behavior). rect.scale(2, 2) - + # Scale the rectangle by a factor of 2, using the top-left corner as the anchor point. rect.scale(2, 2, anchor_x=0, anchor_y=0) - + # Scale the rectangle by a factor of 2, using the bottom-right corner as the anchor point. rect.scale(2, 2, anchor_x=1, anchor_y=1) - + # Scale the rectangle width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. rect.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) """ @@ -80,7 +80,6 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float return Rectangle(new_left, new_top, new_width, new_height) - def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float = 0.5, anchor_y: float = 0.5): """ Scales the rectangle by the given factors for width and height, and adjusts its position based on the anchor point. @@ -96,13 +95,13 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float # Scale the rectangle by a factor of 2, using the center as the anchor point (default behavior). rect.scale(2, 2) - + # Scale the rectangle by a factor of 2, using the top-left corner as the anchor point. rect.scale(2, 2, anchor_x=0, anchor_y=0) - + # Scale the rectangle by a factor of 2, using the bottom-right corner as the anchor point. rect.scale(2, 2, anchor_x=1, anchor_y=1) - + # Scale the rectangle width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. rect.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) """ @@ -120,7 +119,6 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float return Rectangle(new_left, new_top, new_width, new_height) - def set_rectangle_reference(self, rect): """ Sets the rectangle reference of the object. @@ -380,7 +378,7 @@ def distance_from_rect_center(self) -> float: center: Point = self.center() rect_center: Point = self.rect.get_center() return math.dist([center.x, center.y], [rect_center.x, rect_center.y]) - + def distance_from_rect_left(self) -> float: """ Gets the distance between the object and it's Rectangle parent left edge. @@ -393,7 +391,7 @@ def distance_from_rect_left(self) -> float: center: Point = self.center() rect_left: Point = self.rect.get_center_left() return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) - + def distance_from_top_left(self) -> float: """ Gets the distance between the object and it's Rectangle parent top left corner. @@ -406,7 +404,7 @@ def distance_from_top_left(self) -> float: center: Point = self.center() rect_left: Point = self.rect.get_top_left() return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) - + def distance_from_top_right(self) -> float: """ Gets the distance between the object and it's Rectangle parent top right corner. From 9e88e99aaad27e98c2a3c7864d759db1a46b4cf8 Mon Sep 17 00:00:00 2001 From: Kellen Evoy <44652363+kelltom@users.noreply.github.com> Date: Sun, 30 Apr 2023 17:53:18 -0400 Subject: [PATCH 08/11] Removed duplicate method --- src/utilities/geometry.py | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 18e367d4..e4366da8 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -80,45 +80,6 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float return Rectangle(new_left, new_top, new_width, new_height) - def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float = 0.5, anchor_y: float = 0.5): - """ - Scales the rectangle by the given factors for width and height, and adjusts its position based on the anchor point. - Args: - scale_width: The scaling factor for the width of the rectangle (default 1). - scale_height: The scaling factor for the height of the rectangle (default 1). - anchor_x: The horizontal anchor point for scaling (default 0.5, which corresponds to the center). - anchor_y: The vertical anchor point for scaling (default 0.5, which corresponds to the center). - Returns: - The Rectangle object, after scaling. - Examples: - rect = Rectangle(left=10, top=10, width=100, height=100) - - # Scale the rectangle by a factor of 2, using the center as the anchor point (default behavior). - rect.scale(2, 2) - - # Scale the rectangle by a factor of 2, using the top-left corner as the anchor point. - rect.scale(2, 2, anchor_x=0, anchor_y=0) - - # Scale the rectangle by a factor of 2, using the bottom-right corner as the anchor point. - rect.scale(2, 2, anchor_x=1, anchor_y=1) - - # Scale the rectangle width by a factor of 1.5 and height by a factor of 2, using the top-right corner as the anchor point. - rect.scale(scale_width=1.5, scale_height=2, anchor_x=1, anchor_y=0) - """ - old_width = self.width - old_height = self.height - - new_width = int(self.width * scale_width) - new_height = int(self.height * scale_height) - - x_offset = int(old_width * (1 - scale_width) * anchor_x) - y_offset = int(old_height * (1 - scale_height) * anchor_y) - - new_left = self.left + x_offset - new_top = self.top + y_offset - - return Rectangle(new_left, new_top, new_width, new_height) - def set_rectangle_reference(self, rect): """ Sets the rectangle reference of the object. From 7f87e1a2c877e0f7bf4b5bc9b79bedd038185e20 Mon Sep 17 00:00:00 2001 From: Kellen Evoy <44652363+kelltom@users.noreply.github.com> Date: Sun, 30 Apr 2023 18:33:44 -0400 Subject: [PATCH 09/11] Added distance_from_point universal key methods --- src/model/runelite_bot.py | 8 +++---- src/utilities/geometry.py | 49 ++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/model/runelite_bot.py b/src/model/runelite_bot.py index 64281f2a..5ff0fa87 100644 --- a/src/model/runelite_bot.py +++ b/src/model/runelite_bot.py @@ -132,8 +132,8 @@ def pick_up_loot(self, items: Union[str, List[str]], supress_warning=True) -> bo # Locate Ground Items text if item_text := ocr.find_text(items, self.win.game_view, ocr.PLAIN_11, clr.PURPLE): for item in item_text: - item.set_rectangle_reference(self.win.game_view) - sorted_by_closest = sorted(item_text, key=Rectangle.distance_from_center) + item.set_parent_rectangle(self.win.game_view) + sorted_by_closest = sorted(item_text, key=Rectangle.distance_from_point) self.mouse.move_to(sorted_by_closest[0].get_center()) for _ in range(5): if self.mouseover_text(contains=["Take"] + items, color=[clr.OFF_WHITE, clr.OFF_ORANGE]): @@ -197,7 +197,7 @@ def get_nearest_tagged_NPC(self, include_in_combat: bool = False) -> RuneLiteObj print("No tagged NPCs found.") return None for obj in objs: - obj.set_rectangle_reference(self.win.game_view) + obj.set_parent_rectangle(self.win.game_view) # Sort shapes by distance from player objs = sorted(objs, key=RuneLiteObject.distance_from_rect_center) if include_in_combat: @@ -220,7 +220,7 @@ def get_all_tagged_in_rect(self, rect: Rectangle, color: clr.Color) -> List[Rune isolated_colors = clr.isolate_colors(img_rect, color) objs = rcv.extract_objects(isolated_colors) for obj in objs: - obj.set_rectangle_reference(rect) + obj.set_parent_rectangle(rect) return objs def get_nearest_tag(self, color: clr.Color) -> RuneLiteObject: diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index e4366da8..96e1a6a8 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -22,7 +22,7 @@ class Rectangle: """ subtract_list: List[dict] = [] - reference_rect = None + parent_rect = None def __init__(self, left: int, top: int, width: int, height: int): """ @@ -80,14 +80,14 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float return Rectangle(new_left, new_top, new_width, new_height) - def set_rectangle_reference(self, rect): + def set_parent_rectangle(self, rect): """ Sets the rectangle reference of the object. Args: rect: A reference to the the rectangle that this object belongs in (E.g., Bot.win.game_view). """ - self.reference_rect = rect + self.parent_rect = rect @classmethod def from_points(cls, start_point: Point, end_point: Point): @@ -149,19 +149,28 @@ def get_center(self) -> Point: """ return Point(self.left + self.width // 2, self.top + self.height // 2) - # TODO: Consider changing to this to accept a Point to check against; `distance_from(point: Point)` - def distance_from_center(self) -> Point: + def distance_from_point(self, reference_point: Point = None) -> float: """ - Gets the distance between the object and it's Rectangle parent center. + Gets the distance between the object and the given reference point. Useful for sorting lists of Rectangles. + Args: + reference_point: A Point representing the reference point for distance calculation. + Default: The center of the parent rectangle, if available. Returns: The distance from the point to the center of the object. + Example: + >>> # Sort based on an arbitrary point + >>> arbitrary_point = Point(100, 200) + >>> sorted_by_arbitrary_point = sorted(some_rectangles, key=lambda rect: rect.distance_from_point(arbitrary_point)) """ - if self.reference_rect is None: - raise ReferenceError("A Rectangle being sorted is missing a reference to the Rectangle it's contained in and therefore cannot be sorted.") + if reference_point is None: + if self.parent_rect is not None: + reference_point = self.parent_rect.get_center() + else: + raise ValueError("A reference point must be provided if there is no parent rectangle.") + center: Point = self.get_center() - rect_center: Point = self.reference_rect.get_center() - return math.dist([center.x, center.y], [rect_center.x, rect_center.y]) + return math.dist([center.x, center.y], [reference_point.x, reference_point.y]) def get_top_left(self) -> Point: """ @@ -308,9 +317,9 @@ def scale(self, scale_width: float = 1, scale_height: float = 1, anchor_x: float return newObject - def set_rectangle_reference(self, rect: Rectangle): + def set_parent_rectangle(self, rect: Rectangle): """ - Sets the rectangle reference of the object. + Sets the parent rectangle of the object. Args: rect: A reference to the the rectangle that this object belongs in (E.g., Bot.win.game_view). @@ -319,7 +328,7 @@ def set_rectangle_reference(self, rect: Rectangle): def center(self) -> Point: # sourcery skip: raise-specific-error """ - Gets the center of the object relative to the containing Rectangle. + Gets the center of the object relative to the screen. Returns: A Point. """ @@ -327,6 +336,20 @@ def center(self) -> Point: # sourcery skip: raise-specific-error raise ReferenceError("The RuneLiteObject is missing a reference to the Rectangle it's contained in and therefore the center cannot be determined.") return Point(self._center[0] + self.rect.left, self._center[1] + self.rect.top) + def distance_from_point(self, point: Point) -> float: + """ + Gets the distance between the object and the given point. + Args: + point: A tuple (x, y) representing the coordinates of the point. + Returns: + The distance from the point to the center of the object. + Example: + >>> reference_point = Point(300, 200) + >>> sorted_by_distance = sorted(rl_objects, key=lambda obj: obj.distance_from_point(reference_point)) + """ + center: Point = self.center() + return math.dist([center.x, center.y], [point.x, point.y]) + def distance_from_rect_center(self) -> float: """ Gets the distance between the object and it's Rectangle parent center. From 4d482b3237e3729b8494a97e30d9861f69f36955 Mon Sep 17 00:00:00 2001 From: Kellen Evoy <44652363+kelltom@users.noreply.github.com> Date: Sun, 30 Apr 2023 23:20:09 -0400 Subject: [PATCH 10/11] Renamed RLObject's center method to be more consistent --- src/utilities/geometry.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 96e1a6a8..8e5565c9 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -326,7 +326,7 @@ def set_parent_rectangle(self, rect: Rectangle): """ self.rect = rect - def center(self) -> Point: # sourcery skip: raise-specific-error + def get_center(self) -> Point: """ Gets the center of the object relative to the screen. Returns: @@ -347,7 +347,7 @@ def distance_from_point(self, point: Point) -> float: >>> reference_point = Point(300, 200) >>> sorted_by_distance = sorted(rl_objects, key=lambda obj: obj.distance_from_point(reference_point)) """ - center: Point = self.center() + center: Point = self.get_center() return math.dist([center.x, center.y], [point.x, point.y]) def distance_from_rect_center(self) -> float: @@ -359,7 +359,7 @@ def distance_from_rect_center(self) -> float: Note: Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. """ - center: Point = self.center() + center: Point = self.get_center() rect_center: Point = self.rect.get_center() return math.dist([center.x, center.y], [rect_center.x, rect_center.y]) @@ -372,7 +372,7 @@ def distance_from_rect_left(self) -> float: Note: Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. """ - center: Point = self.center() + center: Point = self.get_center() rect_left: Point = self.rect.get_center_left() return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) @@ -385,7 +385,7 @@ def distance_from_top_left(self) -> float: Note: Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. """ - center: Point = self.center() + center: Point = self.get_center() rect_left: Point = self.rect.get_top_left() return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) @@ -398,7 +398,7 @@ def distance_from_top_right(self) -> float: Note: Only use this if you're sorting a list of RuneLiteObjects that are contained in the same Rectangle. """ - center: Point = self.center() + center: Point = self.get_center() rect_left: Point = self.rect.get_top_right() return math.dist([center.x, center.y], [rect_left.x, rect_left.y]) @@ -415,7 +415,7 @@ def random_point(self, custom_seeds: List[List[int]] = None) -> Point: if custom_seeds is None: custom_seeds = rd.random_seeds(mod=(self._center[0] + self._center[1])) x, y = rd.random_point_in(self._x_min, self._y_min, self._width, self._height, custom_seeds) - return self.__relative_point([x, y]) if self.__point_exists([x, y]) else self.center() + return self.__relative_point([x, y]) if self.__point_exists([x, y]) else self.get_center() def __relative_point(self, point: List[int]) -> Point: """ From 76ccd690749300724793006bb93010b2e2bfd9a6 Mon Sep 17 00:00:00 2001 From: Kellen Evoy <44652363+kelltom@users.noreply.github.com> Date: Sun, 7 May 2023 16:26:22 -0400 Subject: [PATCH 11/11] Added some test code --- src/utilities/geometry.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/utilities/geometry.py b/src/utilities/geometry.py index 8e5565c9..1e397872 100644 --- a/src/utilities/geometry.py +++ b/src/utilities/geometry.py @@ -1,11 +1,18 @@ import math +import os from typing import List, NamedTuple import cv2 import mss import numpy as np +if __name__ == "__main__": + import sys + + sys.path[0] = os.path.dirname(sys.path[0]) + import utilities.random_util as rd +import utilities.debug as debug Point = NamedTuple("Point", x=int, y=int) @@ -434,3 +441,26 @@ def __point_exists(self, p: list) -> bool: p: The point to check in the format [x, y]. """ return (self._axis == np.array(p)).all(axis=1).any() + + +if __name__ == "__main__": + """ + Run this file directly to test this module. You must have an instance of RuneLite open for this to work. + """ + # Get/focus the RuneLite window currently running + win = debug.get_test_window() + + # Screenshot the chat box and display it + img = win.chat.screenshot() + cv2.imshow("Chat Box", img) + cv2.waitKey(0) + + # Screenshot control panel and display it + img = win.control_panel.screenshot() + cv2.imshow("Control Panel", img) + cv2.waitKey(0) + + # Screenshot game view and display it + img = win.game_view.screenshot() + cv2.imshow("Game View", img) + cv2.waitKey(0)