From f72604836e592ec260a7f14feac31c60216fb4f2 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Sat, 20 May 2023 19:15:22 +0530 Subject: [PATCH 1/2] PKG: Add package lpconvexhull --- integration_tests/lpconvexhull/__init__.py | 1 + .../lpconvexhull/lpconvexhull_main.py | 56 +++++++++++++++++++ integration_tests/lpconvexhull/utils.py | 29 ++++++++++ 3 files changed, 86 insertions(+) create mode 100644 integration_tests/lpconvexhull/__init__.py create mode 100644 integration_tests/lpconvexhull/lpconvexhull_main.py create mode 100644 integration_tests/lpconvexhull/utils.py diff --git a/integration_tests/lpconvexhull/__init__.py b/integration_tests/lpconvexhull/__init__.py new file mode 100644 index 0000000000..7744538843 --- /dev/null +++ b/integration_tests/lpconvexhull/__init__.py @@ -0,0 +1 @@ +from .lpconvexhull_main import convex_hull diff --git a/integration_tests/lpconvexhull/lpconvexhull_main.py b/integration_tests/lpconvexhull/lpconvexhull_main.py new file mode 100644 index 0000000000..7bdfa62af2 --- /dev/null +++ b/integration_tests/lpconvexhull/lpconvexhull_main.py @@ -0,0 +1,56 @@ +from lpython import i32 +from .utils import min, distance + +def orientation(p: tuple[i32, i32], q: tuple[i32, i32], r: tuple[i32, i32]) -> i32: + # Function to find the orientation of triplet (p, q, r) + # Returns the following values: + # 0: Colinear + # 1: Clockwise + # 2: Counterclockwise + value: i32 = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]) + if value == 0: + return 0 # Colinear + elif value > 0: + return 1 # Clockwise + else: + return 2 # Counterclockwise + + +def convex_hull(points: list[tuple[i32, i32]]) -> list[tuple[i32, i32]]: + """Finds the convex hull of a set of points. + + Args: + points: A list of points. + + Returns: + A list of points that form the convex hull. + """ + + n: i32 = len(points) + if n < 3: + return [(-1, -1)] # Convex hull not possible + + # Find the leftmost point + leftmost: tuple[i32, i32] = min(points) + hull: list[tuple[i32, i32]] = [] + + p: tuple[i32, i32] = leftmost + + while True: + hull.append(p) + q: tuple[i32, i32] = points[0] + + r: tuple[i32, i32] + for r in points: + if r == p or r == q: + continue + direction: i32 = orientation(p, q, r) + if direction == 1 or (direction == 0 and distance(p, r) > distance(p, q)): + q = r + + p = q + + if p == leftmost: + break + + return hull diff --git a/integration_tests/lpconvexhull/utils.py b/integration_tests/lpconvexhull/utils.py new file mode 100644 index 0000000000..a414cb7fa7 --- /dev/null +++ b/integration_tests/lpconvexhull/utils.py @@ -0,0 +1,29 @@ +from lpython import i32, f64 + +def min(points: list[tuple[i32, i32]]) -> tuple[i32, i32]: + """Finds the left-most point in a list of points. + + Args: + points: A list of points. + + Returns: + The left-most point in the list. + """ + + left_most_point: tuple[i32, i32] = points[0] + point: tuple[i32, i32] + for point in points: + if point[0] < left_most_point[0]: + left_most_point = point + + return left_most_point + + +def distance(p: tuple[i32, i32], q: tuple[i32, i32]) -> f64: + # Function to calculate the Euclidean distance between two points + x1: i32; y1: i32 + x2: i32; y2: i32 + + x1, y1 = p + x2, y2 = q + return f64((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 From fe0e7bf355a40bc1c6c40808e31f85f3d3cb8c57 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Sat, 20 May 2023 19:18:51 +0530 Subject: [PATCH 2/2] TEST: Add test for lpconvexhull pkg --- integration_tests/CMakeLists.txt | 1 + integration_tests/test_pkg_lpconvexhull.py | 32 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 integration_tests/test_pkg_lpconvexhull.py diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 590da72d46..f76a802599 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -529,6 +529,7 @@ RUN(NAME test_package_01 LABELS cpython llvm) RUN(NAME test_pkg_lpdraw LABELS cpython llvm wasm) RUN(NAME test_pkg_lnn_01 LABELS cpython llvm) RUN(NAME test_pkg_lnn_02 LABELS cpython llvm) +RUN(NAME test_pkg_lpconvexhull LABELS cpython c) RUN(NAME generics_01 LABELS cpython llvm c) RUN(NAME generics_02 LABELS cpython llvm c) diff --git a/integration_tests/test_pkg_lpconvexhull.py b/integration_tests/test_pkg_lpconvexhull.py new file mode 100644 index 0000000000..793ea696dd --- /dev/null +++ b/integration_tests/test_pkg_lpconvexhull.py @@ -0,0 +1,32 @@ +from lpython import Const, i32, f64 + +from lpdraw import Line, Circle, Clear, Display +from lpconvexhull import convex_hull +from numpy import empty, int32 + +def plot_graph(polygon: list[tuple[i32, i32]], points: list[tuple[i32, i32]]): + Width: Const[i32] = 500 # x-axis limits [0, 499] + Height: Const[i32] = 500 # y-axis limits [0, 499] + Screen: i32[Height, Width] = empty((Height, Width), dtype=int32) + Clear(Height, Width, Screen) + + i: i32 + n: i32 = len(polygon) + for i in range(n): + Line(Height, Width, Screen, polygon[i][0], polygon[i][1], polygon[(i + 1) % n][0], polygon[(i + 1) % n][1]) + + point_size: i32 = 5 + for i in range(len(points)): + Circle(Height, Width, Screen, points[i][0], points[i][1], f64(point_size)) + + Display(Height, Width, Screen) + +def main0(): + points: list[tuple[i32, i32]] = [(445, 193), (138, 28), (418, 279), (62, 438), (168, 345), (435, 325), (293, 440), (158, 94), (403, 288), (136, 278), (141, 243), (287, 313), (338, 492), (172, 78), (29, 404), (79, 377), (184, 91), (69, 324), (408, 72), (494, 1)] + convex_hull_points: list[tuple[i32, i32]] = convex_hull(points) + # print(convex_hull_points) + plot_graph(convex_hull_points, points) + + assert convex_hull_points == [(29, 404), (138, 28), (494, 1), (435, 325), (338, 492), (62, 438)] + +main0()