algorithmmath

Coordinates of dot on an hexagon path


In a project, I'd like to evenly distibute dots around a regular hexagon path.
Thus I'd like to calculate the coordinates of my dots from the center of the hex and the length of a side.

For instance, if I want to do the same thing around a circle I would do (in JS) :

let center = {x: 0, y: 0}
let radius = 10;
let amountOfDots = 48;
for (let i = 0; i < amountOfDots; i++) {
    let x = radius * Math.sin(Math.PI * 2 * i / amountOfDots) + center.x;
    let y = radius * Math.cos(Math.PI * 2 * i / amountOfDots) + center.y;
    // draw my dot in (x, y) or whatever
}

In other words, I would like to get the coordinate of all those points in a single loop.
On this Exemple amountOfDots = 24 enter image description here

I have the intuition it wouldn't be too hard to implement, but I'm struggling with the maths...
Thanks :)


Solution

  • A few observations when we do this on the unit circle (radius = 1):

    Here is an interactive JS snippet to calculate and draw those points:

    // Main algorithm:
    function hexagonDots(center, radius, amountOfDots) {
        // Function to map unit coordinates to the given center & radius
        const project = (x, y) => ({
            x: center.x + radius * x,
            y: center.y + radius * y
        });
        const y = Math.sqrt(3) / 2; // = sin(60°)
        const hexaX = [1, 0.5, -0.5, -1, -0.5, 0.5, 1];
        const hexaY = [0, y, y, 0, -y, -y, 0];
    
        return Array.from({length: amountOfDots}, (_, i) => {
            let offset = 6 * i / amountOfDots;
            const edgenum = Math.floor(offset); // On which edge is this dot?
            offset %= 1; // Retain fractional part only: offset on that edge
            return project( 
                // Use interpolation to get coordinates of that point on that edge
                hexaX[edgenum] + offset * (hexaX[edgenum + 1] - hexaX[edgenum]),
                hexaY[edgenum] + offset * (hexaY[edgenum + 1] - hexaY[edgenum])
            );
        });
    }
    
    // I/O management:
    
    function drawHexagon(ctx, dots) {
        // Draw
        ctx.resetTransform();
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); 
        ctx.translate(200, 80);
        for (const {x, y} of dots) {
            ctx.beginPath();
            ctx.moveTo(x, y);
            ctx.lineTo(x+1, y);
            ctx.stroke();
        }
    }
    
    const ctx = document.querySelector("canvas").getContext("2d");
    
    function refresh() {
        const center = {x: 0, y: 0};
        const radius = 70;
        const amountOfDots = +this.value;
        const dots = hexagonDots(center, radius, amountOfDots);
        drawHexagon(ctx, dots);
    }
    
    const input = document.querySelector("input");
    input.addEventListener("input", refresh);
    refresh.call(input);
    Dots: <input type="number" value="48" size="4"><br>
    <canvas></canvas>