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 # Build upper half of the hull.
23 upper = [points[0], points[1]]
26 while len(upper) > 2 and not _isRightTurn(upper[-3:]):
29 # Build lower half of the hull.
31 lower = [points[0], points[1]]
34 while len(lower) > 2 and not _isRightTurn(lower[-3:]):
41 return numpy.array(upper + lower, numpy.float32) - numpy.array([0.0,0.0], numpy.float32)
43 def minkowskiHull(a, b):
44 points = numpy.zeros((len(a) * len(b), 2))
45 for n in xrange(0, len(a)):
46 for m in xrange(0, len(b)):
47 points[n * len(b) + m] = a[n] + b[m]
48 return convexHull(points.copy())
50 def projectPoly(poly, normal):
51 pMin = numpy.dot(normal, poly[0])
53 for n in xrange(1 , len(poly)):
54 p = numpy.dot(normal, poly[n])
59 def polygonCollision(polyA, polyB):
60 for n in xrange(0, len(polyA)):
63 normal = (p1 - p0)[::-1]
64 normal[1] = -normal[1]
65 normal /= numpy.linalg.norm(normal)
66 aMin, aMax = projectPoly(polyA, normal)
67 bMin, bMax = projectPoly(polyB, normal)
72 for n in xrange(0, len(polyB)):
75 normal = (p1 - p0)[::-1]
76 normal[1] = -normal[1]
77 normal /= numpy.linalg.norm(normal)
78 aMin, aMax = projectPoly(polyA, normal)
79 bMin, bMax = projectPoly(polyB, normal)
86 def polygonCollisionPushVector(polyA, polyB):
89 for n in xrange(0, len(polyA)):
92 normal = (p1 - p0)[::-1]
93 normal[1] = -normal[1]
94 normal /= numpy.linalg.norm(normal)
95 aMin, aMax = projectPoly(polyA, normal)
96 bMin, bMax = projectPoly(polyB, normal)
101 size = min(bMax, bMax) - max(aMin, bMin)
103 ret = normal * (size + 0.1)
105 for n in xrange(0, len(polyB)):
108 normal = (p1 - p0)[::-1]
109 normal[1] = -normal[1]
110 normal /= numpy.linalg.norm(normal)
111 aMin, aMax = projectPoly(polyA, normal)
112 bMin, bMax = projectPoly(polyB, normal)
117 size = min(bMax, bMax) - max(aMin, bMin)
119 ret = normal * -(size + 0.1)
123 #Check if polyA is fully inside of polyB.
124 def fullInside(polyA, polyB):
125 for n in xrange(0, len(polyA)):
128 normal = (p1 - p0)[::-1]
129 normal[1] = -normal[1]
130 normal /= numpy.linalg.norm(normal)
131 aMin, aMax = projectPoly(polyA, normal)
132 bMin, bMax = projectPoly(polyB, normal)
137 for n in xrange(0, len(polyB)):
140 normal = (p1 - p0)[::-1]
141 normal[1] = -normal[1]
142 normal /= numpy.linalg.norm(normal)
143 aMin, aMax = projectPoly(polyA, normal)
144 bMin, bMax = projectPoly(polyB, normal)
152 return ((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0])) > 0
154 def lineLineIntersection(p0, p1, p2, p3):
157 C1 = A1*p0[0] + B1*p0[1]
161 C2 = A2 * p2[0] + B2 * p2[1]
166 return [(B2*C1 - B1*C2)/det, (A1 * C2 - A2 * C1) / det]
168 def clipConvex(poly0, poly1):
170 for p1idx in xrange(0, len(poly1)):
175 for n in xrange(0, len(src)):
177 if not isLeft(p0, p1, p):
178 if isLeft(p0, p1, src[n-1]):
179 res.append(lineLineIntersection(p0, p1, src[n-1], p))
181 elif not isLeft(p0, p1, src[n-1]):
182 res.append(lineLineIntersection(p0, p1, src[n-1], p))
183 return numpy.array(res, numpy.float32)