Уравнение для проверки, если точка находится внутри круга


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. Вероятно, без ABS разница между inCircleи inCircleNбудет меньше.
Цалога

1
Удаление ABS действительно улучшает производительность inCircleN, но этого недостаточно. Тем не менее, мой метод был смещен в сторону точек с большей вероятностью за пределами круга, поскольку R = 1. При случайном радиусе [0..499] около 25% точек находились внутри круга, а inCircleN быстрее.
Филколборн

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

РЕДАКТИРОВАТЬ (шляпа чаевые Полу)

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

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 <= radius на dist <radius, чтобы проверить, находится ли точка внутри окружности.
Джейсон

16
sqrt это дорого. Если возможно, избегайте этого - сравните x ^ 2 + y ^ y с r ^ 2.
Пол Томблин

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

3
Формальное математическое определение внутренней части круга - это то, что я дал в своем посте. Из Википедии: В общем, внутренняя часть чего-либо относится к пространству или части внутри него, исключая любые виды стен или границ вокруг своей внешней стороны. en.wikipedia.org/wiki/Interior_(topology)
Джейсон

1
В pascal, delphi и FPC и power, и sqrt стоят дорого , и нет EG оператора питания: **или ^. Самый быстрый способ сделать это , когда нужно просто х ^ 2 или х ^ 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

Приведенное ниже уравнение является выражением, которое проверяет, находится ли точка в данном круге, где xP & yP - координаты точки, xC & yC - координаты центра круга, а 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.