hmmmm
This commit is contained in:
parent
4f7c4a5699
commit
69037ec771
|
@ -2,7 +2,7 @@
|
||||||
import random
|
import random
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from math import atan2, degrees, tau, pi, acos, sqrt
|
from math import acos, sqrt
|
||||||
|
|
||||||
Point = namedtuple('Point', 'x y')
|
Point = namedtuple('Point', 'x y')
|
||||||
Vector = namedtuple('Vector', 'x y')
|
Vector = namedtuple('Vector', 'x y')
|
||||||
|
@ -18,8 +18,19 @@ def gen_point():
|
||||||
return p_i
|
return p_i
|
||||||
|
|
||||||
|
|
||||||
def calc_angle(v: Vector, upside_down=False) -> float:
|
def calc_angle(v1: Vector, v2: Vector) -> float:
|
||||||
return (90 - degrees(atan2(v.y, v.x)) - 180*upside_down) % 360
|
dot = (v1.x * v2.x) + (v1.y * v2.y)
|
||||||
|
len_1 = sqrt(v1.x**2 + v1.y**2)
|
||||||
|
len_2 = sqrt(v2.x**2 + v2.y**2)
|
||||||
|
|
||||||
|
tmp = dot / (len_1 * len_2)
|
||||||
|
|
||||||
|
# pls
|
||||||
|
hmmmmmmm = round(tmp, 6)
|
||||||
|
|
||||||
|
return acos(hmmmmmmm)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def calc_vector(p1: Point, p2: Point) -> Vector:
|
def calc_vector(p1: Point, p2: Point) -> Vector:
|
||||||
|
@ -41,16 +52,15 @@ def display(points, hull):
|
||||||
|
|
||||||
def rapper(points: set):
|
def rapper(points: set):
|
||||||
min_pt = min(points)
|
min_pt = min(points)
|
||||||
max_pt = max(points)
|
|
||||||
hull = [min_pt]
|
hull = [min_pt]
|
||||||
upside_down = False
|
comp_vec = Vector(0, 1)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
hull.append(min(points - {hull[-1]},
|
hull.append(min(points - {hull[-1]},
|
||||||
key=lambda p: calc_angle(calc_vector(hull[-1], p), upside_down)))
|
key=lambda p: calc_angle(comp_vec, calc_vector(hull[-1], p))))
|
||||||
if hull[-1].x == max_pt.x:
|
comp_vec = calc_vector(hull[-2], hull[-1])
|
||||||
upside_down = True
|
|
||||||
display(points, hull)
|
display(points, hull)
|
||||||
|
|
||||||
if hull[-1] == min_pt:
|
if hull[-1] == min_pt:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
106
h2/quick_hull.py
Normal file
106
h2/quick_hull.py
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import random
|
||||||
|
from collections import namedtuple
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from enum import Enum, auto
|
||||||
|
from math import atan2, degrees, tau, pi, acos, sqrt
|
||||||
|
|
||||||
|
|
||||||
|
Point = namedtuple('Point', 'x y')
|
||||||
|
|
||||||
|
|
||||||
|
class Side(Enum):
|
||||||
|
ON = auto()
|
||||||
|
ABOVE = auto()
|
||||||
|
BELOW = auto()
|
||||||
|
|
||||||
|
|
||||||
|
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 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 sidedness(p1, p2, p3, eps=0.0000001):
|
||||||
|
y = p1.y * (p3.x - p2.x)
|
||||||
|
x = p1.x
|
||||||
|
a = (p3.y - p2.y)
|
||||||
|
b = p3.y * (p3.x - p2.x) - a * p3.x
|
||||||
|
|
||||||
|
line = a*x+b
|
||||||
|
|
||||||
|
if y - eps < line < y + eps:
|
||||||
|
return [Side.ON, y - line]
|
||||||
|
elif y > line:
|
||||||
|
return [Side.ABOVE, y - line]
|
||||||
|
return [Side.BELOW, y - line]
|
||||||
|
|
||||||
|
|
||||||
|
def prune_below_find_highest(points: set, line_segment, side = Side.BELOW, lel=max):
|
||||||
|
min_pt, max_pt = line_segment
|
||||||
|
|
||||||
|
above_pts = []
|
||||||
|
|
||||||
|
for point in points:
|
||||||
|
sidedness_res = sidedness(min_pt, max_pt, point)
|
||||||
|
if sidedness_res[0] != side:
|
||||||
|
above_pts.append(point)
|
||||||
|
|
||||||
|
highest_above = lel(above_pts, key=lambda pt: pt[1])
|
||||||
|
|
||||||
|
return above_pts, highest_above
|
||||||
|
|
||||||
|
|
||||||
|
def find_line_segment(points):
|
||||||
|
min_pt = min(points, key=lambda pt: pt.x)
|
||||||
|
max_pt = max(points, key=lambda pt: pt.x)
|
||||||
|
return min_pt, max_pt
|
||||||
|
|
||||||
|
|
||||||
|
def quick_hull(points, side=Side.BELOW, lel=max, hull=None):
|
||||||
|
if hull is None:
|
||||||
|
hull = set()
|
||||||
|
|
||||||
|
print(len(points))
|
||||||
|
if len(points) <= 2:
|
||||||
|
return hull
|
||||||
|
|
||||||
|
min_pt, max_pt = find_line_segment(points)
|
||||||
|
|
||||||
|
above_points, max_dist_pt = prune_below_find_highest(points, (min_pt, max_pt), side, lel)
|
||||||
|
|
||||||
|
left_side = prune_below_find_highest(points, (min_pt, max_dist_pt), side, lel)[0]
|
||||||
|
right_side = prune_below_find_highest(points, (max_dist_pt, max_pt), side, lel)[0]
|
||||||
|
|
||||||
|
hull.add(max_dist_pt)
|
||||||
|
|
||||||
|
quick_hull(left_side, side, lel, hull=hull).union(quick_hull(right_side, side, lel, hull=hull))
|
||||||
|
|
||||||
|
return hull
|
||||||
|
|
||||||
|
points = {Point(2, 5), Point(3, 1), Point(3, 4), Point(9, 4), Point(1, 5), Point(5, 7)}
|
||||||
|
#points = {gen_point() for _ in range(10)}
|
||||||
|
|
||||||
|
line_segment = find_line_segment(points)
|
||||||
|
uh_hull = quick_hull(points)
|
||||||
|
lh_hull = quick_hull(points, Side.ABOVE, min)
|
||||||
|
|
||||||
|
hull = uh_hull.union(lh_hull)
|
||||||
|
|
||||||
|
display(points, hull)
|
Loading…
Reference in New Issue
Block a user