三边测量算法将 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)

我们将长度定义为:

  1. La = Ra+Rb
  2. Lb = Rb+Rc
  3. 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.RC的中心距离B.R + C.R ] 从 B 的圆心算起,其中 A.RB.RC.R 是圆的半径 ABC.也就是说,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 的最终中心。

如果你不想应用初始平移和旋转,当然你仍然可以解决这个问题,但是代数有点乱。