I took this answer, which is AABB - circle intersection and changed it into OBB - circle intersection and added compute of intersection point.
struct Vec2
{
Vec2(): x( 0.0f ), y( 0.0f ) { }
Vec2( float _x, float _y ): x( _x ), y( _y ) { }
float x, y;
};
struct Box
{
Vec2 Position, Size;
float rotation;
};
struct Circle
{
Vec2 Position;
float radius;
};
Vec2 TranslatePointOnBox( const Vec2& BoxPosition, const Vec2& BoxRotation, const Vec2& Point, const Vec2& Sign )
{
Vec2 LocalPoint( Point.x * Sign.x, Point.y * Sign.y );
Vec2 WorldPoint;
// rotate
WorldPoint.x = LocalPoint.x * BoxRotation.x - LocalPoint.y * BoxRotation.y + BoxPosition.x;
WorldPoint.y = LocalPoint.y * BoxRotation.x + LocalPoint.x * BoxRotation.y + BoxPosition.y;
// translate
WorldPoint.x += BoxPosition.x;
WorldPoint.y += BoxPosition.y;
return WorldPoint;
}
bool Itersects( const Circle& circle, const Box& box, Vec2& OutputPoint )
{
Vec2 Diff1; // difference in world coord.
Vec2 Diff2; // difference in local coord.
Vec2 Rotation;
Vec2 HalfSize;
Vec2 Sign; // for restoring intersection quadrant
Diff1.x = circle.Position.x - box.Position.x;
Diff1.y = circle.Position.y - box.Position.y;
Rotation.x = cos( box.rotation );
Rotation.y = sin( box.rotation );
Diff2.x = Diff1.x * Rotation.x - Diff1.y * Rotation.y;
Diff2.y = Diff1.y * Rotation.x + Diff1.x * Rotation.y;
Sign.x = Diff2.x < 0.0f ? -1.0f : 1.0f;
Sign.y = Diff2.y < 0.0f ? -1.0f : 1.0f;
Diff2.x = abs( Diff2.x );
Diff2.y = abs( Diff2.y );
HalfSize.x = box.Size.x / 2.0f;
HalfSize.y = box.Size.y / 2.0f;
// intersection AABB - circle
if( Diff2.x > HalfSize.x + circle.radius ||
Diff2.y > HalfSize.y + circle.radius )
{
OutputPoint = Vec2( 0.0f, 0.0f );
return false;
}
if( Diff2.x <= HalfSize.x )
{
OutputPoint = TranslatePointOnBox( box.Position, Rotation, Vec2( HalfSize.x, Diff2.y ), Sign );
return true;
}
if( Diff2.y <= HalfSize.y )
{
OutputPoint = TranslatePointOnBox( box.Position, Rotation, Vec2( Diff2.x, HalfSize.y ), Sign );
return true;
}
float CornerDistSquared =
pow( Diff2.x - HalfSize.x, 2.0f ) +
pow( Diff2.y - HalfSize.y, 2.0f );
if( CornerDistSquared <= circle.radius * circle.radius )
{
OutputPoint = TranslatePointOnBox( box.Position, Rotation, HalfSize, Sign );
return true;
}
else
{
OutputPoint = Vec2( 0.0f, 0.0f );
return false;
}
}
Note:
Intersection point is located on box surface, closest to circle center.
It is better to hold Box rotation in Vec2 rotation; instead float rotation;, so you don't need to compute sin/cos each intersection (compute only when rotation changes).
And you can omit OutputPoint = Vec2( 0.0f, 0.0f );, it return zero vector in no intersection cases.