Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何确定线段是否与圆相切?_Algorithm_Math_Graphics_Language Agnostic_Geometry - Fatal编程技术网

Algorithm 如何确定线段是否与圆相切?

Algorithm 如何确定线段是否与圆相切?,algorithm,math,graphics,language-agnostic,geometry,Algorithm,Math,Graphics,Language Agnostic,Geometry,我有一个原点为(cx,cy)的圆。 半径为r。 然后,有一条直线段由 两点:(x1,y1)和(x2,y2)。 如何确定线段(不是延长线)是否 与圆相切吗?如果是的话,两者在哪里接触 我现在做的是:找出点的距离 (cx,cy)从延长线开始。如果距离足够远!=r、 然后 当然,线段与圆不相切。即使 如果距离=r,那么我们需要找出点 他们接触的地方。然后检查该点是否位于 (x1,y1)和(x2,y2)之间的段。如果是,请拨打电话 线段与圆和接触点相切 已经计算过了。这是可行的,但涉及太多的数学问题。

我有一个原点为(cx,cy)的圆。 半径为r。 然后,有一条直线段由 两点:(x1,y1)和(x2,y2)。 如何确定线段(不是延长线)是否 与圆相切吗?如果是的话,两者在哪里接触

我现在做的是:找出点的距离 (cx,cy)从延长线开始。如果距离足够远!=r、 然后 当然,线段与圆不相切。即使 如果距离=r,那么我们需要找出点 他们接触的地方。然后检查该点是否位于 (x1,y1)和(x2,y2)之间的段。如果是,请拨打电话 线段与圆和接触点相切 已经计算过了。这是可行的,但涉及太多的数学问题。 所有变量都是浮点数或双变量。不是有一个 更智能、更快的算法可以实现相同的结果吗

感谢和问候,
根据定义,切线必须垂直于半径线。在下图中,当且仅当红线垂直于绿线(从中心到接触点)时,红线为切线

因此,如果你知道切线的斜率
M
(根据
(x1,y1)
(x2,y2)
)计算),那么半径线的斜率是
-1/M
。既然你知道

  • 圆心
  • 圆的半径
  • 绿线的斜率
计算接触点很容易。实际上,有两个可能的接触点,在圆的两侧


因此,您所需要做的就是检查两个可能的接触点是否在线段上。

您可能知道这样一个属性,即如果
f(x,y)=y-m*x-c
是线段,那么
|f(x1,y1)|/sqrt(1+m^2)
表示线到
(x1,y1)
的距离。因此:

double m = (y2-y1)/(x2-x1);//slope
double c = y1 - m*x1;//since (x1,y1) lies on the line f(x1,y1) is zero
double d = abs(cy - m*cx - c)/sqrt(1+m*m);//distance
if(d==r)//radius
 //Yeah its tangent and do whatever you want
else
 //Nope
第二部分为伪码

g1(x,y) = y+(1/m)*x-c1;//perpendicular line through (x1,y1)
g2(x,y) = y+(1/m)*x-c2;//perpendicular line through (x2,y2)
c1 = y1+(1/m)*x1;
c2 = y2+(1/m)*x2;
if(g1(cx,cy)*g2(cx,cy)<0)//condition if point lies between two lines.Here make sure the coeffecients of y and x are of same sign in g1 and g2
//yes
else
//no
g1(x,y)=y+(1/m)*x-c1//穿过(x1,y1)的垂直线
g2(x,y)=y+(1/m)*x-c2//垂直线穿过(x2,y2)
c1=y1+(1/m)*x1;
c2=y2+(1/m)*x2;

如果(g1(cx,cy)*g2(cx,cy)我建议您停止使用斜率进行推理,因为垂直方向上的奇点总是难以处理。请尝试使用参数形式:

p = p1 + t v   where   v = p2 - p1
现在将向量
p1-c
投影到
v
上,取导数wrt
t
,设置为零,您很快就得到了
t
值的表达式,该表达式描述了无限线上最靠近
c
的点,即切点:

    (c - p1) dot v
t = --------------
       v dot v
如果该值介于0和1之间,则切点位于
p1
p2
之间。这是一个非常便宜的计算。如果该值为真,则可以进行半径检查

(c - p1 - tv) dot (c - p1 - tv) ~= r^2  ?
注:上面已经计算了子项
c-p1


你提到只有圆圈在移动,所以你可以计算一次并保存它。

你能发布你现在使用的代码吗?也许你的方法还可以,但代码可以优化。恐怕我不能“发布代码”,因为它在纸上。它只是伪代码。谢谢,但我也在做同样的事情。在找到接触点之前,我首先检查原点到直线的距离。如果它与半径不一样,我只是避免做其余的数学运算。是的,它“很容易计算接触点”-从某种意义上说,这是一个直接的过程。只是我想知道是否还有另一个算法需要更少的计算?谢谢!在阅读了你的建议后,我意识到在我的情况下,线段是固定的,只有圆在改变位置。所以我只能计算一次m和c。其余的在循环中进行。有什么建议吗问题的第二部分?即,一旦我们知道直线相切,是否有一个快速算法来检查接触点是否实际位于给定的线段上?这看起来不错,但您似乎假设:如果直线由y=mx+c给出,那么垂直直线的斜率将为-m。我相信它应该是-1/m,对吗?您将得到除以垂直测量的零误差lines@samgak,您可以添加条件bro。这从来都不是问题。如果
x1=x2
,则将方程更改为
x=c
。谢天谢地,我的线段将永远不会垂直!事实上,它的坡度将始终在0到45度之间。谢谢,这似乎很好。我将尝试实现此功能,并检查它是否垂直节省计算时间(与@yobro97建议的实现相比)@Pramod好的。请记住,速度与第一次测试返回false的频率有很大关系,这取决于您对测试用例的选择。正如我所说,这种方法的主要优点是避免特殊情况。对于坡度,您会发现对于近垂直,坡度方法是不稳定的。您必须实现两种方法s表示低于和高于1的绝对坡度。