构造一个嵌套正方形的圆

sig*_*lor 2 javascript math html5 canvas

我想构建一个嵌套正方形的圆圈,如下所示:

circleOfSquares

目前,我正在使用JavaScript/HTML5画布进行编程.这是我的代码:

<html>
<head>
<title>Circle of squares</title>
<script type="text/javascript">
var r = 150, u = 20, nests = 200;       //radius in pixels, circumference in squares, nests in squares
var w = r;                              //any number != 0

function getNewW()
{
    if(u < 3)
        alert("Error: u < 3 (" + u + " < 3)!");

    var tangents = new Array(new Array(0, w/2), new Array(Math.sin((1/u*360)*(Math.PI/180))*(w/2), -Math.cos((1/u*360)*(Math.PI/180))*(w/2)));
    var sta = new Array(new Array(r, 0), new Array(Math.cos((1/u*360)*(Math.PI/180))*r, Math.sin((1/u*360)*(Math.PI/180))*r));
    var end = new Array(new Array(sta[0][0]+tangents[0][0], sta[0][1]+tangents[0][1]), new Array(sta[1][0]+tangents[1][0], sta[1][1]+tangents[1][1]));
    var pts = new Array(sta[0], end[0], sta[1], end[1]);
    var intersect = new Array(((pts[0][0]*pts[1][1]-pts[0][1]*pts[1][0])*(pts[2][0]-pts[3][0]) - (pts[0][0]-pts[1][0])*(pts[2][0]*pts[3][1]-pts[2][1]*pts[3][0])) / ((pts[0][0]-pts[1][0])*(pts[2][1]-pts[3][1]) - (pts[0][1]-pts[1][1])*(pts[2][0]-pts[3][0])), ((pts[0][0]*pts[1][1]-pts[0][1]*pts[1][0])*(pts[2][1]-pts[3][1]) - (pts[0][1]-pts[1][1])*(pts[2][0]*pts[3][1]-pts[2][1]*pts[3][0])) / ((pts[0][0]-pts[1][0])*(pts[2][1]-pts[3][1]) - (pts[0][1]-pts[1][1])*(pts[2][0]-pts[3][0])));        //Formula from http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection


    //distTo0 should be equal to distTo1
    var distTo0 = Math.sqrt(Math.pow(sta[0][0]-intersect[0], 2) + Math.pow(sta[0][1]-intersect[1], 2));
    var distTo1 = Math.sqrt(Math.pow(sta[1][0]-intersect[0], 2) + Math.pow(sta[1][1]-intersect[1], 2));
    if(Math.round(distTo0*100)/100 != Math.round(distTo1*100)/100)
        alert("Error: distTo0 != distTo1 (" + distTo0 + " != " + distTo1 + ")!");

    return distTo0*2;
}

function start()
{
    var canvas = document.getElementById("outputCanvas");

    canvas.setAttribute("width",  600);
    canvas.setAttribute("height", 600);

    if(canvas.getContext)
    {
        var ctx = canvas.getContext("2d");
        ctx.translate(300, 300);

        w = getNewW();
        for(var i=0; i<u; i++)
        {
            ctx.rotate((1/u*360)*(Math.PI/180));
            ctx.fillRect(r, -w/2, w, w);
        }

        for(var j=1; j<nests; j++)
        {
            var oldr = r;
            var temp1 = 1/(10*j+1);
            while(r+w > oldr)        //This is the while-loop that makes the program slow
            {
                r -= temp1;
                w = getNewW();
            }
            if(r < 0)       //When the radius gets smaller than 0, the center is reached -> no new squares have to be drawn
                break;

            var temp2 = (1/u*360)*(Math.PI/180);
            for(var i=0; i<u; i++)
            {
                ctx.rotate(temp2);
                ctx.fillRect(r, -w/2, w, w);
            }
        }
    }
}
</script>
</head>
<body id="main" onload="start()">
<canvas style="border:1px #000000 solid;" width="0" height="0" id="outputCanvas">Canvas not supported...</canvas>
<div id="info"> </div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

但由于我没有解决方案的公式,我使用while循环来越来越接近解决方案(直到它因为浮动不准确而达到零),这就是为什么它很慢.那么,可以使用什么公式来计算(思考)圆内的下一个正方形的宽度,如果有必要,可以在其他地方优化代码?

Mar*_*eed 6

圆附近,那里的方块是足够小的中心,可以近似的一侧(长度W¯¯由弧长) -也就是说,一个多久ü个内圆的是,如果你画了它作为一个实际圈子.这只是在弧度的角度(2 π/ù)倍穿过正方形的内角那张的圆的半径.由于您r的代码有所不同,我将在单个时刻r2调用特定的半径值; 这使得弧长:

w_approx = (2 * Math.PI / u) * r2
Run Code Online (Sandbox Code Playgroud)

但是对于你图片中的大多数方块而言,它与w的实际值之间的差异太大了; 如果你使用它作为边长,你将得到重叠的正方形.幸运的是,我们也可以直接计算w的真实值; 它只需要一点三角学.

如果从正方形的内角到圆的中心绘制线条,那么这两条线加上正方形的内侧形成一个三角形.我们知道我们刚刚画出的这两条线有多长; 它们等于内半径.我们不知道第三边有多长-这就是价值W¯¯我们要找的-但我们知道与它相对的角度.这三条信息足以计算w.

这是一张图片来展示我在说什么:

在此输入图像描述

在圆,标记的中心的角度α在图片(阿尔法),仅仅是一个ü第一个完整的圆,其值为2的π/ù弧度(或360/ù度,但三角函数所有期望弧度) :

alpha = 2 * Math.PI / u
Run Code Online (Sandbox Code Playgroud)

三角形的另外两个角度是相等的(它们必须是,因为它们是相等的长度相等的边),因此它们都被标记为β.由于三角形的三个角总是加起来为π弧度(或180°),我们可以计算β ; 它等于(π - α)/ 2弧度:

beta = (Math.PI - alpha)/2
Run Code Online (Sandbox Code Playgroud)

根据正弦定律,如果你将任何三角形任何一边的长度除以与该边相反的角度的正弦,无论你选择哪三边,结果都是一样的.这告诉我们,w ^/ α必须是一样的R2/ β.解决w的等式得到了我们:

w = r2 * Math.sin(alpha) / Math.sin(beta)
Run Code Online (Sandbox Code Playgroud)