$search
00001 """convexhull.py 00002 00003 Calculate the convex hull of a set of n 2D-points in O(n log n) time. 00004 Taken from Berg et al., Computational Geometry, Springer-Verlag, 1997. 00005 Prints output as EPS file. 00006 00007 When run from the command line it generates a random set of points 00008 inside a square of given length and finds the convex hull for those, 00009 printing the result as an EPS file. 00010 00011 Usage: 00012 00013 convexhull.py <numPoints> <squareLength> <outFile> 00014 00015 Dinu C. Gherman 00016 """ 00017 00018 00019 import sys, string, random 00020 00021 00022 ###################################################################### 00023 # Helpers 00024 ###################################################################### 00025 00026 def _myDet(p, q, r): 00027 """Calc. determinant of a special matrix with three 2D points. 00028 00029 The sign, "-" or "+", determines the side, right or left, 00030 respectivly, on which the point r lies, when measured against 00031 a directed vector from p to q. 00032 """ 00033 00034 # We use Sarrus' Rule to calculate the determinant. 00035 # (could also use the Numeric package...) 00036 sum1 = q[0]*r[1] + p[0]*q[1] + r[0]*p[1] 00037 sum2 = q[0]*p[1] + r[0]*q[1] + p[0]*r[1] 00038 00039 return sum1 - sum2 00040 00041 00042 def _isRightTurn((p, q, r)): 00043 "Do the vectors pq:qr form a right turn, or not?" 00044 00045 assert p != q and q != r and p != r 00046 00047 if _myDet(p, q, r) < 0: 00048 return 1 00049 else: 00050 return 0 00051 00052 00053 def _isPointInPolygon(r, P): 00054 "Is point r inside a given polygon P?" 00055 00056 # We assume the polygon is a list of points, listed clockwise! 00057 for i in xrange(len(P[:-1])): 00058 p, q = P[i], P[i+1] 00059 if not _isRightTurn((p, q, r)): 00060 return 0 # Out! 00061 00062 return 1 # It's within! 00063 00064 00065 def _makeRandomData(numPoints=10, sqrLength=100, addCornerPoints=0): 00066 "Generate a list of random points within a square." 00067 00068 # Fill a square with random points. 00069 min, max = 0, sqrLength 00070 P = [] 00071 for i in xrange(numPoints): 00072 rand = random.randint 00073 x = rand(min+1, max-1) 00074 y = rand(min+1, max-1) 00075 P.append((x, y)) 00076 00077 # Add some "outmost" corner points. 00078 if addCornerPoints != 0: 00079 P = P + [(min, min), (max, max), (min, max), (max, min)] 00080 00081 return P 00082 00083 00084 00085 00086 ###################################################################### 00087 # Public interface 00088 ###################################################################### 00089 00090 def convex_hull(P): 00091 "Calculate the convex hull of a set of points." 00092 00093 # Get a local list copy of the points and sort them lexically. 00094 points = map(None, P) 00095 points.sort() 00096 00097 # Build upper half of the hull. 00098 upper = [points[0], points[1]] 00099 for p in points[2:]: 00100 upper.append(p) 00101 while len(upper) > 2 and not _isRightTurn(upper[-3:]): 00102 del upper[-2] 00103 00104 # Build lower half of the hull. 00105 points.reverse() 00106 lower = [points[0], points[1]] 00107 for p in points[2:]: 00108 lower.append(p) 00109 while len(lower) > 2 and not _isRightTurn(lower[-3:]): 00110 del lower[-2] 00111 00112 # Remove duplicates. 00113 del lower[0] 00114 del lower[-1] 00115 00116 # Concatenate both halfs and return. 00117 return tuple(upper + lower) 00118 00119 00120 ###################################################################### 00121 # Test 00122 ###################################################################### 00123 00124 def test(): 00125 a = 200 00126 p = _makeRandomData(30, a, 0) 00127 c = convexHull(p) 00128 00129 00130