Рівняння для тестування, якщо точка знаходиться в колі


309

Якщо у вас є коло з центром (center_x, center_y)і радіусом radius, як ви перевіряєте, чи є дана точка з координатами (x, y)всередині кола?


20
Це питання насправді мовний агностик, я використовую ту саму формулу в java, Тож повторне позначення тегів.
Гаутам

Здається, що припускаючи лише позитивні координати. Наведені нижче рішення не працюють із підписаними координатами.
cjbarth

Більшість рішень нижче зробити роботу з позитивними і негативними координатами. Просто виправляючи цей примх для майбутніх глядачів цього питання.
Вільям Моррісон

Я голосую, щоб закрити це питання поза темою, оскільки це стосується математики середньої школи, а не програмування.
н. 'займенники' м.

Відповіді:


481

Загалом, xі yповинні задовольняти (x - center_x)^2 + (y - center_y)^2 < radius^2.

Зверніть увагу, що точки, які задовольняють наведеному рівнянню <замінені на ==, вважаються точками на колі, а точки, які задовольняють наведеному рівнянню на <замінені на >, вважаються поза колом.


6
Можливо, це допоможе деяким менш розумним людям побачити операцію квадратного кореня, яка використовується для вимірювання відстані порівняно з радіусом. Я усвідомлюю, що це не оптимально, але оскільки формату вашої відповіді більше нагадує рівняння, ніж код, можливо, це має більше сенсу? Просто пропозиція.
Вільям Моррісон

30
Це найбільш зрозуміле пояснення, подане лише у простому реченні та негайно використаному рівнянні. Молодці.
thgc

це велике бажання, якби я знайшов цей ресурс швидше. Звідки береться значення x?
Девін Тріпп

2
@DevinTripp 'x' - координата x точки тестуваної точки.
Кріс

5
Це може бути очевидним, але слід зазначити, що <=знайдете точки всередині кола або на його краю.
Тайлер

131

Математично Піфагор - це, мабуть, простий метод, про який багато хто вже згадував.

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

Обчислено, існують більш швидкі способи. Визначте:

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

Якщо більша ймовірність того, що точка знаходиться поза цим колом, то уявіть собі квадрат, намальований навколо нього, таким чином, що сторони є дотичними до цього кола:

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

Тепер уявіть собі квадратний ромб, намальований всередині цього кола, таким чином, щоб його вершини торкалися цього кола:

if dx + dy <= R then 
    return true.

Тепер ми охопили більшу частину нашого простору, і лише невелика площа цього кола залишається між нашим квадратом та діамантом, який потрібно перевірити. Тут ми повертаємось до Піфагора, як вище.

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

Якщо більша ймовірність, що точка знаходиться всередині цього кола, то зворотний порядок перших 3 кроків:

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.

Альтернативні методи уявляють собі квадрат у цьому колі замість алмазу, але для цього потрібно трохи більше випробувань та обчислень без обчислювальної переваги (внутрішній квадрат і алмази мають однакові площі):

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

Оновлення:

Для тих, хто зацікавлений у продуктивності, я реалізував цей метод на c і ​​склав з -O3.

Я отримав терміни виконання до time ./a.out

Я реалізував цей метод, звичайний метод і фіктивний метод, щоб визначити накладні витрати.

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

Отже, здається, що цей метод є більш ефективним у цій реалізації.

// 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
Ця відповідь відмінна. Я ніколи не усвідомлював деякі запропоновані вами оптимізації. Молодці.
Вільям Моррісон

2
Мені цікаво дізнатися, чи ви профілювали ці оптимізації? Моє відчуття кишки полягає в тому, що кілька умовних умов будуть повільнішими, ніж деякі математичні та одні умовні, але я можу помилитися.
yoyo

3
@yoyo, у мене не передбачено профілювання - це питання про метод для будь-якої мови програмування. Якщо хтось вважає, що це може покращити ефективність їх застосування, то, як ви пропонуєте, він повинен продемонструвати це швидше в звичайних сценаріях.
philcolbourn

2
У функції inCircleNви використовуєте непотрібний ABS. Напевно, без різниці між АБС inCircleі inCircleNбуло б менше.
tzaloga

1
Видалення ABS покращує продуктивність inCircleN, але недостатньо. Однак мій метод був упереджений до точок, більш імовірних поза колом, оскільки R = 1. Із випадковим радіусом [0..499] близько 25% точок знаходилися всередині кола, а InCircleN швидше.
philcolbourn

74

Ви можете використовувати Піфагора, щоб виміряти відстань між точкою та центром і побачити, чи нижчий він від радіуса:

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 (капелюшний наконечник до Пола)

