1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
5 def convexHull(pointList):
6 def _isRightTurn((p, q, r)):
7 sum1 = q[0]*r[1] + p[0]*q[1] + r[0]*p[1]
8 sum2 = q[0]*p[1] + r[0]*q[1] + p[0]*r[1]
19 points = unique.keys()
22 return numpy.array([], numpy.float32)
24 # Build upper half of the hull.
25 upper = [points[0], points[1]]
28 while len(upper) > 2 and not _isRightTurn(upper[-3:]):
31 # Build lower half of the hull.
33 lower = [points[0], points[1]]
36 while len(lower) > 2 and not _isRightTurn(lower[-3:]):
43 return numpy.array(upper + lower, numpy.float32)
45 def minkowskiHull(a, b):
46 points = numpy.zeros((len(a) * len(b), 2))
47 for n in xrange(0, len(a)):
48 for m in xrange(0, len(b)):
49 points[n * len(b) + m] = a[n] + b[m]
50 return convexHull(points.copy())
52 def projectPoly(poly, normal):
53 pMin = numpy.dot(normal, poly[0])
55 for n in xrange(1 , len(poly)):
56 p = numpy.dot(normal, poly[n])
61 def polygonCollision(polyA, polyB):
62 for n in xrange(0, len(polyA)):
65 normal = (p1 - p0)[::-1]
66 normal[1] = -normal[1]
67 normal /= numpy.linalg.norm(normal)
68 aMin, aMax = projectPoly(polyA, normal)
69 bMin, bMax = projectPoly(polyB, normal)
74 for n in xrange(0, len(polyB)):
77 normal = (p1 - p0)[::-1]
78 normal[1] = -normal[1]
79 normal /= numpy.linalg.norm(normal)
80 aMin, aMax = projectPoly(polyA, normal)
81 bMin, bMax = projectPoly(polyB, normal)
88 def polygonCollisionPushVector(polyA, polyB):
91 for n in xrange(0, len(polyA)):
94 normal = (p1 - p0)[::-1]
95 normal[1] = -normal[1]
96 normal /= numpy.linalg.norm(normal)
97 aMin, aMax = projectPoly(polyA, normal)
98 bMin, bMax = projectPoly(polyB, normal)
103 size = min(bMax, bMax) - max(aMin, bMin)
105 ret = normal * (size + 0.1)
107 for n in xrange(0, len(polyB)):
110 normal = (p1 - p0)[::-1]
111 normal[1] = -normal[1]
112 normal /= numpy.linalg.norm(normal)
113 aMin, aMax = projectPoly(polyA, normal)
114 bMin, bMax = projectPoly(polyB, normal)
119 size = min(bMax, bMax) - max(aMin, bMin)
121 ret = normal * -(size + 0.1)
125 #Check if polyA is fully inside of polyB.
126 def fullInside(polyA, polyB):
127 for n in xrange(0, len(polyA)):
130 normal = (p1 - p0)[::-1]
131 normal[1] = -normal[1]
132 normal /= numpy.linalg.norm(normal)
133 aMin, aMax = projectPoly(polyA, normal)
134 bMin, bMax = projectPoly(polyB, normal)
139 for n in xrange(0, len(polyB)):
142 normal = (p1 - p0)[::-1]
143 normal[1] = -normal[1]
144 normal /= numpy.linalg.norm(normal)
145 aMin, aMax = projectPoly(polyA, normal)
146 bMin, bMax = projectPoly(polyB, normal)
154 return ((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0])) > 0
156 def lineLineIntersection(p0, p1, p2, p3):
159 C1 = A1*p0[0] + B1*p0[1]
163 C2 = A2 * p2[0] + B2 * p2[1]
168 return [(B2*C1 - B1*C2)/det, (A1 * C2 - A2 * C1) / det]
170 def clipConvex(poly0, poly1):
172 for p1idx in xrange(0, len(poly1)):
177 for n in xrange(0, len(src)):
179 if not isLeft(p0, p1, p):
180 if isLeft(p0, p1, src[n-1]):
181 res.append(lineLineIntersection(p0, p1, src[n-1], p))
183 elif not isLeft(p0, p1, src[n-1]):
184 res.append(lineLineIntersection(p0, p1, src[n-1], p))
185 return numpy.array(res, numpy.float32)