Arrange circles of different sizes around a circular path without spaces

I am creating a Canvas animation and have managed to set x the number of circles in a circular path. Here's a simplified version of the code I'm using:

var total = circles.length,
    i = 0,
    radius = 500,
    angle = 0,
    step = (2*Math.PI) / total;

for( i; i < total; i++ ) {
    var circle = circles[i].children[0],
        cRadius = circle[i].r,
        x = Math.round(winWidth/2 + radius * Math.cos( angle ) - cRadius),
        y = Math.round(winHeight/2 + radius * Math.sin( angle ) - cRadius);

    circle.x = x;
    circle.y = y;

    angle += step;
}

      

The result is the following: enter image description here

I'm trying to get all the circles next to each other with no spaces in between (except the first and last). The dimensions of the circles (radius) are randomly generated and should not be adjusted to match the circular path:

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

      

I expect there will be a gap between the first and last lap.

I am struggling to get around this, so any help would be greatly appreciated :)

Hooray!

+3


source to share


2 answers


It's something like this, but you need to figure out the size of the last circle:

http://jsfiddle.net/rudiedirkx/ufvf62yf/2/

Basic logic:

var firstStep = 0, rad = 0, step = 0;
firstStep = step = stepSize();
for ( var i=0; i<30; i++ ) {
    draw.radCircle(rad, step);
    rad += step;
    step = stepSize();
    rad += step;
}

      

  • stepSize()

    creates a random delight between Math.PI/48

    and Math.PI/48 + Math.PI/36

    (no particular reason, but it looked good). You can fix this as correct dimensions.
  • draw.radCircle(rad, step)

    creates a circle at a rad

    dimension position step

    (also in a rad).
  • step

    is added twice per iteration: once to go from the current center of the circle to its edge, and once to find the next center of the circle
  • firstStep

    important because you have to know where to stop (since the first circle crosses the negative angle)
  • I haven't figured out how to make the last circle the perfect size yet =)


There's also a bit of magic in draw.radCircle()

:

var r = rRad * Math.PI/3 * 200 * .95;

      

  • 200

    - this is obviously a large circle radius
  • 95%

    is that the length of the edge of the circle is slightly longer (straight) than the radius of each circle
  • I have no idea why Math.PI/3

    this is what ... I figured it should be Math.PI / 2, which is 1 rad, but that didn't work at all. 1/3

    for some reason ..... Explain what!

If you want to animate these circle dimensions and keep them aligned, you will find it difficult. Now they are all random. In animation, only the first iteration can be random and the rest is a big mess in cache and math =)

+2


source


The main creation loop:
• take the current radius
• calculate the corners that it covers (= atan2 (smallRadius / bigRadius))
• move the base corner to this last corner.

enter image description here

http://jsfiddle.net/dj2v7mbw/9/

function CircledCircle(x, y, radius, margin, subCircleCount, subRadiusMin, subRadiusMax) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.subCircleCount = subCircleCount;
    var circles = this.circles = [];
    // build top sub-circles
    var halfCount = Math.floor(subCircleCount / 2);
    var totalAngle = addCircles(halfCount);
    // re-center top circles
    var correction = totalAngle / 2 + Math.PI / 2;
    for (var i = 0; i < halfCount; i++) this.circles[i].angle -= correction;
    // build bottom sub-circles
    totalAngle = addCircles(subCircleCount - halfCount);
    // re-center bottom circles
    var correction = totalAngle / 2 - Math.PI / 2;
    for (var i = halfCount; i < subCircleCount; i++) this.circles[i].angle -= correction;
    // -- draw this C
    this.draw = function (angleShift) {
        for (var i = 0; i < this.circles.length; i++) drawDistantCircle(this.circles[i], angleShift);
    }
    //
    function drawDistantCircle(c, angleShift) {
        angleShift = angleShift || 0;
        var thisX = x + radius * Math.cos(c.angle + angleShift);
        var thisY = y + radius * Math.sin(c.angle + angleShift);
        ctx.beginPath();
        ctx.arc(thisX, thisY, c.r, 0, 2 * Math.PI);
        ctx.fillStyle = 'hsl(' + (c.index * 15) + ',75%, 75%)';
        ctx.fill();
        ctx.stroke();
    }
    //
    function addCircles(cnt) {
        var currAngle = 0;
        for (var i = 0; i < cnt; i++) {
            var thisRadius = getRandomInt(subRadiusMin, subRadiusMax);
            var thisAngle = Math.atan2(2 * thisRadius + margin, radius);
            var thisCircle = new subCircle(thisRadius, currAngle + thisAngle / 2, i);
            currAngle += thisAngle;
            circles.push(thisCircle);
        }
        return currAngle;
    }
}

      

from



function subCircle(radius, angle, index) {
    this.r = radius;
    this.angle = angle;
    this.index = index;
}

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

      

use

 var myCircles = new CircledCircle(winWidth / 2, winHeight / 2, 350, 2, 24, 5, 50);
 myCircles.draw();

      

animate with:

var angleShift = 0;

function draw() {
    requestAnimationFrame(draw);
    ctx.clearRect(0, 0, winWidth, winHeight);
    myCircles.draw(angleShift);
    angleShift += 0.010;
}
draw();

      

+3


source







All Articles