4

Below is a function that detects if two circles intersect. I want to change it to only detect if the periferi of the circles intersect. Hence, if circle A is completely inside circle B, there is no collision!

How?

private bool IsCircleCollision(
    int x1, int y1, int radius1,
    int x2, int y2, int radius2)
{
    int dx = x2 - x1;
    int dy = y2 - y1;

    int distance = (dx * dx) + (dy * dy);

    int radii = radius1 + radius2;
    if (distance < radii * radii)
    {
        return true;
    }
    else
    {
        return false;
    }
}
l33t
  • 18,692
  • 16
  • 103
  • 180
  • You may want to rephrase that title - if two circles are inside *each other*, i.e. *A is inside B* and *B is inside A* at the same time, then, depending on your definition, this is either always false or only true if A and B have identical location and radius. – Hackworth Sep 03 '12 at 16:07
  • This seems like a duplicate of the following question, does this suit your needs? [http://stackoverflow.com/questions/8367512/algorithm-to-detect-if-a-circles-intersect-with-any-other-circle-in-the-same-pla](http://stackoverflow.com/questions/8367512/algorithm-to-detect-if-a-circles-intersect-with-any-other-circle-in-the-same-pla) – alvonellos Sep 03 '12 at 16:06

4 Answers4

7

You work this out by calculating the distance between the two centres, D say. There is an intersection if

abs(R1-R2) < D < R1+R2

where R1 and R2 are the radii of the two circles.

The first test, abs(R1-R2) < D handles the case when one circle's centre is inside the other's. And the second test, D < R1+R2, handles the case when neither circle contains the other's centre.

So, adapting your code we have:

private bool IsCircleCollision(
    int x1, int y1, int radius1,
    int x2, int y2, int radius2)
{
    int dx = x2 - x1;
    int dy = y2 - y1;

    double D = Math.Sqrt(dx*dx + dy*dy);
    return Math.Abs(radius1-radius2)<D && D<radius1+radius2;
}

If performance is important here, you can do without the call to Math.Sqrt like this:

private bool IsCircleCollision(
    int x1, int y1, int radius1,
    int x2, int y2, int radius2)
{
    int dx = x2 - x1;
    int dy = y2 - y1;

    int Dsqr = dx*dx + dy*dy;
    int rdiff = Math.Abs(radius1-radius2);
    int rsum = radius1+radius2
    return rdiff*rdiff<Dsqr && D<rsum*rsum;
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Drop the `Sqrt` it can be expensive then just compare the squared values – Bob Vale Sep 03 '12 at 16:07
  • @DavidHeffernan yes but as the OP is already using that optimization in their example... – Bob Vale Sep 03 '12 at 16:09
  • Aren't there plenty of cases where D/Dsqr can be less than the differences in radius for an otherwise acceptable collision? For instance, what if the distance between the two circles is zero? – S.Ahl Jan 09 '18 at 00:27
2

The perimeters will be intersecting if and only if the distance between the two centers is less than or equal to the sum of the two radii but greater than or equal to their absolute difference. With this fact, it shouldn't be hard to re-write the function.

arshajii
  • 127,459
  • 24
  • 238
  • 287
0

You could add a check to see if the distance + radius1 is less than radius2 or distance + radius2 is less than radius1, but then you'll need distance to be the actual distance rather than its square.

David
  • 1,429
  • 8
  • 8
0
else if (Math.Sqrt(dx * dx + dy * dy) < Math.Abs(radius1 - radius2))
LaGrandMere
  • 10,265
  • 1
  • 33
  • 41