# Separating Axis Theorem fails at certain angles

I'm currently attempting to add an overlap tester for an axis aligned and orientated bounding box but the solution only seems to work accurately when the OBB's angle is between -10 and +10. As the angle approaches +90 degrees the collision area seems to at first move to the right half of the OBB and then become non existent. Between 90 and 270 I couldn't get an overlap and then when it comes round a full 360 the area registers accurately again.

Any light on this subject would be great. I'm using positive X for 0 degrees increasing CCW.

EDIT: Did a little more research and realized that projecting a vector onto another requires more than just a dot product. Could any one give me a correct version of one of the check axis methods below?

EDIT 2: Actually just a dot product should do I think since the vectors being projected onto are unit length.

public static bool overlapAABB_OBB(AABB a, OBB o)
{
T = Vector2.Subtract(o.position, a.position);
Ax.X = 1;
Ax.Y = 0;
Ay.X = 0;
Ay.Y = 1;
Oy.X = -Ox.Y;
Oy.Y = Ox.X;
if (checkAX(a, o) &&
checkAY(a, o) &&
checkOX(a, o) &&
checkOY(a, o))
return true;
else
return false;
}

private static bool checkAX(AABB a, OBB o)
{
float TAx = Vector2.Dot(T, Ax);
float WoOxAx = Vector2.Dot(Vector2.Multiply(Ox, o.halfWidth), Ax);
float HoOyAx = Vector2.Dot(Vector2.Multiply(Oy, o.halfHeight), Ax);
if (TAx > a.halfWidth + WoOxAx + HoOyAx)
return false;
else
return true;
}

private static bool checkAY(AABB a, OBB o)
{
float TAy = Vector2.Dot(T, Ay);
float WoOxAy = Vector2.Dot(Vector2.Multiply(Ox, o.halfWidth), Ay);
float HoOyAy = Vector2.Dot(Vector2.Multiply(Oy, o.halfHeight), Ay);
if (TAy > a.halfHeight + WoOxAy + HoOyAy)
return false;
else
return true;
}

private static bool checkOX(AABB a, OBB o)
{
float TOx = Vector2.Dot(T, Ox);
float WaAxOx = Vector2.Dot(Vector2.Multiply(Ax, a.halfWidth), Ox);
float HaAyOx = Vector2.Dot(Vector2.Multiply(Ay, a.halfHeight), Ox);
if (TOx > o.halfWidth + WaAxOx + HaAyOx)
return false;
else
return true;
}

private static bool checkOY(AABB a, OBB o)
{
float TOy = Vector2.Dot(T, Oy);
float WaAxOy = Vector2.Dot(Vector2.Multiply(Ax, a.halfWidth), Oy);
float HaAyOy = Vector2.Dot(Vector2.Multiply(Ay, a.halfHeight), Oy);
if (TOy > o.halfHeight + WaAxOy + HaAyOy)
return false;
else
return true;
}

• Since this is a well known algorithm, I'm assuming this is just a flaw in your implementation. Most likely too localized for the site. – MichaelHouse Jan 11 '13 at 3:30
• I thought I was close as I followed the calculation as best as I could I just didn't realise |ProjB(A)| meant the absolute value of vector B on A – Mazk1985 Jan 11 '13 at 16:52

dot product is negative when the angle between the two vectors is greater than 90º, for the code to work properly you would need to take the absolute value of the dot product.

//...
private static bool checkAX(AABB a, OBB o)
{
float TAx    = Math.Abs( Vector2.Dot(T, Ax) );
float WoOxAx = Math.Abs( Vector2.Dot(Vector2.Multiply(Ox, o.halfWidth), Ax) );
float HoOyAx = Math.Abs( Vector2.Dot(Vector2.Multiply(Oy, o.halfHeight), Ax) );
if (TAx > a.halfWidth + WoOxAx + HoOyAx)
return false;
else
return true;
}
//...


this also applies to checkAY, checkOX, and checkOY

• Nice one. Thank you very much. I did eventually get it to work but I replaced every dot product with a custom method that got the projection vector and then worked out it length but your way eliminates 12 square roots per overlap so that's awesome. Thanks again. – Mazk1985 Jan 11 '13 at 16:37