用于测试点是否在圆内的等式

时间:2009-01-26 20:07:26

标签: algorithm language-agnostic geometry

如果您有一个中心为(center_x, center_y)且半径为radius的圆圈,那么如何测试坐标为(x, y)的给定点是否在圆圈内?

17 个答案:

答案 0 :(得分:452)

通常,xy必须满足(x - center_x)^2 + (y - center_y)^2 < radius^2

请注意,满足<取代==的上述等式的点被视为 on 圆上的点,以及满足上述等式的点{被<取代的{1}}被视为外部圈。

答案 1 :(得分:120)

数学上,毕达哥拉斯可能是一个很多人已经提到过的简单方法。

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

答案 2 :(得分:71)

您可以使用毕达哥拉斯来测量您的点与中心之间的距离,看它是否低于半径:

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

此外,Jason指出<=应该被<取代,并且取决于使用情况,这实际上可能有意义,即使我认为在严格的数学意义上它不是真的我的立场得到了纠正。

答案 3 :(得分:35)

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

这更有效,更易读。它避免了昂贵的平方根操作。我还添加了一个检查,以确定该点是否在圆的边界矩形内。

除非有许多点或多个圆圈,否则不需要进行矩形检查。如果大多数点在圆圈内,则边界矩形检查实际上会使事情变慢!

一如既往,请务必考虑您的使用案例。

答案 4 :(得分:12)

计算距离

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

在C#中转换为在python中使用...

答案 5 :(得分:10)

你应该检查从圆心到点的距离是否小于半径,即

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

答案 6 :(得分: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

答案 7 :(得分: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");

答案 8 :(得分:2)

这与mentioned by Jason Punyon的解决方案相同,但它包含一个伪代码示例和一些更多细节。写完这篇文章后我看到了他的答案,但我不想删除我的答案。

我认为最容易理解的方法是首先计算圆心和点之间的距离。我会用这个公式:

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

然后,只需将该公式的结果,距离(d)与radius进行比较。如果距离(d)小于或等于半径(r),则该点位于圆圈内(如果dr则位于圆的边缘是等于)。

这是一个伪代码示例,可以很容易地转换为任何编程语言:

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_xcircle_y是圆的中心坐标,r是圆的半径,xy是坐标重点。

答案 9 :(得分:2)

我在C#中的答案是一个完整的剪辑&amp;粘贴(未优化)解决方案:

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

答案 10 :(得分: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)

答案 11 :(得分:1)

下面的方程式是一个测试点的表达式,其中 xP yP 是点的坐标, xC yC 是圆心的坐标,而 R 是给定圆的半径。

enter image description here

如果以上表达式为真,则该点位于圆内。

以下是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;
    }

答案 12 :(得分:0)

PHP

if ((($x - $center_x) ** 2 + ($y - $center_y) ** 2) <=  $radius **2) {
    return true; // Inside
} else {
    return false; // Outside
}

答案 13 :(得分:0)

这是解决此问题的简单Java代码:

及其背后的数学:https://math.stackexchange.com/questions/198764/how-to-know-if-a-point-is-inside-a-circle

boolean insideCircle(int[] point, int[] center, int radius) {
    return (float)Math.sqrt((int)Math.pow(point[0]-center[0],2)+(int)Math.pow(point[1]-center[1],2)) <= radius;
}

答案 14 :(得分: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));
}

答案 15 :(得分: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;
    }

答案 16 :(得分:0)

我为以下的初学者使用了以下代码:)。

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



    }
}}