一个点在圆中的位置

3

大家好,第一部分已经顺利完成了,非常感谢大家。

但是我还有一个问题...

由于我没有界面,是否有一种方法可以不知道圆的半径而实现相同的功能?

应该刷新页面,CodeMonkey的解决方案正是我正在寻找的...

再次感谢你们。

============================

首先,我不是开发者,我只是一个离校太早的简单木匠...

我试图让我的工具与自主机器人配合使用。 通过阅读很多教程,我让它们进行通信。

但我有一个问题无法解决。

机器人期望将工具位置表示为(X,Y),但工具的输出是(A,B,C) A是从工具到北部的距离 B是东部距离 C是东轴顺时针120度处的距离

边缘是一个圆形,半径可能会改变,也可能不是我所知道的。

我已经在这上面花费了1个月的时间,无法找到一种将这些值转换为位置的方法。

我用一张画在木板上的圆上的3颗钉子做了一个测试,如果我有距离,只有一个可能的位置,所以我想这是可能的。 但是怎么做呢?

此外,如果有人有答案,我希望是伪代码而不是实际代码,这样我就可以练习。

如果有一种制作图纸的工具可以使它更加清晰,你能告诉我吗?

谢谢。

希望这有所帮助:

http://imgur.com/a/CvoNB

X,Y是从中心点开始的坐标,Da,Db,Dc是已知的。

试图使其更加清晰(抱歉,这在我的脑海中非常清晰)。

X,Y是工具(P)所在点的坐标。 中心点在0,0处

A是垂直线从P切割圆形的点,与Da距离P到A;

B是水平线从P切割圆形的点,与Db距离P到B。

C是120度顺时针方向的线从水平线切割圆形的点,与Dc距离P到C。

从工具输出的是一个整数数组(单位毫米):A=123,B=114,C=89 这些是我唯一拥有的信息

非常感谢你们提供的所有想法,我稍后会在家里尝试它们, 希望能有效:)


1
不确定你在这里所指的X和Y具体是什么意思。如果你能画个图示,会很有帮助。 - Rishikesh Raje
@Jean-BaptisteYunès,我尝试将其放入C代码中,并寻求将其转化为代码的方法,这可能可以吗? - A.albin
至少选择C或C++中的一个,不要同时选择。 - Jean-Baptiste Yunès
你能否给我们一些来自你的钉板、你的工具输出(A、B、C)等方面的例子吗?我认为这将有助于澄清问题并帮助我们给出更好的答案。 - CodeMonkey
@A.albin谢谢你添加了ABC的示例。据我所见,现在这个ABC实际上就是你在图纸中所称的Da,Db,Dc。你说你还知道圆的直径,并且圆的中心点在(0,0)处,对吗? - CodeMonkey
显示剩余11条评论
5个回答

2

基本几何学。我决定放弃将圆放在原点上。我们还不知道圆的中心。你所拥有的是该圆上的三个点。让我们尝试将工具的位置P作为新的(0,0)。因此,需要找到一个由三个点构成的圆:(0,Da);(Db,0),并向后退120°,距离为Dc。

伪代码:

  • 计算从A到B的直线:称之为AB。找到AB的中点。通过该中点计算与AB垂直的直线(例如,AB和单位Z轴的叉积可以找到垂直向量)。
  • 计算从B到C(或C到A同样有效)的直线:称之为BC。找到BC的中点。通过该中点计算与BC垂直的直线。
  • 计算这两条直线相交的位置。这将是你的圆的原点。

由于P位于(0,0),你的圆的原点的负数将是你的工具相对于圆的原点的坐标。现在,你应该能够计算出任何你需要的相对于它的内容。

两点之间的中点:X=(X1+X2)/2. Y=(Y1+Y2)/2。

