Equazione per verificare se un punto si trova all'interno di un cerchio


309

Se hai un cerchio con centro (center_x, center_y)e raggio radius, come fai a verificare se un determinato punto con coordinate si (x, y)trova all'interno del cerchio?


20
Questa domanda è davvero indipendente dal linguaggio, sto usando la stessa formula in Java, quindi ri-tagging.
Gautam,

Sembra che stai assumendo solo coordinate positive. Le soluzioni seguenti non funzionano con coordinate firmate.
cjbarth,

La maggior parte delle soluzioni di seguito fanno il lavoro con le coordinate positive e negative. Sto solo correggendo quel bocconcino per i futuri spettatori di questa domanda.
William Morrison,

Sto votando per chiudere questa domanda come fuori tema perché si tratta di matematica della scuola media piuttosto che di programmazione.
n. 'pronomi' m.

Risposte:


481

In generale, xe ydeve soddisfare (x - center_x)^2 + (y - center_y)^2 < radius^2.

Si noti che i punti che soddisfano l'equazione di cui sopra con <sostituiti da ==vengono considerati i punti sul cerchio e i punti che soddisfano l'equazione di cui sopra con <sostituiti da >vengono considerati all'esterno del cerchio.


6
Potrebbe aiutare alcune persone meno matematiche a vedere l'operazione di radice quadrata utilizzata per misurare la distanza rispetto al raggio. Mi rendo conto che non è ottimale, ma poiché la tua risposta è formattata più come un'equazione che come codice forse ha più senso? Solo un suggerimento.
William Morrison,

30
Questa è la spiegazione più comprensibile fornita in una semplice frase e un'equazione immediatamente utilizzabile. Molto bene.
thgc

questo è un grande desiderio di trovare questa risorsa più velocemente. Da dove viene il valore x?
Devin Tripp

2
@DevinTripp 'x' è la coordinata x del punto da testare.
Chris,

5
Questo può essere ovvio, ma va detto che <=troveranno punti all'interno del cerchio o sul bordo.
Tyler,

131

Matematicamente, Pitagora è probabilmente un metodo semplice come molti hanno già menzionato.

(x-center_x)^2 + (y - center_y)^2 < radius^2

Computazionalmente, ci sono modi più rapidi. Definire:

dx = abs(x-center_x)
dy = abs(y-center_y)
R = radius

Se è più probabile che un punto si trovi all'esterno di questo cerchio, immagina un quadrato disegnato attorno ad esso in modo tale che i suoi lati siano tangenti a questo cerchio:

if dx>R then 
    return false.
if dy>R then 
    return false.

Ora immagina un diamante quadrato disegnato all'interno di questo cerchio in modo tale che i suoi vertici tocchino questo cerchio:

if dx + dy <= R then 
    return true.

Ora abbiamo coperto la maggior parte del nostro spazio e solo una piccola area di questo cerchio rimane tra il nostro quadrato e il diamante da testare. Qui torniamo a Pitagora come sopra.

if dx^2 + dy^2 <= R^2 then 
    return true
else 
    return false.

Se è più probabile che un punto si trovi all'interno di questo cerchio, inverti l'ordine dei primi 3 passaggi:

if dx + dy <= R then 
    return true.
if dx > R then 
    return false.
if dy > R 
    then return false.
if dx^2 + dy^2 <= R^2 then 
    return true
else
    return false.

Metodi alternativi immaginano un quadrato all'interno di questo cerchio anziché un diamante, ma ciò richiede leggermente più test e calcoli senza alcun vantaggio computazionale (il quadrato interno e i diamanti hanno aree identiche):

k = R/sqrt(2)
if dx <= k and dy <= k then 
    return true.

Aggiornare:

Per coloro che sono interessati alle prestazioni, ho implementato questo metodo in c e compilato con -O3.

Ho ottenuto i tempi di esecuzione di time ./a.out

Ho implementato questo metodo, un metodo normale e un metodo fittizio per determinare i tempi di consegna.

Normal: 21.3s This: 19.1s Overhead: 16.5s

Quindi, sembra che questo metodo sia più efficiente in questa implementazione.

// compile gcc -O3 <filename>.c
// run: time ./a.out

#include <stdio.h>
#include <stdlib.h>

#define TRUE  (0==0)
#define FALSE (0==1)

