web-dev-qa-db-fra.com

Comment détecter les intersections entre un cercle et un autre cercle dans le même plan?

Je cherche un algorithme pour détecter si un cercle coupe un autre cercle dans le même plan (étant donné qu'il peut y avoir plus d'un cercle dans un plan).

Une méthode que j'ai trouvée consiste à faire le test de l'axe de séparation. Ça dit:

Deux objets ne se croisent pas si vous pouvez trouver une ligne séparant les deux objets, c’est-à-dire une ligne telle que tous les objets ou points d’un objet se trouvent sur des côtés différents de la ligne.

Cependant, je ne sais pas comment appliquer cette méthode à mon cas.

Quelqu'un peut-il m'aider?

33
Jean-Luc Godard

Deux cercles se croisent si et seulement si la distance entre leurs centres est comprise entre la somme et la différence de leurs rayons. Étant donné deux cercles (x0, y0, R0) et (x1, y1, R1), la formule est la suivante:

ABS(R0 - R1) <= SQRT((x0 - x1)^2 + (y0 - y1)^2) <= (R0 + R1)

La quadrature des deux côtés vous permet d’éviter la lente SQRT et de conserver les ints si vos entrées sont des entiers:

(R0 - R1)^2 <= (x0 - x1)^2 + (y0 - y1)^2 <= (R0 + R1)^2

Comme vous n'avez besoin que d'un test oui/non, cette vérification est plus rapide que le calcul des points d'intersection exacts.

La solution ci-dessus devrait fonctionner même pour le cas "un cercle dans l'autre".

63
dasblinkenlight

En supposant une intersection de cercle rempli (c.-à-d. Qu'un cercle à l'intérieur d'un autre est une intersection).

Où:

  • x0, y0, r0 = centre et rayon du cercle 0.
  • x1, y1, r1 = centre et rayon du cercle 1.

Code:

boolean intersects = Math.hypot(x0-x1, y0-y1) <= (r0 + r1);
6
Craigo

Solution XNA/C #

    class Circle
    {
        public Vector2 Center;
        public float Radius;

        public bool Intersects(Circle circle)
        {
            float distanceX = Center.X - circle.Center.X;
            float distanceY = Center.Y - circle.Center.Y;
            float radiusSum = circle.Radius + Radius;
            return distanceX * distanceX + distanceY * distanceY <= radiusSum * radiusSum;
        }
        public bool Contains(Circle circle)
        {
            if (circle.Radius > Radius)
                return false;
            float distanceX = Center.X - circle.Center.X;
            float distanceY = Center.Y - circle.Center.Y;
            float radiusD = Radius - circle.Radius;
            return distanceX * distanceX + distanceY * distanceY <= radiusD * radiusD;
        }
    }

Notez que la méthode Circle.Intersects () renvoie true, même si un cercle se trouve dans un autre (les traite comme des cercles "remplis").

4
Peter Gruden

Si la distance entre les centres de deux cercles est au plus la somme de leurs rayons, mais au moins la valeur absolue de la différence entre les rayons, les cercles eux-mêmes se coupent en un point.

La partie "au moins la différence" s'applique si vous vous souciez uniquement des cercles eux-mêmes, et non de leurs zones intérieures. Si vous vous souciez de savoir si les cercles ou les zones qu’ils délimitent partagent des points - c’est-à-dire si un cercle totalement à l’autre compte comme "se croisant" pour vous - vous pouvez alors laisser tomber le "au moins la différence" vérifier.

2
cHao

J'ai essayé la formule donnée ici qui est une réponse supposée et tout le monde a voté de haut en bas bien que ce soit sérieusement imparfait. J'ai écrit un programme en JavaFX pour permettre à l'utilisateur de vérifier si deux cercles se croisent en modifiant les valeurs de chaque centre centerX, centerY et Radius. Cette formule ne fonctionne absolument déplacer le cercle 2 près du cercle 1 ça marche mais quand je déplace le cercle 1 de l’autre côté du cercle 2 ça ne marche pas ..... ????? c'est un peu bizarre ... pensais que la formule devait être testée dans le sens opposé, donc essayée et ça ne marche pas

if (Math.abs(circle1Radius - circle2Radius) <=
            Math.sqrt(Math.pow((circle1X - circle2X), 2)
            + Math.pow((circle1Y - circle2Y), 2)) &&
            Math.sqrt(Math.pow((circle1X - circle2X), 2)
            + Math.pow((circle1X - circle2Y), 2)) <=
            (circle1Radius + circle2Radius)} {
    return true;
} else {
    return false;
}

Cela marche:

    // dx and dy are the vertical and horizontal distances
    double dx = circle2X - circle1X;
    double dy = circle2Y - circle1Y;

    // Determine the straight-line distance between centers.
    double d = Math.sqrt((dy * dy) + (dx * dx));

    // Check Intersections
    if (d > (circle1Radius + circle2Radius)) {
        // No Solution. Circles do not intersect
        return false;
    } else if (d < Math.abs(circle1Radius - circle2Radius)) {
        // No Solution. one circle is contained in the other
        return false;
    } else {
        return true;
    }

Allez ici pour la formule Intersection de deux cercles

La formule utilisée n’est pas la mienne, tout le mérite revient à Paul Bourke (avril 1997)

 First calculate the distance d between the center of the circles. d = ||P1 - P0||.

    If d > r0 + r1 then there are no solutions, the circles are separate.

    If d < |r0 - r1| then there are no solutions because one circle is contained within the other.

    If d = 0 and r0 = r1 then the circles are coincident and there are an infinite number of solutions.

Considering the two triangles P0P2P3 and P1P2P3 we can write

a2 + h2 = r02 and b2 + h2 = r12

Using d = a + b we can solve for a,

a = (r02 - r12 + d2 ) / (2 d)

It can be readily shown that this reduces to r0 when the two circles touch at one point, ie: d = r0 + r1

Solve for h by substituting a into the first equation, h2 = r02 - a2
So

P2 = P0 + a ( P1 - P0 ) / d

And finally, P3 = (x3,y3) in terms of P0 = (x0,y0), P1 = (x1,y1) and P2 = (x2,y2), is

x3 = x2 +- h ( y1 - y0 ) / d

y3 = y2 -+ h ( x1 - x0 ) / d 
0
John Conner