На практиці, квадратування часто набагато дешевше, ніж отримання квадратного кореня, і оскільки нас цікавить лише замовлення, ми, звичайно, можемо відмовитися від отримання квадратного кореня:

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

Також Джейсон зауважив, що його <=слід замінити <і залежно від використання це може насправді мати сенсхоча я вважаю, що це неправда в суворому математичному сенсі. Я стою виправлений.


1
Замініть dist <= радіус на dist <радіус, щоб перевірити, чи є точка всередині кола.
Ясон

16
sqrt дорого. Якщо це можливо, уникайте цього - порівняйте x ^ 2 + y ^ y з r ^ 2.
Пол Томблін

Джейсон: наші визначення можуть НЕ погодитися , але для мене, точки, на окружності кола, найбільш рішуче і в колі , і я впевнений , що шахта згідно з формальним, математичним визначенням.
Конрад Рудольф

3
Формальне математичне визначення інтер’єру кола - це те, що я дав у своєму дописі. З Вікіпедії: Взагалі інтер'єр чогось стосується простору або частини всередині нього, виключаючи будь-яку стіну або межу навколо її зовнішньої сторони. en.wikipedia.org/wiki/Interior_(topology)
ясон

1
У паскалі, delphi та FPC, і power, і sqrt коштує дорого , і немає енергооператора EG: **або ^. Найшвидший спосіб зробити це, коли вам просто потрібно x ^ 2 або x ^ 3 - це зробити це «вручну» : 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;
}

Це більш ефективно та читабельно. Це дозволяє уникнути дорогої операції квадратного кореня. Я також додав чек, щоб визначити, чи точка знаходиться в обмежувальному прямокутнику кола.

Перевірка прямокутника зайва, за винятком багатьох точок або багатьох кіл. Якщо більшість точок знаходяться всередині кіл, перевірка обмежувального прямокутника насправді полегшить роботу!

Як завжди, обов'язково врахуйте ваш варіант використання.


12

Обчисліть відстань

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

це в C # ... конвертувати для використання в python ...


11
Ви можете уникнути двох дорогих дзвінків Sqrt, порівнюючи D-квадрат до радіуса.
Пол Томблін

10

Ви повинні перевірити, чи менша відстань від центру кола до точки, ніж радіус, тобто

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

5

Як було сказано вище - використовуйте евклідову відстань.

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

Знайдіть відстань між центром кола і поданими точками. Якщо відстань між ними менша за радіус, то точка знаходиться всередині кола. якщо відстань між ними дорівнює радіусу кола, то точка знаходиться на окружності кола. якщо відстань більша за радіус, то точка знаходиться поза колом.

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

Рівняння нижче є виразом , яке перевіряє , є чи точка знаходиться в межах заданої окружності , де хРи & Урів є координатами точки, хс & вус є координатами центру кола , а R являє собою радіус цієї заданої окружності.

введіть тут опис зображення

Якщо наведене вище вираження є істинним, то точка знаходиться в колі.

Нижче представлений зразок реалізації в 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

Це те саме рішення, що згадував Джейсон Пуньйон , але воно містить приклад псевдокоду та ще деякі деталі. Я побачив його відповідь після написання цього, але не хотів знімати свою.

Я думаю, що найбільш легко зрозумілим способом є спочатку обчислити відстань між центром кола та точкою. Я б використав цю формулу:

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

Потім просто порівняйте результат цієї формули, відстань ( d), і значення radius. Якщо відстань ( d) менше або дорівнює радіусу ( r), то точка знаходиться всередині кола (на краю кола, якщо dі rрівні).

Ось приклад псевдокоду, який можна легко перетворити на будь-яку мову програмування:

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

Де circle_xі circle_yє центральними координатами кола, r- радіус кола, xі y- координати точки.


2

Моя відповідь на C # як повне вирізання та вставлення (не оптимізоване) рішення:

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));
}

Використання:

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

1

Як було сказано раніше, щоб показати, чи точка знаходиться в колі, ми можемо використовувати наступне

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

Щоб зобразити це графічно, ми можемо використовувати:

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

Я використовував код нижче для початківців, як я :).

публічний клас 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

Перемістившись у світ 3D, якщо ви хочете перевірити, чи є 3D-точка в одиничній сфері, ви зробите щось подібне. Все, що потрібно для роботи в 2D, - це використання 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

Я знаю, що минуло кілька років від найкращої проголосованої відповіді, але мені вдалося скоротити час обчислення на 4.

Потрібно лише обчислити пікселі на 1/4 кола, а потім помножити на 4.

Це рішення, якого я досяг:

#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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.