2018-09-20 14:59:42 +00:00
|
|
|
from math import sqrt
|
2018-09-20 13:44:39 +00:00
|
|
|
from typing import Set
|
|
|
|
|
2018-10-09 17:26:55 +00:00
|
|
|
from util import Point, gen_point, display
|
2018-09-20 12:50:16 +00:00
|
|
|
|
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
def distance(a, b, c):
|
2018-09-20 14:54:47 +00:00
|
|
|
nom = abs((b.y - a.y) * c.x - (b.x - a.x) * c.y + b.x * a.y - b.y * a.x)
|
|
|
|
den = sqrt((b.y - a.y) ** 2 + (b.x - a.x) ** 2)
|
|
|
|
return nom / den
|
2018-09-20 12:50:16 +00:00
|
|
|
|
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
def is_left(a: Point, b: Point, c: Point):
|
|
|
|
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) > 0
|
2018-09-20 12:50:16 +00:00
|
|
|
|
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
def quick_hull(points: Set[Point]):
|
|
|
|
assert len(points) >= 2
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
left = min(points)
|
|
|
|
right = max(points)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
hull = {left, right}
|
2018-09-20 13:58:02 +00:00
|
|
|
points = points - hull
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
find_hull({p for p in points if not is_left(left, right, p)},
|
|
|
|
left,
|
|
|
|
right,
|
|
|
|
hull)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 13:58:02 +00:00
|
|
|
find_hull({p for p in points if not is_left(right, left, p)},
|
2018-09-20 13:44:39 +00:00
|
|
|
right,
|
|
|
|
left,
|
|
|
|
hull)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
return hull
|
2018-09-20 12:50:16 +00:00
|
|
|
|
|
|
|
|
2018-09-20 13:44:39 +00:00
|
|
|
def find_hull(points: Set[Point], p: Point, q: Point, hull: Set[Point]):
|
|
|
|
if not points:
|
|
|
|
return
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 14:54:47 +00:00
|
|
|
farthest = max(points, key=lambda point: abs(distance(p, q, point)))
|
2018-09-20 13:44:39 +00:00
|
|
|
hull.add(farthest)
|
2018-09-20 14:54:47 +00:00
|
|
|
points.remove(farthest)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 14:54:47 +00:00
|
|
|
find_hull({po for po in points if not is_left(p, farthest, po)},
|
|
|
|
p,
|
|
|
|
farthest,
|
|
|
|
hull)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 14:54:47 +00:00
|
|
|
find_hull({po for po in points if not is_left(farthest, q, po)},
|
|
|
|
farthest,
|
|
|
|
q,
|
|
|
|
hull)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
|
|
|
|
2018-09-20 14:59:42 +00:00
|
|
|
points = {gen_point() for _ in range(30)}
|
|
|
|
hull = quick_hull(points)
|
2018-09-20 12:50:16 +00:00
|
|
|
|
2018-09-20 14:59:42 +00:00
|
|
|
display(points, hull)
|