沿圆排列圆而不重叠

Arrange Circles along Circle without Overlap

我想将一组圆圈沿另一个圆圈放置,以使“子”圆圈彼此不重叠。我知道所有圆的半径,还有目标圆的位置。

目标圆总是足够大以适合所有圆。

看这张图:

:

interface Circle {
  radius: number;
  x: number;
  y: number;
}

const childRadii = [1, 3, 2, 5, 1, 2];

const largeCircle = { radius: 10, x: 0, y: 0 };

const arrangedCircles = positionCirclesOnCircle(largeCircle, childRadii);

function positionCirclesOnCircle(
  largeCircle: Circle,
  radii: number[]
): Circle[] {
  const arrangedCircles: Circle[] = [];
  //for each of our radii  find the correct x and y position along largeCircle
  for (let index = 0; index < radii.length; index++) {
    //find the x and y pos for this circle
    //push to arrangedCircles
  }
  return arrangedCircles;
}


我不确定我应该用什么样的方程或数学来找到每个子圆圈的 x 和 y 位置。

我在数学论坛上看到 that there's an equation for something that looks similar,但我对如何将其翻译成打字稿一无所知。

R为大圆的半径,r[i]为小圆的半径i = 0..n

让我们把第一个圆的圆心放在点

c[0] = (R, 0).

Т然后后续圆心的坐标:

c[i] = (R * cos(f[i]), R * sin(f[i]))

在哪里

f[i] = f[i-1] + 2 * arcsin((r[i] + r[i-1]) / (2 * R)) 
f[0] = 0

用 Python 和 matplotlib 测试这个给出了下图。

关于试穿:

  1. 如果两个相邻的圆的半径之和大于大圆的直径,则无法放置。
  2. f[i] > 2 * Pi的值表示不能再添加不重叠的圆

这是另一种方法。我试图避免使用“计算昂贵”的函数arcsinsincos,只用昂贵的函数sqrt代替它们,你可以试试根据您的需要调整以下代码。

import math
import numpy as np

def initial_child_cetner(large_circle, argument):
    cos_arg = math.cos(math.pi * argument / 180)
    sin_arg = math.sin(math.pi * argument / 180)
    rotation = np.array([[ cos_arg, -sin_arg],
                         [ sin_arg,  cos_arg]])
    initial_center = large_circle['radius'] * np.array([1., 0.])
    return rotation.dot(initial_center)

def cos_sin_angle(large_radius, chord):
    cos_angle = 1 - ( chord )**2 / (2*large_radius**2)  
    sin_angle = math.sqrt(1 - cos_angle**2)
    return cos_angle, sin_angle

def next_child_center(large_circle_center, current_child_center, large_radius, chord):
    cos_a, sin_a = cos_sin_angle(large_radius, chord)
    rotation = np.array([[ cos_a,  sin_a],
                         [-sin_a,  cos_a]])
    child_center_next =  large_circle_center + rotation.dot(current_child_center - large_circle_center)
    return child_center_next

def chain_of_child_circles(large_circle, child_radii, argument):
    n = len(child_radii)
    child_centers = np.empty((n, 2), dtype = float)
    child_centers[0, :] = initial_child_cetner(large_circle, argument)
    large_center = np.array([large_circle['x'], large_circle['y']])
    for i in range(n-1):
        chord = child_radii[i] + child_radii[i+1]
        child_centers[i+1, :] = next_child_center(large_center, 
                                                  child_centers[i, :], 
                                                  large_circle['radius'], 
                                                  chord) 
    return child_centers
    

childRadii = [1, 3, 2, 5, 1, 2]
largeCircle = { 'radius': 10, 'x': 0, 'y': 0 }

childCircleCenters = chain_of_child_circles(largeCircle, childRadii, -90)

fig, axs = plt.subplots()
axs.plot(childCircleCenters[:,0], childCircleCenters[:,1], 'bo')

axs.plot(childCircleCenters[:,0], childCircleCenters[:,1])


axs.set_aspect('equal')
plt.grid()
plt.show()