点が円の内側にあるかどうかをテストするための方程式


309

中心(center_x, center_y)と半径のある円があるradius場合、座標を持つ特定の点が(x, y)円の内側にあるかどうかをどのようにテストしますか?


20
この質問は本当に言語にとらわれないです、私はJavaで同じ式を使用しているので、タグを付け直します。
ゴータム

正の座標のみを想定しているようです。以下のソリューションは、署名された座標では機能しません。
cjbarth 2015

以下のほとんどのソリューション、正と負の座標で機能します。この質問の将来の視聴者のためにその一口を訂正するだけです。
ウィリアムモリソン、

この問題はプログラミングではなく中学生の数学に関するものであるため、この問題をトピック外として締めくくります。
n。「代名詞」m。

回答:


481

一般に、xy満たす必要があり(x - center_x)^2 + (y - center_y)^2 < radius^2ます。

上記の式をで<置き換えた条件を満たす==点は円の点と見なされ、上記の式をで置き換えた点は円の外側と見なさ<れることに注意してください。>


6
半径と比較して距離を測定するために使用される平方根演算を理解することは、数学をあまり気にしない人々に役立ちます。私はそれが最適ではないことを理解していますが、あなたの答えはコードよりも方程式のようにフォーマットされているので、おそらくそれはもっと理にかなっていますか?ただの提案です。
William Morrison

30
これは、簡単な文とすぐに使える方程式で提供される最もわかりやすい説明です。よくやった。
thgc 2013年

これが私がこのリソースをより早く見つけたいと願っています。値xはどこから来るのですか?
Devin Tripp

2
@DevinTripp 'x'は、テストされる点のx座標です。
Chris

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
この答えは素晴らしいです。あなたが提案する最適化のいくつかに気づいたことはありません。よくやった。
William Morrison

2
これらの最適化のプロファイルを作成したかどうか知りたいですか?私の直感は、複数の条件式は、いくつかの数学や1つの条件式よりも遅いと思いますが、私は間違っている可能性があります。
ヨーヨー2014年

3
@yoyo、私はプロファイリングを実行していません。この質問は、あらゆるプログラミング言語のメソッドに関するものです。これがアプリケーションのパフォーマンスを向上させる可能性があると誰かが思った場合、あなたが提案するように、通常のシナリオではそれがより速いことを実証する必要があります。
philcolbourn 14年

2
関数inCircleNでは、不要なABSを使用しています。おそらく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

編集(ポールへのヒント)

実際には、二乗は平方根を取るよりもはるかに安価であることが多く、順序付けにのみ関心があるので、もちろん平方根を取ることはできません。

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は、使用方法によってはこれを<=置き換える必要があることに注意してください<厳密な数学的意味ではそうではないと私は信じていますが私は修正された立場です。


1
dist <= radiusをdist <radiusに置き換えて、円の内側にある点をテストします。
ジェイソン

16
sqrtは高価です。可能であれば避けてください-x ^ 2 + y ^ yをr ^ 2と比較してください。
ポールトンブリン

ジェイソン:私たちの定義は一致しないかもしれませんが、私にとって、円の円周の点は最も強調されており、円にもあり、私のものは正式な数学的定義と一致していると確信しています。
Konrad Rudolph、

3
円の内部の正式な数学的定義は、私が私の投稿で与えたものです。ウィキペディアから:一般に、何かの内部とは、その外側の周囲の壁や境界を除いて、その内部の空間または部分を指します。en.wikipedia.org/wiki/Interior_(topology)
ジェイソン・

1
パスカル、DelphiとFPC、両方の電源、およびSQRT INにある高価な、そして何の電力事業者は、EGありません:**または^。x ^ 2またはx ^ 3が必要な場合にこれを実行する最も速い方法は、「手動」で実行することですx*x
JHolta 2013年

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
D-squaredとradius-squaredを比較することで、2つの高価なSqrt呼び出しを回避できます。
ポールトンブリン

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

以下の方程式は、ポイントが特定の円内にあるかどうかをテストする式です。xPyPはポイントの座標、xCyCは円の中心の座標、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

これは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の半径、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

私は私のような初心者のために以下のコードを使用しました:)

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

3DポイントがUnit Sphere内にあるかどうかを確認したい場合は、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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.