96 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Example from http://wiki.scipy.org/Cookbook/Finding_Convex_Hull
 | 
						|
 | 
						|
import numpy as n
 | 
						|
import pylab as p
 | 
						|
import time
 | 
						|
 | 
						|
 | 
						|
def _angle_to_point(point, centre):
 | 
						|
    '''calculate angle in 2-D between points and x axis'''
 | 
						|
    delta = point - centre
 | 
						|
    res = n.arctan(delta[1] / delta[0])
 | 
						|
    if delta[0] < 0:
 | 
						|
        res += n.pi
 | 
						|
    return res
 | 
						|
 | 
						|
 | 
						|
def _draw_triangle(p1, p2, p3, **kwargs):
 | 
						|
    tmp = n.vstack((p1, p2, p3))
 | 
						|
    x, y = [x[0] for x in zip(tmp.transpose())]
 | 
						|
    p.fill(x, y, **kwargs)
 | 
						|
    # XXX time.sleep(0.2)
 | 
						|
 | 
						|
 | 
						|
def area_of_triangle(p1, p2, p3):
 | 
						|
    '''calculate area of any triangle given co-ordinates of the corners'''
 | 
						|
    return n.linalg.norm(n.cross((p2 - p1), (p3 - p1)))/2.
 | 
						|
 | 
						|
 | 
						|
def convex_hull(points, graphic=True, smidgen=0.0075):
 | 
						|
    '''Calculate subset of points that make a convex hull around points
 | 
						|
 | 
						|
Recursively eliminates points that lie inside two neighbouring points until
 | 
						|
only convex hull is remaining.
 | 
						|
 | 
						|
:Parameters:
 | 
						|
    points : ndarray (2 x m)
 | 
						|
        array of points for which to find hull
 | 
						|
    graphic : bool
 | 
						|
        use pylab to show progress?
 | 
						|
    smidgen : float
 | 
						|
        offset for graphic number labels - useful values depend on your data
 | 
						|
        range
 | 
						|
 | 
						|
:Returns:
 | 
						|
    hull_points : ndarray (2 x n)
 | 
						|
        convex hull surrounding points
 | 
						|
'''
 | 
						|
    if graphic:
 | 
						|
        p.clf()
 | 
						|
        p.plot(points[0], points[1], 'ro')
 | 
						|
    n_pts = points.shape[1]
 | 
						|
    assert(n_pts > 5)
 | 
						|
    centre = points.mean(1)
 | 
						|
    if graphic:
 | 
						|
        p.plot((centre[0], ), (centre[1], ), 'bo')
 | 
						|
    angles = n.apply_along_axis(_angle_to_point, 0, points, centre)
 | 
						|
    pts_ord = points[:, angles.argsort()]
 | 
						|
    if graphic:
 | 
						|
        for i in xrange(n_pts):
 | 
						|
            p.text(pts_ord[0, i] + smidgen, pts_ord[1, i] + smidgen,
 | 
						|
                   '%d' % i)
 | 
						|
    pts = [x[0] for x in zip(pts_ord.transpose())]
 | 
						|
    prev_pts = len(pts) + 1
 | 
						|
    k = 0
 | 
						|
    while prev_pts > n_pts:
 | 
						|
        prev_pts = n_pts
 | 
						|
        n_pts = len(pts)
 | 
						|
        if graphic:
 | 
						|
            p.gca().patches = []
 | 
						|
        i = -2
 | 
						|
        while i < (n_pts - 2):
 | 
						|
            Aij = area_of_triangle(centre, pts[i],     pts[(i + 1) % n_pts])
 | 
						|
            Ajk = area_of_triangle(centre, pts[(i + 1) % n_pts],
 | 
						|
                                   pts[(i + 2) % n_pts])
 | 
						|
            Aik = area_of_triangle(centre, pts[i],     pts[(i + 2) % n_pts])
 | 
						|
            if graphic:
 | 
						|
                _draw_triangle(centre, pts[i], pts[(i + 1) % n_pts],
 | 
						|
                               facecolor='blue', alpha=0.2)
 | 
						|
                _draw_triangle(centre, pts[(i + 1) % n_pts],
 | 
						|
                               pts[(i + 2) % n_pts],
 | 
						|
                               facecolor='green', alpha=0.2)
 | 
						|
                _draw_triangle(centre, pts[i], pts[(i + 2) % n_pts],
 | 
						|
                               facecolor='red', alpha=0.2)
 | 
						|
            if Aij + Ajk < Aik:
 | 
						|
                if graphic:
 | 
						|
                    p.plot((pts[i + 1][0], ), (pts[i + 1][1], ), 'go')
 | 
						|
                del pts[i+1]
 | 
						|
            i += 1
 | 
						|
            n_pts = len(pts)
 | 
						|
        k += 1
 | 
						|
    return n.asarray(pts)
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    points = n.random.random_sample((2, 40))
 | 
						|
    hull_pts = convex_hull(points)
 | 
						|
    p.show()
 |