用于testing点是否在圆内的等式
如果你有一个圆心(center_x, center_y)
和半径radius
,你如何testing一个给定的点坐标(x, y)
是否在圆内?
一般来说, x
和y
必须满足(x - center_x)^2 + (y - center_y)^2 < radius^2
。
请注意,满足上述方程式的<
用==
代替的点被认为是圆上的点,满足上述方程式的<
代替>
被认为是圆外的点。
在math上,毕达哥拉斯可能是很多已经提到过的简单方法。
(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.
现在我们已经覆盖了我们的大部分空间,只有这个圈子的一小部分留在我们的方形和钻石之间进行testing。 这里我们回到上面的毕达哥拉斯。
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.
替代方法想象这个圆形内的正方形,而不是钻石,但是这需要稍微更多的testing和计算,没有计算优势(内部正方形和钻石具有相同的区域):
k = R/sqrt(2) if dx <= k and dy <= k then return true.
更新:
对于那些对性能感兴趣的人,我用c实现了这个方法,并用-O3编译。
我按time ./a.out
获得执行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); }
你可以使用毕达哥拉斯测量你的点和中心之间的距离,看看它是否低于半径:
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
另外,杰森指出<=
应该被replace为<
,根据使用情况,这实际上是有意义的 尽pipe我相信在严格的math意义上这不是真的 。 我纠正了。
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; }
这是更高效,可读性强。 它避免了昂贵的平方根操作。 我还添加了一个检查来确定点是否在圆的边界矩形内。
除了多点或多圈之外,矩形检查是不必要的。 如果大多数点在圆圈内,则边界矩形检查实际上会使事情变慢。
一如既往,一定要考虑你的用例。
计算距离
D = Math.Sqrt(Math.Pow(center_x - x, 2) + Math.Pow(center_y - y, 2)) return D <= radius
这是在C#中…在Python中使用转换…
你应该检查从圆心到点的距离是否小于半径,即
if (x-center_x)**2 + (y-center_y)**2 <= radius**2: # inside circle
如上所述 – 使用欧几里德距离。
from math import hypot def in_radius(c_x, c_y, r, x, y): return math.hypot(c_x-x, c_y-y) <= r
这与Jason Punyon提到的解决scheme是一样的,但它包含一个伪代码示例和一些更多的细节。 写完这个之后我看到了他的回答,但是我不想把它移走。
我认为最容易理解的方法是首先计算圆心和点之间的距离。 我会用这个公式:
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
是点的坐标。
找出圆心和给定点之间的距离。 如果它们之间的距离小于半径,则该点在圆内。 如果它们之间的距离等于圆的半径,则该点在圆的圆周上。 如果距离大于半径,则该点在圆外。
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");
我在C#中的答案作为一个完整的剪切和粘贴(未优化)解决scheme:
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)) { }
我使用下面的代码像我这样的初学者:)。
公共课程incirkel {
public static void main(String[] args) { int x; int y; int middelx; int middely; int straal; { // Adjust the coordinates of x and yx = -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"); } } } }}
如前所述,要显示该点是否在圆圈内,我们可以使用以下内容
if ((x-center_x)^2 + (y - center_y)^2 < radius^2) { in.circle <- "True" } else { in.circle <- "False" }
要用graphics表示,我们可以使用:
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)