【问题标题】:Equation for testing if a point is inside a circle测试点是否在圆内的方程
【发布时间】:2010-10-03 15:04:02
【问题描述】:

如果你有一个圆心(center_x, center_y),半径radius,你如何测试坐标(x, y)的给定点是否在圆内?

【问题讨论】:

  • 这个问题真的与语言无关,我在java中使用相同的公式,所以重新标记。
  • 看来你只假设正坐标。以下解决方案不适用于带符号的坐标。
  • 以下大多数解决方案确实适用于正坐标和负坐标。只是为这个问题的未来观众纠正这个花絮。

标签: algorithm language-agnostic geometry


【解决方案1】:

一般情况下,xy 必须满足 (x - center_x)² + (y - center_y)² < radius²

请注意,用== 替换的< 满足上述等式的点被认为是圆上 上的点,而用< 替换满足上述等式的点被认为是> 被认为是圈外

【讨论】:

  • 它可能会帮助一些不太懂数学的人看到用于测量距离与半径相比的平方根运算。我意识到这不是最佳选择,但是由于您的答案的格式更像一个方程式而不是代码,所以它可能更有意义?只是一个建议。
  • 这是最容易理解的解释,只用一个简单的句子和一个立即可用的方程式。干得好。
  • 非常希望我能更快地找到这个资源。 x 的值从何而来?
  • @DevinTripp 'x' 是被测点的 x 坐标。
  • 这可能很明显,但应该说明<= 会在圆内或边缘上找到点。
【解决方案2】:

求圆心与给定点之间的距离。如果它们之间的距离小于半径,则该点在圆内。 如果它们之间的距离等于圆的半径,则该点位于圆的圆周上。 如果距离大于半径,则该点在圆外。

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

【讨论】:

    【解决方案3】:

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

    使用 Python

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

    【讨论】:

      【解决方案4】:

      PHP

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

      【讨论】:

        【解决方案5】:

        下面的等式是一个表达式,用于测试一个点是否在给定的圆内,其中 xP & yP 是该点的坐标,xC em> & 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;
            }
        

        【讨论】:

          【解决方案6】:

          下面是解决这个问题的简单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;
          }
          

          【讨论】:

            【解决方案7】:

            进入 3D 世界,如果您想检查 3D 点是否在 Unit Sphere 中,您最终会做类似的事情。在 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;
                }
            

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                【解决方案9】:

                如前所述,要显示该点是否在圆圈中,我们可以使用以下方法

                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)
                

                【讨论】:

                  【解决方案10】:
                  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;
                  }
                  

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

                  矩形检查是不必要的,除非有很多点或很多圆。如果大多数点都在圆圈内,那么边界矩形检查实际上会使事情变慢!

                  与往常一样,请务必考虑您的用例。

                  【讨论】:

                    【解决方案11】:

                    这与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是点的坐标。

                    【讨论】:

                      【解决方案12】:

                      我为像我这样的初学者使用了下面的代码:)。

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

                      【讨论】:

                        【解决方案13】:

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

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

                        【讨论】:

                        • 这个答案非常好。我从来没有意识到你建议的一些优化。干得好。
                        • 我很想知道您是否分析过这些优化?我的直觉是多个条件会比一些数学和一个条件要慢,但我可能是错的。
                        • @yoyo,我没有进行任何分析 - 这个问题是关于任何编程语言的方法。如果有人认为这可能会提高其应用程序的性能,那么他们应该按照您的建议证明它在正常情况下更快。
                        • 在函数 inCircleN 中,您使用了不必要的 ABS。可能没有 ABS,inCircleinCircleN 之间的差异会更小。
                        • 移除 ABS 确实提高了 inCircleN 的性能,但还不够。但是,由于 R=1,我的方法更倾向于圈外的点。使用随机半径 [0..499],大约 25% 的点在圆内,inCircleN 更快。
                        【解决方案14】:

                        如上所述——使用欧几里得距离。

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

                        【讨论】:

                          【解决方案15】:

                          你可以用毕达哥拉斯来测量你的点到中心的距离,看看它是否低于半径:

                          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 指出 &lt;= 应该替换为 &lt; 并且根据使用情况,这实际上可能是有意义的即使我认为这在严格的数学意义上并不正确我的立场是正确的。

                          【讨论】:

                          • 将 dist
                          • sqrt 很贵。尽可能避免使用 - 将 x^2+y^y 与 r^2 进行比较。
                          • Jason:我们的定义可能不一致,但对我来说,on 圆的圆周上的点也最重要的是 in 圆,我是很确定我的与正式的数学定义一致。
                          • 圆内部的正式数学定义是我在帖子中给出的。来自维基百科:一般来说,事物的内部是指其内部的空间或部分,不包括其外部的任何类型的墙壁或边界。 en.wikipedia.org/wiki/Interior_(topology)
                          • 在 pascal、delphi 和 FPC 中,power 和 sqrt 都昂贵,并且没有 power-operator EG:**^。当您只需要 x^2 或 x^3 时,最快的方法是“手动”:x*x.
                          【解决方案16】:

                          计算距离

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

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

                          【讨论】:

                          • 您可以通过比较 D-squared 和 radius-squared 来避免两次昂贵的 Sqrt 调用。
                          猜你喜欢
                          • 1970-01-01
                          • 2013-05-23
                          • 1970-01-01
                          • 2016-02-08
                          • 2016-08-30
                          • 2011-02-05
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多