#define ABS(x) (((x)<0)?(0-(x)):(x))

int xo, yo, R;

int inline inCircle( int x, int y ){  // 19.1, 19.1, 19.1
  int dx = ABS(x-xo);
  if (    dx >  R ) return FALSE;
  int dy = ABS(y-yo);
  if (    dy >  R ) return FALSE;
  if ( dx+dy <= R ) return TRUE;
  return ( dx*dx + dy*dy <= R*R );
}

int inline inCircleN( int x, int y ){  // 21.3, 21.1, 21.5
  int dx = ABS(x-xo);
  int dy = ABS(y-yo);
  return ( dx*dx + dy*dy <= R*R );
}

int inline dummy( int x, int y ){  // 16.6, 16.5, 16.4
  int dx = ABS(x-xo);
  int dy = ABS(y-yo);
  return FALSE;
}

#define N 1000000000

int main(){
  int x, y;
  xo = rand()%1000; yo = rand()%1000; R = 1;
  int n = 0;
  int c;
  for (c=0; c<N; c++){
    x = rand()%1000; y = rand()%1000;
//    if ( inCircle(x,y)  ){
    if ( inCircleN(x,y) ){
//    if ( dummy(x,y) ){
      n++;
    }
  }
  printf( "%d of %d inside circle\n", n, N);
}

5
Questa risposta è eccellente Non avevo mai realizzato alcune delle ottimizzazioni che suggerisci. Molto bene.
William Morrison,

2
Sono curioso di sapere se hai profilato queste ottimizzazioni? La mia sensazione è che più condizionali sarebbero più lenti di alcuni matematici e uno condizionale, ma potrei sbagliarmi.
yoyo

3
@yoyo, non ho preformato nessuna profilazione - questa domanda riguarda un metodo per qualsiasi linguaggio di programmazione. Se qualcuno ritiene che ciò possa migliorare le prestazioni nella propria applicazione, dovrebbe, come suggerisci, dimostrare che è più veloce in scenari normali.
philcolbourn,

2
In funzione inCircleNstai usando ABS non necessari. Probabilmente senza ABS differenza tra inCirclee inCircleNsarebbe più piccolo.
tzaloga,

1
La rimozione dell'ABS migliora le prestazioni inCircleN ma non è sufficiente. Tuttavia, il mio metodo è stato distorto verso punti più probabili al di fuori del cerchio poiché R = 1. Con raggio casuale [0..499], circa il 25% dei punti erano all'interno del cerchio e inCircleN è più veloce.
philcolbourn,

74

Puoi usare Pitagora per misurare la distanza tra il tuo punto e il centro e vedere se è inferiore al raggio:

def in_circle(center_x, center_y, radius, x, y):
    dist = math.sqrt((center_x - x) ** 2 + (center_y - y) ** 2)
    return dist <= radius

EDIT (punta di cappello a Paul)

In pratica, la quadratura è spesso molto più economica rispetto alla radice quadrata e poiché siamo interessati solo a un ordinamento, possiamo ovviamente rinunciare a prendere la radice quadrata:

def in_circle(center_x, center_y, radius, x, y):
    square_dist = (center_x - x) ** 2 + (center_y - y) ** 2
    return square_dist <= radius ** 2

Inoltre, Jason ha notato che <=dovrebbe essere sostituito da <e, a seconda dell'uso, questo potrebbe effettivamente avere sensoanche se credo che non sia vero in senso matematico rigoroso. Sono corretto.


1
Sostituisci dist <= raggio con dist <raggio per verificare il punto all'interno del cerchio.
Jason,

16
sqrt è costoso. Se possibile, evitatelo: confronta x ^ 2 + y ^ y con r ^ 2.
Paul Tomblin,

Jason: le nostre definizioni possono non essere d'accordo, ma per me un punto che si trova sulla circonferenza del cerchio è più enfaticamente anche nel cerchio e sono abbastanza sicuro che il mio sia in accordo con la definizione formale, matematica.
Konrad Rudolph,

3
La definizione matematica formale dell'interno di un cerchio è quella che ho dato nel mio post. Da Wikipedia: In generale, l'interno di qualcosa si riferisce allo spazio o parte al suo interno, escludendo qualsiasi tipo di muro o confine attorno al suo esterno. en.wikipedia.org/wiki/Interior_(topology)
jason

