Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filling circle with hexagons

I'm trying to find a way to put as much hexagons in a circle as possible. So far the best result I have obtained is by generating hexagons from the center outward in a circular shape.

But I think my calculation to get the maximum hexagon circles is wrong, especially the part where I use the Math.ceil() and Math.Floor functions to round down/up some values.

When using Math.ceil(), hexagons are sometimes overlapping the circle.
When using Math.floor() on the other hand , it sometimes leaves too much space between the last circle of hexagons and the circle's border.

var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");

var canvas_width = c_el.clientWidth;
var canvas_height = c_el.clientHeight;

var PI=Math.PI;
var PI2=PI*2;

var hexCircle = {
	r: 110, /// radius 
	pos: {
		x: (canvas_width / 2),
		y: (canvas_height / 2)
	}
};

var hexagon = {
	r: 20,
	pos:{
		x: 0,
		y: 0
	},
	space: 1
};

drawHexCircle( hexCircle, hexagon );
function drawHexCircle(hc, hex ) {
	drawCircle(hc);
	var hcr = Math.ceil( Math.sqrt(3) * (hc.r / 2) ); 
    var hr =  Math.ceil( ( Math.sqrt(3) * (hex.r / 2) ) ) + hexagon.space; // hexRadius
	var circles =  Math.ceil( ( hcr / hr ) / 2 );
    drawHex( hc.pos.x , hc.pos.y, hex.r ); //center hex ///
	for (var i = 1; i<=circles; i++) {
		for (var j = 0; j<6; j++) {
			var currentX = hc.pos.x+Math.cos(j*PI2/6)*hr*2*i;
			var currentY = hc.pos.y+Math.sin(j*PI2/6)*hr*2*i;
			drawHex( currentX,currentY, hex.r );
			for (var k = 1; k<i; k++) {
				var newX = currentX + Math.cos((j*PI2/6+PI2/3))*hr*2*k;
				var newY = currentY +  Math.sin((j*PI2/6+PI2/3))*hr*2*k;
				drawHex( newX,newY, hex.r );
			}
		}
	}
}

function drawHex(x, y, r){
    ctx.beginPath();
    ctx.moveTo(x,y-r);
    for (var i = 0; i<=6; i++) {
        ctx.lineTo(x+Math.cos((i*PI2/6-PI2/4))*r,y+Math.sin((i*PI2/6-PI2/4))*r);
    }
    ctx.closePath();
    ctx.stroke();
}

function drawCircle( circle ){
	ctx.beginPath();
	ctx.arc(circle.pos.x, circle.pos.y, circle.r, 0, 2 * Math.PI);
	ctx.closePath();
	ctx.stroke();
}
<canvas id="myCanvas" width="350" height="350" style="border:1px solid #d3d3d3;">
like image 684
Alexus Avatar asked Feb 25 '16 12:02

Alexus


People also ask

Can a hexagon fit in a circle?

Solution. Since a regular hexagon divides the circle into six equal parts and there are 360 degrees in the circle, each side of the regular hexagon should span a chord of 60 degrees on the circle.

How many hexagons fit in a circle?

No need to approximate the radius - you can compute it exactly. A regular hexagon can be divided into six identical equilateral triangles. So the radius of the circle exactly equals the length of one of the sides of the hexagon, which is 90 / 6 = 15. A unit circle contains seven equal, regular hexagons.

What is the formula of hexagonal packing?

Four faces as hexagons having the area =4×(6√3r2)=24√3r2 = 4 × ( 6 3 r 2 ) = 24 3 r 2 is the radius of the packing sphere, Hence the area of hexagonal packed=(4+24√3)r2 = ( 4 + 24 3 ) r 2 sq. units.


1 Answers

If all the points on the hexagon are within the circle, the hexagon is within the circle. I don't think there's a simpler way than doing the distance calculation.

I'm not sure how to select the optimal fill point, (but here's a js snippet proving that the middle isn't always it). It's possible that when you say "hexagon circle" you mean hexagon made out of hexagons, in which case the snippet proves nothing :)

