将正方形定位在最小直径的圆上

时间:2010-07-21 08:18:36

标签: algorithm math geometry

给定边长 l n 正方形,如何确定圆的最小半径 r ,以便我可以分配所有正方形均匀地沿着圆周边而没有重叠? (约束:第一个方格将始终位于12点。)

后续问题:如何放置高度为 h 和宽度 w n 相同的矩形?

example http://pub.n3rd.org/circle.png

6 个答案:

答案 0 :(得分:12)

可能有一种数学上聪明的方法来做到这一点,但我不知道。 我觉得有点复杂,因为每个不同数量的正方形的几何形状都不同;对于4它是菱形,对于5它是五边形,依此类推。

我要做的是将这些方块放在1个单位的圆上(太小,我知道,忍受我),平均分布在它上面。这很容易,只需将你的360度对等(划分)为正方形。然后测试你所有的方块与他们的邻居重叠;如果它们重叠,则增加半径。

通过使用智能算法接近正确的大小,您可以使此过程不那么愚蠢。我正在考虑像牛顿算法这样的东西:给定两个连续的猜测,其中一个太小而一个太大,你的下一个猜测需要是这两个的平均值。

您可以迭代到您喜欢的任何精度。每当猜测之间的距离小于某个任意小的误差范围时停止。

编辑我有更好的解决方案:

如果你问“我怎么知道方块是否重叠?”我正在考虑告诉你什么。这让我对如何准确地计算圆周大小有了一个想法:

将你的方块放在一个太小的圆圈上。您知道如何:计算360 / n角与其相交的圆上的点,并将正方形的中心放在那里。实际上,您还不需要放置方块,接下来的步骤只需要中点。

计算方形与其邻域的最小距离:计算X的差异和中点的Y差异,并取最小值。 X和Y实际上只是圆圈上的余弦和正弦。

您希望任何方格的最小值与其邻居相比(顺时针方向,比如说)。因此,您需要绕着圆圈找到最小的圆圈。

方块之间的最小(X或Y)距离需要变为1.0。因此,只需取最小距离的倒数并乘以圆的大小即可。 Presto,你的圈子大小合适。

修改

在不失一般性的情况下,我认为可以将我的解决方案略微下调,以便接近编码。这是一个改进:

  • 假设正方形的大小为1,即每个边的长度为1个单位。最后,你的盒子肯定会大于1个像素,但这只是缩放的问题。
  • 摆脱角落案件:

    if (n < 2) throw new IllegalArgumentException();
    if (n == 2) return 0.5; // 2 squares will fit exactly on a circle of radius 0.5
    
  • 以0.5的圆圈尺寸r开头,对于任意数量的正方形而言,这肯定太小了&gt; 2。

    r = 0.5;
    dmin = 1.0; // start assuming minimum distance is fine
    a = 2 * PI / n;
    for (p1 = 0.0; p1 <= PI; p1+=a) { // starting with angle 0, try all points till halfway around
       // (yeah, we're starting east, not north. doesn't matter)
       p2 = p1 + a; // next point on the circle 
       dx = abs(r * cos(p2) - r * cos(p1))
       dy = abs(r * sin(p2) - r * sin(p1))
       dmin = min(dmin, dx, dy)
    }
    
    r = r / dmin;
    

修改

我将其转换为真正的Java代码并运行与此类似的东西。代码和结果在此处:http://ideone.com/r9aiu

我使用GnuPlot创建了图形输出。通过将输出中的点集剪切并粘贴到数据文件然后运行,我能够创建简单的圆形框图。

plot '5.dat' with boxxyerrorbars

文件中的.5用于调整框的大小...懒惰但工作正常。 .5适用于中心的两侧,因此盒子的大小正好是1.0。

唉,我的算法不起作用。它使得半径太大,因此将盒子放置得比必要的远得多。即使按比例缩小2倍(在某些地方使用0.5可能是错误的)也无济于事。

抱歉,我放弃了。也许我的方法可以被挽救,但它不会像我那样工作。 :(


修改

我讨厌放弃。当我想到一种方法来挽救我的算法时,我正要离开我的电脑:

该算法将X或Y距离的较小调整为至少为1.很容易证明这只是愚蠢的。当你有很多盒子然后在圆圈的东边和西边时,你的盒子几乎直接堆叠在一起,它们的X彼此非常接近,但是它们之间只有足够的Y距离就可以保存它们。它们。

所以......为了使这个工作,你必须将dx和dy的最大缩放到(对于所有情况)至少半径(或者它是半径的两倍?)。 / p>

更正后的代码位于: http://ideone.com/EQ03g http://ideone.com/VRyyo

再次在GnuPlot中测试,它会产生漂亮的小圆圈,有时只有1或2个盒子正在接触。 问题解决了!:)

