# Use atan2 instead of acos to calc angle; atan2(x,y) of the point we potentially want to add import random from collections import namedtuple import matplotlib.pyplot as plt from math import atan2, degrees, tau, pi Point = namedtuple('Point', 'x y') Vector = namedtuple('Vector', 'x y') def gen_point(): a = random.uniform(1, 5) b = random.uniform(1, 5) x_i = random.uniform(1, 5) p_i = Point(x_i, a * x_i + b) return p_i def calc_angle(v1: Vector) -> float: # x = atan2(v1.y, v1.x) theta_deg = atan2(-v1.y, -v1.x) / pi * 180 + 180 lel = (90 - theta_deg) % 360 # degrees = (atan2(-v1.y, -v1.x)) + 180 return lel def calc_vector(p1: Point, p2: Point) -> Vector: return Vector((p2.x - p1.x), (p2.y - p1.y)) def display(points, hull): x = [point.x for point in points] y = [point.y for point in points] h_x = [point.x for point in hull] h_y = [point.y for point in hull] plt.plot(h_x, h_y, 'ro-') plt.scatter(x, y) plt.show() def rapper(points: set): min_pt = min(points) hull = [min_pt] while True: hull.append(min(points - {hull[-1]}, key=lambda p: calc_angle(calc_vector(hull[-1], p)))) display(points, hull) if hull[-1] == min_pt: break return hull points = {gen_point() for _ in range(10)} hull = rapper(points)