I made the hexagon sides 2/11ths the radius of the circle and spaced them by 5% the side length.

var hex = {x:0, y:0, r:10};
var circle = {x:100, y:100, r:100};
var spacing = 1.05;
var SQRT_3 = Math.sqrt(3);
var hexagon_offsets = [
  {x: 1/2, y: -SQRT_3 / 2},
  {x: 1, y: 0},
  {x: 1/2, y: SQRT_3 / 2},
  {x: -1/2, y: SQRT_3 / 2},
  {x: -1, y: 0},
  {x: -1/2, y: -SQRT_3 / 2}
];


var bs = document.body.style;
var ds = document.documentElement.style;
bs.height = bs.width = ds.height = ds.width = "100%";
bs.border = bs.margin = bs.padding = 0;
var c = document.createElement("canvas");
c.style.display = "block";
c.addEventListener("mousemove", follow, false);
document.body.appendChild(c);
var ctx = c.getContext("2d");
window.addEventListener("resize", redraw);
redraw();


function follow(e) {
  hex.x = e.clientX;
  hex.y = e.clientY;
  redraw();
}
function drawCircle() {
  ctx.strokeStyle = "black";
  ctx.beginPath();
  ctx.arc(circle.x, circle.y, circle.r, 0, 2 * Math.PI, true);
  ctx.closePath();
  ctx.stroke();
}
function is_in_circle(p) {
  return Math.pow(p.x - circle.x, 2) + Math.pow(p.y - circle.y, 2) < Math.pow(circle.r, 2);
}
function drawLine(a, b) {
  var within = is_in_circle(a) && is_in_circle(b);
  ctx.strokeStyle = within ? "green": "red";
  ctx.beginPath();
  ctx.moveTo(a.x, a.y);
  ctx.lineTo(b.x, b.y);
  ctx.closePath();
  ctx.stroke();
  return within;
}
function drawShape(shape) {
  var within = true;
  for (var i = 0; i < shape.length; i++) {
    within = drawLine(shape[i % shape.length], shape[(i + 1) % shape.length]) && within;
  }
  if (!within) return false;
  ctx.fillStyle = "green";
  ctx.beginPath();
  ctx.moveTo(shape[0].x, shape[0].y);
  for (var i = 1; i <= shape.length; i++) {
    ctx.lineTo(shape[i % shape.length].x, shape[i % shape.length].y);
  }
  ctx.closePath();
  ctx.fill();
  return true;
}
function calculate_hexagon(x, y, r) {
  return hexagon_offsets.map(function (offset) {
    return {x: x + r * offset.x, y: y + r * offset.y};
  })
}
function drawHexGrid() {
  var hex_count = 0;
  var grid_space = calculate_hexagon(0, 0, hex.r * spacing);
  var y = hex.y;
  var x = hex.x;
  while (y > 0) {
    y += grid_space[0].y * 3;
    x += grid_space[0].x * 3;
  }
  while (y < c.height) {
    x %= grid_space[1].x * 3;
    while (x < c.width) {
      var hexagon = calculate_hexagon(x, y, hex.r);
      if (drawShape(hexagon)) hex_count++;
      x += 3 * grid_space[1].x;
    }
    y += grid_space[3].y;
    x += grid_space[3].x;
    x += 2 * grid_space[1].x;
  }
  return hex_count;
}

function redraw() {
  c.width = window.innerWidth;
  c.height = window.innerHeight;
  circle.x = c.width / 2;
  circle.y = c.height / 2;
  circle.r = Math.min(circle.x, circle.y) * 0.9;
  hex.r = circle.r * (20 / 110);
  ctx.clearRect(0, 0, c.width, c.height);
  var hex_count = drawHexGrid();
  drawCircle();
  ctx.fillStyle = "rgb(0, 0, 50)";
  ctx.font = "40px serif";
  ctx.fillText(hex_count + " hexes within circle", 20, 40);
}
like image 196
dtudury Avatar answered Oct 05 '22 11:10

dtudury