195 lines
4.8 KiB
Python
195 lines
4.8 KiB
Python
|
|
import matplotlib.pyplot as plt
|
|
import collections
|
|
from enum import Enum, auto
|
|
from random import randint
|
|
|
|
Point = collections.namedtuple("Point", "x y")
|
|
|
|
class Side(Enum):
|
|
ON = auto()
|
|
ABOVE = auto()
|
|
BELOW = auto()
|
|
|
|
|
|
def sidedness(slope, intersection, p3, eps=0.0000001):
|
|
print(slope * p3[0] + intersection )
|
|
""" finds where a point is in regards to a line """
|
|
if p3[1] - eps <= slope * p3[0] + intersection <= p3[1] + eps or p3[0] - eps <= (p3[1] - intersection)/slope <= p3[0] + eps:
|
|
return Side.ON
|
|
elif p3[1] > slope * p3[0] + intersection:
|
|
return Side.ABOVE
|
|
return Side.BELOW
|
|
|
|
def diplay_prune_points(points, p1, p2):
|
|
xs = [p[0] for p in points]
|
|
ys = [p[1] for p in points]
|
|
|
|
plt.plot(xs, ys, 'ro')
|
|
plt.plot([p1[0], p2[0]], [p1[1], p2[1]])
|
|
plt.show()
|
|
|
|
|
|
def solve1D(points, xm, iteration_num):
|
|
#print("iter:", iteration_num)
|
|
point = points[iteration_num]
|
|
|
|
if iteration_num == 0:
|
|
return -float('Inf'), -float('Inf')
|
|
|
|
# lad point[1] = point[0] * a + b <=> y = x * a + b
|
|
# isolere b og sæt ind i constraints
|
|
a = None
|
|
b = point[1] - point[0] # * a
|
|
|
|
# minimere xm*a + b, hvor b har ny værdi
|
|
# Vi regner kun med koefficienterne
|
|
# obj_fun = (xm - point[0]) + points[1] = (xm*a - xi*a) + y
|
|
|
|
# max eller min
|
|
#print("XM og point[0]:", xm, point[0])
|
|
a = xm - point[0]
|
|
#print("a lige her:", a)
|
|
|
|
a_constraint_list = []
|
|
# looping over the i constraints
|
|
for p in points[:iteration_num]:
|
|
# we can't make a straigt vertical line
|
|
if p[0] == point[0]:
|
|
if p[1] > point[1]:
|
|
p[0] = p[0] + 0.0001
|
|
else:
|
|
point[0] = point[0] + 0.0001
|
|
|
|
print(p, point)
|
|
# Spring over den i'te constraint
|
|
if p != point:
|
|
# y_j - yi
|
|
c = p[1] - point[1]
|
|
# x_j * a - xi * a
|
|
a_diff = p[0] - point[0]
|
|
|
|
print(c, a_diff, c/a_diff)
|
|
# det her er forkert og skal fikses
|
|
if a >= 0 and a_diff < 0:
|
|
a_constraint_list.append(-float('Inf'))
|
|
else:
|
|
a_constraint_list.append(c/a_diff)
|
|
|
|
# hvis a > 0 så min
|
|
# hvis a < 0 så max.
|
|
if a >= 0:
|
|
v1 = max(a_constraint_list)
|
|
v2 = point[1] - point[0] * v1
|
|
v = (v1, v2)
|
|
elif a < 0:
|
|
v1 = min(a_constraint_list)
|
|
v2 = point[1] - point[0] * v1
|
|
v = (v1, v2)
|
|
|
|
return v
|
|
|
|
|
|
|
|
def findBridge(points, xm):
|
|
if xm > 0:
|
|
v = (-float('Inf'), -float('Inf'))
|
|
elif xm < 0:
|
|
4 # noget
|
|
else:
|
|
# TODO: xm == 0
|
|
4
|
|
# looping over constraints
|
|
for point in points:
|
|
# checking for violation
|
|
if not point[1] <= point[0] * v[0] + v[1]:
|
|
v = solve1D(points, xm, points.index(point))
|
|
#print("HER OVER: ", v)
|
|
|
|
slope = v[0]
|
|
intercept = v[1]
|
|
|
|
line_points = [p for p in points if sidedness(slope, intercept, p) == Side.ON]
|
|
|
|
if len(line_points) > 3:
|
|
print("Halli HAllo")
|
|
print(line_points)
|
|
|
|
return line_points[0], line_points[1]
|
|
|
|
|
|
def find_median(points):
|
|
if len(points) % 2 == 0:
|
|
first_med_idx = int(len(points) / 2 - 1)
|
|
second_med_idx = int(len(points) / 2)
|
|
return (points[first_med_idx][0] + points[second_med_idx][0]) / 2
|
|
else:
|
|
idx = int((len(points)-1) / 2)
|
|
return points[idx][0]
|
|
|
|
|
|
def upperHull(points, all_points):
|
|
print("Punkter:", points)
|
|
if len(points) < 2:
|
|
return []
|
|
xm = find_median(points)
|
|
|
|
# end-points of bridge
|
|
(xi, yi), (xj, yj) = findBridge(points, xm)
|
|
|
|
#print(xm)
|
|
print((xi, yi), (xj, yj))
|
|
prune_points = [p for p in points if p[0] < xi or xj < p[0]] + [(xi, yi), (xj, yj)]
|
|
|
|
# Neden for er mest for visualisering
|
|
prune_all_points = [p for p in all_points if p[0] < xi or xj < p[0]] + [(xi, yi), (xj, yj)]
|
|
diplay_prune_points(prune_all_points, (xi, yi), (xj, yj))
|
|
|
|
Pl = [p for p in prune_points if p[0] < xm]
|
|
Pr = [p for p in prune_points if p[0] >= xm]
|
|
#print("Pl:", Pl, "Pr", Pr)
|
|
|
|
print("\n")
|
|
# recurse results and return
|
|
ret = [(xi, yi), (xj, yj)]
|
|
ret = ret + [p for p in upperHull(Pl, prune_all_points) if p not in ret]
|
|
ret = ret + [p for p in upperHull(Pr, prune_all_points) if p not in ret]
|
|
return ret
|
|
|
|
|
|
|
|
p1 = (2, 1)
|
|
p2 = (3, 4)
|
|
p3 = (5, 2)
|
|
p4 = (6, 5)
|
|
|
|
list_of_points = []
|
|
|
|
list_of_points.append(p1)
|
|
list_of_points.append(p2)
|
|
list_of_points.append(p3)
|
|
list_of_points.append(p4)
|
|
|
|
|
|
|
|
|
|
xs = [p[0] for p in list_of_points]
|
|
ys = [p[1] for p in list_of_points]
|
|
|
|
plt.plot(xs, ys, 'ro')
|
|
plt.show()
|
|
|
|
result = list(sorted(upperHull(list_of_points, list_of_points)))
|
|
|
|
result
|
|
res_xs = [p[0] for p in result]
|
|
res_ys = [p[1] for p in result]
|
|
|
|
|
|
#print("result", result)
|
|
plt.plot(res_xs, res_ys)
|
|
plt.plot(xs, ys, 'ro')
|
|
plt.show()
|
|
|
|
|