在大正方形内圆形布局较小的正方形

时间:2014-01-03 01:52:17

标签: html5 canvas graphics

给定一个边界正方形和较小正方形的总数。较小的正方形需要在较大的正方形内绘制,均匀地以圆形方式间隔开,只是接触但不重叠。你如何计算内部正方形的宽度?

(更新小提琴链接) http://jsfiddle.net/mdluffy/6bUVz/3/

///////// INPUTS ///////////////////////////////////////////
var BoundingBoxSide = 100;
var NofInnerBoxes = 14; 
    //////////////////////////////////////////////////////////// 
 drawBoxes();

function drawBoxes()
{
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.rect(0,0,BoundingBoxSide,BoundingBoxSide);
ctx.stroke();

for(var i=0; i < NofInnerBoxes; i++)
{
    // ************************************************************************************ //
    // This needs to be computed so that the boxes touch each other, but not overlap
    var innerBoxSide = 20;   
    // ************************************************************************************ //
    var angle = degToRad(i * 360/NofInnerBoxes);
    var innerX = ((BoundingBoxSide - innerBoxSide)/2) * Math.cos(angle);
    var innerY = ((BoundingBoxSide - innerBoxSide)/2) * Math.sin(angle);
    ctx.rect(BoundingBoxSide/2 + innerX - innerBoxSide/2, BoundingBoxSide/2 - innerY - innerBoxSide/2, innerBoxSide, innerBoxSide);

    ctx.stroke();

}
}

function degToRad(d)
{
    return d * Math.PI / 180;
}

更新

我正在使用Three.js进行3D可视化。这是一个树结构,节点表示为多维数据集。子节点多维数据集循环放置在父节点多维数据集的顶部。递归应用。

内部正方形不需要触摸外部正方形,但它应该触及可以放在外部正方形内部的最大圆。

1 个答案:

答案 0 :(得分:1)

这是我的尝试:

var alpha = Math.PI * (NofInnerBoxes - 2) / (2 * NofInnerBoxes)
var t = Math.tan(alpha)
var innerBoxSide = BoundingBoxSide / Math.sqrt(t*t + 4*t + 5)

(信用:WolframAlpha解决innerBoxSide;以及我背后涂鸦的信封。)

更新:以上是假设每个内部正方形的两边平行于穿过该内部正方形和外部正方形的中心的直线。我现在看到这个假设不是你想到的。

这是另一种方法。在这一个中,围绕内部正方形的圆圈将全部相互接触,尽管内部正方形本身不会相互接触:

var alpha = Math.PI / NofInnerBoxes
var t = Math.sin(alpha)
var innerBoxSide = BoundingBoxSide * t / ((t + 1) * Math.sqrt(2))

结果:

enter image description here

推导

回应关于如何推导出公式的请求......

r_s (r sub s)为“小半径”,即围绕内部正方形的圆的半径。这些内圈都与大圆相切, >划分外方。调用大圆圈的半径r_b(b表示“大”)。

请注意,外部正方形a.k.a. BoundingBoxSide的边是= 2 * r_b。还要注意,每个内圆的直径2 * r_s也是每个内圆的对角线。因此,每个内部正方形的,即a.k.a. innerBoxSide,是=(2 * r_s)/ sqrt(2)。

现在让角度 alpha =每个内圈所围绕的角度的一半(如果这是正确的动词)围绕大圆圈的中心。即alpha =(2 * pi / NofInnerBoxes)/ 2 = pi / NofInnerBoxes。

关键是绘制一个直角三角形,其中一个角度是alpha;这将使用像sin()这样的trig函数告诉我们该三角形的所有边之间的比率。我们可以画出这样一个顶点为的三角形:

A. The center of the big circle
B. The center of a small circle
C. The point where that small circle touches its neighbor

直角位于顶点C,角度α位于顶点A.边BC的长度= r_s,斜边的长度(AB)= r_b - r_s。

因此,通过sin()的定义,我们可以说sin(alpha)=反面/斜边= BC / AB = r_s /(r_b - r_s)。求解r_s的这个等式,得到r_s = r_b * sin(alpha)/(1 + sin(alpha))。

最后,插入事实(上图)BoundingBoxSide = 2 * r_b,innerBoxSide =(2 * r_s)/ sqrt(2);然后你得到上面显示的公式innerBoxSide = BoundingBoxSide * t / ((t + 1) * Math.sqrt(2))

对不起,这是一段长篇文章,但如果仔细阅读,我希望它足够清楚。如果时间允许,我也可以发布图表。如果您有疑问,请告诉我。 (可能有一种更简单的方法来推导它,但这就是我做到的。)