ROSBuzz_MISTLab/buzz_scripts/include/utils/quickhull.bzz

122 lines
3.1 KiB
Plaintext

hullPts = {}
hullC = 0
# When called returns a list of points that forms a convex hull around
# the listPts Given (http://adultstudylife.blogspot.com/2016/06/quick-hull-in-python.html)
function QuickHull(focalpts) {
listPts = {}
hullPts = {}
jp = 0
foreach(focalpts, function(key, pt) {
ip = 0
while(ip<6){
listPts[jp*6+ip]=math.vec2.add(pt,math.vec2.newp(20, ip*math.pi/3))
#log("Created new pt: ", listPts[j*6+i].x, listPts[j*6+i].y, "(", pt.x, pt.y, ")")
ip=ip+1
}
jp=jp+1
})
# get the min, and max from the list of points
min_max = get_min_max_x(listPts)
hullPts = quickhull_rec(listPts, min_max.min, min_max.max)
hullPts = quickhull_rec(listPts, min_max.max, min_max.min)
return hullPts
}
# Does the sorting for the quick hull sorting algorithm
function quickhull_rec(listPts, minp, maxp) {
left_of_line_pts = get_points_left_of_line(minp, maxp, listPts)
ptC = point_max_from_line(minp, maxp, left_of_line_pts)
if(size(ptC) < 1){
hullPts[hullC] = maxp # max
hullC = hullC +1
return hullPts
#log("Add pt:", maxp.x, maxp.y)
}
hullPts = quickhull_rec(left_of_line_pts, minp, ptC)
hullPts = quickhull_rec(left_of_line_pts, ptC, maxp)
return hullPts
}
# Returns all points that are LEFT of a line start->end
function get_points_left_of_line(minp, maxp, listPts) {
pts = {}
ih = 0
foreach(listPts, function(key, pt) {
if(isCCW(minp, maxp, pt)){
pts[ih]=pt
ih=ih+1
}
})
return pts
}
# Returns the maximum point from a line start->end
function point_max_from_line(minp, maxp, points) {
max_dist = 0
max_point = {}
foreach(points, function(key, point) {
if((not(math.vec2.equal(point, minp))) and (not(math.vec2.equal(point, maxp)))) {
#log("Get distance of pt: ", point.x, point.y)
dist = distance_toline(minp, maxp, point)
if(dist > max_dist) {
max_dist = dist
max_point = point
}
}
})
return max_point
}
function get_min_max_x(list_pts) {
min_x = 100000
max_x = 0
min_y = 0
max_y = 0
foreach(list_pts, function(key, point) {
if(point.x < min_x){
min_x = point.x
min_y = point.y
}
if(point.x > max_x){
max_x = point.x
max_y = point.y
}
})
return {.min=math.vec2.new(min_x, min_y), .max=math.vec2.new(max_x, max_y)}
}
# Given a line of start->end, will return the distance that
# point, pt, is from the line.
function distance_toline(start, end, pt) { # pt is the point
x1 = start.x
y1 = start.y
x2 = end.x
y2 = end.y
x0 = pt.x
y0 = pt.y
nom = math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1)
denom = math.vec2.length(math.vec2.sub(end,start))
result = nom / denom
return result
}
# Tests whether the turn formed by A, B, and C is ccw
function isCCW(A, B, C){
return (B.x - A.x) * (C.y - A.y) > (B.y - A.y) * (C.x - A.x)
}