(这些图像比它们高很宽,因为GnuPlot不知道我想要比例布局。想象一下整个作品被挤成方形:))

答案 1 :(得分:4)

我会计算最小半径的上限,方法是使用包围正方形的圆圈而不是正方形本身。

我的计算结果为:

Rmin&lt; = X /(sqrt(2)* sin(180 / N))

其中: X是方形边长,N是所需的平方数。

我认为圆圈的位置使得它们的中心位于大圆周上。

- 编辑 -

在下面的评论中使用Dave的想法,我们也可以通过考虑圆形在正方形内(因此具有半径X / 2)来计算一个漂亮的下界。这个界限是:

Rmin> = X /(2 * sin(180 / N))

答案 2 :(得分:1)

如已经指出的那样,将圆形圆周等间隔的n个点定位的问题是微不足道的。问题的(非常非常)困难的部分是找出给出方形的令人愉悦的布局所需的圆的半径。我建议你按照其他一个答案进行思考,然后把方块想象成一个圆形的“缓冲区”,大小足以容纳正方形和足够的空间以满足你的审美要求。然后检查相邻正方形中心之间chord length的公式。现在你有一个角度,在圆心,由方形中心之间的和弦对齐,可以很容易地从三角形的三角学计算圆的半径。

并且,关于你的后续问题:我建议你解决圆周边长min(h,w)的正方形的问题,然后将正方形转换为矩形,将圆转换为具有偏心率的椭圆h / w(或w / h)。

答案 3 :(得分:0)

从一个任意圆开始(例如,直径为(* n l))并将方块均匀地放在圆周上。然后你通过每对相邻的广场和:

  • 计算连接其中点的直线,
  • 计算此线与插入的方形边的交点(M1和M2是中点,S1和S2是与方边相对应的交点:

                    S2         S1
    M1--------------*----------*---------------M2
    
    ------------------------
    |                      |
    |                      |
    |                      |
    |                      |
    |          M1          |
    |           \          |
    |            \         |
    |      -------*------- +--------
    |      |       \       |       |
    |      |        \      |       |
    -------+---------*------       |
           |          \            |
           |           M2          |
           |                       |
           |                       |
           |                       |
           |                       |
           -------------------------
    
  • 计算使S1和S2合在一起所需的比例因子(简单地说是M1-S1和S2-M2之和与M1-M2之比),

最后通过找到的比例因子的最大值来缩放圆圈。

编辑:这是确切的解决方案。但是,有一点想法可以进一步优化速度:

  • 您只需要对最接近45°的方块(如果 n 是偶数)执行此操作。 45°和135°(如果 n 是奇数;实际上,您可能证明只需要其中一个)。
  • 对于大 n ,圆上正方形的最佳间距将快速接近正方形对角线的长度。因此,您可以预先计算一些小的 n (最多十几个)的缩放因子,然后用对角线进行足够好的近似。

答案 4 :(得分:0)

我会这样解决:

要找到半径r和长度l之间的关系,让我们分析无量纲表示

  • 以圆圈(x1,y1)...(xn,yn)
  • 获取中心
  • 从每个中心到第i个第1个方格的第i个方块和左上角的右下角
  • 两个点应该具有相等的x或相等的y,以较小的l
  • 为准 应对每个中心重复
  • 程序,产生最小l的程序是最终解决方案。

这是最佳解决方案,可以用r = f(l)来解决。 通过调整xLR [i]和yUL [i + 1]的公式,可以使解决方案适应矩形。

会尝试给出一些伪代码。

编辑:
程序中存在一个错误,右下角和左上角不是两个相邻正方形/矩形的必要最近点。

答案 5 :(得分:0)

我们假设你解决了3或4个方格的问题。

如果你有 n &gt; = 5个方格,并且在圆的顶部放置一个方格,你将有另一个方形落入与你的圆同心的笛卡尔平面的第一个象限

问题是找到圆的半径 r ,使得圆圈的左侧与顶部圆圈相邻,而顶部圆圈的右侧不会“交叉”其他

顶部圆圈右侧的 x 坐标是 x1 = L / 2,其中 L 是正方形的一面。顶部旁边的圆圈左侧的 x 坐标为 x2 = r cos a - L / 2,其中 r 是半径, a 是每对方形中心之间的角度( a = 360 / n 度)。

所以我们需要解决 x1 &lt; = x2 ,这会导致

r &gt; = L / cos a

L a 已知,所以我们完成了: - )