1
In pascal, delphi e FPC, sia la potenza che sqrt sono costose , e non c'è nessun operatore di energia EG: **o ^. Il modo più veloce per farlo quando basta x ^ 2 o x ^ 3 è quello di farlo "manualmente": x*x.
JHolta

37
boolean isInRectangle(double centerX, double centerY, double radius, 
    double x, double y)
{
        return x >= centerX - radius && x <= centerX + radius && 
            y >= centerY - radius && y <= centerY + radius;
}    

//test if coordinate (x, y) is within a radius from coordinate (center_x, center_y)
public boolean isPointInCircle(double centerX, double centerY, 
    double radius, double x, double y)
{
    if(isInRectangle(centerX, centerY, radius, x, y))
    {
        double dx = centerX - x;
        double dy = centerY - y;
        dx *= dx;
        dy *= dy;
        double distanceSquared = dx + dy;
        double radiusSquared = radius * radius;
        return distanceSquared <= radiusSquared;
    }
    return false;
}

Questo è più efficiente e leggibile. Evita la costosa operazione di radice quadrata. Ho anche aggiunto un segno di spunta per determinare se il punto si trova all'interno del rettangolo di delimitazione del cerchio.

Il controllo del rettangolo non è necessario se non con molti punti o molti cerchi. Se la maggior parte dei punti sono all'interno dei cerchi, il controllo del rettangolo di delimitazione renderà le cose più lente!

Come sempre, assicurati di considerare il tuo caso d'uso.


12

Calcola la distanza

D = Math.Sqrt(Math.Pow(center_x - x, 2) + Math.Pow(center_y - y, 2))
return D <= radius

che è in C # ... converti per l'uso in Python ...


11
Puoi evitare due costose chiamate Sqrt confrontando D-quadrato con raggio-quadrato.
Paul Tomblin,

10

Dovresti verificare se la distanza dal centro del cerchio al punto è inferiore al raggio, ad es

if (x-center_x)**2 + (y-center_y)**2 <= radius**2:
    # inside circle

5

Come detto sopra, usa la distanza euclidea.

from math import hypot

def in_radius(c_x, c_y, r, x, y):
    return math.hypot(c_x-x, c_y-y) <= r

4

Trova la distanza tra il centro del cerchio e i punti indicati. Se la distanza tra loro è inferiore al raggio, il punto si trova all'interno del cerchio. se la distanza tra loro è uguale al raggio del cerchio, allora il punto è sulla circonferenza del cerchio. se la distanza è maggiore del raggio, il punto si trova all'esterno del cerchio.

int d = r^2 - (center_x-x)^2 + (center_y-y)^2;

if(d>0)
  print("inside");
else if(d==0)
  print("on the circumference");
else
  print("outside");

4

L'equazione seguente è un'espressione che verifica se un punto si trova all'interno di un determinato cerchio in cui xP e yP sono le coordinate del punto, xC e yC sono le coordinate del centro del cerchio e R è il raggio di quel determinato cerchio.

inserisci qui la descrizione dell'immagine

Se l'espressione sopra è vera, il punto è all'interno del cerchio.

Di seguito è riportata un'implementazione di esempio in C #:

    public static bool IsWithinCircle(PointF pC, Point pP, Single fRadius){
        return Distance(pC, pP) <= fRadius;
    }

    public static Single Distance(PointF p1, PointF p2){
        Single dX = p1.X - p2.X;
        Single dY = p1.Y - p2.Y;
        Single multi = dX * dX + dY * dY;
        Single dist = (Single)Math.Round((Single)Math.Sqrt(multi), 3);

        return (Single)dist;
    }

2

Questa è la stessa soluzione menzionata da Jason Punyon , ma contiene un esempio di pseudo-codice e alcuni dettagli in più. Ho visto la sua risposta dopo aver scritto questo, ma non volevo rimuovere la mia.

Penso che il modo più facilmente comprensibile sia calcolare prima la distanza tra il centro del cerchio e il punto. Vorrei usare questa formula:

d = sqrt((circle_x - x)^2 + (circle_y - y)^2)

Quindi, confronta semplicemente il risultato di quella formula, la distanza ( d), con il radius. Se la distanza ( d) è inferiore o uguale al raggio ( r), il punto si trova all'interno del cerchio (sul bordo del cerchio se de rsono uguali).