圆的半径可以使用例如点A和圆的原点进行计算:R=sqrt(sqr((Ax-CirX)+sqr(Ay-CirY))

边缘距离:再次使用勾股定理,圆的半径减去工具到圆心的距离。


1
好的,我会尝试。但我不确定能否做到......我没有ABC坐标,那么我该如何得到它们之间的直线?据我所知,需要两个点的坐标才能得到一条直线,对吧? - A.albin
1
@A.albin:这个答案的前提是重新表述问题,假设P位于(0,0)。如果P位于(0,0),则A位于(0,D_A),B位于(D_B,0)。对于C的几何形状有点复杂,我认为C由(D_C * cos(4/3 * Pi),D_C * sin(4/3 * Pi))给出。 - Linuxios
1
@A.albin:CodeLurker所概述的方法允许您在这个新的坐标系中找到圆的中心,然后可以用它来找到该点与P(这里再次是(0,0))之间的偏移量,以便在原始坐标系中找到P的位置,其中圆的中心位于原点。 - Linuxios
我做了一些更改,以使它更易于理解。我将原来称为T的变量改为使用原始变量P。我还更好地指定了我考虑的三个点,并明确表示P(我所说的T)现在是(0,0)。我还引入了AB线和BC线术语。 - CodeLurker
@CodeLurker 谢谢,我现在更容易理解了。要得到 C(Xc,Yc),我需要使用三角函数对吗? - A.albin
显示剩余6条评论

1

让我们设 a=Da,b=Db。然后我们可以为圆周上的点A和点B编写一个系统:

(x+b)^2 + y^2 = r^2
(y+a)^2 + x^2 = r^2

经过转换后,我们得到了二次方程。
y^2 * (4*b^2+4*a^2) + y * (4*a^3+4*a*b^2) + b^4-4*b^2*r^2+a^4+2*a^2*b^2 = 0
or 
AA * y^2  + BB * y + CC = 0
where coefficients are
AA = (4*b^2+4*a^2)
BB = (4*a^3+4*a*b^2)
CC = b^4-4*b^2*r^2+a^4+2*a^2*b^2 

因此,计算AA、BB、CC系数,找到二次方程的解y1、y2,然后使用以下公式获取相应的x1、x2值:

 x = (a^2 - b^2 + 2 * a * y) / (2 * b)    

并选择真正的解决方案对(其中坐标在圆内)

快速检查:
a=1,b=1,r=1 给出坐标 0,0,如预期所示(不合法的 1,-1 在圆外)
a=3,b=4,r=5 给出(大致)坐标 0.65, 1.96,在图片中,距离约为 3 和 4。

enter image description here

这段 Delphi 代码(未检查所有可能的错误)输出 x: 0.5981 y: 1.9641

var
  a, b, r, a2, b2: Double;
  aa, bb, cc, dis, y1, y2, x1, x2: Double;
begin
  a := 3;
  b := 4;
  r := 5;
  a2 := a * a;
  b2:= b * b;
  aa := 4 * (b2 + a2);
  bb := 4 * a * (a2 + b2);
  cc := b2 * b2 - 4 * b2 * r * r + a2 * a2 + 2 * a2 * b2;
  dis := bb * bb - 4 * aa * cc;
  if Dis < 0 then begin
    ShowMessage('no solutions');
    Exit;
  end;

  y1 := (- bb - Sqrt(Dis)) / (2 * aa);
  y2 := (- bb + Sqrt(Dis)) / (2 * aa);
  x1 := (a2 - b2 + 2 * a * y1) / (2 * b);
  x2 := (a2 - b2 + 2 * a * y2) / (2 * b);

  if x1 * x1 + y1 * y1 <= r * r then
    Memo1.Lines.Add(Format('x: %6.4f  y: %6.4f', [x1, y1]))
  else
  if x2 * x2 + y2 * y2 <= r * r then
    Memo1.Lines.Add(Format('x: %6.4f  y: %6.4f', [x2, y2]));

第一次迭代时是否有一种方法可以使用未知半径执行相同的操作?另外,你的代码是用Python编写的,对吗?(只是好奇) - A.albin
不,这种方法使用半径(但忽略第三个距离)。为了避免使用半径,您需要使用外接圆方法。代码是用Delphi(Pascal)编写的。 - MBo

1
假设您已经了解X和Y。R是圆的半径。
|(X, Y + Da)| = R
|(X + Db, Y)| = R
|(X - cos(pi/3) * Dc, Y - cos(pi/6) * Dc)| = R

假设我们不知道半径 R,我们仍然可以说:
|(X, Y + Da)|^2 = |(X + Db, Y)|^2
=> X^2 + (Y+Da)^2 = (X+Db)^2 + Y^2
=> 2YDa + Da^2 = 2XDb + Db^2 (I)

将cos(pi/3)*Dc表示为c1,将cos(pi/6)*Dc表示为c2:

|(X, Y + Da)|^2 = |(X - c1, Y - c2)|^2
=> X^2 + Y^2 + 2YDa + Da^2 = X^2 - 2Xc1 + c1^2 + Y^2 - 2Yc2 + c2^2
=> 2YDa + Da^2 = - 2Xc1 + c1^2 - 2Yc2 + c2^2
=> Y = (-2Xc1 + c1^2 + c2^2 - Da^2) / 2(c2+Da) (II)

将 (II) 放回方程式 (I) 中,我们得到:
=> (-2Xc1 + c1^2 + c2^2 - Da^2) Da / (c2+Da) + Da^2 = 2XDb + Db^2
=> (-2Xc1 + c1^2 + c2^2 - Da^2) Da + Da^2 * (c2+Da) = 2XDb(c2+Da) + Db^2 * (c2+Da)
=> (-2Xc1 + c1^2 + c2^2) Da + Da^2 * c2 = 2XDb(c2+Da) + Db^2 * (c2+Da)

=> X = ((c1^2 + c2^2) Da + Da^2 * c2 - Db^2 * (c2+Da)) / (2Dbc2 + 2Db*Da + 2Dac1) (III)

通过计算(II),您可以了解X并得到Y。

您还可以进行一些简化,例如c1^2 + c2^2 = Dc^2

将其放入Python中(几乎是伪代码):

import math


def GetXYR(Da, Db, Dc):
    c1 = math.cos(math.pi/3) * Dc
    c2 = math.cos(math.pi/6) * Dc

    X = ((c1**2 + c2**2) * Da + Da**2 * c2 - Db * Db * (c2 + Da)) / (2 * Db * c2 + 2 * Db * Da + 2 * Da * c1)
    Y = (-2*X*c1 + c1**2 + c2**2 - Da**2) / (2*(c2+Da))
    R = math.sqrt(X**2 + (Y+Da)**2)
    R2 = math.sqrt(Y**2 + (X+Db)**2)
    R3 = math.sqrt((X - math.cos(math.pi/3) * Dc)**2 + (Y - math.cos(math.pi/6) * Dc)**2)
    return (X, Y, R, R2, R3)

(X, Y, R, R2, R3) = GetXYR(123.0, 114.0, 89.0)

print((X, Y, R, R2, R3))

我得到的结果(X,Y,R,R2,R3)=(-8.129166703588021,-16.205081335032794,107.1038654949096,107.10386549490958,107.1038654949096),如果Da和Db都比Dc长,则两个坐标可能都为负数,这似乎是合理的。
我通过三个方程计算半径以进行交叉检查,以确定我的计算是否有意义。它似乎满足我们在一开始设置的所有三个方程。

1
我使用了一个未刷新的页面,直到现在才看到了你的回答,看起来正是我所需要的,我会尽快尝试,它完美地运行。 - A.albin
感谢您接受答案。我希望您的项目取得成功 :-). - CodeMonkey

