Hi
I have a problem with a collision detection method I have written. I use the separating axis theorem to detect collisions and the detection is working well.
The problem is that the minimum translation vector I get from the method is sometimes wrong if there are parallel edges in the polygons.
Parallel edges, although in opposite directions, give the same overlap distance, so it's just a matter of chance if the returned vector will point in the right direction.
How would I go about to fix this?
My code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| Vector getCollisionSAT(Polygon a, Polygon b) {
ArrayList<Vector> aVerts = new ArrayList<Vector>(a.getVertices()); ArrayList<Vector> bVerts = new ArrayList<Vector>(b.getVertices()); ArrayList<Vector> normals = new ArrayList<Vector>(); for (int i = 0; i < aVerts.size(); i++) { Vector p1, p2; p1 = aVerts.get(i); p2 = aVerts.get((i + 1 == aVerts.size()) ? 0 : i + 1); Vector normal = p2.subtract(p1).perpendicularCCW(); normal = normal.normalize(); normals.add(normal); } for (int i = 0; i < bVerts.size(); i++) { Vector p1, p2; p1 = bVerts.get(i); p2 = bVerts.get((i + 1 == bVerts.size()) ? 0 : i + 1); Vector normal = p2.subtract(p1).perpendicularCW(); normal = normal.normalize(); normals.add(normal); } Vector minOverlapVector = null; double minOverlap = Double.MAX_VALUE; for (Vector normal : normals) { double aMin = aVerts.get(0).dotProduct(normal); double aMax = aMin; for (Vector v : aVerts) { double dot = v.dotProduct(normal); if (dot < aMin) { aMin = dot; } else if (dot > aMax) { aMax = dot; } } double bMin = bVerts.get(0).dotProduct(normal); double bMax = bMin; for (Vector v : bVerts) { double dot = v.dotProduct(normal); if (dot < bMin) { bMin = dot; } if (dot > bMax) { bMax = dot; } } if (aMin > bMax || bMin > aMax) { return new Vector(0,0); } else { double overlap = Math.min(aMax - bMin, bMax - aMin); if (overlap <= minOverlap) { minOverlap = overlap; minOverlapVector = normal.scalarMultiplication(overlap); } } } return minOverlapVector; } |