用六边形填充圆

Posted

技术标签:

【中文标题】用六边形填充圆【英文标题】:filling circle with hexagons 【发布时间】:2016-06-08 05:55:21 【问题描述】:

我正在尝试找到一种方法将尽可能多的六边形放在一个圆圈中。到目前为止,我获得的最好结果是从中心向外生成圆形六边形。

但我认为我得到最大六边形圆的计算是错误的,尤其是我使用Math.ceil()Math.Floor 函数向下/向上舍入某些值的部分。

使用Math.ceil() 时,六边形有时会与圆重叠。 另一方面,当使用Math.floor() 时,有时会在最后一个六边形圆和圆的边界之间留下太多空间。

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();
&lt;canvas id="myCanvas" width="350" height="350" style="border:1px solid #d3d3d3;"&gt;

【问题讨论】:

【参考方案1】:

如果六边形上的所有点都在圆内,则六边形在圆内。我认为没有比计算距离更简单的方法了。

我不确定如何选择最佳填充点,(但这里有一个 js sn-p 证明中间并不总是它)。当你说“六边形圆”时,你的意思可能是由六边形组成的六边形,在这种情况下,sn-p 证明不了任何事情:)

我将六边形边设为圆半径的 2/11,并将它们间隔为边长的 5%。

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);

【讨论】:

以上是关于用六边形填充圆的主要内容,如果未能解决你的问题,请参考以下文章

qt creator 怎么画圆环,还要填充颜色

求一个C语言实现的种子填充多边形算法程序

MapTiler 用透明海洋设置土地多边形填充

剪辑/剪切多边形外部的所有内容或用白色填充外部

如何用增加的半径填充圆?

计算机图形学输出图元_10_多边形填充区_7_OpenGL多边形填充区函数(上)