1
你的问题是了解“外接圆”。你有一个三角形,由机器人位置处给定角度的3个距离定义,然后你可以从这三个点构造外接圆(参见Wikipedia上的外接圆-其他属性部分)。因此,你知道直径(如果需要的话)。
众所周知,三角形边的垂直平分线的交点是外接圆的中心。

也许我误解了你的回答,但我的印象是OP想要在圆中点P的坐标,而不是圆本身。 - Linuxios
我需要一个更简单的答案或更多的细节,我无法理解那些数学。而且这不需要我知道三角形ABC的角度吗?我没有它们。 - A.albin

0
从您的图表中,您有一个点P,您需要它的XY坐标。因此,我们需要找到PxPy(Px, Py)。我们知道Ax = PxBy = Py。如果需要,我们可以使用这些进行替换。我们知道CP创建一条线,并且所有线的斜率都以y = mx + b的形式表示。其中斜率为m,y截距为b。此时我们不知道mb,但是它们可以被找到。我们知道向量CPPB之间的夹角为120°,但这并没有将角度放在标准位置,因为这是一个CW旋转。在处理圆和三角函数以及其中的斜率线性方程时,最好使用标准形式。因此,如果这条线y = mx + b包含点CP,则由点PB组成的与水平轴平行的水平线上方的角度将为180° - 120° = 60°。我们还知道两个向量之间的cos角度也等于这些向量的点积除以它们的大小的乘积。
我们还没有确切的数字,但我们可以构建一个公式:由于θ =标准位置中水平线上方的60°,我们知道斜率m也是该角度的正切;因此,这条线的斜率是tan(60°)。所以让我们回到我们的线性方程y = tan(60°)x + b。由于b是y截距,我们需要找出当y等于0时x是多少。由于我们仍然有三个未定义变量y、x和b,我们可以使用这条线上的点来帮助我们。我们知道点C和P在这条线上。因此,y = tan(60°)x + b的向量是由(Px, Py) - (Cx, Cy)构成的。然后,向量为(Px-Cx, Py-Cy),其角度为60°,与水平轴平行。这次我们需要使用另一种涉及点和斜率的线性方程形式,即y - y1 = m(x - x1),所以这就变成了y - Py = tan(60°)(x - Px),我之前说过我们可以代入,那么让我们继续做吧:y - By = tan(60°)(x - Ax),然后y - By = tan(60°)x - tan(60°)Ax。如果你知道A和B的实际坐标点,那么这就变得很容易了。唯一的问题是你必须将你的120°角度转换为标准形式。这完全取决于你所知道的和未知的内容。因此,如果你需要P,并且你已经从图表中知道了A和B,那么工作就很容易了,因为你需要的P点坐标将是P(Ax, By)。既然你已经说过你知道Da、Db和Dc以及它们的长度,那么只需要应用正确的三角函数和适当的角度或使用勾股定理来找到三角形的另一条腿的长度即可。从其他点中找到P(x,y)并不难。你可以使用三角函数、线性方程、勾股定理、向量计算等。如果你能找到指向C和P的线的方程,知道P具有A的x值和B的y值,并且知道该线的斜率由上方的正切定义,该正切为180°-phi,其中phi是你给出的顺时针旋转的角度,而theta则是标准位置或水平线上方的角度,那么你就有了一个一般形式的y - By = tan(180°-phi)(x - Ax)方程,从这个方程中你可以找到该线上的任何一点。

