ok
This commit is contained in:
parent
69037ec771
commit
3cead7083e
|
@ -1,5 +1,7 @@
|
||||||
import random
|
import random
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from math import atan2, degrees, tau, pi, acos, sqrt
|
from math import atan2, degrees, tau, pi, acos, sqrt
|
||||||
|
@ -37,70 +39,63 @@ def gen_point():
|
||||||
return p_i
|
return p_i
|
||||||
|
|
||||||
|
|
||||||
def sidedness(p1, p2, p3, eps=0.0000001):
|
def distance(a, b, c):
|
||||||
y = p1.y * (p3.x - p2.x)
|
try:
|
||||||
x = p1.x
|
nom = abs((b.y - a.y) * c.x - (b.x - a.x) * c.y + b.x * a.y - b.y * a.x)
|
||||||
a = (p3.y - p2.y)
|
den = sqrt((b.y - a.y) ** 2 + (b.x - a.x) ** 2)
|
||||||
b = p3.y * (p3.x - p2.x) - a * p3.x
|
return nom / den
|
||||||
|
except ZeroDivisionError:
|
||||||
line = a*x+b
|
return 0
|
||||||
|
|
||||||
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):
|
def is_left(a: Point, b: Point, c: Point):
|
||||||
min_pt, max_pt = line_segment
|
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) > 0
|
||||||
|
|
||||||
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):
|
def quick_hull(points: Set[Point]):
|
||||||
min_pt = min(points, key=lambda pt: pt.x)
|
assert len(points) >= 2
|
||||||
max_pt = max(points, key=lambda pt: pt.x)
|
|
||||||
return min_pt, max_pt
|
|
||||||
|
|
||||||
|
left = min(points)
|
||||||
|
right = max(points)
|
||||||
|
|
||||||
def quick_hull(points, side=Side.BELOW, lel=max, hull=None):
|
hull = {left, right}
|
||||||
if hull is None:
|
|
||||||
hull = set()
|
|
||||||
|
|
||||||
print(len(points))
|
find_hull({p for p in points if not is_left(left, right, p)},
|
||||||
if len(points) <= 2:
|
left,
|
||||||
return hull
|
right,
|
||||||
|
hull)
|
||||||
|
|
||||||
min_pt, max_pt = find_line_segment(points)
|
find_hull({p for p in points if is_left(left, right, p)},
|
||||||
|
right,
|
||||||
above_points, max_dist_pt = prune_below_find_highest(points, (min_pt, max_pt), side, lel)
|
left,
|
||||||
|
hull)
|
||||||
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
|
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)
|
def find_hull(points: Set[Point], p: Point, q: Point, hull: Set[Point]):
|
||||||
uh_hull = quick_hull(points)
|
if not points:
|
||||||
lh_hull = quick_hull(points, Side.ABOVE, min)
|
return
|
||||||
|
|
||||||
hull = uh_hull.union(lh_hull)
|
farthest = max(points, key=lambda point: distance(p, q, point))
|
||||||
|
hull.add(farthest)
|
||||||
|
|
||||||
|
s1 = {point
|
||||||
|
for point in points
|
||||||
|
if not is_left(p, farthest, point)}
|
||||||
|
print("--")
|
||||||
|
print(s1)
|
||||||
|
|
||||||
|
s2 = {point
|
||||||
|
for point in points
|
||||||
|
if not is_left(farthest, q, point)}
|
||||||
|
print(s2)
|
||||||
|
|
||||||
|
find_hull(s1, p, farthest, hull)
|
||||||
|
find_hull(s2, farthest, q, hull)
|
||||||
|
|
||||||
|
|
||||||
|
points = {gen_point() for _ in range(10)}
|
||||||
|
hull = quick_hull(points)
|
||||||
|
|
||||||
display(points, hull)
|
display(points, hull)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user