Ecco un esempio di pseudo-codice che può essere facilmente convertito in qualsiasi linguaggio di programmazione:

function is_in_circle(circle_x, circle_y, r, x, y)
{
    d = sqrt((circle_x - x)^2 + (circle_y - y)^2);
    return d <= r;
}

Dove circle_xe circle_ysono le coordinate centrali del cerchio, rè il raggio del cerchio xed yè le coordinate del punto.


2

La mia risposta in C # come soluzione completa taglia e incolla (non ottimizzata):

public static bool PointIsWithinCircle(double circleRadius, double circleCenterPointX, double circleCenterPointY, double pointToCheckX, double pointToCheckY)
{
    return (Math.Pow(pointToCheckX - circleCenterPointX, 2) + Math.Pow(pointToCheckY - circleCenterPointY, 2)) < (Math.Pow(circleRadius, 2));
}

Uso:

if (!PointIsWithinCircle(3, 3, 3, .5, .5)) { }

1

Come affermato in precedenza, per mostrare se il punto è nel cerchio possiamo usare quanto segue

if ((x-center_x)^2 + (y - center_y)^2 < radius^2) {
    in.circle <- "True"
} else {
    in.circle <- "False"
}

Per rappresentarlo graficamente possiamo usare:

plot(x, y, asp = 1, xlim = c(-1, 1), ylim = c(-1, 1), col = ifelse((x-center_x)^2 + (y - center_y)^2 < radius^2,'green','red'))
draw.circle(0, 0, 1, nv = 1000, border = NULL, col = NA, lty = 1, lwd = 1)

0

Ho usato il codice qui sotto per i principianti come me :).

public class incirkel {

public static void main(String[] args) {
    int x; 
    int y; 
    int middelx; 
    int middely; 
    int straal; {

// Adjust the coordinates of x and y 
x = -1;
y = -2;

// Adjust the coordinates of the circle
middelx = 9; 
middely = 9;
straal =  10;

{
    //When x,y is within the circle the message below will be printed
    if ((((middelx - x) * (middelx - x)) 
                    + ((middely - y) * (middely - y))) 
                    < (straal * straal)) {
                        System.out.println("coordinaten x,y vallen binnen cirkel");
    //When x,y is NOT within the circle the error message below will be printed
    } else {
        System.err.println("x,y coordinaten vallen helaas buiten de cirkel");
    } 
}



    }
}}

0

Spostandoti nel mondo del 3D se vuoi verificare se un punto 3D si trova in una Sfera Unità, finisci per fare qualcosa di simile. Tutto ciò che serve per lavorare in 2D è usare le operazioni vettoriali 2D.

    public static bool Intersects(Vector3 point, Vector3 center, float radius)
    {
        Vector3 displacementToCenter = point - center;

        float radiusSqr = radius * radius;

        bool intersects = displacementToCenter.magnitude < radiusSqr;

        return intersects;
    }

0

So che mancano pochi anni alla risposta più votata, ma sono riuscito a ridurre i tempi di calcolo di 4.

Devi solo calcolare i pixel da 1/4 del cerchio, quindi moltiplicarli per 4.

Questa è la soluzione che ho raggiunto:

#include <stdio.h>
#include <stdlib.h>
#include <time.h> 

int x, y, r;
int mx, c, t;
int dx, dy;
int p;

int main() {
    for (r = 1; r < 128; r++){

        clock_t t; 
        t = clock();

        p = calculatePixels(r);

        t = clock() - t; 
        double time_taken = ((double)t)/CLOCKS_PER_SEC; // in seconds 

        printf( "%d of pixels inside circle with radius %d, took %f seconds to execute \n", p, r, time_taken);
    }
}

int calculatePixels(int r){
    mx = 2 * r;
    c = (mx+1)*(mx+1);
    t = r * r;
    int a = 0;
    for (x = 0; x < r; x++){
      for (y = 0; y < r; y++){
          dx = x-r;
          dy = y-r;
          if ((dx*dx + dy*dy) > t)
              a++;
          else 
              y = r;
      }
    }
    return (c - (a * 4));
}


0

PHP

if ((($x - $center_x) ** 2 + ($y - $center_y) ** 2) <=  $radius **2) {
    return true; // Inside
} else {
    return false; // Outside
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.