还有其他方法,例如使用现有的点和它们之间创建的向量,然后使用这些点生成一个等边三角形,然后从该等边三角形中生成一个垂直平分线,以找到该三角形的重心。这是另一种可行的方法。唯一需要考虑的是来自原点的线性平移。因此,您将在(Ax - origin, By - origin)的线路上进行移动,并将其中一个设置为0,另一个设置为相反数。有许多不同的方法可以找到它。

我刚刚向您展示了几种数学技巧,可以帮助您根据已知和未知量找到通用方程。只需识别哪些方程适用于哪种情况即可。一旦您识别出给定的正确方程式,其余部分就相当容易了。希望这能帮助到您。

编辑

我忘了提到一件事情,那就是CP这条线在第一象限中由(cos(60°), sin(60°))定义的圆上有一个点。在第三象限中,如果这条线穿过原点(0,0),并且它与由(-cos(60°), -sin(60°))定义的圆相交,那么这条线上的点和圆上的点将成为该圆的半径,因为在原点处没有yx截距。


一个提示;你可以将任何圆视为一个单位圆,其中它的半径任意取1,以使你所有的三角函数、度数转弧度、找点和向量、在圆内定义三角形等等都变得更容易。原因是当它们是单位圆时,所有圆的周长都是2PI,向量旋转为360°,所有单位圆的面积都是PI平方单位。另一个有用的知识是,圆的方程和勾股定理是相同的。 - Francis Cugler
这让我非常感兴趣,这意味着我可以在不费力的情况下完成整个过程(参见更新的帖子),对吗? - A.albin
事实上,解决问题有很多方法;如果您拥有满足任何一条线方程的所有信息,您可以使用具有特定斜率的线性方法在一条直线上使用2个点进行操作;您也可以使用三角法或几何法,前提是您拥有所需的信息。从视觉上看,三角形、矩形(甚至正方形)和圆形看起来并不相似,但它们都与点在一条线上的属性、构成线段或向量的属性以及向量、矩阵和向量之间的旋转相关。 - Francis Cugler
例如,给定一条直线上的任意两点,通过任意第三个不在该直线上的点,可以构造一个三角形、正方形或圆形,其半径或直径由这两个点确定。对于任何其他多边形形状也是如此,只是需要更多的点来创建所需的向量。请记住,当一个点被共享为两个向量的交点、旋转、反射、对称时,它被认为是一个顶点,一系列或一组它们是顶点。 - Francis Cugler
你只需要找到一个通用方程式,从已知的条件中得出所需的结果。如果你有多个未知数,则可能需要先解决那个已知数,然后将其代回原方程式以得出所需的答案。也许可以拿一本高中或大学早期的微积分物理书,做一些基本的运动和力学练习,比如一个重物被绳子拉上一定角度的斜面,具有特定的张力和摩擦力,然后找到移动它所需的力量。 - Francis Cugler
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接