三边测量算法将 3 个圆定位为尽可能靠近而不重叠
Trilateration algorithm to position 3 circles as close as possible without overlapping
我有两个圆圈,它们完全位于彼此的边界上。它们具有位置 A 和 B(均为矢量),以及半径 Ra 和 Rb。
现在我添加第三个圆,半径为 Rc。如何找到三个圆尽可能靠近且不重叠的位置向量C?
我写这篇文章是为了我正在建立的网站的插图,所以效率加分:)
编辑:
当我最初 post 编辑时,我没有足够的代表来 post 插图。
两个圆圈(B 和 C)将重叠,但与 A 相切。我想将 C 移出它与 B 共享的重叠区域,进入虚线。
编辑 2:
很抱歉,我一直不清楚,我创建了一个图表来试图解释我正在尝试做的事情。
我正在 Pixi.js 中创建插图,这是一个简单的 canvas/webGL 库。我正在使用矢量(通过 Victor.js)来定位圆圈并四处移动它们。
我随机生成了一堆圆圈,然后我将最大的圆圈 (A) 放在容器的中间。之后,我想将 A 周围的所有圆聚集在一起,解决发生的碰撞。这很重要,因为我将在用户点击或悬停时缩放单个圆圈。
对于没有任何碰撞的简单情况,矢量解决方案非常简单,我想尽可能解决两个圆以相同方式碰撞的情况。
答案是找到边长为:Ra+Rb、Ra+Rc、Rb+Rc 的三角形的点。这就是所谓的三边求解,但你会得到 2 个可能的答案。
这里使用的基本公式是余弦定律:c^2 = a^2 + b^2 - 2ab*cos(gamma)
我们将长度定义为:
- La = Ra+Rb
- Lb = Rb+Rc
- Lc = Rc+Ra
我们先求出AB和AC的夹角。求解 arccos(a) = (Lb^2 + Lc^2 - La^2) / 2*Lb*Lc
(如果此时你已经有了AB的坐标系角度,可以跳到第3步)
第二步是求AB相对于X轴的坐标系角度。这是使用基本三角函数完成的。求高度h = Ay - By
,角度arcsin(b) = h / La
.
第三步是添加或减去(2 个答案!)角度 a 和 b,这是从点 A 开始的矢量方向,其中点 C 位于距离 Lc 处。要找到 C,请再次使用三角函数。
Cx = Ax + Lc * cos(a + b)
Cy = Ay + Lc * sin(a + b)
当圆相互接触时,圆心之间的距离称为半径之和。求解这个方程组并找到 Cx,Cy
坐标。有两种可能的解决方案。将坐标原点放在一个圆的圆心上,求解更简单。
(Cx-Ax)^2 + (Cy-Ay)^2 = (Ra+Rc)^2
(Cx-Bx)^2 + (Cy-By)^2 = (Rb+Rc)^2
如果您假设第一个圆 (A
) 的圆心为 (0,0)
,第二个圆 (B
) 的圆心为正 [=17],则问题会得到简化=]-轴。如果不是这种情况,您可以将 A
的中心平移到 (0,0)
,然后旋转平面使其成为这种情况。 (然后最后反转这些操作恢复原来的配置。)
那么C
的中心距离A
的中心距离A.R + C.R
,C
的中心距离B.R + C.R
] 从 B
的圆心算起,其中 A.R
、B.R
、C.R
是圆的半径 A
、B
、C
.也就是说,C
的圆心在两个圆
的交点上
x^2 + y^2 = (A.R + C.R)^2
(x-B.x)^2 + y^2 = (B.R + C.R)^2
其中 (B.x,0)
是圆心 B
。从第二个方程中减去第一个方程
-2*B.x*x + B.x^2 = B.R^2 + 2*B.R*C.R - A.R^2 - 2*A.R*C.R
也就是说C
的圆心有x
坐标
C.x = (A.R^2 + 2*A.R*C.R + B.x^2 - B.R^2 - 2*B.R*C.R)/(2*B.x)
现在我们有了C.x
,我们可以很容易地计算出C.y
:
C.y = plus or minus sqrt((A.R+C.R)^2 - C.x^2)
现在反转你在开始时应用的变换(如果有的话)(先反转旋转,然后反转平移),你就得到了 C
的最终中心。
如果你不想应用初始平移和旋转,当然你仍然可以解决这个问题,但是代数有点乱。
我有两个圆圈,它们完全位于彼此的边界上。它们具有位置 A 和 B(均为矢量),以及半径 Ra 和 Rb。
现在我添加第三个圆,半径为 Rc。如何找到三个圆尽可能靠近且不重叠的位置向量C?
我写这篇文章是为了我正在建立的网站的插图,所以效率加分:)
编辑: 当我最初 post 编辑时,我没有足够的代表来 post 插图。 两个圆圈(B 和 C)将重叠,但与 A 相切。我想将 C 移出它与 B 共享的重叠区域,进入虚线。
编辑 2: 很抱歉,我一直不清楚,我创建了一个图表来试图解释我正在尝试做的事情。
我正在 Pixi.js 中创建插图,这是一个简单的 canvas/webGL 库。我正在使用矢量(通过 Victor.js)来定位圆圈并四处移动它们。
我随机生成了一堆圆圈,然后我将最大的圆圈 (A) 放在容器的中间。之后,我想将 A 周围的所有圆聚集在一起,解决发生的碰撞。这很重要,因为我将在用户点击或悬停时缩放单个圆圈。
对于没有任何碰撞的简单情况,矢量解决方案非常简单,我想尽可能解决两个圆以相同方式碰撞的情况。
答案是找到边长为:Ra+Rb、Ra+Rc、Rb+Rc 的三角形的点。这就是所谓的三边求解,但你会得到 2 个可能的答案。
这里使用的基本公式是余弦定律:c^2 = a^2 + b^2 - 2ab*cos(gamma)
我们将长度定义为:
- La = Ra+Rb
- Lb = Rb+Rc
- Lc = Rc+Ra
我们先求出AB和AC的夹角。求解 arccos(a) = (Lb^2 + Lc^2 - La^2) / 2*Lb*Lc
(如果此时你已经有了AB的坐标系角度,可以跳到第3步)
第二步是求AB相对于X轴的坐标系角度。这是使用基本三角函数完成的。求高度h = Ay - By
,角度arcsin(b) = h / La
.
第三步是添加或减去(2 个答案!)角度 a 和 b,这是从点 A 开始的矢量方向,其中点 C 位于距离 Lc 处。要找到 C,请再次使用三角函数。
Cx = Ax + Lc * cos(a + b)
Cy = Ay + Lc * sin(a + b)
当圆相互接触时,圆心之间的距离称为半径之和。求解这个方程组并找到 Cx,Cy
坐标。有两种可能的解决方案。将坐标原点放在一个圆的圆心上,求解更简单。
(Cx-Ax)^2 + (Cy-Ay)^2 = (Ra+Rc)^2
(Cx-Bx)^2 + (Cy-By)^2 = (Rb+Rc)^2
如果您假设第一个圆 (A
) 的圆心为 (0,0)
,第二个圆 (B
) 的圆心为正 [=17],则问题会得到简化=]-轴。如果不是这种情况,您可以将 A
的中心平移到 (0,0)
,然后旋转平面使其成为这种情况。 (然后最后反转这些操作恢复原来的配置。)
那么C
的中心距离A
的中心距离A.R + C.R
,C
的中心距离B.R + C.R
] 从 B
的圆心算起,其中 A.R
、B.R
、C.R
是圆的半径 A
、B
、C
.也就是说,C
的圆心在两个圆
x^2 + y^2 = (A.R + C.R)^2
(x-B.x)^2 + y^2 = (B.R + C.R)^2
其中 (B.x,0)
是圆心 B
。从第二个方程中减去第一个方程
-2*B.x*x + B.x^2 = B.R^2 + 2*B.R*C.R - A.R^2 - 2*A.R*C.R
也就是说C
的圆心有x
坐标
C.x = (A.R^2 + 2*A.R*C.R + B.x^2 - B.R^2 - 2*B.R*C.R)/(2*B.x)
现在我们有了C.x
,我们可以很容易地计算出C.y
:
C.y = plus or minus sqrt((A.R+C.R)^2 - C.x^2)
现在反转你在开始时应用的变换(如果有的话)(先反转旋转,然后反转平移),你就得到了 C
的最终中心。
如果你不想应用初始平移和旋转,当然你仍然可以解决这个问题,但是代数有点乱。